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