Bug 629172 - Fix the regression in switching the text input direction using Cmd/Ctrl+Shift+X; r=roc a=blocking-final+
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 27 Jan 2011 00:26:33 -0500
changeset 61556 3de1641119d1c5bb0a3daa9ae9e7f2fdce3bc0f6
parent 61555 7e5338ae09f9ce53057caed795d3c2541e023665
child 61557 e102c0b5f6f07afe5155ee1c9770b7934fa69f52
push idunknown
push userunknown
push dateunknown
reviewersroc, blocking-final
bugs629172
milestone2.0b11pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 629172 - Fix the regression in switching the text input direction using Cmd/Ctrl+Shift+X; r=roc a=blocking-final+
content/html/content/src/nsTextEditorState.cpp
editor/idl/nsIPlaintextEditor.idl
editor/libeditor/base/nsEditor.cpp
editor/libeditor/text/tests/Makefile.in
editor/libeditor/text/tests/test_bug629172.html
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1119,16 +1119,28 @@ nsTextEditorState::BindToFrame(nsTextCon
                                              (mTextListener));
   }
 
   // If an editor exists from before, prepare it for usage
   if (mEditor) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
     NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
 
+    // Set the correct direction on the newly created root node
+    PRUint32 flags;
+    rv = mEditor->GetFlags(&flags);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (flags & nsIPlaintextEditor::eEditorRightToLeft) {
+      rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), PR_FALSE);
+    } else if (flags & nsIPlaintextEditor::eEditorLeftToRight) {
+      rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), PR_FALSE);
+    } else {
+      // otherwise, inherit the content node's direction
+    }
+
     if (!nsContentUtils::AddScriptRunner(
           new PrepareEditorEvent(*this, content, currentValue)))
       return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
--- a/editor/idl/nsIPlaintextEditor.idl
+++ b/editor/idl/nsIPlaintextEditor.idl
@@ -66,16 +66,22 @@ interface nsIPlaintextEditor : nsISuppor
   const long eEditorNoCSSMask           = 0x0400;
   // whether HTML document specific actions are executed or not.
   // e.g., if this flag is set, the editor doesn't handle Tab key.
   // besides, anchors of HTML are not clickable.
   const long eEditorAllowInteraction    = 0x0800;
   // when this is set, the characters in password editor are always masked.
   // see bug 530367 for the detail.
   const long eEditorDontEchoPassword    = 0x1000;
+  // when this flag is set, the internal direction of the editor is RTL.
+  // if neither of the direction flags are set, the direction is determined
+  // from the text control's content node.
+  const long eEditorRightToLeft         = 0x2000;
+  // when this flag is set, the internal direction of the editor is LTR.
+  const long eEditorLeftToRight         = 0x4000;
 
   /*
    * The valid values for newlines handling.
    * Can't change the values unless we remove
    * use of the pref.
    */
   const long eNewlinesPasteIntact                = 0;
   const long eNewlinesPasteToFirst               = 1;
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -5170,27 +5170,50 @@ nsEditor::GetRoot()
 
 NS_IMETHODIMP
 nsEditor::SwitchTextDirection()
 {
   // Get the current root direction from its frame
   nsIDOMElement *rootElement = GetRoot();
 
   nsresult rv;
-  nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsIFrame *frame = content->GetPrimaryFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); 
+
+  // If we don't have an explicit direction, determine our direction
+  // from the content's direction
+  if (!(mFlags & (nsIPlaintextEditor::eEditorLeftToRight |
+                  nsIPlaintextEditor::eEditorRightToLeft))) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsIFrame* frame = content->GetPrimaryFrame();
+    NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+    // Set the flag here, to enable us to use the same code path below.
+    // It will be flipped before returning from the function.
+    if (frame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
+      mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
+    } else {
+      mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
+    }
+  }
 
   // Apply the opposite direction
-  if (frame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
+  if (mFlags & nsIPlaintextEditor::eEditorRightToLeft) {
+    NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
+                 "Unexpected mutually exclusive flag");
+    mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
+    mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
     rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("ltr"));
-  else
+  } else if (mFlags & nsIPlaintextEditor::eEditorLeftToRight) {
+    NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
+                 "Unexpected mutually exclusive flag");
+    mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
+    mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
     rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("rtl"));
+  }
 
   return rv;
 }
 
 #if DEBUG_JOE
 void
 nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
 {
--- a/editor/libeditor/text/tests/Makefile.in
+++ b/editor/libeditor/text/tests/Makefile.in
@@ -53,16 +53,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug596333.html \
 		test_bug596506.html \
 		test_bug597331.html \
 		test_bug600570.html \
 		test_bug602130.html \
 		test_bug603556.html \
 		test_bug604532.html \
 		test_bug625452.html \
+		test_bug629172.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_bug629172.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=629172
+-->
+<head>
+  <title>Test for Bug 629172</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>
+  <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.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=629172">Mozilla Bug 629172</a>
+<p id="display"></p>
+<div id="content">
+<textarea id="ltr-ref" style="display: none">test.</textarea>
+<textarea id="rtl-ref" style="display: none; direction: rtl">test.</textarea>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 629172 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  var LTRRef = document.getElementById("ltr-ref");
+  var RTLRef = document.getElementById("rtl-ref");
+  var Screenshots = {};
+
+  // generate the reference screenshots
+  LTRRef.style.display = "";
+  document.body.clientWidth;
+  Screenshots.ltr = snapshotWindow(window);
+  LTRRef.parentNode.removeChild(LTRRef);
+  RTLRef.style.display = "";
+  document.body.clientWidth;
+  Screenshots.rtl = snapshotWindow(window);
+  RTLRef.parentNode.removeChild(RTLRef);
+  Screenshots.get = function(dir, flip) {
+    if (flip) {
+      return this[dir == "rtl" ? "ltr" : "rtl"];
+    } else {
+      return this[dir];
+    }
+  };
+
+  function testDirection(initialDir) {
+    var t = document.createElement("textarea");
+    t.setAttribute("dir", initialDir);
+    t.value = "test.";
+    document.getElementById("content").appendChild(t);
+    document.body.clientWidth;
+    var s1 = snapshotWindow(window);
+    ok(compareSnapshots(s1, Screenshots.get(initialDir, false), true)[0],
+       "Textarea should appear correctly before switching the direction (" + initialDir + ")");
+    t.focus();
+    synthesizeKey("x", {accelKey: true, shiftKey: true});
+    t.blur();
+    var s2 = snapshotWindow(window);
+    ok(compareSnapshots(s2, Screenshots.get(initialDir, true), true)[0],
+       "Textarea should appear correctly after switching the direction (" + initialDir + ")");
+    t.focus();
+    synthesizeKey("x", {accelKey: true, shiftKey: true});
+    t.blur();
+    var s3 = snapshotWindow(window);
+    ok(compareSnapshots(s3, Screenshots.get(initialDir, false), true)[0],
+       "Textarea should appear correctly after switching back the direction (" + initialDir + ")");
+    t.parentNode.removeChild(t);
+  }
+
+  testDirection("ltr");
+  testDirection("rtl");
+
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>