blob: 79f43f606e12873bbab591256a7de09c5f5788bf [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- rfbUpdateTracker.cpp
20//
21// Tracks updated regions and a region-copy event, too
22//
23
24#include <assert.h>
25
26#include <rfb/UpdateTracker.h>
27#include <rfb/LogWriter.h>
28
29using namespace rfb;
30
31static LogWriter vlog("UpdateTracker");
32
33
34// -=- ClippingUpdateTracker
35
36void ClippingUpdateTracker::add_changed(const Region &region) {
37 ut->add_changed(region.intersect(clipRect));
38}
39
40void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
41 // Clip the destination to the display area
42 Region clipdest = dest.intersect(clipRect);
43 if (clipdest.is_empty()) return;
44
45 // Clip the source to the screen
46 Region tmp = clipdest;
47 tmp.translate(delta.negate());
48 tmp.assign_intersect(clipRect);
49 if (!tmp.is_empty()) {
50 // Translate the source back to a destination region
51 tmp.translate(delta);
52
53 // Pass the copy region to the child tracker
54 ut->add_copied(tmp, delta);
55 }
56
57 // And add any bits that we had to remove to the changed region
58 tmp = clipdest.subtract(tmp);
59 if (!tmp.is_empty())
60 ut->add_changed(tmp);
61}
62
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +000063void ClippingUpdateTracker::set_video_area(const Rect &rect) {
64 ut->set_video_area(rect.intersect(clipRect));
65}
66
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000067// SimpleUpdateTracker
68
69SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
70 copy_enabled = use_copyrect;
71}
72
73SimpleUpdateTracker::~SimpleUpdateTracker() {
74}
75
76void SimpleUpdateTracker::enable_copyrect(bool enable) {
77 if (!enable && copy_enabled) {
78 add_changed(copied);
79 copied.clear();
80 }
81 copy_enabled=enable;
82}
83
84void SimpleUpdateTracker::add_changed(const Region &region) {
85 changed.assign_union(region);
86}
87
88void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
89 // Do we support copyrect?
90 if (!copy_enabled) {
91 add_changed(dest);
92 return;
93 }
94
95 // Is there anything to do?
96 if (dest.is_empty()) return;
97
98 // Calculate whether any of this copy can be treated as a continuation
99 // of an earlier one
100 Region src = dest;
101 src.translate(delta.negate());
102 Region overlap = src.intersect(copied);
103
104 if (overlap.is_empty()) {
105 // There is no overlap
106
107 Rect newbr = dest.get_bounding_rect();
108 Rect oldbr = copied.get_bounding_rect();
109 if (oldbr.area() > newbr.area()) {
110 // Old copyrect is (probably) bigger - use it
111 changed.assign_union(dest);
112 } else {
113 // New copyrect is probably bigger
114 // Use the new one
115 // But be careful not to copy stuff that still needs
116 // to be updated.
117 Region invalid_src = src.intersect(changed);
118 invalid_src.translate(delta);
119 changed.assign_union(invalid_src);
120 changed.assign_union(copied);
121 copied = dest;
122 copy_delta = delta;
123 }
124 return;
125 }
126
127 Region invalid_src = overlap.intersect(changed);
128 invalid_src.translate(delta);
129 changed.assign_union(invalid_src);
130
131 overlap.translate(delta);
132
133 Region nonoverlapped_copied = dest.union_(copied).subtract(overlap);
134 changed.assign_union(nonoverlapped_copied);
135
136 copied = overlap;
137 copy_delta = copy_delta.translate(delta);
138
139 return;
140}
141
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +0000142void SimpleUpdateTracker::set_video_area(const Rect &rect)
143{
144 video_area = rect;
145}
146
147//
148// subtract() is called to mark some region as unchanged. We just remove that
149// region from both `copied' and `changed' regions. Note that `video_area' is
150// not affected intentionally; we assume that video is continuously changing,
151// so it should always be treated as "changed".
152//
153
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000154void SimpleUpdateTracker::subtract(const Region& region) {
155 copied.assign_subtract(region);
156 changed.assign_subtract(region);
157}
158
159void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
160{
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +0000161 changed.assign_subtract(video_area);
162 copied.assign_subtract(changed.union_(video_area));
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000163 info->changed = changed.intersect(clip);
164 info->copied = copied.intersect(clip);
165 info->copy_delta = copy_delta;
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +0000166 // FIXME: Using get_bounding_rect() is not what should actually be done!
167 // We should use the biggest inner rectangle of the `clip' instead.
168 // From the other side, `clip' is usually just a sole rectangle.
169 info->video_area = video_area.intersect(clip.get_bounding_rect());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170}
171
172void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
173 if (!copied.is_empty())
174 to->add_copied(copied, copy_delta);
175 if (!changed.is_empty())
176 to->add_changed(changed);
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +0000177 to->set_video_area(video_area);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000178}