Changeset 17276 in webkit


Ignore:
Timestamp:
Oct 24, 2006 6:37:04 PM (18 years ago)
Author:
justing
Message:

LayoutTests:

Reviewed by darin

<http://bugs.webkit.org/show_bug.cgi?id=10993>
GMail Editor: Caret doesn't always position itself after list marker

  • editing/execCommand/create-list-1-expected.checksum: Added.
  • editing/execCommand/create-list-1-expected.png: Added.
  • editing/execCommand/create-list-1-expected.txt: Added.
  • editing/execCommand/create-list-1.html: Added.


Fixed:

  • editing/execCommand/create-list-with-hr-expected.checksum:
  • editing/execCommand/create-list-with-hr-expected.png:
  • editing/execCommand/create-list-with-hr-expected.txt:
  • editing/execCommand/create-list-with-hr.html:
  • editing/execCommand/remove-list-1-expected.checksum:
  • editing/execCommand/remove-list-1-expected.png:
  • editing/execCommand/remove-list-1-expected.txt:
  • fast/text/attributed-substring-from-range-001-expected.txt:

WebCore:

Reviewed by darin

<http://bugs.webkit.org/show_bug.cgi?id=10993>
GMail Editor: Caret doesn't always position itself after list marker


List creation uses moveParagraphs to push content into list items.
moveParagraphs uses a TextIterator to restore selections after moves.
Some characters emitted by the TextIterator had bad ranges associated
with them. rangeFromLocationAndLength would skip past the range it
should have used when asked for ranges of length 0.

  • editing/TextIterator.cpp: (WebCore::TextIterator::TextIterator): No longer need to initialize a removed member variable. (WebCore::TextIterator::advance): An extra newline is emitted when leaving some blocks. Use the same range for this newline as for the first newline. We should remove this code and just emit two '\n's. (WebCore::TextIterator::handleTextNode): Setup m_range. (WebCore::TextIterator::handleTextBox): Ditto. (WebCore::TextIterator::handleReplacedElement): Ditto. (WebCore::TextIterator::handleNonTextNode): Ditto. (WebCore::TextIterator::exitNode): Use an m_range from the last VisiblePosition in the block we're leaving to that VP after that one. (WebCore::TextIterator::emitCharacter): This function now takes in the start and the end of the range associated with the emited character, and sets up m_range. (WebCore::TextIterator::range): Return m_range. If it is null (we are atEnd), return the end of the range used to create the iterator, as a convenience to callers that use call range() on an iterator that is atEnd. (WebCore::SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator): Same as the changes made to TextIterator's constructor. (WebCore::SimplifiedBackwardsTextIterator::advance): Use a null m_range instead of a null m_positionNode to signal that we're finished. (WebCore::SimplifiedBackwardsTextIterator::handleTextNode): Ditto. (WebCore::SimplifiedBackwardsTextIterator::handleReplacedElement): Similar to changes made to TextIterator. (WebCore::SimplifiedBackwardsTextIterator::emitCharacter): Ditto. (WebCore::SimplifiedBackwardsTextIterator::emitNewline): Simplified. (WebCore::SimplifiedBackwardsTextIterator::range): Similar to the changes made to TextIterator::range. (WebCore::CharacterIterator::range): This function assumed that an iterator's range() was safe to modify. (WebCore::TextIterator::rangeFromLocationAndLength): If the range we're looking for starts in the current chunk, this function assumed that if the chunk started in a text node, it would end in the same text node. This is no longer the case. If the range we're looking for starts in the middle of the current chunk, I assume that the chunk is inside a text node, because those are the only chunks with length greater than one at the moment. If the range we're looking for is a zero length range that starts/ends at the end of the current chunk, we used to return the start of the next chunk, but that's wrong and is what caused this bug.
  • editing/TextIterator.h: (WebCore::TextIterator::atEnd): The iterator is atEnd when m_range is null. (WebCore::SimplifiedBackwardsTextIterator::atEnd):
  • editing/visible_units.cpp: (WebCore::previousBoundary): Cleaned up by using a convenience function. (WebCore::nextBoundary): Ditto.
Location:
trunk
Files:
4 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r17234 r17276  
     12006-10-24  Justin Garcia  <justin.garcia@apple.com>
     2
     3        Reviewed by darin
     4
     5        <http://bugs.webkit.org/show_bug.cgi?id=10993>
     6        GMail Editor: Caret doesn't always position itself after list marker
     7
     8        * editing/execCommand/create-list-1-expected.checksum: Added.
     9        * editing/execCommand/create-list-1-expected.png: Added.
     10        * editing/execCommand/create-list-1-expected.txt: Added.
     11        * editing/execCommand/create-list-1.html: Added.
     12       
     13        Fixed:
     14        * editing/execCommand/create-list-with-hr-expected.checksum:
     15        * editing/execCommand/create-list-with-hr-expected.png:
     16        * editing/execCommand/create-list-with-hr-expected.txt:
     17        * editing/execCommand/create-list-with-hr.html:
     18        * editing/execCommand/remove-list-1-expected.checksum:
     19        * editing/execCommand/remove-list-1-expected.png:
     20        * editing/execCommand/remove-list-1-expected.txt:
     21        * fast/text/attributed-substring-from-range-001-expected.txt:
     22       
    1232006-10-23  Justin Garcia  <justin.garcia@apple.com>
    224
  • trunk/LayoutTests/editing/execCommand/create-list-with-hr-expected.checksum

    r16746 r17276  
    1 1a920b25e56e869eaa3be7e22932cd09
     1f557f6e45eb1c0240e2e0e6edfa6b0cc
  • trunk/LayoutTests/editing/execCommand/create-list-with-hr-expected.txt

    r16746 r17276  
    33EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    44EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    5 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 49 of #text > B > P > BODY > HTML > #document to 49 of #text > B > P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     5EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > LI > UL > DIV > BODY > HTML > #document to 0 of DIV > LI > UL > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    66EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    77EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
     
    1111  RenderBlock {HTML} at (0,0) size 800x600
    1212    RenderBody {BODY} at (8,8) size 784x576
    13       RenderBlock {P} at (0,0) size 784x54
     13      RenderBlock {P} at (0,0) size 784x36
    1414        RenderText {#text} at (0,0) size 514x18
    1515          text run at (0,0) width 514: "This test pushes a horizontal rule into an unordered list with InsertUnorderedList. "
     
    1717          RenderText {#text} at (514,0) size 771x36
    1818            text run at (514,0) width 257: "The fact that the horizontal rule is put"
    19             text run at (0,18) width 544: "into an unnecessary div when it's pushed into the list might be considered a bug. "
    20         RenderInline {B} at (0,0) size 726x36
    21           RenderText {#text} at (544,18) size 726x36
    22             text run at (544,18) width 182: "The fact that the caret isn't"
    23             text run at (0,36) width 127: "preserved is a bug."
    24       RenderBlock {DIV} at (0,70) size 784x28
     19            text run at (0,18) width 540: "into an unnecessary div when it's pushed into the list might be considered a bug."
     20      RenderBlock {DIV} at (0,52) size 784x28
    2521        RenderBlock {UL} at (0,0) size 784x28
    2622          RenderListItem {LI} at (40,0) size 744x28
     
    3127            RenderBlock (anonymous) at (0,36) size 744x0
    3228        RenderBlock (anonymous) at (0,44) size 784x0
    33 caret: position 49 of child 0 {#text} of child 2 {B} of child 0 {P} of child 0 {BODY} of child 0 {HTML} of document
     29caret: position 0 of child 0 {HR} of child 0 {DIV} of child 0 {LI} of child 0 {UL} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
  • trunk/LayoutTests/editing/execCommand/create-list-with-hr.html

    r16728 r17276  
    1 <p>This test pushes a horizontal rule into an unordered list with InsertUnorderedList. <b>The fact that the horizontal rule is put into an unnecessary div when it's pushed into the list might be considered a bug. </b><b>The fact that the caret isn't preserved is a bug.</b></p>
     1<p>This test pushes a horizontal rule into an unordered list with InsertUnorderedList. <b>The fact that the horizontal rule is put into an unnecessary div when it's pushed into the list might be considered a bug.</b></p>
    22<div contenteditable="true" id="div"><hr></div>
    33
  • trunk/LayoutTests/editing/execCommand/remove-list-1-expected.checksum

    r17114 r17276  
    1 958726dee6c5c5c73089d158c46f17c5
     12b441a195ceda3a506ff2bb266cbe8a2
  • trunk/LayoutTests/editing/execCommand/remove-list-1-expected.txt

    r17114 r17276  
    55EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of LI > OL > DIV > BODY > HTML > #document to 49 of #text > LI > OL > DIV > BODY > HTML > #document toDOMRange:range from 0 of LI > OL > DIV > BODY > HTML > #document to 49 of #text > LI > OL > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    66EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    7 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     7EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 49 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    88EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    99EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
     
    2424        RenderText {#text} at (0,18) size 322x18
    2525          text run at (0,18) width 322: "There should be a empty paragraph above this one."
    26 caret: position 0 of child 0 {BR} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
     26selection start: position 0 of child 0 {BR} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
     27selection end:   position 49 of child 1 {#text} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
  • trunk/LayoutTests/fast/text/attributed-substring-from-range-001-expected.txt

    r16642 r17276  
    99(1, 1): h{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; }
    1010(1, 5): hello{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; }
    11 (1, 6): hello{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; } {}
    12 (1, 100): hello{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; } {}
    13 (6, 1): {}
     11(1, 6): hello{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; }
     12(1, 100): hello{ NSColor = NSCalibratedWhiteColorSpace 0 1; NSFont = "Times-Roman 16.00 pt. S [] (0xXXXXXXXX) fobj=0xXXXXXXXX, spc=4.00"; }
     13(6, 1):
    1414(7, 1):
    1515(100, 0): undefined
  • trunk/WebCore/ChangeLog

    r17273 r17276  
     12006-10-24  Justin Garcia  <justin.garcia@apple.com>
     2
     3        Reviewed by darin
     4
     5        <http://bugs.webkit.org/show_bug.cgi?id=10993>
     6        GMail Editor: Caret doesn't always position itself after list marker
     7       
     8        List creation uses moveParagraphs to push content into list items. 
     9        moveParagraphs uses a TextIterator to restore selections after moves.
     10        Some characters emitted by the TextIterator had bad ranges associated
     11        with them.  rangeFromLocationAndLength would skip past the range it
     12        should have used when asked for ranges of length 0.
     13
     14        * editing/TextIterator.cpp:
     15        (WebCore::TextIterator::TextIterator): No longer need to initialize a
     16        removed member variable.
     17        (WebCore::TextIterator::advance): An extra newline is emitted when leaving
     18        some blocks.  Use the same range for this newline as for the first newline.
     19        We should remove this code and just emit two '\n's.
     20        (WebCore::TextIterator::handleTextNode): Setup m_range.
     21        (WebCore::TextIterator::handleTextBox): Ditto.
     22        (WebCore::TextIterator::handleReplacedElement): Ditto.
     23        (WebCore::TextIterator::handleNonTextNode): Ditto.
     24        (WebCore::TextIterator::exitNode): Use an m_range from the last VisiblePosition
     25        in the block we're leaving to that VP after that one.
     26        (WebCore::TextIterator::emitCharacter): This function now takes in the start
     27        and the end of the range associated with the emited character, and sets up m_range.
     28        (WebCore::TextIterator::range): Return m_range.  If it is null (we are atEnd),
     29        return the end of the range used to create the iterator, as a convenience to
     30        callers that use call range() on an iterator that is atEnd.
     31        (WebCore::SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator):
     32        Same as the changes made to TextIterator's constructor.
     33        (WebCore::SimplifiedBackwardsTextIterator::advance): Use a null m_range instead of
     34        a null m_positionNode to signal that we're finished.
     35        (WebCore::SimplifiedBackwardsTextIterator::handleTextNode): Ditto.
     36        (WebCore::SimplifiedBackwardsTextIterator::handleReplacedElement): Similar to changes
     37        made to TextIterator.
     38        (WebCore::SimplifiedBackwardsTextIterator::emitCharacter): Ditto.
     39        (WebCore::SimplifiedBackwardsTextIterator::emitNewline): Simplified.
     40        (WebCore::SimplifiedBackwardsTextIterator::range): Similar to the changes made to
     41        TextIterator::range.
     42        (WebCore::CharacterIterator::range): This function assumed that an iterator's
     43        range() was safe to modify.
     44        (WebCore::TextIterator::rangeFromLocationAndLength):
     45        If the range we're looking for starts in the current chunk, this function assumed
     46        that if the chunk started in a text node, it would end in the same text node.  This
     47        is no longer the case.
     48        If the range we're looking for starts in the middle of the current chunk, I assume
     49        that the chunk is inside a text node, because those are the only chunks with length
     50        greater than one at the moment.
     51        If the range we're looking for is a zero length range that starts/ends at the end of the
     52        current chunk, we used to return the start of the next chunk, but that's wrong and
     53        is what caused this bug.
     54        * editing/TextIterator.h:
     55        (WebCore::TextIterator::atEnd): The iterator is atEnd when m_range is null.
     56        (WebCore::SimplifiedBackwardsTextIterator::atEnd):
     57        * editing/visible_units.cpp:
     58        (WebCore::previousBoundary): Cleaned up by using a convenience function.
     59        (WebCore::nextBoundary): Ditto.
     60
    1612006-10-24  Anders Carlsson  <acarlsson@apple.com>
    262
  • trunk/WebCore/editing/TextIterator.cpp

    r16737 r17276  
    7474};
    7575
    76 TextIterator::TextIterator() : m_endContainer(0), m_endOffset(0), m_positionNode(0), m_lastCharacter(0)
    77 {
    78 }
    79 
    80 TextIterator::TextIterator(const Range *r, IteratorKind kind) : m_endContainer(0), m_endOffset(0), m_positionNode(0)
     76TextIterator::TextIterator() : m_endContainer(0), m_endOffset(0), m_lastCharacter(0)
     77{
     78}
     79
     80TextIterator::TextIterator(const Range *r, IteratorKind kind) : m_endContainer(0), m_endOffset(0)
    8181{
    8282    if (!r)
     
    121121
    122122#ifndef NDEBUG
    123     // need this just because of the assert in advance()
    124     m_positionNode = m_node;
     123    // Need this just because of the assert in advance().
     124    m_range = new Range(m_node->document(), Position(m_node, 0), Position(m_node, 0));
    125125#endif
    126126
     
    132132{
    133133    // reset the run information
    134     m_positionNode = 0;
     134    m_range = 0;
    135135    m_textLength = 0;
    136136
    137137    // handle remembered node that needed a newline after the text node's newline
    138138    if (m_needAnotherNewline) {
    139         // emit the newline, with position a collapsed range at the end of current node.
    140         emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);
     139        VisiblePosition lastInNode(Position(m_node, maxDeepOffset(m_node)));
     140        VisiblePosition next = lastInNode.next();
     141        Position start = lastInNode.deepEquivalent();
     142        Position end = next.isNull() ? start : next.deepEquivalent();
     143        emitCharacter('\n', start, end);
    141144        m_needAnotherNewline = false;
    142145        return;
     
    146149    if (m_textBox) {
    147150        handleTextBox();
    148         if (m_positionNode)
     151        if (m_range)
    149152            return;
    150153    }
     
    163166            } else
    164167                m_handledNode = handleNonTextNode();
    165             if (m_positionNode)
     168            if (m_range)
    166169                return;
    167170        }
     
    179182                    m_node = m_node->parentNode();
    180183                    exitNode();
    181                     if (m_positionNode) {
     184                    if (m_range) {
    182185                        m_handledNode = true;
    183186                        m_handledChildren = true;
     
    194197        m_handledChildren = false;
    195198
    196         // how would this ever be?
    197         if (m_positionNode)
     199        // FIXME: How would this ever be?
     200        if (m_range)
    198201            return;
    199202    }
     
    216219        int runStart = m_offset;
    217220        if (m_lastTextNodeEndedWithCollapsedSpace) {
    218             emitCharacter(' ', m_node, 0, runStart, runStart);
     221            emitCharacter(' ', Position(m_node, runStart), Position(m_node, runStart));
    219222            return false;
    220223        }
     
    226229            return true;
    227230
    228         m_positionNode = m_node;
    229         m_positionOffsetBaseNode = 0;
    230         m_positionStartOffset = runStart;
    231         m_positionEndOffset = runEnd;
     231        m_range = new Range(m_node->document(), Position(m_node, runStart), Position(m_node, runEnd));
     232       
    232233        m_textCharacters = str.characters() + runStart;
    233234        m_textLength = runEnd - runStart;
     
    273274            || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0);
    274275        if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter) {
    275             emitCharacter(' ', m_node, 0, runStart, runStart);
     276            emitCharacter(' ', Position(m_node, runStart), Position(m_node, runStart));
    276277            return;
    277278        }
     
    292293            // This effectively translates newlines to spaces without copying the text.
    293294            if (str[runStart] == '\n') {
    294                 emitCharacter(' ', m_node, 0, runStart, runStart + 1);
     295                emitCharacter(' ', Position(m_node, runStart), Position(m_node, runStart + 1));
    295296                m_offset = runStart + 1;
    296297            } else {
     
    301302                m_offset = subrunEnd;
    302303
    303                 m_positionNode = m_node;
    304                 m_positionOffsetBaseNode = 0;
    305                 m_positionStartOffset = runStart;
    306                 m_positionEndOffset = subrunEnd;
     304                m_range = new Range(m_node->document(), Position(m_node, runStart), Position(m_node, subrunEnd));
    307305                m_textCharacters = str.characters() + runStart;
    308306                m_textLength = subrunEnd - runStart;
     
    314312            // If we are doing a subrun that doesn't go to the end of the text box,
    315313            // come back again to finish handling this text box; don't advance to the next one.
    316             if (m_positionEndOffset < textBoxEnd)
     314            ExceptionCode ec;
     315            if (m_range->endOffset(ec) < textBoxEnd)
    317316                return;
    318317
     
    336335{
    337336    if (m_lastTextNodeEndedWithCollapsedSpace) {
    338         emitCharacter(' ', m_lastTextNode->parentNode(), m_lastTextNode, 1, 1);
     337        emitCharacter(' ', positionAfterNode(m_lastTextNode), positionAfterNode(m_lastTextNode));
    339338        return false;
    340339    }
    341340
    342     m_positionNode = m_node->parentNode();
    343     m_positionOffsetBaseNode = m_node;
    344     m_positionStartOffset = 0;
    345     m_positionEndOffset = 1;
     341    m_range = new Range(m_node->document(), positionBeforeNode(m_node), positionAfterNode(m_node));
    346342
    347343    m_textCharacters = 0;
     
    471467{
    472468    if (shouldEmitNewlineForNode(m_node)) {
    473         emitCharacter('\n', m_node->parentNode(), m_node, 0, 1);
     469        Position start = positionBeforeNode(m_node);
     470        VisiblePosition next = VisiblePosition(start).next();
     471        Position end = next.isNull() ? start : next.deepEquivalent();
     472        emitCharacter('\n', start, end);
    474473    } else if (m_lastCharacter != '\n' && m_lastTextNode) {
    475         // only add the tab or newline if not at the start of a line
     474        // Only add the tab or newline if not at the start of a line.
     475        // FIXME: The ranges for these emitted characters should be the part of the
     476        // document that this imaginary character would occupy.
    476477        if (shouldEmitTabBeforeNode(m_node))
    477             emitCharacter('\t', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
     478            emitCharacter('\t', positionBeforeNode(m_lastTextNode), positionAfterNode(m_lastTextNode));
    478479        else if (shouldEmitNewlinesBeforeAndAfterNode(m_node))
    479             emitCharacter('\n', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
     480            emitCharacter('\n', positionBeforeNode(m_lastTextNode), positionAfterNode(m_lastTextNode));
    480481        else if (shouldEmitSpaceBeforeAndAfterNode(m_node))
    481             emitCharacter(' ', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
     482            emitCharacter(' ', positionBeforeNode(m_lastTextNode), positionAfterNode(m_lastTextNode));
    482483    }
    483484
     
    487488void TextIterator::exitNode()
    488489{
     490    VisiblePosition lastInNode(Position(m_node, maxDeepOffset(m_node)));
     491    VisiblePosition next = lastInNode.next();
     492    Position start = lastInNode.deepEquivalent();
     493    Position end = next.isNull() ? start : next.deepEquivalent();
     494   
    489495    if (m_lastTextNode && shouldEmitNewlinesBeforeAndAfterNode(m_node)) {
    490496        // use extra newline to represent margin bottom, as needed
     
    492498       
    493499        if (m_lastCharacter != '\n') {
    494             // insert a newline with a position following this block
    495             emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);
     500
     501            emitCharacter('\n', start, end);
    496502
    497503            // remember whether to later add a newline for the current node
     
    500506        } else if (addNewline) {
    501507            // insert a newline with a position following this block
    502             emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);
     508            emitCharacter('\n', start, end);
    503509        }
    504510    } else if (shouldEmitSpaceBeforeAndAfterNode(m_node))
    505         emitCharacter(' ', m_node->parentNode(), m_node, 1, 1);
    506 }
    507 
    508 void TextIterator::emitCharacter(UChar c, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset)
    509 {
    510     // remember information with which to construct the TextIterator::range()
    511     // NOTE: textNode is often not a text node, so the range will specify child nodes of positionNode
    512     m_positionNode = textNode;
    513     m_positionOffsetBaseNode = offsetBaseNode;
    514     m_positionStartOffset = textStartOffset;
    515     m_positionEndOffset = textEndOffset;
     511        emitCharacter(' ', start, end);
     512}
     513
     514void TextIterator::emitCharacter(UChar c, const Position& start, const Position& end)
     515{
     516    m_range = start.isNull() ? 0 : new Range(start.node()->document(), start, end);
    516517 
    517518    // remember information with which to construct the TextIterator::characters() and length()
     
    527528PassRefPtr<Range> TextIterator::range() const
    528529{
    529     // use the current run information, if we have it
    530     if (m_positionNode) {
    531         if (m_positionOffsetBaseNode) {
    532             int index = m_positionOffsetBaseNode->nodeIndex();
    533             m_positionStartOffset += index;
    534             m_positionEndOffset += index;
    535             m_positionOffsetBaseNode = 0;
    536         }
    537         return new Range(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
    538     }
    539 
    540     // otherwise, return the end of the overall range we were given
     530    if (m_range)
     531        return m_range;
     532       
    541533    if (m_endContainer)
    542534        return new Range(m_endContainer->document(), m_endContainer, m_endOffset, m_endContainer, m_endOffset);
    543        
     535   
    544536    return 0;
    545537}
    546538
    547 SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionNode(0)
     539SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator()
    548540{
    549541}
     
    551543SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range *r)
    552544{
    553     m_positionNode = 0;
    554 
    555545    if (!r)
    556546        return;
     
    593583#ifndef NDEBUG
    594584    // Need this just because of the assert.
    595     m_positionNode = endNode;
     585    m_range = new Range(endNode->document(), Position(endNode, 0), Position(endNode, 0));
    596586#endif
    597587
     
    604594void SimplifiedBackwardsTextIterator::advance()
    605595{
    606     assert(m_positionNode);
    607 
    608     m_positionNode = 0;
     596    assert(m_range);
     597
     598    m_range = 0;
    609599    m_textLength = 0;
    610600
     
    621611            } else
    622612                m_handledNode = handleNonTextNode();
    623             if (m_positionNode)
     613            if (m_range)
    624614                return;
    625615        }
     
    669659        m_handledNode = false;
    670660       
    671         if (m_positionNode)
     661        if (m_range)
    672662            return;
    673663    }
     
    684674        return true;
    685675
    686     m_positionEndOffset = m_offset;
    687 
     676    Position end(m_node, m_offset);
    688677    m_offset = (m_node == m_startNode) ? m_startOffset : 0;
    689     m_positionNode = m_node;
    690     m_positionStartOffset = m_offset;
    691     m_textLength = m_positionEndOffset - m_positionStartOffset;
    692     m_textCharacters = str.characters() + m_positionStartOffset;
    693 
    694     m_lastCharacter = str[m_positionEndOffset - 1];
     678    Position start(m_node, m_offset);
     679    m_range = new Range(m_node->document(), start, end);
     680    m_textLength = end.offset() - start.offset();
     681    m_textCharacters = str.characters() + start.offset();
     682
     683    m_lastCharacter = str[end.offset() - 1];
    695684
    696685    return true;
     
    699688bool SimplifiedBackwardsTextIterator::handleReplacedElement()
    700689{
    701     int offset = m_node->nodeIndex();
    702 
    703     m_positionNode = m_node->parentNode();
    704     m_positionStartOffset = offset;
    705     m_positionEndOffset = offset + 1;
     690    m_range = new Range(m_node->document(), positionBeforeNode(m_node), positionAfterNode(m_node));
    706691
    707692    m_textCharacters = 0;
     
    735720}
    736721
    737 void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, Node *node, int startOffset, int endOffset)
     722void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, const Position& start, const Position& end)
    738723{
    739724    m_singleCharacterBuffer = c;
    740     m_positionNode = node;
    741     m_positionStartOffset = startOffset;
    742     m_positionEndOffset = endOffset;
     725   
     726    m_range = start.isNull() ? 0 : new Range(start.node()->document(), start, end);
     727   
    743728    m_textCharacters = &m_singleCharacterBuffer;
    744729    m_textLength = 1;
     
    748733void SimplifiedBackwardsTextIterator::emitNewline()
    749734{
    750     int offset;
    751    
    752     if (m_lastTextNode) {
    753         offset = m_lastTextNode->nodeIndex();
    754         emitCharacter('\n', m_lastTextNode->parentNode(), offset, offset + 1);
    755     } else {
    756         offset = m_node->nodeIndex();
    757         emitCharacter('\n', m_node->parentNode(), offset, offset + 1);
    758     }
     735    if (m_lastTextNode)
     736        emitCharacter('\n', positionBeforeNode(m_lastTextNode), positionAfterNode(m_lastTextNode));
     737    else
     738        emitCharacter('\n', positionBeforeNode(m_node), positionAfterNode(m_node));
    759739}
    760740
    761741PassRefPtr<Range> SimplifiedBackwardsTextIterator::range() const
    762742{
    763     if (m_positionNode)
    764         return new Range(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
     743    if (m_range)
     744        return m_range;
    765745   
    766746    return new Range(m_startNode->document(), m_startNode, m_startOffset, m_startNode, m_startOffset);
     
    782762PassRefPtr<Range> CharacterIterator::range() const
    783763{
    784     RefPtr<Range> r = m_textIterator.range();
     764    ExceptionCode ec;
     765    RefPtr<Range> r = m_textIterator.range()->cloneRange(ec);
    785766    if (!m_textIterator.atEnd()) {
    786767        if (m_textIterator.length() <= 1) {
     
    10521033            startRangeFound = true;
    10531034            int exception = 0;
    1054             if (textRunRange->startContainer(exception)->isTextNode()) {
     1035            if (rangeLocation == docTextPosition + len)
     1036                resultRange->setStart(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
     1037            else {
    10551038                int offset = rangeLocation - docTextPosition;
    10561039                resultRange->setStart(textRunRange->startContainer(exception), offset + textRunRange->startOffset(exception), exception);
    1057             } else {
    1058                 if (rangeLocation == docTextPosition)
    1059                     resultRange->setStart(textRunRange->startContainer(exception), textRunRange->startOffset(exception), exception);
    1060                 else
    1061                     resultRange->setStart(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
    10621040            }
    10631041        }
     
    10741052                    resultRange->setEnd(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
    10751053            }
    1076             if (!(rangeLength == 0 && rangeEnd == docTextPosition + len)) {
    1077                 docTextPosition += len;
    1078                 break;
    1079             }
     1054           
     1055            docTextPosition += len;
     1056            break;
    10801057        }
    10811058        docTextPosition += len;
  • trunk/WebCore/editing/TextIterator.h

    r16737 r17276  
    6363    explicit TextIterator(const Range *, IteratorKind kind = CONTENT );
    6464   
    65     bool atEnd() const { return !m_positionNode; }
     65    bool atEnd() const { return !m_range; }
    6666    void advance();
    6767   
     
    8080    bool handleNonTextNode();
    8181    void handleTextBox();
    82     void emitCharacter(UChar, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset);
     82    void emitCharacter(UChar, const Position&, const Position&);
    8383   
    8484    // Current position, not necessarily of the text being returned, but position
     
    9595   
    9696    // The current text and its position, in the form to be returned from the iterator.
    97     Node *m_positionNode;
    98     mutable Node *m_positionOffsetBaseNode;
    99     mutable int m_positionStartOffset;
    100     mutable int m_positionEndOffset;
     97    RefPtr<Range> m_range;
    10198    const UChar* m_textCharacters;
    10299    int m_textLength;
     
    129126    explicit SimplifiedBackwardsTextIterator(const Range *);
    130127   
    131     bool atEnd() const { return !m_positionNode; }
     128    bool atEnd() const { return !m_range; }
    132129    void advance();
    133130   
     
    142139    bool handleReplacedElement();
    143140    bool handleNonTextNode();
    144     void emitCharacter(UChar, Node *Node, int startOffset, int endOffset);
     141    void emitCharacter(UChar, const Position&, const Position&);
    145142    void emitNewline();
    146143   
     
    157154   
    158155    // The current text and its position, in the form to be returned from the iterator.
    159     Node* m_positionNode;
    160     int m_positionStartOffset;
    161     int m_positionEndOffset;
     156    RefPtr<Range> m_range;
    162157    const UChar* m_textCharacters;
    163158    int m_textLength;
  • trunk/WebCore/editing/visible_units.cpp

    r17223 r17276  
    8686   
    8787    if (it.atEnd() && next == 0) {
    88         RefPtr<Range> range(it.range());
    89         pos = Position(range->startContainer(exception), range->startOffset(exception));
     88        pos = it.range()->startPosition();
    9089    } else if (!it.atEnd() && it.length() == 0) {
    9190        // Got a zero-length chunk.
     
    162161   
    163162    if (it.atEnd() && next == string.length()) {
    164         RefPtr<Range> range(it.range());
    165         int exception = 0;
    166         pos = Position(range->startContainer(exception), range->startOffset(exception));
     163        pos = it.range()->startPosition();
    167164    } else if (!it.atEnd() && it.length() == 0) {
    168165        // Got a zero-length chunk.
     
    186183        CharacterIterator charIt(searchRange.get());
    187184        charIt.advance(next - 1);
    188         pos = Position(charIt.range()->endContainer(ec), charIt.range()->endOffset(ec));
     185        pos = charIt.range()->endPosition();
    189186    }
    190187
Note: See TracChangeset for help on using the changeset viewer.