[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677

kocienda kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 08:35:03 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 88ca6d57f7c4be136e9a52254040acf48a0585d7
Author: kocienda <kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Apr 19 22:54:55 2004 +0000

    WebCore:
    
            Reviewed by Hyatt
    
            * khtml/khtml_part.cpp:
            (KHTMLPart::notifySelectionChanged): Clear the value
            used for maintaining x position when doing vertical arrow
            navigation. WebCoreBridge restores this value when needed.
            (KHTMLPart::setXPosForVerticalArrowNavigation): New accessor.
            (KHTMLPart::xPosForVerticalArrowNavigation): New accessor.
            * khtml/khtml_part.h:
            (KHTMLPart::): Add NoXPosForVerticalArrowNavigation constant.
            * khtml/khtml_selection.cpp:
            (KHTMLSelection::modify): Add cases for UP and DOWN navigation
            (KHTMLSelection::xPosForVerticalArrowNavigation): New helper.
            * khtml/khtml_selection.h: Add UP and DOWN constants to EDirection enum.
            (KHTMLSelection::):
            * khtml/khtmlpart_p.h: Declare storage for m_xPosForVerticalArrowNavigation,
            the value used for maintaining x position when doing vertical arrow
            navigation.
            * khtml/rendering/render_block.cpp:
            (khtml::RenderBlock::positionForCoordinates): Improved this function to
            handle deficiencies exposed when trying to implement new behavior.
            * khtml/rendering/render_br.cpp:
            (RenderBR::positionForCoordinates): Added implementation of this virtual function.
            * khtml/rendering/render_br.h: Declare implementation for positionForCoordinates virtual function.
            * khtml/rendering/render_replaced.cpp:
            (RenderReplaced::positionForCoordinates): Improved this function to
            handle deficiencies exposed when trying to implement new behavior.
            * khtml/rendering/render_text.cpp:
            (InlineTextBox::offsetForPosition): Remove left/right "bounds" check here.
            (RenderText::positionForCoordinates): Improved this function to
            handle deficiencies exposed when trying to implement new behavior.
            * khtml/xml/dom_position.cpp:
            (inlineBoxForRenderer): Moved to top of file so all code in the file can see this static function.
            (renderersOnDifferentLine): Ditto.
            (nextRenderedEditable): Ditto.
            (previousRenderedEditable): Ditto.
            (DOMPosition::previousLinePosition): New function. Implements the guts of up/down navigation.
            (DOMPosition::nextLinePosition): Ditto.
            * khtml/xml/dom_position.h: Added declarations for nextLinePosition and previousLinePosition.
            * kwq/WebCoreBridge.h: Add WebSelectUp and WebSelectDown constants.
            * kwq/WebCoreBridge.mm:
            (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Handles saving and restoring the
            x position used for doing vertical arrow navigation.
    
    WebKit:
    
            Reviewed by Hyatt
    
            * WebView.subproj/WebView.m:
            (-[WebView moveDown:]): Added implementation.
            (-[WebView moveUp:]): Added implementation.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@6426 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index 57d106f..3731d22 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,49 @@
+2004-04-19  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+        * khtml/khtml_part.cpp:
+        (KHTMLPart::notifySelectionChanged): Clear the value
+        used for maintaining x position when doing vertical arrow
+        navigation. WebCoreBridge restores this value when needed. 
+        (KHTMLPart::setXPosForVerticalArrowNavigation): New accessor.
+        (KHTMLPart::xPosForVerticalArrowNavigation): New accessor.
+        * khtml/khtml_part.h:
+        (KHTMLPart::): Add NoXPosForVerticalArrowNavigation constant.
+        * khtml/khtml_selection.cpp:
+        (KHTMLSelection::modify): Add cases for UP and DOWN navigation
+        (KHTMLSelection::xPosForVerticalArrowNavigation): New helper.
+        * khtml/khtml_selection.h: Add UP and DOWN constants to EDirection enum.
+        (KHTMLSelection::):
+        * khtml/khtmlpart_p.h: Declare storage for m_xPosForVerticalArrowNavigation, 
+        the value used for maintaining x position when doing vertical arrow
+        navigation. 
+        * khtml/rendering/render_block.cpp:
+        (khtml::RenderBlock::positionForCoordinates): Improved this function to
+        handle deficiencies exposed when trying to implement new behavior.
+        * khtml/rendering/render_br.cpp:
+        (RenderBR::positionForCoordinates): Added implementation of this virtual function.
+        * khtml/rendering/render_br.h: Declare implementation for positionForCoordinates virtual function.
+        * khtml/rendering/render_replaced.cpp:
+        (RenderReplaced::positionForCoordinates): Improved this function to
+        handle deficiencies exposed when trying to implement new behavior.
+        * khtml/rendering/render_text.cpp:
+        (InlineTextBox::offsetForPosition): Remove left/right "bounds" check here.
+        (RenderText::positionForCoordinates): Improved this function to
+        handle deficiencies exposed when trying to implement new behavior.
+        * khtml/xml/dom_position.cpp:
+        (inlineBoxForRenderer): Moved to top of file so all code in the file can see this static function.
+        (renderersOnDifferentLine): Ditto.
+        (nextRenderedEditable): Ditto.
+        (previousRenderedEditable): Ditto.
+        (DOMPosition::previousLinePosition): New function. Implements the guts of up/down navigation.
+        (DOMPosition::nextLinePosition): Ditto.
+        * khtml/xml/dom_position.h: Added declarations for nextLinePosition and previousLinePosition.
+        * kwq/WebCoreBridge.h: Add WebSelectUp and WebSelectDown constants.
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Handles saving and restoring the 
+        x position used for doing vertical arrow navigation.
+
 2004-04-16  Ken Kocienda  <kocienda at apple.com>
 
         Reviewed by Hyatt
diff --git a/WebCore/khtml/editing/SelectionController.cpp b/WebCore/khtml/editing/SelectionController.cpp
index 6107244..96d50e2 100644
--- a/WebCore/khtml/editing/SelectionController.cpp
+++ b/WebCore/khtml/editing/SelectionController.cpp
@@ -317,6 +317,18 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
                     break;
             }
             break;
+        case UP:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            break;
+        case DOWN:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            break;
     }
     
     if (pos.isEmpty())
