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 |