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