@@ -335,6 +347,29 @@ void KHTMLSelection::expandToElement(ETextGranularity select)
     validate(select);
 }
 
+int KHTMLSelection::xPosForVerticalArrowNavigation() const
+{
+    int x = 0;
+
+    if (state() == NONE)
+        return x;
+
+    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    if (!part)
+        return x;
+        
+    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+        int y, w, h;
+        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        part->setXPosForVerticalArrowNavigation(x);
+    }
+    else {
+        x = part->xPosForVerticalArrowNavigation();
+    }
+
+    return x;
+}
+
 void KHTMLSelection::clear()
 {
 	setBaseNode(0);
diff --git a/WebCore/khtml/editing/SelectionController.h b/WebCore/khtml/editing/SelectionController.h
index a52f542..f96e49a 100644
--- a/WebCore/khtml/editing/SelectionController.h
+++ b/WebCore/khtml/editing/SelectionController.h
@@ -53,7 +53,7 @@ public:
 
 	enum EState { NONE, CARET, RANGE };
 	enum EAlter { MOVE, EXTEND };
-	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
 	enum ETextGranularity { CHARACTER, WORD, LINE };
 
 	EState state() const { return m_state; }
@@ -129,6 +129,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
+    int xPosForVerticalArrowNavigation() const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/editing/selection.cpp b/WebCore/khtml/editing/selection.cpp
index 6107244..96d50e2 100644
--- a/WebCore/khtml/editing/selection.cpp
+++ b/WebCore/khtml/editing/selection.cpp
@@ -317,6 +317,18 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
                     break;
             }
             break;
+        case UP:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            break;
+        case DOWN:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            break;
     }
     
     if (pos.isEmpty())
@@ -335,6 +347,29 @@ void KHTMLSelection::expandToElement(ETextGranularity select)
     validate(select);
 }
 
+int KHTMLSelection::xPosForVerticalArrowNavigation() const
+{
+    int x = 0;
+
+    if (state() == NONE)
+        return x;
+
+    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    if (!part)
+        return x;
+        
+    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+        int y, w, h;
+        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        part->setXPosForVerticalArrowNavigation(x);
+    }
+    else {
+        x = part->xPosForVerticalArrowNavigation();
+    }
+
+    return x;
+}
+
 void KHTMLSelection::clear()
 {
 	setBaseNode(0);
diff --git a/WebCore/khtml/editing/selection.h b/WebCore/khtml/editing/selection.h
index a52f542..f96e49a 100644
--- a/WebCore/khtml/editing/selection.h
+++ b/WebCore/khtml/editing/selection.h
@@ -53,7 +53,7 @@ public:
 
 	enum EState { NONE, CARET, RANGE };
 	enum EAlter { MOVE, EXTEND };
-	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
 	enum ETextGranularity { CHARACTER, WORD, LINE };
 
 	EState state() const { return m_state; }
@@ -129,6 +129,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
+    int xPosForVerticalArrowNavigation() const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/khtml_part.cpp b/WebCore/khtml/khtml_part.cpp
index cab37de..cb13fca 100644
--- a/WebCore/khtml/khtml_part.cpp
+++ b/WebCore/khtml/khtml_part.cpp
@@ -2585,10 +2585,24 @@ void KHTMLPart::notifySelectionChanged(bool endTyping)
     
     if (endTyping)
         TypingCommand::closeTyping(lastEditCommand());
-                
+    
+    // Always clear the x position used for vertical arrow navigation.
+    // It will be restored by the vertical arrow navigation code if necessary.
+    d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
+    
     emitSelectionChanged();
 }
 
