1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator.h"
6
7 #include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
8
9 namespace blink {
10
Generate()11 void DisplayItemRasterInvalidator::Generate() {
12 struct OldAndNewDisplayItems {
13 const IntRect* old_visual_rect = nullptr;
14 const IntRect* new_visual_rect = nullptr;
15 PaintInvalidationReason reason = PaintInvalidationReason::kNone;
16 };
17 // If there are multiple display items changed for a client, the map will
18 // store only one (pair) of them because we only need the visual rect and the
19 // the multiple items have the same visual rect.
20 HashMap<const DisplayItemClient*, OldAndNewDisplayItems>
21 clients_to_invalidate;
22
23 Vector<bool> old_display_items_matched;
24 old_display_items_matched.resize(old_chunk_.size());
25 auto next_old_item_to_match = old_chunk_.begin_index;
26 auto max_cached_old_index = next_old_item_to_match;
27
28 for (const auto& new_item :
29 new_paint_artifact_.GetDisplayItemList().ItemsInPaintChunk(new_chunk_)) {
30 auto matched_old_index =
31 MatchNewDisplayItemInOldChunk(new_item, next_old_item_to_match);
32 if (matched_old_index == kNotFound) {
33 if (new_item.DrawsContent()) {
34 // Will invalidate for the new display item which doesn't match any old
35 // display item.
36 auto& value = clients_to_invalidate
37 .insert(&new_item.Client(), OldAndNewDisplayItems())
38 .stored_value->value;
39 if (!value.new_visual_rect) {
40 value.new_visual_rect = &new_item.VisualRect();
41 value.reason = new_item.Client().IsCacheable()
42 ? PaintInvalidationReason::kAppeared
43 : PaintInvalidationReason::kUncacheable;
44 }
45 }
46 continue;
47 }
48
49 auto reason = new_item.Client().GetPaintInvalidationReason();
50 if (!IsFullPaintInvalidationReason(reason) &&
51 matched_old_index < max_cached_old_index) {
52 // |new_item| has been moved above other cached items.
53 reason = PaintInvalidationReason::kReordered;
54 }
55
56 const auto& old_item =
57 old_paint_artifact_.GetDisplayItemList()[matched_old_index];
58 if (reason != PaintInvalidationReason::kNone &&
59 (old_item.DrawsContent() || new_item.DrawsContent())) {
60 // The display item reordered, skipped cache or changed. Will invalidate
61 // for both the old and new display items.
62 auto& value = clients_to_invalidate
63 .insert(&new_item.Client(), OldAndNewDisplayItems())
64 .stored_value->value;
65 if (old_item.IsTombstone() || old_item.DrawsContent())
66 value.old_visual_rect = &old_item.VisualRect();
67 if (new_item.DrawsContent())
68 value.new_visual_rect = &new_item.VisualRect();
69 value.reason = reason;
70 }
71
72 wtf_size_t offset = matched_old_index - old_chunk_.begin_index;
73 DCHECK(!old_display_items_matched[offset]);
74 old_display_items_matched[offset] = true;
75
76 // |old_item.IsTombstone()| is true means that |new_item| was copied from
77 // cached |old_item|.
78 if (old_item.IsTombstone())
79 max_cached_old_index = std::max(max_cached_old_index, matched_old_index);
80 }
81
82 // Invalidate remaining unmatched (disappeared or uncacheable) old items.
83 for (auto i = old_chunk_.begin_index; i < old_chunk_.end_index; ++i) {
84 if (old_display_items_matched[i - old_chunk_.begin_index])
85 continue;
86
87 const auto& old_item = old_paint_artifact_.GetDisplayItemList()[i];
88 if (old_item.DrawsContent() || old_item.IsTombstone()) {
89 clients_to_invalidate.insert(&old_item.Client(), OldAndNewDisplayItems())
90 .stored_value->value.old_visual_rect = &old_item.VisualRect();
91 }
92 }
93
94 for (const auto& item : clients_to_invalidate) {
95 GenerateRasterInvalidation(*item.key, item.value.old_visual_rect,
96 item.value.new_visual_rect, item.value.reason);
97 }
98 }
99
MatchNewDisplayItemInOldChunk(const DisplayItem & new_item,wtf_size_t & next_old_item_to_match)100 wtf_size_t DisplayItemRasterInvalidator::MatchNewDisplayItemInOldChunk(
101 const DisplayItem& new_item,
102 wtf_size_t& next_old_item_to_match) {
103 if (!new_item.IsCacheable())
104 return kNotFound;
105 for (; next_old_item_to_match < old_chunk_.end_index;
106 next_old_item_to_match++) {
107 const auto& old_item =
108 old_paint_artifact_.GetDisplayItemList()[next_old_item_to_match];
109 if (!old_item.IsCacheable())
110 continue;
111 if (old_item.GetId() == new_item.GetId())
112 return next_old_item_to_match++;
113 // Add the skipped old item into index.
114 old_display_items_index_.insert(&old_item.Client(), Vector<wtf_size_t>())
115 .stored_value->value.push_back(next_old_item_to_match);
116 }
117
118 // Didn't find matching old item in sequential matching. Look up the index.
119 auto it = old_display_items_index_.find(&new_item.Client());
120 if (it == old_display_items_index_.end())
121 return kNotFound;
122 for (auto i : it->value) {
123 const auto& old_item = old_paint_artifact_.GetDisplayItemList()[i];
124 if (old_item.GetId() == new_item.GetId())
125 return i;
126 }
127 return kNotFound;
128 }
129
AddRasterInvalidation(const DisplayItemClient & client,const IntRect & rect,PaintInvalidationReason reason,RasterInvalidator::ClientIsOldOrNew old_or_new)130 void DisplayItemRasterInvalidator::AddRasterInvalidation(
131 const DisplayItemClient& client,
132 const IntRect& rect,
133 PaintInvalidationReason reason,
134 RasterInvalidator::ClientIsOldOrNew old_or_new) {
135 IntRect r = invalidator_.ClipByLayerBounds(mapper_.MapVisualRect(rect));
136 if (r.IsEmpty())
137 return;
138
139 invalidator_.AddRasterInvalidation(raster_invalidation_function_, r, client,
140 reason, old_or_new);
141 }
142
GenerateRasterInvalidation(const DisplayItemClient & client,const IntRect * old_visual_rect,const IntRect * new_visual_rect,PaintInvalidationReason reason)143 void DisplayItemRasterInvalidator::GenerateRasterInvalidation(
144 const DisplayItemClient& client,
145 const IntRect* old_visual_rect,
146 const IntRect* new_visual_rect,
147 PaintInvalidationReason reason) {
148 if (!new_visual_rect || new_visual_rect->IsEmpty()) {
149 if (old_visual_rect && !old_visual_rect->IsEmpty()) {
150 AddRasterInvalidation(client, *old_visual_rect,
151 PaintInvalidationReason::kDisappeared,
152 kClientIsOld);
153 }
154 return;
155 }
156
157 if (!old_visual_rect || old_visual_rect->IsEmpty()) {
158 AddRasterInvalidation(client, *new_visual_rect,
159 PaintInvalidationReason::kAppeared, kClientIsNew);
160 return;
161 }
162
163 if (client.IsJustCreated()) {
164 // The old client has been deleted and the new client happens to be at the
165 // same address. They have no relationship.
166 AddRasterInvalidation(client, *old_visual_rect,
167 PaintInvalidationReason::kDisappeared, kClientIsOld);
168 AddRasterInvalidation(client, *new_visual_rect,
169 PaintInvalidationReason::kAppeared, kClientIsNew);
170 return;
171 }
172
173 if (IsFullPaintInvalidationReason(reason)) {
174 GenerateFullRasterInvalidation(client, *old_visual_rect, *new_visual_rect,
175 reason);
176 return;
177 }
178
179 GenerateIncrementalRasterInvalidation(client, *old_visual_rect,
180 *new_visual_rect);
181
182 IntRect partial_rect = client.PartialInvalidationVisualRect();
183 if (!partial_rect.IsEmpty())
184 AddRasterInvalidation(client, partial_rect, reason, kClientIsNew);
185 }
186
ComputeRightDelta(const IntPoint & location,const IntSize & old_size,const IntSize & new_size)187 static IntRect ComputeRightDelta(const IntPoint& location,
188 const IntSize& old_size,
189 const IntSize& new_size) {
190 int delta = new_size.Width() - old_size.Width();
191 if (delta > 0) {
192 return IntRect(location.X() + old_size.Width(), location.Y(), delta,
193 new_size.Height());
194 }
195 if (delta < 0) {
196 return IntRect(location.X() + new_size.Width(), location.Y(), -delta,
197 old_size.Height());
198 }
199 return IntRect();
200 }
201
ComputeBottomDelta(const IntPoint & location,const IntSize & old_size,const IntSize & new_size)202 static IntRect ComputeBottomDelta(const IntPoint& location,
203 const IntSize& old_size,
204 const IntSize& new_size) {
205 int delta = new_size.Height() - old_size.Height();
206 if (delta > 0) {
207 return IntRect(location.X(), location.Y() + old_size.Height(),
208 new_size.Width(), delta);
209 }
210 if (delta < 0) {
211 return IntRect(location.X(), location.Y() + new_size.Height(),
212 old_size.Width(), -delta);
213 }
214 return IntRect();
215 }
216
GenerateIncrementalRasterInvalidation(const DisplayItemClient & client,const IntRect & old_visual_rect,const IntRect & new_visual_rect)217 void DisplayItemRasterInvalidator::GenerateIncrementalRasterInvalidation(
218 const DisplayItemClient& client,
219 const IntRect& old_visual_rect,
220 const IntRect& new_visual_rect) {
221 DCHECK(old_visual_rect.Location() == new_visual_rect.Location());
222
223 IntRect right_delta =
224 ComputeRightDelta(new_visual_rect.Location(), old_visual_rect.Size(),
225 new_visual_rect.Size());
226 if (!right_delta.IsEmpty()) {
227 AddRasterInvalidation(client, right_delta,
228 PaintInvalidationReason::kIncremental, kClientIsNew);
229 }
230
231 IntRect bottom_delta =
232 ComputeBottomDelta(new_visual_rect.Location(), old_visual_rect.Size(),
233 new_visual_rect.Size());
234 if (!bottom_delta.IsEmpty()) {
235 AddRasterInvalidation(client, bottom_delta,
236 PaintInvalidationReason::kIncremental, kClientIsNew);
237 }
238 }
239
GenerateFullRasterInvalidation(const DisplayItemClient & client,const IntRect & old_visual_rect,const IntRect & new_visual_rect,PaintInvalidationReason reason)240 void DisplayItemRasterInvalidator::GenerateFullRasterInvalidation(
241 const DisplayItemClient& client,
242 const IntRect& old_visual_rect,
243 const IntRect& new_visual_rect,
244 PaintInvalidationReason reason) {
245 if (!new_visual_rect.Contains(old_visual_rect)) {
246 AddRasterInvalidation(client, old_visual_rect, reason, kClientIsNew);
247 if (old_visual_rect.Contains(new_visual_rect))
248 return;
249 }
250
251 AddRasterInvalidation(client, new_visual_rect, reason, kClientIsNew);
252 }
253
254 } // namespace blink
255