[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

rniwa at webkit.org rniwa at webkit.org
Wed Dec 22 14:24:29 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 148eaf51290706b67944f3b64f634c66588f1fd2
Author: rniwa at webkit.org <rniwa at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Oct 7 23:55:00 2010 +0000

    2010-10-07  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Tony Chang.
    
            REGRESSION: Indenting pre duplicates content
            https://bugs.webkit.org/show_bug.cgi?id=47233
    
            The bug was caused by our not splitting text nodes properly.
    
            In new approach, we split text nodes in each iteration. Added rangeForParagraphSplitingTextNodesIfNeeded
            to split text nodes at the start and at the end of paragraph, which also adjusts start and end positions
            for moveParagraphWithClones. Added endOfNextParagrahSplittingTextNodesIfNeeded to adjust endOfNextParagraph,
            start, and end to work-around moveParagraphWithClones's removing a line feed.
    
            Tests: editing/execCommand/indent-pre-list.html
                   editing/execCommand/indent-pre-paragraphs.html
    
            * editing/ApplyBlockElementCommand.cpp:
            (WebCore::ApplyBlockElementCommand::formatSelection): See above.
            (WebCore::isNewLineAtPosition):
            (WebCore::renderStyleOfEnclosingTextNode): Added.
            (WebCore::ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded): Added.
            (WebCore::ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded): Added.
            * editing/ApplyBlockElementCommand.h:
            * editing/FormatBlockCommand.cpp:
            (WebCore::FormatBlockCommand::formatRange): Takes two Positions instead of one VisiblePosition.
            * editing/FormatBlockCommand.h:
            * editing/IndentOutdentCommand.cpp:
            (WebCore::IndentOutdentCommand::tryIndentingAsListItem): Ditto.
            (WebCore::IndentOutdentCommand::indentIntoBlockquote): Ditto.
            (WebCore::IndentOutdentCommand::formatRange): Ditto.
            * editing/IndentOutdentCommand.h:
    2010-10-07  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Tony Chang.
    
            REGRESSION: Indenting pre duplicates content
            https://bugs.webkit.org/show_bug.cgi?id=47233
    
            Added tests to ensure WebKit indents texts inside pre correctly.
    
            * editing/execCommand/indent-pre-expected.txt: This test passes if WebKit does not crash.
            * editing/execCommand/indent-pre-list-expected.txt: Added.
            * editing/execCommand/indent-pre-list.html: Added.
            * editing/execCommand/indent-pre-paragraphs-expected.txt: Added.
            * editing/execCommand/indent-pre-paragraphs.html: Added.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@69354 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 81ffabb..237d632 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2010-10-07  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Tony Chang.
+
+        REGRESSION: Indenting pre duplicates content
+        https://bugs.webkit.org/show_bug.cgi?id=47233
+
+        Added tests to ensure WebKit indents texts inside pre correctly.
+
+        * editing/execCommand/indent-pre-expected.txt: This test passes if WebKit does not crash.
+        * editing/execCommand/indent-pre-list-expected.txt: Added.
+        * editing/execCommand/indent-pre-list.html: Added.
+        * editing/execCommand/indent-pre-paragraphs-expected.txt: Added.
+        * editing/execCommand/indent-pre-paragraphs.html: Added.
+
 2010-10-07  Albert J. Wong  <ajwong at chromium.org>
 
         [Chromium] Unreviewed. Build fix.
diff --git a/LayoutTests/editing/execCommand/indent-pre-expected.txt b/LayoutTests/editing/execCommand/indent-pre-expected.txt
index cd64c84..e701721 100644
--- a/LayoutTests/editing/execCommand/indent-pre-expected.txt
+++ b/LayoutTests/editing/execCommand/indent-pre-expected.txt
@@ -1,5 +1,7 @@
 CONSOLE MESSAGE: line 44: Wrong node selected.
 CONSOLE MESSAGE: line 46: Wrong anchor offset: 8 instead of 0
+CONSOLE MESSAGE: line 41: Wrong end node type: [object HTMLBRElement]
+CONSOLE MESSAGE: line 44: Wrong node selected.
 | <html>
 |   <head>
 |   <body>
@@ -17,8 +19,7 @@ does not crash."
 |         style="margin: 0 0 0 40px; border: none; padding: 0px;"
 |         <pre>
 |           id="pre-basic"
-|           "line one
-"
+|           "line one"
 |       <pre>
 |         id="pre-basic"
 |         "line two
@@ -27,8 +28,7 @@ does not crash."
 |         class="webkit-indent-blockquote"
 |         style="margin: 0 0 0 40px; border: none; padding: 0px;"
 |         <pre>
-|           "line three
-"
+|           "line three"
 |         <pre>
 |           "line four"
 |       "
@@ -43,12 +43,11 @@ does not crash."
 |             <blockquote>
 |               class="webkit-indent-blockquote"
 |               style="margin: 0 0 0 40px; border: none; padding: 0px;"
-|               "list two
-"
-|               "list three
-"
-|             "list four
-"
+|               "list two"
+|               <br>
+|               "list three"
+|               <br>
+|               "list four"
 |       "
 
 "
@@ -66,8 +65,7 @@ does not crash."
 |                 class="webkit-indent-blockquote"
 |                 style="margin: 0 0 0 40px; border: none; padding: 0px;"
 |                 <pre>
-|                   "table two
-"
+|                   "table two"
 |                 <pre>
 |                   "table three<#selection-focus>"
 |             <td>
diff --git a/LayoutTests/editing/execCommand/indent-pre-list-expected.txt b/LayoutTests/editing/execCommand/indent-pre-list-expected.txt
new file mode 100644
index 0000000..52c172f
--- /dev/null
+++ b/LayoutTests/editing/execCommand/indent-pre-list-expected.txt
@@ -0,0 +1,167 @@
+
+Indenting:
+| "
+"
+| <pre>
+|   <ul>
+|     <li>
+|       "<#selection-anchor>hello<#selection-focus>"
+| "
+"
+
+yields:
+| "
+"
+| <pre>
+|   <ul>
+|     <ul>
+|       <li>
+|         "<#selection-anchor>hello<#selection-focus>"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   <ul>
+|     <li>
+|       "<#selection-anchor>hello
+world"
+|     "<#selection-focus>
+"
+| "
+"
+
+yields:
+| "
+"
+| <pre>
+|   <ul>
+|     <ul>
+|       <li>
+|         "<#selection-anchor>hello"
+|       <li>
+|         "world<#selection-focus>"
+|     "
+"
+| "
+"
+
+Indenting:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "<#selection-anchor>hello
+world
+webkit<#selection-focus>
+"
+| "
+"
+
+yields:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       <blockquote>
+|         class="webkit-indent-blockquote"
+|         style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|         "hello"
+|         <br>
+|         "world"
+|         <br>
+|         "webkit"
+| "
+"
+
+Indenting:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "<#selection-anchor>hello<#selection-focus>
+world
+webkit
+"
+| "
+"
+
+yields:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       <blockquote>
+|         class="webkit-indent-blockquote"
+|         style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|         "<#selection-anchor>hello<#selection-focus>"
+|       "world
+webkit
+"
+| "
+"
+
+Indenting:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "hello
+<#selection-anchor>world<#selection-focus>
+webkit
+"
+| "
+"
+
+yields:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "hello
+"
+|       <blockquote>
+|         class="webkit-indent-blockquote"
+|         style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|         "<#selection-anchor>world<#selection-focus>"
+|       "webkit
+"
+| "
+"
+
+Indenting:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "hello
+world
+<#selection-anchor>webki<#selection-focus>t
+"
+| "
+"
+
+yields:
+| "
+"
+| <ul>
+|   <li>
+|     <pre>
+|       "hello
+world
+"
+|       <blockquote>
+|         class="webkit-indent-blockquote"
+|         style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|         "<#selection-anchor>webki<#selection-focus>t"
+| "
+"
diff --git a/LayoutTests/editing/execCommand/indent-pre-list.html b/LayoutTests/editing/execCommand/indent-pre-list.html
new file mode 100644
index 0000000..116c94b
--- /dev/null
+++ b/LayoutTests/editing/execCommand/indent-pre-list.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/dump-as-markup.js"></script>
+<div id="test0" contenteditable>
+<pre>
+<ul><li>hello</li></ul></pre>
+</div>
+
+<div id="test1" contenteditable>
+<pre><ul><li>hello
+world</li>
+</ul></pre>
+</div>
+
+<div id="test2" contenteditable>
+<ul><li><pre>
+hello
+world
+webkit
+</pre></li></ul>
+</div>
+
+<div id="test3" contenteditable>
+<ul><li><pre>
+hello
+world
+webkit
+</pre></li></ul>
+</div>
+
+<div id="test4" contenteditable>
+<ul><li><pre>
+hello
+world
+webkit
+</pre></li></ul>
+</div>
+
+<div id="test5" contenteditable>
+<ul><li><pre>
+hello
+world
+webkit
+</pre></li></ul>
+</div>
+
+<script>
+
+function testIndentation(containerId, selector) {
+    var container = document.getElementById(containerId);
+    selector(container);
+    Markup.dump(container, 'Indenting');
+    document.execCommand('indent', false, null);
+    Markup.dump(container, 'yields');
+}
+
+function selectAll(container) {
+    window.getSelection().selectAllChildren(container);
+}
+
+function selectorForLineN(line) {
+    return function (container) {
+        window.getSelection().setPosition(container, 0);
+        for (var i = 0; i < line - 1; i++)
+            window.getSelection().modify('move', 'forward', 'line');
+        window.getSelection().modify('extend', 'forward', 'line');
+        // Avoid including \n at the end of line.
+        window.getSelection().modify('extend', 'backward', 'character');
+    }
+}
+
+testIndentation('test0', selectAll);
+testIndentation('test1', selectAll);
+testIndentation('test2', selectAll);
+testIndentation('test3', selectorForLineN(1));
+testIndentation('test4', selectorForLineN(2));
+testIndentation('test5', selectorForLineN(3));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/editing/execCommand/indent-pre-paragraphs-expected.txt b/LayoutTests/editing/execCommand/indent-pre-paragraphs-expected.txt
new file mode 100644
index 0000000..80b87ae
--- /dev/null
+++ b/LayoutTests/editing/execCommand/indent-pre-paragraphs-expected.txt
@@ -0,0 +1,160 @@
+
+Indenting:
+| "
+"
+| <pre>
+|   "<#selection-anchor>hello<#selection-focus>"
+| "
+"
+
+yields:
+| "
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "<#selection-anchor>hello<#selection-focus>"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   "<#selection-anchor>hello
+
+world
+
+webkit<#selection-focus>
+"
+| "
+"
+
+yields:
+| "
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "<#selection-anchor>hello"
+|   <pre>
+|     "
+"
+|   <pre>
+|     "world"
+|   <pre>
+|     "
+"
+|   <pre>
+|     "webkit<#selection-focus>"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   "<#selection-anchor>hello
+world
+webkit<#selection-focus>
+"
+| "
+"
+
+yields:
+| "
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "<#selection-anchor>hello"
+|   <pre>
+|     "world"
+|   <pre>
+|     "webkit<#selection-focus>"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   "<#selection-anchor>hello<#selection-focus>
+
+world
+"
+| "
+"
+
+yields:
+| "
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "<#selection-anchor>hello<#selection-focus>"
+| <pre>
+|   "
+world
+"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   "hello
+<#selection-caret>
+world
+"
+| "
+"
+
+yields:
+| "
+"
+| <pre>
+|   "hello<#selection-caret>
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "
+"
+| <pre>
+|   "world
+"
+| "
+"
+
+Indenting:
+| "
+"
+| <pre>
+|   "hello
+
+<#selection-anchor>worl<#selection-focus>d
+"
+| "
+"
+
+yields:
+| "
+"
+| <pre>
+|   "hello
+<#selection-anchor>
+"
+| <blockquote>
+|   class="webkit-indent-blockquote"
+|   style="margin: 0 0 0 40px; border: none; padding: 0px;"
+|   <pre>
+|     "worl<#selection-focus>d"
+| "
+"
diff --git a/LayoutTests/editing/execCommand/indent-pre-paragraphs.html b/LayoutTests/editing/execCommand/indent-pre-paragraphs.html
new file mode 100644
index 0000000..735d6c9
--- /dev/null
+++ b/LayoutTests/editing/execCommand/indent-pre-paragraphs.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/dump-as-markup.js"></script>
+<div id="test0" contenteditable>
+<pre>hello</pre>
+</div>
+
+<div id="test1" contenteditable>
+<pre>
+hello
+
+world
+
+webkit
+</pre>
+</div>
+
+<div id="test2" contenteditable>
+<pre>
+hello
+world
+webkit
+</pre>
+</div>
+
+<div id="test3" contenteditable>
+<pre>
+hello
+
+world
+</pre>
+</div>
+
+<div id="test4" contenteditable>
+<pre>
+hello
+
+world
+</pre>
+</div>
+
+<div id="test5" contenteditable>
+<pre>
+hello
+
+world
+</pre>
+</div>
+<script>
+
+function testIndentation(containerId, selector) {
+    var container = document.getElementById(containerId);
+    selector(container);
+    Markup.dump(container, 'Indenting');
+    document.execCommand('indent', false, null);
+    Markup.dump(container, 'yields');
+}
+
+function selectAll(container) {
+    window.getSelection().selectAllChildren(container);
+}
+
+function selectorForLineN(line) {
+    return function (container) {
+        window.getSelection().setPosition(container, 0);
+        for (var i = 0; i < line - 1; i++)
+            window.getSelection().modify('move', 'forward', 'line');
+        window.getSelection().modify('extend', 'forward', 'line');
+        window.getSelection().modify('extend', 'backward', 'character');
+    }
+}
+
+testIndentation('test0', selectAll);
+testIndentation('test1', selectAll);
+testIndentation('test2', selectAll);
+testIndentation('test3', selectorForLineN(1));
+testIndentation('test4', selectorForLineN(2));
+testIndentation('test5', selectorForLineN(3));
+
+</script>
+</body>
+</html>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 0eb8201..7a148ad 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,36 @@
+2010-10-07  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Tony Chang.
+
+        REGRESSION: Indenting pre duplicates content
+        https://bugs.webkit.org/show_bug.cgi?id=47233
+
+        The bug was caused by our not splitting text nodes properly.
+
+        In new approach, we split text nodes in each iteration. Added rangeForParagraphSplitingTextNodesIfNeeded
+        to split text nodes at the start and at the end of paragraph, which also adjusts start and end positions
+        for moveParagraphWithClones. Added endOfNextParagrahSplittingTextNodesIfNeeded to adjust endOfNextParagraph,
+        start, and end to work-around moveParagraphWithClones's removing a line feed.
+
+        Tests: editing/execCommand/indent-pre-list.html
+               editing/execCommand/indent-pre-paragraphs.html
+
+        * editing/ApplyBlockElementCommand.cpp:
+        (WebCore::ApplyBlockElementCommand::formatSelection): See above.
+        (WebCore::isNewLineAtPosition):
+        (WebCore::renderStyleOfEnclosingTextNode): Added.
+        (WebCore::ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded): Added.
+        (WebCore::ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded): Added.
+        * editing/ApplyBlockElementCommand.h:
+        * editing/FormatBlockCommand.cpp:
+        (WebCore::FormatBlockCommand::formatRange): Takes two Positions instead of one VisiblePosition.
+        * editing/FormatBlockCommand.h:
+        * editing/IndentOutdentCommand.cpp:
+        (WebCore::IndentOutdentCommand::tryIndentingAsListItem): Ditto.
+        (WebCore::IndentOutdentCommand::indentIntoBlockquote): Ditto.
+        (WebCore::IndentOutdentCommand::formatRange): Ditto.
+        * editing/IndentOutdentCommand.h:
+
 2010-10-07  Jian Li  <jianli at chromium.org>
 
         Reviewed by Adam Barth.
diff --git a/WebCore/editing/ApplyBlockElementCommand.cpp b/WebCore/editing/ApplyBlockElementCommand.cpp
index b2ce6f4..d810555 100644
--- a/WebCore/editing/ApplyBlockElementCommand.cpp
+++ b/WebCore/editing/ApplyBlockElementCommand.cpp
@@ -38,22 +38,6 @@
 namespace WebCore {
 
 using namespace HTMLNames;
-    
-// This function can return -1 if we are unable to count the paragraphs between |start| and |end|.
-static int countParagraphs(const VisiblePosition& endOfFirstParagraph, const VisiblePosition& endOfLastParagraph)
-{
-    int count = 0;
-    VisiblePosition cur = endOfFirstParagraph;
-    while (cur != endOfLastParagraph) {
-        ++count;
-        cur = endOfParagraph(cur.next());
-        // If start is before a table and end is inside a table, we will never hit end because the
-        // whole table is considered a single paragraph.
-        if (cur.isNull())
-            return -1;
-    }
-    return count;
-}
 
 ApplyBlockElementCommand::ApplyBlockElementCommand(Document* document, const QualifiedName& tagName, const AtomicString& className, const AtomicString& inlineStyle)
     : CompositeEditCommand(document)
@@ -125,30 +109,24 @@ void ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSel
     RefPtr<Element> blockquoteForNextIndent;
     VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection);
     VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
-    int endOfCurrentParagraphIndex = indexForVisiblePosition(endOfCurrentParagraph);
-    int endAfterSelectionIndex = indexForVisiblePosition(endAfterSelection);
-
-    // When indenting within a <pre> tag, we need to split each paragraph into a separate node for moveParagraphWithClones to work.
-    // However, splitting text nodes can cause endOfCurrentParagraph and endAfterSelection to point to an invalid position if we
-    // changed the text node it was pointing at.  So we have to reset these positions.
-    int numParagraphs = countParagraphs(endOfCurrentParagraph, endAfterSelection);
-    if (splitTextNodes(startOfParagraph(startOfSelection), numParagraphs + 1)) {
-        RefPtr<Range> endOfCurrentParagraphRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endOfCurrentParagraphIndex, 0, true);
-        RefPtr<Range> endAfterSelectionRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endAfterSelectionIndex, 0, true);
-        if (!endOfCurrentParagraphRange.get() || !endAfterSelectionRange.get()) {
-            ASSERT_NOT_REACHED();
-            return;
-        }
-        endOfCurrentParagraph = VisiblePosition(endOfCurrentParagraphRange->startPosition(), DOWNSTREAM);
-        endAfterSelection = VisiblePosition(endAfterSelectionRange->startPosition(), DOWNSTREAM);
-    }
+    VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection);
+
+    bool atEnd = false;
+    while (endOfCurrentParagraph != endAfterSelection && !atEnd) {
+        Position start;
+        Position end;
+
+        if (endOfCurrentParagraph == endOfLastParagraph)
+            atEnd = true;
 
-    while (endOfCurrentParagraph != endAfterSelection) {
-        // Iterate across the selected paragraphs...
-        VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
+        rangeForParagraphSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end);
+        endOfCurrentParagraph = end;
+
+        Position afterEnd = end.next();
         Node* enclosingCell = enclosingNodeOfType(start, &isTableCell);
+        VisiblePosition endOfNextParagraph = endOfNextParagrahSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end);
 
