Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 | |
| 33 #include "FrameTestHelpers.h" | |
| 34 #include "RuntimeEnabledFeatures.h" | |
| 35 #include "URLTestHelpers.h" | |
| 36 #include "WebDocument.h" | |
| 37 #include "WebFrame.h" | |
| 38 #include "WebInputEvent.h" | |
| 39 #include "WebView.h" | |
| 40 #include "WebViewClient.h" | |
| 41 #include "WebViewImpl.h" | |
| 42 #include "core/dom/ClientRect.h" | |
| 43 #include "core/dom/ClientRectList.h" | |
| 44 #include "core/dom/Document.h" | |
| 45 #include "core/dom/Element.h" | |
| 46 #include "core/frame/Frame.h" | |
| 47 #include "core/frame/FrameView.h" | |
| 48 #include "core/rendering/HitTestResult.h" | |
| 49 #include "core/rendering/RenderTreeAsText.h" | |
| 50 #include "public/platform/Platform.h" | |
| 51 #include "public/platform/WebUnitTestSupport.h" | |
| 52 #include "public/web/WebHitTestResult.h" | |
| 53 #include "public/web/WebWidgetClient.h" | |
| 54 | |
| 55 #include <gtest/gtest.h> | |
| 56 | |
| 57 using namespace blink; | |
| 58 using blink::FrameTestHelpers::runPendingTasks; | |
| 59 | |
| 60 namespace { | |
| 61 | |
| 62 class TouchActionTrackingWebViewClient : public WebViewClient { | |
| 63 public: | |
| 64 TouchActionTrackingWebViewClient() : | |
| 65 m_actionSetCount(0), | |
| 66 m_touchId(0), | |
| 67 m_actionDelayed(false), | |
| 68 m_action(TouchActionAuto) | |
| 69 { | |
| 70 } | |
| 71 | |
| 72 // WebWidgetClient methods | |
| 73 virtual void setTouchAction(int touchId, bool touchActionDelayed, TouchActio n touchAction) | |
| 74 { | |
| 75 m_actionSetCount++; | |
| 76 m_touchId = touchId; | |
| 77 m_actionDelayed = touchActionDelayed; | |
| 78 m_action = touchAction; | |
| 79 } | |
| 80 | |
| 81 // Local methods | |
| 82 void reset() | |
| 83 { | |
| 84 m_actionSetCount = 0; | |
| 85 m_touchId = 0; | |
| 86 m_actionDelayed = false; | |
| 87 m_action = TouchActionAuto; | |
| 88 } | |
| 89 | |
| 90 int touchActionSetCount() | |
| 91 { | |
| 92 return m_actionSetCount; | |
| 93 } | |
| 94 | |
| 95 int lastTouchActionTouchId() | |
| 96 { | |
| 97 return m_touchId; | |
| 98 } | |
| 99 | |
| 100 bool lastTouchActionDelayed() | |
| 101 { | |
| 102 return m_actionDelayed; | |
| 103 } | |
| 104 | |
| 105 TouchAction lastTouchAction() | |
| 106 { | |
| 107 return m_action; | |
| 108 } | |
| 109 | |
| 110 private: | |
| 111 bool m_actionSetCount; | |
| 112 int m_touchId; | |
| 113 bool m_actionDelayed; | |
| 114 TouchAction m_action; | |
| 115 }; | |
| 116 | |
| 117 const int kfakeTouchId = 7; | |
| 118 | |
| 119 class TouchActionTest : public testing::Test { | |
| 120 public: | |
| 121 TouchActionTest() | |
| 122 : m_baseURL("http://www.test.com/") | |
| 123 { | |
| 124 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseU RL), "touch-action-tests.css"); | |
| 125 WebCore::RuntimeEnabledFeatures::setCSSTouchActionEnabled(true); | |
| 126 } | |
| 127 | |
| 128 virtual void TearDown() | |
| 129 { | |
| 130 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); | |
| 131 } | |
| 132 | |
| 133 protected: | |
| 134 void runTouchActionTest(std::string file) | |
|
abarth-chromium
2013/11/18 21:16:59
This looks pretty involved. Would it be better to
Rick Byers
2013/11/19 21:24:21
Yeah that was my first thought as well. I eventua
| |
| 135 { | |
| 136 TouchActionTrackingWebViewClient client; | |
| 137 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseU RL), WebString::fromUTF8(file)); | |
| 138 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + file, f alse, 0, &client); | |
| 139 | |
| 140 // Set size to enable hit testing, and avoid line wrapping for consisten cy with browser. | |
| 141 webView->resize(WebSize(700, 1000)); | |
| 142 | |
| 143 // Get the document and bypass the no-touch-handler optimization. | |
| 144 RefPtr<WebCore::Document> document = static_cast<PassRefPtr<WebCore::Doc ument> >(webView->mainFrame()->document()); | |
| 145 document->didAddTouchEventHandler(document.get()); | |
| 146 | |
| 147 // Scroll to verify the code properly transforms windows to client co-or ds. | |
| 148 const int kScrollOffset = 100; | |
| 149 document->frame()->view()->setScrollOffset(WebCore::IntPoint(0, kScrollO ffset)); | |
| 150 | |
| 151 // Find all elements to test the touch-action of in the document. | |
| 152 WebCore::TrackExceptionState es; | |
| 153 RefPtr<WebCore::NodeList> nodes = document->querySelectorAll("[expected- action]", es); | |
| 154 ASSERT_FALSE(es.hadException()); | |
| 155 ASSERT_GE(nodes->length(), 1u); | |
| 156 | |
| 157 for (unsigned index = 0; index < nodes->length(); index++) { | |
| 158 WebCore::Element* element = toElement(nodes->item(index)); | |
| 159 element->scrollIntoViewIfNeeded(); | |
| 160 ASSERT_TRUE(nodes->item(index)->isElementNode()); | |
| 161 | |
| 162 std::string failureContext("Test case: "); | |
| 163 if (element->hasID()) { | |
| 164 failureContext.append(element->getIdAttribute().string().ascii() .data()); | |
| 165 } else if (element->firstChild()) { | |
| 166 failureContext.append("\""); | |
| 167 failureContext.append(element->firstChild()->textContent(false). stripWhiteSpace().ascii().data()); | |
| 168 failureContext.append("\""); | |
| 169 } else { | |
| 170 failureContext += "<missing ID>"; | |
| 171 } | |
| 172 | |
| 173 // Run each test three times at different positions in the element. | |
| 174 // Note that we don't want the bounding box because our tests someti mes have elements with | |
| 175 // multiple border boxes with other elements in between. Use the fir st border box (which | |
| 176 // we can easily visualize in a browser for debugging). | |
| 177 RefPtr<WebCore::ClientRectList> rects = element->getClientRects(); | |
| 178 ASSERT_GE(rects->length(), 0u) << failureContext; | |
| 179 RefPtr<WebCore::ClientRect> r = rects->item(0); | |
| 180 WebCore::FloatRect clientFloatRect = WebCore::FloatRect(r->left(), r ->top(), r->width(), r->height()); | |
| 181 WebCore::IntRect clientRect = enclosedIntRect(clientFloatRect); | |
| 182 for (int locIdx = 0; locIdx < 3; locIdx++) { | |
| 183 WebCore::IntPoint clientPoint; | |
| 184 std::stringstream contextStream; | |
| 185 contextStream << failureContext << " ("; | |
| 186 switch (locIdx) { | |
| 187 case 0: | |
| 188 clientPoint = clientRect.center(); | |
| 189 contextStream << "center"; | |
| 190 break; | |
| 191 case 1: | |
| 192 clientPoint = clientRect.location(); | |
| 193 contextStream << "top-left"; | |
| 194 break; | |
| 195 case 2: | |
| 196 clientPoint = clientRect.maxXMaxYCorner(); | |
| 197 clientPoint.move(-1, -1); | |
| 198 contextStream << "bottom-right"; | |
| 199 break; | |
| 200 default: | |
| 201 FAIL() << "Invalid location index."; | |
| 202 } | |
| 203 contextStream << "=" << clientPoint.x() << "," << clientPoint.y( ) << ")."; | |
| 204 std::string failureContextPos = contextStream.str(); | |
| 205 | |
| 206 WebCore::IntRect visibleRect = document->frame()->view()->window ClipRect(); | |
| 207 ASSERT_TRUE(visibleRect.contains(clientPoint)) << failureContext Pos | |
| 208 << " Test point not contained in visible area: " << visibleR ect.x() << "," << visibleRect.y() | |
| 209 << "-" << visibleRect.maxX() << "," << visibleRect.maxY(); | |
| 210 | |
| 211 // First validate that a hit test at this point will really hit the element | |
| 212 // we intended. This is the easiest way for a test to be broken, but has nothing really | |
| 213 // to do with touch action. | |
| 214 WebCore::HitTestResult result = static_cast<WebCore::HitTestResu lt>(webView->hitTestResultAt(clientPoint)); | |
| 215 ASSERT_EQ(element, result.innerElement()) << "Unexpected hit tes t result " << failureContextPos | |
| 216 << " Got element: \"" << result.innerElement()->outerHTML() .stripWhiteSpace().left(80).ascii().data() << "\"" | |
| 217 << std::endl << "Document render tree:" << std::endl << exte rnalRepresentation(document->frame()).utf8().data(); | |
| 218 | |
| 219 // Now send the touch event and check any touch action result. | |
| 220 sendTouchEvent(webView, WebInputEvent::TouchStart, clientPoint); | |
| 221 | |
| 222 AtomicString expectedAction = element->getAttribute("expected-ac tion"); | |
| 223 if (expectedAction == "auto") { | |
| 224 // Auto is the default - no action set. | |
| 225 EXPECT_EQ(0, client.touchActionSetCount()) << failureContext Pos; | |
| 226 EXPECT_EQ(WebWidgetClient::TouchActionAuto, client.lastTouch Action()) << failureContextPos; | |
| 227 } else { | |
| 228 // Should have received exactly one touch action. | |
| 229 EXPECT_EQ(1, client.touchActionSetCount()) << failureContext Pos; | |
| 230 if (client.touchActionSetCount()) { | |
| 231 EXPECT_TRUE(client.lastTouchActionDelayed()) << failureC ontextPos; | |
| 232 EXPECT_EQ(kfakeTouchId, client.lastTouchActionTouchId()) << failureContextPos; | |
| 233 if (expectedAction == "none") { | |
| 234 EXPECT_EQ(WebWidgetClient::TouchActionNone, client.l astTouchAction()) << failureContextPos; | |
| 235 } else { | |
| 236 FAIL() << "Unrecognized expected-action \"" << expec tedAction.string().ascii().data() | |
| 237 << "\" " << failureContextPos; | |
| 238 } | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 // Reset webview touch state. | |
| 243 client.reset(); | |
| 244 sendTouchEvent(webView, WebInputEvent::TouchCancel, clientPoint) ; | |
| 245 EXPECT_EQ(0, client.touchActionSetCount()); | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 void sendTouchEvent(WebView* webView, WebInputEvent::Type type, WebCore::Int Point clientPoint) | |
| 251 { | |
| 252 ASSERT_TRUE(type == WebInputEvent::TouchStart || type == WebInputEvent:: TouchCancel); | |
| 253 | |
| 254 WebTouchEvent webTouchEvent; | |
| 255 webTouchEvent.type = type; | |
| 256 webTouchEvent.touchesLength = 1; | |
| 257 webTouchEvent.touches[0].state = (type == WebInputEvent::TouchStart ? | |
| 258 WebTouchPoint::StatePressed : | |
| 259 WebTouchPoint::StateCancelled); | |
| 260 webTouchEvent.touches[0].id = kfakeTouchId; | |
| 261 webTouchEvent.touches[0].screenPosition.x = clientPoint.x(); | |
| 262 webTouchEvent.touches[0].screenPosition.y = clientPoint.y(); | |
| 263 webTouchEvent.touches[0].position.x = clientPoint.x(); | |
| 264 webTouchEvent.touches[0].position.y = clientPoint.y(); | |
| 265 webTouchEvent.touches[0].radiusX = 10; | |
| 266 webTouchEvent.touches[0].radiusY = 10; | |
| 267 | |
| 268 webView->handleInputEvent(webTouchEvent); | |
| 269 runPendingTasks(); | |
| 270 } | |
| 271 | |
| 272 std::string m_baseURL; | |
| 273 FrameTestHelpers::WebViewHelper m_webViewHelper; | |
| 274 }; | |
| 275 | |
| 276 TEST_F(TouchActionTest, Simple) | |
| 277 { | |
| 278 runTouchActionTest("touch-action-simple.html"); | |
| 279 } | |
| 280 | |
| 281 TEST_F(TouchActionTest, Overflow) | |
| 282 { | |
| 283 runTouchActionTest("touch-action-overflow.html"); | |
| 284 } | |
| 285 | |
| 286 } | |
| OLD | NEW |