~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
#include "TouchEventHandler.h"
 
21
 
 
22
#include "BlackBerryPlatformSystemSound.h"
 
23
#include "DOMSupport.h"
 
24
#include "Document.h"
 
25
#include "DocumentMarkerController.h"
 
26
#include "FocusController.h"
 
27
#include "Frame.h"
 
28
#include "FrameView.h"
 
29
#include "HTMLAnchorElement.h"
 
30
#include "HTMLAreaElement.h"
 
31
#include "HTMLImageElement.h"
 
32
#include "HTMLInputElement.h"
 
33
#include "HTMLNames.h"
 
34
#include "HTMLPlugInElement.h"
 
35
#include "InRegionScroller_p.h"
 
36
#include "InputHandler.h"
 
37
#include "IntRect.h"
 
38
#include "IntSize.h"
 
39
#include "Node.h"
 
40
#include "Page.h"
 
41
#include "PlatformMouseEvent.h"
 
42
#include "PlatformTouchEvent.h"
 
43
#include "RenderLayer.h"
 
44
#include "RenderTheme.h"
 
45
#include "RenderView.h"
 
46
#include "SelectionHandler.h"
 
47
#include "WebPage_p.h"
 
48
#include "WebTapHighlight.h"
 
49
 
 
50
#include <wtf/MathExtras.h>
 
51
 
 
52
using namespace WebCore;
 
53
using namespace WTF;
 
