| 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 |