Reviewed by Darin.
authorharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Apr 2006 00:14:21 +0000 (00:14 +0000)
committerharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Apr 2006 00:14:21 +0000 (00:14 +0000)
        <rdar://problem/4386640> AX: AXPreviousSentenceStartTextMarkerForTextMarker does not respect paragraph boundary
        <rdar://problem/4414575> AX: Dictionary popup cannot find some words on Dictionary.app

        AXPreviousSentenceStartTextMarkerForTextMarker failed to stop at the beginning a block because
        SimplifiedBackwardsTextIterator::handleNonTextNode() emitted a space when exiting the block.
        Fixed by emitting a newline instead.

        Word boundary failed to stop at the beginning of a block because no character at all was emitted
        when leaving the block, because the exitNode was checking specific html tags to decide whether the
        node is block, but the node was xml.  Fixed by using the node's renderer, if present.

        (see related changes in WebKit)

        Tests added:
        * editing/selection/extend-by-sentence-001.html: Added.
        * fast/dom/inner-text-001.html: Added.

        * bridge/mac/WebCoreFrameBridge.h:
        * bridge/mac/WebCoreFrameBridge.mm:
        (-[WebCoreFrameBridge alterCurrentSelection:direction:granularity:]):
        Add sentence navigation/selection.

        * editing/Selection.cpp:
        (WebCore::Selection::validate):
        Add sentence navigation/selection.

        * editing/SelectionController.cpp:
        (WebCore::SelectionController::modifyExtendingRightForward):
        (WebCore::SelectionController::modifyMovingRightForward):
        (WebCore::SelectionController::modifyExtendingLeftBackward):
        (WebCore::SelectionController::modifyMovingLeftBackward):
        (WebCore::SelectionController::modify):
        Add sentence navigation/selection.

        * editing/TextGranularity.h:
        (WebCore::):
        Add SentenceGranularity and SentenceBoundary.

        * editing/TextIterator.cpp:
        (WebCore::isTableCell):
        (WebCore::shouldEmitTabBeforeNode):
        (WebCore::shouldEmitNewlineForNode):
        (WebCore::shouldEmitNewlinesBeforeAndAfterNode):
        (WebCore::shouldEmitExtraNewlineForNode):
        New utility functions that prefer renderers over html tag names.

        (WebCore::TextIterator::handleNonTextNode):
        (WebCore::TextIterator::exitNode):
        (WebCore::SimplifiedBackwardsTextIterator::advance):
        Use new utility functions.

        (WebCore::SimplifiedBackwardsTextIterator::handleNonTextNode):
        Use new utility functions.  Also emit linefeed instead of space,
        so sentence parsing works across block boundaries.

        (WebCore::SimplifiedBackwardsTextIterator::exitNode):
        Use new utility functions.

        (WebCore::SimplifiedBackwardsTextIterator::emitNewline):
        Renamed from emitNewlineForBROrText because it is not always for BR or text.

        * editing/TextIterator.h:
        Renamed emitNewlineForBROrText to emitNewline.

        * editing/visible_units.cpp:
        * editing/visible_units.h:
        (WebCore::previousBoundary):
        (WebCore::nextBoundary):
        (WebCore::previousSentencePosition):
        (WebCore::nextSentencePosition):
        Add sentence navigation/selection.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@13849 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/bridge/mac/WebCoreFrameBridge.h
WebCore/bridge/mac/WebCoreFrameBridge.mm
WebCore/editing/Selection.cpp
WebCore/editing/SelectionController.cpp
WebCore/editing/TextGranularity.h
WebCore/editing/TextIterator.cpp
WebCore/editing/TextIterator.h
WebCore/editing/visible_units.cpp
WebCore/editing/visible_units.h

