webengine/osswebengine/WebKit/s60/misc/WebTabbedNavigation.cpp
changeset 0 dd21522fd290
child 8 7c90e6132015
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Frame in webkit side
       
    15 *
       
    16 */
       
    17 
       
    18 #include "config.h"
       
    19 #include <../bidi.h>
       
    20 #include <e32math.h>
       
    21 #include <e32base.h>
       
    22 #include "WebTabbedNavigation.h"
       
    23 #include "WebUtil.h"
       
    24 #include "Document.h"
       
    25 #include "Frame.h"
       
    26 #include "HTMLNames.h"
       
    27 #include "FrameTree.h"
       
    28 #include "BrCtlDefs.h"
       
    29 #include "WebCursor.h"
       
    30 #include "StaticObjectsContainer.h"
       
    31 #include "Page.h"
       
    32 #include "WebView.h"
       
    33 #include "WebFrame.h"
       
    34 #include "WebFrameView.h"
       
    35 #include <wtf/RefPtr.h>
       
    36 #include "EventHandler.h"
       
    37 #include "webkitlogger.h"
       
    38 #include "FocusController.h"
       
    39 #include "RenderListBox.h"
       
    40 #include "HTMLSelectElement.h"
       
    41 
       
    42 using namespace WebCore;
       
    43 using namespace HTMLNames;
       
    44 
       
    45 const int KMaxJumpPercent = 90;
       
    46 const int KScrollWhenNotFound = 5;
       
    47 
       
    48 WebTabbedNavigation::WebTabbedNavigation(WebView* webView)
       
    49 {
       
    50     m_webView = webView;
       
    51     clear();
       
    52 }
       
    53 
       
    54 WebTabbedNavigation::~WebTabbedNavigation()
       
    55 {
       
    56 }
       
    57 
       
    58 void WebTabbedNavigation::clear()
       
    59 {
       
    60     // Different initialization for mirrored layouts?
       
    61     m_selectedElementRect.SetRect(0, 0, m_webView->Rect().Width(), 0);
       
    62     m_initializedForPage = false;
       
    63     m_firstNavigationOnPage = true;
       
    64     m_focusPosition = TPoint(0,0);
       
    65     m_node = NULL;
       
    66 }
       
    67 
       
    68 void WebTabbedNavigation::initializeForPage()
       
    69 {
       
    70     if (!m_initializedForPage) {
       
    71         if (navigate(0, 1)) {
       
    72             m_initializedForPage = true;
       
    73             m_firstNavigationOnPage = false;
       
    74         }
       
    75     }
       
    76 }
       
    77 
       
    78 
       
    79 bool WebTabbedNavigation::navigate(int horizontalDir, int verticalDir)
       
    80 {
       
    81     if (handleSelectElementScrolling(m_webView, verticalDir)) {
       
    82         StaticObjectsContainer::instance()->webCursor()->cursorUpdate(true);
       
    83         return true;
       
    84     }
       
    85     bool ret = m_firstNavigationOnPage;
       
    86     Frame* focusedFrame = m_webView->page()->focusController()->focusedFrame();
       
    87     if (focusedFrame == NULL) focusedFrame = m_webView->page()->mainFrame();
       
    88     if (focusedFrame->document()) {
       
    89         Node* focusNode = focusedFrame->document()->focusedNode();
       
    90         if (focusNode) {
       
    91             m_node = focusNode;
       
    92             m_selectedElementRect = focusNode->getRect().Rect();
       
    93             Frame* frame = focusNode->document()->frame();
       
    94             m_selectedElementRect = TRect(kit(frame)->frameView()->frameCoordsInViewCoords(m_selectedElementRect.iTl), 
       
    95                 kit(frame)->frameView()->frameCoordsInViewCoords(m_selectedElementRect.iBr));
       
    96         }
       
    97     }
       
    98     TPoint oldFocusPoint(m_focusPosition);
       
    99     // Move the focus to the edge of the current object
       
   100     if (horizontalDir == -1) {
       
   101         m_focusPosition.iX = m_selectedElementRect.iTl.iX;
       
   102     }
       
   103     else if (horizontalDir == 1) {
       
   104         m_focusPosition.iX = m_selectedElementRect.iBr.iX;
       
   105     }
       
   106     if (verticalDir == -1) {
       
   107         m_focusPosition.iY = m_selectedElementRect.iTl.iY;
       
   108     }
       
   109     else if (verticalDir == 1) {
       
   110         m_focusPosition.iY = m_selectedElementRect.iBr.iY;
       
   111     }
       
   112     wkDebug()<<"WebTabbedNavigation::navigate. x = "<<m_focusPosition.iX<<" y = "<<m_focusPosition.iY<<flush;
       
   113     wkDebug()<<"x1 = "<<m_selectedElementRect.iTl.iX<<" y1 = "<<m_selectedElementRect.iTl.iY<<" x2 = "<<m_selectedElementRect.iBr.iX<<" y2 = "<<m_selectedElementRect.iBr.iY<<flush;
       
   114     
       
   115     // Adjust the move
       
   116     TPoint br;
       
   117     br.iX = m_webView->Rect().iBr.iX * KMaxJumpPercent / m_webView->scalingFactor();
       
   118     br.iY = m_webView->Rect().iBr.iY * KMaxJumpPercent / m_webView->scalingFactor();
       
   119     TRect view;
       
   120     // define the view rect where we are looking for a match
       
   121     if (horizontalDir == -1) {
       
   122         view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX, m_focusPosition.iY + br.iY);
       
   123     }
       
   124     else if (horizontalDir == 1) {
       
   125         view.SetRect(m_focusPosition.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY + br.iY);
       
   126     }
       
   127     else if (verticalDir == -1) {
       
   128         view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY);
       
   129     }
       
   130     else if (verticalDir == 1) {
       
   131         view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY + br.iY);
       
   132     }
       
   133     //wkDebug()<<"view x1 = "<<view.iTl.iX<<" y1 = "<<view.iTl.iY<<" x2 = "<<view.iBr.iX<<" y2 = "<<view.iBr.iY<<flush;
       
   134     // walk all focusable nodes
       
   135     Frame* f = m_webView->page()->mainFrame();
       
   136     TPoint selectedPoint(0, 0);
       
   137     TRect selectedRect(0, 0, 0, 0);
       
   138     Node* selectedNode = NULL;
       
   139     while ( f ) {
       
   140         PassRefPtr<HTMLCollection> elements = f->document()->all();   
       
   141         TRect frameRect = kit(f)->frameView()->rectInGlobalCoords();
       
   142         for (Node* n = elements->firstItem(); n; n = elements->nextItem()) {
       
   143             if (n == m_node) continue;
       
   144             if (n->isFocusable() && n->isElementNode() && !n->hasTagName(iframeTag) && !n->hasTagName(frameTag)) {
       
   145                 // Does the node intersect with the view rect?
       
   146                 TRect nodeRect = n->getRect().Rect();
       
   147                 //wkDebug()<<"Each node rect x1 = "<<nodeRect.iTl.iX<<" y1 = "<<nodeRect.iTl.iY<<" x2 = "<<nodeRect.iBr.iX<<" y2 = "<<nodeRect.iBr.iY<<flush;
       
   148                 nodeRect = TRect(kit(f)->frameView()->frameCoordsInViewCoords(nodeRect.iTl), 
       
   149                     kit(f)->frameView()->frameCoordsInViewCoords(nodeRect.iBr));
       
   150                 if (nodeRect.Intersects(view)) {
       
   151                     // Compare nodes and select the best fit
       
   152                     TPoint newFocusPoint = potentialFocusPoint(horizontalDir, verticalDir, nodeRect);
       
   153                     wkDebug()<<"Matching node rect x1 = "<<nodeRect.iTl.iX<<" y1 = "<<nodeRect.iTl.iY<<" x2 = "<<nodeRect.iBr.iX<<" y2 = "<<nodeRect.iBr.iY<<flush;
       
   154                     if (selectNode(horizontalDir, verticalDir, selectedRect, nodeRect, selectedPoint, newFocusPoint)) {
       
   155                         // found a better fit
       
   156                         selectedNode = n;
       
   157                         selectedRect.SetRect(nodeRect.iTl, nodeRect.iBr);
       
   158                         selectedPoint = newFocusPoint;
       
   159                     }
       
   160                 } // if (nodeRect.Intersects(rect[i])
       
   161             } // if (n->isFocusable() && n->isElementNode())
       
   162         } // for (Node* n = elements->firstItem(); n; n = elements->nextItem())
       
   163         f = f->tree()->traverseNext();
       
   164     } // while ( f )
       
   165     // Remember new selection
       
   166     TPoint contentPos = m_webView->mainFrame()->frameView()->contentPos();
       
   167     if (selectedNode) {
       
   168         // Found an element to jump to
       
   169         m_selectedElementRect = selectedRect;
       
   170         m_focusPosition = selectedPoint;
       
   171         m_node = selectedNode;
       
   172         selectedNode->document()->setFocusedNode(selectedNode);
       
   173          m_webView->page()->focusController()->setFocusedFrame(selectedNode->document()->frame());
       
   174         // And scroll to the selected element
       
   175         RenderLayer *layer = selectedNode->renderer()->enclosingLayer();
       
   176         if (layer) {
       
   177             layer->scrollRectToVisible(selectedNode->getRect(), RenderLayer::gAlignCenterIfNeeded, RenderLayer::gAlignCenterIfNeeded);
       
   178             TRect newRect = TRect(kit(selectedNode->document()->frame())->frameView()->frameCoordsInViewCoords(selectedNode->getRect().Rect().iTl), 
       
   179                 kit(selectedNode->document()->frame())->frameView()->frameCoordsInViewCoords(selectedNode->getRect().Rect().iBr));
       
   180             selectedPoint += (newRect.iTl - selectedRect.iTl);
       
   181             m_focusPosition = selectedPoint;
       
   182             selectedRect = newRect;
       
   183             m_selectedElementRect = selectedRect;
       
   184             StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(selectedPoint);
       
   185             // special handling for Select-Multi
       
   186             if (m_webView->focusedElementType() == TBrCtlDefs::EElementSelectMultiBox) {
       
   187                 Element* e = static_cast<Element*>(m_node);
       
   188                 if (e->isControl()) {
       
   189                     HTMLGenericFormElement* ie = static_cast<HTMLGenericFormElement*>( e );
       
   190                     if (ie->type() == "select-multiple") {
       
   191                         RenderListBox* render = static_cast<RenderListBox*>(e->renderer());
       
   192                         HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>( e );
       
   193                         IntRect itemRect = render->itemRect(0, 0, 0);
       
   194                         TPoint cursorPoint(StaticObjectsContainer::instance()->webCursor()->position());
       
   195                         int gap = (20 * m_webView->scalingFactor()) / 100;
       
   196                         cursorPoint.iX = max(m_focusPosition.iX,  m_selectedElementRect.iTl.iX + gap);
       
   197                         cursorPoint.iX = std::min(cursorPoint.iX,  m_selectedElementRect.iBr.iX - gap);
       
   198                         if (verticalDir == -1) {
       
   199                             cursorPoint.iY -= (itemRect.height() * m_webView->scalingFactor()) / 125;
       
   200                         }
       
   201                         if (cursorPoint != StaticObjectsContainer::instance()->webCursor()->position()) {
       
   202                             StaticObjectsContainer::instance()->webCursor()->setPosition(cursorPoint);
       
   203                         }
       
   204                     }
       
   205                 }
       
   206             }
       
   207             TPointerEvent event;
       
   208             event.iPosition = StaticObjectsContainer::instance()->webCursor()->position();
       
   209             event.iModifiers = 0;
       
   210             event.iType = TPointerEvent::EMove;
       
   211             core(m_webView->mainFrame())->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event));            
       
   212             wkDebug()<<"Focus position x = "<<selectedPoint.iX<<" y = "<<selectedPoint.iY<<flush;
       
   213             ret = true;
       
   214         }
       
   215     }
       
   216     else {
       
   217         if (!m_firstNavigationOnPage) {
       
   218             m_webView->mainFrame()->frameView()->scrollTo(contentPos + TPoint(horizontalDir * m_webView->Rect().Width() / KScrollWhenNotFound, verticalDir * m_webView->Rect().Height() / KScrollWhenNotFound));
       
   219             TPoint diff(m_webView->mainFrame()->frameView()->contentPos() - contentPos);
       
   220             if (diff.iX || diff.iY) {
       
   221                 m_selectedElementRect.Move(diff);
       
   222                 m_focusPosition = oldFocusPoint + diff;
       
   223                 m_node = NULL;
       
   224                 StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(m_focusPosition - m_webView->mainFrame()->frameView()->contentPos());
       
   225                 ret = true;
       
   226             }
       
   227         }
       
   228     }
       
   229     StaticObjectsContainer::instance()->webCursor()->cursorUpdate(true);
       
   230     return ret;
       
   231 }
       
   232 
       
   233 bool WebTabbedNavigation::selectNode(int horizontalDir, int verticalDir, TRect& selectedRect, TRect& newNodeRect, TPoint& selectedPoint, TPoint& newFocusPoint)
       
   234 {
       
   235     if (selectedPoint == TPoint(0, 0)) { // first selected node fixme: ensure not to divert direction too much
       
   236         return true;
       
   237     }
       
   238     int selectedDist = distanceFunction(horizontalDir, verticalDir, selectedRect, selectedPoint);
       
   239     int newDist = distanceFunction(horizontalDir, verticalDir, newNodeRect, newFocusPoint);
       
   240     wkDebug()<<"WebTabbedNavigation::selectNode. selected x = "<<selectedPoint.iX<<" y = "<<selectedPoint.iY<<" new x = "<<newFocusPoint.iX<<" y = "<<newFocusPoint.iY<<"old distance = "<<selectedDist<<" new distance = "<<newDist<<flush;
       
   241     return newDist < selectedDist;
       
   242 }
       
   243 
       
   244 TPoint WebTabbedNavigation::potentialFocusPoint(int horizontalDir, int verticalDir, TRect& newNodeRect)
       
   245 {
       
   246     int x = 0;
       
   247     int y = 0;
       
   248     // Focus points must be inside the element and not on the border in order for the outline to be drawn.
       
   249     if (horizontalDir) { // horizontal
       
   250         if (horizontalDir == -1) { // left
       
   251             x = newNodeRect.iBr.iX - 1;
       
   252         }
       
   253         else if (horizontalDir == 1) { // right
       
   254             x = newNodeRect.iTl.iX + 1;
       
   255         }
       
   256         if (newNodeRect.iBr.iY < m_focusPosition.iY) {
       
   257             y = newNodeRect.iBr.iY - 1;
       
   258         }
       
   259         else if (newNodeRect.iTl.iY > m_focusPosition.iY) {
       
   260             y = newNodeRect.iTl.iY + 1;
       
   261         }
       
   262         else {
       
   263             y = m_focusPosition.iY;
       
   264         }
       
   265     }
       
   266     else { // vertical
       
   267         if (verticalDir == -1) { // up
       
   268             y = newNodeRect.iBr.iY - 1;
       
   269         }
       
   270         else if (verticalDir == 1) { // down
       
   271             y = newNodeRect.iTl.iY + 1;
       
   272         }
       
   273         if (newNodeRect.iBr.iX < m_focusPosition.iX) {
       
   274             x = newNodeRect.iBr.iX - 1;
       
   275         }
       
   276         else if (newNodeRect.iTl.iX > m_focusPosition.iX) {
       
   277             x = newNodeRect.iTl.iX + 1;
       
   278         }
       
   279         else {
       
   280             x = m_focusPosition.iX;
       
   281         }
       
   282     }
       
   283     return TPoint(x, y);
       
   284 }
       
   285 
       
   286 int WebTabbedNavigation::distanceFunction(int horizontalDir, int verticalDir, TRect& rect, TPoint& point)
       
   287 {
       
   288     TReal x, y, euclidianDistance;
       
   289     int sameAxisDist, otherAxisDist, overlap;
       
   290 
       
   291     Math::Pow(x, (m_focusPosition.iX - point.iX), 2.0);
       
   292     Math::Pow(y, (m_focusPosition.iY - point.iY), 2.0);
       
   293     Math::Sqrt(euclidianDistance, x + y);
       
   294     sameAxisDist = horizontalDir * (point.iX - m_focusPosition.iX) + verticalDir * (point.iY - m_focusPosition.iY);
       
   295     otherAxisDist = (horizontalDir) ? (point.iY - m_focusPosition.iY) : (point.iX - m_focusPosition.iX) ;
       
   296     otherAxisDist = (otherAxisDist < 0 ) ? (otherAxisDist * -1) : otherAxisDist;
       
   297     if (horizontalDir) { // horizontal
       
   298         if (rect.iBr.iY < m_selectedElementRect.iTl.iY || rect.iTl.iY > m_selectedElementRect.iBr.iY) {
       
   299             overlap = 0;
       
   300         }
       
   301         else {
       
   302             int top = max(m_selectedElementRect.iTl.iY, rect.iTl.iY);
       
   303             int bottom = std::min(m_selectedElementRect.iBr.iY, rect.iBr.iY);
       
   304             overlap = bottom - top;
       
   305         }
       
   306     }
       
   307     else { // vertical    
       
   308         if (rect.iBr.iX < m_selectedElementRect.iTl.iX || rect.iTl.iX > m_selectedElementRect.iBr.iX) {
       
   309             overlap = 0;
       
   310         }
       
   311         else {
       
   312             int top = max(m_selectedElementRect.iTl.iX, rect.iTl.iX);
       
   313             int bottom = std::min(m_selectedElementRect.iBr.iX, rect.iBr.iX);
       
   314             overlap = bottom - top;
       
   315         }
       
   316     }
       
   317     long ed, o;
       
   318     Math::Int(ed, euclidianDistance);
       
   319     Math::Int(o, sqrt(overlap));
       
   320     return ed + sameAxisDist + 2 * otherAxisDist + o;
       
   321 }