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