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/WebTouchAction.h" | |
| 54 #include "public/web/WebWidgetClient.h" | |
| 55 | |
| 56 #include <gtest/gtest.h> | |
| 57 | |
| 58 using namespace blink; | |
| 59 using blink::FrameTestHelpers::runPendingTasks; | |
| 60 | |
| 61 namespace { | |
| 62 | |
| 63 class TouchActionTrackingWebViewClient : public WebViewClient { | |
| 64 public: | |
| 65 TouchActionTrackingWebViewClient() : | |
| 66 m_actionSetCount(0), | |
| 67 m_action(WebTouchActionAuto) | |
| 68 { | |
| 69 } | |
| 70 | |
| 71 // WebWidgetClient methods | |
| 72 virtual void setTouchAction(WebTouchAction touchAction) | |
| 73 { | |
| 74 m_actionSetCount++; | |
| 75 m_action = touchAction; | |
| 76 } | |
| 77 | |
| 78 // Local methods | |
| 79 void reset() | |
| 80 { | |
| 81 m_actionSetCount = 0; | |
| 82 m_action = WebTouchActionAuto; | |
| 83 } | |
| 84 | |
| 85 int touchActionSetCount() | |
| 86 { | |
| 87 return m_actionSetCount; | |
| 88 } | |
| 89 | |
| 90 WebTouchAction lastTouchAction() | |
| 91 { | |
| 92 return m_action; | |
| 93 } | |
| 94 | |
| 95 private: | |
| 96 int m_actionSetCount; | |
| 97 WebTouchAction m_action; | |
| 98 }; | |
| 99 | |
| 100 const int kfakeTouchId = 7; | |
| 101 | |
| 102 class TouchActionTest : public testing::Test { | |
| 103 public: | |
| 104 TouchActionTest() | |
| 105 : m_baseURL("http://www.test.com/") | |
| 106 { | |
| 107 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseU RL), "touch-action-tests.css"); | |
| 108 WebCore::RuntimeEnabledFeatures::setCSSTouchActionEnabled(true); | |
| 109 } | |
| 110 | |
| 111 virtual void TearDown() | |
| 112 { | |
| 113 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); | |
| 114 } | |
| 115 | |
| 116 protected: | |
| 117 void runTouchActionTest(std::string file) | |
|
esprehn
2013/11/21 16:26:29
It would be nicer to put this method outside the c
Rick Byers
2013/11/21 22:09:29
Done.
| |
| 118 { | |
| 119 TouchActionTrackingWebViewClient client; | |
| 120 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseU RL), WebString::fromUTF8(file)); | |
| 121 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + file, f alse, 0, &client); | |
| 122 | |
| 123 // Set size to enable hit testing, and avoid line wrapping for consisten cy with browser. | |
| 124 webView->resize(WebSize(700, 1000)); | |
| 125 | |
| 126 // Get the document and bypass the no-touch-handler optimization. | |
| 127 RefPtr<WebCore::Document> document = static_cast<PassRefPtr<WebCore::Doc ument> >(webView->mainFrame()->document()); | |
| 128 document->didAddTouchEventHandler(document.get()); | |
| 129 | |
| 130 // Scroll to verify the code properly transforms windows to client co-or ds. | |
| 131 const int kScrollOffset = 100; | |
| 132 document->frame()->view()->setScrollOffset(WebCore::IntPoint(0, kScrollO ffset)); | |
| 133 | |
| 134 // Find all elements to test the touch-action of in the document. | |
| 135 WebCore::TrackExceptionState es; | |
| 136 RefPtr<WebCore::NodeList> nodes = document->querySelectorAll("[expected- action]", es); | |
| 137 ASSERT_FALSE(es.hadException()); | |
| 138 ASSERT_GE(nodes->length(), 1u); | |
| 139 | |
| 140 for (unsigned index = 0; index < nodes->length(); index++) { | |
| 141 WebCore::Element* element = toElement(nodes->item(index)); | |
| 142 element->scrollIntoViewIfNeeded(); | |
| 143 ASSERT_TRUE(nodes->item(index)->isElementNode()); | |
| 144 | |
| 145 std::string failureContext("Test case: "); | |
| 146 if (element->hasID()) { | |
| 147 failureContext.append(element->getIdAttribute().string().ascii() .data()); | |
| 148 } else if (element->firstChild()) { | |
| 149 failureContext.append("\""); | |
| 150 failureContext.append(element->firstChild()->textContent(false). stripWhiteSpace().ascii().data()); | |
| 151 failureContext.append("\""); | |
| 152 } else { | |
| 153 failureContext += "<missing ID>"; | |
| 154 } | |
| 155 | |
| 156 // Run each test three times at different positions in the element. | |
| 157 // Note that we don't want the bounding box because our tests someti mes have elements with | |
| 158 // multiple border boxes with other elements in between. Use the fir st border box (which | |
| 159 // we can easily visualize in a browser for debugging). | |
| 160 RefPtr<WebCore::ClientRectList> rects = element->getClientRects(); | |
| 161 ASSERT_GE(rects->length(), 0u) << failureContext; | |
| 162 RefPtr<WebCore::ClientRect> r = rects->item(0); | |
| 163 WebCore::FloatRect clientFloatRect = WebCore::FloatRect(r->left(), r ->top(), r->width(), r->height()); | |
| 164 WebCore::IntRect clientRect = enclosedIntRect(clientFloatRect); | |
| 165 for (int locIdx = 0; locIdx < 3; locIdx++) { | |
| 166 WebCore::IntPoint clientPoint; | |
| 167 std::stringstream contextStream; | |
| 168 contextStream << failureContext << " ("; | |
| 169 switch (locIdx) { | |
| 170 case 0: | |
| 171 clientPoint = clientRect.center(); | |
| 172 contextStream << "center"; | |
| 173 break; | |
| 174 case 1: | |
| 175 clientPoint = clientRect.location(); | |
| 176 contextStream << "top-left"; | |
| 177 break; | |
| 178 case 2: | |
| 179 clientPoint = clientRect.maxXMaxYCorner(); | |
| 180 clientPoint.move(-1, -1); | |
| 181 contextStream << "bottom-right"; | |
| 182 break; | |
| 183 default: | |
| 184 FAIL() << "Invalid location index."; | |
| 185 } | |
| 186 contextStream << "=" << clientPoint.x() << "," << clientPoint.y( ) << ")."; | |
| 187 std::string failureContextPos = contextStream.str(); | |
| 188 | |
| 189 WebCore::IntRect visibleRect = document->frame()->view()->window ClipRect(); | |
| 190 ASSERT_TRUE(visibleRect.contains(clientPoint)) << failureContext Pos | |
| 191 << " Test point not contained in visible area: " << visibleR ect.x() << "," << visibleRect.y() | |
| 192 << "-" << visibleRect.maxX() << "," << visibleRect.maxY(); | |
| 193 | |
| 194 // First validate that a hit test at this point will really hit the element | |
| 195 // we intended. This is the easiest way for a test to be broken, but has nothing really | |
| 196 // to do with touch action. | |
| 197 WebCore::HitTestResult result = static_cast<WebCore::HitTestResu lt>(webView->hitTestResultAt(clientPoint)); | |
| 198 ASSERT_EQ(element, result.innerElement()) << "Unexpected hit tes t result " << failureContextPos | |
| 199 << " Got element: \"" << result.innerElement()->outerHTML() .stripWhiteSpace().left(80).ascii().data() << "\"" | |
| 200 << std::endl << "Document render tree:" << std::endl << exte rnalRepresentation(document->frame()).utf8().data(); | |
| 201 | |
| 202 // Now send the touch event and check any touch action result. | |
| 203 sendTouchEvent(webView, WebInputEvent::TouchStart, clientPoint); | |
| 204 | |
| 205 AtomicString expectedAction = element->getAttribute("expected-ac tion"); | |
| 206 if (expectedAction == "auto") { | |
| 207 // Auto is the default - no action set. | |
| 208 EXPECT_EQ(0, client.touchActionSetCount()) << failureContext Pos; | |
| 209 EXPECT_EQ(WebTouchActionAuto, client.lastTouchAction()) << f ailureContextPos; | |
| 210 } else { | |
| 211 // Should have received exactly one touch action. | |
| 212 EXPECT_EQ(1, client.touchActionSetCount()) << failureContext Pos; | |
| 213 if (client.touchActionSetCount()) { | |
| 214 if (expectedAction == "none") { | |
| 215 EXPECT_EQ(WebTouchActionNone, client.lastTouchAction ()) << failureContextPos; | |
| 216 } else { | |
| 217 FAIL() << "Unrecognized expected-action \"" << expec tedAction.string().ascii().data() | |
| 218 << "\" " << failureContextPos; | |
| 219 } | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 // Reset webview touch state. | |
| 224 client.reset(); | |
| 225 sendTouchEvent(webView, WebInputEvent::TouchCancel, clientPoint) ; | |
| 226 EXPECT_EQ(0, client.touchActionSetCount()); | |
| 227 } | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 void sendTouchEvent(WebView* webView, WebInputEvent::Type type, WebCore::Int Point clientPoint) | |
|
esprehn
2013/11/21 16:26:29
Same.
Rick Byers
2013/11/21 22:09:29
Done.
| |
| 232 { | |
| 233 ASSERT_TRUE(type == WebInputEvent::TouchStart || type == WebInputEvent:: TouchCancel); | |
| 234 | |
| 235 WebTouchEvent webTouchEvent; | |
| 236 webTouchEvent.type = type; | |
| 237 webTouchEvent.touchesLength = 1; | |
| 238 webTouchEvent.touches[0].state = (type == WebInputEvent::TouchStart ? | |
| 239 WebTouchPoint::StatePressed : | |
| 240 WebTouchPoint::StateCancelled); | |
| 241 webTouchEvent.touches[0].id = kfakeTouchId; | |
| 242 webTouchEvent.touches[0].screenPosition.x = clientPoint.x(); | |
| 243 webTouchEvent.touches[0].screenPosition.y = clientPoint.y(); | |
| 244 webTouchEvent.touches[0].position.x = clientPoint.x(); | |
| 245 webTouchEvent.touches[0].position.y = clientPoint.y(); | |
| 246 webTouchEvent.touches[0].radiusX = 10; | |
| 247 webTouchEvent.touches[0].radiusY = 10; | |
| 248 | |
| 249 webView->handleInputEvent(webTouchEvent); | |
| 250 runPendingTasks(); | |
| 251 } | |
| 252 | |
| 253 std::string m_baseURL; | |
| 254 FrameTestHelpers::WebViewHelper m_webViewHelper; | |
| 255 }; | |
| 256 | |
| 257 TEST_F(TouchActionTest, Simple) | |
| 258 { | |
| 259 runTouchActionTest("touch-action-simple.html"); | |
| 260 } | |
| 261 | |
| 262 TEST_F(TouchActionTest, Overflow) | |
| 263 { | |
| 264 runTouchActionTest("touch-action-overflow.html"); | |
| 265 } | |
| 266 | |
| 267 } | |
| OLD | NEW |