WebCore:
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Apr 2008 19:09:48 +0000 (19:09 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Apr 2008 19:09:48 +0000 (19:09 +0000)
        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: https://svn.webkit.org/repository/webkit/trunk@32508 268f45cc-cd09-0410-ab3c-d52691b4dbfc

40 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/editing/input/caret-primary-bidi-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/editing/input/caret-primary-bidi.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/dom/Position.cpp
WebCore/dom/Position.h
WebCore/editing/DeleteSelectionCommand.cpp
WebCore/editing/SelectionController.cpp
WebCore/editing/VisiblePosition.cpp
WebCore/editing/VisiblePosition.h
WebCore/editing/visible_units.cpp
WebCore/page/AccessibilityObject.cpp
WebCore/page/Frame.cpp
WebCore/rendering/InlineBox.cpp
WebCore/rendering/InlineBox.h
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/RenderBR.cpp
WebCore/rendering/RenderBR.h
WebCore/rendering/RenderBox.cpp
WebCore/rendering/RenderBox.h
WebCore/rendering/RenderFlow.cpp
WebCore/rendering/RenderFlow.h
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RenderReplaced.cpp
WebCore/rendering/RenderReplaced.h
WebCore/rendering/RenderSVGInlineText.cpp
WebCore/rendering/RenderSVGInlineText.h
WebCore/rendering/RenderText.cpp
WebCore/rendering/RenderText.h
WebCore/rendering/RenderTextControl.cpp
WebCore/rendering/RenderTreeAsText.cpp
WebCore/rendering/SVGInlineTextBox.cpp
WebCore/rendering/SVGRenderTreeAsText.cpp
WebCore/rendering/SVGRootInlineBox.cpp
WebCore/rendering/bidi.cpp
WebCore/svg/SVGTextContentElement.cpp
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebFrame.mm

index 0691a20..09b8953 100644 (file)
@@ -1,3 +1,12 @@
+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.
diff --git a/LayoutTests/platform/mac/editing/input/caret-primary-bidi-expected.txt b/LayoutTests/platform/mac/editing/input/caret-primary-bidi-expected.txt
new file mode 100644 (file)
index 0000000..c3a9eb0
--- /dev/null
@@ -0,0 +1,87 @@
+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
+
diff --git a/LayoutTests/platform/mac/editing/input/caret-primary-bidi.html b/LayoutTests/platform/mac/editing/input/caret-primary-bidi.html
new file mode 100644 (file)
index 0000000..1e9000b
--- /dev/null
@@ -0,0 +1,42 @@
+<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>
index 72e4afb..747d41e 100644 (file)
@@ -1,3 +1,176 @@
+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.
index ad3d112..72279a2 100644 (file)
@@ -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
index 4d0b311..b489d0c 100644 (file)
@@ -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())
index 6641b20..2624238 100644 (file)
@@ -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*);
     
index e4060da..e2645b7 100644 (file)
@@ -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();
index cd6286a..6f46571 100644 (file)
@@ -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());
+            m_caretRect = pos.caretRect();
+
             int x, y;
-            pos.node()->renderer()->absolutePositionForContent(x, y);
+            pos.deepEquivalent().node()->renderer()->absolutePositionForContent(x, y);
             m_caretPositionOnLayout = IntPoint(x, y);
         }
     }
index 0d6bee6..b2481c9 100644 (file)
@@ -242,10 +242,22 @@ UChar VisiblePosition::characterAfter() const
 
 IntRect VisiblePosition::caretRect() const
 {
-    if (!m_deepPosition.node() || !m_deepPosition.node()->renderer())
+    Node* node = m_deepPosition.node();
+    if (!node)
+        return IntRect();
+
+    RenderObject* renderer = node->renderer();
+    if (!renderer)
         return IntRect();
 
-    return m_deepPosition.node()->renderer()->caretRect(m_deepPosition.offset(), m_affinity);
+    InlineBox* inlineBox;
+    int caretOffset;
+    getInlineBoxAndOffset(inlineBox, caretOffset);
+
+    if (inlineBox)
+        renderer = inlineBox->object();
+
+    return renderer->caretRect(inlineBox, caretOffset);
 }
 
 void VisiblePosition::debugPosition(const char* msg) const
index b6a8eb4..64b9d44 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "Node.h"
 #include "Position.h"
