| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/PaintPropertyTreeBuilderTest.h" |
| 6 |
| 5 #include "core/html/HTMLIFrameElement.h" | 7 #include "core/html/HTMLIFrameElement.h" |
| 6 #include "core/layout/LayoutTestHelper.h" | |
| 7 #include "core/layout/LayoutTreeAsText.h" | 8 #include "core/layout/LayoutTreeAsText.h" |
| 8 #include "core/layout/api/LayoutViewItem.h" | 9 #include "core/layout/api/LayoutViewItem.h" |
| 9 #include "core/paint/ObjectPaintProperties.h" | 10 #include "core/paint/ObjectPaintProperties.h" |
| 10 #include "core/paint/PaintPropertyTreePrinter.h" | 11 #include "core/paint/PaintPropertyTreePrinter.h" |
| 11 #include "platform/graphics/paint/GeometryMapper.h" | 12 #include "platform/graphics/paint/GeometryMapper.h" |
| 12 #include "platform/graphics/paint/ScrollPaintPropertyNode.h" | 13 #include "platform/graphics/paint/ScrollPaintPropertyNode.h" |
| 13 #include "platform/graphics/paint/TransformPaintPropertyNode.h" | 14 #include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| 14 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h" | |
| 15 #include "platform/testing/UnitTestHelpers.h" | |
| 16 #include "platform/text/TextStream.h" | 15 #include "platform/text/TextStream.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 #include "wtf/HashMap.h" | 16 #include "wtf/HashMap.h" |
| 19 #include "wtf/Vector.h" | 17 #include "wtf/Vector.h" |
| 20 | 18 |
| 21 namespace blink { | 19 namespace blink { |
| 22 | 20 |
| 23 typedef bool TestParamRootLayerScrolling; | 21 void PaintPropertyTreeBuilderTest::loadTestData(const char* fileName) { |
| 24 class PaintPropertyTreeBuilderTest | 22 String fullPath = testing::blinkRootDir(); |
| 25 : public ::testing::WithParamInterface<TestParamRootLayerScrolling>, | 23 fullPath.append("/Source/core/paint/test_data/"); |
| 26 private ScopedSlimmingPaintV2ForTest, | 24 fullPath.append(fileName); |
| 27 private ScopedRootLayerScrollingForTest, | 25 RefPtr<SharedBuffer> inputBuffer = testing::readFromFile(fullPath); |
| 28 public RenderingTest { | 26 setBodyInnerHTML(String(inputBuffer->data(), inputBuffer->size())); |
| 29 public: | 27 } |
| 30 PaintPropertyTreeBuilderTest() | |
| 31 : ScopedSlimmingPaintV2ForTest(true), | |
| 32 ScopedRootLayerScrollingForTest(GetParam()), | |
| 33 RenderingTest(SingleChildFrameLoaderClient::create()) {} | |
| 34 | 28 |
| 35 void loadTestData(const char* fileName) { | 29 const TransformPaintPropertyNode* |
| 36 String fullPath = testing::blinkRootDir(); | 30 PaintPropertyTreeBuilderTest::framePreTranslation() { |
| 37 fullPath.append("/Source/core/paint/test_data/"); | 31 FrameView* frameView = document().view(); |
| 38 fullPath.append(fileName); | 32 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) |
| 39 RefPtr<SharedBuffer> inputBuffer = testing::readFromFile(fullPath); | 33 return frameView->layoutView()->paintProperties()->paintOffsetTranslation(); |
| 40 setBodyInnerHTML(String(inputBuffer->data(), inputBuffer->size())); | 34 return frameView->preTranslation(); |
| 41 } | 35 } |
| 42 | 36 |
| 43 const TransformPaintPropertyNode* framePreTranslation() { | 37 const TransformPaintPropertyNode* |
| 44 FrameView* frameView = document().view(); | 38 PaintPropertyTreeBuilderTest::frameScrollTranslation() { |
| 45 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) | 39 FrameView* frameView = document().view(); |
| 46 return frameView->layoutView() | 40 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) |
| 47 ->paintProperties() | 41 return frameView->layoutView()->paintProperties()->scrollTranslation(); |
| 48 ->paintOffsetTranslation(); | 42 return frameView->scrollTranslation(); |
| 49 return frameView->preTranslation(); | 43 } |
| 50 } | |
| 51 | 44 |
| 52 const TransformPaintPropertyNode* frameScrollTranslation() { | 45 const ClipPaintPropertyNode* PaintPropertyTreeBuilderTest::frameContentClip() { |
| 53 FrameView* frameView = document().view(); | 46 FrameView* frameView = document().view(); |
| 54 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) | 47 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) |
| 55 return frameView->layoutView()->paintProperties()->scrollTranslation(); | 48 return frameView->layoutView()->paintProperties()->overflowClip(); |
| 56 return frameView->scrollTranslation(); | 49 return frameView->contentClip(); |
| 57 } | 50 } |
| 58 | 51 |
| 59 const ClipPaintPropertyNode* frameContentClip() { | 52 const ScrollPaintPropertyNode* PaintPropertyTreeBuilderTest::frameScroll( |
| 60 FrameView* frameView = document().view(); | 53 FrameView* frameView) { |
| 61 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) | 54 if (!frameView) |
| 62 return frameView->layoutView()->paintProperties()->overflowClip(); | 55 frameView = document().view(); |
| 63 return frameView->contentClip(); | 56 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) |
| 64 } | 57 return frameView->layoutView()->paintProperties()->scroll(); |
| 58 return frameView->scroll(); |
| 59 } |
| 65 | 60 |
| 66 const ScrollPaintPropertyNode* frameScroll(FrameView* frameView = nullptr) { | 61 LayoutPoint PaintPropertyTreeBuilderTest::paintOffset( |
| 67 if (!frameView) | 62 const LayoutObject* object) { |
| 68 frameView = document().view(); | 63 return object->paintProperties()->localBorderBoxProperties()->paintOffset; |
| 69 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) | 64 } |
| 70 return frameView->layoutView()->paintProperties()->scroll(); | |
| 71 return frameView->scroll(); | |
| 72 } | |
| 73 | |
| 74 LayoutPoint paintOffset(const LayoutObject* object) { | |
| 75 return object->paintProperties()->localBorderBoxProperties()->paintOffset; | |
| 76 } | |
| 77 | |
| 78 private: | |
| 79 void SetUp() override { | |
| 80 Settings::setMockScrollbarsEnabled(true); | |
| 81 | |
| 82 RenderingTest::SetUp(); | |
| 83 enableCompositing(); | |
| 84 } | |
| 85 | |
| 86 void TearDown() override { | |
| 87 RenderingTest::TearDown(); | |
| 88 | |
| 89 Settings::setMockScrollbarsEnabled(false); | |
| 90 } | |
| 91 }; | |
| 92 | 65 |
| 93 #define CHECK_VISUAL_RECT(expected, sourceLayoutObject, ancestorLayoutObject, \ | 66 #define CHECK_VISUAL_RECT(expected, sourceLayoutObject, ancestorLayoutObject, \ |
| 94 slopFactor) \ | 67 slopFactor) \ |
| 95 do { \ | 68 do { \ |
| 96 GeometryMapper geometryMapper; \ | 69 GeometryMapper geometryMapper; \ |
| 97 LayoutRect source((sourceLayoutObject)->localVisualRect()); \ | 70 LayoutRect source((sourceLayoutObject)->localVisualRect()); \ |
| 98 source.moveBy((sourceLayoutObject) \ | 71 source.moveBy((sourceLayoutObject) \ |
| 99 ->paintProperties() \ | 72 ->paintProperties() \ |
| 100 ->localBorderBoxProperties() \ | 73 ->localBorderBoxProperties() \ |
| 101 ->paintOffset); \ | 74 ->paintOffset); \ |
| (...skipping 2586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2688 setBodyInnerHTML( | 2661 setBodyInnerHTML( |
| 2689 "<svg id='svg' xmlns='http://www.w3.org/2000/svg' width='100px' " | 2662 "<svg id='svg' xmlns='http://www.w3.org/2000/svg' width='100px' " |
| 2690 "height='100px' style='overflow: visible'>" | 2663 "height='100px' style='overflow: visible'>" |
| 2691 " <rect width='200' height='200' fill='red' />" | 2664 " <rect width='200' height='200' fill='red' />" |
| 2692 "</svg>"); | 2665 "</svg>"); |
| 2693 | 2666 |
| 2694 EXPECT_FALSE( | 2667 EXPECT_FALSE( |
| 2695 getLayoutObjectByElementId("svg")->paintProperties()->overflowClip()); | 2668 getLayoutObjectByElementId("svg")->paintProperties()->overflowClip()); |
| 2696 } | 2669 } |
| 2697 | 2670 |
| 2698 TEST_P(PaintPropertyTreeBuilderTest, | |
| 2699 ThreadedScrollingDisabledMainThreadScrollReason) { | |
| 2700 setBodyInnerHTML( | |
| 2701 "<style>" | |
| 2702 " #overflowA {" | |
| 2703 " position: absolute;" | |
| 2704 " overflow: scroll;" | |
| 2705 " width: 20px;" | |
| 2706 " height: 20px;" | |
| 2707 " }" | |
| 2708 " .forceScroll {" | |
| 2709 " height: 4000px;" | |
| 2710 " }" | |
| 2711 "</style>" | |
| 2712 "<div id='overflowA'>" | |
| 2713 " <div class='forceScroll'></div>" | |
| 2714 "</div>" | |
| 2715 "<div class='forceScroll'></div>"); | |
| 2716 Element* overflowA = document().getElementById("overflowA"); | |
| 2717 EXPECT_FALSE(frameScroll()->threadedScrollingDisabled()); | |
| 2718 EXPECT_FALSE(overflowA->layoutObject() | |
| 2719 ->paintProperties() | |
| 2720 ->scroll() | |
| 2721 ->threadedScrollingDisabled()); | |
| 2722 | |
| 2723 document().settings()->setThreadedScrollingEnabled(false); | |
| 2724 // TODO(pdr): The main thread scrolling setting should invalidate properties. | |
| 2725 document().view()->setNeedsPaintPropertyUpdate(); | |
| 2726 overflowA->layoutObject()->setNeedsPaintPropertyUpdate(); | |
| 2727 document().view()->updateAllLifecyclePhases(); | |
| 2728 | |
| 2729 EXPECT_TRUE(frameScroll()->threadedScrollingDisabled()); | |
| 2730 EXPECT_TRUE(overflowA->layoutObject() | |
| 2731 ->paintProperties() | |
| 2732 ->scroll() | |
| 2733 ->threadedScrollingDisabled()); | |
| 2734 } | |
| 2735 | |
| 2736 TEST_P(PaintPropertyTreeBuilderTest, | |
| 2737 BackgroundAttachmentFixedMainThreadScrollReasonsWithNestedScrollers) { | |
| 2738 setBodyInnerHTML( | |
| 2739 "<style>" | |
| 2740 " #overflowA {" | |
| 2741 " position: absolute;" | |
| 2742 " overflow: scroll;" | |
| 2743 " width: 20px;" | |
| 2744 " height: 20px;" | |
| 2745 " }" | |
| 2746 " #overflowB {" | |
| 2747 " position: absolute;" | |
| 2748 " overflow: scroll;" | |
| 2749 " width: 5px;" | |
| 2750 " height: 3px;" | |
| 2751 " }" | |
| 2752 " .backgroundAttachmentFixed {" | |
| 2753 " background-image: url('foo');" | |
| 2754 " background-attachment: fixed;" | |
| 2755 " }" | |
| 2756 " .forceScroll {" | |
| 2757 " height: 4000px;" | |
| 2758 " }" | |
| 2759 "</style>" | |
| 2760 "<div id='overflowA'>" | |
| 2761 " <div id='overflowB' class='backgroundAttachmentFixed'>" | |
| 2762 " <div class='forceScroll'></div>" | |
| 2763 " </div>" | |
| 2764 " <div class='forceScroll'></div>" | |
| 2765 "</div>" | |
| 2766 "<div class='forceScroll'></div>"); | |
| 2767 Element* overflowA = document().getElementById("overflowA"); | |
| 2768 Element* overflowB = document().getElementById("overflowB"); | |
| 2769 | |
| 2770 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants()); | |
| 2771 EXPECT_TRUE(overflowA->layoutObject() | |
| 2772 ->paintProperties() | |
| 2773 ->scroll() | |
| 2774 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2775 EXPECT_FALSE(overflowB->layoutObject() | |
| 2776 ->paintProperties() | |
| 2777 ->scroll() | |
| 2778 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2779 | |
| 2780 // Removing a main thread scrolling reason should update the entire tree. | |
| 2781 overflowB->removeAttribute("class"); | |
| 2782 document().view()->updateAllLifecyclePhases(); | |
| 2783 EXPECT_FALSE(frameScroll()->hasBackgroundAttachmentFixedDescendants()); | |
| 2784 EXPECT_FALSE(overflowA->layoutObject() | |
| 2785 ->paintProperties() | |
| 2786 ->scroll() | |
| 2787 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2788 EXPECT_FALSE(overflowB->layoutObject() | |
| 2789 ->paintProperties() | |
| 2790 ->scroll() | |
| 2791 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2792 | |
| 2793 // Adding a main thread scrolling reason should update the entire tree. | |
| 2794 overflowB->setAttribute(HTMLNames::classAttr, "backgroundAttachmentFixed"); | |
| 2795 document().view()->updateAllLifecyclePhases(); | |
| 2796 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants()); | |
| 2797 EXPECT_TRUE(overflowA->layoutObject() | |
| 2798 ->paintProperties() | |
| 2799 ->scroll() | |
| 2800 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2801 EXPECT_FALSE(overflowB->layoutObject() | |
| 2802 ->paintProperties() | |
| 2803 ->scroll() | |
| 2804 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2805 } | |
| 2806 | |
| 2807 TEST_P(PaintPropertyTreeBuilderTest, MainThreadScrollReasonsWithoutScrolling) { | 2671 TEST_P(PaintPropertyTreeBuilderTest, MainThreadScrollReasonsWithoutScrolling) { |
| 2808 setBodyInnerHTML( | 2672 setBodyInnerHTML( |
| 2809 "<style>" | 2673 "<style>" |
| 2810 " #overflow {" | 2674 " #overflow {" |
| 2811 " overflow: scroll;" | 2675 " overflow: scroll;" |
| 2812 " width: 100px;" | 2676 " width: 100px;" |
| 2813 " height: 100px;" | 2677 " height: 100px;" |
| 2814 " }" | 2678 " }" |
| 2815 " .backgroundAttachmentFixed {" | 2679 " .backgroundAttachmentFixed {" |
| 2816 " background-image: url('foo');" | 2680 " background-image: url('foo');" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2827 "</div>" | 2691 "</div>" |
| 2828 "<div class='forceScroll'></div>"); | 2692 "<div class='forceScroll'></div>"); |
| 2829 Element* overflow = document().getElementById("overflow"); | 2693 Element* overflow = document().getElementById("overflow"); |
| 2830 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants()); | 2694 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants()); |
| 2831 EXPECT_TRUE(overflow->layoutObject() | 2695 EXPECT_TRUE(overflow->layoutObject() |
| 2832 ->paintProperties() | 2696 ->paintProperties() |
| 2833 ->scroll() | 2697 ->scroll() |
| 2834 ->hasBackgroundAttachmentFixedDescendants()); | 2698 ->hasBackgroundAttachmentFixedDescendants()); |
| 2835 } | 2699 } |
| 2836 | 2700 |
| 2837 TEST_P(PaintPropertyTreeBuilderTest, | |
| 2838 BackgroundAttachmentFixedMainThreadScrollReasonsWithFixedScroller) { | |
| 2839 setBodyInnerHTML( | |
| 2840 "<style>" | |
| 2841 " #overflowA {" | |
| 2842 " position: absolute;" | |
| 2843 " overflow: scroll;" | |
| 2844 " width: 20px;" | |
| 2845 " height: 20px;" | |
| 2846 " }" | |
| 2847 " #overflowB {" | |
| 2848 " position: fixed;" | |
| 2849 " overflow: scroll;" | |
| 2850 " width: 5px;" | |
| 2851 " height: 3px;" | |
| 2852 " }" | |
| 2853 " .backgroundAttachmentFixed {" | |
| 2854 " background-image: url('foo');" | |
| 2855 " background-attachment: fixed;" | |
| 2856 " }" | |
| 2857 " .forceScroll {" | |
| 2858 " height: 4000px;" | |
| 2859 " }" | |
| 2860 "</style>" | |
| 2861 "<div id='overflowA'>" | |
| 2862 " <div id='overflowB' class='backgroundAttachmentFixed'>" | |
| 2863 " <div class='forceScroll'></div>" | |
| 2864 " </div>" | |
| 2865 " <div class='forceScroll'></div>" | |
| 2866 "</div>" | |
| 2867 "<div class='forceScroll'></div>"); | |
| 2868 Element* overflowA = document().getElementById("overflowA"); | |
| 2869 Element* overflowB = document().getElementById("overflowB"); | |
| 2870 | |
| 2871 // This should be false. We are not as strict about main thread scrolling | |
| 2872 // reasons as we could be. | |
| 2873 EXPECT_TRUE(overflowA->layoutObject() | |
| 2874 ->paintProperties() | |
| 2875 ->scroll() | |
| 2876 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2877 EXPECT_FALSE(overflowB->layoutObject() | |
| 2878 ->paintProperties() | |
| 2879 ->scroll() | |
| 2880 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2881 EXPECT_TRUE(overflowB->layoutObject() | |
| 2882 ->paintProperties() | |
| 2883 ->scroll() | |
| 2884 ->parent() | |
| 2885 ->isRoot()); | |
| 2886 | |
| 2887 // Removing a main thread scrolling reason should update the entire tree. | |
| 2888 overflowB->removeAttribute("class"); | |
| 2889 document().view()->updateAllLifecyclePhases(); | |
| 2890 EXPECT_FALSE(overflowA->layoutObject() | |
| 2891 ->paintProperties() | |
| 2892 ->scroll() | |
| 2893 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2894 EXPECT_FALSE(overflowB->layoutObject() | |
| 2895 ->paintProperties() | |
| 2896 ->scroll() | |
| 2897 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2898 EXPECT_FALSE(overflowB->layoutObject() | |
| 2899 ->paintProperties() | |
| 2900 ->scroll() | |
| 2901 ->parent() | |
| 2902 ->hasBackgroundAttachmentFixedDescendants()); | |
| 2903 } | |
| 2904 | |
| 2905 TEST_P(PaintPropertyTreeBuilderTest, PaintOffsetsUnderMultiColumn) { | 2701 TEST_P(PaintPropertyTreeBuilderTest, PaintOffsetsUnderMultiColumn) { |
| 2906 setBodyInnerHTML( | 2702 setBodyInnerHTML( |
| 2907 "<style>" | 2703 "<style>" |
| 2908 " body { margin: 0; }" | 2704 " body { margin: 0; }" |
| 2909 " .space { height: 30px; }" | 2705 " .space { height: 30px; }" |
| 2910 " .abs { position: absolute; width: 20px; height: 20px; }" | 2706 " .abs { position: absolute; width: 20px; height: 20px; }" |
| 2911 "</style>" | 2707 "</style>" |
| 2912 "<div style='columns:2; width: 200px; column-gap: 0'>" | 2708 "<div style='columns:2; width: 200px; column-gap: 0'>" |
| 2913 " <div style='position: relative'>" | 2709 " <div style='position: relative'>" |
| 2914 " <div id=space1 class=space></div>" | 2710 " <div id=space1 class=space></div>" |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3021 childProperties->localBorderBoxProperties()->propertyTreeState; | 2817 childProperties->localBorderBoxProperties()->propertyTreeState; |
| 3022 EXPECT_EQ(framePreTranslation(), | 2818 EXPECT_EQ(framePreTranslation(), |
| 3023 childProperties->paintOffsetTranslation()->parent()); | 2819 childProperties->paintOffsetTranslation()->parent()); |
| 3024 EXPECT_EQ(childProperties->paintOffsetTranslation(), | 2820 EXPECT_EQ(childProperties->paintOffsetTranslation(), |
| 3025 childPaintState.transform()); | 2821 childPaintState.transform()); |
| 3026 // This will change once we added clip expansion node. | 2822 // This will change once we added clip expansion node. |
| 3027 EXPECT_EQ(filterProperties->effect()->outputClip(), childPaintState.clip()); | 2823 EXPECT_EQ(filterProperties->effect()->outputClip(), childPaintState.clip()); |
| 3028 EXPECT_EQ(filterProperties->effect(), childPaintState.effect()); | 2824 EXPECT_EQ(filterProperties->effect(), childPaintState.effect()); |
| 3029 } | 2825 } |
| 3030 | 2826 |
| 3031 TEST_P(PaintPropertyTreeBuilderTest, DescendantNeedsUpdateAcrossFrames) { | |
| 3032 setBodyInnerHTML( | |
| 3033 "<style>body { margin: 0; }</style>" | |
| 3034 "<div id='divWithTransform' style='transform: translate3d(1px,2px,3px);'>" | |
| 3035 " <iframe style='border: 7px solid black'></iframe>" | |
| 3036 "</div>"); | |
| 3037 setChildFrameHTML( | |
| 3038 "<style>body { margin: 0; }</style><div id='transform' style='transform: " | |
| 3039 "translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>"); | |
| 3040 | |
| 3041 FrameView* frameView = document().view(); | |
| 3042 frameView->updateAllLifecyclePhases(); | |
| 3043 | |
| 3044 LayoutObject* divWithTransform = | |
| 3045 document().getElementById("divWithTransform")->layoutObject(); | |
| 3046 LayoutObject* childLayoutView = childDocument().layoutView(); | |
| 3047 LayoutObject* innerDivWithTransform = | |
| 3048 childDocument().getElementById("transform")->layoutObject(); | |
| 3049 | |
| 3050 // Initially, no objects should need a descendant update. | |
| 3051 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3052 EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3053 EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3054 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3055 | |
| 3056 // Marking the child div as needing a paint property update should propagate | |
| 3057 // up the tree and across frames. | |
| 3058 innerDivWithTransform->setNeedsPaintPropertyUpdate(); | |
| 3059 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3060 EXPECT_TRUE(divWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3061 EXPECT_TRUE(childLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3062 EXPECT_TRUE(innerDivWithTransform->needsPaintPropertyUpdate()); | |
| 3063 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3064 | |
| 3065 // After a lifecycle update, no nodes should need a descendant update. | |
| 3066 frameView->updateAllLifecyclePhases(); | |
| 3067 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3068 EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3069 EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3070 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3071 | |
| 3072 // A child frame marked as needing a paint property update should not be | |
| 3073 // skipped if the owning layout tree does not need an update. | |
| 3074 FrameView* childFrameView = childDocument().view(); | |
| 3075 childFrameView->setNeedsPaintPropertyUpdate(); | |
| 3076 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3077 frameView->updateAllLifecyclePhases(); | |
| 3078 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3079 EXPECT_FALSE(frameView->needsPaintPropertyUpdate()); | |
| 3080 EXPECT_FALSE(childFrameView->needsPaintPropertyUpdate()); | |
| 3081 } | |
| 3082 | |
| 3083 TEST_P(PaintPropertyTreeBuilderTest, UpdatingFrameViewContentClip) { | |
| 3084 setBodyInnerHTML("hello world."); | |
| 3085 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect()); | |
| 3086 document().view()->resize(800, 599); | |
| 3087 document().view()->updateAllLifecyclePhases(); | |
| 3088 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), frameContentClip()->clipRect()); | |
| 3089 document().view()->resize(800, 600); | |
| 3090 document().view()->updateAllLifecyclePhases(); | |
| 3091 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect()); | |
| 3092 document().view()->resize(5, 5); | |
| 3093 document().view()->updateAllLifecyclePhases(); | |
| 3094 EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), frameContentClip()->clipRect()); | |
| 3095 } | |
| 3096 | |
| 3097 TEST_P(PaintPropertyTreeBuilderTest, BuildingStopsAtThrottledFrames) { | |
| 3098 setBodyInnerHTML( | |
| 3099 "<style>body { margin: 0; }</style>" | |
| 3100 "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'>" | |
| 3101 "</div>" | |
| 3102 "<iframe id='iframe' sandbox></iframe>"); | |
| 3103 setChildFrameHTML( | |
| 3104 "<style>body { margin: 0; }</style>" | |
| 3105 "<div id='iframeTransform'" | |
| 3106 " style='transform: translate3d(4px, 5px, 6px);'/>"); | |
| 3107 | |
| 3108 // Move the child frame offscreen so it becomes available for throttling. | |
| 3109 auto* iframe = toHTMLIFrameElement(document().getElementById("iframe")); | |
| 3110 iframe->setAttribute(HTMLNames::styleAttr, "transform: translateY(5555px)"); | |
| 3111 document().view()->updateAllLifecyclePhases(); | |
| 3112 // Ensure intersection observer notifications get delivered. | |
| 3113 testing::runPendingTasks(); | |
| 3114 EXPECT_FALSE(document().view()->isHiddenForThrottling()); | |
| 3115 EXPECT_TRUE(childDocument().view()->isHiddenForThrottling()); | |
| 3116 | |
| 3117 auto* transform = document().getElementById("transform")->layoutObject(); | |
| 3118 auto* iframeLayoutView = childDocument().layoutView(); | |
| 3119 auto* iframeTransform = | |
| 3120 childDocument().getElementById("iframeTransform")->layoutObject(); | |
| 3121 | |
| 3122 // Invalidate properties in the iframe and ensure ancestors are marked. | |
| 3123 iframeTransform->setNeedsPaintPropertyUpdate(); | |
| 3124 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate()); | |
| 3125 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3126 EXPECT_FALSE(transform->needsPaintPropertyUpdate()); | |
| 3127 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate()); | |
| 3128 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate()); | |
| 3129 EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3130 EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate()); | |
| 3131 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3132 | |
| 3133 transform->setNeedsPaintPropertyUpdate(); | |
| 3134 EXPECT_TRUE(transform->needsPaintPropertyUpdate()); | |
| 3135 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate()); | |
| 3136 | |
| 3137 { | |
| 3138 DocumentLifecycle::AllowThrottlingScope throttlingScope( | |
| 3139 document().lifecycle()); | |
| 3140 EXPECT_FALSE(document().view()->shouldThrottleRendering()); | |
| 3141 EXPECT_TRUE(childDocument().view()->shouldThrottleRendering()); | |
| 3142 | |
| 3143 // A lifecycle update should update all properties except those with | |
| 3144 // actively throttled descendants. | |
| 3145 document().view()->updateAllLifecyclePhases(); | |
| 3146 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate()); | |
| 3147 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3148 EXPECT_FALSE(transform->needsPaintPropertyUpdate()); | |
| 3149 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate()); | |
| 3150 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate()); | |
| 3151 EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3152 EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate()); | |
| 3153 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3154 } | |
| 3155 | |
| 3156 EXPECT_FALSE(document().view()->shouldThrottleRendering()); | |
| 3157 EXPECT_FALSE(childDocument().view()->shouldThrottleRendering()); | |
| 3158 // Once unthrottled, a lifecycel update should update all properties. | |
| 3159 document().view()->updateAllLifecyclePhases(); | |
| 3160 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate()); | |
| 3161 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate()); | |
| 3162 EXPECT_FALSE(transform->needsPaintPropertyUpdate()); | |
| 3163 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate()); | |
| 3164 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate()); | |
| 3165 EXPECT_FALSE(iframeLayoutView->descendantNeedsPaintPropertyUpdate()); | |
| 3166 EXPECT_FALSE(iframeTransform->needsPaintPropertyUpdate()); | |
| 3167 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate()); | |
| 3168 } | |
| 3169 | |
| 3170 TEST_P(PaintPropertyTreeBuilderTest, ClipChangesUpdateOverflowClip) { | |
| 3171 setBodyInnerHTML( | |
| 3172 "<style>" | |
| 3173 " body { margin:0 }" | |
| 3174 " #div { overflow:hidden; height:0px; }" | |
| 3175 "</style>" | |
| 3176 "<div id='div'></div>"); | |
| 3177 auto* div = document().getElementById("div"); | |
| 3178 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;"); | |
| 3179 document().view()->updateAllLifecyclePhases(); | |
| 3180 auto* clipProperties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3181 EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect()); | |
| 3182 | |
| 3183 // Width changes should update the overflow clip. | |
| 3184 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;"); | |
| 3185 document().view()->updateAllLifecyclePhases(); | |
| 3186 clipProperties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3187 EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect()); | |
| 3188 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:9px;"); | |
| 3189 document().view()->updateAllLifecyclePhases(); | |
| 3190 EXPECT_EQ(FloatRect(0, 0, 9, 0), clipProperties->clipRect().rect()); | |
| 3191 | |
| 3192 // An inline block's overflow clip should be updated when padding changes, | |
| 3193 // even if the border box remains unchanged. | |
| 3194 div->setAttribute(HTMLNames::styleAttr, | |
| 3195 "display:inline-block; width:7px; padding-right:3px;"); | |
| 3196 document().view()->updateAllLifecyclePhases(); | |
| 3197 clipProperties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3198 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect()); | |
| 3199 div->setAttribute(HTMLNames::styleAttr, | |
| 3200 "display:inline-block; width:8px; padding-right:2px;"); | |
| 3201 document().view()->updateAllLifecyclePhases(); | |
| 3202 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect()); | |
| 3203 div->setAttribute(HTMLNames::styleAttr, | |
| 3204 "display:inline-block; width:8px;" | |
| 3205 "padding-right:1px; padding-left:1px;"); | |
| 3206 document().view()->updateAllLifecyclePhases(); | |
| 3207 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect()); | |
| 3208 | |
| 3209 // An block's overflow clip should be updated when borders change. | |
| 3210 div->setAttribute(HTMLNames::styleAttr, "border-right:3px solid red;"); | |
| 3211 document().view()->updateAllLifecyclePhases(); | |
| 3212 clipProperties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3213 EXPECT_EQ(FloatRect(0, 0, 797, 0), clipProperties->clipRect().rect()); | |
| 3214 div->setAttribute(HTMLNames::styleAttr, "border-right:5px solid red;"); | |
| 3215 document().view()->updateAllLifecyclePhases(); | |
| 3216 EXPECT_EQ(FloatRect(0, 0, 795, 0), clipProperties->clipRect().rect()); | |
| 3217 | |
| 3218 // Removing overflow clip should remove the property. | |
| 3219 div->setAttribute(HTMLNames::styleAttr, "overflow:hidden;"); | |
| 3220 document().view()->updateAllLifecyclePhases(); | |
| 3221 clipProperties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3222 EXPECT_EQ(FloatRect(0, 0, 800, 0), clipProperties->clipRect().rect()); | |
| 3223 div->setAttribute(HTMLNames::styleAttr, "overflow:visible;"); | |
| 3224 document().view()->updateAllLifecyclePhases(); | |
| 3225 EXPECT_TRUE(!div->layoutObject()->paintProperties() || | |
| 3226 !div->layoutObject()->paintProperties()->overflowClip()); | |
| 3227 } | |
| 3228 | |
| 3229 TEST_P(PaintPropertyTreeBuilderTest, ContainPaintChangesUpdateOverflowClip) { | |
| 3230 setBodyInnerHTML( | |
| 3231 "<style>" | |
| 3232 " body { margin:0 }" | |
| 3233 " #div { will-change:transform; width:7px; height:6px; }" | |
| 3234 "</style>" | |
| 3235 "<div id='div' style='contain:paint;'></div>"); | |
| 3236 document().view()->updateAllLifecyclePhases(); | |
| 3237 auto* div = document().getElementById("div"); | |
| 3238 auto* properties = div->layoutObject()->paintProperties()->overflowClip(); | |
| 3239 EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->clipRect().rect()); | |
| 3240 | |
| 3241 div->setAttribute(HTMLNames::styleAttr, ""); | |
| 3242 document().view()->updateAllLifecyclePhases(); | |
| 3243 EXPECT_TRUE(!div->layoutObject()->paintProperties() || | |
| 3244 !div->layoutObject()->paintProperties()->overflowClip()); | |
| 3245 } | |
| 3246 | |
| 3247 // A basic sanity check for over-invalidation of paint properties. | |
| 3248 TEST_P(PaintPropertyTreeBuilderTest, NoPaintPropertyUpdateOnBackgroundChange) { | |
| 3249 setBodyInnerHTML("<div id='div' style='background-color: blue'>DIV</div>"); | |
| 3250 auto* div = document().getElementById("div"); | |
| 3251 | |
| 3252 document().view()->updateAllLifecyclePhases(); | |
| 3253 div->setAttribute(HTMLNames::styleAttr, "background-color: green"); | |
| 3254 document().view()->updateLifecycleToLayoutClean(); | |
| 3255 EXPECT_FALSE(div->layoutObject()->needsPaintPropertyUpdate()); | |
| 3256 } | |
| 3257 | |
| 3258 // Disabled due to stale scrollsOverflow values, see: https://crbug.com/675296. | |
| 3259 TEST_P(PaintPropertyTreeBuilderTest, | |
| 3260 DISABLED_FrameVisibilityChangeUpdatesProperties) { | |
| 3261 setBodyInnerHTML( | |
| 3262 "<style>body { margin: 0; }</style>" | |
| 3263 "<div id='iframeContainer'>" | |
| 3264 " <iframe id='iframe' style='width: 100px; height: 100px;'></iframe>" | |
| 3265 "</div>"); | |
| 3266 setChildFrameHTML( | |
| 3267 "<style>body { margin: 0; }</style>" | |
| 3268 "<div id='forceScroll' style='height: 3000px;'></div>"); | |
| 3269 | |
| 3270 FrameView* frameView = document().view(); | |
| 3271 frameView->updateAllLifecyclePhases(); | |
| 3272 EXPECT_EQ(nullptr, frameScroll(frameView)); | |
| 3273 FrameView* childFrameView = childDocument().view(); | |
| 3274 EXPECT_NE(nullptr, frameScroll(childFrameView)); | |
| 3275 | |
| 3276 auto* iframeContainer = document().getElementById("iframeContainer"); | |
| 3277 iframeContainer->setAttribute(HTMLNames::styleAttr, "visibility: hidden;"); | |
| 3278 frameView->updateAllLifecyclePhases(); | |
| 3279 | |
| 3280 EXPECT_EQ(nullptr, frameScroll(frameView)); | |
| 3281 EXPECT_EQ(nullptr, frameScroll(childFrameView)); | |
| 3282 } | |
| 3283 | |
| 3284 } // namespace blink | 2827 } // namespace blink |
| OLD | NEW |