54
 
 
55
namespace BlackBerry {
 
56
namespace WebKit {
 
57
 
 
58
TouchEventHandler::TouchEventHandler(WebPagePrivate* webpage)
 
59
    : m_webPage(webpage)
 
60
    , m_existingTouchMode(ProcessedTouchEvents)
 
61
    , m_shouldRequestSpellCheckOptions(false)
 
62
{
 
63
}
 
64
 
 
65
TouchEventHandler::~TouchEventHandler()
 
66
{
 
67
}
 
68
 
 
69
void TouchEventHandler::doFatFingers(Platform::TouchPoint& point)
 
70
{
 
71
    m_lastScreenPoint = point.m_screenPos;
 
72
    m_lastFatFingersResult.reset(); // Theoretically this shouldn't be required. Keep it just in case states get mangled.
 
73
    IntPoint contentPos(m_webPage->mapFromViewportToContents(point.m_pos));
 
74
    m_webPage->postponeDocumentStyleRecalc();
 
75
    m_lastFatFingersResult = FatFingers(m_webPage, contentPos, FatFingers::ClickableElement).findBestPoint();
 
76
    m_webPage->resumeDocumentStyleRecalc();
 
77
}
 
78
 
 
79
void TouchEventHandler::sendClickAtFatFingersPoint()
 
80
{
 
81
    handleFatFingerPressed();
 
82
    PlatformMouseEvent mouseRelease(m_webPage->mapFromContentsToViewport(m_lastFatFingersResult.adjustedPosition()), m_lastScreenPoint, PlatformEvent::MouseReleased, 1, LeftButton, TouchScreen);
 
83
    m_webPage->handleMouseEvent(mouseRelease);
 
84
}
 
85
 
 
86
void TouchEventHandler::handleTouchPoint(Platform::TouchPoint& point)
 
87
{
 
88
    // Enable input mode on any touch event.
 
89
    m_webPage->m_inputHandler->setInputModeEnabled();
 
90
    switch (point.m_state) {
 
91
    case Platform::TouchPoint::TouchPressed:
 
92
        {
 
93
            doFatFingers(point);
 
94
 
 
95
            // FIXME Draw tap highlight as soon as possible if we can
 
96
            Element* elementUnderFatFinger = m_lastFatFingersResult.nodeAsElementIfApplicable();
 
97
            if (elementUnderFatFinger)
 
98
                drawTapHighlight();
 
99
 
 
100
            // Check for text selection
 
101
            if (m_lastFatFingersResult.isTextInput()) {
 
102
                elementUnderFatFinger = m_lastFatFingersResult.nodeAsElementIfApplicable(FatFingersResult::ShadowContentNotAllowed, true /* shouldUseRootEditableElement */);
 
103
                m_shouldRequestSpellCheckOptions = m_webPage->m_inputHandler->shouldRequestSpellCheckingOptionsForPoint(point.m_pos, elementUnderFatFinger, m_spellCheckOptionRequest);
 
104
            }
 
105
 
 
106
            handleFatFingerPressed();
 
107
            break;
 
108
        }
 
109
    case Platform::TouchPoint::TouchReleased:
 
110
        {
 
111
 
 
112
            if (!m_shouldRequestSpellCheckOptions)
 
113
                m_webPage->m_inputHandler->processPendingKeyboardVisibilityChange();
 
114
 
 
115
            // The rebase has eliminated a necessary event when the mouse does not
 
116
            // trigger an actual selection change preventing re-showing of the
 
117
            // keyboard. If input mode is active, call showVirtualKeyboard which
 
118
            // will update the state and display keyboard if needed.
 
119
            if (m_webPage->m_inputHandler->isInputMode())
 
120
                m_webPage->m_inputHandler->notifyClientOfKeyboardVisibilityChange(true);
 
121
 
 
122
            m_webPage->m_tapHighlight->hide();
 
123
 
 
124
            IntPoint adjustedPoint = m_webPage->mapFromContentsToViewport(m_lastFatFingersResult.adjustedPosition());
 
125
            PlatformMouseEvent mouseEvent(adjustedPoint, m_lastScreenPoint, PlatformEvent::MouseReleased, 1, LeftButton, TouchScreen);
 
126
            m_webPage->handleMouseEvent(mouseEvent);
 
127
 
 
128
            if (m_shouldRequestSpellCheckOptions) {
 
129
                IntPoint pixelPositionRelativeToViewport = m_webPage->mapToTransformed(adjustedPoint);
 
130
                m_webPage->m_inputHandler->requestSpellingCheckingOptions(m_spellCheckOptionRequest, IntSize(m_lastScreenPoint - pixelPositionRelativeToViewport));
 
131
            }
 
132
 
 
133
            m_lastFatFingersResult.reset(); // Reset the fat finger result as its no longer valid when a user's finger is not on the screen.
 
134
            break;
 
135
        }
 
136
    case Platform::TouchPoint::TouchMoved:
 
137
        {
 
138
            // You can still send mouse move events
 
139
            PlatformMouseEvent mouseEvent(point.m_pos, m_lastScreenPoint, PlatformEvent::MouseMoved, 1, LeftButton, TouchScreen);
 
140
            m_lastScreenPoint = point.m_screenPos;
 
141
            m_webPage->handleMouseEvent(mouseEvent);
 
142
            break;
 
143
        }
 
144
    default:
 
145
        break;
 
146
    }
 
147
}
 
148
 
 
149
void TouchEventHandler::handleFatFingerPressed()
 
150
{
 
151
    // First update the mouse position with a MouseMoved event.
 
152
    PlatformMouseEvent mouseMoveEvent(m_webPage->mapFromContentsToViewport(m_lastFatFingersResult.adjustedPosition()), m_lastScreenPoint, PlatformEvent::MouseMoved, 0, LeftButton, TouchScreen);
 
153
    m_webPage->handleMouseEvent(mouseMoveEvent);
 
154
 
 
155
    // Then send the MousePressed event.
 
156
    PlatformMouseEvent mousePressedEvent(m_webPage->mapFromContentsToViewport(m_lastFatFingersResult.adjustedPosition()), m_lastScreenPoint, PlatformEvent::MousePressed, 1, LeftButton, TouchScreen);
 
157
    m_webPage->handleMouseEvent(mousePressedEvent);
 
158
}
 
159
 
 
160
// This method filters what element will get tap-highlight'ed or not. To start with,
 
161
// we are going to highlight links (anchors with a valid href element), and elements
 
162
// whose tap highlight color value is different than the default value.
 
163
static Element* elementForTapHighlight(Element* elementUnderFatFinger)
 
164
{
 
165
    // Do not bail out right way here if there element does not have a renderer.
 
166
    // It is the casefor <map> (descendent of <area>) elements. The associated <image>
 
167
    // element actually has the renderer.
 
168
    if (elementUnderFatFinger->renderer()) {
 
169
        Color tapHighlightColor = elementUnderFatFinger->renderStyle()->tapHighlightColor();
 
170
        if (tapHighlightColor != RenderTheme::defaultTheme()->platformTapHighlightColor())
 
171
            return elementUnderFatFinger;
 
172
    }
 
173
 
 
174
    bool isArea = elementUnderFatFinger->hasTagName(HTMLNames::areaTag);
 
175
    Node* linkNode = elementUnderFatFinger->enclosingLinkEventParentOrSelf();
 
176
    if (!linkNode || !linkNode->isHTMLElement() || (!linkNode->renderer() && !isArea))
 
177
        return 0;
 
178
 
 
179
    ASSERT(linkNode->isLink());
 
180
 
 
181
    // FatFingers class selector ensure only anchor with valid href attr value get here.
 
182
    // It includes empty hrefs.
 
183
    Element* highlightCandidateElement = static_cast<Element*>(linkNode);
 
184
 
 
185
    if (!isArea)
 
186
        return highlightCandidateElement;
 
187
 
 
188
    HTMLAreaElement* area = static_cast<HTMLAreaElement*>(highlightCandidateElement);
 
189
    HTMLImageElement* image = area->imageElement();
 
190
    if (image && image->renderer())
 
191
        return image;
 
192
 
 
193
    return 0;
 
194
}
 
195
 
 
196
void TouchEventHandler::drawTapHighlight()
 
197
{
 
198
    Element* elementUnderFatFinger = m_lastFatFingersResult.nodeAsElementIfApplicable();
 
199
    if (!elementUnderFatFinger)
 
200
        return;
 
201
 
 
202
    Element* element = elementForTapHighlight(elementUnderFatFinger);
 
203
    if (!element)
 
204
        return;
 
205
 
 
206
    // Get the element bounding rect in transformed coordinates so we can extract
 
207
    // the focus ring relative position each rect.
 
208
    RenderObject* renderer = element->renderer();
 
209
    ASSERT(renderer);
 
210
 
 
211
    Frame* elementFrame = element->document()->frame();
 
212
    ASSERT(elementFrame);
 
213
 
 
214
    FrameView* elementFrameView = elementFrame->view();
 
215
    if (!elementFrameView)
 
216
        return;
 
217
 
 
218
    // Tell the client if the element is either in a scrollable container or in a fixed positioned container.
 
219
    // On the client side, this info is being used to hide the tap highlight window on scroll.
 
220
    RenderLayer* layer = m_webPage->enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(renderer->enclosingLayer());
 
221
    bool shouldHideTapHighlightRightAfterScrolling = !layer->renderer()->isRenderView();
 
222
    shouldHideTapHighlightRightAfterScrolling |= !!m_webPage->m_inRegionScroller->d->isActive();
 
223
 
 
224
    IntPoint framePos(m_webPage->frameOffset(elementFrame));
 
225
 
 
226
    // FIXME: We can get more precise on the <map> case by calculating the rect with HTMLAreaElement::computeRect().
 
227
    IntRect absoluteRect(renderer->absoluteClippedOverflowRect());
 
228
    absoluteRect.move(framePos.x(), framePos.y());
 
229
 
 
230
    IntRect clippingRect;
 
231
    if (elementFrame == m_webPage->mainFrame())
 
232
        clippingRect = IntRect(IntPoint(0, 0), elementFrameView->contentsSize());
 
233
    else
 
234
        clippingRect = m_webPage->mainFrame()->view()->windowToContents(m_webPage->getRecursiveVisibleWindowRect(elementFrameView, true /*noClipToMainFrame*/));
 
235
    clippingRect = intersection(absoluteRect, clippingRect);
 
236
 
 
237
    Vector<FloatQuad> focusRingQuads;
 
238
    renderer->absoluteFocusRingQuads(focusRingQuads);
 
239
 
 
240
    Platform::IntRectRegion region;
 
241
    for (size_t i = 0; i < focusRingQuads.size(); ++i) {
 
242
        IntRect rect = focusRingQuads[i].enclosingBoundingBox();
 
243
        rect.move(framePos.x(), framePos.y());
 
244
        IntRect clippedRect = intersection(clippingRect, rect);
 
245
        // FIXME we shouldn't have any empty rects here PR 246960
 
246
        if (clippedRect.isEmpty())
 
247
            continue;
 
248
        clippedRect.inflate(2);
 
249
        region = unionRegions(region, Platform::IntRect(clippedRect));
 
250
    }
 
251
 
 
252
    Color highlightColor = element->renderStyle()->tapHighlightColor();
 
253
 
 
254
    m_webPage->m_tapHighlight->draw(region,
 
255
                                    highlightColor.red(), highlightColor.green(), highlightColor.blue(), highlightColor.alpha(),
 
256
                                    shouldHideTapHighlightRightAfterScrolling);
 
257
}
 
258
 
 
259
void TouchEventHandler::playSoundIfAnchorIsTarget() const
 
260
{
 
261
    if (m_lastFatFingersResult.node() && m_lastFatFingersResult.node()->isLink())
 
262
        BlackBerry::Platform::SystemSound::instance()->playSound(BlackBerry::Platform::SystemSoundType::InputKeypress);
 
263
}
 
264
 
 
265
}
 
266
}