OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |