TextIterator: Use StringView and references rather than pointers
[WebKit-https.git] / Source / WebCore / editing / TextIterator.h
index 749f12732f665c555da208eeb4d10abab5ec3e86..416b5ecc1637508f63bd495f396c1d4cd000d02f 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef TextIterator_h
 #define TextIterator_h
 
+// FIXME: Move each iterator class into a separate header file.
+
 #include "FindOptions.h"
 #include "Range.h"
 #include "TextIteratorBehavior.h"
@@ -39,7 +41,7 @@ class RenderText;
 class RenderTextFragment;
 
 String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
-PassRefPtr<Range> findPlainText(const Range*, const String&, FindOptions);
+PassRefPtr<Range> findPlainText(const Range&, const String&, FindOptions);
 
 // FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
 bool isRendererReplacedElement(RenderObject*);
@@ -60,116 +62,115 @@ private:
     Vector<unsigned, 1> m_words;
 };
 
+class TextIteratorCopyableText {
+public:
+    TextIteratorCopyableText()
+        : m_singleCharacter(0)
+        , m_offset(0)
+        , m_length(0)
+    {
+    }
+
+    StringView text() const { return m_singleCharacter ? StringView(&m_singleCharacter, 1) : StringView(m_string).substring(m_offset, m_length); }
+    void appendToStringBuilder(StringBuilder&) const;
+
+    void reset();
+    void set(String&&);
+    void set(String&&, unsigned offset, unsigned length);
+    void set(UChar);
+
+private:
+    UChar m_singleCharacter;
+    String m_string;
+    unsigned m_offset;
+    unsigned m_length;
+};
+
 // Iterates through the DOM range, returning all the text, and 0-length boundaries
-// at points where replaced elements break up the text flow.  The text comes back in
-// chunks so as to optimize for performance of the iteration.
+// at points where replaced elements break up the text flow. The text is delivered in
+// the chunks it's already stored in, to avoid copying any text.
 
 class TextIterator {
 public:
     explicit TextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
     ~TextIterator();
 
-    bool atEnd() const { return !m_positionNode || m_shouldStop; }
+    bool atEnd() const { return !m_positionNode; }
     void advance();
-    
-    StringView text() const { return m_textCharacters ? StringView(m_textCharacters, m_textLength) : StringView(m_text).substring(m_positionStartOffset, m_textLength); }
-    int length() const { return m_textLength; }
-
-    const UChar* deprecatedTextIteratorCharacters() const { return m_textCharacters ? m_textCharacters : m_text.deprecatedCharacters() + m_positionStartOffset; }
 
-    UChar characterAt(unsigned index) const;
-    void appendTextToStringBuilder(StringBuilder&) const;
-    
+    StringView text() const { ASSERT(!atEnd()); return m_text; }
     PassRefPtr<Range> range() const;
     Node* node() const;
-     
+
+    const TextIteratorCopyableText& copyableText() const { ASSERT(!atEnd()); return m_copyableText; }
+    void appendTextToStringBuilder(StringBuilder& builder) const { copyableText().appendToStringBuilder(builder); }
+
     static int rangeLength(const Range*, bool spacesForReplacedElements = false);
     static PassRefPtr<Range> rangeFromLocationAndLength(ContainerNode* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
     static bool getLocationAndLengthFromRange(Node* scope, const Range*, size_t& location, size_t& length);
     static PassRefPtr<Range> subrange(Range* entireRange, int characterOffset, int characterCount);
-    
+
 private:
     void exitNode();
     bool shouldRepresentNodeOffsetZero();
-    bool shouldEmitSpaceBeforeAndAfterNode(Node*);
+    bool shouldEmitSpaceBeforeAndAfterNode(Node&);
     void representNodeOffsetZero();
     bool handleTextNode();
     bool handleReplacedElement();
     bool handleNonTextNode();
     void handleTextBox();
-    void handleTextNodeFirstLetter(RenderTextFragment*);
-    bool hasVisibleTextNode(RenderText*);
-    void emitCharacter(UChar, Node* textNode, Node* offsetBaseNode, int textStartOffset, int textEndOffset);
-    void emitText(Node* textNode, RenderObject* renderObject, int textStartOffset, int textEndOffset);
-    void emitText(Node* textNode, int textStartOffset, int textEndOffset);
-    
-    // Current position, not necessarily of the text being returned, but position
-    // as we walk through the DOM tree.
+    void handleTextNodeFirstLetter(RenderTextFragment&);
+    void emitCharacter(UChar, Node& characterNode, Node* offsetBaseNode, int textStartOffset, int textEndOffset);
+    void emitText(Text& textNode, RenderText&, int textStartOffset, int textEndOffset);
+
+    const TextIteratorBehavior m_behavior;
+
+    // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
     Node* m_node;
     int m_offset;
     bool m_handledNode;
     bool m_handledChildren;
     BitStack m_fullyClippedStack;
-    
+
     // The range.
     Node* m_startContainer;
     int m_startOffset;
     Node* m_endContainer;
     int m_endOffset;
     Node* m_pastEndNode;
-    
+
     // The current text and its position, in the form to be returned from the iterator.
     Node* m_positionNode;
     mutable Node* m_positionOffsetBaseNode;
     mutable int m_positionStartOffset;
     mutable int m_positionEndOffset;
-    const UChar* m_textCharacters; // If null, then use m_text for character data.
-    int m_textLength;
-    // Hold string m_textCharacters points to so we ensure it won't be deleted.
-    String m_text;
+    TextIteratorCopyableText m_copyableText;
+    StringView m_text;
 
-    // Used when there is still some pending text from the current node; when these
-    // are false and 0, we go back to normal iterating.
+    // Used when there is still some pending text from the current node; when these are false and null, we go back to normal iterating.
     bool m_needsAnotherNewline;
     InlineTextBox* m_textBox;
-    // Used when iteration over :first-letter text to save pointer to
-    // remaining text box.
+
+    // Used when iterating over :first-letter text to save pointer to remaining text box.
     InlineTextBox* m_remainingTextBox;
+
     // Used to point to RenderText object for :first-letter.
-    RenderText *m_firstLetterText;
-    
+    RenderTextm_firstLetterText;
+
     // Used to do the whitespace collapsing logic.
-    Node* m_lastTextNode;    
+    Text* m_lastTextNode;
     bool m_lastTextNodeEndedWithCollapsedSpace;
     UChar m_lastCharacter;
-    
-    // Used for whitespace characters that aren't in the DOM, so we can point at them.
-    UChar m_singleCharacterBuffer;
-    
-    // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
+
+    // Used when text boxes are out of order (Hebrew/Arabic with embedded LTR text)
     Vector<InlineTextBox*> m_sortedTextBoxes;
     size_t m_sortedTextBoxesPosition;
-    
+
     // Used when deciding whether to emit a "positioning" (e.g. newline) before any other content
     bool m_hasEmitted;
-    
-    bool m_emitsCharactersBetweenAllVisiblePositions;
-    bool m_entersTextControls;
-    bool m_emitsTextWithoutTranscoding;
-    bool m_emitsOriginalText;
 
     // Used when deciding text fragment created by :first-letter should be looked into.
     bool m_handledFirstLetter;
-
-    bool m_ignoresStyleVisibility;
-    bool m_emitsObjectReplacementCharacters;
-    bool m_stopsOnFormControls;
-
-    // Used when m_stopsOnFormControls is set to determine if the iterator should keep advancing.
-    bool m_shouldStop;
-
-    bool m_emitsImageAltText;
-    bool m_hasNodesFollowing;
 };
 
 // Iterates through the DOM range, returning all the text, and 0-length boundaries
@@ -177,145 +178,119 @@ private:
 // chunks so as to optimize for performance of the iteration.
 class SimplifiedBackwardsTextIterator {
 public:
-    explicit SimplifiedBackwardsTextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
-    
-    bool atEnd() const { return !m_positionNode || m_shouldStop; }
-    void advance();
-
-    Node* node() const { return m_node; }
+    explicit SimplifiedBackwardsTextIterator(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
 
-    StringView text() const { return StringView(m_textCharacters, m_textLength); }
-    int length() const { return m_textLength; }
+    bool atEnd() const { return !m_positionNode; }
+    void advance();
 
+    StringView text() const { ASSERT(!atEnd()); return m_text; }
     PassRefPtr<Range> range() const;
-        
+    Node* node() const { ASSERT(!atEnd()); return m_node; }
+
 private:
     void exitNode();
     bool handleTextNode();
     RenderText* handleFirstLetter(int& startOffset, int& offsetInNode);
     bool handleReplacedElement();
     bool handleNonTextNode();
-    void emitCharacter(UChar, Node*, int startOffset, int endOffset);
+    void emitCharacter(UChar, Node&, int startOffset, int endOffset);
     bool advanceRespectingRange(Node*);
 
-    // Current position, not necessarily of the text being returned, but position
-    // as we walk through the DOM tree.
+    const TextIteratorBehavior m_behavior;
+
+    // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
     Node* m_node;
     int m_offset;
     bool m_handledNode;
     bool m_handledChildren;
     BitStack m_fullyClippedStack;
 
-    // End of the range.
-    Node* m_startNode;
+    // The range.
+    Node* m_startContainer;
     int m_startOffset;
-    // Start of the range.
-    Node* m_endNode;
+    Node* m_endContainer;
     int m_endOffset;
     
     // The current text and its position, in the form to be returned from the iterator.
     Node* m_positionNode;
     int m_positionStartOffset;
     int m_positionEndOffset;
-    const UChar* m_textCharacters;
-    int m_textLength;
+    TextIteratorCopyableText m_copyableText;
+    StringView m_text;
 
     // Used to do the whitespace logic.
-    Node* m_lastTextNode;    
+    Text* m_lastTextNode;
     UChar m_lastCharacter;
-    
-    // Used for whitespace characters that aren't in the DOM, so we can point at them.
-    UChar m_singleCharacterBuffer;
 
-    // Whether m_node has advanced beyond the iteration range (i.e. m_startNode).
-    bool m_havePassedStartNode;
+    // Whether m_node has advanced beyond the iteration range (i.e. m_startContainer).
+    bool m_havePassedStartContainer;
 
     // Should handle first-letter renderer in the next call to handleTextNode.
     bool m_shouldHandleFirstLetter;
-
-    // Used when the iteration should stop if form controls are reached.
-    bool m_stopsOnFormControls;
-
-    // Used when m_stopsOnFormControls is set to determine if the iterator should keep advancing.
-    bool m_shouldStop;
-
-    // Used in pasting inside password field.
-    bool m_emitsOriginalText;
 };
 
 // Builds on the text iterator, adding a character position so we can walk one
 // character at a time, or faster, as needed. Useful for searching.
 class CharacterIterator {
 public:
-    explicit CharacterIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
+    explicit CharacterIterator(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
     
+    bool atEnd() const { return m_underlyingIterator.atEnd(); }
     void advance(int numCharacters);
     
-    bool atBreak() const { return m_atBreak; }
-    bool atEnd() const { return m_textIterator.atEnd(); }
-    
-    StringView text() const { return m_textIterator.text().substring(m_runOffset); }
-    int length() const { return m_textIterator.length() - m_runOffset; }
+    StringView text() const { return m_underlyingIterator.text().substring(m_runOffset); }
+    PassRefPtr<Range> range() const;
 
-    String string(int numCharacters);
-    
+    bool atBreak() const { return m_atBreak; }
     int characterOffset() const { return m_offset; }
-    PassRefPtr<Range> range() const;
 
 private:
+    TextIterator m_underlyingIterator;
+
     int m_offset;
     int m_runOffset;
     bool m_atBreak;
-    
-    TextIterator m_textIterator;
 };
     
 class BackwardsCharacterIterator {
 public:
-    explicit BackwardsCharacterIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
+    explicit BackwardsCharacterIterator(const Range&);
 
-    void advance(int);
-
-    bool atEnd() const { return m_textIterator.atEnd(); }
+    bool atEnd() const { return m_underlyingIterator.atEnd(); }
+    void advance(int numCharacters);
 
     PassRefPtr<Range> range() const;
 
 private:
+    SimplifiedBackwardsTextIterator m_underlyingIterator;
+
     int m_offset;
     int m_runOffset;
     bool m_atBreak;
-
-    SimplifiedBackwardsTextIterator m_textIterator;
 };
 
-// Very similar to the TextIterator, except that the chunks of text returned are "well behaved", meaning
+// Similar to the TextIterator, except that the chunks of text returned are "well behaved", meaning
 // they never split up a word. This is useful for spell checking and perhaps one day for searching as well.
 class WordAwareIterator {
 public:
-    explicit WordAwareIterator(const Range*);
-    ~WordAwareIterator();
+    explicit WordAwareIterator(const Range&);
 
-    bool atEnd() const { return !m_didLookAhead && m_textIterator.atEnd(); }
+    bool atEnd() const { return !m_didLookAhead && m_underlyingIterator.atEnd(); }
     void advance();
-    
-    int length() const;
 
     StringView text() const;
-    PassRefPtr<Range> range() const { return m_range; }
 
 private:
+    TextIterator m_underlyingIterator;
+
     // Text from the previous chunk from the text iterator.
-    StringView m_previousText;
+    TextIteratorCopyableText m_previousText;
 
     // Many chunks from text iterator concatenated.
     Vector<UChar> m_buffer;
     
     // Did we have to look ahead in the text iterator to confirm the current chunk?
     bool m_didLookAhead;
-
-    RefPtr<Range> m_range;
-
-    TextIterator m_textIterator;
 };
 
 }