index b03d8c8225a97fb99b1dafb10e146ed35d816781..07cb2521438217a3807f6e5cb6fe711e826b20c6 100644 (file)
@@ -1,3 +1,79 @@
+2006-04-12  David Harrison  <harrison@apple.com>
+
+        Reviewed by Darin.
+
+        <rdar://problem/4386640> AX: AXPreviousSentenceStartTextMarkerForTextMarker does not respect paragraph boundary
+        <rdar://problem/4414575> AX: Dictionary popup cannot find some words on Dictionary.app
+
+        AXPreviousSentenceStartTextMarkerForTextMarker failed to stop at the beginning a block because
+        SimplifiedBackwardsTextIterator::handleNonTextNode() emitted a space when exiting the block.
+        Fixed by emitting a newline instead.
+        
+        Word boundary failed to stop at the beginning of a block because no character at all was emitted
+        when leaving the block, because the exitNode was checking specific html tags to decide whether the
+        node is block, but the node was xml.  Fixed by using the node's renderer, if present.
+        
+        (see related changes in WebKit)
+        
+        Tests added:
+        * editing/selection/extend-by-sentence-001.html: Added.
+        * fast/dom/inner-text-001.html: Added.
+        
+        * bridge/mac/WebCoreFrameBridge.h:
+        * bridge/mac/WebCoreFrameBridge.mm:
+        (-[WebCoreFrameBridge alterCurrentSelection:direction:granularity:]):
+        Add sentence navigation/selection.
+        
+        * editing/Selection.cpp:
+        (WebCore::Selection::validate):
+        Add sentence navigation/selection.
+
+        * editing/SelectionController.cpp:
+        (WebCore::SelectionController::modifyExtendingRightForward):
+        (WebCore::SelectionController::modifyMovingRightForward):
+        (WebCore::SelectionController::modifyExtendingLeftBackward):
+        (WebCore::SelectionController::modifyMovingLeftBackward):
+        (WebCore::SelectionController::modify):
+        Add sentence navigation/selection.
+
+        * editing/TextGranularity.h:
+        (WebCore::):
+        Add SentenceGranularity and SentenceBoundary.
+
+        * editing/TextIterator.cpp:
+        (WebCore::isTableCell):
+        (WebCore::shouldEmitTabBeforeNode):
+        (WebCore::shouldEmitNewlineForNode):
+        (WebCore::shouldEmitNewlinesBeforeAndAfterNode):
+        (WebCore::shouldEmitExtraNewlineForNode):
+        New utility functions that prefer renderers over html tag names.
+
+        (WebCore::TextIterator::handleNonTextNode):
+        (WebCore::TextIterator::exitNode):
+        (WebCore::SimplifiedBackwardsTextIterator::advance):
+        Use new utility functions.
+        
+        (WebCore::SimplifiedBackwardsTextIterator::handleNonTextNode):
+        Use new utility functions.  Also emit linefeed instead of space,
+        so sentence parsing works across block boundaries.
+        
+        (WebCore::SimplifiedBackwardsTextIterator::exitNode):
+        Use new utility functions.
+
+        (WebCore::SimplifiedBackwardsTextIterator::emitNewline):
+        Renamed from emitNewlineForBROrText because it is not always for BR or text.
+        
+        * editing/TextIterator.h:
+        Renamed emitNewlineForBROrText to emitNewline.
+        
+        * editing/visible_units.cpp:
+        * editing/visible_units.h:
+        (WebCore::previousBoundary):
+        (WebCore::nextBoundary):
+        (WebCore::previousSentencePosition):
+        (WebCore::nextSentencePosition):
+        Add sentence navigation/selection.
+
 2006-04-12  Darin Adler  <darin@apple.com>
 
         Rubber-stamped by Hyatt.
index a83c62c1adbd9cecda05c165edb40cfbac0e2a2f..380996fac000b9f5fb8dfd927d2e6918460fefe2 100644 (file)
@@ -97,8 +97,10 @@ typedef enum {
 typedef enum {
     WebBridgeSelectByCharacter,
     WebBridgeSelectByWord,
+    WebBridgeSelectBySentence,
     WebBridgeSelectByLine,
     WebBridgeSelectByParagraph,
+    WebBridgeSelectToSentenceBoundary,
     WebBridgeSelectToLineBoundary,
     WebBridgeSelectToParagraphBoundary,
     WebBridgeSelectToDocumentBoundary
index a4505a370e05dd34d59c57f07e1fd8723acfe453..545a41e1b35d5a4c1eef6856776e077d7954ee69 100644 (file)
@@ -1615,8 +1615,10 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
             break;
         case WebBridgeSelectByCharacter:
         case WebBridgeSelectByWord:
+        case WebBridgeSelectBySentence:
         case WebBridgeSelectToLineBoundary:
         case WebBridgeSelectToParagraphBoundary:
+        case WebBridgeSelectToSentenceBoundary:
         case WebBridgeSelectToDocumentBoundary:
             break;
     }
index c437f3d554901d7d3122a2936e2ae5173eea3a62..a9a5acd8cda13b9e68d1d05c2002ab84a9f230e2 100644 (file)
@@ -236,6 +236,11 @@ void Selection::validate()
             m_end = endOfWord(end, side).deepEquivalent();
             break;
         }
