diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/s60/webview/WebPointerEventHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/s60/webview/WebPointerEventHandler.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,600 @@ +/* +* Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include "config.h" +#include "../../bidi.h" +#include +#ifdef BRDO_TOUCH_ENABLED_FF +#include +#endif // BRDO_TOUCH_ENABLED_FF +#include "brctl.h" +#include "BrCtlDefs.h" +#include "WebPointerEventHandler.h" +#include "WebView.h" +#include "WebFrame.h" +#include "WebFrameView.h" +#include "WebCursor.h" +#include "WebPopupDrawer.h" +#include "WebFormFillPopup.h" +#include "WebPageScrollHandler.h" +#include "WebFepTextEditor.h" +#include "WebCoreFrameBridge.h" +#include "StaticObjectsContainer.h" +#include "PluginSkin.h" +#include "WebUtil.h" +#include "Element.h" +#include "Document.h" +#include "Frame.h" +#include "FrameView.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "HitTestResult.h" +#include "MouseEvent.h" +#include "WebPageFullScreenHandler.h" +#include "PluginSkin.h" +#include "PluginWin.h" +#include "WebFrameBridge.h" +#include "Page.h" +#include "Chrome.h" +#include "ChromeClient.h" +#include "FocusController.h" + + +#include "WebKitLogger.h" +using namespace WebCore; +using namespace EventNames; +using namespace RT_GestureHelper; + +static const int KMinScrollAndTapInterval = 200000; // 200 ms +static const int KDoubleTapMinActivationInterval = 100000; // 100 ms +static const int KDoubleTapMaxActivationInterval = 500000; // 500 ms +static const int KDoubleTapIdleInterval = 700000; // 700 ms, to prevent triple-tap effects + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::NewL +//----------------------------------------------------------------------------- +WebPointerEventHandler* WebPointerEventHandler::NewL(WebView* view) +{ + WebPointerEventHandler* self = new (ELeave) WebPointerEventHandler(view); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; +} + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::WebPointerEventHandler +//----------------------------------------------------------------------------- +WebPointerEventHandler::WebPointerEventHandler(WebView* view) + : m_webview(view), + m_isHighlighted(false), + m_highlightedNode(NULL), + m_buttonDownTimer( this, &WebPointerEventHandler::buttonDownTimerCB ), + m_ignoreTap(false) +{ +} + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::~WebPointerEventHandler +//----------------------------------------------------------------------------- +WebPointerEventHandler::~WebPointerEventHandler() +{ + delete m_gestureHelper; + delete m_waiter; +} + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::ConstructL +//----------------------------------------------------------------------------- +void WebPointerEventHandler::ConstructL() +{ +#ifdef BRDO_USE_GESTURE_HELPER + m_gestureHelper = CGestureHelper::NewL( *this ); + m_gestureHelper->SetDoubleTapEnabled(true); + m_gestureHelper->SetHoldingEnabled(false); +#else + m_gestureHelper = NULL; +#endif + m_waiter = new(ELeave) CActiveSchedulerWait(); +} +/** + * EGestureStart is sent on touch down + * EGestureReleased is sent on touch up + * EGestureTap = touch down + touch up - events sent: EGestureStart, EGestureTap + * EGestureReleased + * EGestureDrag = touch down + "move" - events sent: EGestureStart, EGestureDrag + * EGestureDoubleTap = 2 * (touch down + touch up) - events sent EGestureStart, + * EGestureDoubleTap, EGestureReleased + * EGestureLongTap = touch down + "long touch" - events sent: EGestureStart, + * EGestureLongTap + * EGestureSwipe - drag + touch up, where movements is + * close to particular direction - event sent: EGestureSwipe, + * EGestureReleased + * EGestureFlick - "fast" drag + touch up - events sent: EGestureFlick, + * EGestureReleased + * EGestureDrop - drag + touch up, !(EGestureSwipe || EGestureFlick) - events + * sent: EGestureDrop, EGestureReleased + */ +void WebPointerEventHandler::HandleGestureL( const MGestureEvent& aEvent ) +{ + TGestureCode gtype = const_cast(aEvent).Code(MGestureEvent::EAxisBoth); + updateCursor(aEvent.CurrentPos()); + + switch (gtype) { + // sent on touch down + case EGestureStart: + { + if (m_webview->viewIsScrolling()) { + m_ignoreTap = true; + m_webview->pageScrollHandler()->handleTouchDownGH(aEvent); + } + else { + handleTouchDownL(aEvent); + } + break; + } + + // sent on tap + case EGestureTap: + { + if (!m_ignoreTap) { + handleTapL(aEvent); + } + break; + } + + // sent on double tap + case EGestureDoubleTap: + { + handleDoubleTap(aEvent); + break; + } + + // sent on long tap + case EGestureLongTap: + { + break; + } + + // sent on touch up after drag + case EGestureDrop: + case EGestureFlick: + case EGestureSwipeLeft: + case EGestureSwipeRight: + case EGestureSwipeUp: + case EGestureSwipeDown: + { + m_ignoreTap = false; + handleTouchUp(aEvent); + break; + } + // sent on move + case EGestureDrag: + { + handleMove(aEvent); + break; + } + + // sent on touch up after tap double tap and long tap + case EGestureReleased: + { + m_ignoreTap = false; + handleTouchUp(aEvent); + break; + } + } +} + + +// ====================================================================== +// WebPointerEventHandler::handleTap +// ====================================================================== +void WebPointerEventHandler::handleTapL(const MGestureEvent& aEvent) +{ + m_buttonDownTimer.stop(); + m_lastTapEvent = m_currentEvent; + if(!m_webview->inPageViewMode()){ + doTapL(); + } +} +// ====================================================================== +// WebPointerEventHandler::handleDoubleTap +//====================================================================== +void WebPointerEventHandler::handleDoubleTap(const MGestureEvent& aEvent) +{ + if ( !m_webview->viewIsScrolling() && + (m_webview->brCtl()->capabilities() & TBrCtlDefs::ECapabilityFitToScreen)) { + if (m_isHighlighted){ + dehighlight(); + } + m_webview->setZoomLevelAdaptively(); + } + else { + m_webview->resetLastZoomLevelIfNeeded(); + } +} + +// ====================================================================== +// WebPointerEventHandler::handleTouchDownL +//====================================================================== +void WebPointerEventHandler::handleTouchDownL(const MGestureEvent& aEvent) +{ + TBrCtlDefs::TBrCtlElementType elType = m_webview->focusedElementType(); + m_buttonDownEvent = m_currentEvent; + m_highlightPos = aEvent.CurrentPos(); + + if ( !m_buttonDownTimer.isActive() && !m_webview->inPageViewMode() ){ + m_buttonDownTimer.startOneShot(0.1f); + } + + m_webview->pageScrollHandler()->handleTouchDownGH(aEvent); + + if ( TBrCtlDefs::EElementActivatedObjectBox == elType) { + PluginSkin* plugin = m_webview->mainFrame()->focusedPlugin(); + if (plugin && plugin->pluginWin()) { + if (!plugin->getClipRect().Contains(m_buttonDownEvent.iPosition)) { + plugin->deActivate(); + } + else { + plugin->pluginWin()->HandlePointerEventL(m_buttonDownEvent); + } + } + } + /* + * After introducing "link selection" pointer down action is done in + * buttondown timer callback. When "down" gesture event is arrived we start + * timer end exit, so gesture helper is ready to deliver next gesture event. + * Meanwhile the processing of the first gesture event hasn't been finished yet. + * The gesture helper doesn't "know" about our plans to handle the event inside + * timer callback and only way for us to "tell" about this is to stop RunL() + * of CGestureEventSender (HandleGestureL() is inside it) and finish buttondown + * timer callback first. + */ + if ( m_buttonDownTimer.isActive()){ + m_waiter->Start(); + } +} + +// ====================================================================== +// WebPointerEventHandler::handleTouchUp +// ====================================================================== +void WebPointerEventHandler::handleTouchUp(const MGestureEvent& aEvent) +{ + m_highlightPos = TPoint(-1,-1); + m_highlightedNode = NULL; + + m_webview->pageScrollHandler()->handleTouchUpGH(aEvent); +} + +// ====================================================================== +// WebPointerEventHandler::handleMoveL +// ====================================================================== +void WebPointerEventHandler::handleMove(const MGestureEvent& aEvent) +{ + TBrCtlDefs::TBrCtlElementType elType = m_webview->focusedElementType(); + TPoint curPos = aEvent.CurrentPos(); + + m_buttonDownTimer.stop(); + HandleHighlightChange(curPos); + + if (elType == TBrCtlDefs::EElementActivatedObjectBox) { + PluginSkin* plugin = m_webview->mainFrame()->focusedPlugin(); + if (plugin) { + plugin->deActivate(); + } + } + + m_webview->pageScrollHandler()->handleScrollingGH(aEvent); +} + + +// ====================================================================== +// WebPointerEventHandler::HandlePointerEventL +// ====================================================================== +void WebPointerEventHandler::HandlePointerEventL(const TPointerEvent& aPointerEvent) +{ + m_currentEvent = aPointerEvent; + + if (m_webview->isSynchRequestPending()) { + return; + } + + // Handle graphical history - should never happen, as HistoryView handles this event by itself + if ( m_webview->brCtl()->historyHandler()->historyController()->historyView()) { + return; + } + + // Handle FormFill popup + if (m_webview->formFillPopup() && m_webview->formFillPopup()->IsVisible()) { + m_webview->formFillPopup()->HandlePointerEventL(aPointerEvent); + return; + } + + if (!m_webview->inPageViewMode()) { + if (aPointerEvent.iType == TPointerEvent::EButton1Down) { + m_webview->GetContainerWindow().EnablePointerMoveBuffer(); + } + else if (aPointerEvent.iType == TPointerEvent::EButton1Up) { + m_webview->GetContainerWindow().DisablePointerMoveBuffer(); + } + } + +#ifdef BRDO_USE_GESTURE_HELPER + m_gestureHelper->HandlePointerEventL(aPointerEvent); +#endif +} + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::HandleHighlightChange +//----------------------------------------------------------------------------- +void WebPointerEventHandler::HandleHighlightChange(const TPoint &aPoint) +{ + if (!m_highlightedNode || !m_isHighlighted) return; + + if (!canDehighlight(aPoint)) return; + + dehighlight(); +} + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::checkForEventListener +//----------------------------------------------------------------------------- +bool WebPointerEventHandler::checkForEventListener(WebCore::Node* node) +{ + EventTargetNode* etnfound = NULL; + for (Node* np = node; np; np = np->parentNode()) { + //check for a mouseover event listener + if (np->isEventTargetNode()) { + if (m_webview->page()->chrome()->client()->elementVisibilityChanged()) { + return true; + } + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::highlitableElement +//----------------------------------------------------------------------------- +TBrCtlDefs::TBrCtlElementType WebPointerEventHandler::highlitableElement() +{ + TRect elRect; + TBrCtlDefs::TBrCtlElementType elType = TBrCtlDefs::EElementNone; + Frame* coreFrame = core(m_webview->mainFrame()); + WebCursor* cursor = StaticObjectsContainer::instance()->webCursor(); + m_webview->page()->chrome()->client()->setElementVisibilityChanged(false); + HitTestResult htresult(cursor->position()); + TPointerEvent event; + TPoint pos = cursor->position(); + event.iPosition = pos; + event.iModifiers = 0; + event.iType = TPointerEvent::EMove; + coreFrame->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event),&htresult); + WebFrame* frm = cursor->getFrameUnderCursor(); + TPoint pt(frm->frameView()->viewCoordsInFrameCoords(pos)); + TPoint nodePoint; + + m_highlightedNode = NULL; + + cursor->navigableNodeUnderCursor(*(frm), pt, elType, elRect); + if (elType == TBrCtlDefs::EElementNone) { + + Node* n = frm->getClosestAnchorElement(cursor->position(), pos); + if (n) { + htresult = HitTestResult(pos); + event.iPosition = pos; + coreFrame->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event),&htresult); + coreFrame->bridge()->getTypeFromElement(htresult.innerNode(), elType, elRect); + TPoint nodePoint = n->getRect().Rect().Center(); + m_offset = (pt.iX- nodePoint.iX)*(pt.iX- nodePoint.iX) + + (pt.iY- nodePoint.iY)*(pt.iY- nodePoint.iY); + + + } + } + m_highlightedNode = htresult.innerNode(); + if (m_highlightedNode) { + m_highlightPos = pos; + m_buttonDownEvent.iPosition = m_highlightPos; + } + m_webview->setFocusedElementType(elType); + return elType; +} + +// ====================================================================== +// WebPointerEventHandler::isHighlitableElement +// ====================================================================== +bool WebPointerEventHandler::isHighlitableElement(TBrCtlDefs::TBrCtlElementType& elType) +{ + return (elType == TBrCtlDefs::EElementAnchor + || elType == TBrCtlDefs::EElementInputBox + || elType == TBrCtlDefs::EElementActivatedInputBox + || elType == TBrCtlDefs::EElementButton + || elType == TBrCtlDefs::EElementCheckBoxChecked + || elType == TBrCtlDefs::EElementCheckBoxUnChecked + || elType == TBrCtlDefs::EElementTextAreaBox + || elType == TBrCtlDefs::EElementRadioButtonSelected + || elType == TBrCtlDefs::EElementRadioButtonUnSelected + || elType == TBrCtlDefs::EElementTelAnchor + || elType == TBrCtlDefs::EElementMailtoAnchor + || elType == TBrCtlDefs::EElementSmartLinkTel + || elType == TBrCtlDefs::EElementSmartLinkEmail + || elType == TBrCtlDefs::EElementSmartLinkVoip); +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::doTapL +//----------------------------------------------------------------------------- +void WebPointerEventHandler::doTapL() +{ + TBrCtlDefs::TBrCtlElementType elType = m_webview->focusedElementType(); + Frame* coreFrame = core(m_webview->mainFrame()); + +#ifdef BRDO_TOUCH_ENABLED_FF + if (m_isHighlighted) + { + MTouchFeedback* feedback = MTouchFeedback::Instance(); + if (feedback) + { + feedback->InstantFeedback(ETouchFeedbackBasic); + } + } +#endif // BRDO_TOUCH_ENABLED_FF + + + // We assume that if element visibility has been changed + // between "up" and "down" that means that some node event + // listener (onMouseOver etc) handling happened and we don't + // want to send a click (mouse press + mouse release) event. + if (m_webview->page()->chrome()->client()->elementVisibilityChanged()) { + return; + } + + m_lastTapEvent.iPosition = m_buttonDownEvent.iPosition; + m_lastTapEvent.iType = TPointerEvent::EButton1Up; + m_lastTapEvent.iModifiers = 0; + + // don't pass the event if the text input is not in valid format + if (isHighlitableElement(elType) || m_webview->fepTextEditor()->validateTextFormat()) { + // because of scrolling we delay sending EButton1Down till we get EButton1Up event and if the content is not scrolling + coreFrame->eventHandler()->handleMousePressEvent(PlatformMouseEvent(m_buttonDownEvent)); + coreFrame->eventHandler()->handleMouseReleaseEvent(PlatformMouseEvent(m_lastTapEvent)); + } + + // special handling for broken image (why is this here??) + if (m_webview->focusedElementType() == TBrCtlDefs::EElementBrokenImage) { + loadFocusedImage(m_webview); + } + else if (elType == TBrCtlDefs::EElementActivatedObjectBox) { + PluginSkin* plugin = m_webview->mainFrame()->focusedPlugin(); + if(plugin && plugin->pluginWin() && plugin->getClipRect().Contains(m_lastTapEvent.iPosition)){ + plugin->pluginWin()->HandlePointerEventL(m_lastTapEvent); + } + } + else { + m_webview->activateVirtualKeyboard(); + } +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::deHighlight +//----------------------------------------------------------------------------- +void WebPointerEventHandler::dehighlight() +{ + // send dehighlight event to engine by passing -1, -1 + // sending any other pointer value may result in highligh of other links + m_highlightPos = TPoint(-1, -1); + m_isHighlighted = EFalse; + TPointerEvent event; + event.iType = TPointerEvent::EMove; + event.iPosition = m_highlightPos; + event.iModifiers = 0; + + Frame* coreFrame = core(m_webview->mainFrame()); + Frame* frm = m_webview->page()->focusController()->focusedOrMainFrame(); + frm->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event)); + + + m_highlightedNode = NULL; + + m_webview->syncRepaint(); +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::canDehighlight +//----------------------------------------------------------------------------- + bool WebPointerEventHandler::canDehighlight(const TPoint &aPoint) + { + TBool checkDehighlight = true; + + if (!m_webview->viewIsScrolling()) + { + WebFrame* frm = StaticObjectsContainer::instance()->webCursor()->getFrameUnderCursor(); + IntPoint framePoint = frm->frameView()->viewCoordsInFrameCoords(aPoint); + if (m_highlightedNode->getRect().contains(framePoint)) { + checkDehighlight = false; + } // check if new points are coming towards closest element + else if(m_offset) { + //Calculate the new offset + IntPoint nodePoint = m_highlightedNode->getRect().Rect().Center(); + TInt newoffset = (framePoint.x()- nodePoint.x())*(framePoint.x()- nodePoint.x()) + (framePoint.y()- nodePoint.y())*(framePoint.y()- nodePoint.y()); + + if(newoffset <= m_offset ) { + m_offset = newoffset; + checkDehighlight = false; + } + else { + m_offset =0; + checkDehighlight = true; + } + } + } + + return checkDehighlight; +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::buttonDownTimerCallback +//----------------------------------------------------------------------------- +void WebPointerEventHandler::buttonDownTimerCB(Timer* t) +{ + m_buttonDownTimer.stop(); + + WebCursor* cursor = StaticObjectsContainer::instance()->webCursor(); + + Frame* coreFrame = core(m_webview->mainFrame()); + TPointerEvent event; + + TBrCtlDefs::TBrCtlElementType elType = highlitableElement(); + + if (!isHighlitableElement(elType)) { + elType = TBrCtlDefs::EElementNone; + } + m_isHighlighted = (m_highlightedNode != NULL) && (elType != TBrCtlDefs::EElementNone) ; + + event.iPosition = m_highlightPos; + event.iModifiers = 0; + event.iType = TPointerEvent::EMove; + + coreFrame->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event)); + m_waiter->AsyncStop(); +} + + +//----------------------------------------------------------------------------- +// WebPointerEventHandler::updateCursor +//---------------------------------------------------------------------------- +void WebPointerEventHandler::updateCursor(const TPoint& pos) +{ + WebCursor* cursor = StaticObjectsContainer::instance()->webCursor(); + if (cursor) { + if (pos != TPoint(0, 0)) { + cursor->setPosition(pos); + } + if (m_webview->showCursor()) { + cursor->resetTransparency(); + m_webview->setShowCursor(false); + cursor->cursorUpdate(false); + } + } +}