+#include "TextDirection.h"
 
 namespace WebCore {
 
@@ -44,6 +45,8 @@ namespace WebCore {
 // position is not at a line break.
 #define VP_UPSTREAM_IF_POSSIBLE UPSTREAM
 
+class InlineBox;
+
 class VisiblePosition {
 public:
     // NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
@@ -74,6 +77,16 @@ public:
     
     Element* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.node()->rootEditableElement() : 0; }
     
+    void getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
+    {
+        m_deepPosition.getInlineBoxAndOffset(m_affinity, inlineBox, caretOffset);
+    }
+
+    void getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
+    {
+        m_deepPosition.getInlineBoxAndOffset(m_affinity, primaryDirection, inlineBox, caretOffset);
+    }
+
     IntRect caretRect() const;
 
 #ifndef NDEBUG
@@ -84,7 +97,7 @@ public:
 private:
     void init(const Position&, EAffinity);
     Position canonicalPosition(const Position&);
-        
+
     Position m_deepPosition;
     EAffinity m_affinity;
 };
index 2a280fa..4151427 100644 (file)
@@ -257,12 +257,12 @@ static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
     RenderObject *renderer = node->renderer();
     if (!renderer)
         return 0;
+
+    InlineBox* box;
+    int offset;
+    c.getInlineBoxAndOffset(box, offset);
     
-    InlineBox *box = renderer->inlineBox(p.offset(), c.affinity());
-    if (!box)
-        return 0;
-    
-    return box->root();
+    return box ? box->root() : 0;
 }
 
 static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