+        case SentenceGranularity: {
+            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+        }
         case LineGranularity: {
             m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
             VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
@@ -279,6 +284,10 @@ void Selection::validate()
             m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
             m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
             break;
+        case SentenceBoundary:
+            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
     }
     
     adjustForEditableContent();
index 876e080399dafb0dcdd6f9445956b799cc5007c5..e22d2be4475e83c02d74d34d11106a853c5fb123 100644 (file)
@@ -283,12 +283,18 @@ VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity
             else
                 pos = nextWordPosition(pos);
             break;
-        case ParagraphGranularity:
-            pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+        case SentenceGranularity:
+            pos = nextSentencePosition(pos);
             break;
         case LineGranularity:
             pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
             break;
+        case ParagraphGranularity:
+            pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case SentenceBoundary:
+            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
         case LineBoundary:
             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
             break;
@@ -316,8 +322,8 @@ VisiblePosition SelectionController::modifyMovingRightForward(TextGranularity gr
         case WordGranularity:
             pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
             break;
-        case ParagraphGranularity:
-            pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(END, isRange()));
+        case SentenceGranularity:
+            pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
             break;
         case LineGranularity: {
             // down-arrowing from a range selection that ends at the start of a line needs
@@ -327,6 +333,12 @@ VisiblePosition SelectionController::modifyMovingRightForward(TextGranularity gr
                 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(END, isRange()));
             break;
         }
+        case ParagraphGranularity:
+            pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(END, isRange()));
+            break;
+        case SentenceBoundary:
+            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
         case LineBoundary:
             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
             break;
@@ -361,12 +373,18 @@ VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity
             else
                 pos = previousWordPosition(pos);
             break;
-        case ParagraphGranularity:
-            pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+        case SentenceGranularity:
+            pos = previousSentencePosition(pos);
             break;
         case LineGranularity:
             pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
             break;
+        case ParagraphGranularity:
+            pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case SentenceBoundary:
+            pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
         case LineBoundary:
             pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
             break;