+void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
+{
+    d->m_xPosForVerticalArrowNavigation = x;
+}
+
+int KHTMLPart::xPosForVerticalArrowNavigation() const
+{
+    return d->m_xPosForVerticalArrowNavigation;
+}
+
 void KHTMLPart::timerEvent(QTimerEvent *e)
 {
     if (e->timerId() == d->m_caretBlinkTimer && 
diff --git a/WebCore/khtml/khtml_part.h b/WebCore/khtml/khtml_part.h
index 69c28f5..0173e6a 100644
--- a/WebCore/khtml/khtml_part.h
+++ b/WebCore/khtml/khtml_part.h
@@ -181,6 +181,7 @@ class KHTMLPart : public KParts::ReadOnlyPart
 
 public:
   enum GUIProfile { DefaultGUI, BrowserViewGUI /* ... */ };
+  enum { NoXPosForVerticalArrowNavigation = INT_MIN };
 
   /**
    * Constructs a new KHTMLPart.
@@ -604,6 +605,16 @@ public:
   void paintCaret(QPainter *p, const QRect &rect) const;
 
   /**
+   * Set info for vertical arrow navigation.
+   */
+  void setXPosForVerticalArrowNavigation(int x);
+
+  /**
+   * Get info for vertical arrow navigation.
+   */
+  int xPosForVerticalArrowNavigation() const;
+
+  /**
    * Returns the text for a part of the document.
    */
   QString text(const DOM::Range &) const;
diff --git a/WebCore/khtml/khtml_selection.cpp b/WebCore/khtml/khtml_selection.cpp
index 6107244..96d50e2 100644
--- a/WebCore/khtml/khtml_selection.cpp
+++ b/WebCore/khtml/khtml_selection.cpp
@@ -317,6 +317,18 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
                     break;
             }
             break;
+        case UP:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            break;
+        case DOWN:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            break;
     }
     
     if (pos.isEmpty())
@@ -335,6 +347,29 @@ void KHTMLSelection::expandToElement(ETextGranularity select)
     validate(select);
 }
 