@@ -279,7 +279,7 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c)
 {
     if (c.isNull())
         return VisiblePosition();
-        
+
     RootInlineBox *rootBox = rootBoxForLine(c);
     if (!rootBox) {
         // There are VisiblePositions at offset 0 in blocks without
@@ -347,7 +347,7 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c)
 {
     if (c.isNull())
         return VisiblePosition();
-        
+
     RootInlineBox *rootBox = rootBoxForLine(c);
     if (!rootBox) {
         // There are VisiblePositions at offset 0 in blocks without
@@ -441,7 +441,9 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
 
     RenderBlock *containingBlock = 0;
     RootInlineBox *root = 0;
-    InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
+    InlineBox* box;
+    int ignoredCaretOffset;
+    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
     if (box) {
         root = box->root()->prevRootBox();
         if (root)
@@ -462,7 +464,8 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
             Position pos(n, caretMinOffset(n));
             if (pos.isCandidate()) {
                 ASSERT(n->renderer());
-                box = n->renderer()->inlineBox(caretMaxOffset(n));
+                Position maxPos(n, caretMaxOffset(n));
+                maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
                 if (box) {
                     // previous root line box found
                     root = box->root();
@@ -511,7 +514,9 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
 
     RenderBlock *containingBlock = 0;
     RootInlineBox *root = 0;
-    InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
+    InlineBox* box;
+    int ignoredCaretOffset;
+    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
     if (box) {
         root = box->root()->nextRootBox();
         if (root)
@@ -532,7 +537,7 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
             Position pos(n, caretMinOffset(n));
             if (pos.isCandidate()) {
                 ASSERT(n->renderer());
-                box = n->renderer()->inlineBox(caretMinOffset(n));
+                pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
                 if (box) {
                     // next root line box found
                     root = box->root();
index a51e3e2..76616c3 100644 (file)
@@ -991,7 +991,12 @@ static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition
         if (!p.node())
             break;
         renderer = p.node()->renderer();
-        if (!renderer || renderer->inlineBox(p.offset(), tempPosition.affinity()) || (renderer->isRenderBlock() && p.offset() == 0))
+        if (!renderer || renderer->isRenderBlock() && !p.offset())
+            break;
+        InlineBox* box;
+        int ignoredCaretOffset;
+        p.getInlineBoxAndOffset(tempPosition.affinity(), box, ignoredCaretOffset);
+        if (box)
             break;
         startPosition = tempPosition;
     }
index 3fa1edd..8f7dfce 100644 (file)
@@ -278,11 +278,16 @@ IntRect Frame::firstRectForRange(Range* range) const
     ExceptionCode ec = 0;
     ASSERT(range->startContainer(ec));
     ASSERT(range->endContainer(ec));
-    IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(range->startOffset(ec), DOWNSTREAM, &extraWidthToEndOfLine);
-    ASSERT(!ec);
-    IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(range->endOffset(ec), UPSTREAM);
-    ASSERT(!ec);
-    
+    InlineBox* startInlineBox;
+    int startCaretOffset;
+    range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
+    IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
+
+    InlineBox* endInlineBox;
+    int endCaretOffset;
+    range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
+    IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(endInlineBox, endCaretOffset);
+
     if (startCaretRect.y() == endCaretRect.y()) {
         // start and end are on the same line
         return IntRect(min(startCaretRect.x(), endCaretRect.x()), 
index b74d862..5dc1f47 100644 (file)
@@ -86,12 +86,12 @@ void InlineBox::showTreeForThis() const
 
 int InlineBox::caretMinOffset() const 
 { 
-    return 0
+    return m_object->caretMinOffset()
 }
 
 int InlineBox::caretMaxOffset() const 
 { 
-    return 1
+    return m_object->caretMaxOffset()
 }
 
 unsigned InlineBox::caretMaxRenderedOffset() const 
index e51ed9b..48aab77 100644 (file)
@@ -22,6 +22,7 @@
 #define InlineBox_h
 
 #include "RenderObject.h" // needed for RenderObject::PaintInfo
+#include "TextDirection.h"
 
 namespace WebCore {
 
@@ -46,6 +47,7 @@ public:
         , m_parent(0)
         , m_firstLine(false)
         , m_constructed(false)
+        , m_bidiEmbeddingLevel(0)
         , m_dirty(false)
         , m_extracted(false)
         , m_includeLeftEdge(false)
@@ -54,7 +56,7 @@ public:
         , m_endsWithBreak(false)
         , m_hasSelectedChildren(false)
         , m_hasEllipsisBox(false)
-        , m_reversed(false)
+        , m_dirOverride(false)
         , m_treatAsText(true)
         , m_determinedIfNextOnLineExists(false)
         , m_determinedIfPrevOnLineExists(false)
@@ -80,6 +82,7 @@ public:
         , m_parent(parent)
         , m_firstLine(firstLine)
         , m_constructed(constructed)
+        , m_bidiEmbeddingLevel(0)
         , m_dirty(dirty)
         , m_extracted(extracted)
         , m_includeLeftEdge(false)
@@ -88,7 +91,7 @@ public:
         , m_endsWithBreak(false)
         , m_hasSelectedChildren(false)   
         , m_hasEllipsisBox(false)
-        , m_reversed(false)
+        , m_dirOverride(false)
         , m_treatAsText(true)
         , m_determinedIfNextOnLineExists(false)
         , m_determinedIfPrevOnLineExists(false)
@@ -211,7 +214,13 @@ public:
     virtual int caretMinOffset() const;
     virtual int caretMaxOffset() const;
     virtual unsigned caretMaxRenderedOffset() const;
-    
+
+    unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; }
+    void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; }
+    TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; }
+    int caretLeftmostOffset() const { return direction() == LTR ? caretMinOffset() : caretMaxOffset(); }
+    int caretRightmostOffset() const { return direction() == LTR ? caretMaxOffset() : caretMinOffset(); }
+
     virtual void clearTruncation() { }
 
     bool isDirty() const { return m_dirty; }
@@ -250,6 +259,7 @@ protected:
     bool m_firstLine : 1;
 private:
     bool m_constructed : 1;
+    unsigned char m_bidiEmbeddingLevel : 6;
 protected:
     bool m_dirty : 1;
     bool m_extracted : 1;
@@ -266,7 +276,6 @@ protected:
 
     // for InlineTextBox
 public:
-    bool m_reversed : 1;
     bool m_dirOverride : 1;
     bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height.
 protected:
index fcdd045..a79feeb 100644 (file)
@@ -97,7 +97,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
     int selHeight = selectionHeight();
     const Font& f = textObj->style(m_firstLine)->font();
 
-    IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(textObj->text()->characters() + m_start, m_len, textObj->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride),
+    IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(textObj->text()->characters() + m_start, m_len, textObj->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
                                                         IntPoint(tx + m_x, ty + selTop), selHeight, sPos, ePos));
     if (r.x() > tx + m_x + m_width)
         r.setWidth(0);
@@ -147,7 +147,7 @@ int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth,
         }
 
         if (ellipsisX < m_x + m_width) {
-            if (m_reversed)
+            if (direction() == RTL)
                 return -1; // FIXME: Support LTR truncation when the last run is RTL someday.
 
             foundBox = true;
@@ -385,7 +385,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         int endPoint = m_len;
         if (m_truncation != cNoTruncation)
             endPoint = m_truncation;
-        paintInfo.context->drawText(TextRun(textStr->characters() + m_start, endPoint, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || styleToUse->visuallyOrdered()),
+        paintInfo.context->drawText(TextRun(textStr->characters() + m_start, endPoint, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
                                     IntPoint(m_x + tx, m_y + ty + m_baseline));
     } else {
         int sPos, ePos;
@@ -393,14 +393,14 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         if (paintSelectedTextSeparately) {
             // paint only the text that is not selected
             if (sPos >= ePos)
-                paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || styleToUse->visuallyOrdered()),
+                paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
                                             IntPoint(m_x + tx, m_y + ty + m_baseline));
             else {
                 if (sPos - 1 >= 0)
-                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || styleToUse->visuallyOrdered()),
+                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
                                                 IntPoint(m_x + tx, m_y + ty + m_baseline),  0, sPos);
                 if (ePos < m_start + m_len)
-                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || styleToUse->visuallyOrdered()),
+                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
                                                 IntPoint(m_x + tx, m_y + ty + m_baseline), ePos);
             }
         }
@@ -415,7 +415,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
             if (selectionTextShadow)
                 paintInfo.context->setShadow(IntSize(selectionTextShadow->x, selectionTextShadow->y),
                                              selectionTextShadow->blur, selectionTextShadow->color);
-            paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || styleToUse->visuallyOrdered()),
+            paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
                                         IntPoint(m_x + tx, m_y + ty + m_baseline), sPos, ePos);
             if (selectionTextShadow)
                 paintInfo.context->clearShadow();
@@ -508,7 +508,7 @@ void InlineTextBox::paintSelection(GraphicsContext* p, int tx, int ty, RenderSty
     int y = selectionTop();
     int h = selectionHeight();
     p->clip(IntRect(m_x + tx, y + ty, m_width, h));
-    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered()),
+    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                             IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
     p->restore();
 }
