Commit 576e84e8 authored by mitz@apple.com's avatar mitz@apple.com

WebCore:

        Reviewed by Darin Adler.

        - preparation for https://bugs.webkit.org/show_bug.cgi?id=3729
          <rdar://problem/4036353> REGRESSION: arrow keys move insertion bar backwards in RTL text

        The three main changes in this patch are:

        1) Making all inline boxes know their bidi level, instead of just text
           boxes knowing whether their bidi level is odd or even. This is
           required for the next change.

        2) Replacing RenderObject::inlineBox() with
           Position::getInlineBoxAndOffset() in recognition of the fact that the
           inline box containing the primary caret for a position in a given
           node may belong to a different node's renderer.

        3) Changing RenderObject::caretRect() to take an InlineBox parameter,
           and changing callers to call VisiblePosition::caretRect(), which
           locates the inline box, then calls caretRect() on the renderer for
           that box. This, combined with the previous change, ensures that the
           primary caret is rendered at the right place for positions that
           lie on a directionality boundary.

        Test: platform/mac/editing/input/caret-primary-bidi.html

        * WebCore.base.exp: Added the VisiblePosition(Node*, int, EAffinity)
        constructor and VisiblePosition::caretRect(), and sorted.

        * dom/Position.cpp:
        (WebCore::nextRenderedEditable): Adjusted for the removal of
        RenderObject::inlineBox().
        (WebCore::previousRenderedEditable): Ditto.
        (WebCore::Position::rendersInDifferentPosition): Ditto.
        (WebCore::Position::getInlineBoxAndOffset): Added. Gets the inline box
        and the offset within that box at which the primary caret for this
        position should render.

        * dom/Position.h:

        * editing/DeleteSelectionCommand.cpp:
        (WebCore::DeleteSelectionCommand::mergeParagraphs): Changed to call
        VisiblePosition::caretRect() instead of calling the RenderObject method.

        * editing/SelectionController.cpp:
        (WebCore::caretY): Ditto.
        (WebCore::SelectionController::xPosForVerticalArrowNavigation): Ditto.
        (WebCore::SelectionController::layout): Ditto.

        * editing/VisiblePosition.cpp:
        (WebCore::VisiblePosition::caretRect): Changed to call
        getInlineBoxAndOffset() to get the correct inline box and call the
        renderer for that box.

        * editing/VisiblePosition.h:
        (WebCore::VisiblePosition::getInlineBoxAndOffset): Added convenience
        methods for getting the inline box and caret offset for a visible
        position, accounting for its affinity.

        * editing/visible_units.cpp:
        (WebCore::rootBoxForLine): Changed to use getInlineBoxAndOffset()
        instead of RenderObject::inlineBox().
        (WebCore::startPositionForLine):
        (WebCore::endPositionForLine):
        (WebCore::previousLinePosition): Ditto.
        (WebCore::nextLinePosition): Ditto.

        * page/AccessibilityObject.cpp:
        (WebCore::updateAXLineStartForVisiblePosition): Ditto.

        * page/Frame.cpp:
        (WebCore::Frame::firstRectForRange): Ditto.

        * rendering/InlineBox.cpp:
        (WebCore::InlineBox::caretMinOffset): Changed to forward to the
        renderer.
        (WebCore::InlineBox::caretMaxOffset): Ditto.
        * rendering/InlineBox.h: Replaced the m_reversed bit, intended for use
        in InlineTextBox only, with six bits of the bidi level of the box,
        intended for use in all leaf inline boxes.
        (WebCore::InlineBox::InlineBox): Added missing initializer for
        m_dirOverride and initialized the bidi level.
        (WebCore::InlineBox::bidiLevel): Added this accessor.
        (WebCore::InlineBox::setBidiLevel): Ditto.
        (WebCore::InlineBox::direction): Ditto.
        (WebCore::InlineBox::caretLeftmostOffset): Added this convenience
        method.
        (WebCore::InlineBox::caretRightmostOffset): Ditto.

        * rendering/InlineTextBox.cpp: Replaced all references to m_reversed
        with checking of direction().
        (WebCore::InlineTextBox::selectionRect):
        (WebCore::InlineTextBox::placeEllipsisBox):
        (WebCore::InlineTextBox::paint):
        (WebCore::InlineTextBox::paintSelection):
        (WebCore::InlineTextBox::paintCompositionBackground):
        (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
        (WebCore::InlineTextBox::paintTextMatchMarker):
        (WebCore::InlineTextBox::textPos):
        (WebCore::InlineTextBox::offsetForPosition):
        (WebCore::InlineTextBox::positionForOffset):

        * rendering/RenderBR.cpp: Removed inlineBox().
        * rendering/RenderBR.h: Ditto.

        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::caretRect): Changed to take an inline box and
        account for the direction of the box (or the renderer) in positioning
        the caret: in right-to-left boxes, the "before" position is to the right
        while "after" is to the left.
        * rendering/RenderBox.h:

        * rendering/RenderFlow.cpp:
        (WebCore::RenderFlow::caretRect): Updated the signature.
        * rendering/RenderFlow.h:

        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::caretRect): Updated the signature.
        (WebCore::RenderObject::caretMaxOffset): Changed to return the child
        node count (or 1 if there are no children) for replaced elements, such
        as <select>s.
        * rendering/RenderObject.h:

        * rendering/RenderReplaced.cpp: Removed caretMinOffset() and
        caretMaxOffset() because the base class implementation does the right
        thing for replaced objects now.
        * rendering/RenderReplaced.h:

        * rendering/RenderSVGInlineText.cpp:
        (WebCore::RenderSVGInlineText::caretRect): Updated the signature.
        (WebCore::RenderSVGInlineText::positionForCoordinates): Updated for
        the change from m_reversed to direction().
        * rendering/RenderSVGInlineText.h:

        * rendering/RenderText.cpp:
        (WebCore::RenderText::caretRect): Changed to take an inline box and
        removed the code that used to find the inline for the given position.
        Changed use of m_reversed to use direction().
        (WebCore::RenderText::position): Changed use of m_reversed to use
        direction().
        * rendering/RenderText.h:

        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::textWithHardLineBreaks): Adjusted for the
        removal of RenderObject::inlineBox().

        * rendering/RenderTreeAsText.cpp:
        (WebCore::writeTextRun): Changed to use direction() instead of
        m_reversed.

        * rendering/SVGInlineTextBox.cpp: Ditto.
        (WebCore::SVGInlineTextBox::calculateGlyphBoundaries):
        (WebCore::SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback):
        (WebCore::SVGInlineTextBox::svgCharacterHitsPosition):

        * rendering/SVGRenderTreeAsText.cpp: Ditto.
        (WebCore::writeSVGInlineTextBox):

        * rendering/SVGRootInlineBox.cpp: Ditto.
        (WebCore::svgTextRunForInlineTextBox):
        (WebCore::cummulatedWidthOrHeightOfTextChunk):
        (WebCore::SVGRootInlineBox::buildLayoutInformationForTextBox):

        * rendering/bidi.cpp:
        (WebCore::RenderBlock::constructLine): Made this function set the
        bidi level on all leaf boxes.

        * svg/SVGTextContentElement.cpp: Changed to use direction() instead of
        m_reversed.
        (WebCore::cumulativeCharacterRangeLength):
        (WebCore::SVGInlineTextBoxQueryWalker::chunkPortionCallback):

