Reviewed by John
authorkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Jan 2005 18:11:21 +0000 (18:11 +0000)
committerkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Jan 2005 18:11:21 +0000 (18:11 +0000)
        Fix for this bug:

        <rdar://problem/3952877> REGRESSION (Mail): Command-left/right-arrows don't work with file attachment

        * khtml/editing/selection.cpp:
        (khtml::nodeForInlineBox): New helper function used in reimplementation of function below.
        (khtml::selectionForLine): Reimplemented using line box smarts. I originally wrote this code when
        I had a less than full understanding of line layout. I can do better now, and my new version no
        longer fails to notice attachments when doing the kind of navigation mentioned in the bug.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8395 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/SelectionController.cpp
WebCore/khtml/editing/selection.cpp

index 7fb389543c37ded6f3ae6859338531b73f51e7c2..af4438594452c10d25c730ab1ac294ed9f4c7cfe 100644 (file)
@@ -1,3 +1,17 @@
+2005-01-18  Ken Kocienda  <kocienda@apple.com>
+
+        Reviewed by John
+
+        Fix for this bug:
+        
+        <rdar://problem/3952877> REGRESSION (Mail): Command-left/right-arrows don't work with file attachment
+
+        * khtml/editing/selection.cpp:
+        (khtml::nodeForInlineBox): New helper function used in reimplementation of function below.
+        (khtml::selectionForLine): Reimplemented using line box smarts. I originally wrote this code when
+        I had a less than full understanding of line layout. I can do better now, and my new version no
+        longer fails to notice attachments when doing the kind of navigation mentioned in the bug.
+
 2005-01-17  David Harrison  <harrison@apple.com>
 
         Reviewed by John Sullivan.
index 3ef872911e3ef065c06dd05fe3ec1e46a1dd810b..8308d9cc69a9d20ddf592f2fbefab53cf2587b1c 100644 (file)
@@ -973,85 +973,53 @@ void Selection::validate(ETextGranularity granularity)
 #endif
 }
 
-static Position startOfFirstRunAt(RenderObject *renderNode, int y)
+static NodeImpl *nodeForInlineBox(const InlineBox *box)
 {
-    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
-        if (n->isText()) {
-            RenderText *textRenderer = static_cast<RenderText *>(n);
-            for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
-                int absx, absy;
-                n->absolutePosition(absx, absy);
-                int top = absy + box->root()->topOverflow();
-                if (top == y)
-                    return Position(textRenderer->element(), box->m_start);
-            }
-        }
-        
-        Position position = startOfFirstRunAt(n->firstChild(), y);
-        if (position.isNotNull())
-            return position;
-    }
-    
-    return Position();
+    if (!box || !box->object())
+        return 0;
+    return box->object()->element();
 }
 
-static Position endOfLastRunAt(RenderObject *renderNode, int y)
+static Selection selectionForLine(const Position &pos, EAffinity affinity)
 {
-    RenderObject *n = renderNode;
-    if (!n)
-        return Position();
-    if (RenderObject *parent = n->parent())
-        n = parent->lastChild();
-    
-    while (1) {
-        Position position = endOfLastRunAt(n->firstChild(), y);
-        if (position.isNotNull())
-            return position;
-        
-        if (n->isText() && !n->isBR()) {
-            RenderText *textRenderer = static_cast<RenderText *>(n);
-            for (InlineTextBox* box = textRenderer->lastTextBox(); box; box = box->prevTextBox()) {
-                int absx, absy;
-                n->absolutePosition(absx, absy);
-                int top = absy + box->root()->topOverflow();
-                if (top == y)
-                    return Position(textRenderer->element(), box->m_start + box->m_len);
-            }
-        }
-        
-        if (n == renderNode)
-            return Position();
-        
-        n = n->previousSibling();
-    }
-}
+    if (pos.isNull())
+        return Selection();
 
-static Selection selectionForLine(const Position &position, EAffinity affinity)
-{
-    NodeImpl *node = position.node();
-    if (!node || !node->renderer())
+    RenderObject *renderer = pos.node()->renderer();
+    if (!renderer)
         return Selection();
     
-    QRect rect = node->renderer()->caretRect(position.offset(), affinity);
-    int selectionPointY = rect.y();
+    InlineBox *box = renderer->inlineBox(pos.offset(), affinity);
+    if (!box)
+        return Selection();
     
-    // Go up to first non-inline element.
-    RenderObject *renderNode = node->renderer();
-    while (renderNode && renderNode->isInline())
-        renderNode = renderNode->parent();
-    renderNode = renderNode->firstChild();
+    RootInlineBox *rootBox = box->root();
+    if (!rootBox)
+        return Selection();
     
-    // Look for all the first child in the block that is on the same line
-    // as the selection point.
-    Position start = startOfFirstRunAt(renderNode, selectionPointY);
-    if (start.isNull())
+    // Find the start position for this line.
+    InlineBox *startBox = rootBox->firstChild();
+    NodeImpl *startNode = nodeForInlineBox(startBox);
+    if (!startNode)
         return Selection();
-
-    // Look for all the last child in the block that is on the same line
-    // as the selection point.
-    Position end = endOfLastRunAt(renderNode, selectionPointY);
-    if (end.isNull())
+    long startOffset = 0;
+    if (startBox->isInlineTextBox()) {
+        InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
+        startOffset = startTextBox->m_start;
+    }
+    Position start(startNode, startOffset);
+    
+    // Find the end position for this line.
+    InlineBox *endBox = rootBox->lastChild();
+    NodeImpl *endNode = nodeForInlineBox(endBox);
+    if (!endNode)
         return Selection();
+    long endOffset = 1;
+    if (endBox->isInlineTextBox()) {
+        InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
+        endOffset = endTextBox->m_start + endTextBox->m_len;
+    }
+    Position end(endNode, endOffset);
     
     return Selection(start, end);
 }