@@ -530,7 +530,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* p, int tx, int t
 
     int y = selectionTop();
     int h = selectionHeight();
-    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered()),
+    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                             IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
     p->restore();
 }
@@ -629,7 +629,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
         IntPoint startPoint = IntPoint(m_x + tx, y + ty);
         int startPosition = max(marker.startOffset - m_start, (unsigned)0);
         int endPosition = min(marker.endOffset - m_start, (unsigned)m_len);    
-        TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered());
+        TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
         IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, startPoint, selectionHeight(), startPosition, endPosition));
         object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect);
     }
@@ -662,7 +662,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do
     
     int sPos = max(marker.startOffset - m_start, (unsigned)0);
     int ePos = min(marker.endOffset - m_start, (unsigned)m_len);    
-    TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered());
+    TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
     IntPoint startPoint = IntPoint(m_x + tx, y + ty);
     
     // Always compute and store the rect associated with this marker
@@ -801,7 +801,7 @@ int InlineTextBox::textPos() const
         return 0;
         
     RenderBlock *blockElement = object()->containingBlock();
-    return m_reversed ? xPos() - blockElement->borderRight() - blockElement->paddingRight()
+    return direction() == RTL ? xPos() - blockElement->borderRight() - blockElement->paddingRight()
                       : xPos() - blockElement->borderLeft() - blockElement->paddingLeft();
 }
 
@@ -813,7 +813,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
     RenderText* text = static_cast<RenderText*>(m_object);
     RenderStyle *style = text->style(m_firstLine);
     const Font* f = &style->font();
-    return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered()),
+    return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                                 _x - m_x, includePartialGlyphs);
 }
 
@@ -824,10 +824,10 @@ int InlineTextBox::positionForOffset(int offset) const
 
     RenderText* text = static_cast<RenderText*>(m_object);
     const Font& f = text->style(m_firstLine)->font();
-    int from = m_reversed ? offset - m_start : 0;
-    int to = m_reversed ? m_len : offset - m_start;
+    int from = direction() == RTL ? offset - m_start : 0;
+    int to = direction() == RTL ? m_len : offset - m_start;
     // FIXME: Do we need to add rightBearing here?
-    return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, m_reversed, m_dirOverride),
+    return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
                                                    IntPoint(m_x, 0), 0, from, to)).right();
 }
 
index a8290e4..03a6a18 100644 (file)
@@ -108,9 +108,4 @@ VisiblePosition RenderBR::positionForCoordinates(int /*x*/, int /*y*/)
     return VisiblePosition(element(), 0, DOWNSTREAM);
 }
 
-InlineBox* RenderBR::inlineBox(int /*offset*/, EAffinity /*affinity*/)
-{
-    return firstTextBox();
-}
-
 } // namespace WebCore
index c5ce42b..b5bdb2f 100644 (file)
@@ -60,8 +60,6 @@ public:
 
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
-    virtual InlineBox* inlineBox(int offset, EAffinity = UPSTREAM);
-
 private:
     mutable short m_lineHeight;
 };
index 81500b4..8c16fcc 100644 (file)
@@ -2522,7 +2522,7 @@ void RenderBox::calcAbsoluteVerticalReplaced()
     m_y = topValue + m_marginTop + containerBlock->borderTop();
 }
 
-IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
+IntRect RenderBox::caretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
 {
     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
     // those containers (tables and select elements) or b) refer to the position inside an empty block.
@@ -2532,9 +2532,12 @@ IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEn
     // FIXME: What about border and padding?
     const int caretWidth = 1;
     IntRect rect(xPos(), yPos(), caretWidth, m_height);
-    if (offset)
+    TextDirection direction = box ? box->direction() : style()->direction();
+
+    if ((!caretOffset) ^ (direction == LTR))
         rect.move(IntSize(m_width - caretWidth, 0));
-    if (InlineBox* box = inlineBoxWrapper()) {
+
+    if (box) {
         RootInlineBox* rootBox = box->root();
         int top = rootBox->topOverflow();
         rect.setY(top);
index fcf4dcd..a71f7d4 100644 (file)
@@ -139,7 +139,7 @@ public:
 
     virtual RenderLayer* layer() const { return m_layer; }
 
-    virtual IntRect caretRect(int offset, EAffinity = UPSTREAM, int* extraWidthToEndOfLine = 0);
+    virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
 
     virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight,
                                         int tx, int ty, int width, int height, InlineFlowBox* = 0);
index 60f69a5..9e9ce5a 100644 (file)
@@ -620,11 +620,11 @@ int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf)
     return left;
 }
 
-IntRect RenderFlow::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
+IntRect RenderFlow::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
 {
     // Do the normal calculation in most cases.
     if (firstChild() || style()->display() == INLINE)
-        return RenderContainer::caretRect(offset, affinity, extraWidthToEndOfLine);
+        return RenderContainer::caretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
 
     // This is a special case:
     // The element is not an inline element, and it's empty. So we have to
index d59c4c9..dbf057f 100644 (file)
@@ -93,7 +93,7 @@ public:
     virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
     virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
 
-    virtual IntRect caretRect(int offset, EAffinity = UPSTREAM, int* extraWidthToEndOfLine = 0);
+    virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
 
     virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
     void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine);
index 006d68d..8b1fb44 100644 (file)
@@ -2344,7 +2344,7 @@ bool RenderObject::absolutePosition(int& xPos, int& yPos, bool f) const
     }
 }
 
-IntRect RenderObject::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
+IntRect RenderObject::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
 {
    if (extraWidthToEndOfLine)
        *extraWidthToEndOfLine = 0;
@@ -2955,7 +2955,7 @@ int RenderObject::caretMinOffset() const
 
 int RenderObject::caretMaxOffset() const
 {
-    return isReplaced() ? 1 : 0;
+    return isReplaced() ? (element() ? max(1U, element()->childNodeCount()) : 1) : 0;
 }
 
 unsigned RenderObject::caretMaxRenderedOffset() const
@@ -2973,11 +2973,6 @@ int RenderObject::nextOffset(int current) const
     return current + 1;
 }
 
-InlineBox* RenderObject::inlineBox(int offset, EAffinity affinity)
-{
-    return inlineBoxWrapper();
-}
-
 int RenderObject::maxTopMargin(bool positive) const
 {
     return positive ? max(0, marginTop()) : -min(0, marginTop());
index a208816..35f35dc 100644 (file)
@@ -433,8 +433,6 @@ public:
     virtual void setInlineBoxWrapper(InlineBox*);
     virtual void deleteLineBoxWrapper();
 
-    virtual InlineBox* inlineBox(int offset = 0, EAffinity = UPSTREAM);
-
     // for discussion of lineHeight see CSS2 spec
     virtual short lineHeight(bool firstLine, bool isRootLineBox = false) const;
     // for the vertical-align property of inline elements
@@ -832,7 +830,7 @@ public:
      * @param extraWidthToEndOfLine optional out arg to give extra width to end of line -
      * useful for character range rect computations
      */
-    virtual IntRect caretRect(int offset, EAffinity = UPSTREAM, int* extraWidthToEndOfLine = 0);
+    virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
 
     virtual int lowestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; }
     virtual int rightmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; }
index a6b13e4..91e90f4 100644 (file)
@@ -196,20 +196,6 @@ short RenderReplaced::baselinePosition(bool, bool) const
     return height() + marginTop() + marginBottom();
 }
 
-int RenderReplaced::caretMinOffset() const 
-{ 
-    return 0; 
-}
-
-// Returns 1 since a replaced element can have the caret positioned 
-// at its beginning (0), or at its end (1).
-// NOTE: Yet, "select" elements can have any number of "option" elements
-// as children, so this "0 or 1" idea does not really hold up.
-int RenderReplaced::caretMaxOffset() const 
-{ 
-    return 1; 
-}
-
 unsigned RenderReplaced::caretMaxRenderedOffset() const
 {
     return 1; 
index f7c8056..c124fc5 100644 (file)
@@ -55,8 +55,6 @@ public:
     virtual int overflowTop(bool includeInterior = true) const;
     virtual IntRect overflowRect(bool includeInterior = true) const;
 
-    virtual int caretMinOffset() const;
-    virtual int caretMaxOffset() const;
     virtual unsigned caretMaxRenderedOffset() const;
     virtual VisiblePosition positionForCoordinates(int x, int y);
     
index 36eb128..ee8f9fe 100644 (file)
@@ -122,7 +122,7 @@ InlineTextBox* RenderSVGInlineText::createInlineTextBox()
     return new (renderArena()) SVGInlineTextBox(this);
 }
 
