Fix document.dir getters and setters to (a) work and (b) conform to HTML5. Bug 151407, r=ehsan
authorSimon Montagu <smontagu@smontagu.org>
Sun, 14 Apr 2013 05:37:48 -0700
changeset 140502 f3165dffa51cadd94d094486619226ff24f38959
parent 140501 59691d48243e05138a9cfcaf427356387b8563f8
child 140503 b17e0eb827c0d866e31875c9823768b1866cf8cb
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs151407
milestone23.0a1
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
Fix document.dir getters and setters to (a) work and (b) conform to HTML5. Bug 151407, r=ehsan
browser/base/content/browser.js
content/base/public/nsIDocument.h
content/base/src/DirectionalityUtils.cpp
content/base/src/nsDocument.cpp
dom/webidl/Document.webidl
layout/reftests/bidi/151407-1-ref.html
layout/reftests/bidi/151407-1.html
layout/reftests/bidi/151407-1a.html
layout/reftests/bidi/151407-2-auto-ref.html
layout/reftests/bidi/151407-2-auto.html
layout/reftests/bidi/151407-2-empty-ref.html
layout/reftests/bidi/151407-2-empty.html
layout/reftests/bidi/151407-2-foopy.html
layout/reftests/bidi/151407-2-ltr-ref.html
layout/reftests/bidi/151407-2-ltr.html
layout/reftests/bidi/151407-2-rtl-ref.html
layout/reftests/bidi/151407-2-rtl.html
layout/reftests/bidi/151407-3-auto-ref.html
layout/reftests/bidi/151407-3-auto.html
layout/reftests/bidi/151407-3-empty-ref.html
layout/reftests/bidi/151407-3-foopy.html
layout/reftests/bidi/151407-3-ltr-ref.html
layout/reftests/bidi/151407-3-ltr.html
layout/reftests/bidi/151407-3-rtl-ref.html
layout/reftests/bidi/151407-3-rtl.html
layout/reftests/bidi/reftest.list
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6134,17 +6134,22 @@ function AddKeywordForSearchField() {
                                    , hiddenRows: [ "location"
                                                  , "description"
                                                  , "tags"
                                                  , "loadInSidebar" ]
                                    }, window);
 }
 
 function SwitchDocumentDirection(aWindow) {
-  aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
+  // document.dir can also be "auto", in which case it won't change
+  if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
+    aWindow.document.dir = "rtl";
+  } else if (aWindow.document.dir == "rtl") {
+    aWindow.document.dir = "ltr";
+  }
   for (var run = 0; run < aWindow.frames.length; run++)
     SwitchDocumentDirection(aWindow.frames[run]);
 }
 
 function convertFromUnicode(charset, str)
 {
   try {
     var unicodeConverter = Components
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -18,17 +18,16 @@
 #include "nsILoadContext.h"              // for member (in nsCOMPtr)
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIScriptGlobalObject.h"       // for member (in nsCOMPtr)
 #include "nsIStructuredCloneContainer.h" // for member (in nsCOMPtr)
 #include "nsPIDOMWindow.h"               // for use in inline functions
 #include "nsPropertyTable.h"             // for member
 #include "nsTHashtable.h"                // for member
-#include "mozilla/dom/DirectionalityUtils.h"
 #include "mozilla/dom/DocumentBinding.h"
 
 class imgIRequest;
 class nsAString;
 class nsBindingManager;
 class nsCSSStyleSheet;
 class nsDOMNavigationTiming;
 class nsEventStates;
@@ -518,20 +517,16 @@ public:
    * Set the sandbox flags for this document.
    * @see nsSandboxFlags.h for the possible flags
    */
   void SetSandboxFlags(uint32_t sandboxFlags)
   {
     mSandboxFlags = sandboxFlags;
   }
 
-  inline mozilla::Directionality GetDocumentDirectionality() {
-    return mDirectionality;
-  }
-  
   /**
    * Access HTTP header data (this may also get set from other
    * sources, like HTML META tags).
    */
   virtual void GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const = 0;
   virtual void SetHeaderData(nsIAtom* aheaderField, const nsAString& aData) = 0;
 
   /**
@@ -636,17 +631,17 @@ public:
   }
 
 protected:
   virtual Element *GetRootElementInternal() const = 0;
 
 public:
   // Get the root <html> element, or return null if there isn't one (e.g.
   // if the root isn't <html>)
-  Element* GetHtmlElement();
+  Element* GetHtmlElement() const;
   // Returns the first child of GetHtmlContent which has the given tag,
   // or nullptr if that doesn't exist.
   Element* GetHtmlChildElement(nsIAtom* aTag);
   // Get the canonical <body> element, or return null if there isn't one (e.g.
   // if the root isn't <html> or if the <body> isn't there)
   mozilla::dom::HTMLBodyElement* GetBodyElement();
   // Get the canonical <head> element, or return null if there isn't one (e.g.
   // if the root isn't <html> or if the <head> isn't there)
@@ -1996,17 +1991,17 @@ public:
   void GetLastModified(nsAString& aLastModified) const;
   void GetReadyState(nsAString& aReadyState) const;
   // Not const because otherwise the compiler can't figure out whether to call
   // this GetTitle or the nsAString version from non-const methods, since
   // neither is an exact match.
   virtual void GetTitle(nsString& aTitle) = 0;
   virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv) = 0;
   void GetDir(nsAString& aDirection) const;
-  void SetDir(const nsAString& aDirection, mozilla::ErrorResult& rv);
+  void SetDir(const nsAString& aDirection);
   nsIDOMWindow* GetDefaultView() const
   {
     return GetWindow();
   }
   Element* GetActiveElement();
   bool HasFocus(mozilla::ErrorResult& rv) const;
   // Event handlers are all on nsINode already
   bool MozSyntheticDocument() const
@@ -2145,22 +2140,16 @@ protected:
     mContentType = aType;
   }
 
   nsCString GetContentTypeInternal() const
   {
     return mContentType;
   }
 
-  inline void
-  SetDocumentDirectionality(mozilla::Directionality aDir)
-  {
-    mDirectionality = aDir;
-  }
-
   // All document WrapNode implementations MUST call this method.  A
   // false return value means an exception was thrown.
   bool PostCreateWrapper(JSContext* aCx, JSObject *aNewObject);
 
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
@@ -2330,19 +2319,16 @@ protected:
   // defined in nsBidiUtils.h
   uint32_t mBidiOptions;
 
   // The sandbox flags on the document. These reflect the value of the sandbox attribute of the
   // associated IFRAME or CSP-protectable content, if existent. These are set at load time and
   // are immutable - see nsSandboxFlags.h for the possible flags.
   uint32_t mSandboxFlags;
 
-  // The root directionality of this document.
-  mozilla::Directionality mDirectionality;
-
   nsCString mContentLanguage;
 private:
   nsCString mContentType;
 protected:
 
   // The document's security info
   nsCOMPtr<nsISupports> mSecurityInfo;
 
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -595,23 +595,19 @@ RecomputeDirectionality(Element* aElemen
       // If the element doesn't have an explicit dir attribute with a valid
       // value, the directionality is the same as the parent element (but
       // don't propagate the parent directionality if it isn't set yet).
       Directionality parentDir = parent->GetDirectionality();
       if (parentDir != eDir_NotSet) {
         dir = parentDir;
       }
     } else {
-      // If there is no parent element, the directionality is the same as the
-      // document direction.
-      Directionality documentDir =
-        aElement->OwnerDoc()->GetDocumentDirectionality();
-      if (documentDir != eDir_NotSet) {
-        dir = documentDir;
-      }
+      // If there is no parent element and no dir attribute, the directionality
+      // is LTR.
+      dir = eDir_LTR;
     }
 
     aElement->SetDirectionality(dir, aNotify);
   }
   return dir;
 }
 
 void
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -89,17 +89,16 @@
 #include "nsFocusManager.h"
 
 // for radio group stuff
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIFormControl.h"
 
 #include "nsBidiUtils.h"
-#include "mozilla/dom/DirectionalityUtils.h"
 
 #include "nsIDOMUserDataHandler.h"
 #include "nsIDOMXPathEvaluator.h"
 #include "nsIDOMXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsIXPathEvaluatorInternal.h"
 #include "nsIParserService.h"
 #include "nsContentCreatorFunctions.h"
@@ -1318,17 +1317,16 @@ nsIDocument::nsIDocument()
     mRemovedFromDocShell(false),
     // mAllowDNSPrefetch starts true, so that we can always reliably && it
     // with various values that might disable it.  Since we never prefetch
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
     mAllowDNSPrefetch(true),
     mIsBeingUsedAsImage(false),
     mHasLinksToUpdate(false),
-    mDirectionality(eDir_LTR),
     mPartID(0)
 {
   SetInDocument();
 }
 
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
 
@@ -5777,17 +5775,17 @@ nsIDocument::GetLocation() const
   }
 
   nsCOMPtr<nsIDOMLocation> loc;
   w->GetLocation(getter_AddRefs(loc));
   return loc.forget();
 }
 
 Element*
-nsIDocument::GetHtmlElement()
+nsIDocument::GetHtmlElement() const
 {
   Element* rootElement = GetRootElement();
   if (rootElement && rootElement->IsHTML(nsGkAtoms::html))
     return rootElement;
   return nullptr;
 }
 
 Element*
@@ -6236,98 +6234,66 @@ nsDocument::GetAnimationController()
   // because they don't get OnPageShow / OnPageHide calls).
   if (!mIsShowing && !mIsBeingUsedAsImage) {
     mAnimationController->OnPageHide();
   }
 
   return mAnimationController;
 }
 
-struct DirTable {
-  const char* mName;
-  uint8_t     mValue;
-};
-
-static const DirTable dirAttributes[] = {
-  {"ltr", IBMBIDI_TEXTDIRECTION_LTR},
-  {"rtl", IBMBIDI_TEXTDIRECTION_RTL},
-  {0}
-};
+static const char* dirAttributes[] = { "ltr", "rtl", "auto", 0 };
 
 /**
  * Retrieve the "direction" property of the document.
  *
  * @lina 01/09/2001
  */
 NS_IMETHODIMP
 nsDocument::GetDir(nsAString& aDirection)
 {
   nsIDocument::GetDir(aDirection);
   return NS_OK;
 }
 
 void
 nsIDocument::GetDir(nsAString& aDirection) const
 {
-  uint32_t options = GetBidiOptions();
-  for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
-    if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) {
-      CopyASCIItoUTF16(elt->mName, aDirection);
-      return;
+  aDirection.Truncate();
+  Element* rootElement = GetHtmlElement();
+  if (rootElement) {
+    nsAutoString dir;
+    rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir);
+    for (uint32_t i = 0; dirAttributes[i]; ++i) {
+      if (dir.LowerCaseEqualsASCII(dirAttributes[i])) {
+        aDirection.AssignASCII(dirAttributes[i]);
+        return;
+      }
     }
   }
 }
 
 /**
  * Set the "direction" property of the document.
  *
  * @lina 01/09/2001
  */
 NS_IMETHODIMP
 nsDocument::SetDir(const nsAString& aDirection)
 {
-  ErrorResult rv;
-  nsIDocument::SetDir(aDirection, rv);
-  return rv.ErrorCode();
-}
-
-void
-nsIDocument::SetDir(const nsAString& aDirection, ErrorResult& rv)
-{
-  uint32_t options = GetBidiOptions();
-
-  for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
-    if (aDirection == NS_ConvertASCIItoUTF16(elt->mName)) {
-      if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) {
-        SET_BIDI_OPTION_DIRECTION(options, elt->mValue);
-        nsIPresShell *shell = GetShell();
-        if (shell) {
-          nsPresContext *context = shell->GetPresContext();
-          if (!context) {
-            rv.Throw(NS_ERROR_UNEXPECTED);
-            return;
-          }
-          context->SetBidi(options, true);
-        } else {
-          // No presentation; just set it on ourselves
-          SetBidiOptions(options);
-        }
-        Directionality dir = elt->mValue == IBMBIDI_TEXTDIRECTION_RTL ?
-                               eDir_RTL : eDir_LTR;
-        SetDocumentDirectionality(dir);
-        // Set the directionality of the root element and its descendants, if any
-        Element* rootElement = GetRootElement();
-        if (rootElement) {
-          rootElement->SetDirectionality(dir, true);
-          SetDirectionalityOnDescendants(rootElement, dir);
-        }
-      }
-
-      break;
-    }
+  nsIDocument::SetDir(aDirection);
+  return NS_OK;
+}
+
+void
+nsIDocument::SetDir(const nsAString& aDirection)
+{
+  Element* rootElement = GetHtmlElement();
+  if (rootElement) {
+    rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
+                         aDirection, true);
   }
 }
 
 NS_IMETHODIMP
 nsDocument::GetInputEncoding(nsAString& aInputEncoding)
 {
   nsIDocument::GetInputEncoding(aInputEncoding);
   return NS_OK;
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -95,17 +95,16 @@ partial interface Document {
   //(HTML only)         attribute DOMString cookie;
   readonly attribute DOMString lastModified;
   readonly attribute DOMString readyState;
 
   // DOM tree accessors
   //(Not proxy yet)getter object (DOMString name);
            [SetterThrows]
            attribute DOMString title;
-           [SetterThrows]
            attribute DOMString dir;
   //(HTML only)         attribute HTMLElement? body;
   //(HTML only)readonly attribute HTMLHeadElement? head;
   //(HTML only)readonly attribute HTMLCollection images;
   //(HTML only)readonly attribute HTMLCollection embeds;
   //(HTML only)readonly attribute HTMLCollection plugins;
   //(HTML only)readonly attribute HTMLCollection links;
   //(HTML only)readonly attribute HTMLCollection forms;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for elements</title>
+  </head>
+  <body>
+    <div dir="">dir="", getDir returns ""</div>
+    <div dir="ltr">dir="ltr", getDir returns "ltr"</div>
+    <div dir="rtl">dir="rtl", getDir returns "rtl"</div>
+    <div dir="auto">dir="auto", getDir returns "auto"</div>
+    <div dir="foopy">dir="foopy", getDir returns ""</div>
+    <div>no dir attribute, getDir returns ""</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for elements</title>
+    <script type="text/javascript">
+function fill() {
+    for (var i = 0; ; ++i) {
+	div = document.getElementById("div" + i);
+	if (!div) break;
+	span = document.getElementById("span" + i);
+	span.innerHTML = div.dir;
+    }
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div id="div0" dir="">dir="", getDir returns "<span id="span0"></span>"</div>
+    <div id="div1" dir="ltr">dir="ltr", getDir returns "<span id="span1"></span>"</div>
+    <div id="div2" dir="rtl">dir="rtl", getDir returns "<span id="span2"></span>"</div>
+    <div id="div3" dir="auto">dir="auto", getDir returns "<span id="span3"></span>"</div>
+    <div id="div4" dir="foopy">dir="foopy", getDir returns "<span id="span4"></span>"</div>
+    <div id="div5">no dir attribute, getDir returns "<span id="span5"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-1a.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for elements</title>
+    <script type="text/javascript">
+function fill() {
+    div0.dir = "";
+    div1.dir = "ltr";
+    div2.dir = "rtl";
+    div3.dir = "auto";
+    div4.dir = "foopy";
+
+    for (var i = 0; ; ++i) {
+	div = document.getElementById("div" + i);
+	if (!div) break;
+	span = document.getElementById("span" + i);
+	span.innerHTML = div.dir;
+    }
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div id="div0">dir="", getDir returns "<span id="span0"></span>"</div>
+    <div id="div1">dir="ltr", getDir returns "<span id="span1"></span>"</div>
+    <div id="div2">dir="rtl", getDir returns "<span id="span2"></span>"</div>
+    <div id="div3">dir="auto", getDir returns "<span id="span3"></span>"</div>
+    <div id="div4">dir="foopy", getDir returns "<span id="span4"></span>"</div>
+    <div id="div5">no dir attribute, getDir returns "<span id="span5"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-auto-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html dir="auto">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document returns "auto"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-auto.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html dir="auto">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-empty-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document returns ""</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-empty.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-foopy.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html dir="foopy">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-ltr-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document returns "ltr"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-ltr.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-rtl-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document returns "rtl"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-2-rtl.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test GetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-auto-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document after setDir returns "auto"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-auto.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    document.dir = "auto"
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document after setDir returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-empty-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document after setDir returns ""</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-foopy.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    document.dir = "foopy"
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document after setDir returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-ltr-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document after setDir returns "ltr"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-ltr.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    document.dir = "ltr"
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document after setDir returns "<span id="span0"></span>"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-rtl-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html dir="rtl">
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+  </head>
+  <body>
+    <div>getDir on document after setDir returns "rtl"</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/151407-3-rtl.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <title>Test SetDir() for documents</title>
+    <script type="text/javascript">
+function fill() {
+    document.dir = "rtl"
+    span = document.getElementById("span0");
+    span.innerHTML = document.dir;
+}
+    </script>
+  </head>
+  <body onLoad="fill()">
+    <div>getDir on document after setDir returns "<span id="span0"></span>"</div>
+  </body>
+</html>
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -49,16 +49,27 @@ random-if(cocoaWidget) == with-first-let
 == 83958-1a.html 83958-1-ref.html
 == 83958-1b.html 83958-1-ref.html
 == 83958-1c.html 83958-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2a.html 83958-2-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2b.html 83958-2-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2c.html 83958-2-ref.html
 == 115921-1.html 115921-1-ref.html
 == 115921-2.html 115921-2-ref.html
+== 151407-1.html 151407-1-ref.html
+== 151407-1a.html 151407-1-ref.html
+== 151407-2-ltr.html 151407-2-ltr-ref.html
+== 151407-2-rtl.html 151407-2-rtl-ref.html
+== 151407-2-auto.html 151407-2-auto-ref.html
+== 151407-2-empty.html 151407-2-empty-ref.html
+== 151407-2-foopy.html 151407-2-empty-ref.html
+== 151407-3-ltr.html 151407-3-ltr-ref.html
+== 151407-3-rtl.html 151407-3-rtl-ref.html
+== 151407-3-auto.html 151407-3-auto-ref.html
+== 151407-3-foopy.html 151407-3-empty-ref.html
 == 229367-1.html 229367-1-ref.html
 == 229367-2.html 229367-2-ref.html
 == 229367-3.html 229367-3-ref.html
 == 258928-1.html 258928-1-ref.html
 == 263359-1.html 263359-1-ref.html
 == 263359-1a.html 263359-1-ref.html
 != 263359-1b.html 263359-1-ref.html
 == 263359-2.html 263359-2-ref.html