Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorDaniel Varga <dvarga@mozilla.com>
Mon, 31 Dec 2018 23:26:34 +0200
changeset 509326 2f42b03f9e8fc93439c11c6d65a066325b1c3796
parent 509325 1a2501b02a56344234a72e519c2a1ede2cb217c9 (current diff)
parent 509315 595b7807fb110bbb87717938a2f85bd083b608f3 (diff)
child 509327 605aa74c29e369941cbf83c23492322c1256915c
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.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
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
dom/svg/nsSVGFeatures.cpp
dom/svg/nsSVGFeatures.h
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -51,17 +51,20 @@ nsINodeList* nsDOMMutationRecord::Remove
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationRecord)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord)
+// Break down the linked list so that cycle collector can delete the
+// objects sooner.
+NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsDOMMutationRecord,
+                                                   mNext = nullptr)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, mTarget,
                                       mPreviousSibling, mNextSibling,
                                       mAddedNodes, mRemovedNodes,
                                       mAddedAnimations, mRemovedAnimations,
                                       mChangedAnimations, mNext, mOwner)
 
 // Observer
--- a/dom/svg/SVGTests.cpp
+++ b/dom/svg/SVGTests.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGTests.h"
 #include "DOMSVGStringList.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
-#include "nsSVGFeatures.h"
 #include "mozilla/dom/SVGSwitchElement.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsStyleUtil.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -37,19 +36,27 @@ already_AddRefed<DOMSVGStringList> SVGTe
                                          AsSVGElement(), true, EXTENSIONS);
 }
 
 already_AddRefed<DOMSVGStringList> SVGTests::SystemLanguage() {
   return DOMSVGStringList::GetDOMWrapper(&mStringListAttributes[LANGUAGE],
                                          AsSVGElement(), true, LANGUAGE);
 }
 
-bool SVGTests::HasExtension(const nsAString& aExtension) {
-  return nsSVGFeatures::HasExtension(aExtension,
-                                     AsSVGElement()->IsInChromeDocument());
+bool SVGTests::HasExtension(const nsAString& aExtension) const {
+#define SVG_SUPPORTED_EXTENSION(str) \
+  if (aExtension.EqualsLiteral(str)) return true;
+  SVG_SUPPORTED_EXTENSION("http://www.w3.org/1999/xhtml")
+  nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
+  if (AsSVGElement()->IsInChromeDocument() || !nameSpaceManager->mMathMLDisabled) {
+    SVG_SUPPORTED_EXTENSION("http://www.w3.org/1998/Math/MathML")
+  }
+#undef SVG_SUPPORTED_EXTENSION
+
+  return false;
 }
 
 bool SVGTests::IsConditionalProcessingAttribute(
     const nsAtom* aAttribute) const {
   for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
     if (aAttribute == sStringListNames[i]) {
       return true;
     }
@@ -104,18 +111,17 @@ bool SVGTests::PassesConditionalProcessi
   // go beyond the feature set defined in the SVG specification.
   // Each extension is identified by a URI reference.
   // For now, claim that mozilla's SVG implementation supports XHTML and MathML.
   if (mStringListAttributes[EXTENSIONS].IsExplicitlySet()) {
     if (mStringListAttributes[EXTENSIONS].IsEmpty()) {
       return false;
     }
     for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) {
-      if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i],
-                                       AsSVGElement()->IsInChromeDocument())) {
+      if (!HasExtension(mStringListAttributes[EXTENSIONS][i])) {
         return false;
       }
     }
   }
 
   if (aAcceptLangs == kIgnoreSystemLanguage) {
     return true;
   }
