--- /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