[Webkit-unassigned] [Bug 45174] Freeze in VisiblePosition::leftVisuallyDistinctCandidate with ::first-letter

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Thu May 9 19:44:47 PDT 2024


https://bugs.webkit.org/show_bug.cgi?id=45174

--- Comment #11 from hytime at duck.com ---
Comment on attachment 74042
  --> https://bugs.webkit.org/attachment.cgi?id=74042
Patch

>Index: WebCore/dom/Position.cpp
>===================================================================
>--- WebCore/dom/Position.cpp	(revision 71591)
>+++ WebCore/dom/Position.cpp	(working copy)
>@@ -31,6 +31,7 @@
> #include "Logging.h"
> #include "PositionIterator.h"
> #include "RenderBlock.h"
>+#include "RenderTextFragment.h"
> #include "Text.h"
> #include "TextIterator.h"
> #include "VisiblePosition.h"
>@@ -558,14 +559,21 @@
>             unsigned textOffset = currentPos.offsetInLeafNode();
>             RenderText* textRenderer = toRenderText(renderer);
>             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
>+            unsigned offsetForFirstLetter = 0;
>+            if (textRenderer->isTextFragment()) {
>+                RenderTextFragment* textFragment = static_cast<RenderTextFragment*>(textRenderer);
>+                offsetForFirstLetter = textFragment->start();
>+                if (offsetForFirstLetter && textOffset <= offsetForFirstLetter)
>+                    return currentPos;
>+            }
>             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-                if (textOffset <= box->start() + box->len()) {
>-                    if (textOffset > box->start())
>+                if (textOffset <= box->start() + box->len() + offsetForFirstLetter) {
>+                    if (textOffset > box->start() + offsetForFirstLetter)
>                         return currentPos;
>                     continue;
>                 }
> 
>-                if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
>+                if (box == lastTextBox || textOffset != box->start() + box->len() + offsetForFirstLetter + 1)
>                     continue;
> 
>                 // The text continues on the next line only if the last text box is not on this line and
>@@ -680,14 +688,21 @@
>             unsigned textOffset = currentPos.offsetInLeafNode();
>             RenderText* textRenderer = toRenderText(renderer);
>             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
>+            unsigned offsetForFirstLetter = 0;
>+            if (textRenderer->isTextFragment()) {
>+                RenderTextFragment* textFragment = static_cast<RenderTextFragment*>(textRenderer);
>+                offsetForFirstLetter = textFragment->start();
>+                if (textOffset < offsetForFirstLetter)
>+                    return currentPos;
>+            }
>             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-                if (textOffset <= box->end()) {
>-                    if (textOffset >= box->start())
>+                if (textOffset <= box->end() + offsetForFirstLetter) {
>+                    if (textOffset >= box->start() + offsetForFirstLetter)
>                         return currentPos;
>                     continue;
>                 }
> 
>-                if (box == lastTextBox || textOffset != box->start() + box->len())
>+                if (box == lastTextBox || textOffset != box->start() + box->len() + offsetForFirstLetter)
>                     continue;
> 
>                 // The text continues on the next line only if the last text box is not on this line and
>@@ -783,17 +798,31 @@
>     if (!renderer)
>         return false;
>     
>+    int offset = m_offset;
>     RenderText *textRenderer = toRenderText(renderer);
>+    
>+    // If there's first-letter content, we need to either see if the position is rendered in the
>+    // first-letter's renderer, or subtract the offset for that content.
>+    if (textRenderer->isTextFragment()) {
>+        RenderTextFragment *textFragmentRenderer = static_cast<RenderTextFragment*>(textRenderer);
>+        if (offset < static_cast<int>(textFragmentRenderer->start()) && 
>+            textFragmentRenderer->firstLetter() && textFragmentRenderer->firstLetter()->firstChild())
>+            textRenderer = toRenderText(static_cast<RenderTextFragment*>(textRenderer)->firstLetter()->firstChild());
>+        else
>+            // Only set offsetForFirstLetter when we're looking at the trailing text fragment
>+            offset -= textFragmentRenderer->start();
>+    }
>+    
>     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-        if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
>+        if (offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
>             // The offset we're looking for is before this node
>             // this means the offset must be in content that is
>             // not rendered. Return false.
>             return false;
>         }
>-        if (box->containsCaretOffset(m_offset))
>-            // Return false for offsets inside composed characters.
>-            return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
>+        if (box->containsCaretOffset(offset))
>+             // Return false for offsets inside composed characters.
>+            return offset == 0 || offset == textRenderer->nextOffset(textRenderer->previousOffset(offset));
>     }
>     
>     return false;
>@@ -1052,10 +1081,20 @@
> 
>         InlineTextBox* box;
>         InlineTextBox* candidate = 0;
>+        
>+        unsigned offsetForFirstLetter = 0;
>+        if (textRenderer->isTextFragment()) {
>+            RenderTextFragment *textFragmentRenderer = static_cast<RenderTextFragment*>(textRenderer);
>+            if (caretOffset < static_cast<int>(textFragmentRenderer->start()) && 
>+                textFragmentRenderer->firstLetter() && textFragmentRenderer->firstLetter()->firstChild())
>+                textRenderer = toRenderText(static_cast<RenderTextFragment*>(textRenderer)->firstLetter()->firstChild());
>+            else
>+                offsetForFirstLetter = textFragmentRenderer->start();
>+        }
> 
>         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
>                 continue;
>@@ -1074,7 +1113,7 @@
>         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
>             box = searchAheadForBetterMatch(textRenderer);
>             if (box)
>-                caretOffset = box->caretMinOffset();
>+                caretOffset = box->caretMinOffset() + offsetForFirstLetter;
>         }
>         inlineBox = box ? box : candidate;
>     }
>Index: WebCore/editing/VisiblePosition.cpp
>===================================================================
>--- WebCore/editing/VisiblePosition.cpp	(revision 71591)
>+++ WebCore/editing/VisiblePosition.cpp	(working copy)
>@@ -33,6 +33,7 @@
> #include "InlineTextBox.h"
> #include "Logging.h"
> #include "Range.h"
>+#include "RenderTextFragment.h"
> #include "Text.h"
> #include "htmlediting.h"
> #include "visible_units.h"
>@@ -126,9 +127,16 @@
>                 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
> 
>             offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
>+            
>+            int offsetForFirstLetter = 0;
>+            if (renderer->isText() && toRenderText(renderer)->isTextFragment()) {
>+                offsetForFirstLetter = static_cast<RenderTextFragment*>(renderer)->start();
>+                if (offset < offsetForFirstLetter)
>+                    break;
>+            }
> 
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>             if (offset > caretMinOffset && offset < caretMaxOffset)
>                 break;
>@@ -146,7 +154,7 @@
>                 continue;
>             }
> 
>-            ASSERT(offset == box->caretLeftmostOffset());
>+            ASSERT(offset == box->caretLeftmostOffset() + offsetForFirstLetter);
> 
>             unsigned char level = box->bidiLevel();
>             InlineBox* prevBox = box->prevLeafChild();
>@@ -252,20 +260,25 @@
>         InlineBox* box;
>         int offset;
>         p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
>+        offset = p.offsetInContainerNode();
>         if (!box)
>             return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
> 
>         RenderObject* renderer = box->renderer();
>+        
>+        int offsetForFirstLetter = 0;
>+        if (renderer->isText() && toRenderText(renderer)->isTextFragment())
>+            offsetForFirstLetter = static_cast<RenderTextFragment*>(renderer)->start();
> 
>         while (true) {
>             if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
>                 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
> 
>             offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
>+            
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>-
>             if (offset > caretMinOffset && offset < caretMaxOffset)
>                 break;
> 
>@@ -282,7 +295,7 @@
>                 continue;
>             }
> 
>-            ASSERT(offset == box->caretRightmostOffset());
>+            ASSERT(offset == box->caretRightmostOffset() + offsetForFirstLetter);
> 
>             unsigned char level = box->bidiLevel();
>             InlineBox* nextBox = box->nextLeafChild();
>@@ -351,7 +364,11 @@
>             }
>             break;
>         }
>-
>+        
>+        // We need to adjust the offset to take into account first-letter content
>+       // if (renderer->isText() && toRenderText(renderer)->isTextFragment())
>+//            offset += static_cast<RenderTextFragment*>(renderer)->start();
>+        
>         p = Position(renderer->node(), offset);
> 
>         if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
>Index: WebCore/rendering/RenderText.cpp
>===================================================================
>--- WebCore/rendering/RenderText.cpp	(revision 71591)
>+++ WebCore/rendering/RenderText.cpp	(working copy)
>@@ -412,11 +412,18 @@
> 
> VisiblePosition RenderText::positionForPoint(const IntPoint& point)
> {
>+    return positionForPointAddingModifier(point, 0);
>+}
>+
>+VisiblePosition RenderText::positionForPointAddingModifier(const IntPoint& point, unsigned modifier)
>+{
>     if (!firstTextBox() || textLength() == 0)
>         return createVisiblePosition(0, DOWNSTREAM);
> 
>     // Get the offset for the position, since this will take rtl text into account.
>     int offset;
>+    
>+    // FIXME: We shouldn't need to 
> 
>     int pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
>     int pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
>@@ -426,13 +433,13 @@
>         // at the y coordinate of the first line or above
>         // and the x coordinate is to the left of the first text box left edge
>         offset = firstTextBox()->offsetForPosition(pointLineDirection);
>-        return createVisiblePosition(offset + firstTextBox()->start(), DOWNSTREAM);
>+        return createVisiblePosition(offset + modifier + firstTextBox()->start(), DOWNSTREAM);
>     }
>     if (lastTextBox() && pointBlockDirection >= lastTextBox()->root()->selectionTop() && pointLineDirection >= lastTextBox()->logicalRight()) {
>         // at the y coordinate of the last line or below
>         // and the x coordinate is to the right of the last text box right edge
>         offset = lastTextBox()->offsetForPosition(pointLineDirection);
>-        return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
>+        return createVisiblePosition(offset + modifier + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
>     }
> 
>     InlineTextBox* lastBoxAbove = 0;
>@@ -448,29 +455,29 @@
>                 if (pointLineDirection == box->logicalLeft())
>                     // the x coordinate is equal to the left edge of this box
>                     // the affinity must be downstream so the position doesn't jump back to the previous line
>-                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), DOWNSTREAM);
> 
>                 if (pointLineDirection < box->logicalRight())
>                     // and the x coordinate is to the left of the right edge of this box
>                     // check to see if position goes in this box
>-                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
> 
>                 if (!box->prevOnLine() && pointLineDirection < box->logicalLeft())
>                     // box is first on line
>                     // and the x coordinate is to the left of the first text box left edge
>-                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), DOWNSTREAM);
> 
>                 if (!box->nextOnLine())
>                     // box is last on line
>                     // and the x coordinate is to the right of the last text box right edge
>                     // generate VisiblePosition, use UPSTREAM affinity if possible
>-                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>             }
>             lastBoxAbove = box;
>         }
>     }
> 
>-    return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM);
>+    return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() + modifier : modifier, DOWNSTREAM);
> }
> 
> IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
>Index: WebCore/rendering/RenderTextFragment.cpp
>===================================================================
>--- WebCore/rendering/RenderTextFragment.cpp	(revision 71591)
>+++ WebCore/rendering/RenderTextFragment.cpp	(working copy)
>@@ -25,6 +25,7 @@
> 
> #include "RenderBlock.h"
> #include "Text.h"
>+#include "VisiblePosition.h"
> 
> namespace WebCore {
> 
>@@ -57,7 +58,25 @@
>         return 0;
>     return result->substring(start(), end());
> }
>-
>+    
>+VisiblePosition RenderTextFragment::positionForPoint(const IntPoint& point)
>+{
>+    if (m_firstLetter && m_firstLetter->firstChild()) {
>+        //FIXME: this solution is slow
>+        VisiblePosition positionInFirstLetter = m_firstLetter->firstChild()->positionForPoint(point);
>+        if (positionInFirstLetter.deepEquivalent().offsetInContainerNode() != (int) m_start)
>+            return positionInFirstLetter;
>+    }
>+    return RenderText::positionForPointAddingModifier(point, m_start);
>+}
>+    
>+IntRect RenderTextFragment::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
>+{
>+    if (caretOffset < (int) m_start && m_firstLetter && m_firstLetter->firstChild())
>+        return m_firstLetter->firstChild()->localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
>+    return RenderText::localCaretRect(inlineBox, caretOffset - m_start, extraWidthToEndOfLine);
>+}
>+    
> void RenderTextFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
> {
>     RenderText::styleDidChange(diff, oldStyle);
>Index: WebCore/rendering/RenderTextFragment.h
>===================================================================
>--- WebCore/rendering/RenderTextFragment.h	(revision 71591)
>+++ WebCore/rendering/RenderTextFragment.h	(working copy)
>@@ -50,6 +50,10 @@
>     StringImpl* contentString() const { return m_contentString.get(); }
>     virtual PassRefPtr<StringImpl> originalText() const;
> 
>+    virtual VisiblePosition positionForPoint(const IntPoint&);
>+
>+    virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
>+
> protected:
>     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
> 
>Index: WebCore/rendering/RenderText.h
>===================================================================
>--- WebCore/rendering/RenderText.h	(revision 71591)
>+++ WebCore/rendering/RenderText.h	(working copy)
>@@ -126,6 +126,8 @@
>     bool isAllCollapsibleWhitespace();
>     
> protected:
>+    VisiblePosition positionForPointAddingModifier(const IntPoint&, unsigned);
>+    
>     virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
>     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
>

--- Comment #12 from hytime at duck.com ---
Comment on attachment 74042
  --> https://bugs.webkit.org/attachment.cgi?id=74042
Patch

>Index: WebCore/dom/Position.cpp
>===================================================================
>--- WebCore/dom/Position.cpp	(revision 71591)
>+++ WebCore/dom/Position.cpp	(working copy)
>@@ -31,6 +31,7 @@
> #include "Logging.h"
> #include "PositionIterator.h"
> #include "RenderBlock.h"
>+#include "RenderTextFragment.h"
> #include "Text.h"
> #include "TextIterator.h"
> #include "VisiblePosition.h"
>@@ -558,14 +559,21 @@
>             unsigned textOffset = currentPos.offsetInLeafNode();
>             RenderText* textRenderer = toRenderText(renderer);
>             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
>+            unsigned offsetForFirstLetter = 0;
>+            if (textRenderer->isTextFragment()) {
>+                RenderTextFragment* textFragment = static_cast<RenderTextFragment*>(textRenderer);
>+                offsetForFirstLetter = textFragment->start();
>+                if (offsetForFirstLetter && textOffset <= offsetForFirstLetter)
>+                    return currentPos;
>+            }
>             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-                if (textOffset <= box->start() + box->len()) {
>-                    if (textOffset > box->start())
>+                if (textOffset <= box->start() + box->len() + offsetForFirstLetter) {
>+                    if (textOffset > box->start() + offsetForFirstLetter)
>                         return currentPos;
>                     continue;
>                 }
> 
>-                if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
>+                if (box == lastTextBox || textOffset != box->start() + box->len() + offsetForFirstLetter + 1)
>                     continue;
> 
>                 // The text continues on the next line only if the last text box is not on this line and
>@@ -680,14 +688,21 @@
>             unsigned textOffset = currentPos.offsetInLeafNode();
>             RenderText* textRenderer = toRenderText(renderer);
>             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
>+            unsigned offsetForFirstLetter = 0;
>+            if (textRenderer->isTextFragment()) {
>+                RenderTextFragment* textFragment = static_cast<RenderTextFragment*>(textRenderer);
>+                offsetForFirstLetter = textFragment->start();
>+                if (textOffset < offsetForFirstLetter)
>+                    return currentPos;
>+            }
>             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-                if (textOffset <= box->end()) {
>-                    if (textOffset >= box->start())
>+                if (textOffset <= box->end() + offsetForFirstLetter) {
>+                    if (textOffset >= box->start() + offsetForFirstLetter)
>                         return currentPos;
>                     continue;
>                 }
> 
>-                if (box == lastTextBox || textOffset != box->start() + box->len())
>+                if (box == lastTextBox || textOffset != box->start() + box->len() + offsetForFirstLetter)
>                     continue;
> 
>                 // The text continues on the next line only if the last text box is not on this line and
>@@ -783,17 +798,31 @@
>     if (!renderer)
>         return false;
>     
>+    int offset = m_offset;
>     RenderText *textRenderer = toRenderText(renderer);
>+    
>+    // If there's first-letter content, we need to either see if the position is rendered in the
>+    // first-letter's renderer, or subtract the offset for that content.
>+    if (textRenderer->isTextFragment()) {
>+        RenderTextFragment *textFragmentRenderer = static_cast<RenderTextFragment*>(textRenderer);
>+        if (offset < static_cast<int>(textFragmentRenderer->start()) && 
>+            textFragmentRenderer->firstLetter() && textFragmentRenderer->firstLetter()->firstChild())
>+            textRenderer = toRenderText(static_cast<RenderTextFragment*>(textRenderer)->firstLetter()->firstChild());
>+        else
>+            // Only set offsetForFirstLetter when we're looking at the trailing text fragment
>+            offset -= textFragmentRenderer->start();
>+    }
>+    
>     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-        if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
>+        if (offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
>             // The offset we're looking for is before this node
>             // this means the offset must be in content that is
>             // not rendered. Return false.
>             return false;
>         }
>-        if (box->containsCaretOffset(m_offset))
>-            // Return false for offsets inside composed characters.
>-            return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
>+        if (box->containsCaretOffset(offset))
>+             // Return false for offsets inside composed characters.
>+            return offset == 0 || offset == textRenderer->nextOffset(textRenderer->previousOffset(offset));
>     }
>     
>     return false;
>@@ -1052,10 +1081,20 @@
> 
>         InlineTextBox* box;
>         InlineTextBox* candidate = 0;
>+        
>+        unsigned offsetForFirstLetter = 0;
>+        if (textRenderer->isTextFragment()) {
>+            RenderTextFragment *textFragmentRenderer = static_cast<RenderTextFragment*>(textRenderer);
>+            if (caretOffset < static_cast<int>(textFragmentRenderer->start()) && 
>+                textFragmentRenderer->firstLetter() && textFragmentRenderer->firstLetter()->firstChild())
>+                textRenderer = toRenderText(static_cast<RenderTextFragment*>(textRenderer)->firstLetter()->firstChild());
>+            else
>+                offsetForFirstLetter = textFragmentRenderer->start();
>+        }
> 
>         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
>                 continue;
>@@ -1074,7 +1113,7 @@
>         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
>             box = searchAheadForBetterMatch(textRenderer);
>             if (box)
>-                caretOffset = box->caretMinOffset();
>+                caretOffset = box->caretMinOffset() + offsetForFirstLetter;
>         }
>         inlineBox = box ? box : candidate;
>     }
>Index: WebCore/editing/VisiblePosition.cpp
>===================================================================
>--- WebCore/editing/VisiblePosition.cpp	(revision 71591)
>+++ WebCore/editing/VisiblePosition.cpp	(working copy)
>@@ -33,6 +33,7 @@
> #include "InlineTextBox.h"
> #include "Logging.h"
> #include "Range.h"
>+#include "RenderTextFragment.h"
> #include "Text.h"
> #include "htmlediting.h"
> #include "visible_units.h"
>@@ -126,9 +127,16 @@
>                 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
> 
>             offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
>+            
>+            int offsetForFirstLetter = 0;
>+            if (renderer->isText() && toRenderText(renderer)->isTextFragment()) {
>+                offsetForFirstLetter = static_cast<RenderTextFragment*>(renderer)->start();
>+                if (offset < offsetForFirstLetter)
>+                    break;
>+            }
> 
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>             if (offset > caretMinOffset && offset < caretMaxOffset)
>                 break;
>@@ -146,7 +154,7 @@
>                 continue;
>             }
> 
>-            ASSERT(offset == box->caretLeftmostOffset());
>+            ASSERT(offset == box->caretLeftmostOffset() + offsetForFirstLetter);
> 
>             unsigned char level = box->bidiLevel();
>             InlineBox* prevBox = box->prevLeafChild();
>@@ -252,20 +260,25 @@
>         InlineBox* box;
>         int offset;
>         p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
>+        offset = p.offsetInContainerNode();
>         if (!box)
>             return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
> 
>         RenderObject* renderer = box->renderer();
>+        
>+        int offsetForFirstLetter = 0;
>+        if (renderer->isText() && toRenderText(renderer)->isTextFragment())
>+            offsetForFirstLetter = static_cast<RenderTextFragment*>(renderer)->start();
> 
>         while (true) {
>             if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
>                 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
> 
>             offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
>+            
>+            int caretMinOffset = box->caretMinOffset() + offsetForFirstLetter;
>+            int caretMaxOffset = box->caretMaxOffset() + offsetForFirstLetter;
> 
>-            int caretMinOffset = box->caretMinOffset();
>-            int caretMaxOffset = box->caretMaxOffset();
>-
>             if (offset > caretMinOffset && offset < caretMaxOffset)
>                 break;
> 
>@@ -282,7 +295,7 @@
>                 continue;
>             }
> 
>-            ASSERT(offset == box->caretRightmostOffset());
>+            ASSERT(offset == box->caretRightmostOffset() + offsetForFirstLetter);
> 
>             unsigned char level = box->bidiLevel();
>             InlineBox* nextBox = box->nextLeafChild();
>@@ -351,7 +364,11 @@
>             }
>             break;
>         }
>-
>+        
>+        // We need to adjust the offset to take into account first-letter content
>+       // if (renderer->isText() && toRenderText(renderer)->isTextFragment())
>+//            offset += static_cast<RenderTextFragment*>(renderer)->start();
>+        
>         p = Position(renderer->node(), offset);
> 
>         if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
>Index: WebCore/rendering/RenderText.cpp
>===================================================================
>--- WebCore/rendering/RenderText.cpp	(revision 71591)
>+++ WebCore/rendering/RenderText.cpp	(working copy)
>@@ -412,11 +412,18 @@
> 
> VisiblePosition RenderText::positionForPoint(const IntPoint& point)
> {
>+    return positionForPointAddingModifier(point, 0);
>+}
>+
>+VisiblePosition RenderText::positionForPointAddingModifier(const IntPoint& point, unsigned modifier)
>+{
>     if (!firstTextBox() || textLength() == 0)
>         return createVisiblePosition(0, DOWNSTREAM);
> 
>     // Get the offset for the position, since this will take rtl text into account.
>     int offset;
>+    
>+    // FIXME: We shouldn't need to 
> 
>     int pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
>     int pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
>@@ -426,13 +433,13 @@
>         // at the y coordinate of the first line or above
>         // and the x coordinate is to the left of the first text box left edge
>         offset = firstTextBox()->offsetForPosition(pointLineDirection);
>-        return createVisiblePosition(offset + firstTextBox()->start(), DOWNSTREAM);
>+        return createVisiblePosition(offset + modifier + firstTextBox()->start(), DOWNSTREAM);
>     }
>     if (lastTextBox() && pointBlockDirection >= lastTextBox()->root()->selectionTop() && pointLineDirection >= lastTextBox()->logicalRight()) {
>         // at the y coordinate of the last line or below
>         // and the x coordinate is to the right of the last text box right edge
>         offset = lastTextBox()->offsetForPosition(pointLineDirection);
>-        return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
>+        return createVisiblePosition(offset + modifier + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
>     }
> 
>     InlineTextBox* lastBoxAbove = 0;
>@@ -448,29 +455,29 @@
>                 if (pointLineDirection == box->logicalLeft())
>                     // the x coordinate is equal to the left edge of this box
>                     // the affinity must be downstream so the position doesn't jump back to the previous line
>-                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), DOWNSTREAM);
> 
>                 if (pointLineDirection < box->logicalRight())
>                     // and the x coordinate is to the left of the right edge of this box
>                     // check to see if position goes in this box
>-                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
> 
>                 if (!box->prevOnLine() && pointLineDirection < box->logicalLeft())
>                     // box is first on line
>                     // and the x coordinate is to the left of the first text box left edge
>-                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), DOWNSTREAM);
> 
>                 if (!box->nextOnLine())
>                     // box is last on line
>                     // and the x coordinate is to the right of the last text box right edge
>                     // generate VisiblePosition, use UPSTREAM affinity if possible
>-                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>+                    return createVisiblePosition(offset + modifier + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
>             }
>             lastBoxAbove = box;
>         }
>     }
> 
>-    return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM);
>+    return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() + modifier : modifier, DOWNSTREAM);
> }
> 
> IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
>Index: WebCore/rendering/RenderTextFragment.cpp
>===================================================================
>--- WebCore/rendering/RenderTextFragment.cpp	(revision 71591)
>+++ WebCore/rendering/RenderTextFragment.cpp	(working copy)
>@@ -25,6 +25,7 @@
> 
> #include "RenderBlock.h"
> #include "Text.h"
>+#include "VisiblePosition.h"
> 
> namespace WebCore {
> 
>@@ -57,7 +58,25 @@
>         return 0;
>     return result->substring(start(), end());
> }
>-
>+    
>+VisiblePosition RenderTextFragment::positionForPoint(const IntPoint& point)
>+{
>+    if (m_firstLetter && m_firstLetter->firstChild()) {
>+        //FIXME: this solution is slow
>+        VisiblePosition positionInFirstLetter = m_firstLetter->firstChild()->positionForPoint(point);
>+        if (positionInFirstLetter.deepEquivalent().offsetInContainerNode() != (int) m_start)
>+            return positionInFirstLetter;
>+    }
>+    return RenderText::positionForPointAddingModifier(point, m_start);
>+}
>+    
>+IntRect RenderTextFragment::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
>+{
>+    if (caretOffset < (int) m_start && m_firstLetter && m_firstLetter->firstChild())
>+        return m_firstLetter->firstChild()->localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
>+    return RenderText::localCaretRect(inlineBox, caretOffset - m_start, extraWidthToEndOfLine);
>+}
>+    
> void RenderTextFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
> {
>     RenderText::styleDidChange(diff, oldStyle);
>Index: WebCore/rendering/RenderTextFragment.h
>===================================================================
>--- WebCore/rendering/RenderTextFragment.h	(revision 71591)
>+++ WebCore/rendering/RenderTextFragment.h	(working copy)
>@@ -50,6 +50,10 @@
>     StringImpl* contentString() const { return m_contentString.get(); }
>     virtual PassRefPtr<StringImpl> originalText() const;
> 
>+    virtual VisiblePosition positionForPoint(const IntPoint&);
>+
>+    virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
>+
> protected:
>     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
> 
>Index: WebCore/rendering/RenderText.h
>===================================================================
>--- WebCore/rendering/RenderText.h	(revision 71591)
>+++ WebCore/rendering/RenderText.h	(working copy)
>@@ -126,6 +126,8 @@
>     bool isAllCollapsibleWhitespace();
>     
> protected:
>+    VisiblePosition positionForPointAddingModifier(const IntPoint&, unsigned);
>+    
>     virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
>     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
>

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20240510/a052b46d/attachment-0001.htm>


More information about the webkit-unassigned mailing list