--- a/dom/svg/SVGTests.h
+++ b/dom/svg/SVGTests.h
@@ -91,17 +91,17 @@ class SVGTests : public nsISupports {
   void GetAttrValue(uint8_t aAttrEnum, nsAttrValue& aValue) const;
 
   void MaybeInvalidate();
 
   // WebIDL
   already_AddRefed<DOMSVGStringList> RequiredFeatures();
   already_AddRefed<DOMSVGStringList> RequiredExtensions();
   already_AddRefed<DOMSVGStringList> SystemLanguage();
-  bool HasExtension(const nsAString& aExtension);
+  bool HasExtension(const nsAString& aExtension) const;
 
   virtual SVGElement* AsSVGElement() = 0;
 
   const SVGElement* AsSVGElement() const {
     return const_cast<SVGTests*>(this)->AsSVGElement();
   }
 
  protected:
--- a/dom/svg/moz.build
+++ b/dom/svg/moz.build
@@ -6,17 +6,16 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "SVG")
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsSVGClass.h',
-    'nsSVGFeatures.h',
 ]
 
 EXPORTS.mozilla += [
     'SVGAttrValueWrapper.h',
     'SVGContentUtils.h',
     'SVGPreserveAspectRatio.h',
     'SVGStringList.h',
     'SVGTagList.h',
@@ -126,17 +125,16 @@ UNIFIED_SOURCES += [
     'DOMSVGStringList.cpp',
     'DOMSVGTransform.cpp',
     'DOMSVGTransformList.cpp',
     'nsISVGPoint.cpp',
     'nsSVGAngle.cpp',
     'nsSVGBoolean.cpp',
     'nsSVGClass.cpp',
     'nsSVGEnum.cpp',
-    'nsSVGFeatures.cpp',
     'nsSVGInteger.cpp',
     'nsSVGIntegerPair.cpp',
     'nsSVGLength2.cpp',
     'nsSVGNumber2.cpp',
     'nsSVGNumberPair.cpp',
     'nsSVGString.cpp',
     'nsSVGViewBox.cpp',
     'SVGAElement.cpp',
deleted file mode 100644
--- a/dom/svg/nsSVGFeatures.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * This file contains code to help implement the Conditional Processing
- * section of the SVG specification (i.e. the <switch> element and the
- * requiredFeatures, requiredExtensions and systemLanguage attributes).
- *
- *   http://www.w3.org/TR/SVG11/struct.html#ConditionalProcessing
- */
-
-#include "nsSVGFeatures.h"
-#include "nsIContent.h"
-#include "nsIDocument.h"
-#include "nsNameSpaceManager.h"
-#include "mozilla/Preferences.h"
-
-using namespace mozilla;
-
-/*static*/ bool nsSVGFeatures::HasExtension(const nsAString& aExtension,
-                                            const bool aIsInChrome) {
-#define SVG_SUPPORTED_EXTENSION(str) \
-  if (aExtension.EqualsLiteral(str)) return true;
-  SVG_SUPPORTED_EXTENSION("http://www.w3.org/1999/xhtml")
-  nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
-  if (aIsInChrome || !nameSpaceManager->mMathMLDisabled) {
-    SVG_SUPPORTED_EXTENSION("http://www.w3.org/1998/Math/MathML")
-  }
-#undef SVG_SUPPORTED_EXTENSION
-
-  return false;
-}
deleted file mode 100644
--- a/dom/svg/nsSVGFeatures.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef __NS_SVGFEATURES_H__
-#define __NS_SVGFEATURES_H__
-
-#include "nsString.h"
-
-class nsSVGFeatures {
- public:
-  /**
-   * Check whether we support the given extension string.
-   *
-   * @param aExtension the URI of an extension. Known extensions are
-   *   "http://www.w3.org/1999/xhtml" and "http://www.w3.org/1998/Math/MathML"
-   */
-  static bool HasExtension(const nsAString& aExtension, const bool aIsInChrome);
-};
-
-#endif  // __NS_SVGFEATURES_H__
--- a/js/src/jit-test/tests/ctypes/conversion-finalizer.js
+++ b/js/src/jit-test/tests/ctypes/conversion-finalizer.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: !getBuildConfiguration()['x86'] && !getBuildConfiguration()['x64']
+// Skip on non x86/x64 until Bug 1511615 is fixed for arm7/arm64.
 load(libdir + 'asserts.js');
 
 function test() {
   // non object
   assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, "foo"); },
                          "expected _a CData object_ of a function pointer type, got the string \"foo\"");
   // non CData object
   assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, ["foo"]); },
--- a/js/src/jit-test/tests/wasm/atomic.js
+++ b/js/src/jit-test/tests/wasm/atomic.js
@@ -1,9 +1,10 @@
-// |jit-test| skip-if: !wasmThreadsSupported()
+// |jit-test| skip-if: !wasmThreadsSupported() || getBuildConfiguration()['arm64']
+// skip arm64 due to bug 1513231
 
 const oob = /index out of bounds/;
 const unaligned = /unaligned memory access/;
 const RuntimeError = WebAssembly.RuntimeError;
 
 // Check that the output of wasmTextToBinary verifies correctly.
 
 let SHARED = 'shared';
