[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