index 3ef872911e3ef065c06dd05fe3ec1e46a1dd810b..8308d9cc69a9d20ddf592f2fbefab53cf2587b1c 100644 (file)
@@ -973,85 +973,53 @@ void Selection::validate(ETextGranularity granularity)
 #endif
 }
 
-static Position startOfFirstRunAt(RenderObject *renderNode, int y)
+static NodeImpl *nodeForInlineBox(const InlineBox *box)
 {
-    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
-        if (n->isText()) {
-            RenderText *textRenderer = static_cast<RenderText *>(n);
-            for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
-                int absx, absy;
-                n->absolutePosition(absx, absy);
-                int top = absy + box->root()->topOverflow();
-                if (top == y)
-                    return Position(textRenderer->element(), box->m_start);
-            }
-        }
-        
-        Position position = startOfFirstRunAt(n->firstChild(), y);
-        if (position.isNotNull())
-            return position;
-    }
-    
-    return Position();
+    if (!box || !box->object())
+        return 0;
+    return box->object()->element();
 }
 
-static Position endOfLastRunAt(RenderObject *renderNode, int y)
+static Selection selectionForLine(const Position &pos, EAffinity affinity)
 {
-    RenderObject *n = renderNode;
-    if (!n)
-        return Position();
-    if (RenderObject *parent = n->parent())
-        n = parent->lastChild();
-    
-    while (1) {
-        Position position = endOfLastRunAt(n->firstChild(), y);
-        if (position.isNotNull())
-            return position;
-        
-        if (n->isText() && !n->isBR()) {
-            RenderText *textRenderer = static_cast<RenderText *>(n);
-            for (InlineTextBox* box = textRenderer->lastTextBox(); box; box = box->prevTextBox()) {
-                int absx, absy;
-                n->absolutePosition(absx, absy);
-                int top = absy + box->root()->topOverflow();
-                if (top == y)
-                    return Position(textRenderer->element(), box->m_start + box->m_len);
-            }
-        }
-        
-        if (n == renderNode)
-            return Position();
-        
-        n = n->previousSibling();
-    }
-}
+    if (pos.isNull())
+        return Selection();
 
-static Selection selectionForLine(const Position &position, EAffinity affinity)
-{
-    NodeImpl *node = position.node();
-    if (!node || !node->renderer())
+    RenderObject *renderer = pos.node()->renderer();
+    if (!renderer)
         return Selection();
     
-    QRect rect = node->renderer()->caretRect(position.offset(), affinity);
-    int selectionPointY = rect.y();
+    InlineBox *box = renderer->inlineBox(pos.offset(), affinity);
+    if (!box)
+        return Selection();
     
-    // Go up to first non-inline element.
-    RenderObject *renderNode = node->renderer();
-    while (renderNode && renderNode->isInline())
-        renderNode = renderNode->parent();
-    renderNode = renderNode->firstChild();
+    RootInlineBox *rootBox = box->root();
+    if (!rootBox)
+        return Selection();
     
-    // Look for all the first child in the block that is on the same line
-    // as the selection point.
-    Position start = startOfFirstRunAt(renderNode, selectionPointY);
-    if (start.isNull())
+    // Find the start position for this line.
+    InlineBox *startBox = rootBox->firstChild();
+    NodeImpl *startNode = nodeForInlineBox(startBox);
+    if (!startNode)
         return Selection();
-
-    // Look for all the last child in the block that is on the same line
-    // as the selection point.
-    Position end = endOfLastRunAt(renderNode, selectionPointY);
-    if (end.isNull())
+    long startOffset = 0;
+    if (startBox->isInlineTextBox()) {
+        InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
+        startOffset = startTextBox->m_start;
+    }
+    Position start(startNode, startOffset);
+    
+    // Find the end position for this line.
+    InlineBox *endBox = rootBox->lastChild();
+    NodeImpl *endNode = nodeForInlineBox(endBox);
+    if (!endNode)
         return Selection();
+    long endOffset = 1;
+    if (endBox->isInlineTextBox()) {
+        InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
+        endOffset = endTextBox->m_start + endTextBox->m_len;
+    }
+    Position end(endNode, endOffset);
     
     return Selection(start, end);
 }