OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "core/paint/PaintLayerPainter.h" | 5 #include "core/paint/PaintLayerPainter.h" |
6 | 6 |
7 #include "core/frame/LocalFrame.h" | 7 #include "core/frame/LocalFrame.h" |
8 #include "core/layout/LayoutView.h" | 8 #include "core/layout/LayoutView.h" |
9 #include "core/paint/ClipPathClipper.h" | 9 #include "core/paint/ClipPathClipper.h" |
10 #include "core/paint/FilterPainter.h" | 10 #include "core/paint/FilterPainter.h" |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 // TODO(trchen): We haven't decided how to handle visual fragmentation with | 415 // TODO(trchen): We haven't decided how to handle visual fragmentation with |
416 // SPv2. Related thread | 416 // SPv2. Related thread |
417 // https://groups.google.com/a/chromium.org/forum/#!topic/graphics-dev/81XuW
Ff-mxM | 417 // https://groups.google.com/a/chromium.org/forum/#!topic/graphics-dev/81XuW
Ff-mxM |
418 if (fragmentPolicy == ForceSingleFragment || | 418 if (fragmentPolicy == ForceSingleFragment || |
419 RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 419 RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
420 m_paintLayer.appendSingleFragmentIgnoringPagination( | 420 m_paintLayer.appendSingleFragmentIgnoringPagination( |
421 layerFragments, localPaintingInfo.rootLayer, | 421 layerFragments, localPaintingInfo.rootLayer, |
422 localPaintingInfo.paintDirtyRect, cacheSlot, | 422 localPaintingInfo.paintDirtyRect, cacheSlot, |
423 IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, | 423 IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, |
424 localPaintingInfo.subPixelAccumulation); | 424 localPaintingInfo.subPixelAccumulation); |
425 } else if (!collectPaintFragmentsForPaginatedFixedPosition( | 425 } else if (isFixedPositionObjectInPagedMedia()) { |
426 paintingInfo, layerFragments)) { | 426 PaintLayerFragments singleFragment; |
| 427 m_paintLayer.appendSingleFragmentIgnoringPagination( |
| 428 singleFragment, localPaintingInfo.rootLayer, |
| 429 localPaintingInfo.paintDirtyRect, cacheSlot, |
| 430 IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, |
| 431 localPaintingInfo.subPixelAccumulation); |
| 432 repeatFixedPositionObjectInPages(singleFragment[0], paintingInfo, |
| 433 layerFragments); |
| 434 } else { |
427 m_paintLayer.collectFragments(layerFragments, localPaintingInfo.rootLayer, | 435 m_paintLayer.collectFragments(layerFragments, localPaintingInfo.rootLayer, |
428 localPaintingInfo.paintDirtyRect, cacheSlot, | 436 localPaintingInfo.paintDirtyRect, cacheSlot, |
429 IgnoreOverlayScrollbarSize, | 437 IgnoreOverlayScrollbarSize, |
430 respectOverflowClip, &offsetFromRoot, | 438 respectOverflowClip, &offsetFromRoot, |
431 localPaintingInfo.subPixelAccumulation); | 439 localPaintingInfo.subPixelAccumulation); |
432 } | 440 } |
433 | 441 |
434 if (shouldPaintContent) { | 442 if (shouldPaintContent) { |
435 // TODO(wangxianzhu): This is for old slow scrolling. Implement similar | 443 // TODO(wangxianzhu): This is for old slow scrolling. Implement similar |
436 // optimization for slimming paint v2. | 444 // optimization for slimming paint v2. |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 // fragment.layerBounds is set to the border box, not the bounding box, of | 587 // fragment.layerBounds is set to the border box, not the bounding box, of |
580 // the layer. | 588 // the layer. |
581 if (m_paintLayer.intersectsDamageRect(fragment.layerBounds, | 589 if (m_paintLayer.intersectsDamageRect(fragment.layerBounds, |
582 fragment.backgroundRect.rect(), | 590 fragment.backgroundRect.rect(), |
583 newOffsetFromRoot)) | 591 newOffsetFromRoot)) |
584 return true; | 592 return true; |
585 } | 593 } |
586 return false; | 594 return false; |
587 } | 595 } |
588 | 596 |
589 bool PaintLayerPainter::collectPaintFragmentsForPaginatedFixedPosition( | 597 inline bool PaintLayerPainter::isFixedPositionObjectInPagedMedia() { |
| 598 LayoutObject* object = m_paintLayer.layoutObject(); |
| 599 LayoutView* view = object->view(); |
| 600 return object->styleRef().position() == FixedPosition && |
| 601 object->container() == view && view->pageLogicalHeight() && |
| 602 // TODO(crbug.com/619094): Figure out the correct behaviour for fixed |
| 603 // position objects in paged media with vertical writing modes. |
| 604 view->isHorizontalWritingMode(); |
| 605 } |
| 606 |
| 607 // "For paged media, boxes with fixed positions are repeated on every page." |
| 608 // https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#fixed-positioning |
| 609 // TODO(wangxianzhu): Fold this into PaintLayer::collectFragments(). |
| 610 void PaintLayerPainter::repeatFixedPositionObjectInPages( |
| 611 const PaintLayerFragment& singleFragmentIgnoredPagination, |
590 const PaintLayerPaintingInfo& paintingInfo, | 612 const PaintLayerPaintingInfo& paintingInfo, |
591 PaintLayerFragments& layerFragments) { | 613 PaintLayerFragments& layerFragments) { |
592 LayoutObject* object = m_paintLayer.layoutObject(); | 614 DCHECK(isFixedPositionObjectInPagedMedia()); |
593 LayoutView* view = object->view(); | |
594 bool isFixedPosObjectInPagedMedia = | |
595 object->style()->position() == FixedPosition && | |
596 object->container() == view && view->pageLogicalHeight(); | |
597 | 615 |
598 // TODO(crbug.com/619094): Figure out the correct behaviour for fixed position | 616 LayoutView* view = m_paintLayer.layoutObject()->view(); |
599 // objects in paged media with vertical writing modes. | |
600 if (!isFixedPosObjectInPagedMedia || !view->isHorizontalWritingMode()) | |
601 return false; | |
602 | |
603 // "For paged media, boxes with fixed positions are repeated on every page." | |
604 // https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#fixed-positioning | |
605 unsigned pages = | 617 unsigned pages = |
606 ceilf(view->documentRect().height() / view->pageLogicalHeight()); | 618 ceilf(view->documentRect().height() / view->pageLogicalHeight()); |
607 LayoutPoint paginationOffset; | |
608 | 619 |
609 // The fixed position object is offset from the top of the page, so remove | 620 // The fixed position object is offset from the top of the page, so remove |
610 // any scroll offset. | 621 // any scroll offset. |
611 LayoutPoint offsetFromRoot; | 622 LayoutPoint offsetFromRoot; |
612 m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); | 623 m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); |
613 paginationOffset -= offsetFromRoot - m_paintLayer.location(); | 624 LayoutSize offsetAdjustment = m_paintLayer.location() - offsetFromRoot; |
| 625 layerFragments.append(singleFragmentIgnoredPagination); |
| 626 layerFragments[0].paginationOffset += offsetAdjustment; |
| 627 layerFragments[0].layerBounds.move(offsetAdjustment); |
614 | 628 |
615 for (unsigned i = 0; i < pages; i++) { | 629 LayoutPoint pageOffset(LayoutUnit(), view->pageLogicalHeight()); |
616 PaintLayerFragment fragment; | 630 for (unsigned i = 1; i < pages; i++) { |
617 fragment.backgroundRect = paintingInfo.paintDirtyRect; | 631 PaintLayerFragment fragment = layerFragments[i - 1]; |
618 fragment.paginationOffset = paginationOffset; | 632 fragment.paginationOffset += pageOffset; |
| 633 fragment.layerBounds.moveBy(pageOffset); |
619 layerFragments.append(fragment); | 634 layerFragments.append(fragment); |
620 paginationOffset += LayoutPoint(LayoutUnit(), view->pageLogicalHeight()); | |
621 } | 635 } |
622 return true; | |
623 } | 636 } |
624 | 637 |
625 PaintResult PaintLayerPainter::paintLayerWithTransform( | 638 PaintResult PaintLayerPainter::paintLayerWithTransform( |
626 GraphicsContext& context, | 639 GraphicsContext& context, |
627 const PaintLayerPaintingInfo& paintingInfo, | 640 const PaintLayerPaintingInfo& paintingInfo, |
628 PaintLayerFlags paintFlags) { | 641 PaintLayerFlags paintFlags) { |
629 TransformationMatrix layerTransform = | 642 TransformationMatrix layerTransform = |
630 m_paintLayer.renderableTransform(paintingInfo.getGlobalPaintFlags()); | 643 m_paintLayer.renderableTransform(paintingInfo.getGlobalPaintFlags()); |
631 // If the transform can't be inverted, then don't paint anything. | 644 // If the transform can't be inverted, then don't paint anything. |
632 if (!layerTransform.isInvertible()) | 645 if (!layerTransform.isInvertible()) |
633 return FullyPainted; | 646 return FullyPainted; |
634 | 647 |
635 // FIXME: We should make sure that we don't walk past paintingInfo.rootLayer | 648 // FIXME: We should make sure that we don't walk past paintingInfo.rootLayer |
636 // here. m_paintLayer may be the "root", and then we should avoid looking at | 649 // here. m_paintLayer may be the "root", and then we should avoid looking at |
637 // its parent. | 650 // its parent. |
638 PaintLayer* parentLayer = m_paintLayer.parent(); | 651 PaintLayer* parentLayer = m_paintLayer.parent(); |
639 | 652 |
640 LayoutObject* object = m_paintLayer.layoutObject(); | |
641 LayoutView* view = object->view(); | |
642 bool isFixedPosObjectInPagedMedia = | |
643 object->style()->position() == FixedPosition && | |
644 object->container() == view && view->pageLogicalHeight(); | |
645 PaintLayer* paginationLayer = m_paintLayer.enclosingPaginationLayer(); | 653 PaintLayer* paginationLayer = m_paintLayer.enclosingPaginationLayer(); |
646 PaintLayerFragments layerFragments; | 654 PaintLayerFragments layerFragments; |
647 if (!collectPaintFragmentsForPaginatedFixedPosition(paintingInfo, | 655 bool isFixedPositionObjectInPagedMedia = |
648 layerFragments)) { | 656 this->isFixedPositionObjectInPagedMedia(); |
649 if (paginationLayer) { | 657 if (!paginationLayer || isFixedPositionObjectInPagedMedia) { |
650 // FIXME: This is a mess. Look closely at this code and the code in Layer | 658 // We don't need to collect any fragments in the regular way here. We have |
651 // and fix any issues in it & refactor to make it obvious from code | 659 // already calculated a clip rectangle for the ancestry if it was needed, |
652 // structure what it does and that it's correct. | 660 // and clipping this layer is something that can be done further down the |
653 ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) | 661 // path, when the transform has been applied. |
654 ? UncachedClipRects | 662 PaintLayerFragment fragment; |
655 : PaintingClipRects; | 663 fragment.backgroundRect = paintingInfo.paintDirtyRect; |
656 ShouldRespectOverflowClipType respectOverflowClip = | 664 if (isFixedPositionObjectInPagedMedia) |
657 shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()); | 665 repeatFixedPositionObjectInPages(fragment, paintingInfo, layerFragments); |
658 // Calculate the transformed bounding box in the current coordinate space, | 666 else |
659 // to figure out which fragmentainers (e.g. columns) we need to visit. | |
660 LayoutRect transformedExtent = PaintLayer::transparencyClipBox( | |
661 &m_paintLayer, paginationLayer, | |
662 PaintLayer::PaintingTransparencyClipBox, | |
663 PaintLayer::RootOfTransparencyClipBox, | |
664 paintingInfo.subPixelAccumulation, | |
665 paintingInfo.getGlobalPaintFlags()); | |
666 // FIXME: we don't check if paginationLayer is within | |
667 // paintingInfo.rootLayer | |
668 // here. | |
669 paginationLayer->collectFragments( | |
670 layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, | |
671 cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, 0, | |
672 paintingInfo.subPixelAccumulation, &transformedExtent); | |
673 } else { | |
674 // We don't need to collect any fragments in the regular way here. We have | |
675 // already calculated a clip rectangle for the ancestry if it was needed, | |
676 // and clipping this layer is something that can be done further down the | |
677 // path, when the transform has been applied. | |
678 PaintLayerFragment fragment; | |
679 fragment.backgroundRect = paintingInfo.paintDirtyRect; | |
680 layerFragments.append(fragment); | 667 layerFragments.append(fragment); |
681 } | 668 } else { |
| 669 // FIXME: This is a mess. Look closely at this code and the code in Layer |
| 670 // and fix any issues in it & refactor to make it obvious from code |
| 671 // structure what it does and that it's correct. |
| 672 ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) |
| 673 ? UncachedClipRects |
| 674 : PaintingClipRects; |
| 675 ShouldRespectOverflowClipType respectOverflowClip = |
| 676 shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()); |
| 677 // Calculate the transformed bounding box in the current coordinate space, |
| 678 // to figure out which fragmentainers (e.g. columns) we need to visit. |
| 679 LayoutRect transformedExtent = PaintLayer::transparencyClipBox( |
| 680 &m_paintLayer, paginationLayer, PaintLayer::PaintingTransparencyClipBox, |
| 681 PaintLayer::RootOfTransparencyClipBox, |
| 682 paintingInfo.subPixelAccumulation, paintingInfo.getGlobalPaintFlags()); |
| 683 // FIXME: we don't check if paginationLayer is within |
| 684 // paintingInfo.rootLayer |
| 685 // here. |
| 686 paginationLayer->collectFragments( |
| 687 layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, |
| 688 cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, nullptr, |
| 689 paintingInfo.subPixelAccumulation, &transformedExtent); |
682 } | 690 } |
683 | 691 |
684 Optional<DisplayItemCacheSkipper> cacheSkipper; | 692 Optional<DisplayItemCacheSkipper> cacheSkipper; |
685 if (layerFragments.size() > 1) | 693 if (layerFragments.size() > 1) |
686 cacheSkipper.emplace(context); | 694 cacheSkipper.emplace(context); |
687 | 695 |
688 ClipRect ancestorBackgroundClipRect; | 696 ClipRect ancestorBackgroundClipRect; |
689 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 697 if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
690 if (parentLayer) { | 698 if (parentLayer) { |
691 // Calculate the clip rectangle that the ancestors establish. | 699 // Calculate the clip rectangle that the ancestors establish. |
692 ClipRectsContext clipRectsContext( | 700 ClipRectsContext clipRectsContext( |
693 paintingInfo.rootLayer, | 701 paintingInfo.rootLayer, |
694 (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects | 702 (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects |
695 : PaintingClipRects, | 703 : PaintingClipRects, |
696 IgnoreOverlayScrollbarSize); | 704 IgnoreOverlayScrollbarSize); |
697 if (shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()) == | 705 if (shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()) == |
698 IgnoreOverflowClip) | 706 IgnoreOverflowClip) |
699 clipRectsContext.setIgnoreOverflowClip(); | 707 clipRectsContext.setIgnoreOverflowClip(); |
700 ancestorBackgroundClipRect = | 708 ancestorBackgroundClipRect = |
701 m_paintLayer.clipper().backgroundClipRect(clipRectsContext); | 709 m_paintLayer.clipper().backgroundClipRect(clipRectsContext); |
702 } | 710 } |
703 } | 711 } |
704 | 712 |
705 PaintResult result = FullyPainted; | 713 PaintResult result = FullyPainted; |
706 for (const auto& fragment : layerFragments) { | 714 for (const auto& fragment : layerFragments) { |
707 Optional<LayerClipRecorder> clipRecorder; | 715 Optional<LayerClipRecorder> clipRecorder; |
708 if (parentLayer && !RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 716 if (parentLayer && !RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
709 ClipRect clipRectForFragment(ancestorBackgroundClipRect); | 717 ClipRect clipRectForFragment(ancestorBackgroundClipRect); |
710 // A fixed-position object is repeated on every page, but if it is clipped | 718 // A fixed-position object is repeated on every page instead of paginated, |
711 // by an ancestor layer then the repetitions are clipped out. | 719 // so we should apply the original ancestor clip rect. |
712 if (!isFixedPosObjectInPagedMedia) | 720 if (!isFixedPositionObjectInPagedMedia) |
713 clipRectForFragment.moveBy(fragment.paginationOffset); | 721 clipRectForFragment.moveBy(fragment.paginationOffset); |
714 clipRectForFragment.intersect(fragment.backgroundRect); | 722 clipRectForFragment.intersect(fragment.backgroundRect); |
715 if (clipRectForFragment.isEmpty()) | 723 if (clipRectForFragment.isEmpty()) |
716 continue; | 724 continue; |
717 if (needsToClip(paintingInfo, clipRectForFragment)) { | 725 if (needsToClip(paintingInfo, clipRectForFragment)) { |
718 clipRecorder.emplace(context, *parentLayer->layoutObject(), | 726 clipRecorder.emplace(context, *parentLayer->layoutObject(), |
719 DisplayItem::kClipLayerParent, clipRectForFragment, | 727 DisplayItem::kClipLayerParent, clipRectForFragment, |
720 &paintingInfo, fragment.paginationOffset, | 728 &paintingInfo, fragment.paginationOffset, |
721 paintFlags); | 729 paintFlags); |
722 } | 730 } |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1119 | 1127 |
1120 PaintLayerPaintingInfo paintingInfo(&m_paintLayer, | 1128 PaintLayerPaintingInfo paintingInfo(&m_paintLayer, |
1121 LayoutRect(enclosingIntRect(damageRect)), | 1129 LayoutRect(enclosingIntRect(damageRect)), |
1122 paintFlags, LayoutSize()); | 1130 paintFlags, LayoutSize()); |
1123 paint(context, paintingInfo, PaintLayerPaintingOverlayScrollbars); | 1131 paint(context, paintingInfo, PaintLayerPaintingOverlayScrollbars); |
1124 | 1132 |
1125 m_paintLayer.setContainsDirtyOverlayScrollbars(false); | 1133 m_paintLayer.setContainsDirtyOverlayScrollbars(false); |
1126 } | 1134 } |
1127 | 1135 |
1128 } // namespace blink | 1136 } // namespace blink |
OLD | NEW |