-IntRect RenderSVGInlineText::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
+IntRect RenderSVGInlineText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
 {
     // SVG doesn't have any editable content where a caret rect would be needed
     return IntRect();
@@ -146,7 +146,7 @@ VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y)
     for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) {
         if (box->svgCharacterHitsPosition(x + object->xPos(), y + object->yPos(), offset)) {
             // If we're not at the end/start of the box, stop looking for other selected boxes.
-            if (!box->m_reversed) {
+            if (box->direction() == LTR) {
                 if (offset <= (int) box->end() + 1)
                     break;
             } else {
index 7bb93ca..316e870 100644 (file)
@@ -39,7 +39,7 @@ public:
     virtual bool isSVGText() const { return true; }
     virtual InlineTextBox* createInlineTextBox();
 
-    virtual IntRect caretRect(int offset, EAffinity, int* extraWidthToEndOfLine = 0);
+    virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
 private:
index e767e37..b506c6f 100644 (file)
@@ -324,43 +324,21 @@ VisiblePosition RenderText::positionForCoordinates(int x, int y)
     return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM);
 }
 
-static inline bool atLineWrap(InlineTextBox* box, int offset)
+IntRect RenderText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
 {
-    return box->nextTextBox() && !box->nextOnLine() && offset == box->m_start + box->m_len;
-}
-
-IntRect RenderText::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
-{
-    if (!firstTextBox() || !textLength())
+    if (!inlineBox)
         return IntRect();
 
-    // Find the text box for the given offset
-    InlineTextBox* box = 0;
-    for (box = firstTextBox(); box; box = box->nextTextBox()) {
-        if (box->containsCaretOffset(offset)) {
-            // Check if downstream affinity would make us move to the next line.
-            if (atLineWrap(box, offset) && affinity == DOWNSTREAM) {
-                // Use the next text box
-                box = box->nextTextBox();
-                offset = box->m_start;
-            } else {
-                InlineTextBox* prevBox = box->prevTextBox();
-                if (offset == box->m_start && affinity == UPSTREAM && prevBox && !box->prevOnLine()) {
-                    box = prevBox;
-                    offset = box->m_start + box->m_len;
-                }
-            }
-            break;
-        }
-    }
-
-    if (!box)
+    ASSERT(inlineBox->isInlineTextBox());
+    if (!inlineBox->isInlineTextBox())
         return IntRect();
 
+    InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
+
     int height = box->root()->bottomOverflow() - box->root()->topOverflow();
     int top = box->root()->topOverflow();
 
-    int left = box->positionForOffset(offset);
+    int left = box->positionForOffset(caretOffset);
 
     int rootLeft = box->root()->xPos();
     // FIXME: should we use the width of the root inline box or the
@@ -376,7 +354,7 @@ IntRect RenderText::caretRect(int offset, EAffinity affinity, int* extraWidthToE
     RenderBlock* cb = containingBlock();
     if (style()->autoWrap()) {
         int availableWidth = cb->lineWidth(top);
-        if (!box->m_reversed)
+        if (box->direction() == LTR)
             left = min(left, absx + rootLeft + availableWidth - 1);
         else
             left = max(left, absx + rootLeft);
@@ -1005,7 +983,7 @@ void RenderText::position(InlineBox* box)
         return;
     }
 
-    m_containsReversedText |= s->m_reversed;
+    m_containsReversedText |= s->direction() == RTL;
 }
 
 unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bool firstLine) const
@@ -1171,24 +1149,6 @@ int RenderText::nextOffset(int current) const
     return result;
 }
 
-InlineBox* RenderText::inlineBox(int offset, EAffinity affinity)
-{
-    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
-        if (box->containsCaretOffset(offset)) {
-            if (atLineWrap(box, offset) && affinity == DOWNSTREAM)
-                return box->nextTextBox();
-            return box;
-        }
-        if (offset < box->m_start)
-            // The offset we're looking for is before this node
-            // this means the offset must be in content that is
-            // not rendered.
-            return box->prevTextBox() ? box->prevTextBox() : firstTextBox();
-    }
-
-    return 0;
-}
-
 #ifndef NDEBUG
 
 void RenderText::checkConsistency() const
index 2f77c90..14faa91 100644 (file)
@@ -105,7 +105,7 @@ public:
     virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); }
     virtual void setSelectionState(SelectionState s);
     virtual IntRect selectionRect(bool clipToVisibleContent = true);
-    virtual IntRect caretRect(int offset, EAffinity, int* extraWidthToEndOfLine = 0);
+    virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
 
     virtual int marginLeft() const { return style()->marginLeft().calcMinValue(0); }
     virtual int marginRight() const { return style()->marginRight().calcMinValue(0); }