WebKit/mac:

        Reviewed by Darin Adler.

        - preparation for https://bugs.webkit.org/show_bug.cgi?id=3729
          <rdar://problem/4036353> REGRESSION: arrow keys move insertion bar backwards in RTL text

        * WebView/WebFrame.mm:
        (-[WebFrame _caretRectAtNode:offset:affinity:]): Changed to use
        VisiblePosition::caretRect() instead of the RenderObject method which
        was removed.

LayoutTests:

        Reviewed by Darin Adler.

        - test the visual position of the primary caret in bidirectional text

        * platform/mac/editing/input/caret-primary-bidi-expected.txt: Added.
        * platform/mac/editing/input/caret-primary-bidi.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@32508 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3eaedb3e
2008-04-24 Dan Bernstein <mitz@apple.com>
Reviewed by Darin Adler.
- test the visual position of the primary caret in bidirectional text
* platform/mac/editing/input/caret-primary-bidi-expected.txt: Added.
* platform/mac/editing/input/caret-primary-bidi.html: Added.
2008-04-24 Justin Garcia <justin.garcia@apple.com>
Reviewed by Darin Adler.
0: -1,572,0,28
1: -1,572,0,28
2: 8,478,0,28
3: 49,564,0,28
4: 157,564,0,28
5: 143,564,0,28
6: 86,564,0,28
7: 101,564,0,28
8: 116,564,0,28
9: 132,564,0,28
10: 74,564,0,28
11: 57,564,0,28
12: 172,564,0,28
13: 187,564,0,28
14: 200,564,0,28
15: 210,564,0,28
16: 8,536,0,28
17: 116,536,0,28
18: 102,536,0,28
19: 45,536,0,28
20: 60,536,0,28
21: 75,536,0,28
22: 91,536,0,28
23: 33,536,0,28
24: 16,536,0,28
25: 131,536,0,28
26: 8,508,0,28
27: 150,508,0,28
28: 136,508,0,28
29: 125,508,0,28
30: 33,508,0,28
31: 16,508,0,28
32: 165,508,0,28
33: 8,478,0,28
34: 33,478,0,28
35: 19,478,0,28
36: 48,478,0,28
37: 61,478,0,28
38: 76,478,0,28
39: 89,478,0,28
40: 114,478,0,28
41: 97,478,0,28
42: 126,478,0,28
43: 792,450,0,28
44: 764,450,0,28
45: 779,450,0,28
46: 751,450,0,28
47: 736,450,0,28
48: 722,450,0,28
49: 711,450,0,28
50: 680,450,0,28
51: 695,450,0,28
52: 665,450,0,28
53: 653,450,0,28
54: 636,450,0,28
55: 628,450,0,28
56: 605,450,0,28
57: 618,450,0,28
58: 590,450,0,28
59: 792,422,0,28
60: 777,422,0,28
61: 763,422,0,28
62: 752,422,0,28
63: 721,422,0,28
64: 736,422,0,28
65: 706,422,0,28
66: 694,422,0,28
67: 677,422,0,28
68: 669,422,0,28
69: 792,394,0,28
70: 777,394,0,28
71: 763,394,0,28
72: 752,394,0,28
73: 660,394,0,28
74: 643,394,0,28
75: 635,394,0,28
76: 792,364,0,28
77: 764,364,0,28
78: 779,364,0,28
79: 751,364,0,28
80: 736,364,0,28
81: 722,364,0,28
82: 711,364,0,28
83: 688,364,0,28
84: 701,364,0,28
85: 673,364,0,28
<style>
div#tests { -webkit-user-modify: read-write; font-family: Lucida Grande; font-size: 24px; }
</style>
<div id="tests">
<div>
abc&#x05d0;&#x05d1;&#x05d2;123&#x05d3;&#x05d4;&#x05d5;def
</div>
<div>
&#x05d0;&#x05d1;&#x05d2;123&#x05d3;&#x05d4;&#x05d5;
</div>
<div>
&#x05d0;&#x05d1;&#x05d2;<select></select><select></select>&#x05d3;&#x05d4;&#x05d5;
</div>
<div>
&#x05d0;&#x05d1;&#x05d2;abc&#x05d3;&#x05d4;&#x05d5;
</div>
<div style="direction: rtl;">
abc&#x05d0;&#x05d1;&#x05d2;123&#x05d3;&#x05d4;&#x05d5;def
</div>
<div style="direction: rtl;">
&#x05d0;&#x05d1;&#x05d2;123&#x05d3;&#x05d4;&#x05d5;
</div>
<div style="direction: rtl;">
&#x05d0;&#x05d1;&#x05d2;<select></select><select></select>&#x05d3;&#x05d4;&#x05d5;
</div>
<div style="direction: rtl;">
abc&#x05d0;&#x05d1;&#x05d2;def
</div>
</div>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
var log = "";
for (var i = 0; i < 86; ++i)
log += i + ": " + textInputController.firstRectForCharacterRange(i, 0) + "\n";
document.body.appendChild(document.createElement("pre")).appendChild(document.createTextNode(log));
document.getElementById("tests").style.display = "none";
}
</script>
2008-04-24 Dan Bernstein <mitz@apple.com>
Reviewed by Darin Adler.
- preparation for https://bugs.webkit.org/show_bug.cgi?id=3729
<rdar://problem/4036353> REGRESSION: arrow keys move insertion bar backwards in RTL text
The three main changes in this patch are:
1) Making all inline boxes know their bidi level, instead of just text
boxes knowing whether their bidi level is odd or even. This is
required for the next change.
2) Replacing RenderObject::inlineBox() with
Position::getInlineBoxAndOffset() in recognition of the fact that the
inline box containing the primary caret for a position in a given
node may belong to a different node's renderer.
3) Changing RenderObject::caretRect() to take an InlineBox parameter,
and changing callers to call VisiblePosition::caretRect(), which
locates the inline box, then calls caretRect() on the renderer for
that box. This, combined with the previous change, ensures that the
primary caret is rendered at the right place for positions that
lie on a directionality boundary.
Test: platform/mac/editing/input/caret-primary-bidi.html
* WebCore.base.exp: Added the VisiblePosition(Node*, int, EAffinity)
constructor and VisiblePosition::caretRect(), and sorted.
* dom/Position.cpp:
(WebCore::nextRenderedEditable): Adjusted for the removal of
RenderObject::inlineBox().
(WebCore::previousRenderedEditable): Ditto.
(WebCore::Position::rendersInDifferentPosition): Ditto.
(WebCore::Position::getInlineBoxAndOffset): Added. Gets the inline box
and the offset within that box at which the primary caret for this
position should render.
* dom/Position.h:
* editing/DeleteSelectionCommand.cpp:
(WebCore::DeleteSelectionCommand::mergeParagraphs): Changed to call
VisiblePosition::caretRect() instead of calling the RenderObject method.
* editing/SelectionController.cpp:
(WebCore::caretY): Ditto.
(WebCore::SelectionController::xPosForVerticalArrowNavigation): Ditto.
(WebCore::SelectionController::layout): Ditto.
* editing/VisiblePosition.cpp:
(WebCore::VisiblePosition::caretRect): Changed to call
getInlineBoxAndOffset() to get the correct inline box and call the
renderer for that box.
* editing/VisiblePosition.h:
(WebCore::VisiblePosition::getInlineBoxAndOffset): Added convenience
methods for getting the inline box and caret offset for a visible
position, accounting for its affinity.
* editing/visible_units.cpp:
(WebCore::rootBoxForLine): Changed to use getInlineBoxAndOffset()
instead of RenderObject::inlineBox().
(WebCore::startPositionForLine):
(WebCore::endPositionForLine):
(WebCore::previousLinePosition): Ditto.
(WebCore::nextLinePosition): Ditto.
* page/AccessibilityObject.cpp:
(WebCore::updateAXLineStartForVisiblePosition): Ditto.
* page/Frame.cpp:
(WebCore::Frame::firstRectForRange): Ditto.
* rendering/InlineBox.cpp:
(WebCore::InlineBox::caretMinOffset): Changed to forward to the
renderer.
(WebCore::InlineBox::caretMaxOffset): Ditto.
* rendering/InlineBox.h: Replaced the m_reversed bit, intended for use
in InlineTextBox only, with six bits of the bidi level of the box,
intended for use in all leaf inline boxes.
(WebCore::InlineBox::InlineBox): Added missing initializer for
m_dirOverride and initialized the bidi level.
(WebCore::InlineBox::bidiLevel): Added this accessor.
(WebCore::InlineBox::setBidiLevel): Ditto.
(WebCore::InlineBox::direction): Ditto.
(WebCore::InlineBox::caretLeftmostOffset): Added this convenience
method.
(WebCore::InlineBox::caretRightmostOffset): Ditto.
* rendering/InlineTextBox.cpp: Replaced all references to m_reversed
with checking of direction().
(WebCore::InlineTextBox::selectionRect):
(WebCore::InlineTextBox::placeEllipsisBox):
(WebCore::InlineTextBox::paint):
(WebCore::InlineTextBox::paintSelection):
(WebCore::InlineTextBox::paintCompositionBackground):
(WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
(WebCore::InlineTextBox::paintTextMatchMarker):
(WebCore::InlineTextBox::textPos):
(WebCore::InlineTextBox::offsetForPosition):
(WebCore::InlineTextBox::positionForOffset):
* rendering/RenderBR.cpp: Removed inlineBox().
* rendering/RenderBR.h: Ditto.
* rendering/RenderBox.cpp:
(WebCore::RenderBox::caretRect): Changed to take an inline box and
account for the direction of the box (or the renderer) in positioning
the caret: in right-to-left boxes, the "before" position is to the right
while "after" is to the left.
* rendering/RenderBox.h:
* rendering/RenderFlow.cpp:
(WebCore::RenderFlow::caretRect): Updated the signature.
* rendering/RenderFlow.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::caretRect): Updated the signature.
(WebCore::RenderObject::caretMaxOffset): Changed to return the child
node count (or 1 if there are no children) for replaced elements, such
as <select>s.
* rendering/RenderObject.h:
* rendering/RenderReplaced.cpp: Removed caretMinOffset() and
caretMaxOffset() because the base class implementation does the right
thing for replaced objects now.
* rendering/RenderReplaced.h:
* rendering/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::caretRect): Updated the signature.
(WebCore::RenderSVGInlineText::positionForCoordinates): Updated for
the change from m_reversed to direction().
* rendering/RenderSVGInlineText.h:
* rendering/RenderText.cpp:
(WebCore::RenderText::caretRect): Changed to take an inline box and
removed the code that used to find the inline for the given position.
Changed use of m_reversed to use direction().
(WebCore::RenderText::position): Changed use of m_reversed to use
direction().
* rendering/RenderText.h:
* rendering/RenderTextControl.cpp:
(WebCore::RenderTextControl::textWithHardLineBreaks): Adjusted for the
removal of RenderObject::inlineBox().
* rendering/RenderTreeAsText.cpp:
(WebCore::writeTextRun): Changed to use direction() instead of
m_reversed.
* rendering/SVGInlineTextBox.cpp: Ditto.
(WebCore::SVGInlineTextBox::calculateGlyphBoundaries):
(WebCore::SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback):
(WebCore::SVGInlineTextBox::svgCharacterHitsPosition):
* rendering/SVGRenderTreeAsText.cpp: Ditto.
(WebCore::writeSVGInlineTextBox):
* rendering/SVGRootInlineBox.cpp: Ditto.
(WebCore::svgTextRunForInlineTextBox):
(WebCore::cummulatedWidthOrHeightOfTextChunk):
(WebCore::SVGRootInlineBox::buildLayoutInformationForTextBox):
* rendering/bidi.cpp:
(WebCore::RenderBlock::constructLine): Made this function set the
bidi level on all leaf boxes.
* svg/SVGTextContentElement.cpp: Changed to use direction() instead of
m_reversed.
(WebCore::cumulativeCharacterRangeLength):
(WebCore::SVGInlineTextBoxQueryWalker::chunkPortionCallback):
2008-04-24 Sam Weinig <sam@webkit.org>
Fix the world.
......@@ -334,6 +334,7 @@ __ZN7WebCore15GraphicsContextD1Ev
__ZN7WebCore15StringTruncator13rightTruncateERKNS_6StringEfRKNS_4FontEb
__ZN7WebCore15StringTruncator14centerTruncateERKNS_6StringEfRKNS_4FontEb
__ZN7WebCore15StringTruncator5widthERKNS_6StringERKNS_4FontEb
__ZN7WebCore15VisiblePositionC1EPNS_4NodeEiNS_9EAffinityE
__ZN7WebCore15VisiblePositionC1ERKNS_8PositionENS_9EAffinityE
__ZN7WebCore16FontPlatformDataC1EP6NSFontbb
__ZN7WebCore16FontPlatformDataD1Ev
......@@ -632,8 +633,8 @@ __ZNK7WebCore11FrameLoader15firstLayoutDoneEv
__ZNK7WebCore11FrameLoader16outgoingReferrerEv
__ZNK7WebCore11FrameLoader16responseMIMETypeEv
__ZNK7WebCore11FrameLoader20activeDocumentLoaderEv
__ZNK7WebCore11FrameLoader25provisionalDocumentLoaderEv
__ZNK7WebCore11FrameLoader21isQuickRedirectComingEv
__ZNK7WebCore11FrameLoader25provisionalDocumentLoaderEv
__ZNK7WebCore11FrameLoader27numPendingOrLoadingRequestsEb
__ZNK7WebCore11FrameLoader6clientEv
__ZNK7WebCore11FrameLoader8loadTypeEv
......@@ -701,6 +702,7 @@ __ZNK7WebCore15ResourceRequest12nsURLRequestEv
__ZNK7WebCore15VisiblePosition14characterAfterEv
__ZNK7WebCore15VisiblePosition4nextEb
__ZNK7WebCore15VisiblePosition8previousEb
__ZNK7WebCore15VisiblePosition9caretRectEv
__ZNK7WebCore16ResourceResponse13nsURLResponseEv
__ZNK7WebCore17ResourceErrorBase8lazyInitEv
__ZNK7WebCore19InspectorController17drawNodeHighlightERNS_15GraphicsContextE
......
......@@ -50,9 +50,10 @@ static Node *nextRenderedEditable(Node *node)
node = node->nextEditable();
if (!node)
return 0;
if (!node->renderer())
RenderObject* renderer = node->renderer();
if (!renderer)
continue;
if (node->renderer()->inlineBox(0))
if (renderer->inlineBoxWrapper() || renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox())
return node;
}
return 0;
......@@ -64,9 +65,10 @@ static Node *previousRenderedEditable(Node *node)
node = node->previousEditable();
if (!node)
return 0;
if (!node->renderer())
RenderObject* renderer = node->renderer();
if (!renderer)
continue;
if (node->renderer()->inlineBox(0))
if (renderer->inlineBoxWrapper() || renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox())
return node;
}
return 0;
......@@ -683,17 +685,20 @@ bool Position::rendersInDifferentPosition(const Position &pos) const
if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
return false;
LOG(Editing, "renderer: %p [%p]\n", renderer, renderer ? renderer->inlineBox(offset()) : 0);
int ignoredCaretOffset;
InlineBox* b1;
getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
InlineBox* b2;
pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, posRenderer ? posRenderer->inlineBox(offset()) : 0);
LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2);
LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(node()), caretMaxRenderedOffset(node()));
LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.node()), caretMaxRenderedOffset(pos.node()));
LOG(Editing, "----------------------------------------------------------------------\n");
InlineBox *b1 = renderer ? renderer->inlineBox(offset()) : 0;
InlineBox *b2 = posRenderer ? posRenderer->inlineBox(pos.offset()) : 0;
if (!b1 || !b2) {
return false;
}
......@@ -754,6 +759,144 @@ Position Position::trailingWhitespacePosition(EAffinity affinity, bool considerN
return Position();
}
void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
{
TextDirection primaryDirection = LTR;
for (RenderObject* r = node()->renderer(); r; r = r->parent()) {
if (r->isBlockFlow()) {
primaryDirection = r->style()->direction();
break;
}
}
getInlineBoxAndOffset(affinity, primaryDirection, inlineBox, caretOffset);
}
void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
{
caretOffset = offset();
RenderObject* renderer = node()->renderer();
if (!renderer->isText()) {
inlineBox = renderer->inlineBoxWrapper();
if (!inlineBox || caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset())
return;
} else {
RenderText* textRenderer = static_cast<RenderText*>(renderer);
InlineTextBox* box;
InlineTextBox* candidate = 0;
for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
int caretMinOffset = box->caretMinOffset();
int caretMaxOffset = box->caretMaxOffset();
if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset)
continue;
if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
inlineBox = box;
return;
}
if (caretOffset == caretMinOffset ^ affinity == UPSTREAM)
break;
candidate = box;
}
inlineBox = box ? box : candidate;
}
if (!inlineBox)
return;
unsigned char level = inlineBox->bidiLevel();
if (inlineBox->direction() == primaryDirection) {
if (caretOffset == inlineBox->caretRightmostOffset()) {
InlineBox* nextBox = inlineBox->nextLeafChild();
if (!nextBox || nextBox->bidiLevel() >= level)
return;
level = nextBox->bidiLevel();
InlineBox* prevBox = inlineBox;
do {
prevBox = prevBox->prevLeafChild();
} while (prevBox && prevBox->bidiLevel() > level);
if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
return;
// For example, abc 123 ^ CBA
while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
if (nextBox->bidiLevel() < level)
break;
inlineBox = nextBox;
}
caretOffset = inlineBox->caretRightmostOffset();
} else {
InlineBox* prevBox = inlineBox->prevLeafChild();
if (!prevBox || prevBox->bidiLevel() >= level)
return;
level = prevBox->bidiLevel();
InlineBox* nextBox = inlineBox;
do {
nextBox = nextBox->nextLeafChild();
} while (nextBox && nextBox->bidiLevel() > level);
if (nextBox && nextBox->bidiLevel() == level)
return;
while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
if (prevBox->bidiLevel() < level)
break;
inlineBox = prevBox;
}
caretOffset = inlineBox->caretLeftmostOffset();
}
return;
}
if (caretOffset == inlineBox->caretLeftmostOffset()) {
InlineBox* prevBox = inlineBox->prevLeafChild();
if (!prevBox || prevBox->bidiLevel() < level) {
// Left edge of a secondary run. Set to the right edge of the entire run.
while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
if (nextBox->bidiLevel() < level)
break;
inlineBox = nextBox;
}
caretOffset = inlineBox->caretRightmostOffset();
} else if (prevBox->bidiLevel() > level) {
// Right edge of a "tertiary" run. Set to the left edge of that run.
while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
if (tertiaryBox->bidiLevel() <= level)
break;
inlineBox = tertiaryBox;
}
caretOffset = !inlineBox->caretLeftmostOffset();
}
} else {
InlineBox* nextBox = inlineBox->nextLeafChild();
if (!nextBox || nextBox->bidiLevel() < level) {
// Right edge of a secondary run. Set to the left edge of the entire run.
while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
if (prevBox->bidiLevel() < level)
break;
inlineBox = prevBox;
}
caretOffset = inlineBox->caretLeftmostOffset();
} else if (nextBox->bidiLevel() > level) {
// Left edge of a "tertiary" run. Set to the right edge of that run.
while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
if (tertiaryBox->bidiLevel() <= level)
break;
inlineBox = tertiaryBox;
}
caretOffset = inlineBox->caretRightmostOffset();
}
}
}
void Position::debugPosition(const char* msg) const
{
if (isNull())
......
......@@ -27,6 +27,7 @@
#define Position_h
#include "TextAffinity.h"
#include "TextDirection.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
......@@ -34,6 +35,7 @@ namespace WebCore {
class CSSComputedStyleDeclaration;
class Element;
class InlineBox;
class Node;
class Range;
class RenderObject;
......@@ -88,7 +90,10 @@ public:
bool inRenderedText() const;
bool isRenderedCharacter() const;
bool rendersInDifferentPosition(const Position&) const;
void getInlineBoxAndOffset(EAffinity, InlineBox*&, int& caretOffset) const;
void getInlineBoxAndOffset(EAffinity, TextDirection primaryDirection, InlineBox*&, int& caretOffset) const;
static bool hasRenderedNonAnonymousDescendantsWithHeight(RenderObject*);
static bool nodeIsUserSelectNone(Node*);
......
......@@ -551,9 +551,7 @@ void DeleteSelectionCommand::mergeParagraphs()
// The rule for merging into an empty block is: only do so if its farther to the right.
// FIXME: Consider RTL.
// FIXME: handleSpecialCaseBRDelete prevents us from getting here in a case like <ul><li>foo<br><br></li></ul>^foo
if (isStartOfParagraph(mergeDestination) &&
startOfParagraphToMove.deepEquivalent().node()->renderer()->caretRect(startOfParagraphToMove.deepEquivalent().offset()).location().x() >
mergeDestination.deepEquivalent().node()->renderer()->caretRect(startOfParagraphToMove.deepEquivalent().offset()).location().x()) {
if (isStartOfParagraph(mergeDestination) && startOfParagraphToMove.caretRect().x() > mergeDestination.caretRect().x()) {
ASSERT(mergeDestination.deepEquivalent().downstream().node()->hasTagName(brTag));
removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().node());
m_endingPosition = startOfParagraphToMove.deepEquivalent();
......
......@@ -495,14 +495,7 @@ bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranular
// FIXME: Maybe baseline would be better?
static bool caretY(const VisiblePosition &c, int &y)
{
Position p = c.deepEquivalent();
Node *n = p.node();
if (!n)
return false;
RenderObject *r = p.node()->renderer();
if (!r)
return false;
IntRect rect = r->caretRect(p.offset());
IntRect rect = c.caretRect();
if (rect.isEmpty())
return false;
y = rect.y() + rect.height() / 2;
......@@ -627,10 +620,10 @@ int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
return x;
if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
pos = VisiblePosition(pos, m_sel.affinity()).deepEquivalent();
VisiblePosition visiblePosition(pos, m_sel.affinity());
// VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
// after the selection is created and before this function is called.
x = pos.isNotNull() ? pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity()).x() : 0;
x = visiblePosition.isNotNull() ? visiblePosition.caretRect().x() : 0;
m_xPosForVerticalArrowNavigation = x;
}
else
......@@ -683,14 +676,13 @@ void SelectionController::layout()
m_caretPositionOnLayout = IntPoint();
if (isCaret()) {
Position pos = m_sel.start();
pos = VisiblePosition(m_sel.start(), m_sel.affinity()).deepEquivalent();
VisiblePosition pos(m_sel.start(), m_sel.affinity());
if (pos.isNotNull()) {
ASSERT(pos.node()->renderer());
m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity());
ASSERT(pos.deepEquivalent().node()->renderer()