-        formatParagraph(endOfCurrentParagraph, blockquoteForNextIndent);
+        formatRange(start, end, blockquoteForNextIndent);
 
         // Don't put the next paragraph in the blockquote we just created for this paragraph unless 
         // the next paragraph is in the same cell.
@@ -170,6 +148,108 @@ void ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSel
     }
 }
 
+static bool isNewLineAtPosition(const Position& position)
+{
+    if (position.anchorType() != Position::PositionIsOffsetInAnchor)
+        return false;
+
+    Node* textNode = position.containerNode();
+    int offset = position.offsetInContainerNode();
+    if (!textNode || !textNode->isTextNode() || offset < 0 || offset >= textNode->maxCharacterOffset())
+        return false;
+
+    ExceptionCode ec = 0;
+    String textAtPosition = static_cast<Text*>(textNode)->substringData(offset, 1, ec);
+    if (ec)
+        return false;
+
+    return textAtPosition[0] == '\n';
+}
+
+static RenderStyle* renderStyleOfEnclosingTextNode(const Position& position)
+{
+    if (position.anchorType() != Position::PositionIsOffsetInAnchor
+        || !position.containerNode()
+        || !position.containerNode()->isTextNode()
+        || !position.containerNode()->renderer())
+        return 0;
+    return position.containerNode()->renderer()->style();
+}
+
+void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const VisiblePosition& endOfCurrentParagraph, Position& start, Position& end)
+{
+    start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
+    end = endOfCurrentParagraph.deepEquivalent();
+
+    RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start);
+    if (startStyle) {
+        // Avoid obtanining the start of next paragraph for start
+        if (startStyle->preserveNewline() && isNewLineAtPosition(start) && !isNewLineAtPosition(start.previous()) && start.offsetInContainerNode() > 0)
+            start = startOfParagraph(end.previous()).deepEquivalent();
+
+        // If start is in the middle of a text node, split.
+        if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) {
+            int startOffset = start.offsetInContainerNode();
+            splitTextNode(static_cast<Text*>(start.node()), startOffset);
+            start = positionBeforeNode(start.node());
+            if (start.node() == end.node()) {
+                ASSERT(end.offsetInContainerNode() >= startOffset);
+                end = Position(end.node(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor);
+            }
+        }
+    }
+
+    RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end);
+    if (endStyle) {
+        // Include \n at the end of line if we're at an empty paragraph
+        if (endStyle->preserveNewline() && start == end
+            && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
+            int endOffset = end.offsetInContainerNode();
+            if (!isNewLineAtPosition(end.previous()) && isNewLineAtPosition(end))
+                end = Position(end.node(), endOffset + 1, Position::PositionIsOffsetInAnchor);
+        }
+
+        // If end is in the middle of a text node, split.
+        if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode()
+            && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
+            splitTextNode(static_cast<Text*>(end.node()), end.offsetInContainerNode());
+            if (start.node() == end.node())
+                start = positionBeforeNode(end.node()->previousSibling());
+            end = lastPositionInNode(end.node()->previousSibling());
+        }
+    }
+}
+
+VisiblePosition ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded(VisiblePosition& endOfCurrentParagraph, Position& start, Position& end)
+{
+    VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
+    Position position = endOfNextParagraph.deepEquivalent();
+    RenderStyle* style = renderStyleOfEnclosingTextNode(position);
+    if (!style)
+        return endOfNextParagraph;
+
+    RefPtr<Node> containerNode = position.containerNode();
+    if (!style->preserveNewline() || !position.offsetInContainerNode()
+        || !isNewLineAtPosition(Position(containerNode.get(), 0, Position::PositionIsOffsetInAnchor)))
+        return endOfNextParagraph;
+
+    // \n at the beginning of the text node immediately following the current paragraph is trimmed by moveParagraphWithClones.
+    // If endOfNextParagraph was pointing at this same text node, endOfNextParagraph will be shifted by one paragraph.
+    // Avoid this by splitting "\n"
+    splitTextNode(static_cast<Text*>(containerNode.get()), 1);
+
+    if (start.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == start.containerNode()) {
+        ASSERT(start.offsetInContainerNode() < position.offsetInContainerNode());
+        start = Position(containerNode->previousSibling(), start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
+    }
+    if (end.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == end.containerNode()) {
+        ASSERT(end.offsetInContainerNode() < position.offsetInContainerNode());
+        end = Position(containerNode->previousSibling(), end.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
+    }
+
+    return Position(containerNode.get(), position.offsetInContainerNode() - 1, Position::PositionIsOffsetInAnchor);
+}
+
 PassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() const
 {
     RefPtr<Element> element = createHTMLElement(document(), m_tagName);
@@ -180,27 +260,4 @@ PassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() const
     return element.release();
 }
 
-// Returns true if at least one text node was split.
-bool ApplyBlockElementCommand::splitTextNodes(const VisiblePosition& start, int numParagraphs)
-{
-    VisiblePosition currentParagraphStart = start;
-    bool hasSplit = false;
-    int paragraphCount;
-    for (paragraphCount = 0; paragraphCount < numParagraphs; ++paragraphCount) {
-        // If there are multiple paragraphs in a single text node, we split the text node into a separate node for each paragraph.
-        if (currentParagraphStart.deepEquivalent().node()->isTextNode() && currentParagraphStart.deepEquivalent().node() == startOfParagraph(currentParagraphStart.previous()).deepEquivalent().node()) {
-            Text* textNode = static_cast<Text *>(currentParagraphStart.deepEquivalent().node());
-            int offset = currentParagraphStart.deepEquivalent().offsetInContainerNode();
-            splitTextNode(textNode, offset);
-            currentParagraphStart = VisiblePosition(textNode, 0, VP_DEFAULT_AFFINITY);
-            hasSplit = true;
-        }
-        VisiblePosition nextParagraph = startOfParagraph(endOfParagraph(currentParagraphStart).next());
-        if (nextParagraph.isNull())
-            break;
-        currentParagraphStart = nextParagraph;
-    }
-    return hasSplit;
-}
-
 }
diff --git a/WebCore/editing/ApplyBlockElementCommand.h b/WebCore/editing/ApplyBlockElementCommand.h
index 898b285..1fc4931 100644
--- a/WebCore/editing/ApplyBlockElementCommand.h
+++ b/WebCore/editing/ApplyBlockElementCommand.h
@@ -46,8 +46,9 @@ protected:
 
 private:
     virtual void doApply();
-    virtual void formatParagraph(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>&) = 0;
-    bool splitTextNodes(const VisiblePosition& start, int numParagraphs);
+    virtual void formatRange(const Position& start, const Position&, RefPtr<Element>&) = 0;
+    void rangeForParagraphSplittingTextNodesIfNeeded(const VisiblePosition&, Position&, Position&);
+    VisiblePosition endOfNextParagrahSplittingTextNodesIfNeeded(VisiblePosition&, Position&, Position&);
 
     QualifiedName m_tagName;
     AtomicString m_className;
diff --git a/WebCore/editing/FormatBlockCommand.cpp b/WebCore/editing/FormatBlockCommand.cpp
index e4ec872..c4e81e2 100644
--- a/WebCore/editing/FormatBlockCommand.cpp
+++ b/WebCore/editing/FormatBlockCommand.cpp
@@ -41,16 +41,17 @@ FormatBlockCommand::FormatBlockCommand(Document* document, const QualifiedName&
 {
 }
 
-void FormatBlockCommand::formatParagraph(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>&)
+void FormatBlockCommand::formatRange(const Position&, const Position& end, RefPtr<Element>&)
 {
-    setEndingSelection(endOfCurrentParagraph);
+    setEndingSelection(VisiblePosition(end));
+
     Node* refNode = enclosingBlockFlowElement(endingSelection().visibleStart());
     if (refNode->hasTagName(tagName()))
         // We're already in a block with the format we want, so we don't have to do anything
         return;
 
-    VisiblePosition paragraphStart = startOfParagraph(endingSelection().visibleStart());
-    VisiblePosition paragraphEnd = endOfParagraph(endingSelection().visibleStart());
+    VisiblePosition paragraphStart = startOfParagraph(end);
+    VisiblePosition paragraphEnd = endOfParagraph(end);
     VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart());
     VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart());
     RefPtr<Element> blockNode = createBlockElement();
diff --git a/WebCore/editing/FormatBlockCommand.h b/WebCore/editing/FormatBlockCommand.h
index 519ce37..5e9cb96 100644
--- a/WebCore/editing/FormatBlockCommand.h
+++ b/WebCore/editing/FormatBlockCommand.h
@@ -41,7 +41,7 @@ public:
 private:
     FormatBlockCommand(Document*, const QualifiedName& tagName);
 
-    virtual void formatParagraph(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>&);
+    virtual void formatRange(const Position&, const Position&, RefPtr<Element>&);
     virtual EditAction editingAction() const { return EditActionFormatBlock; }
 };
 