@@ -115,8 +115,6 @@ public:
     InlineTextBox* firstTextBox() const { return m_firstTextBox; }
     InlineTextBox* lastTextBox() const { return m_lastTextBox; }
 
-    virtual InlineBox* inlineBox(int offset, EAffinity = UPSTREAM);
-
     virtual int caretMinOffset() const;
     virtual int caretMaxOffset() const;
     virtual unsigned caretMaxRenderedOffset() const;
index 8cb9e90..a660c9a 100644 (file)
@@ -631,7 +631,7 @@ String RenderTextControl::textWithHardLineBreaks()
     if (!renderer)
         return "";
 
-    InlineBox* box = renderer->inlineBox(0, DOWNSTREAM);
+    InlineBox* box = renderer->isText() ? static_cast<RenderText*>(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
     if (!box)
         return "";
 
index 99ba6a9..dd5ebf7 100644 (file)
@@ -305,8 +305,8 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o)
 static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run)
 {
     ts << "text run at (" << run.m_x << "," << run.m_y << ") width " << run.m_width;
-    if (run.m_reversed || run.m_dirOverride) {
-        ts << (run.m_reversed ? " RTL" : " LTR");
+    if (run.direction() == RTL || run.m_dirOverride) {
+        ts << (run.direction() == RTL ? " RTL" : " LTR");
         if (run.m_dirOverride)
             ts << " override";
     }
index 96fd835..ceb7b0e 100644 (file)
@@ -99,7 +99,7 @@ FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int off
     // FIXME: account for multi-character glyphs
     int charsConsumed;
     String glyphName;
-    if (!m_reversed)
+    if (direction() == LTR)
         glyphWidth = calculateGlyphWidth(style, offset, 0, charsConsumed, glyphName);
     else
         glyphWidth = calculateGlyphWidth(style, start() + end() - offset, 0, charsConsumed, glyphName);
@@ -148,7 +148,7 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker {
 
             // Take RTL text into account and pick right glyph width/height.
             // NOTE: This offset has to be corrected _after_ calling calculateGlyphBoundaries
-            if (textBox->m_reversed)
+            if (textBox->direction() == RTL)
                 newOffset = textBox->start() + textBox->end() - newOffset;
 
             // Calculate distances relative to the glyph mid-point. I hope this is accurate enough.
@@ -248,7 +248,7 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
     RenderStyle* style = textObject()->style(m_firstLine);
     FloatRect glyphRect = calculateGlyphBoundaries(style, offset, charAtPos);
 
-    if (m_reversed)
+    if (direction() == RTL)
         offset++;
 
     // FIXME: todo list
@@ -260,9 +260,9 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
 
     // Check whether x position hits the current character
     if (x < charAtPos.x) {
-        if (offset > 0 && !m_reversed)
+        if (offset > 0 && direction() == LTR)
             return true;
-        else if (offset < (int) end() && m_reversed)
+        else if (offset < (int) end() && direction() == RTL)
             return true;
 
         return false;
@@ -274,7 +274,7 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
 
     // Snap to character at half of it's advance
     if (x >= charAtPos.x + glyphRect.width() / 2.0)
-        offset += m_reversed ? -1 : 1;
+        offset += direction() == RTL ? -1 : 1;
 
     return true;
 }
index 4c13dc9..d3e029c 100644 (file)
@@ -423,8 +423,8 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB
             else
                 ts << " width " << cummulatedWidthOfInlineBoxCharacterRange(range);
 
-            if (textBox->m_reversed || textBox->m_dirOverride) {
-                ts << (textBox->m_reversed ? " RTL" : " LTR");
+            if (textBox->direction() == RTL || textBox->m_dirOverride) {
+                ts << (textBox->direction() == RTL ? " RTL" : " LTR");
 
                 if (textBox->m_dirOverride)
                     ts << " override";
index ca60ba7..f5575da 100644 (file)
@@ -648,7 +648,7 @@ TextRun svgTextRunForInlineTextBox(const UChar* c, int len, RenderStyle* style,
     ASSERT(textBox);
     ASSERT(style);
 
-    TextRun run(c, len, false, static_cast<int>(xPos), textBox->toAdd(), textBox->m_reversed, textBox->m_dirOverride || style->visuallyOrdered());
+    TextRun run(c, len, false, static_cast<int>(xPos), textBox->toAdd(), textBox->direction() == RTL, textBox->m_dirOverride || style->visuallyOrdered());
 
 #if ENABLE(SVG_FONTS)
     run.setReferencingRenderObject(textBox->textObject()->parent());
@@ -709,7 +709,7 @@ static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWi
                 SVGChar& lastCharacter = *(itSearch - 1);
                 SVGChar& currentCharacter = *itSearch;
 
-                int offset = box->m_reversed ? box->end() - i - positionOffset + 1 : box->start() + i + positionOffset - 1;
+                int offset = box->direction() == RTL ? box->end() - i - positionOffset + 1 : box->start() + i + positionOffset - 1;
 
                 // FIXME: does this need to change to handle multichar glyphs?
                 int charsConsumed = 1;
@@ -1130,7 +1130,7 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
 
         String unicodeStr;
         String glyphName;
-        if (textBox->m_reversed) {
+        if (textBox->direction() == RTL) {
             glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed, glyphName);
             glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable);
             unicodeStr = String(textBox->textObject()->text()->characters() + textBox->end() - i, charsConsumed);
@@ -1189,10 +1189,10 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
         // Take letter & word spacing and kerning into account
         float spacing = font.letterSpacing() + calculateKerning(textBox->object()->element()->renderer());
 
-        const UChar* currentCharacter = text->characters() + (textBox->m_reversed ? textBox->end() - i : textBox->start() + i);
+        const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i);
         const UChar* lastCharacter = 0;
 
-        if (textBox->m_reversed) {
+        if (textBox->direction() == RTL) {
             if (i < textBox->end())
                 lastCharacter = text->characters() + textBox->end() - i +  1;
         } else {
index f14ec70..392316d 100644 (file)
@@ -518,9 +518,11 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
         bool isOnlyRun = (runCount == 1);
         if (runCount == 2 && !r->m_object->isListMarker())
             isOnlyRun = ((style()->direction() == RTL) ? lastRun : firstRun)->m_object->isListMarker();
-        r->m_box = r->m_object->createInlineBox(r->m_object->isPositioned(), false, isOnlyRun);
 
-        if (r->m_box) {
+        InlineBox* box = r->m_object->createInlineBox(r->m_object->isPositioned(), false, isOnlyRun);
+        r->m_box = box;
+
+        if (box) {
             // If we have no parent box yet, or if the run is not simply a sibling,
             // then we need to construct inline boxes as necessary to properly enclose the
             // run's inline box.
@@ -529,14 +531,15 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
                 parentBox = createLineBoxes(r->m_object->parent());
 
             // Append the inline box to this line.
-            parentBox->addToLine(r->m_box);
-            
-            if (r->m_box->isInlineTextBox()) {
-                InlineTextBox* text = static_cast<InlineTextBox*>(r->m_box);
+            parentBox->addToLine(box);
+
+            bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
+            box->setBidiLevel(visuallyOrdered ? 0 : r->level());
+
+            if (box->isInlineTextBox()) {
+                InlineTextBox* text = static_cast<InlineTextBox*>(box);
                 text->setStart(r->m_start);
                 text->setLen(r->m_stop - r->m_start);
-                bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
-                text->m_reversed = r->reversed(visuallyOrdered);
                 text->m_dirOverride = r->dirOverride(visuallyOrdered);
             }
         }
index 66f07dd..2ebf4b9 100644 (file)
@@ -74,7 +74,7 @@ static inline float cumulativeCharacterRangeLength(const Vector<SVGChar>::iterat
             unsigned int newOffset = textBox->start() + (it - start) + startOffset;
 
             // Take RTL text into account and pick right glyph width/height.
-            if (textBox->m_reversed)
+            if (textBox->direction() == RTL)
                 newOffset = textBox->start() + textBox->end() - newOffset;
 
             // FIXME: does this handle multichar glyphs ok? not sure
@@ -191,7 +191,7 @@ struct SVGInlineTextBoxQueryWalker {
                     unsigned int newOffset = textBox->start() + (it - start) + startOffset;
 
                     // Take RTL text into account and pick right glyph width/height.
-                    if (textBox->m_reversed)
+                    if (textBox->direction() == RTL)
                         newOffset = textBox->start() + textBox->end() - newOffset;
 
                     int charsConsumed;
index 690d212..61aeeaf 100644 (file)
@@ -1,3 +1,15 @@
+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
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _caretRectAtNode:offset:affinity:]): Changed to use
+        VisiblePosition::caretRect() instead of the RenderObject method which
+        was removed.
+
 2008-04-24  Brady Eidson  <beidson@apple.com>
 
         Reviewed by Darin
index 622ce7b..95d14f4 100644 (file)
@@ -616,7 +616,8 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
 
 - (NSRect)_caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
 {
-    return [node _node]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity));
+    VisiblePosition visiblePosition([node _node], offset, static_cast<EAffinity>(affinity));
+    return visiblePosition.caretRect();
 }
 
 - (NSRect)_firstRectForDOMRange:(DOMRange *)range