Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(535)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp

Issue 2729243002: Improve performance of GeometryMapper cache. (Closed)
Patch Set: none Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/graphics/paint/GeometryMapper.h" 5 #include "platform/graphics/paint/GeometryMapper.h"
6 6
7 #include "platform/RuntimeEnabledFeatures.h" 7 #include "platform/RuntimeEnabledFeatures.h"
8 #include "platform/geometry/LayoutRect.h" 8 #include "platform/geometry/LayoutRect.h"
9 9
10 namespace blink { 10 namespace blink {
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 return rect; 207 return rect;
208 208
209 const auto& transformMatrix = 209 const auto& transformMatrix =
210 localToAncestorMatrix(localTransformNode, ancestorTransformNode); 210 localToAncestorMatrix(localTransformNode, ancestorTransformNode);
211 DCHECK(transformMatrix.isInvertible()); 211 DCHECK(transformMatrix.isInvertible());
212 212
213 // TODO(chrishtr): Cache the inverse? 213 // TODO(chrishtr): Cache the inverse?
214 return transformMatrix.inverse().mapRect(rect); 214 return transformMatrix.inverse().mapRect(rect);
215 } 215 }
216 216
217 GeometryMapper::TransformCache& GeometryMapper::getTransformCache( 217 Vector<GeometryMapper::ClipCacheEntry>* GeometryMapper::getClipCacheEntries(
218 const TransformPaintPropertyNode* ancestor) { 218 const ClipPaintPropertyNode* descendantClip) {
219 auto addResult = m_transformCache.insert(ancestor, nullptr); 219 auto addResult = m_clipCache.insert(descendantClip, nullptr);
220 if (addResult.isNewEntry) 220 if (addResult.isNewEntry)
221 addResult.storedValue->value = WTF::wrapUnique(new TransformCache); 221 addResult.storedValue->value = WTF::wrapUnique(new Vector<ClipCacheEntry>);
222 return *addResult.storedValue->value; 222
223 return addResult.storedValue->value.get();
223 } 224 }
224 225
225 GeometryMapper::ClipCache& GeometryMapper::getClipCache( 226 const FloatClipRect* GeometryMapper::getClip(
226 const ClipPaintPropertyNode* ancestorClip, 227 const ClipPaintPropertyNode* descendantClip,
227 const TransformPaintPropertyNode* ancestorTransform) { 228 const ClipAndTransform& clipAndTransform) {
228 auto addResultTransform = m_clipCache.insert(ancestorClip, nullptr); 229 auto* clipCacheEntries = getClipCacheEntries(descendantClip);
229 if (addResultTransform.isNewEntry) { 230
230 addResultTransform.storedValue->value = 231 for (const auto& entry : *clipCacheEntries) {
231 WTF::wrapUnique(new TransformToClip); 232 if (entry.clipAndTransform == clipAndTransform) {
233 return &entry.clipRect;
234 }
235 }
236 return nullptr;
237 }
238
239 void GeometryMapper::setClip(const ClipPaintPropertyNode* descendantClip,
240 const ClipAndTransform& clipAndTransform,
241 const FloatClipRect& clip) {
242 auto* clipCacheEntries = getClipCacheEntries(descendantClip);
243 #if DCHECK_IS_ON
244 for (const auto& entry : clipCachEntries) {
245 if (entry.clipAndTransform == clipAndTransform)
246 DCHECK(false); // There should be no existing entry.
247 }
248 #endif
249 clipCacheEntries->push_back(ClipCacheEntry(clipAndTransform, clip));
250 }
251
252 Vector<GeometryMapper::TransformCacheEntry>*
253 GeometryMapper::getTransformCacheEntries(
254 const TransformPaintPropertyNode* descendantTransform) {
255 auto addResult = m_transformCache.insert(descendantTransform, nullptr);
256 if (addResult.isNewEntry) {
257 addResult.storedValue->value =
258 WTF::wrapUnique(new Vector<TransformCacheEntry>);
232 } 259 }
233 260
234 auto addResultClip = 261 return addResult.storedValue->value.get();
235 addResultTransform.storedValue->value->insert(ancestorTransform, nullptr); 262 }
236 if (addResultClip.isNewEntry)
237 addResultClip.storedValue->value = WTF::wrapUnique(new ClipCache);
238 263
239 return *addResultClip.storedValue->value; 264 const TransformationMatrix* GeometryMapper::getTransform(
265 const TransformPaintPropertyNode* descendantTransform,
266 const TransformPaintPropertyNode* ancestorTransform) {
267 auto* clipCacheEntries = getTransformCacheEntries(descendantTransform);
268
269 for (const auto& entry : *clipCacheEntries) {
270 if (entry.ancestorNode == ancestorTransform) {
271 return &entry.toAncestor;
272 }
273 }
274 return nullptr;
275 }
276
277 void GeometryMapper::setTransform(
278 const TransformPaintPropertyNode* descendantTransform,
279 const TransformPaintPropertyNode* ancestorTransform,
280 const TransformationMatrix& toAncestor) {
281 auto* transformCacheEntries = getTransformCacheEntries(descendantTransform);
282 #if DCHECK_IS_ON
283 for (const auto& entry : transformCacheEntries) {
284 if (entry.ancestorNode == ancestorTransform)
285 DCHECK(false); // There should be no existing entry.
286 }
287 #endif
288 transformCacheEntries->push_back(
289 TransformCacheEntry(ancestorTransform, toAncestor));
240 } 290 }
241 291
242 FloatClipRect GeometryMapper::localToAncestorClipRect( 292 FloatClipRect GeometryMapper::localToAncestorClipRect(
243 const PropertyTreeState& localState, 293 const PropertyTreeState& localState,
244 const PropertyTreeState& ancestorState) { 294 const PropertyTreeState& ancestorState) {
245 bool success = false; 295 bool success = false;
246 FloatClipRect result = 296 FloatClipRect result =
247 localToAncestorClipRectInternal(localState.clip(), ancestorState.clip(), 297 localToAncestorClipRectInternal(localState.clip(), ancestorState.clip(),
248 ancestorState.transform(), success); 298 ancestorState.transform(), success);
249 299
(...skipping 17 matching lines...) Expand all
267 const PropertyTreeState& sourceState, 317 const PropertyTreeState& sourceState,
268 const PropertyTreeState& destinationState, 318 const PropertyTreeState& destinationState,
269 bool& success) { 319 bool& success) {
270 FloatClipRect result = localToAncestorClipRectInternal( 320 FloatClipRect result = localToAncestorClipRectInternal(
271 sourceState.clip(), destinationState.clip(), destinationState.transform(), 321 sourceState.clip(), destinationState.clip(), destinationState.transform(),
272 success); 322 success);
273 // Success if destinationState is an ancestor state. 323 // Success if destinationState is an ancestor state.
274 if (success) 324 if (success)
275 return result; 325 return result;
276 326
277 // Otherwise first map to the lowest common ancestor, then map to destination. 327 // Otherwise first map to the lowest common ancestor, then map to
328 // destination.
278 const TransformPaintPropertyNode* lcaTransform = lowestCommonAncestor( 329 const TransformPaintPropertyNode* lcaTransform = lowestCommonAncestor(
279 sourceState.transform(), destinationState.transform()); 330 sourceState.transform(), destinationState.transform());
280 DCHECK(lcaTransform); 331 DCHECK(lcaTransform);
281 332
282 // Assume that the clip of destinationState is an ancestor of the clip of 333 // Assume that the clip of destinationState is an ancestor of the clip of
283 // sourceState and is under the space of lcaTransform. Otherwise 334 // sourceState and is under the space of lcaTransform. Otherwise
284 // localToAncestorClipRectInternal() will fail. 335 // localToAncestorClipRectInternal() will fail.
285 PropertyTreeState lcaState = destinationState; 336 PropertyTreeState lcaState = destinationState;
286 lcaState.setTransform(lcaTransform); 337 lcaState.setTransform(lcaTransform);
287 338
288 result = localToAncestorClipRectInternal(sourceState.clip(), lcaState.clip(), 339 result = localToAncestorClipRectInternal(sourceState.clip(), lcaState.clip(),
289 lcaState.transform(), success); 340 lcaState.transform(), success);
290 if (!success) { 341 if (!success) {
291 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { 342 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
292 // On SPv1 we may fail when the paint invalidation container creates an 343 // On SPv1 we may fail when the paint invalidation container creates an
293 // overflow clip (in ancestorState) which is not in localState of an 344 // overflow clip (in ancestorState) which is not in localState of an
294 // out-of-flow positioned descendant. See crbug.com/513108 and layout test 345 // out-of-flow positioned descendant. See crbug.com/513108 and layout
295 // compositing/overflow/handle-non-ancestor-clip-parent.html (run with 346 // test compositing/overflow/handle-non-ancestor-clip-parent.html (run
347 // with
296 // --enable-prefer-compositing-to-lcd-text) for details. 348 // --enable-prefer-compositing-to-lcd-text) for details.
Xianzhu 2017/03/07 16:58:46 Nit: join the above two lines.
chrishtr 2017/03/07 19:09:01 Done.
297 // Ignore it for SPv1 for now. 349 // Ignore it for SPv1 for now.
298 success = true; 350 success = true;
299 } 351 }
300 return result; 352 return result;
301 } 353 }
302 if (!result.isInfinite()) { 354 if (!result.isInfinite()) {
303 FloatRect final = ancestorToLocalRect(result.rect(), lcaTransform, 355 FloatRect final = ancestorToLocalRect(result.rect(), lcaTransform,
304 destinationState.transform()); 356 destinationState.transform());
305 result.setRect(final); 357 result.setRect(final);
306 } 358 }
307 return result; 359 return result;
308 } 360 }
309 361
310 FloatClipRect GeometryMapper::localToAncestorClipRectInternal( 362 const FloatClipRect& GeometryMapper::localToAncestorClipRectInternal(
311 const ClipPaintPropertyNode* descendant, 363 const ClipPaintPropertyNode* descendant,
312 const ClipPaintPropertyNode* ancestorClip, 364 const ClipPaintPropertyNode* ancestorClip,
313 const TransformPaintPropertyNode* ancestorTransform, 365 const TransformPaintPropertyNode* ancestorTransform,
314 bool& success) { 366 bool& success) {
315 FloatClipRect clip; 367 FloatClipRect clip;
316 if (descendant == ancestorClip) { 368 if (descendant == ancestorClip) {
317 success = true; 369 success = true;
318 // Return an infinite clip. 370 return m_infiniteClip;
319 return clip;
320 } 371 }
321 372
322 ClipCache& clipCache = getClipCache(ancestorClip, ancestorTransform);
323 const ClipPaintPropertyNode* clipNode = descendant; 373 const ClipPaintPropertyNode* clipNode = descendant;
324 Vector<const ClipPaintPropertyNode*> intermediateNodes; 374 Vector<const ClipPaintPropertyNode*> intermediateNodes;
325 375
376 ClipAndTransform clipAndTransform(ancestorClip, ancestorTransform);
377
326 // Iterate over the path from localState.clip to ancestorState.clip. Stop if 378 // Iterate over the path from localState.clip to ancestorState.clip. Stop if
327 // we've found a memoized (precomputed) clip for any particular node. 379 // we've found a memoized (precomputed) clip for any particular node.
328 while (clipNode && clipNode != ancestorClip) { 380 while (clipNode && clipNode != ancestorClip) {
329 auto it = clipCache.find(clipNode); 381 if (const FloatClipRect* cachedClip = getClip(clipNode, clipAndTransform)) {
330 if (it != clipCache.end()) { 382 clip = *cachedClip;
331 clip = it->value;
332 break; 383 break;
333 } 384 }
385
334 intermediateNodes.push_back(clipNode); 386 intermediateNodes.push_back(clipNode);
335 clipNode = clipNode->parent(); 387 clipNode = clipNode->parent();
336 } 388 }
337 if (!clipNode) { 389 if (!clipNode) {
338 success = false; 390 success = false;
339 return clip; 391 return m_infiniteClip;
340 } 392 }
341 393
342 // Iterate down from the top intermediate node found in the previous loop, 394 // Iterate down from the top intermediate node found in the previous loop,
343 // computing and memoizing clip rects as we go. 395 // computing and memoizing clip rects as we go.
344 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); 396 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend();
345 ++it) { 397 ++it) {
346 success = false; 398 success = false;
347 const TransformationMatrix& transformMatrix = localToAncestorMatrixInternal( 399 const TransformationMatrix& transformMatrix = localToAncestorMatrixInternal(
348 (*it)->localTransformSpace(), ancestorTransform, success); 400 (*it)->localTransformSpace(), ancestorTransform, success);
349 if (!success) 401 if (!success)
350 return clip; 402 return m_infiniteClip;
351 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); 403 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect());
352 clip.intersect(mappedRect); 404 clip.intersect(mappedRect);
353 if ((*it)->clipRect().isRounded()) 405 if ((*it)->clipRect().isRounded())
354 clip.setHasRadius(); 406 clip.setHasRadius();
355 clipCache.set(*it, clip); 407 setClip(*it, clipAndTransform, clip);
356 } 408 }
357 409
358 success = true; 410 success = true;
359 return clipCache.find(descendant)->value; 411 const FloatClipRect* cachedClip = getClip(descendant, clipAndTransform);
412 DCHECK(cachedClip);
413 return *cachedClip;
360 } 414 }
361 415
362 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( 416 const TransformationMatrix& GeometryMapper::localToAncestorMatrix(
363 const TransformPaintPropertyNode* localTransformNode, 417 const TransformPaintPropertyNode* localTransformNode,
364 const TransformPaintPropertyNode* ancestorTransformNode) { 418 const TransformPaintPropertyNode* ancestorTransformNode) {
365 bool success = false; 419 bool success = false;
366 const auto& result = localToAncestorMatrixInternal( 420 const auto& result = localToAncestorMatrixInternal(
367 localTransformNode, ancestorTransformNode, success); 421 localTransformNode, ancestorTransformNode, success);
368 DCHECK(success); 422 DCHECK(success);
369 return result; 423 return result;
370 } 424 }
371 425
372 const TransformationMatrix& GeometryMapper::localToAncestorMatrixInternal( 426 const TransformationMatrix& GeometryMapper::localToAncestorMatrixInternal(
373 const TransformPaintPropertyNode* localTransformNode, 427 const TransformPaintPropertyNode* localTransformNode,
374 const TransformPaintPropertyNode* ancestorTransformNode, 428 const TransformPaintPropertyNode* ancestorTransformNode,
375 bool& success) { 429 bool& success) {
376 if (localTransformNode == ancestorTransformNode) { 430 if (localTransformNode == ancestorTransformNode) {
377 success = true; 431 success = true;
378 return m_identity; 432 return m_identity;
379 } 433 }
380 434
381 TransformCache& transformCache = getTransformCache(ancestorTransformNode);
382
383 const TransformPaintPropertyNode* transformNode = localTransformNode; 435 const TransformPaintPropertyNode* transformNode = localTransformNode;
384 Vector<const TransformPaintPropertyNode*> intermediateNodes; 436 Vector<const TransformPaintPropertyNode*> intermediateNodes;
385 TransformationMatrix transformMatrix; 437 TransformationMatrix transformMatrix;
386 438
387 // Iterate over the path from localTransformNode to ancestorState.transform. 439 // Iterate over the path from localTransformNode to ancestorState.transform.
388 // Stop if we've found a memoized (precomputed) transform for any particular 440 // Stop if we've found a memoized (precomputed) transform for any particular
389 // node. 441 // node.
390 while (transformNode && transformNode != ancestorTransformNode) { 442 while (transformNode && transformNode != ancestorTransformNode) {
391 auto it = transformCache.find(transformNode); 443 if (const TransformationMatrix* cachedMatrix =
392 if (it != transformCache.end()) { 444 getTransform(transformNode, ancestorTransformNode)) {
393 transformMatrix = it->value; 445 transformMatrix = *cachedMatrix;
394 break; 446 break;
395 } 447 }
448
396 intermediateNodes.push_back(transformNode); 449 intermediateNodes.push_back(transformNode);
397 transformNode = transformNode->parent(); 450 transformNode = transformNode->parent();
398 } 451 }
399 if (!transformNode) { 452 if (!transformNode) {
400 success = false; 453 success = false;
401 return m_identity; 454 return m_identity;
402 } 455 }
403 456
404 // Iterate down from the top intermediate node found in the previous loop, 457 // Iterate down from the top intermediate node found in the previous loop,
405 // computing and memoizing transforms as we go. 458 // computing and memoizing transforms as we go.
406 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); 459 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend();
407 it++) { 460 it++) {
408 TransformationMatrix localTransformMatrix = (*it)->matrix(); 461 TransformationMatrix localTransformMatrix = (*it)->matrix();
409 localTransformMatrix.applyTransformOrigin((*it)->origin()); 462 localTransformMatrix.applyTransformOrigin((*it)->origin());
410 transformMatrix = transformMatrix * localTransformMatrix; 463 transformMatrix = transformMatrix * localTransformMatrix;
411 transformCache.set(*it, transformMatrix); 464 setTransform(*it, ancestorTransformNode, transformMatrix);
412 } 465 }
413 success = true; 466 success = true;
414 return transformCache.find(localTransformNode)->value; 467 const TransformationMatrix* cachedMatrix =
468 getTransform(localTransformNode, ancestorTransformNode);
469 DCHECK(cachedMatrix);
470 return *cachedMatrix;
415 } 471 }
416 472
417 void GeometryMapper::clearCache() { 473 void GeometryMapper::clearCache() {
418 m_transformCache.clear(); 474 m_transformCache.clear();
419 m_clipCache.clear(); 475 m_clipCache.clear();
420 } 476 }
421 477
422 namespace { 478 namespace {
423 479
424 template <typename NodeType> 480 template <typename NodeType>
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 const TransformPaintPropertyNode*, 526 const TransformPaintPropertyNode*,
471 const TransformPaintPropertyNode*); 527 const TransformPaintPropertyNode*);
472 template const ClipPaintPropertyNode* GeometryMapper::lowestCommonAncestor( 528 template const ClipPaintPropertyNode* GeometryMapper::lowestCommonAncestor(
473 const ClipPaintPropertyNode*, 529 const ClipPaintPropertyNode*,
474 const ClipPaintPropertyNode*); 530 const ClipPaintPropertyNode*);
475 template const ScrollPaintPropertyNode* GeometryMapper::lowestCommonAncestor( 531 template const ScrollPaintPropertyNode* GeometryMapper::lowestCommonAncestor(
476 const ScrollPaintPropertyNode*, 532 const ScrollPaintPropertyNode*,
477 const ScrollPaintPropertyNode*); 533 const ScrollPaintPropertyNode*);
478 534
479 } // namespace blink 535 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698