Bug 645914 - Do not eat the white-space when doing word selection if the eaten whitespace is a newline character and we have been instructed not to jump between lines; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 30 Mar 2011 11:56:48 -0400
changeset 64445 cbb7ffa045d365f3b027b95485f27e8a62386666
parent 64444 db8e95fbcd39b56b7ae7ad0877e774f9e046949b
child 64446 422bbd8245a728ebedbd64433dec253baa6c10d0
child 64483 2cea7ec127338e4f5882cba3fb40a51ad5424567
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs645914
milestone2.2a1pre
Bug 645914 - Do not eat the white-space when doing word selection if the eaten whitespace is a newline character and we have been instructed not to jump between lines; r=roc This fixes a bug in selecting words at the end of lines in textarea's for Windows.
editor/libeditor/text/tests/Makefile.in
editor/libeditor/text/tests/test_bug645914.html
layout/generic/nsFrame.cpp
--- a/editor/libeditor/text/tests/Makefile.in
+++ b/editor/libeditor/text/tests/Makefile.in
@@ -56,16 +56,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug600570.html \
 		test_bug602130.html \
 		test_bug603556.html \
 		test_bug604532.html \
 		test_bug625452.html \
 		test_bug629172.html \
 		test_bug638596.html \
 		test_bug641466.html \
+		test_bug645914.html \
 		$(NULL)
 
 # disables the key handling test on gtk2 because gtk2 overrides some key events
 # on our editor, and the combinations depend on the system.
 ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 _TEST_FILES += \
 		test_texteditor_keyevent_handling.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/text/tests/test_bug645914.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=645914
+-->
+<head>
+  <title>Test for Bug 645914</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=645914">Mozilla Bug 645914</a>
+<p id="display"></p>
+<div id="content">
+<textarea>foo
+bar</textarea>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 645914 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  var textarea = document.querySelector("textarea");
+  SpecialPowers.setBoolPref("layout.word_select.eat_space_to_next_word", true);
+  SpecialPowers.setBoolPref("browser.triple_click_selects_paragraph", false);
+
+  textarea.selectionStart = textarea.selectionEnd = 0;
+
+  // Simulate a double click on foo
+  synthesizeMouse(textarea, 5, 5, {clickCount: 2});
+
+  ok(true, "Testing word selection");
+  is(textarea.selectionStart, 0, "The start of the selection should be at the beginning of the text");
+  is(textarea.selectionEnd, 3, "The end of the selection should not include a newline character");
+
+  textarea.selectionStart = textarea.selectionEnd = 0;
+
+  // Simulate a triple click on foo
+  synthesizeMouse(textarea, 5, 5, {clickCount: 3});
+
+  ok(true, "Testing line selection");
+  is(textarea.selectionStart, 0, "The start of the selection should be at the beginning of the text");
+  is(textarea.selectionEnd, 3, "The end of the selection should not include a newline character");
+
+  textarea.selectionStart = textarea.selectionEnd = 0;
+  textarea.value = "Very very long value which would eventually overflow the visible section of the textarea";
+
+  // Simulate a quadruple click on Very
+  synthesizeMouse(textarea, 5, 5, {clickCount: 4});
+
+  ok(true, "Testing paragraph selection");
+  is(textarea.selectionStart, 0, "The start of the selection should be at the beginning of the text");
+  is(textarea.selectionEnd, textarea.value.length, "The end of the selection should be the end of the paragraph");
+
+  SpecialPowers.clearUserPref("layout.word_select.eat_space_to_next_word");
+  SpecialPowers.clearUserPref("browser.triple_click_selects_paragraph");
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5538,16 +5538,17 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct*
       // before the boundary we're looking for". Examples:
       // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
       //    between whitespace and non-whitespace), then eatingWS==PR_TRUE means
       //    "we already saw some whitespace".
       // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
       //    between non-whitespace and whitespace), then eatingWS==PR_TRUE means
       //    "we already saw some non-whitespace".
       PeekWordState state;
+      PRInt32 offsetAdjustment = 0;
       PRBool done = PR_FALSE;
       while (!done) {
         PRBool movingInFrameDirection =
           IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
         
         done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
                                        aPos->mIsKeyboardSelect, &offset, &state);
         
@@ -5559,16 +5560,23 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct*
             current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
                                            aPos->mJumpLines, aPos->mScrollViewStop,
                                            &nextFrame, &nextFrameOffset, &jumpedLine);
           // We can't jump lines if we're looking for whitespace following
           // non-whitespace, and we already encountered non-whitespace.
           if (NS_FAILED(result) ||
               (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
             done = PR_TRUE;
+            // If we've crossed the line boundary, check to make sure that we
+            // have not consumed a trailing newline as whitesapce if it's significant.
+            if (jumpedLine && wordSelectEatSpace &&
+                current->HasTerminalNewline() &&
+                current->GetStyleText()->NewlineIsSignificant()) {
+              offsetAdjustment = -1;
+            }
           } else {
             if (jumpedLine) {
               state.mContext.Truncate();
             }
             current = nextFrame;
             offset = nextFrameOffset;
             // Jumping a line is equivalent to encountering whitespace
             if (wordSelectEatSpace && jumpedLine)
@@ -5577,17 +5585,17 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct*
         }
       }
       
       // Set outputs
       range = GetRangeForFrame(current);
       aPos->mResultFrame = current;
       aPos->mResultContent = range.content;
       // Output offset is relative to content, not frame
-      aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
+      aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
       break;
     }
     case eSelectLine :
     {
       nsAutoLineIterator iter;
       nsIFrame *blockFrame = this;
 
       while (NS_FAILED(result)){