--- a/js/src/jit-test/tests/wasm/baseline-abs-addr-opt.js
+++ b/js/src/jit-test/tests/wasm/baseline-abs-addr-opt.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: getBuildConfiguration()['arm64']
+// skip arm64 due to bug 1513231
 // Test bounds checking at the end of memory with a constant base pointer.
 // This is intended to verify a bounds check elimination optimization in
 // the baseline compiler.
 
 // This can be only a functional test, we can't really see whether
 // the optimization is being applied.  However, manual inspection
 // of the generated code has verified that the optimization is
 // being applied.
--- a/js/src/jit-test/tests/wasm/bce.js
+++ b/js/src/jit-test/tests/wasm/bce.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: getBuildConfiguration()['arm64']
+// skip arm64 due to bug 1513231
 mem='\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'+
     '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'+
     '\x00'.repeat(65488) +
     '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
 
 let accessWidth = {
   '8_s':  1,
   '8_u':  1,
--- a/js/src/jit-test/tests/wasm/memory.js
+++ b/js/src/jit-test/tests/wasm/memory.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: getBuildConfiguration()['arm64']
+// skip arm64 due to bug 1513231
 const RuntimeError = WebAssembly.RuntimeError;
 
 function loadModuleSrc(type, ext, offset, align, drop = false) {
     let maybeResult = drop ? '' : `(result ${type})`;
     let maybeDrop = drop ? 'drop' : '';
     return `(module
        (memory 1)
        (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
--- a/js/src/jit-test/tests/wasm/spec/float_memory.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/float_memory.wast.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: !getBuildConfiguration()['x86'] && !getBuildConfiguration()['x64'] && !getBuildConfiguration()['arm64']
+// skip arm7 due to bug 1513231
 
 // float_memory.wast:5
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8c\x80\x80\x80\x00\x03\x60\x00\x01\x7d\x60\x00\x01\x7f\x60\x00\x00\x03\x86\x80\x80\x80\x00\x05\x00\x01\x02\x02\x02\x05\x84\x80\x80\x80\x00\x01\x01\x01\x01\x07\xb7\x80\x80\x80\x00\x05\x08\x66\x33\x32\x2e\x6c\x6f\x61\x64\x00\x00\x08\x69\x33\x32\x2e\x6c\x6f\x61\x64\x00\x01\x09\x66\x33\x32\x2e\x73\x74\x6f\x72\x65\x00\x02\x09\x69\x33\x32\x2e\x73\x74\x6f\x72\x65\x00\x03\x05\x72\x65\x73\x65\x74\x00\x04\x0a\xca\x80\x80\x80\x00\x05\x87\x80\x80\x80\x00\x00\x41\x00\x2a\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x00\x28\x02\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x43\x00\x00\xa0\x7f\x38\x02\x00\x0b\x8d\x80\x80\x80\x00\x00\x41\x00\x41\x80\x80\x80\xfd\x07\x36\x02\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x00\x41\x00\x36\x02\x00\x0b\x0b\x8a\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x04\x00\x00\xa0\x7f");
 
 // float_memory.wast:15
 assert_return(() => call($1, "i32.load", []), 2141192192);
 
 // float_memory.wast:16
--- a/js/src/jit-test/tests/wasm/spec/memory_redundancy.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/memory_redundancy.wast.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: !getBuildConfiguration()['x86'] && !getBuildConfiguration()['x64'] && !getBuildConfiguration()['arm64']
+// skip arm7 due to bug 1513231
 
 // memory_redundancy.wast:5
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8c\x80\x80\x80\x00\x03\x60\x00\x00\x60\x00\x01\x7f\x60\x00\x01\x7d\x03\x85\x80\x80\x80\x00\x04\x00\x01\x01\x02\x05\x84\x80\x80\x80\x00\x01\x01\x01\x01\x07\xd0\x80\x80\x80\x00\x04\x0f\x7a\x65\x72\x6f\x5f\x65\x76\x65\x72\x79\x74\x68\x69\x6e\x67\x00\x00\x12\x74\x65\x73\x74\x5f\x73\x74\x6f\x72\x65\x5f\x74\x6f\x5f\x6c\x6f\x61\x64\x00\x01\x13\x74\x65\x73\x74\x5f\x72\x65\x64\x75\x6e\x64\x61\x6e\x74\x5f\x6c\x6f\x61\x64\x00\x02\x0f\x74\x65\x73\x74\x5f\x64\x65\x61\x64\x5f\x73\x74\x6f\x72\x65\x00\x03\x0a\x8c\x81\x80\x80\x00\x04\x9e\x80\x80\x80\x00\x00\x41\x00\x41\x00\x36\x02\x00\x41\x04\x41\x00\x36\x02\x00\x41\x08\x41\x00\x36\x02\x00\x41\x0c\x41\x00\x36\x02\x00\x0b\x98\x80\x80\x80\x00\x00\x41\x08\x41\x00\x36\x02\x00\x41\x05\x43\x00\x00\x00\x80\x38\x02\x00\x41\x08\x28\x02\x00\x0b\xa2\x80\x80\x80\x00\x01\x02\x7f\x41\x08\x28\x02\x00\x21\x00\x41\x05\x41\x80\x80\x80\x80\x78\x36\x02\x00\x41\x08\x28\x02\x00\x21\x01\x20\x00\x20\x01\x6a\x0b\x9f\x80\x80\x80\x00\x01\x01\x7d\x41\x08\x41\xa3\xc6\x8c\x99\x02\x36\x02\x00\x41\x0b\x2a\x02\x00\x21\x00\x41\x08\x41\x00\x36\x02\x00\x20\x00\x0b");
 
 // memory_redundancy.wast:39
 assert_return(() => call($1, "test_store_to_load", []), 128);
 
 // memory_redundancy.wast:40
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -507,16 +507,21 @@ def check_output(out, err, rc, timed_out
             return True
 
         # When building with ASan enabled, ASan will convert the -11 returned
         # value to 1. As a work-around we look for the error output which
         # includes the crash reason.
         if rc == 1 and ("Hit MOZ_CRASH" in err or "Assertion failure:" in err):
             return True
 
+        # When running jittests on Android, SEGV results in a return code
+        # of 128+11=139.
+        if rc == 139:
+            return True
+
     if rc != test.expect_status:
         # Tests which expect a timeout check for exit code 6.
         # Sometimes 0 is returned on Windows for unknown reasons.
         # See bug 899697.
         if sys.platform in ['win32', 'cygwin'] and rc == 0:
             return True
 
         # Allow a non-zero exit code if we want to allow OOM, but only if we
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1823,38 +1823,120 @@ bool BuildTextRunsScanner::ContinueTextR
     FrameBidiData data2 = aFrame2->GetBidiData();
     if (data1.embeddingLevel != data2.embeddingLevel ||
         data2.precedingControl != kBidiLevelNone) {
       return false;
     }
   }
 
   ComputedStyle* sc1 = aFrame1->Style();
+  ComputedStyle* sc2 = aFrame2->Style();
+
+  // Any difference in writing-mode/directionality inhibits shaping across
+  // the boundary.
+  WritingMode wm(sc1);
+  if (wm != WritingMode(sc2)) {
+    return false;
+  }
+
   const nsStyleText* textStyle1 = sc1->StyleText();
   // If the first frame ends in a preformatted newline, then we end the textrun
   // here. This avoids creating giant textruns for an entire plain text file.
   // Note that we create a single text frame for a preformatted text node,
   // even if it has newlines in it, so typically we won't see trailing newlines
   // until after reflow has broken up the frame into one (or more) frames per
   // line. That's OK though.
-  if (textStyle1->NewlineIsSignificant(aFrame1) && HasTerminalNewline(aFrame1))
+  if (textStyle1->NewlineIsSignificant(aFrame1) &&
+      HasTerminalNewline(aFrame1)) {
     return false;
+  }
+
+  if (aFrame1->GetParent()->GetContent() !=
+      aFrame2->GetParent()->GetContent()) {
+    // Does aFrame, or any ancestor between it and aAncestor, have a property
+    // that should inhibit cross-element-boundary shaping on aSide?
+    auto PreventCrossBoundaryShaping = [](const nsIFrame* aFrame,
+                                          const nsIFrame* aAncestor,
+                                          Side aSide) {
+      while (aFrame != aAncestor) {
+        ComputedStyle* ctx = aFrame->Style();
+        // According to https://drafts.csswg.org/css-text/#boundary-shaping:
+        //
+        // Text shaping must be broken at inline box boundaries when any of the
+        // following are true for any box whose boundary separates the two
+        // typographic character units:
+        //
+        // 1. Any of margin/border/padding separating the two typographic
+        //    character units in the inline axis is non-zero.
+        const nsStyleCoord& margin = ctx->StyleMargin()->mMargin.Get(aSide);
+        if (!margin.ConvertsToLength() || margin.ToLength() != 0) {
+          return true;
+        }
+        const nsStyleCoord& padding = ctx->StylePadding()->mPadding.Get(aSide);
+        if (!padding.ConvertsToLength() || padding.ToLength() != 0) {
+          return true;
+        }
+        if (ctx->StyleBorder()->GetComputedBorderWidth(aSide) != 0) {
+          return true;
+        }
+
+        // 2. vertical-align is not baseline.
+        const nsStyleCoord& coord = ctx->StyleDisplay()->mVerticalAlign;
+        if (coord.GetUnit() != eStyleUnit_Enumerated ||
+            coord.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
+          return true;
+        }
+
+        // 3. The boundary is a bidi isolation boundary.
+        const uint8_t unicodeBidi = ctx->StyleTextReset()->mUnicodeBidi;
+        if (unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE ||
+            unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE) {
+          return true;
+        }
+
+        aFrame = aFrame->GetParent();
+      }
+      return false;
+    };
+
+    const nsIFrame* ancestor =
+      nsLayoutUtils::FindNearestCommonAncestorFrame(aFrame1, aFrame2);
+    MOZ_ASSERT(ancestor);
+
+    // Map inline-end and inline-start to physical sides for checking presence
+    // of non-zero margin/border/padding.
+    Side side1 = wm.PhysicalSide(eLogicalSideIEnd);
+    Side side2 = wm.PhysicalSide(eLogicalSideIStart);
+    // If the frames have an embedding level that is opposite to the writing
+    // mode, we need to swap which sides we're checking.
+    if (IS_LEVEL_RTL(aFrame1->GetEmbeddingLevel()) == wm.IsBidiLTR()) {
+      Swap(side1, side2);
+    }
+
+    if (PreventCrossBoundaryShaping(aFrame1, ancestor, side1) ||
+        PreventCrossBoundaryShaping(aFrame2, ancestor, side2)) {
+      return false;
+    }
+  }
 
   if (aFrame1->GetContent() == aFrame2->GetContent() &&
       aFrame1->GetNextInFlow() != aFrame2) {
     // aFrame2 must be a non-fluid continuation of aFrame1. This can happen
     // sometimes when the unicode-bidi property is used; the bidi resolver
     // breaks text into different frames even though the text has the same
     // direction. We can't allow these two frames to share the same textrun
     // because that would violate our invariant that two flows in the same
     // textrun have different content elements.
     return false;
   }
 
-  ComputedStyle* sc2 = aFrame2->Style();
+  if (sc1 == sc2) {
+    return true;
+  }
+
   const nsStyleText* textStyle2 = sc2->StyleText();
   if (sc1 == sc2) return true;
 
   nsPresContext* pc = aFrame1->PresContext();
   MOZ_ASSERT(pc == aFrame2->PresContext());
 
   const nsStyleFont* fontStyle1 = sc1->StyleFont();
   const nsStyleFont* fontStyle2 = sc2->StyleFont();
--- a/layout/reftests/css-ruby/intrinsic-isize-1-ref.html
+++ b/layout/reftests/css-ruby/intrinsic-isize-1-ref.html
@@ -2,16 +2,18 @@
 <html lang="ja">
 <head>
   <meta charset="UTF-8">
   <title>Bug 1134432 - Intrinsic ISize calculation of ruby</title>
   <style>
     div {
       display: inline-block;
       border: 1px solid black;
+      font-kerning: none; /* disable kerning, because in the reference file
+                             it might occur across <span> boundaries */
     }
     span {
       white-space: nowrap;
     }
   </style>
 </head>
 <body>
   <div style="width: min-content">
--- a/layout/reftests/css-ruby/intrinsic-isize-1.html
+++ b/layout/reftests/css-ruby/intrinsic-isize-1.html
@@ -2,16 +2,18 @@
 <html lang="ja">
 <head>
   <meta charset="UTF-8">
   <title>Bug 1134432 - Intrinsic ISize calculation of ruby</title>
   <style>
     div {
       display: inline-block;
       border: 1px solid black;
+      font-kerning: none; /* disable kerning, because in the reference file
+                             it might occur across <span> boundaries */
     }
   </style>
 </head>
 <body>
   <div style="width: min-content">
     <ruby><rb>ABC<rb>DEF</ruby>
   </div>
   <div style="width: max-content">
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -852,16 +852,17 @@ class ADBDevice(ADBCommand):
 
         return " ".join(quoted_cmd)
 
     @staticmethod
     def _get_exitcode(file_obj):
         """Get the exitcode from the last line of the file_obj for shell
         commands.
         """
+        re_returncode = re.compile(r'adb_returncode=([0-9]+)')
         file_obj.seek(0, os.SEEK_END)
 
         line = ''
         length = file_obj.tell()
         offset = 1
         while length - offset >= 0:
             file_obj.seek(-offset, os.SEEK_END)
             char = file_obj.read(1)
@@ -869,23 +870,38 @@ class ADBDevice(ADBCommand):
                 break
             if char != '\r' and char != '\n':
                 line = char + line
             elif line:
                 # we have collected everything up to the beginning of the line
                 break
             offset += 1
 
-        match = re.match(r'rc=([0-9]+)', line)
+        match = re_returncode.match(line)
         if match:
             exitcode = int(match.group(1))
+            # Set the position in the file to the position of the
+            # adb_returncode and truncate it from the output.
             file_obj.seek(-1, os.SEEK_CUR)
             file_obj.truncate()
         else:
             exitcode = None
+            # We may have a situation where the adb_returncode= is not
+            # at the end of the output. This happens at least in the
+            # failure jit-tests on arm. To work around this
+            # possibility, we can search the entire output for the
+            # appropriate match.
+            file_obj.seek(0, os.SEEK_SET)
+            for line in file_obj:
+                match = re_returncode.search(line)
+                if match:
+                    exitcode = int(match.group(1))
+                    break
+            # Reset the position in the file to the end.
+            file_obj.seek(0, os.SEEK_END)
 
         return exitcode
 
     def is_path_internal_storage(self, path, timeout=None):
         """
         Return True if the path matches an internal storage path
         as defined by either '/sdcard', '/mnt/sdcard', or any of the
         .*_STORAGE environment variables on the device otherwise False.
@@ -1303,17 +1319,17 @@ class ADBDevice(ADBCommand):
 
         # prepend cwd and env to command if necessary
         if cwd:
             cmd = "cd %s && %s" % (cwd, cmd)
         if env:
             envstr = '&& '.join(map(lambda x: 'export %s=%s' %
                                     (x[0], x[1]), env.iteritems()))
             cmd = envstr + "&& " + cmd
-        cmd += "; echo rc=$?"
+        cmd += "; echo adb_returncode=$?"
 
         args = [self._adb_path]
         if self._adb_host:
             args.extend(['-H', self._adb_host])
         if self._adb_port:
             args.extend(['-P', str(self._adb_port)])
         if self._device_serial:
             args.extend(['-s', self._device_serial])
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -2,20 +2,24 @@
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import absolute_import
 
 import json
 import os
+import posixpath
+import shutil
 import subprocess
 import sys
+import tempfile
 import time
 
+import mozcrash
 import mozinfo
 
 from mozdevice import ADBDevice
 from mozlog import commandline, get_default_logger
 from mozprofile import create_profile
 from mozrunner import runners
 
 # need this so raptor imports work both from /raptor and via mach
@@ -126,17 +130,18 @@ class Raptor(object):
             # create the desktop browser runner
             self.log.info("creating browser runner using mozrunner")
             self.output_handler = OutputHandler()
             process_args = {
                 'processOutputLine': [self.output_handler],
             }
             runner_cls = runners[app]
             self.runner = runner_cls(
-                binary, profile=self.profile, process_args=process_args)
+                binary, profile=self.profile, process_args=process_args,
+                symbols_path=self.config['symbols_path'])
 
         self.log.info("raptor config: %s" % str(self.config))
 
     @property
     def profile_data_dir(self):
         if 'MOZ_DEVELOPER_REPO_DIR' in os.environ:
             return os.path.join(os.environ['MOZ_DEVELOPER_REPO_DIR'], 'testing', 'profiles')
         if build:
@@ -381,24 +386,19 @@ class Raptor(object):
                 if not self.debug_mode:
                     elapsed_time += 1
                     if elapsed_time > (timeout) - 5:  # stop 5 seconds early
                         self.log.info("application timed out after {} seconds".format(timeout))
                         self.control_server.wait_for_quit()
                         break
         finally:
             if self.config['app'] == "geckoview":
-                # TODO: if on geckoview is there some cleanup here i.e. check for crashes?
                 if self.config['power_test']:
                     finish_geckoview_power_test(self)
-            else:
-                try:
-                    self.runner.check_for_crashes()
-                except NotImplementedError:  # not implemented for Chrome
-                    pass
+            self.check_for_crashes()
 
         if self.playback is not None:
             self.playback.stop()
 
         # remove the raptor webext; as it must be reloaded with each subtest anyway
         self.log.info("removing webext %s" % raptor_webext)
         if self.config['app'] in ["firefox", "geckoview"]:
             self.profile.addons.remove_addon(webext_id)
@@ -450,16 +450,41 @@ class Raptor(object):
             raptor_json_path = os.path.join(os.getcwd(), 'local.json')
 
         self.config['raptor_json_path'] = raptor_json_path
         return self.results_handler.summarize_and_output(self.config)
 
     def get_page_timeout_list(self):
         return self.results_handler.page_timeout_list
 
+    def check_for_crashes(self):
+        if self.config['app'] == "geckoview":
+            logcat = self.device.get_logcat()
+            if logcat:
+                if mozcrash.check_for_java_exception(logcat, "raptor"):
+                    return
+            try:
+                dump_dir = tempfile.mkdtemp()
+                remote_dir = posixpath.join(self.device_profile, 'minidumps')
+                if not self.device.is_dir(remote_dir):
+                    self.log.error("No crash directory (%s) found on remote device" % remote_dir)
+                    return
+                self.device.pull(remote_dir, dump_dir)
+                mozcrash.log_crashes(self.log, dump_dir, self.config['symbols_path'])
+            finally:
+                try:
+                    shutil.rmtree(dump_dir)
+                except Exception:
+                    self.log.warning("unable to remove directory: %s" % dump_dir)
+        else:
+            try:
+                self.runner.check_for_crashes()
+            except NotImplementedError:  # not implemented for Chrome
+                pass
+
     def clean_up(self):
         self.control_server.stop()
         if self.config['app'] != "geckoview":
             self.runner.stop()
         elif self.config['app'] == 'geckoview':
             self.log.info('removing reverse socket connections')
             self.device.remove_socket_connections('reverse')
         else:
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/boundary-shaping/boundary-shaping-004.html.ini
@@ -0,0 +1,3 @@
+[boundary-shaping-004.html]
+  expected:
+    if webrender and (os == "win"): FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/boundary-shaping/boundary-shaping-005.html.ini
@@ -0,0 +1,3 @@
+[boundary-shaping-005.html]
+  expected:
+    if webrender and (os == "win"): FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/boundary-shaping/boundary-shaping-010.html.ini
@@ -0,0 +1,4 @@
+[boundary-shaping-010.html]
+  expected:
+    if (os == "mac"): FAIL
+    if (os == "android"): FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must not be broken across inline box boundaries when there is no change in formatting</title>
+<link rel=match href="reference/boundary-shaping-001.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  /* initial values for these properties should not interrupt shaping */
+  vertical-align: initial;
+  padding: initial;
+  margin: initial;
+  border: initial;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-002.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when 'vertical-align' is not 'baseline'</title>
+<link rel=match href="reference/boundary-shaping-002.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  vertical-align: 0; /* distinct from 'baseline', should break shaping */
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-003.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when padding is non-zero</title>
+<link rel=match href="reference/boundary-shaping-003.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  padding-left: 10px;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-004.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when margin is non-zero</title>
+<link rel=match href="reference/boundary-shaping-004.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  margin-right: 10px;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-005.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when border is non-zero</title>
+<link rel=match href="reference/boundary-shaping-005.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  border-right: 10px solid transparent;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-006.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when 'vertical-align' is not 'baseline'</title>
+<link rel=match href="reference/boundary-shaping-006.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  vertical-align: super;
+}
+</style>
+</head>
+<body>
+of<span><span><span class=a><span><span>f</span></span></span></span></span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-007.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when padding or margin is non-zero</title>
+<link rel=match href="reference/boundary-shaping-007.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  padding-left: 10px;
+}
+.b {
+  margin-right: 10px;
+}
+</style>
+</head>
+<body>
+of<span><span class=a><span><span class=b><span>f</span></span></span></span></span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-008.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries at a bidi isolation boundary</title>
+<link rel=match href="reference/boundary-shaping-008.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+@font-face {
+  font-family: test;
+  src: url(resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  unicode-bidi: isolate; /* bidi isolation boundaries should break shaping */
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-009.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must be broken across inline box boundaries when padding or margin is non-zero</title>
+<link rel=match href="reference/boundary-shaping-009.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+body {
+  font: 36px sans-serif;
+}
+div {
+  text-align: center;
+}
+.a {
+  padding-right: 10px;
+}
+.b {
+  margin-left: 10px;
+}
+.c {
+  color: red;
+  padding-left: 10px;
+}
+.d {
+  color: red;
+  margin-right: 10px;
+}
+</style>
+</head>
+<body>
+<div dir=ltr>
+السلام<span class=a>عليكم</span>
+</div>
+<div dir=ltr>
+<span class=b>السلام</span>عليكم
+</div>
+<div dir=rtl>
+السلام<span class=a>عليكم</span>
+</div>
+<div dir=rtl>
+<span class=b>السلام</span>عليكم
+</div>
+<div dir=ltr>
+السلام<span class=c>عليكم</span>
+</div>
+<div dir=ltr>
+<span class=d>السلام</span>عليكم
+</div>
+<div dir=rtl>
+السلام<span class=c>عليكم</span>
+</div>
+<div dir=rtl>
+<span class=d>السلام</span>عليكم
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/boundary-shaping-010.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Text shaping must not be broken across inline box boundaries when there is no change in formatting</title>
+<link rel=match href="reference/boundary-shaping-010.ref.html">
+<link rel=help href="https://drafts.csswg.org/css-text/#boundary-shaping">
+<style>
+body {
+  font: 36px sans-serif;
+}
+div {
+  text-align: center;
+}
+</style>
+</head>
+<body>
+<div dir=rtl>
+ال<span>سل</span>ام
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-001.ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+</style>
+</head>
+<body>
+office
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-002.ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  display: inline-block;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-003.ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  display: inline-block;
+  width: 10px;
+}
+</style>
+</head>
+<body>
+of<span class=a>&nbsp;</span>fice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-004.ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  display: inline-block;
+  width: 10px;
+}
+</style>
+</head>
+<body>
+off<span class=a>&nbsp;</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-005.ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  display: inline-block;
+  width: 10px;
+}
+</style>
+</head>
+<body>
+off<span class=a>&nbsp;</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-006.ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  vertical-align: super;
+  display: inline-block;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-007.ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  padding-left: 10px;
+  margin-right: 10px;
+  display: inline-block;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-008.ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../resources/LinLibertine_Re-4.7.5.woff);
+}
+body {
+  font: 36px test; /* use a font that includes ligatures for "fi" etc */
+}
+.a {
+  display: inline-block;
+}
+</style>
+</head>
+<body>
+of<span class=a>f</span>ice
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-009.ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+body {
+  font: 36px sans-serif;
+}
+div {
+  text-align: center;
+}
+.a {
+  display: inline-block;
+  width: 10px;
+}
+.c1 {
+  padding-left: 10px;
+}
+.c {
+  color: red;
+}
+.d1 {
+  margin-right: 10px;
+}
+.d {
+  color: red;
+}
+</style>
+</head>
+<body>
+<div dir=ltr>
+السلام<span class=a>&nbsp;</span>عليكم
+</div>
+<div dir=ltr>
+السلام<span class=a>&nbsp;</span>عليكم
+</div>
+<div dir=rtl>
+السلام<span class=a>&nbsp;</span>عليكم
+</div>
+<div dir=rtl>
+السلام<span class=a>&nbsp;</span>عليكم
+</div>
+<div dir=ltr>
+<span class=c1>السلام<span class=c>عليكم</span></span>
+</div>
+<div dir=ltr>
+<span class=d1><span class=d>السلام</span>عليكم</span>
+</div>
+<div dir=rtl>
+<span class=c1>السلام<span class=c>عليكم</span></span>
+</div>
+<div dir=rtl>
+<span class=d1><span class=d>السلام</span>عليكم</span>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/boundary-shaping/reference/boundary-shaping-010.ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+body {
+  font: 36px sans-serif;
+}
+div {
+  text-align: center;
+}
+</style>
+</head>
+<body>
+<div dir=rtl>
+السلام
+</body>
+</html>
copy from layout/reftests/fonts/LinLibertine_Re-4.7.5.woff
copy to testing/web-platform/tests/css/css-text/boundary-shaping/resources/LinLibertine_Re-4.7.5.woff