webengine/osswebengine/WebKit/s60/webview/WebCursor.cpp
changeset 0 dd21522fd290
child 1 7c90e6132015
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebKit/s60/webview/WebCursor.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,973 @@
+/*
+* Copyright (c) 2006 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:   Implemetation of CWebKiCursor
+*
+*/
+
+
+#include "config.h"
+#include "../../bidi.h"
+#include <stdlib.h>
+#include "StaticObjectsContainer.h"
+#include "WebView.h"
+#include "WebFrame.h"
+#include "WebFrameView.h"
+#include "WebFrameBridge.h"
+#include "Frame.h"
+#include "Document.h"
+#include "Node.h"
+#include "Element.h"
+#include "HTMLImageElement.h"
+#include "RenderImage.h"
+#include "BrCtl.h"
+#include "HTMLNames.h"
+#include "HTMLElement.h"
+#include "MouseEvent.h"
+#include "EventNames.h"
+#include "WebUtil.h"
+#include "SettingsContainer.h"
+#include "WebCursor.h"
+#include "Page.h"
+#include "FocusController.h"
+#include <AknUtils.h>
+#include "PlatformScrollbar.h"
+
+#include "eikon.hrh"
+
+
+const int KMiddleStep = 8;
+const int KFlipAdjust =12;
+const int KCursorIncremental = 17;         // 17 pixels
+const int KTransparencyTime = 8000*1000; //8s
+const int KTransparencyMoveThreshold = 15;
+
+const int KAggressiveSearch = 50;
+
+#define KCursorOffset TPoint(-3,-4)
+
+using namespace WebCore;
+using namespace EventNames;
+using namespace HTMLNames;
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+inline IntPoint nearestPointInRect(const IntPoint &point, const IntRect &rect)
+{
+  //Error condition
+  if (rect.isEmpty()) return IntPoint(0,0);
+
+  int y = std::max(rect.y(), std::min(rect.bottom(), point.y()));
+  int x = std::max(rect.x(), std::min(rect.right(), point.x()));
+
+  return IntPoint(x,y);
+}
+
+TInt TransparencyTimerCb(TAny* any)
+    {
+    WebCursor* c = static_cast<WebCursor*>(any);
+    c->setTransparent(true);
+    return EFalse;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CWebKitCursor::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+WebCursor* WebCursor::NewL()
+    {
+    WebCursor* self = new (ELeave) WebCursor();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::WebCursor
+// Constructor.
+// -----------------------------------------------------------------------------
+WebCursor::WebCursor() :
+        m_pos(TPoint(KInitialOffset,KInitialOffset))
+      , m_previousLr(0)
+      , m_previousTb(0)
+      , m_view(0)
+      , m_visible(true)
+      , m_flipcounter(0)
+      , m_type(PointerCursor)
+      , m_flipCounter(0)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::~WebCursor
+// Deconstructor.
+// -----------------------------------------------------------------------------
+WebCursor::~WebCursor()
+    {
+    m_sprite.Close();
+    delete m_transarrowmask;
+    delete m_transtimer;
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::ConstructL
+// -----------------------------------------------------------------------------
+void WebCursor::ConstructL()
+    {
+    m_transtimer = CPeriodic::NewL(CActive::EPriorityStandard);
+    m_visible = !AknLayoutUtils::PenEnabled();
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::SetCurrentView
+// -----------------------------------------------------------------------------
+void WebCursor::setCurrentView(WebView& view)
+    {
+    if (!m_view)
+    {
+        m_view = &view;
+        constructSprite();
+    }
+    m_view = &view;
+    setOpaqueUntil(KTransparencyTime);
+    m_transcount = 0;
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::ConstructSprite
+// -----------------------------------------------------------------------------
+void WebCursor::constructSprite()
+    {
+
+    //tot:fixme
+    m_arrow = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageArrowBitmap);
+    m_hand = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageFingerBitmap);
+    m_ibeam = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageIBeam);
+    m_selectMulti = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSelectMulti);
+    //iSmartLinkPhoneImage = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSmartLinkPhone);
+    //iSmartLinkEmailImage = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSmartLinkEmail);
+    m_wait = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageWaitArrowBitmap);
+    TSize s = m_arrow.m_msk->SizeInPixels();
+    m_transarrowmask = new (ELeave) CFbsBitmap();
+    m_transarrowmask->Create(s,m_arrow.m_msk->DisplayMode());
+    CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(m_transarrowmask);
+    CleanupStack::PushL(dev);
+    CFbsBitGc* gc;
+    User::LeaveIfError(dev->CreateContext(gc));
+    gc->BitBlt(TPoint(0,0),m_arrow.m_msk);
+    m_transarrowmask->LockHeap();
+    TUint8* data = (TUint8*)m_transarrowmask->DataAddress();
+    TUint8* end = data + s.iWidth*s.iHeight;
+    // divide all pixels by 3
+    while ( data<end )
+        {
+        *(data++) /= 3;
+        }
+    m_transarrowmask->UnlockHeap();
+    delete gc;
+    CleanupStack::PopAndDestroy();
+    /////////////////////////////////
+    m_sprite = RWsSprite(m_view->ControlEnv()->WsSession());
+    RWindowTreeNode *window =  (RDrawableWindow* )m_view->brCtl()->CCoeControlParent()->DrawableWindow();
+    m_sprite.Construct(*window,TPoint(KInitialOffset,KInitialOffset),ESpriteNoChildClip);
+
+    TSpriteMember spriteMem;
+    spriteMem.iBitmap = 0;
+    spriteMem.iMaskBitmap = 0;
+    spriteMem.iInvertMask = ETrue;
+
+    m_sprite.AppendMember(spriteMem);
+    m_sprite.Activate();
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::CursorUpdate
+// -----------------------------------------------------------------------------
+void WebCursor::setCursor(CursorTypes type)
+{
+    m_sprite.SetPosition( m_pos );
+    m_type = type;
+    if (m_visible) {
+        TSpriteMember spriteMem;
+        switch( type )
+            {
+            case PointerCursor:
+            default:
+                {
+                spriteMem.iBitmap = m_waiton ? m_wait.m_img : m_arrow.m_img;
+                spriteMem.iMaskBitmap = m_waiton ? m_wait.m_img :
+                    (m_transparent && m_transcount > KTransparencyMoveThreshold ? m_transarrowmask : m_arrow.m_msk);
+                break;
+                }
+           case HandCursor:
+                {
+                spriteMem.iBitmap = m_hand.m_img;
+                spriteMem.iMaskBitmap = m_hand.m_msk;
+                break;
+                }
+           case IBeamCursor:
+                {
+               /*tot:fixme if ( m_view->FocusedElementType() == TBrCtlDefs::EElementSmartLinkTel )
+                    {
+                    spriteMem.iBitmap = iSmartLinkPhoneImage.m_img;
+                    spriteMem.iMaskBitmap = iSmartLinkPhoneImage.m_msk;
+                    }
+                else if ( m_view->FocusedElementType() == TBrCtlDefs::EElementSmartLinkEmail )
+                    {
+                    spriteMem.iBitmap = iSmartLinkEmailImage.m_img;
+                    spriteMem.iMaskBitmap = iSmartLinkEmailImage.m_msk;
+                    }
+                else*/
+                    {
+                    spriteMem.iBitmap = m_ibeam.m_img;
+                    spriteMem.iMaskBitmap = m_ibeam.m_msk;
+                    }
+                break;
+                }
+           case SelectMultiCursor:
+               {
+                    spriteMem.iBitmap = m_selectMulti.m_img;
+                    spriteMem.iMaskBitmap = m_selectMulti.m_msk;
+                    break;
+               }
+            }
+        spriteMem.iOffset = KCursorOffset;
+        spriteMem.iInvertMask = ETrue;
+        m_sprite.UpdateMember( 0, spriteMem );
+    } else {
+        TSpriteMember spriteMem;
+        spriteMem.iBitmap = 0;
+        spriteMem.iMaskBitmap = 0;
+        spriteMem.iInvertMask = ETrue;
+        m_sprite.UpdateMember( 0, spriteMem );
+    }
+}
+
+// -----------------------------------------------------------------------------
+// WebCursor::CursorUpdate
+// -----------------------------------------------------------------------------
+void WebCursor::cursorUpdate(bool visible)
+{
+    if (!m_view || !m_view->brCtl()->settings())
+        return;
+    if ( m_view->showCursor() ) {
+        m_visible = visible && (!m_view->brCtl()->settings()->getTabbedNavigation() || m_view->focusedElementType() == TBrCtlDefs::EElementSelectMultiBox); // check for tabbedNavigation here because it is called from so many places.
+    }
+    
+    resetTransparency();
+    CursorTypes type = PointerCursor;
+    TBrCtlDefs::TBrCtlElementType elType = m_view->focusedElementType();
+    if (m_visible) {
+        if (elType == TBrCtlDefs::EElementNone || elType == TBrCtlDefs::EElementBrokenImage)
+            type = PointerCursor;
+        else if (elType == TBrCtlDefs::EElementSmartLinkTel || elType == TBrCtlDefs::EElementSmartLinkEmail)
+            type = IBeamCursor;
+        else if (m_view->brCtl()->settings()->getTabbedNavigation() && elType == TBrCtlDefs::EElementSelectMultiBox)
+            type = SelectMultiCursor;
+        else
+            type = HandCursor;
+    }
+    setCursor(type);
+}
+
+
+
+// -----------------------------------------------------------------------------
+// CWebKitCursor::getFrameAtPoint
+// -----------------------------------------------------------------------------
+WebFrame* WebCursor::getFrameAtPoint(const TPoint& viewPos_)
+    {
+    if (!m_view)
+        return 0;
+    WebFrame* frameAtPoint = m_view->mainFrame()->frameAtPoint(viewPos_);
+    if (!frameAtPoint)
+        frameAtPoint = m_view->mainFrame();
+    return frameAtPoint;
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::Reset
+// -----------------------------------------------------------------------------
+void WebCursor::reset()
+    {
+    m_view->setFocusedElementType(TBrCtlDefs::EElementNone);
+    cursorUpdate(true);
+    m_nodeRect = TRect();
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::SetWaitCursor
+// -----------------------------------------------------------------------------
+void WebCursor::setWaitCursor(bool waiton)
+    {
+    m_waiton = waiton;
+    if (m_waiton)
+        setCursor(PointerCursor);
+    else
+        cursorUpdate(m_visible);
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::OffsetCursor
+// -----------------------------------------------------------------------------
+void WebCursor::offsetCursor(const TPoint& offset)
+    {
+    m_pos -= offset;
+    m_nodeRect.Move(-offset.iX,-offset.iY);
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::SetTransparent
+// -----------------------------------------------------------------------------
+void WebCursor::setTransparent(bool transparent)
+{
+    if (transparent)
+        m_transtimer->Cancel();
+    if (m_transparent != transparent) {
+        m_transparent = transparent;
+        // only pointer cursor is transparent
+        if (m_transparent && m_view->focusedElementType() == TBrCtlDefs::EElementNone)
+            setCursor(PointerCursor);
+        else
+            cursorUpdate(m_visible);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// WebCursor::SetOpaqueUntil
+// -----------------------------------------------------------------------------
+void WebCursor::setOpaqueUntil(int microsecs)
+    {
+    setTransparent(false);
+    m_transtimer->Cancel();
+    m_transtimer->Start(microsecs,0,TCallBack(TransparencyTimerCb,this));
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::IncreaseTransparencyMoveCount
+// -----------------------------------------------------------------------------
+void WebCursor::increaseTransparencyMoveCount()
+    {
+    ++m_transcount;
+    }
+
+// -----------------------------------------------------------------------------
+// WebCursor::ResetTransparency
+// -----------------------------------------------------------------------------
+void WebCursor::resetTransparency()
+    {
+    m_transcount = 0;
+    setOpaqueUntil(KTransparencyTime);
+    }
+
+//-------------------------------------------------------------------------------
+// WebCursor::innerRect()
+//-------------------------------------------------------------------------------
+void WebCursor::innerRect(TRect& rect)
+{
+  TPoint c = rect.Center();
+  int z = m_view->scalingFactor();
+  int dx = KCursorIncremental * z / 100;
+  int dy = KCursorIncremental * z / 100;
+
+  dx = Max(dx, 2 * rect.Width() / 5);
+  dy = Max(dy, 2 * rect.Height() / 5);
+
+  rect.Shrink(dx, dy);
+
+  if (!rect.IsNormalized()) {
+    rect.SetRect(c, c);
+  }
+}
+
+//-------------------------------------------------------------------------------
+// WebCursor::frameHasContentToScroll()
+//-------------------------------------------------------------------------------
+bool WebCursor::frameHasContentToScroll(WebFrame* frame, TPoint& delta)
+{
+    WebFrameView* rfv = frame->frameView();
+    TPoint contentpos = rfv->contentPos();
+    TSize contentsize = rfv->contentSize();
+    bool hasContentToScrollY = false;
+    bool hasContentToScrollX = false;
+
+    if (delta.iY > 0)
+        {
+        hasContentToScrollY = (contentpos.iY < (contentsize.iHeight - rfv->rect().Height()));
+        }
+    else if (delta.iY < 0)
+        {
+        hasContentToScrollY = (contentpos.iY > 0);
+        }
+
+    if (delta.iX > 0)
+        {
+        hasContentToScrollX = (contentpos.iX < (contentsize.iWidth - rfv->rect().Width()));
+        }
+    else if (delta.iX < 0)
+        {
+        hasContentToScrollX = (contentpos.iX > 0);
+        }
+
+    return hasContentToScrollY || hasContentToScrollX;
+
+}
+
+//-------------------------------------------------------------------------------
+// WebCursor::determineScrollingFrame()
+//-------------------------------------------------------------------------------
+WebFrame*  WebCursor::determineScrollingFrame(int border1, int border2, int pos,
+                                              WebFrame* fr1, WebFrame* fr2, TPoint& delta)
+{
+  WebFrame* ret = NULL;
+
+  if (pos < border1 && pos < border2) return ret; //"magic" line has not been reached
+  if (pos >= border1 && pos >= border2) {
+      if (border1 > border2) {
+          ret = frameHasContentToScroll(fr2, delta) ? fr2 : fr1;
+      }
+      else {
+          ret = frameHasContentToScroll(fr1, delta) ? fr1 : fr2;
+      }
+  }
+  else if (border1 <= pos && pos <= border2) {//"magic" line of fr1 was hit first
+      ret = fr1;
+  }
+  else if (border2 <= pos && pos <= border1) {//"magic" line of fr2 was hit first
+      ret = fr2;
+  }
+  return ret;
+}
+
+
+//-------------------------------------------------------------------------------
+// WebCursor::calculateScrollableFrameView()
+// TODO: Investigate diagonal events, especially in the light of IFrames.
+//-------------------------------------------------------------------------------
+WebFrame* WebCursor::calculateScrollableFrameView(TPoint& pos, TPoint& delta, TRect& fRect, bool autoscroll)
+{
+  WebFrame* frame = getFrameAtPoint(pos);
+  WebFrame* ret_frame = NULL;
+  WebFrameView* mfView = m_view->mainFrame()->frameView();
+  TPoint docContPos = mfView->toViewCoords(mfView->contentPos());
+  int z = m_view->scalingFactor();
+  m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100;
+  m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100;
+
+
+  for (; frame; frame = frame->parentFrame())  {
+    bool hScroll = frame->frameView()->hScrollbar()->isEnabled();
+    bool vScroll = frame->frameView()->vScrollbar()->isEnabled();
+          // Dont scroll a frameset
+    if (frame->parentFrame() && frame->parentFrame()->isFrameSet()) {
+      continue;
+    }
+    else if (frame->parentFrame() && !hScroll && !vScroll) {
+      continue;
+    }
+    else if (!frame->parentFrame()) { //main view
+      hScroll = true;
+      vScroll = true;
+    }
+
+
+    WebFrame*  pf = frame->parentFrame() ? frame->parentFrame() : m_view->mainFrame();
+    WebFrameView* pfv = pf->frameView();
+    WebFrameView* ppfv = pf->parentFrame() ? pf->parentFrame()->frameView() : NULL;
+    TRect pfRect = pfv->rect();
+    if (ppfv) {// parent frame is not a main frame
+        pfRect = TRect(ppfv->frameCoordsInViewCoords(pfRect.iTl),
+                          ppfv->frameCoordsInViewCoords(pfRect.iBr));
+    }
+
+    WebFrameView* fv = frame->frameView();
+    TRect framerect = fv ->rect();
+    if (frame->parentFrame()) {// frame is not a main frame
+       framerect = TRect(pfv->frameCoordsInViewCoords(framerect.iTl),
+                         pfv->frameCoordsInViewCoords(framerect.iBr));
+    }
+
+    TRect pfInnerRect = pfRect;
+    innerRect(pfInnerRect);
+    TRect fInnerRect = framerect;
+    innerRect(fInnerRect);
+
+
+    // See which "magic" line we crossed first
+    if (delta.iY > 0) {  //scroll down.
+        ret_frame = determineScrollingFrame(pfInnerRect.iBr.iY, fInnerRect.iBr.iY, pos.iY, pf, frame, delta);
+        m_incrLimit.iY = Min (m_incrLimit.iY, Abs(framerect.iBr.iY - pos.iY));
+    }
+    else if (delta.iY < 0) { //scroll up.
+        ret_frame = determineScrollingFrame(-pfInnerRect.iTl.iY, -fInnerRect.iTl.iY, -pos.iY, pf, frame, delta);
+        m_incrLimit.iY = Min (m_incrLimit.iY, Abs(pos.iY - framerect.iTl.iY));
+    }
+
+    if (delta.iX > 0) {
+        ret_frame = determineScrollingFrame(pfInnerRect.iBr.iX, fInnerRect.iBr.iX, pos.iX, pf, frame, delta);
+        m_incrLimit.iX = Min (m_incrLimit.iX, Abs(framerect.iBr.iX - pos.iX));
+    }
+    else if (delta.iX < 0) {
+        ret_frame = determineScrollingFrame(-pfInnerRect.iTl.iX, -fInnerRect.iTl.iX, -pos.iX, pf, frame, delta);
+        m_incrLimit.iX = Min (m_incrLimit.iX, Abs(pos.iX - framerect.iTl.iX));
+    }
+
+    fRect = (ret_frame == frame) ? framerect : pfRect;
+
+     if (ret_frame) {
+        if (!ret_frame->parentFrame()) {
+                m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100;
+                m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100;
+        }
+
+        if (!frameHasContentToScroll(ret_frame, delta)) {
+            ret_frame = NULL;
+            m_incrLimit.iX = KCursorIncremental * z / 100;
+            m_incrLimit.iY = KCursorIncremental * z / 100;
+        }
+
+        if (ret_frame) {
+            m_incrLimit.iX = Max(m_incrLimit.iX, KMiddleStep);
+            m_incrLimit.iY = Max(m_incrLimit.iY, KMiddleStep);
+            break;
+        }
+    }
+    else {
+         m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100;
+         m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100;
+    }
+  }
+
+  return ret_frame;
+}
+
+
+//-------------------------------------------------------------------------------
+// Method that scrolls and moves the cursor based on the navigation algorithm
+// TODO: Investigate "autoscroll" and diagonal events from real HW and the
+//       diagonal event simulator wedge.
+//-------------------------------------------------------------------------------
+void WebCursor::scrollAndMoveCursor(int dir, int scrollRange, bool autoscroll)
+{
+    if (!m_view)
+        return;
+
+    int lr = 0;
+    int tb = 0;
+    int deltaX;
+    int deltaY;
+
+    switch (dir)
+      {
+
+        case EKeyUpArrow:             // North
+          tb = -1;
+          break;
+
+        case EKeyRightUpArrow:        // Northeast
+        case EStdKeyDevice11:         //   : Extra KeyEvent supports diagonal event simulator wedge
+          tb = -1;
+          lr = +2;                    // Make it run closer to 45 degrees
+          break;
+
+        case EKeyRightArrow:          // East
+          lr = +1;
+          break;
+
+        case EKeyRightDownArrow:      // Southeast
+        case EStdKeyDevice12:         //   : Extra KeyEvent supports diagonal event simulator wedge
+          tb = +1;
+          lr = +2;
+          break;
+
+        case EKeyDownArrow:           // South
+          tb = +1;
+          break;
+
+        case EKeyLeftDownArrow:       // Southwest
+        case EStdKeyDevice13:         //   : Extra KeyEvent supports diagonal event simulator wedge
+          tb = +1;
+          lr = -2;
+          break;
+
+        case EKeyLeftArrow:           // West
+          lr = -1;
+          break;
+
+        case EKeyLeftUpArrow:         // Northwest
+        case EStdKeyDevice10:         //   : Extra KeyEvent supports diagonal event simulator wedge
+          tb = -1;
+          lr = -2;
+          break;
+
+        default:
+          break;
+
+      }
+
+    deltaX = lr * scrollRange/2;
+    deltaY = tb * scrollRange;
+
+    TPoint delta = TPoint(deltaX, deltaY);
+    WebFrame* frame = NULL;
+    WebFrameView* fv = NULL;
+    TPoint oldpos;
+    TRect inRect = TRect();
+    bool needScroll = false;
+
+    frame = calculateScrollableFrameView(m_pos, delta, inRect, autoscroll);
+    needScroll = (frame != NULL);
+    if (!frame) {
+      frame = m_view->mainFrame();
+    }
+    fv = frame->frameView();
+    oldpos = fv->contentPos();
+
+    if (autoscroll || m_view->pageView()) {
+        // scroll
+        fv->scrollTo(oldpos + delta);
+
+        if (!m_view->pageView()) {
+            TPoint cp = position();
+            if (fv->contentPos() == oldpos) {
+                // not scrolling, move the cursor instead
+                cp.iX += deltaX;
+                cp.iY += deltaY;
+            } else {
+                // move cursor slowly out of the way
+                cp.iX += deltaX/6;
+                cp.iY += deltaY/6;
+            }
+            // limit the movement, don't scroll out of the view area
+            if (lr != 0) {
+              cp.iX = (lr < 0) ? Max(inRect.iTl.iX + 8, cp.iX) : Min(inRect.iBr.iX - 8, cp.iX);
+            }
+            if (tb != 0) {
+              cp.iY = (tb < 0) ? Max(inRect.iTl.iY + 8, cp.iY) : Min(inRect.iBr.iY - 8, cp.iY);
+            }
+            if (cp.iX == (inRect.iTl.iX + 8) || (cp.iX == inRect.iBr.iX - 8) ||
+                (cp.iY == inRect.iTl.iY + 8) || (cp.iY == inRect.iBr.iY - 8)) {
+            }
+            setPosition(cp);
+            reset();
+        }
+        return;
+    }
+    if (!handleSelectElementScrolling(m_view, tb)) {
+        // link snapping
+      moveCursor( lr,tb,scrollRange);
+    }
+
+    TPoint newpos(oldpos);
+    newpos += TPoint(lr*scrollRange/2, tb*scrollRange);
+    newpos = fv->nearestPointInFrame(newpos);
+
+    int adjustedScrollRange = Abs(lr*(newpos.iX - oldpos.iX)) + Abs(tb*(newpos.iY - oldpos.iY));
+
+    if (lr==0)
+        increaseTransparencyMoveCount();
+    else
+        resetTransparency();
+
+    if (adjustedScrollRange) {
+        TPoint p = position();
+        if ( needScroll ) {
+            innerRect(inRect);
+            int deltax = (lr != 0 ) ? ( (lr > 0) ? (p.iX - inRect.iBr.iX) : (inRect.iTl.iX - p.iX ) ) : 0 ;
+            int deltay = (tb != 0 ) ? ( (tb > 0) ? (p.iY - inRect.iBr.iY ) : (inRect.iTl.iY - p.iY) ) : 0 ;
+            deltax = Min(adjustedScrollRange, deltax);
+            deltay = Min(adjustedScrollRange, deltay);
+            TPoint offset(fv->toViewCoords(TPoint(lr*deltax,tb*deltay)));
+            offsetCursor(offset);
+            fv->scrollTo(oldpos+TPoint(lr*deltax , tb*deltay));
+        } else {
+            if (m_view->pageView())
+                m_view->brCtl()->DrawNow();
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// WebCursor::setPosition
+// -----------------------------------------------------------------------------
+void WebCursor::updatePositionAndElemType(const TPoint& pt)
+{
+    m_pos = pt;
+    m_sprite.SetPosition(pt);
+    WebFrame* frame = getFrameAtPoint(pt);
+    TBrCtlDefs::TBrCtlElementType elType;
+    TRect r;
+    TPoint point(frame->frameView()->viewCoordsInFrameCoords(m_pos));
+    if (m_view && navigableNodeUnderCursor(*frame, point, elType, r)) {
+        m_view->setFocusedElementType(elType);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// WebCursor::movecursor
+// -----------------------------------------------------------------------------
+void WebCursor::moveCursor(int lr,int tb, int scrollRange)
+    {
+    TPoint cp(m_pos);
+    int z = m_view->scalingFactor();
+
+    //Flipping is set to true only if the user make 3 consective moves in opposite direction
+    //ie if the user went in up down up direction then we apply the flipping logic
+    if ( ( lr*m_previousLr == -1 || tb*m_previousTb == -1) )
+        {
+        m_flipcounter++ ;
+        }
+    else m_flipcounter = 0;
+
+    m_previousLr = lr;
+    m_previousTb = tb;
+
+    if (m_view->focusedElementType() == TBrCtlDefs::EElementAnchor && !m_nodeRect.IsEmpty() && m_flipcounter <= 1 ) {
+        TSize nodeSizeInDocCoords(m_view->mainFrame()->frameView()->toDocCoords(m_nodeRect.Size()));
+        if ( tb == 0 && nodeSizeInDocCoords.iWidth < scrollRange) {
+            cp.iX = (lr == -1) ? Min(cp.iX , Max(m_nodeRect.iTl.iX, cp.iX - m_incrLimit.iX)) :
+                                 Max(cp.iX, Min(m_nodeRect.iBr.iX, cp.iX + m_incrLimit.iX));
+        }
+        if ( lr == 0 && nodeSizeInDocCoords.iHeight < scrollRange) {
+            cp.iY = (tb == -1) ? Min(cp.iY, Max(m_nodeRect.iTl.iY, cp.iY - m_incrLimit.iY)) :
+                                 Max(cp.iY, Min(m_nodeRect.iBr.iY, cp.iY + m_incrLimit.iY));
+        }
+    }
+
+    m_incrLimit.iX -= Abs(m_pos.iX - cp.iX);
+    m_incrLimit.iY -= Abs(m_pos.iY - cp.iY);
+
+    cp.iX += lr*Min(KCursorIncremental*z/100, m_incrLimit.iX);
+    cp.iY += tb*Min(KCursorIncremental*z/100, m_incrLimit.iY);
+
+    TRect rec(TPoint(0,0), m_view->offscreenRect().Size());
+    // limit the movement, don't scroll out of the view area
+    cp.iX = Min(rec.Width(), Max( 0 , cp.iX));
+    cp.iY = Min(rec.Height(), Max( 0 , cp.iY));
+
+    TPoint rPos[] = { cp, cp };
+    rPos[0] -= TPoint(lr*KMiddleStep*z/100,tb*KMiddleStep*z/100);
+
+    // user is trying hard to focus a small element
+    if ( m_flipcounter > 1 )
+        {
+        int flipDistance = KFlipAdjust * z/(100 * (m_flipcounter - 1));
+        rPos[0] = m_pos + TPoint(lr * flipDistance/2,tb * flipDistance/2);
+        rPos[1] = m_pos + TPoint(lr * flipDistance,tb * flipDistance);
+        }
+
+    m_pos = rPos[0];
+
+    for ( int i = 0;i < 2; i++ )
+        {
+        WebFrame* frame = getFrameAtPoint(rPos[i]);
+        if ( !frame ) continue;
+
+        m_view->page()->focusController()->setFocusedFrame(core(frame));
+        TPoint pt = frame->frameView()->viewCoordsInFrameCoords(rPos[i]);
+
+        // now let's do the probing
+        TBrCtlDefs::TBrCtlElementType elType = TBrCtlDefs::EElementNone;
+        TRect nr = TRect();
+
+        bool test = navigableNodeUnderCursor(*frame, pt, elType, nr);
+
+        TRect rt(frame->frameView()->frameCoordsInViewCoords(nr.iTl),m_view->mainFrame()->frameView()->toViewCoords(nr.Size()));
+        rt.Intersection(rec);
+
+        if (i == 0 && ( !test || (m_view->focusedElementType() == elType  && rt == m_nodeRect)) ) continue;
+
+        if ( i == 1 && !test && m_flipCounter <= 1 && !m_nodeRect.IsEmpty())
+            {
+            //Go to webcore to figure out a possible node
+            TRect searchRect = calcSearchRect(lr,tb, scrollRange);
+            TPoint cp(m_pos);
+            WebFrame* f = getFrameAtPoint(cp);
+            if ( !f ) continue;
+
+            cp = f->frameView()->viewCoordsInFrameCoords(cp);
+            bool found = determineCursorPosition(*f, elType, nr, searchRect, cp, false);
+            if ( found )
+                {
+                m_pos = f->frameView()->frameCoordsInViewCoords(cp);
+
+                m_nodeRect = TRect(f->frameView()->frameCoordsInViewCoords(nr.iTl),m_view->mainFrame()->frameView()->toViewCoords(nr.Size()) );
+                m_nodeRect.Intersection(rec);
+                m_view->setFocusedElementType(elType);
+                return;
+                }
+            }
+
+        m_pos = frame->frameView()->frameCoordsInViewCoords(pt);
+        m_nodeRect = rt;
+        m_view->setFocusedElementType(elType);
+        return;
+        }
+    }
+
+
+bool WebCursor::navigableNodeUnderCursor(WebFrame& webFrame, TPoint& aPoint, TBrCtlDefs::TBrCtlElementType& aElType, TRect& aFocusRect) const
+{
+    Frame* coreFrame = core(&webFrame);
+    if (!coreFrame->renderer() )
+        return false;
+
+    Element* node = coreFrame->document()->elementFromPoint(aPoint.iX, aPoint.iY);
+
+    if (node) {
+        return coreFrame->bridge()->getTypeFromElement(node, aElType, aFocusRect);
+    }
+
+    return false;
+}
+
+bool WebCursor::determineCursorPosition( WebFrame& webFrame, TBrCtlDefs::TBrCtlElementType& aElType,
+                                         TRect& aFocusRect, TRect& aSearchRect,
+                                         TPoint &aCursorPosition, bool aInitialize)
+{
+    // FIXME: cursor navigation not implemented
+    IntRect searchRt(aSearchRect);
+    IntPoint pt(aCursorPosition.iX,aCursorPosition.iY);
+    bool found = false;
+
+    if (aInitialize && core(&webFrame)->document()->focusedNode()) {
+       IntRect nodeRect = core(&webFrame)->document()->focusedNode()->getRect();
+       if (nodeRect.intersects(searchRt)) {
+          IntRect rt = nodeRect;
+          rt.intersect(searchRt);
+          pt = IntPoint( rt.x() + rt.width()>>1, rt.y() + rt.height()>>1 );
+          found = true;
+       }
+    }
+
+    found = decideCursorPosition(webFrame, searchRt, pt);
+    TPoint newPos(pt.x(),pt.y());
+
+    bool retest = false;
+    if (found)
+       retest = navigableNodeUnderCursor(webFrame, newPos,aElType,aFocusRect);
+
+    if (!retest)
+        return false;
+
+    aCursorPosition = newPos;
+    return retest;
+}
+
+
+TRect WebCursor::calcSearchRect(int lr, int tb, int scrollRange)
+{
+    TRect searchRect;
+    TPoint pt(m_nodeRect.iTl);
+    TSize nodeSz(m_view->mainFrame()->frameView()->toDocCoords(m_nodeRect.Size()));
+
+    WebFrame* focused = getFrameAtPoint(m_pos);
+    if (!focused)
+        return searchRect;
+    pt = focused->frameView()->viewCoordsInFrameCoords(pt);
+
+    if (focused) {
+        TSize sz( (lr == 0) ? nodeSz.iWidth: scrollRange , (tb == 0) ? nodeSz.iHeight:scrollRange);
+        pt.iX += (tb != 0) ? 0 : (lr == -1) ? -scrollRange: nodeSz.iWidth ;
+        pt.iY += (lr != 0) ? 0 : (tb == -1) ? -scrollRange: nodeSz.iHeight ;
+        searchRect = TRect(pt,sz);
+
+        TBrCtlDefs::TBrCtlElementType elType = m_view->focusedElementType();
+        if (    elType == TBrCtlDefs::EElementInputBox
+             || elType == TBrCtlDefs::EElementTextAreaBox
+             || elType == TBrCtlDefs::EElementRadioButtonUnSelected
+             || elType == TBrCtlDefs::EElementButton
+             || elType == TBrCtlDefs::EElementCheckBoxUnChecked
+             || elType == TBrCtlDefs::EElementCheckBoxChecked
+             || elType == TBrCtlDefs::EElementRadioButtonSelected )
+          increaseSearchRect(lr, tb, searchRect);
+    }
+    return searchRect;
+}
+
+void WebCursor::increaseSearchRect(int lr,int tb,TRect& aRect)
+{
+    int width(aRect.Width());
+    int height(aRect.Height());
+
+    // enlarge the search rect for aggressive probing, the origninal ccb implementation is faulty.
+    if (lr) {
+        if (lr > 0)
+            aRect.SetWidth(width + width*KAggressiveSearch/100);   // right
+        else
+            aRect.iTl.iX -= width*KAggressiveSearch/100;            // left
+    } else if (tb) {
+        if (tb > 0)
+            aRect.SetHeight(height + height*KAggressiveSearch/100); // down
+        else
+            aRect.iTl.iY -= height*KAggressiveSearch/100;           // up
+    }
+    m_flipCounter = 0;
+}
+
+bool WebCursor::decideCursorPosition(WebFrame& webFrame, const IntRect& searchRect, IntPoint& cursorPosition)
+{
+    int distance = -1;
+    bool found = false;
+    IntPoint cp = cursorPosition;
+
+    const int minWidth = 5;
+    const int minHeight = 5;
+
+    Vector<WebCore::IntRect>& recList = *(webFrame.bridge()->focusableRectList());
+
+    if (recList.isEmpty())
+        return false;
+
+    for (int i = 0;i < recList.size();i++) {
+        IntRect nr = recList[i];
+
+        //Resize the rect so that the cursor is comfortably inside the box
+        nr.inflate(-2);
+
+        if (!nr.intersects(searchRect)) continue;
+
+        IntRect intersectRect = nr;
+        intersectRect.intersect(searchRect);
+
+        if ( (nr.width() != intersectRect.width() && intersectRect.width() < minWidth)
+           || (nr.height() != intersectRect.height() && intersectRect.height() < minHeight) )
+            continue;
+
+        intersectRect.inflate(-1);
+        found = true;
+
+        IntPoint np = nearestPointInRect(cp,intersectRect);
+        int disFromCursor = (np.x() - cp.x())*(np.x() - cp.x())
+                           + (np.y() - cp.y())*(np.y() - cp.y());
+
+        if (distance == -1 || distance > disFromCursor) {
+            distance = disFromCursor;
+            cursorPosition = np;
+        }
+    }
+
+    return found;
+}
+
+WebFrame* WebCursor::getFrameUnderCursor()
+{
+  return getFrameAtPoint(m_pos);
+}
+
+
+
+// END OF FILE