diff --git a/WebCore/editing/IndentOutdentCommand.cpp b/WebCore/editing/IndentOutdentCommand.cpp
index 1fe801a..c7ba744 100644
--- a/WebCore/editing/IndentOutdentCommand.cpp
+++ b/WebCore/editing/IndentOutdentCommand.cpp
@@ -56,10 +56,10 @@ IndentOutdentCommand::IndentOutdentCommand(Document* document, EIndentType typeO
 {
 }
 
-bool IndentOutdentCommand::tryIndentingAsListItem(const VisiblePosition& endOfCurrentParagraph)
+bool IndentOutdentCommand::tryIndentingAsListItem(const Position& start, const Position& end)
 {
     // If our selection is not inside a list, bail out.
-    Node* lastNodeInSelectedParagraph = endOfCurrentParagraph.deepEquivalent().node();
+    Node* lastNodeInSelectedParagraph = start.node();
     RefPtr<Element> listNode = enclosingList(lastNodeInSelectedParagraph);
     if (!listNode)
         return false;
@@ -78,7 +78,7 @@ bool IndentOutdentCommand::tryIndentingAsListItem(const VisiblePosition& endOfCu
     RefPtr<Element> newList = document()->createElement(listNode->tagQName(), false);
     insertNodeBefore(newList, selectedListItem);
 
-    moveParagraphWithClones(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, newList.get(), selectedListItem);
+    moveParagraphWithClones(start, end, newList.get(), selectedListItem);
 
     if (canMergeLists(previousList, newList.get()))
         mergeIdenticalElements(previousList, newList);
@@ -87,10 +87,9 @@ bool IndentOutdentCommand::tryIndentingAsListItem(const VisiblePosition& endOfCu
 
     return true;
 }
-    
-void IndentOutdentCommand::indentIntoBlockquote(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>& targetBlockquote)
+
+void IndentOutdentCommand::indentIntoBlockquote(const Position& start, const Position& end, RefPtr<Element>& targetBlockquote)
 {
-    Position start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
     Node* enclosingCell = enclosingNodeOfType(start, &isTableCell);
     Node* nodeToSplitTo;
     if (enclosingCell)
@@ -109,7 +108,7 @@ void IndentOutdentCommand::indentIntoBlockquote(const VisiblePosition& endOfCurr
         insertNodeBefore(targetBlockquote, outerBlock);
     }
 
-    moveParagraphWithClones(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, targetBlockquote.get(), outerBlock.get());
+    moveParagraphWithClones(start, end, targetBlockquote.get(), outerBlock.get());
 }
 
 void IndentOutdentCommand::outdentParagraph()
@@ -220,12 +219,12 @@ void IndentOutdentCommand::formatSelection(const VisiblePosition& startOfSelecti
         outdentRegion(startOfSelection, endOfSelection);
 }
 
-void IndentOutdentCommand::formatParagraph(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>& blockquoteForNextIndent)
+void IndentOutdentCommand::formatRange(const Position& start, const Position& end, RefPtr<Element>& blockquoteForNextIndent)
 {
-    if (tryIndentingAsListItem(endOfCurrentParagraph))
+    if (tryIndentingAsListItem(start, end))
         blockquoteForNextIndent = 0;
     else
-        indentIntoBlockquote(endOfCurrentParagraph, blockquoteForNextIndent);
+        indentIntoBlockquote(start, end, blockquoteForNextIndent);
 }
 
 }
diff --git a/WebCore/editing/IndentOutdentCommand.h b/WebCore/editing/IndentOutdentCommand.h
index 6777258..201e794 100644
--- a/WebCore/editing/IndentOutdentCommand.h
+++ b/WebCore/editing/IndentOutdentCommand.h
@@ -49,11 +49,11 @@ private:
     void indentRegion(const VisiblePosition&, const VisiblePosition&);
     void outdentRegion(const VisiblePosition&, const VisiblePosition&);
     void outdentParagraph();
-    bool tryIndentingAsListItem(const VisiblePosition&);
-    void indentIntoBlockquote(const VisiblePosition&, RefPtr<Element>&);
+    bool tryIndentingAsListItem(const Position&, const Position&);
+    void indentIntoBlockquote(const Position&, const Position&, RefPtr<Element>&);
 
     void formatSelection(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection);
-    void formatParagraph(const VisiblePosition& endOfCurrentParagraph, RefPtr<Element>& blockquoteForNextIndent);
+    void formatRange(const Position&, const Position&, RefPtr<Element>& blockquoteForNextIndent);
 
     EIndentType m_typeOfAction;
     int m_marginInPixels;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list