1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/test/scoped_feature_list.h"
6 #include "testing/gtest/include/gtest/gtest.h"
7 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
8 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
9 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
10 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
11 #include "ui/base/ui_base_features.h"
12
13 namespace blink {
14
15 class StyleAdjusterTest : public RenderingTest {
16 public:
StyleAdjusterTest()17 StyleAdjusterTest()
18 : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
19 };
20
TEST_F(StyleAdjusterTest,TouchActionPropagatedAcrossIframes)21 TEST_F(StyleAdjusterTest, TouchActionPropagatedAcrossIframes) {
22 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
23 SetBodyInnerHTML(R"HTML(
24 <style>body { margin: 0; } iframe { display: block; } </style>
25 <iframe id='owner' src='http://test.com' width='500' height='500'
26 style='touch-action: none'>
27 </iframe>
28 )HTML");
29 SetChildFrameHTML(R"HTML(
30 <style>body { margin: 0; } #target { width: 200px; height: 200px; }
31 </style>
32 <div id='target' style='touch-action: pinch-zoom'></div>
33 )HTML");
34 UpdateAllLifecyclePhasesForTest();
35
36 Element* target = ChildDocument().getElementById("target");
37 EXPECT_EQ(TouchAction::kNone,
38 target->GetComputedStyle()->GetEffectiveTouchAction());
39
40 Element* owner = GetDocument().getElementById("owner");
41 owner->setAttribute(html_names::kStyleAttr, "touch-action: auto");
42 UpdateAllLifecyclePhasesForTest();
43 EXPECT_EQ(TouchAction::kPinchZoom,
44 target->GetComputedStyle()->GetEffectiveTouchAction());
45 }
46
TEST_F(StyleAdjusterTest,TouchActionPanningReEnabledByScrollers)47 TEST_F(StyleAdjusterTest, TouchActionPanningReEnabledByScrollers) {
48 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
49 SetBodyInnerHTML(R"HTML(
50 <style>#ancestor { margin: 0; touch-action: pinch-zoom; }
51 #scroller { overflow: scroll; width: 100px; height: 100px; }
52 #target { width: 200px; height: 200px; } </style>
53 <div id='ancestor'><div id='scroller'><div id='target'>
54 </div></div></div>
55 )HTML");
56 UpdateAllLifecyclePhasesForTest();
57
58 Element* target = GetDocument().getElementById("target");
59 EXPECT_EQ(TouchAction::kManipulation | TouchAction::kInternalPanXScrolls,
60 target->GetComputedStyle()->GetEffectiveTouchAction());
61 }
62
TEST_F(StyleAdjusterTest,TouchActionPropagatedWhenAncestorStyleChanges)63 TEST_F(StyleAdjusterTest, TouchActionPropagatedWhenAncestorStyleChanges) {
64 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
65 SetBodyInnerHTML(R"HTML(
66 <style>#ancestor { margin: 0; touch-action: pan-x; }
67 #potential-scroller { width: 100px; height: 100px; overflow: hidden; }
68 #target { width: 200px; height: 200px; }</style>
69 <div id='ancestor'><div id='potential-scroller'><div id='target'>
70 </div></div></div>
71 )HTML");
72 UpdateAllLifecyclePhasesForTest();
73
74 Element* target = GetDocument().getElementById("target");
75 EXPECT_EQ(TouchAction::kPanX | TouchAction::kInternalPanXScrolls,
76 target->GetComputedStyle()->GetEffectiveTouchAction());
77
78 Element* ancestor = GetDocument().getElementById("ancestor");
79 ancestor->setAttribute(html_names::kStyleAttr, "touch-action: pan-y");
80 UpdateAllLifecyclePhasesForTest();
81 EXPECT_EQ(TouchAction::kPanY,
82 target->GetComputedStyle()->GetEffectiveTouchAction());
83
84 Element* potential_scroller =
85 GetDocument().getElementById("potential-scroller");
86 potential_scroller->setAttribute(html_names::kStyleAttr, "overflow: scroll");
87 UpdateAllLifecyclePhasesForTest();
88 EXPECT_EQ(TouchAction::kPan | TouchAction::kInternalPanXScrolls,
89 target->GetComputedStyle()->GetEffectiveTouchAction());
90 }
91
TEST_F(StyleAdjusterTest,TouchActionRestrictedByLowerAncestor)92 TEST_F(StyleAdjusterTest, TouchActionRestrictedByLowerAncestor) {
93 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
94 SetBodyInnerHTML(R"HTML(
95 <div id='ancestor' style='touch-action: pan'>
96 <div id='parent' style='touch-action: pan-right pan-y'>
97 <div id='target' style='touch-action: pan-x'>
98 </div></div></div>
99 )HTML");
100 UpdateAllLifecyclePhasesForTest();
101
102 Element* target = GetDocument().getElementById("target");
103 EXPECT_EQ(TouchAction::kPanRight | TouchAction::kInternalPanXScrolls,
104 target->GetComputedStyle()->GetEffectiveTouchAction());
105
106 Element* parent = GetDocument().getElementById("parent");
107 parent->setAttribute(html_names::kStyleAttr, "touch-action: auto");
108 UpdateAllLifecyclePhasesForTest();
109 EXPECT_EQ(TouchAction::kPanX | TouchAction::kInternalPanXScrolls,
110 target->GetComputedStyle()->GetEffectiveTouchAction());
111 }
112
TEST_F(StyleAdjusterTest,AdjustOverflow)113 TEST_F(StyleAdjusterTest, AdjustOverflow) {
114 ScopedOverflowClipForTest overflow_clip_feature_enabler(true);
115 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
116 SetBodyInnerHTML(R"HTML(
117 <div id='clipauto' style='overflow-x: clip; overflow-y: auto;
118 overflow-clip-margin: 1px;'>
119 <div id='autoclip' style='overflow-x: auto; overflow-y: clip;
120 overflow-clip-margin: 1px;'>
121 <div id='clipclip' style='overflow-x: clip; overflow-y: clip;
122 overflow-clip-margin: 1px;'>
123 <div id='visclip' style='overflow-x: visible; overflow-y: clip;
124 overflow-clip-margin: 1px;'>
125 <div id='clipvis' style='overflow-x: clip; overflow-y: visible;
126 overflow-clip-margin: 1px;'>
127 <div id='hiddenvis' style='overflow-x: hidden; overflow-y: visible;
128 overflow-clip-margin: 1px;'>
129 <div id='vishidden' style='overflow-x: visible; overflow-y: hidden;
130 overflow-clip-margin: 1px;'>
131 </div>
132 )HTML");
133 UpdateAllLifecyclePhasesForTest();
134
135 Element* target = GetDocument().getElementById("clipauto");
136 ASSERT_TRUE(target);
137 EXPECT_EQ(EOverflow::kHidden, target->GetComputedStyle()->OverflowX());
138 EXPECT_EQ(EOverflow::kAuto, target->GetComputedStyle()->OverflowY());
139 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
140
141 target = GetDocument().getElementById("autoclip");
142 ASSERT_TRUE(target);
143 EXPECT_EQ(EOverflow::kAuto, target->GetComputedStyle()->OverflowX());
144 EXPECT_EQ(EOverflow::kHidden, target->GetComputedStyle()->OverflowY());
145 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
146
147 target = GetDocument().getElementById("clipclip");
148 ASSERT_TRUE(target);
149 EXPECT_EQ(EOverflow::kClip, target->GetComputedStyle()->OverflowX());
150 EXPECT_EQ(EOverflow::kClip, target->GetComputedStyle()->OverflowY());
151 EXPECT_EQ(LayoutUnit(1), target->GetComputedStyle()->OverflowClipMargin());
152
153 target = GetDocument().getElementById("visclip");
154 ASSERT_TRUE(target);
155 EXPECT_EQ(EOverflow::kVisible, target->GetComputedStyle()->OverflowX());
156 EXPECT_EQ(EOverflow::kClip, target->GetComputedStyle()->OverflowY());
157 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
158
159 target = GetDocument().getElementById("clipvis");
160 ASSERT_TRUE(target);
161 EXPECT_EQ(EOverflow::kClip, target->GetComputedStyle()->OverflowX());
162 EXPECT_EQ(EOverflow::kVisible, target->GetComputedStyle()->OverflowY());
163 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
164
165 target = GetDocument().getElementById("vishidden");
166 ASSERT_TRUE(target);
167 EXPECT_EQ(EOverflow::kAuto, target->GetComputedStyle()->OverflowX());
168 EXPECT_EQ(EOverflow::kHidden, target->GetComputedStyle()->OverflowY());
169 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
170
171 target = GetDocument().getElementById("hiddenvis");
172 ASSERT_TRUE(target);
173 EXPECT_EQ(EOverflow::kHidden, target->GetComputedStyle()->OverflowX());
174 EXPECT_EQ(EOverflow::kAuto, target->GetComputedStyle()->OverflowY());
175 EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
176 }
177
TEST_F(StyleAdjusterTest,TouchActionContentEditableArea)178 TEST_F(StyleAdjusterTest, TouchActionContentEditableArea) {
179 base::test::ScopedFeatureList feature_list;
180 feature_list.InitWithFeatures({::features::kSwipeToMoveCursor}, {});
181 if (!::features::IsSwipeToMoveCursorEnabled())
182 return;
183
184 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
185 SetBodyInnerHTML(R"HTML(
186 <div id='editable1' contenteditable='false'></div>
187 <input type="text" id='input1' disabled>
188 <textarea id="textarea1" readonly></textarea>
189 <div id='editable2' contenteditable='true'></div>
190 <input type="text" id='input2'>
191 <textarea id="textarea2"></textarea>
192 )HTML");
193 UpdateAllLifecyclePhasesForTest();
194
195 EXPECT_EQ(TouchAction::kAuto, GetDocument()
196 .getElementById("editable1")
197 ->GetComputedStyle()
198 ->GetEffectiveTouchAction());
199 EXPECT_EQ(TouchAction::kAuto, GetDocument()
200 .getElementById("input1")
201 ->GetComputedStyle()
202 ->GetEffectiveTouchAction());
203 EXPECT_EQ(TouchAction::kAuto, GetDocument()
204 .getElementById("textarea1")
205 ->GetComputedStyle()
206 ->GetEffectiveTouchAction());
207 EXPECT_EQ(TouchAction::kAuto & ~TouchAction::kInternalPanXScrolls,
208 GetDocument()
209 .getElementById("editable2")
210 ->GetComputedStyle()
211 ->GetEffectiveTouchAction());
212 EXPECT_EQ(TouchAction::kAuto & ~TouchAction::kInternalPanXScrolls,
213 GetDocument()
214 .getElementById("input2")
215 ->GetComputedStyle()
216 ->GetEffectiveTouchAction());
217 EXPECT_EQ(TouchAction::kAuto & ~TouchAction::kInternalPanXScrolls,
218 GetDocument()
219 .getElementById("textarea2")
220 ->GetComputedStyle()
221 ->GetEffectiveTouchAction());
222
223 Element* target = GetDocument().getElementById("editable1");
224 target->setAttribute(html_names::kContenteditableAttr, "true");
225 UpdateAllLifecyclePhasesForTest();
226 EXPECT_EQ(TouchAction::kAuto & ~TouchAction::kInternalPanXScrolls,
227 target->GetComputedStyle()->GetEffectiveTouchAction());
228 }
229
TEST_F(StyleAdjusterTest,TouchActionNoPanXScrollsWhenNoPanX)230 TEST_F(StyleAdjusterTest, TouchActionNoPanXScrollsWhenNoPanX) {
231 base::test::ScopedFeatureList feature_list;
232 feature_list.InitWithFeatures({::features::kSwipeToMoveCursor}, {});
233 if (!::features::IsSwipeToMoveCursorEnabled())
234 return;
235
236 GetDocument().SetBaseURLOverride(KURL("http://test.com"));
237 SetBodyInnerHTML(R"HTML(
238 <div id='target' contenteditable='false' style='touch-action: pan-y'></div>
239 )HTML");
240 UpdateAllLifecyclePhasesForTest();
241
242 Element* target = GetDocument().getElementById("target");
243 EXPECT_EQ(TouchAction::kPanY,
244 target->GetComputedStyle()->GetEffectiveTouchAction());
245
246 target->setAttribute(html_names::kContenteditableAttr, "true");
247 UpdateAllLifecyclePhasesForTest();
248 EXPECT_EQ(TouchAction::kPanY,
249 target->GetComputedStyle()->GetEffectiveTouchAction());
250 }
251
252 } // namespace blink
253