@@ -393,12 +411,18 @@ VisiblePosition SelectionController::modifyMovingLeftBackward(TextGranularity gr
         case WordGranularity:
             pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
             break;
-        case ParagraphGranularity:
-            pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
+        case SentenceGranularity:
+            pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
             break;
         case LineGranularity:
             pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
             break;
+        case ParagraphGranularity:
+            pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
+            break;
+        case SentenceBoundary:
+            pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
         case LineBoundary:
             pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
             break;
@@ -442,6 +466,8 @@ bool SelectionController::modify(const String &alterString, const String &direct
         granularity = CharacterGranularity;
     else if (granularityStringLower == "word")
         granularity = WordGranularity;
+    else if (granularityStringLower == "sentence")
+        granularity = SentenceGranularity;
     else if (granularityStringLower == "line")
         granularity = LineGranularity;
     else if (granularityStringLower == "paragraph")
index 035334d233d321a7e164961a422e73dae5e7600f..d95097254567dcd9a74013e778c7b8c29cfd1eed 100644 (file)
@@ -30,11 +30,14 @@ namespace WebCore {
 
 // FIXME: This really should be broken up into more than one concept.
 // Frame doesn't neeed the 3 boundaries in this enum.
+// NOTE: This MUST match WebBridgeSelectionGranularity
 enum TextGranularity {
     CharacterGranularity,
     WordGranularity,
+    SentenceGranularity,
     LineGranularity,
     ParagraphGranularity,
+    SentenceBoundary,
     LineBoundary,
     ParagraphBoundary,
     DocumentBoundary
index 61a397ccfd33adc945cdb14a0ff6c1b8cba66009..6fece057fdb0c54a230e0a79b2abf4a7f97ecec1 100644 (file)
 #include "Document.h"
 #include "Element.h"
 #include "HTMLNames.h"
-
-// FIXME: These classes should probably use the render tree and not the DOM tree, since elements could
-// be hidden using CSS, or additional generated content could be added.  For now, we just make sure
-// text objects walk their renderers' InlineTextBox objects, so that we at least get the whitespace 
-// stripped out properly and obey CSS visibility for text runs.
+#include "htmlediting.h"
+#include "InlineTextBox.h"
+#include "Position.h"
+#include "Range.h"
+#include "RenderTableCell.h"
+#include "RenderTableRow.h"
 
 namespace WebCore {
 
@@ -349,33 +350,122 @@ bool TextIterator::handleReplacedElement()
     return true;
 }
 
+static bool isTableCell(Node* node)
+{
+    RenderObject* r = node->renderer();
+    if (!r)
+        return node->hasTagName(tdTag) || node->hasTagName(thTag);
+    
+    return r->isTableCell();
+}
+
+static bool shouldEmitTabBeforeNode(Node* node)
+{
+    // Table cells are delimited by tabs.
+    if (!isTableCell(node))
+        return false;
+    
+    // Want a tab before every cell other than the first one
+    RenderObject* r = node->renderer();
+    RenderTableCell* rc = static_cast<RenderTableCell*>(r);
+    RenderTable* t = rc->table();
+    return t && (t->cellBefore(rc) || t->cellAbove(rc));
+}
+
+static bool shouldEmitNewlineForNode(Node* node)
+{
+    // br elements are represented by a single newline.
+    RenderObject* r = node->renderer();
+    if (!r)
+        return node->hasTagName(brTag);
+        
+    return r->isBR();
+}
+
+static bool shouldEmitNewlinesBeforeAndAfterNode(Node* node)
+{
+    // Block flow (versus inline flow) is represented by having
+    // a newline both before and after the element.
+    RenderObject* r = node->renderer();
+    if (!r) {
+        return (node->hasTagName(blockquoteTag)
+                || node->hasTagName(ddTag)
+                || node->hasTagName(divTag)
+                || node->hasTagName(dlTag)
+                || node->hasTagName(dtTag)
+                || node->hasTagName(h1Tag)
+                || node->hasTagName(h2Tag)
+                || node->hasTagName(h3Tag)
+                || node->hasTagName(h4Tag)
+                || node->hasTagName(h5Tag)
+                || node->hasTagName(h6Tag)
+                || node->hasTagName(hrTag)
+                || node->hasTagName(liTag)
+                || node->hasTagName(listingTag)
+                || node->hasTagName(olTag)
+                || node->hasTagName(pTag)
+                || node->hasTagName(preTag)
+                || node->hasTagName(trTag)
+                || node->hasTagName(ulTag));
+    }
+
+    // Need to make an exception for table cells, because they are blocks, but we
+    // want them tab-delimited rather than having newlines before and after.
+    if (isTableCell(node))
+        return false;
+    
+    // Need to make an exception for table row elements, because they are neither
+    // "inline" or "RenderBlock", but we want newlines for them.
+    if (r->isTableRow()) {
+        RenderTable* t = static_cast<RenderTableRow*>(r)->table();
+        if (t && !t->isInline())
+            return true;
+    }
+    
+    // Check for non-inline block
+    return !r->isInline() && r->isRenderBlock() && !r->isBody();
+}
+
+static bool shouldEmitExtraNewlineForNode(Node* node)
+{
+    // When there is a significant collapsed bottom margin, emit an extra
+    // newline for a more realistic result.  We end up getting the right
+    // result even without margin collapsing. For example: <div><p>text</p></div>
+    // will work right even if both the <div> and the <p> have bottom margins.
+    RenderObject* r = node->renderer();
+    if (!r)
+        return false;
+    
+    // NOTE: We only do this for a select set of nodes, and fwiw WinIE appears
+    // not to do this at all
+    if (node->hasTagName(h1Tag)
+        || node->hasTagName(h2Tag)
+        || node->hasTagName(h3Tag)
+        || node->hasTagName(h4Tag)
+        || node->hasTagName(h5Tag)
+        || node->hasTagName(h6Tag)
+        || node->hasTagName(pTag)) {
+        RenderStyle* style = r->style();
+        if (style) {
+            int bottomMargin = r->collapsedMarginBottom();
+            int fontSize = style->fontDescription().computedPixelSize();
+            if (bottomMargin * 2 >= fontSize)
+                return true;
+        }
+    }
+    
+    return false;
+}
+
 bool TextIterator::handleNonTextNode()
 {
-    if (m_node->hasTagName(brTag)) {
+    if (shouldEmitNewlineForNode(m_node)) {
         emitCharacter('\n', m_node->parentNode(), m_node, 0, 1);
-    } else if (m_node->hasTagName(tdTag) || m_node->hasTagName(thTag)) {
-        if (m_lastCharacter != '\n' && m_lastTextNode)
+    } else if (m_lastCharacter != '\n' && m_lastTextNode) {
+        // only add the tab or newline if not at the start of a line
+        if (shouldEmitTabBeforeNode(m_node))
             emitCharacter('\t', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
-    } else if (m_node->hasTagName(blockquoteTag)
-                || m_node->hasTagName(ddTag)
-                || m_node->hasTagName(divTag)
-                || m_node->hasTagName(dlTag)
-                || m_node->hasTagName(dtTag)
-                || m_node->hasTagName(h1Tag)
-                || m_node->hasTagName(h2Tag)
-                || m_node->hasTagName(h3Tag)
-                || m_node->hasTagName(h4Tag)
-                || m_node->hasTagName(h5Tag)
-                || m_node->hasTagName(h6Tag)
-                || m_node->hasTagName(hrTag)
-                || m_node->hasTagName(liTag)
-                || m_node->hasTagName(listingTag)
-                || m_node->hasTagName(olTag)
-                || m_node->hasTagName(pTag)
-                || m_node->hasTagName(preTag) 
-                || m_node->hasTagName(trTag)
-                || m_node->hasTagName(ulTag)) {
-        if (m_lastCharacter != '\n' && m_lastTextNode)
+        else if (shouldEmitNewlinesBeforeAndAfterNode(m_node))
             emitCharacter('\n', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
     }
 
@@ -384,57 +474,15 @@ bool TextIterator::handleNonTextNode()
 
 void TextIterator::exitNode()
 {
-    bool endLine = false;
-    bool addNewline = false;
-
-    if (m_node->hasTagName(blockquoteTag)
-            || m_node->hasTagName(ddTag)
-            || m_node->hasTagName(divTag)
-            || m_node->hasTagName(dlTag)
-            || m_node->hasTagName(dtTag)
-            || m_node->hasTagName(hrTag)
-            || m_node->hasTagName(liTag)
-            || m_node->hasTagName(listingTag)
-            || m_node->hasTagName(olTag)
-            || m_node->hasTagName(preTag)
-            || m_node->hasTagName(trTag)
-            || m_node->hasTagName(ulTag))
-        endLine = true;
-    else if (m_node->hasTagName(h1Tag)
-            || m_node->hasTagName(h2Tag)
-            || m_node->hasTagName(h3Tag)
-            || m_node->hasTagName(h4Tag)
-            || m_node->hasTagName(h5Tag)
-            || m_node->hasTagName(h6Tag)
-            || m_node->hasTagName(pTag)) {
-        endLine = true;
-
-        // In certain cases, emit a new newline character for this node
-        // regardless of whether we emit another one.
-        // FIXME: Some day we could do this for other tags.
-        // However, doing it just for the tags above makes it more likely
-        // we'll end up getting the right result without margin collapsing.
-        // For example: <div><p>text</p></div> will work right even if both
-        // the <div> and the <p> have bottom margins.
-        RenderObject *renderer = m_node->renderer();
-        if (renderer) {
-            RenderStyle *style = renderer->style();
-            if (style) {
-                int bottomMargin = renderer->collapsedMarginBottom();
-                int fontSize = style->fontDescription().computedPixelSize();
-                if (bottomMargin * 2 >= fontSize)
-                    addNewline = true;
-            }
-        }
-    }
-
-    // emit character(s) iff there is an earlier text node and we need at least one newline
-    if (m_lastTextNode && endLine) {
+    if (m_lastTextNode && shouldEmitNewlinesBeforeAndAfterNode(m_node)) {
+        // use extra newline to represent margin bottom, as needed
+        bool addNewline = shouldEmitExtraNewlineForNode(m_node);
+        
         if (m_lastCharacter != '\n') {
             // insert a newline with a position following this block
             emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);
 
-            //...and, if needed, set flag to later add a newline for the current node
+            // remember whether to later add a newline for the current node
             assert(!m_needAnotherNewline);
             m_needAnotherNewline = addNewline;
         } else if (addNewline) {
@@ -596,7 +644,7 @@ void SimplifiedBackwardsTextIterator::advance()
             if (block) {
                 Node *nextBlock = next->enclosingBlockFlowElement();
                 if (nextBlock && nextBlock->isAncestor(block))
-                    emitNewlineForBROrText();
+                    emitNewline();
             }
         }
         
@@ -652,44 +700,23 @@ bool SimplifiedBackwardsTextIterator::handleReplacedElement()
 }
 
 bool SimplifiedBackwardsTextIterator::handleNonTextNode()
-{
-    if (m_node->hasTagName(brTag))
-        emitNewlineForBROrText();
-    else if (m_node->hasTagName(blockquoteTag)
-            || m_node->hasTagName(ddTag)
-            || m_node->hasTagName(divTag)
-            || m_node->hasTagName(dlTag)
-            || m_node->hasTagName(dtTag)
-            || m_node->hasTagName(h1Tag)
-            || m_node->hasTagName(h2Tag)
-            || m_node->hasTagName(h3Tag)
-            || m_node->hasTagName(h4Tag)
-            || m_node->hasTagName(h5Tag)
-            || m_node->hasTagName(h6Tag)
-            || m_node->hasTagName(hrTag)
-            || m_node->hasTagName(liTag)
-            || m_node->hasTagName(listingTag)
-            || m_node->hasTagName(olTag)
-            || m_node->hasTagName(pTag)
-            || m_node->hasTagName(preTag)
-            || m_node->hasTagName(tdTag)
-            || m_node->hasTagName(thTag)
-            || m_node->hasTagName(trTag)
-            || m_node->hasTagName(ulTag)) {
-        // Emit a space to "break up" content. Any word break
-        // character will do.
-        emitCharacter(' ', m_node, 0, 0);
-    }
-
+{    
+    // We can use a linefeed in place of a tab because this simple iterator is only used to
+    // find boundaries, not actual content.  A linefeed breaks words, sentences, and paragraphs.
+    if (shouldEmitNewlineForNode(m_node) ||
+        shouldEmitNewlinesBeforeAndAfterNode(m_node) ||
+        shouldEmitTabBeforeNode(m_node))
+        emitNewline();
+    
     return true;
 }
 
 void SimplifiedBackwardsTextIterator::exitNode()
 {
-    // Left this function in so that the name and usage patters remain similar to 
+    // Left this function in so that the name and usage patterns remain similar to 
     // TextIterator. However, the needs of this iterator are much simpler, and
     // the handleNonTextNode() function does just what we want (i.e. insert a
-    // space for certain node types to "break up" text so that it does not seem
+    // BR for certain node types to "break up" text so that it does not seem
     // like content is next to other text when it really isn't). 
     handleNonTextNode();
 }
@@ -705,7 +732,7 @@ void SimplifiedBackwardsTextIterator::emitCharacter(QChar c, Node *node, int sta
     m_lastCharacter = c;
 }
 
-void SimplifiedBackwardsTextIterator::emitNewlineForBROrText()
+void SimplifiedBackwardsTextIterator::emitNewline()
 {
     int offset;
     
index 1149aa64400f5f0f14240fac0a9c6a53a101da0d..04d92fd610934c7e0c84e76fa24cede5096159a1 100644 (file)
@@ -141,7 +141,7 @@ private:
     bool handleReplacedElement();
     bool handleNonTextNode();
     void emitCharacter(QChar, Node *Node, int startOffset, int endOffset);
-    void emitNewlineForBROrText();
+    void emitNewline();
     
     // Current position, not necessarily of the text being returned, but position
     // as we walk through the DOM tree.
index a717d1b7eb345e710f08996753874f97ebde2e2d..e9f462dcbbb9492b434f24d509dabf3e87708000 100644 (file)
@@ -82,8 +82,7 @@ static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*sea
     if (it.atEnd() && next == 0) {
         RefPtr<Range> range(it.range());
         pos = Position(range->startContainer(exception), range->startOffset(exception));
-    }
-    else if (!it.atEnd() && it.length() == 0) {
+    } else if (!it.atEnd() && it.length() == 0) {
         // Got a zero-length chunk.
         // This means we have hit a replaced element.
         // Make a check to see if the position should be before or after the replaced element
@@ -99,8 +98,7 @@ static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*sea
             pos = Position(range->startContainer(exception), range->startOffset(exception));
         else
             pos = Position(range->endContainer(exception), range->endOffset(exception));
-    }
-    else if (next != 0) {
+    } else if (next != 0) {
         // The simpler iterator used in this function, as compared to the one used in 
         // nextWordPosition(), gives us results we can use directly without having to 
         // iterate again to translate the next value into a DOM position. 
@@ -156,8 +154,7 @@ static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchF
         RefPtr<Range> range(it.range());
         int exception = 0;
         pos = Position(range->startContainer(exception), range->startOffset(exception));
-    }
-    else if (!it.atEnd() && it.length() == 0) {
+    } else if (!it.atEnd() && it.length() == 0) {
         // Got a zero-length chunk.
         // This means we have hit a replaced element.
         // Make a check to see if the position should be before or after the replaced element
@@ -174,8 +171,7 @@ static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchF
             pos = Position(range->endContainer(exception), range->endOffset(exception));
         else
             pos = Position(range->startContainer(exception), range->startOffset(exception));
-    }
-    else if (next != 0) {
+    } else if (next != 0) {
         // Use the character iterator to translate the next value into a DOM position.
         CharacterIterator charIt(searchRange.get());
         charIt.advance(next - 1);
@@ -523,7 +519,7 @@ static unsigned previousSentencePositionBoundary(const QChar *characters, unsign
     return findNextSentenceFromIndex(characters, length, length, false);
 }
 
-VisiblePosition previousSentencePosition(const VisiblePosition &c, int x)
+VisiblePosition previousSentencePosition(const VisiblePosition &c)
 {
     return previousBoundary(c, previousSentencePositionBoundary);
 }
@@ -533,7 +529,7 @@ static unsigned nextSentencePositionBoundary(const QChar *characters, unsigned l
     return findNextSentenceFromIndex(characters, length, 0, true);
 }
 
-VisiblePosition nextSentencePosition(const VisiblePosition &c, int x)
+VisiblePosition nextSentencePosition(const VisiblePosition &c)
 {
     return nextBoundary(c, nextSentencePositionBoundary);
 }
index 288b02bf8accfe0f2163975c5fa0dde97bb01a5b..2509720064b5f939e80a223003c9e9068b882e6a 100644 (file)
@@ -40,6 +40,12 @@ VisiblePosition endOfWord(const VisiblePosition &, EWordSide = RightWordIfOnBoun
 VisiblePosition previousWordPosition(const VisiblePosition &);
 VisiblePosition nextWordPosition(const VisiblePosition &);
 
+// sentences
+VisiblePosition startOfSentence(const VisiblePosition &);
+VisiblePosition endOfSentence(const VisiblePosition &);
+VisiblePosition previousSentencePosition(const VisiblePosition &);
+VisiblePosition nextSentencePosition(const VisiblePosition &);
+
 // lines
 VisiblePosition startOfLine(const VisiblePosition &);
 VisiblePosition endOfLine(const VisiblePosition &);
@@ -49,12 +55,6 @@ bool inSameLine(const VisiblePosition &, const VisiblePosition &);
 bool isStartOfLine(const VisiblePosition &);
 bool isEndOfLine(const VisiblePosition &);
 
-// sentences
-VisiblePosition startOfSentence(const VisiblePosition &);
-VisiblePosition endOfSentence(const VisiblePosition &);
-VisiblePosition previousSentencePosition(const VisiblePosition &);
-VisiblePosition nextSentencePosition(const VisiblePosition &);
-
 // paragraphs (perhaps a misnomer, can be divided by line break elements)
 VisiblePosition startOfParagraph(const VisiblePosition &);
 VisiblePosition endOfParagraph(const VisiblePosition &);