| 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( | |
| 218 const TransformPaintPropertyNode* ancestor) { | |
| 219 auto addResult = m_transformCache.insert(ancestor, nullptr); | |
| 220 if (addResult.isNewEntry) | |
| 221 addResult.storedValue->value = WTF::wrapUnique(new TransformCache); | |
| 222 return *addResult.storedValue->value; | |
| 223 } | |
| 224 | |
| 225 GeometryMapper::ClipCache& GeometryMapper::getClipCache( | |
| 226 const ClipPaintPropertyNode* ancestorClip, | |
| 227 const TransformPaintPropertyNode* ancestorTransform) { | |
| 228 auto addResultTransform = m_clipCache.insert(ancestorClip, nullptr); | |
| 229 if (addResultTransform.isNewEntry) { | |
| 230 addResultTransform.storedValue->value = | |
| 231 WTF::wrapUnique(new TransformToClip); | |
| 232 } | |
| 233 | |
| 234 auto addResultClip = | |
| 235 addResultTransform.storedValue->value->insert(ancestorTransform, nullptr); | |
| 236 if (addResultClip.isNewEntry) | |
| 237 addResultClip.storedValue->value = WTF::wrapUnique(new ClipCache); | |
| 238 | |
| 239 return *addResultClip.storedValue->value; | |
| 240 } | |
| 241 | |
| 242 FloatClipRect GeometryMapper::localToAncestorClipRect( | 217 FloatClipRect GeometryMapper::localToAncestorClipRect( |
| 243 const PropertyTreeState& localState, | 218 const PropertyTreeState& localState, |
| 244 const PropertyTreeState& ancestorState) { | 219 const PropertyTreeState& ancestorState) { |
| 245 bool success = false; | 220 bool success = false; |
| 246 FloatClipRect result = | 221 FloatClipRect result = |
| 247 localToAncestorClipRectInternal(localState.clip(), ancestorState.clip(), | 222 localToAncestorClipRectInternal(localState.clip(), ancestorState.clip(), |
| 248 ancestorState.transform(), success); | 223 ancestorState.transform(), success); |
| 249 | 224 |
| 250 DCHECK(success); | 225 DCHECK(success); |
| 251 | 226 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 267 const PropertyTreeState& sourceState, | 242 const PropertyTreeState& sourceState, |
| 268 const PropertyTreeState& destinationState, | 243 const PropertyTreeState& destinationState, |
| 269 bool& success) { | 244 bool& success) { |
| 270 FloatClipRect result = localToAncestorClipRectInternal( | 245 FloatClipRect result = localToAncestorClipRectInternal( |
| 271 sourceState.clip(), destinationState.clip(), destinationState.transform(), | 246 sourceState.clip(), destinationState.clip(), destinationState.transform(), |
| 272 success); | 247 success); |
| 273 // Success if destinationState is an ancestor state. | 248 // Success if destinationState is an ancestor state. |
| 274 if (success) | 249 if (success) |
| 275 return result; | 250 return result; |
| 276 | 251 |
| 277 // Otherwise first map to the lowest common ancestor, then map to destination. | 252 // Otherwise first map to the lowest common ancestor, then map to |
| 253 // destination. |
| 278 const TransformPaintPropertyNode* lcaTransform = lowestCommonAncestor( | 254 const TransformPaintPropertyNode* lcaTransform = lowestCommonAncestor( |
| 279 sourceState.transform(), destinationState.transform()); | 255 sourceState.transform(), destinationState.transform()); |
| 280 DCHECK(lcaTransform); | 256 DCHECK(lcaTransform); |
| 281 | 257 |
| 282 // Assume that the clip of destinationState is an ancestor of the clip of | 258 // Assume that the clip of destinationState is an ancestor of the clip of |
| 283 // sourceState and is under the space of lcaTransform. Otherwise | 259 // sourceState and is under the space of lcaTransform. Otherwise |
| 284 // localToAncestorClipRectInternal() will fail. | 260 // localToAncestorClipRectInternal() will fail. |
| 285 PropertyTreeState lcaState = destinationState; | 261 PropertyTreeState lcaState = destinationState; |
| 286 lcaState.setTransform(lcaTransform); | 262 lcaState.setTransform(lcaTransform); |
| 287 | 263 |
| 288 result = localToAncestorClipRectInternal(sourceState.clip(), lcaState.clip(), | 264 result = localToAncestorClipRectInternal(sourceState.clip(), lcaState.clip(), |
| 289 lcaState.transform(), success); | 265 lcaState.transform(), success); |
| 290 if (!success) { | 266 if (!success) { |
| 291 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 267 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| 292 // On SPv1 we may fail when the paint invalidation container creates an | 268 // On SPv1 we may fail when the paint invalidation container creates an |
| 293 // overflow clip (in ancestorState) which is not in localState of an | 269 // overflow clip (in ancestorState) which is not in localState of an |
| 294 // out-of-flow positioned descendant. See crbug.com/513108 and layout test | 270 // out-of-flow positioned descendant. See crbug.com/513108 and layout |
| 295 // compositing/overflow/handle-non-ancestor-clip-parent.html (run with | 271 // test compositing/overflow/handle-non-ancestor-clip-parent.html (run |
| 296 // --enable-prefer-compositing-to-lcd-text) for details. | 272 // with --enable-prefer-compositing-to-lcd-text) for details. |
| 297 // Ignore it for SPv1 for now. | 273 // Ignore it for SPv1 for now. |
| 298 success = true; | 274 success = true; |
| 299 } | 275 } |
| 300 return result; | 276 return result; |
| 301 } | 277 } |
| 302 if (!result.isInfinite()) { | 278 if (!result.isInfinite()) { |
| 303 FloatRect final = ancestorToLocalRect(result.rect(), lcaTransform, | 279 FloatRect final = ancestorToLocalRect(result.rect(), lcaTransform, |
| 304 destinationState.transform()); | 280 destinationState.transform()); |
| 305 result.setRect(final); | 281 result.setRect(final); |
| 306 } | 282 } |
| 307 return result; | 283 return result; |
| 308 } | 284 } |
| 309 | 285 |
| 310 FloatClipRect GeometryMapper::localToAncestorClipRectInternal( | 286 const FloatClipRect& GeometryMapper::localToAncestorClipRectInternal( |
| 311 const ClipPaintPropertyNode* descendant, | 287 const ClipPaintPropertyNode* descendant, |
| 312 const ClipPaintPropertyNode* ancestorClip, | 288 const ClipPaintPropertyNode* ancestorClip, |
| 313 const TransformPaintPropertyNode* ancestorTransform, | 289 const TransformPaintPropertyNode* ancestorTransform, |
| 314 bool& success) { | 290 bool& success) { |
| 315 FloatClipRect clip; | 291 FloatClipRect clip; |
| 316 if (descendant == ancestorClip) { | 292 if (descendant == ancestorClip) { |
| 317 success = true; | 293 success = true; |
| 318 // Return an infinite clip. | 294 return m_infiniteClip; |
| 319 return clip; | |
| 320 } | 295 } |
| 321 | 296 |
| 322 ClipCache& clipCache = getClipCache(ancestorClip, ancestorTransform); | |
| 323 const ClipPaintPropertyNode* clipNode = descendant; | 297 const ClipPaintPropertyNode* clipNode = descendant; |
| 324 Vector<const ClipPaintPropertyNode*> intermediateNodes; | 298 Vector<const ClipPaintPropertyNode*> intermediateNodes; |
| 325 | 299 |
| 300 GeometryMapperClipCache::ClipAndTransform clipAndTransform(ancestorClip, |
| 301 ancestorTransform); |
| 326 // Iterate over the path from localState.clip to ancestorState.clip. Stop if | 302 // Iterate over the path from localState.clip to ancestorState.clip. Stop if |
| 327 // we've found a memoized (precomputed) clip for any particular node. | 303 // we've found a memoized (precomputed) clip for any particular node. |
| 328 while (clipNode && clipNode != ancestorClip) { | 304 while (clipNode && clipNode != ancestorClip) { |
| 329 auto it = clipCache.find(clipNode); | 305 if (const FloatClipRect* cachedClip = |
| 330 if (it != clipCache.end()) { | 306 clipNode->getClipCache().getCachedClip(clipAndTransform)) { |
| 331 clip = it->value; | 307 clip = *cachedClip; |
| 332 break; | 308 break; |
| 333 } | 309 } |
| 310 |
| 334 intermediateNodes.push_back(clipNode); | 311 intermediateNodes.push_back(clipNode); |
| 335 clipNode = clipNode->parent(); | 312 clipNode = clipNode->parent(); |
| 336 } | 313 } |
| 337 if (!clipNode) { | 314 if (!clipNode) { |
| 338 success = false; | 315 success = false; |
| 339 return clip; | 316 return m_infiniteClip; |
| 340 } | 317 } |
| 341 | 318 |
| 342 // Iterate down from the top intermediate node found in the previous loop, | 319 // Iterate down from the top intermediate node found in the previous loop, |
| 343 // computing and memoizing clip rects as we go. | 320 // computing and memoizing clip rects as we go. |
| 344 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 321 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
| 345 ++it) { | 322 ++it) { |
| 346 success = false; | 323 success = false; |
| 347 const TransformationMatrix& transformMatrix = localToAncestorMatrixInternal( | 324 const TransformationMatrix& transformMatrix = localToAncestorMatrixInternal( |
| 348 (*it)->localTransformSpace(), ancestorTransform, success); | 325 (*it)->localTransformSpace(), ancestorTransform, success); |
| 349 if (!success) | 326 if (!success) |
| 350 return clip; | 327 return m_infiniteClip; |
| 351 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); | 328 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); |
| 352 clip.intersect(mappedRect); | 329 clip.intersect(mappedRect); |
| 353 if ((*it)->clipRect().isRounded()) | 330 if ((*it)->clipRect().isRounded()) |
| 354 clip.setHasRadius(); | 331 clip.setHasRadius(); |
| 355 clipCache.set(*it, clip); | 332 (*it)->getClipCache().setCachedClip(clipAndTransform, clip); |
| 356 } | 333 } |
| 357 | 334 |
| 358 success = true; | 335 success = true; |
| 359 return clipCache.find(descendant)->value; | 336 |
| 337 const FloatClipRect* cachedClip = |
| 338 descendant->getClipCache().getCachedClip(clipAndTransform); |
| 339 DCHECK(cachedClip); |
| 340 return *cachedClip; |
| 360 } | 341 } |
| 361 | 342 |
| 362 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( | 343 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( |
| 363 const TransformPaintPropertyNode* localTransformNode, | 344 const TransformPaintPropertyNode* localTransformNode, |
| 364 const TransformPaintPropertyNode* ancestorTransformNode) { | 345 const TransformPaintPropertyNode* ancestorTransformNode) { |
| 365 bool success = false; | 346 bool success = false; |
| 366 const auto& result = localToAncestorMatrixInternal( | 347 const auto& result = localToAncestorMatrixInternal( |
| 367 localTransformNode, ancestorTransformNode, success); | 348 localTransformNode, ancestorTransformNode, success); |
| 368 DCHECK(success); | 349 DCHECK(success); |
| 369 return result; | 350 return result; |
| 370 } | 351 } |
| 371 | 352 |
| 372 const TransformationMatrix& GeometryMapper::localToAncestorMatrixInternal( | 353 const TransformationMatrix& GeometryMapper::localToAncestorMatrixInternal( |
| 373 const TransformPaintPropertyNode* localTransformNode, | 354 const TransformPaintPropertyNode* localTransformNode, |
| 374 const TransformPaintPropertyNode* ancestorTransformNode, | 355 const TransformPaintPropertyNode* ancestorTransformNode, |
| 375 bool& success) { | 356 bool& success) { |
| 376 if (localTransformNode == ancestorTransformNode) { | 357 if (localTransformNode == ancestorTransformNode) { |
| 377 success = true; | 358 success = true; |
| 378 return m_identity; | 359 return m_identity; |
| 379 } | 360 } |
| 380 | 361 |
| 381 TransformCache& transformCache = getTransformCache(ancestorTransformNode); | |
| 382 | |
| 383 const TransformPaintPropertyNode* transformNode = localTransformNode; | 362 const TransformPaintPropertyNode* transformNode = localTransformNode; |
| 384 Vector<const TransformPaintPropertyNode*> intermediateNodes; | 363 Vector<const TransformPaintPropertyNode*> intermediateNodes; |
| 385 TransformationMatrix transformMatrix; | 364 TransformationMatrix transformMatrix; |
| 386 | 365 |
| 387 // Iterate over the path from localTransformNode to ancestorState.transform. | 366 // Iterate over the path from localTransformNode to ancestorState.transform. |
| 388 // Stop if we've found a memoized (precomputed) transform for any particular | 367 // Stop if we've found a memoized (precomputed) transform for any particular |
| 389 // node. | 368 // node. |
| 390 while (transformNode && transformNode != ancestorTransformNode) { | 369 while (transformNode && transformNode != ancestorTransformNode) { |
| 391 auto it = transformCache.find(transformNode); | 370 if (const TransformationMatrix* cachedMatrix = |
| 392 if (it != transformCache.end()) { | 371 transformNode->getTransformCache().getCachedTransform( |
| 393 transformMatrix = it->value; | 372 ancestorTransformNode)) { |
| 373 transformMatrix = *cachedMatrix; |
| 394 break; | 374 break; |
| 395 } | 375 } |
| 376 |
| 396 intermediateNodes.push_back(transformNode); | 377 intermediateNodes.push_back(transformNode); |
| 397 transformNode = transformNode->parent(); | 378 transformNode = transformNode->parent(); |
| 398 } | 379 } |
| 399 if (!transformNode) { | 380 if (!transformNode) { |
| 400 success = false; | 381 success = false; |
| 401 return m_identity; | 382 return m_identity; |
| 402 } | 383 } |
| 403 | 384 |
| 404 // Iterate down from the top intermediate node found in the previous loop, | 385 // Iterate down from the top intermediate node found in the previous loop, |
| 405 // computing and memoizing transforms as we go. | 386 // computing and memoizing transforms as we go. |
| 406 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 387 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
| 407 it++) { | 388 it++) { |
| 408 TransformationMatrix localTransformMatrix = (*it)->matrix(); | 389 TransformationMatrix localTransformMatrix = (*it)->matrix(); |
| 409 localTransformMatrix.applyTransformOrigin((*it)->origin()); | 390 localTransformMatrix.applyTransformOrigin((*it)->origin()); |
| 410 transformMatrix = transformMatrix * localTransformMatrix; | 391 transformMatrix = transformMatrix * localTransformMatrix; |
| 411 transformCache.set(*it, transformMatrix); | 392 (*it)->getTransformCache().setCachedTransform(ancestorTransformNode, |
| 393 transformMatrix); |
| 412 } | 394 } |
| 413 success = true; | 395 success = true; |
| 414 return transformCache.find(localTransformNode)->value; | 396 const TransformationMatrix* cachedMatrix = |
| 397 localTransformNode->getTransformCache().getCachedTransform( |
| 398 ancestorTransformNode); |
| 399 DCHECK(cachedMatrix); |
| 400 return *cachedMatrix; |
| 415 } | 401 } |
| 416 | 402 |
| 417 void GeometryMapper::clearCache() { | 403 void GeometryMapper::clearCache() { |
| 418 m_transformCache.clear(); | 404 GeometryMapperTransformCache::clearCache(); |
| 419 m_clipCache.clear(); | 405 GeometryMapperClipCache::clearCache(); |
| 420 } | 406 } |
| 421 | 407 |
| 422 namespace { | 408 namespace { |
| 423 | 409 |
| 424 template <typename NodeType> | 410 template <typename NodeType> |
| 425 unsigned nodeDepth(const NodeType* node) { | 411 unsigned nodeDepth(const NodeType* node) { |
| 426 unsigned depth = 0; | 412 unsigned depth = 0; |
| 427 while (node) { | 413 while (node) { |
| 428 depth++; | 414 depth++; |
| 429 node = node->parent(); | 415 node = node->parent(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 const TransformPaintPropertyNode*, | 456 const TransformPaintPropertyNode*, |
| 471 const TransformPaintPropertyNode*); | 457 const TransformPaintPropertyNode*); |
| 472 template const ClipPaintPropertyNode* GeometryMapper::lowestCommonAncestor( | 458 template const ClipPaintPropertyNode* GeometryMapper::lowestCommonAncestor( |
| 473 const ClipPaintPropertyNode*, | 459 const ClipPaintPropertyNode*, |
| 474 const ClipPaintPropertyNode*); | 460 const ClipPaintPropertyNode*); |
| 475 template const ScrollPaintPropertyNode* GeometryMapper::lowestCommonAncestor( | 461 template const ScrollPaintPropertyNode* GeometryMapper::lowestCommonAncestor( |
| 476 const ScrollPaintPropertyNode*, | 462 const ScrollPaintPropertyNode*, |
| 477 const ScrollPaintPropertyNode*); | 463 const ScrollPaintPropertyNode*); |
| 478 | 464 |
| 479 } // namespace blink | 465 } // namespace blink |
| OLD | NEW |