+int KHTMLSelection::xPosForVerticalArrowNavigation() const
+{
+    int x = 0;
+
+    if (state() == NONE)
+        return x;
+
+    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    if (!part)
+        return x;
+        
+    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+        int y, w, h;
+        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        part->setXPosForVerticalArrowNavigation(x);
+    }
+    else {
+        x = part->xPosForVerticalArrowNavigation();
+    }
+
+    return x;
+}
+
 void KHTMLSelection::clear()
 {
 	setBaseNode(0);
diff --git a/WebCore/khtml/khtml_selection.h b/WebCore/khtml/khtml_selection.h
index a52f542..f96e49a 100644
--- a/WebCore/khtml/khtml_selection.h
+++ b/WebCore/khtml/khtml_selection.h
@@ -53,7 +53,7 @@ public:
 
 	enum EState { NONE, CARET, RANGE };
 	enum EAlter { MOVE, EXTEND };
-	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
 	enum ETextGranularity { CHARACTER, WORD, LINE };
 
 	EState state() const { return m_state; }
@@ -129,6 +129,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
+    int xPosForVerticalArrowNavigation() const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/khtmlpart_p.h b/WebCore/khtml/khtmlpart_p.h
index 5cfbf32..8d11d37 100644
--- a/WebCore/khtml/khtmlpart_p.h
+++ b/WebCore/khtml/khtmlpart_p.h
@@ -366,6 +366,7 @@ public:
 
   TristateFlag m_inEditMode;
   khtml::EditCommand m_lastEditCommand;
+  int m_xPosForVerticalArrowNavigation;
 
   int m_focusNodeNumber;
 
diff --git a/WebCore/khtml/rendering/render_block.cpp b/WebCore/khtml/rendering/render_block.cpp
index 70cb877..33dde28 100644
--- a/WebCore/khtml/rendering/render_block.cpp
+++ b/WebCore/khtml/rendering/render_block.cpp
@@ -2078,31 +2078,43 @@ DOMPosition RenderBlock::positionForCoordinates(int _x, int _y)
         // look for the closest line box in the root box which is at the passed-in y coordinate
         for (RootInlineBox *root = firstRootBox(); root; root = root->nextRootBox()) {
             top = absy + root->topOverflow();
+            // set the bottom based on whether there is a next root box
             if (root->nextRootBox())
                 bottom = absy + root->nextRootBox()->topOverflow();
             else
                 bottom = absy + root->bottomOverflow();
-            if (_y >= top && _y < bottom) {
-                InlineBox *closestBox = root->firstChild();
-                int min = INT_MAX;
-                bool start = true;
-                for (InlineBox *box = root->firstChild(); box; box = box->nextOnLine()) {
-                    int cmp;
-                    cmp = abs(_x - (absx + box->m_x));   
-                    if (cmp < min) { 
-                        closestBox = box; 
-                        min = cmp; 
-                        start = true; 
-                    }
-                    cmp = abs(_x - (absx + box->m_x + box->m_width));  
-                    if (cmp < min) { 
-                        closestBox = box; 
-                        min = cmp; 
-                        start = false; 
+            // check if this root line box is located at this y coordinate
+            if (_y >= top && _y < bottom && root->firstChild()) {
+                InlineBox *closestBox = 0;
+                bool useClosestBoxLeftEdge = true;
+
+                if (_x <= absx + root->firstChild()->m_x) {
+                    // if the x coordinate is to the left of the root box's first child, 
+                    // make the first child closest
+                    closestBox = root->firstChild(); 
+                }
+                else if (_x >= absx + root->lastChild()->m_x + root->lastChild()->m_width) {
+                    // if the x coordinate is to the right of the root box's last child, 
+                    // make the last child closest
+                    closestBox = root->lastChild(); 
+                    useClosestBoxLeftEdge = false;
+                }
+                else {
+                    // look for the closest child for this root;
+                    // check only the right edges, since the left edge of the first
+                    // box has already been checked
+                    for (InlineBox *box = root->firstChild(); box; box = box->nextOnLine()) {
+                        if (_x < absx + box->m_x + box->m_width) { 
+                            closestBox = box; 
+                            useClosestBoxLeftEdge = false;
+                            break;
+                        }
                     }
                 }
-                if (closestBox)
-                    return positionForBox(start ? closestBox->firstLeafChild() : closestBox->lastLeafChild(), start);
+                if (closestBox) {
+                    RenderObject *renderer = useClosestBoxLeftEdge ? closestBox->firstLeafChild()->object() : closestBox->lastLeafChild()->object();
+                    return renderer->positionForCoordinates(_x, _y);
+                }
             }
         }
         return DOMPosition(element(), 0);
diff --git a/WebCore/khtml/rendering/render_br.cpp b/WebCore/khtml/rendering/render_br.cpp
index 3f5704e..e77e6e5 100644
--- a/WebCore/khtml/rendering/render_br.cpp
+++ b/WebCore/khtml/rendering/render_br.cpp
@@ -20,9 +20,10 @@
  *
  */
 #include "render_br.h"
+#include "xml/dom_position.h"
 
 using namespace khtml;
-
+using DOM::DOMPosition;
 
 RenderBR::RenderBR(DOM::NodeImpl* node)
     : RenderText(node, new DOM::DOMStringImpl(QChar('\n'))), m_x(0), m_y(0), m_height(0),
@@ -97,6 +98,11 @@ unsigned long RenderBR::caretMaxRenderedOffset() const
     return 1;
 }
 
+DOMPosition RenderBR::positionForCoordinates(int _x, int _y)
+{
+    return DOMPosition(element(), 0);
+}
+
 void RenderBR::caretPos(int offset, bool override, int &_x, int &_y, int &_w, int &_h)
 {
     // EDIT FIXME: This does not work yet. Some other changes are need before
diff --git a/WebCore/khtml/rendering/render_br.h b/WebCore/khtml/rendering/render_br.h
index 9e11c12..70dbff0 100644
--- a/WebCore/khtml/rendering/render_br.h
+++ b/WebCore/khtml/rendering/render_br.h
@@ -24,6 +24,10 @@
 
 #include "render_text.h"
 
+namespace DOM {
+    class DOMPosition;
+};
+
 /*
  * The whole class here is a hack to get <br> working, as long as we don't have support for
  * CSS2 :before and :after pseudo elements
@@ -63,6 +67,7 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
     
+    virtual DOM::DOMPosition positionForCoordinates(int _x, int _y);
     virtual void caretPos(int offset, bool override, int &_x, int &_y, int &_w, int &_h);
 
 private:
diff --git a/WebCore/khtml/rendering/render_replaced.cpp b/WebCore/khtml/rendering/render_replaced.cpp
index 0e0b2a3..6ec4711 100644
--- a/WebCore/khtml/rendering/render_replaced.cpp
+++ b/WebCore/khtml/rendering/render_replaced.cpp
@@ -25,6 +25,7 @@
 
 #include "render_arena.h"
 #include "render_canvas.h"
+#include "render_line.h"
 
 #include <assert.h>
 #include <qwidget.h>
@@ -129,18 +130,30 @@ unsigned long RenderReplaced::caretMaxRenderedOffset() const
 
 DOMPosition RenderReplaced::positionForCoordinates(int _x, int _y)
 {
+    InlineBox *box = inlineBoxWrapper();
+    if (!box)
+        return DOMPosition(element(), 0);
+
+    RootInlineBox *root = box->root();
+
     int absx, absy;
     absolutePosition(absx, absy);
+
+    int top = absy + root->topOverflow();
+    int bottom = absy + root->bottomOverflow();
+
+    if (_y < top)
+        return DOMPosition(element(), caretMinOffset()); // coordinates are above
     
-    bool pointIsInside = (_x >= absx && _x < absx + width() && 
-                          _y >= absy && _y < absx + height());
+    if (_y >= bottom)
+        return DOMPosition(element(), caretMaxOffset()); // coordinates are below
     
-    if (pointIsInside && element()) {
+    if (element()) {
         if (_x <= absx + (width() / 2))
             return DOMPosition(element(), 0);
         return DOMPosition(element(), 1);
     }
-    
+
     return RenderBox::positionForCoordinates(_x, _y);
 }
 
diff --git a/WebCore/khtml/rendering/render_text.cpp b/WebCore/khtml/rendering/render_text.cpp
index 4f03423..7db9f66 100644
--- a/WebCore/khtml/rendering/render_text.cpp
+++ b/WebCore/khtml/rendering/render_text.cpp
@@ -205,14 +205,6 @@ unsigned long InlineTextBox::caretMaxRenderedOffset() const
 
 int InlineTextBox::offsetForPosition(int _x, int _tx, const Font *f, const RenderText *text)
 {
-    if (_x < _tx + m_x)
-        // we're to the left
-        return -1;
-
-    if (_x >= _tx + m_x + m_width)
-        // we're to the right
-        return -1;
-
 #if APPLE_CHANGES
     return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, _x - (_tx + m_x), m_reversed);
 #else
@@ -455,21 +447,37 @@ DOMPosition RenderText::positionForCoordinates(int _x, int _y)
     int absx, absy;
     absolutePosition(absx, absy);
 
-    int top = absy + firstTextBox()->root()->topOverflow();
-    int bottom = absy + lastTextBox()->root()->bottomOverflow();
+    if (firstTextBox() && _y < absy + firstTextBox()->root()->bottomOverflow() && _x < absx + firstTextBox()->m_x) {
+        // at the y coordinate of the first line or above
+        // and the x coordinate is to the left than the first text box left edge
+        return DOMPosition(element(), lastTextBox()->m_start);
+    }
+
+    if (lastTextBox() && _y >= absy + lastTextBox()->root()->topOverflow() && _x >= absx + lastTextBox()->m_x + lastTextBox()->m_width) {
+        // at the y coordinate of the last line or below
+        // and the x coordinate is to the right than the last text box right edge
+        return DOMPosition(element(), lastTextBox()->m_start + lastTextBox()->m_len);
+    }
 
-    if (_y < top)
-        return DOMPosition(element(), caretMinOffset()); // coordinates are above
-    
-    if (_y >= bottom)
-        return DOMPosition(element(), caretMaxOffset()); // coordinates are below
-    
     for (InlineTextBox *box = firstTextBox(); box; box = box->nextTextBox()) {
         if (_y >= absy + box->root()->topOverflow() && _y < absy + box->root()->bottomOverflow()) {
-            const Font *f = htmlFont(box == firstTextBox());
-            int offset = box->offsetForPosition(_x, absx, f, this);
-            if (offset != -1)
-                return DOMPosition(element(), offset + box->m_start);
+            if (_x < absx + box->m_x + box->m_width) {
+                // and the x coordinate is to the left of the right edge of this box
+                // check to see if position goes in this box
+                const Font *f = htmlFont(box == firstTextBox());
+                int offset = box->offsetForPosition(_x, absx, f, this);
+                if (offset != -1) {
+                    return DOMPosition(element(), offset + box->m_start);
+                }
+            }
+            else if (!box->prevOnLine() && _x < absx + box->m_x)
+                // box is first on line
+                // and the x coordinate is to the left than the first text box left edge
+                return DOMPosition(element(), box->m_start);
+            else if (!box->nextOnLine() && _x >= absx + box->m_x + box->m_width)
+                // box is last on line
+                // and the x coordinate is to the right than the last text box right edge
+                return DOMPosition(element(), box->m_start + box->m_len);
         }
     }
     
diff --git a/WebCore/khtml/xml/dom_position.cpp b/WebCore/khtml/xml/dom_position.cpp
index 553f37c..f5aef10 100644
--- a/WebCore/khtml/xml/dom_position.cpp
+++ b/WebCore/khtml/xml/dom_position.cpp
@@ -26,6 +26,7 @@
 #include "dom_position.h"
 
 #include "htmltags.h"
+#include "rendering/render_block.h"
 #include "rendering/render_line.h"
 #include "rendering/render_object.h"
 #include "rendering/render_style.h"
@@ -46,6 +47,7 @@ using khtml::InlineFlowBox;
 using khtml::InlineTextBox;
 using khtml::RenderObject;
 using khtml::RenderText;
+using khtml::RootInlineBox;
 
 #if !APPLE_CHANGES
 #define ASSERT(assertion) ((void)0)
@@ -55,6 +57,70 @@ using khtml::RenderText;
 #define ERROR(formatAndArgs...) ((void)0)
 #endif
 
+static InlineBox *inlineBoxForRenderer(RenderObject *renderer, long offset)
+{
+    if (!renderer)
+        return 0;
+
+    if (renderer->isBR() && static_cast<RenderText *>(renderer)->firstTextBox())
+        return static_cast<RenderText *>(renderer)->firstTextBox();
+    
+    if (renderer->isText()) {
+        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer); 
+        if (textRenderer->isBR() && textRenderer->firstTextBox())
+            return textRenderer->firstTextBox();
+        
+        for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+            if (offset >= box->m_start && offset <= box->m_start + box->m_len) {
+                return box;
+            }
+            else if (offset < box->m_start) {
+                // The offset we're looking for is before this node
+                // this means the offset must be in content that is
+                // not rendered.
+                return box->prevTextBox() ? box->prevTextBox() : textRenderer->firstTextBox();
+            }
+        }
+    }
+    else {
+        return renderer->inlineBoxWrapper();
+    } 
+    
+    return 0;
+}
+
+static bool renderersOnDifferentLine(RenderObject *r1, long o1, RenderObject *r2, long o2)
+{
+    InlineBox *b1 = inlineBoxForRenderer(r1, o1);
+    InlineBox *b2 = inlineBoxForRenderer(r2, o2);
+    return (b1 && b2 && b1->root() != b2->root());
+}
+
+static NodeImpl *nextRenderedEditable(NodeImpl *node)
+{
+    while (1) {
+        node = node->nextEditable();
+        if (!node)
+            return 0;
+        if (inlineBoxForRenderer(node->renderer(), 0))
+            return node;
+    }
+    return 0;
+}
+
+static NodeImpl *previousRenderedEditable(NodeImpl *node)
+{
+    while (1) {
+        node = node->previousEditable();
+        if (!node)
+            return 0;
+        if (inlineBoxForRenderer(node->renderer(), 0))
+            return node;
+    }
+    return 0;
+}
+
+
 DOMPosition::DOMPosition(NodeImpl *node, long offset) 
     : m_node(0), m_offset(offset) 
 { 
@@ -232,6 +298,115 @@ DOMPosition DOMPosition::nextCharacterPosition() const
     return *this;
 }
 
+DOMPosition DOMPosition::previousLinePosition(int x) const
+{
+    if (!node())
+        return DOMPosition();
+
+    if (!node()->renderer())
+        return *this;
+
+    InlineBox *box = inlineBoxForRenderer(node()->renderer(), offset());
+    if (!box)
+        return *this;
+
+    NodeImpl *previousLineNode = 0;
+    RootInlineBox *root = box->root()->prevRootBox();
+    if (root) {
+        previousLineNode = node();
+    }
+    else {
+        // This containing editable block does not have a previous line.
+        // Need to move back to previous containing editable block in this root editable
+        // block and find the last root line box in that block.
+        NodeImpl *startBlock = node()->containingEditableBlock();
+        NodeImpl *n = node()->previousEditable();
+        while (n && startBlock == n->containingEditableBlock())
+            n = n->previousEditable();
+        if (n) {
+            while (n && !DOMPosition(n, n->caretMaxOffset()).inRenderedContent())
+                n = n->previousEditable();
+            if (n && n->inSameRootEditableBlock(node())) {
+                box = inlineBoxForRenderer(n->renderer(), n->caretMaxOffset());
+                ASSERT(box);
+                // previous root line box found
+                root = box->root();
+                previousLineNode = n;
+            }
+        }
+    }
+    
+    if (!root)
+        return *this;
+    ASSERT(previousLineNode);
+    
+    int absx, absy;
+    previousLineNode->renderer()->containingBlock()->absolutePosition(absx, absy);
+    int y = absy + root->topOverflow() + ((root->bottomOverflow() - root->topOverflow()) / 2);
+
+    RenderObject::NodeInfo nodeInfo(true, true);
+    previousLineNode->getDocument()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
+
+    if (!nodeInfo.innerNode() || !nodeInfo.innerNode()->renderer())
+        return *this;
+    
+    return nodeInfo.innerNode()->renderer()->positionForCoordinates(x, y);
+}
+
+DOMPosition DOMPosition::nextLinePosition(int x) const
+{
+    if (!node())
+        return DOMPosition();
+
+    if (!node()->renderer())
+        return *this;
+
+    InlineBox *box = inlineBoxForRenderer(node()->renderer(), offset());
+    if (!box)
+        return *this;
+
+    NodeImpl *nextLineNode = 0;
+    RootInlineBox *root = box->root()->nextRootBox();
+    if (root) {
+        nextLineNode = node();
+    }
+    else {
+        // This containing editable block does not have a next line.
+        // Need to move forward to next containing editable block in this root editable
+        // block and find the first root line box in that block.
+        NodeImpl *startBlock = node()->containingEditableBlock();
+        NodeImpl *n = node()->nextEditable();
+        while (n && startBlock == n->containingEditableBlock())
+            n = n->nextEditable();
+        if (n) {
+            while (n && !DOMPosition(n, n->caretMinOffset()).inRenderedContent())
+                n = n->nextEditable();
+            if (n && n->inSameRootEditableBlock(node())) {
+                box = inlineBoxForRenderer(n->renderer(), n->caretMinOffset());
+                ASSERT(box);
+                // previous root line box found
+                root = box->root();
+                nextLineNode = n;
+            }
+        }
+    }
+    
+    if (!root)
+        return *this;
+    ASSERT(nextLineNode);
+    
+    int absx, absy;
+    nextLineNode->renderer()->containingBlock()->absolutePosition(absx, absy);
+    int y = absy + root->topOverflow() + ((root->bottomOverflow() - root->topOverflow()) / 2);
+    
+    RenderObject::NodeInfo nodeInfo(true, true);
+    nextLineNode->getDocument()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
+    if (!nodeInfo.innerNode() || !nodeInfo.innerNode()->renderer())
+        return *this;
+    
+    return nodeInfo.innerNode()->renderer()->positionForCoordinates(x, y);
+}
+
 DOMPosition DOMPosition::equivalentUpstreamPosition() const
 {
     if (!node())
@@ -377,74 +552,6 @@ bool DOMPosition::inRenderedContent() const
     return false;
 }
 
-
-static InlineBox *inlineBoxForRenderer(RenderObject *renderer, long offset)
-{
-    if (!renderer)
-        return 0;
-
-    if (renderer->isBR() && static_cast<RenderText *>(renderer)->firstTextBox())
-        return static_cast<RenderText *>(renderer)->firstTextBox();
-    
-    if (renderer->isText()) {
-        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer); 
-        if (textRenderer->isBR() && textRenderer->firstTextBox())
-            return textRenderer->firstTextBox();
-        
-        for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
-            if (offset >= box->m_start && offset <= box->m_start + box->m_len) {
-                return box;
-            }
-            else if (offset < box->m_start) {
-                // The offset we're looking for is before this node
-                // this means the offset must be in content that is
-                // not rendered.
-                return box->prevTextBox() ? box->prevTextBox() : textRenderer->firstTextBox();
-            }
-        }
-    }
-    else {
-        return renderer->inlineBoxWrapper();
-    } 
-    
-    return 0;
-}
-
-static bool renderersOnDifferentLine(RenderObject *r1, long o1, RenderObject *r2, long o2)
-{
-    InlineBox *b1 = inlineBoxForRenderer(r1, o1);
-    InlineBox *b2 = inlineBoxForRenderer(r2, o2);
-
-    if (b1 && b2 && b1->root() != b2->root())
-        return true;
-    
-    return false;
-}
-
-static NodeImpl *nextRenderedEditable(NodeImpl *node)
-{
-    while (1) {
-        node = node->nextEditable();
-        if (!node)
-            return 0;
-        if (inlineBoxForRenderer(node->renderer(), 0))
-            return node;
-    }
-    return 0;
-}
-
-static NodeImpl *previousRenderedEditable(NodeImpl *node)
-{
-    while (1) {
-        node = node->previousEditable();
-        if (!node)
-            return 0;
-        if (inlineBoxForRenderer(node->renderer(), 0))
-            return node;
-    }
-    return 0;
-}
-
 bool DOMPosition::inRenderedText() const
 {
     if (!node()->isTextNode())
diff --git a/WebCore/khtml/xml/dom_position.h b/WebCore/khtml/xml/dom_position.h
index ecf4980..b94c867 100644
--- a/WebCore/khtml/xml/dom_position.h
+++ b/WebCore/khtml/xml/dom_position.h
@@ -51,6 +51,8 @@ public:
     DOMPosition nextRenderedEditablePosition() const;
     DOMPosition previousCharacterPosition() const;
     DOMPosition nextCharacterPosition() const;
+    DOMPosition previousLinePosition(int x) const;
+    DOMPosition nextLinePosition(int x) const;
     DOMPosition equivalentUpstreamPosition() const;
     DOMPosition equivalentDownstreamPosition() const;
     bool atStartOfContainingEditableBlock() const;
diff --git a/WebCore/khtml/xml/dom_selection.cpp b/WebCore/khtml/xml/dom_selection.cpp
index 6107244..96d50e2 100644
--- a/WebCore/khtml/xml/dom_selection.cpp
+++ b/WebCore/khtml/xml/dom_selection.cpp
@@ -317,6 +317,18 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
                     break;
             }
             break;
+        case UP:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            break;
+        case DOWN:
+            if (alter == EXTEND)
+                ERROR("unimplemented");
+            else
+                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            break;
     }
     
     if (pos.isEmpty())
@@ -335,6 +347,29 @@ void KHTMLSelection::expandToElement(ETextGranularity select)
     validate(select);
 }
 
+int KHTMLSelection::xPosForVerticalArrowNavigation() const
+{
+    int x = 0;
+
+    if (state() == NONE)
+        return x;
+
+    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    if (!part)
+        return x;
+        
+    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+        int y, w, h;
+        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        part->setXPosForVerticalArrowNavigation(x);
+    }
+    else {
+        x = part->xPosForVerticalArrowNavigation();
+    }
+
+    return x;
+}
+
 void KHTMLSelection::clear()
 {
 	setBaseNode(0);
diff --git a/WebCore/khtml/xml/dom_selection.h b/WebCore/khtml/xml/dom_selection.h
index a52f542..f96e49a 100644
--- a/WebCore/khtml/xml/dom_selection.h
+++ b/WebCore/khtml/xml/dom_selection.h
@@ -53,7 +53,7 @@ public:
 
 	enum EState { NONE, CARET, RANGE };
 	enum EAlter { MOVE, EXTEND };
-	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+	enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
 	enum ETextGranularity { CHARACTER, WORD, LINE };
 
 	EState state() const { return m_state; }
@@ -129,6 +129,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
+    int xPosForVerticalArrowNavigation() const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/kwq/WebCoreBridge.h b/WebCore/kwq/WebCoreBridge.h
index 970cc66..13a69bc 100644
--- a/WebCore/kwq/WebCoreBridge.h
+++ b/WebCore/kwq/WebCoreBridge.h
@@ -95,7 +95,9 @@ typedef enum {
     WebSelectForward, 
     WebSelectBackward, 
     WebSelectRight, 
-    WebSelectLeft 
+    WebSelectLeft, 
+    WebSelectUp, 
+    WebSelectDown,
 } WebSelectionDirection;
 
 typedef enum { 
diff --git a/WebCore/kwq/WebCoreBridge.mm b/WebCore/kwq/WebCoreBridge.mm
index e3bbaa2..1317fb0 100644
--- a/WebCore/kwq/WebCoreBridge.mm
+++ b/WebCore/kwq/WebCoreBridge.mm
@@ -1339,7 +1339,18 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     selection.modify(static_cast<KHTMLSelection::EAlter>(alteration), 
                      static_cast<KHTMLSelection::EDirection>(direction), 
                      static_cast<KHTMLSelection::ETextGranularity>(granularity));
+
+    // save vertical navigation x position if necessary
+    int xPos = _part->xPosForVerticalArrowNavigation();
+    if (direction != WebSelectUp && direction != WebSelectDown)
+        xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
+    
+    // setting the selection always clears saved vertical navigation x position
     _part->setSelection(selection);
+    
+    // restore vertical navigation x position if necessary
+    if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
+        _part->setXPosForVerticalArrowNavigation(xPos);
 }
 
 - (void)setSelectedDOMRange:(DOMRange *)range
diff --git a/WebKit/ChangeLog b/WebKit/ChangeLog
index 7b05940..f5039a2 100644
--- a/WebKit/ChangeLog
+++ b/WebKit/ChangeLog
@@ -1,3 +1,11 @@
+2004-04-19  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+        * WebView.subproj/WebView.m:
+        (-[WebView moveDown:]): Added implementation.
+        (-[WebView moveUp:]): Added implementation.
+
 2004-04-19  Chris Blumenberg  <cblu at apple.com>
 
 	Added support for pasting frames via WebArchives.
diff --git a/WebKit/WebView.subproj/WebView.m b/WebKit/WebView.subproj/WebView.m
index d5f1b81..1722273 100644
--- a/WebKit/WebView.subproj/WebView.m
+++ b/WebKit/WebView.subproj/WebView.m
@@ -2264,7 +2264,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveDown:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectDown granularity:WebSelectByCharacter];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveDown:) with:sender];
@@ -2273,7 +2273,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveDownAndModifySelection:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectDown granularity:WebSelectByCharacter];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveDownAndModifySelection:) with:sender];
@@ -2390,7 +2390,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveUp:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectUp granularity:WebSelectByCharacter];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveUp:) with:sender];

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list