--- /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 <Browser_platform_variant.hrh>
+#include "config.h"
+#include "../../bidi.h"
+#include <AknUtils.h>
+#ifdef BRDO_TOUCH_ENABLED_FF
+#include <touchfeedback.h>
+#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<Up/Down/Left/Right> - 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<MGestureEvent&>(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<WebPointerEventHandler>* 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);
+ }
+ }
+}