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 |