1/*
2 * Copyright (C) 2012 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
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *     notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *     notice, this list of conditions and the following disclaimer in the
11 *     documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#include "LinkHighlight.h"
28
29#include <gtest/gtest.h>
30#include "FrameTestHelpers.h"
31#include "URLTestHelpers.h"
32#include "WebFrame.h"
33#include "WebFrameClient.h"
34#include "WebFrameImpl.h"
35#include "WebInputEvent.h"
36#include "WebInputEventConversion.h"
37#include "WebViewClient.h"
38#include "WebViewImpl.h"
39#include "bindings/v8/ExceptionStatePlaceholder.h"
40#include "core/dom/Node.h"
41#include "core/frame/FrameView.h"
42#include "core/page/TouchDisambiguation.h"
43#include "platform/geometry/IntRect.h"
44#include "public/platform/Platform.h"
45#include "public/platform/WebContentLayer.h"
46#include "public/platform/WebFloatPoint.h"
47#include "public/platform/WebSize.h"
48#include "public/platform/WebUnitTestSupport.h"
49#include "wtf/PassOwnPtr.h"
50
51
52using namespace blink;
53using namespace WebCore;
54
55namespace {
56
57TEST(LinkHighlightTest, verifyWebViewImplIntegration)
58{
59    const std::string baseURL("http://www.test.com/");
60    const std::string fileName("test_touch_link_highlight.html");
61
62    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL.c_str()), WebString::fromUTF8("test_touch_link_highlight.html"));
63    FrameTestHelpers::WebViewHelper webViewHelper;
64    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(baseURL + fileName, true);
65    int pageWidth = 640;
66    int pageHeight = 480;
67    webViewImpl->resize(WebSize(pageWidth, pageHeight));
68    webViewImpl->layout();
69
70    WebGestureEvent touchEvent;
71    touchEvent.type = WebInputEvent::GestureShowPress;
72
73    // The coordinates below are linked to absolute positions in the referenced .html file.
74    touchEvent.x = 20;
75    touchEvent.y = 20;
76
77    {
78        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
79        Node* touchNode = webViewImpl->bestTapNode(platformEvent);
80        ASSERT_TRUE(touchNode);
81    }
82
83    touchEvent.y = 40;
84    {
85        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
86        EXPECT_FALSE(webViewImpl->bestTapNode(platformEvent));
87    }
88
89    touchEvent.y = 20;
90    // Shouldn't crash.
91
92    {
93        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
94        webViewImpl->enableTapHighlightAtPoint(platformEvent);
95    }
96
97    EXPECT_TRUE(webViewImpl->linkHighlight(0));
98    EXPECT_TRUE(webViewImpl->linkHighlight(0)->contentLayer());
99    EXPECT_TRUE(webViewImpl->linkHighlight(0)->clipLayer());
100
101    // Find a target inside a scrollable div
102
103    touchEvent.y = 100;
104    {
105        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
106        webViewImpl->enableTapHighlightAtPoint(platformEvent);
107    }
108
109    ASSERT_TRUE(webViewImpl->linkHighlight(0));
110
111    // Don't highlight if no "hand cursor"
112    touchEvent.y = 220; // An A-link with cross-hair cursor.
113    {
114        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
115        webViewImpl->enableTapHighlightAtPoint(platformEvent);
116    }
117    ASSERT_EQ(0U, webViewImpl->numLinkHighlights());
118
119    touchEvent.y = 260; // A text input box.
120    {
121        PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
122        webViewImpl->enableTapHighlightAtPoint(platformEvent);
123    }
124    ASSERT_EQ(0U, webViewImpl->numLinkHighlights());
125
126    Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
127}
128
129class FakeWebFrameClient : public WebFrameClient {
130    // To make the destructor public.
131};
132
133class FakeCompositingWebViewClient : public WebViewClient {
134public:
135    virtual ~FakeCompositingWebViewClient()
136    {
137    }
138
139    virtual void initializeLayerTreeView() OVERRIDE
140    {
141        m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting(WebUnitTestSupport::TestViewTypeUnitTest));
142        ASSERT(m_layerTreeView);
143    }
144
145    virtual WebLayerTreeView* layerTreeView() OVERRIDE
146    {
147        return m_layerTreeView.get();
148    }
149
150    FakeWebFrameClient m_fakeWebFrameClient;
151
152private:
153    OwnPtr<WebLayerTreeView> m_layerTreeView;
154};
155
156static WebViewClient* compositingWebViewClient()
157{
158    DEFINE_STATIC_LOCAL(FakeCompositingWebViewClient, client, ());
159    return &client;
160}
161
162TEST(LinkHighlightTest, resetDuringNodeRemoval)
163{
164    const std::string baseURL("http://www.test.com/");
165    const std::string fileName("test_touch_link_highlight.html");
166
167    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL.c_str()), WebString::fromUTF8("test_touch_link_highlight.html"));
168    FrameTestHelpers::WebViewHelper webViewHelper;
169    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(baseURL + fileName, true, 0, compositingWebViewClient());
170
171    int pageWidth = 640;
172    int pageHeight = 480;
173    webViewImpl->resize(WebSize(pageWidth, pageHeight));
174    webViewImpl->layout();
175
176    WebGestureEvent touchEvent;
177    touchEvent.type = WebInputEvent::GestureShowPress;
178    touchEvent.x = 20;
179    touchEvent.y = 20;
180
181    PlatformGestureEventBuilder platformEvent(webViewImpl->mainFrameImpl()->frameView(), touchEvent);
182    Node* touchNode = webViewImpl->bestTapNode(platformEvent);
183    ASSERT_TRUE(touchNode);
184
185    webViewImpl->enableTapHighlightAtPoint(platformEvent);
186    ASSERT_TRUE(webViewImpl->linkHighlight(0));
187
188    GraphicsLayer* highlightLayer = webViewImpl->linkHighlight(0)->currentGraphicsLayerForTesting();
189    ASSERT_TRUE(highlightLayer);
190    EXPECT_TRUE(highlightLayer->linkHighlight(0));
191
192    touchNode->remove(IGNORE_EXCEPTION);
193    webViewImpl->layout();
194    ASSERT_EQ(0U, highlightLayer->numLinkHighlights());
195
196    Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
197}
198
199TEST(LinkHighlightTest, multipleHighlights)
200{
201    const std::string baseURL("http://www.test.com/");
202    const std::string fileName("test_touch_link_highlight.html");
203
204    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL.c_str()), WebString::fromUTF8("test_touch_link_highlight.html"));
205    FrameTestHelpers::WebViewHelper webViewHelper;
206    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(baseURL + fileName, true, 0, compositingWebViewClient());
207
208    int pageWidth = 640;
209    int pageHeight = 480;
210    webViewImpl->resize(WebSize(pageWidth, pageHeight));
211    webViewImpl->layout();
212
213    WebGestureEvent touchEvent;
214    touchEvent.x = 50;
215    touchEvent.y = 310;
216    touchEvent.data.tap.width = 30;
217    touchEvent.data.tap.height = 30;
218
219    Vector<IntRect> goodTargets;
220    Vector<Node*> highlightNodes;
221    IntRect boundingBox(touchEvent.x - touchEvent.data.tap.width / 2, touchEvent.y - touchEvent.data.tap.height / 2, touchEvent.data.tap.width, touchEvent.data.tap.height);
222    findGoodTouchTargets(boundingBox, webViewImpl->mainFrameImpl()->frame(), goodTargets, highlightNodes);
223
224    webViewImpl->enableTapHighlights(highlightNodes);
225    EXPECT_EQ(2U, webViewImpl->numLinkHighlights());
226
227    Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
228}
229
230} // namespace
231