merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 02 Jan 2015 13:53:24 +0100
changeset 247668 57e4e9c33bef603482bcdbdab3e5910ac0f2d2d6
parent 247646 4278e53a8a472af1c3fa6894a552f2e196660c99 (current diff)
parent 247667 a124ee010fa7cced5031a7dc765d348d682cb967 (diff)
child 247669 9a6007f38beaac703fb5fbb82d81129add57d20d
child 247694 bf2de389e2455da80c267705706c4d29327b2225
child 247707 9e9d66cbad378585ab6cb68f0de8f0042cbc1492
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
57e4e9c33bef / 37.0a1 / 20150103030215 / files
nightly linux64
57e4e9c33bef / 37.0a1 / 20150103030215 / files
nightly mac
57e4e9c33bef / 37.0a1 / 20150103030215 / files
nightly win32
57e4e9c33bef / 37.0a1 / 20150103030215 / files
nightly win64
57e4e9c33bef / 37.0a1 / 20150103030215 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -246,18 +246,16 @@ GetAccService()
 }
 
 /**
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
-  // XXX temporarily disable ipc accessibility because of crashes.
-return false;
 #ifdef MOZ_B2G
   return false;
 #else
   return XRE_GetProcessType() == GeckoProcessType_Content;
 #endif
 }
 
 /**
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -18,17 +18,18 @@ class Attribute;
 class DocAccessibleParent;
 
 class ProxyAccessible
 {
 public:
 
   ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
                   DocAccessibleParent* aDoc, role aRole) :
-     mParent(aParent), mDoc(aDoc), mID(aID), mRole(aRole), mOuterDoc(false)
+     mParent(aParent), mDoc(aDoc), mWrapper(0), mID(aID), mRole(aRole),
+     mOuterDoc(false)
   {
     MOZ_COUNT_CTOR(ProxyAccessible);
   }
   ~ProxyAccessible()
   {
     MOZ_COUNT_DTOR(ProxyAccessible);
     MOZ_ASSERT(!mWrapper);
   }
--- a/configure.in
+++ b/configure.in
@@ -45,17 +45,17 @@ dnl ====================================
 _SUBDIR_HOST_CFLAGS="$HOST_CFLAGS"
 _SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS"
 _SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS"
 _SUBDIR_CONFIG_ARGS="$ac_configure_args"
 
 dnl Set the version number of the libs included with mozilla
 dnl ========================================================
 MOZJPEG=62
-MOZPNG=10614
+MOZPNG=10616
 NSPR_VERSION=4
 NSPR_MINVER=4.10.3
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=1.2.0
 PERL_VERSION=5.006
@@ -2669,21 +2669,17 @@ WINNT|Darwin|Android)
   ;;
 esac
 
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
 MOZ_GCC_PR49911
 MOZ_GCC_PR39608
-if test "$OS_TARGET" != WINNT; then
-    # Only run this test with clang on non-Windows platforms, because clang
-    # cannot do enough code gen for now to make this test work correctly.
-    MOZ_LLVM_PR8927
-fi
+MOZ_LLVM_PR8927
 
 dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
 dnl ========================================================
 if test "$GNU_CC"; then
   CFLAGS_save="${CFLAGS}"
   CFLAGS="${CFLAGS} -Werror"
   AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute,
                  ac_cv_force_align_arg_pointer,
--- a/dom/svg/test/test_pathLength.html
+++ b/dom/svg/test/test_pathLength.html
@@ -5,17 +5,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <meta charset="utf-8">
   <title>Test path length changes when manipulated</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=946529">Mozilla Bug 1024926</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1024926">Mozilla Bug 1024926</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   <svg width="100%" height="1" id="svg">
     <path id="path" d="M50,100l0,0l0,-50l100,0l86.3325,122.665z"></path>
   </svg>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -9672,16 +9672,20 @@ 19167,19168c24927
 ---
 > cuss/FEGSDM
 19246c25005
 < cysteine
 ---
 > cysteine/M
 19536a25296
 > decertify/DSGNX
+19759c25519
+< deliverable/U
+---
+> deliverable/US
 19935a25696
 > dequeue/DSG
 19999a25761
 > designated/U
 20196,20197c25958,25959
 < dialog/SM
 < dialogue/SM
 ---
@@ -10425,16 +10429,20 @@ 32361,32362c38063
 < melt/ADSG
 ---
 > melt/ADSGM
 32365,32366c38066
 < member's
 < member/EAS
 ---
 > member/EASM
+32386c38086
+< men
+---
+> men/M
 32708a38409
 > might've
 32717a38419
 > migrator/SM
 32760a38463
 > millennia
 32777d38479
 < millionnaire/M
@@ -10456,16 +10464,20 @@ 33051,33052c38753
 < mist's
 < mist/CDRSZG
 ---
 > mist/CDRSZGM
 33056c38757
 < mister's
 ---
 > mister/M
+33083c38784
+< mitigation/M
+---
+> mitigation/MS
 33107,33108c38808
 < mob's
 < mob/CS
 ---
 > mob/CSM
 33448,33449c39148
 < mortgage's
 < mortgage/AGDS
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -25783,17 +25783,17 @@ delineation/M
 delinquency/SM
 delinquent/SMY
 deliquesce/GDS
 deliquescent
 delirious/PY
 deliriousness/M
 delirium/SM
 deliver/ADGS
-deliverable/U
+deliverable/US
 deliverance/M
 delivered/U
 deliverer/SM
 dell/SM
 delphinium/MS
 delta/MS
 deltoids
 delude/GDS
@@ -38379,17 +38379,17 @@ memorably
 memorandum/MS
 memorial/SM
 memorialize/DSG
 memorization/M
 memorize/DSG
 memorized/U
 memory/SM
 memsahib/S
-men
+men/M
 menace/MGDS
 menacing/Y
 menage/MS
 menagerie/MS
 menarche
 mend/MDRSZG
 mendacious/Y
 mendacity/M
@@ -39081,17 +39081,17 @@ mistype/JGDS
 misunderstand/GSJ
 misunderstanding/M
 misunderstood
 misuse/DRSMG
 mite/MZRS
 miter/MDG
 mitigate/DSGN
 mitigated/U
-mitigation/M
+mitigation/MS
 mitigatory
 mitochondria
 mitochondrial
 mitoses
 mitosis/M
 mitotic
 mitt/MNSX
 mitten/M
--- a/gfx/skia/trunk/include/core/SkRect.h
+++ b/gfx/skia/trunk/include/core/SkRect.h
@@ -272,17 +272,16 @@ struct SK_API SkIRect {
         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
     }
 
     /** If rectangles a and b intersect, return true and set this rectangle to
         that intersection, otherwise return false and do not change this
         rectangle. If either rectangle is empty, do nothing and return false.
     */
     bool intersect(const SkIRect& a, const SkIRect& b) {
-        SkASSERT(&a && &b);
 
         if (!a.isEmpty() && !b.isEmpty() &&
                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
             fLeft   = SkMax32(a.fLeft,   b.fLeft);
             fTop    = SkMax32(a.fTop,    b.fTop);
             fRight  = SkMin32(a.fRight,  b.fRight);
             fBottom = SkMin32(a.fBottom, b.fBottom);
@@ -293,17 +292,16 @@ struct SK_API SkIRect {
 
     /** If rectangles a and b intersect, return true and set this rectangle to
         that intersection, otherwise return false and do not change this
         rectangle. For speed, no check to see if a or b are empty is performed.
         If either is, then the return result is undefined. In the debug build,
         we assert that both rectangles are non-empty.
     */
     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
-        SkASSERT(&a && &b);
         SkASSERT(!a.isEmpty() && !b.isEmpty());
 
         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
             fLeft   = SkMax32(a.fLeft,   b.fLeft);
             fTop    = SkMax32(a.fTop,    b.fTop);
             fRight  = SkMin32(a.fRight,  b.fRight);
             fBottom = SkMin32(a.fBottom, b.fBottom);
--- a/gfx/skia/trunk/include/views/SkOSMenu.h
+++ b/gfx/skia/trunk/include/views/SkOSMenu.h
@@ -124,17 +124,17 @@ public:
     /**
      * Create predefined items with the given parameters. To be used with the
      * other helper functions below to retrive/update state information.
      * Note: the helper functions below assume that slotName is UNIQUE for all
      * menu items of the same type since it's used to identify the event
      */
     int appendAction(const char label[], SkEventSinkID target);
     int appendList(const char label[], const char slotName[],
-                   SkEventSinkID target, int defaultIndex, const char[] ...);
+                   SkEventSinkID target, int defaultIndex, const char* ...);
     int appendSlider(const char label[], const char slotName[],
                      SkEventSinkID target, SkScalar min, SkScalar max,
                      SkScalar defaultValue);
     int appendSwitch(const char label[], const char slotName[],
                      SkEventSinkID target, bool defaultState = false);
     int appendTriState(const char label[], const char slotName[],
                        SkEventSinkID target, TriState defaultState = kOffState);
     int appendTextField(const char label[], const char slotName[],
--- a/gfx/skia/trunk/src/core/SkMatrix.cpp
+++ b/gfx/skia/trunk/src/core/SkMatrix.cpp
@@ -1062,17 +1062,17 @@ void SkMatrix::mapVectors(SkPoint dst[],
 
         tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
         tmp.clearTypeMask(kTranslate_Mask);
         tmp.mapPoints(dst, src, count);
     }
 }
 
 bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
-    SkASSERT(dst && &src);
+    SkASSERT(dst);
 
     if (this->rectStaysRect()) {
         this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
         dst->sort();
         return true;
     } else {
         SkPoint quad[4];
 
--- a/gfx/skia/trunk/src/core/SkRect.cpp
+++ b/gfx/skia/trunk/src/core/SkRect.cpp
@@ -109,38 +109,35 @@ bool SkRect::intersect(SkScalar left, Sk
         if (fRight > right) fRight = right;
         if (fBottom > bottom) fBottom = bottom;
         return true;
     }
     return false;
 }
 
 bool SkRect::intersect(const SkRect& r) {
-    SkASSERT(&r);
     return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
 }
 
 bool SkRect::intersect2(const SkRect& r) {
-    SkASSERT(&r);
     SkScalar L = SkMaxScalar(fLeft, r.fLeft);
     SkScalar R = SkMinScalar(fRight, r.fRight);
     if (L >= R) {
         return false;
     }
     SkScalar T = SkMaxScalar(fTop, r.fTop);
     SkScalar B = SkMinScalar(fBottom, r.fBottom);
     if (T >= B) {
         return false;
     }
     this->set(L, T, R, B);
     return true;
 }
 
 bool SkRect::intersect(const SkRect& a, const SkRect& b) {
-    SkASSERT(&a && &b);
 
     if (!a.isEmpty() && !b.isEmpty() &&
         a.fLeft < b.fRight && b.fLeft < a.fRight &&
         a.fTop < b.fBottom && b.fTop < a.fBottom) {
         fLeft   = SkMaxScalar(a.fLeft,   b.fLeft);
         fTop    = SkMaxScalar(a.fTop,    b.fTop);
         fRight  = SkMinScalar(a.fRight,  b.fRight);
         fBottom = SkMinScalar(a.fBottom, b.fBottom);
--- a/gfx/skia/trunk/src/core/SkScan_Path.cpp
+++ b/gfx/skia/trunk/src/core/SkScan_Path.cpp
@@ -427,17 +427,17 @@ static SkEdge* sort_edges(SkEdge* list[]
 // clipRect may be null, even though we always have a clip. This indicates that
 // the path is contained in the clip, and so we can ignore it during the blit
 //
 // clipRect (if no null) has already been shifted up
 //
 void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
                   int start_y, int stop_y, int shiftEdgesUp,
                   const SkRegion& clipRgn) {
-    SkASSERT(&path && blitter);
+    SkASSERT(blitter);
 
     SkEdgeBuilder   builder;
 
     int count = builder.build(path, clipRect, shiftEdgesUp);
     SkEdge**    list = builder.edgeList();
 
     if (count < 2) {
         if (path.isInverseFillType()) {
--- a/gfx/skia/trunk/src/ports/SkFontHost_FreeType.cpp
+++ b/gfx/skia/trunk/src/ports/SkFontHost_FreeType.cpp
@@ -1332,17 +1332,17 @@ void SkScalerContext_FreeType::generateI
     generateGlyphImage(fFace, glyph);
 }
 
 
 void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph,
                                             SkPath* path) {
     SkAutoMutexAcquire  ac(gFTMutex);
 
-    SkASSERT(&glyph && path);
+    SkASSERT(path);
 
     if (this->setupSize()) {
         path->reset();
         return;
     }
 
     uint32_t flags = fLoadGlyphFlags;
     flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
--- a/gfx/skia/trunk/src/views/SkTextBox.cpp
+++ b/gfx/skia/trunk/src/views/SkTextBox.cpp
@@ -162,17 +162,17 @@ void SkTextBox::setSpacing(SkScalar mul,
     fSpacingMul = mul;
     fSpacingAdd = add;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////////
 
 void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint)
 {
-    SkASSERT(canvas && &paint && (text || len == 0));
+    SkASSERT(canvas && (text || len == 0));
 
     SkScalar marginWidth = fBox.width();
 
     if (marginWidth <= 0 || len == 0)
         return;
 
     const char* textStop = text + len;
 
--- a/gfx/skia/trunk/src/views/SkViewPriv.cpp
+++ b/gfx/skia/trunk/src/views/SkViewPriv.cpp
@@ -12,17 +12,17 @@
 void SkView::Artist::draw(SkView* view, SkCanvas* canvas)
 {
     SkASSERT(view && canvas);
     this->onDraw(view, canvas);
 }
 
 void SkView::Artist::inflate(const SkDOM& dom, const SkDOM::Node* node)
 {
-    SkASSERT(&dom && node);
+    SkASSERT(node);
     this->onInflate(dom, node);
 }
 
 void SkView::Artist::onInflate(const SkDOM&, const SkDOM::Node*)
 {
     // subclass should override this as needed
 }
 
@@ -58,17 +58,17 @@ void SkView::Layout::layoutChildren(SkVi
 {
     SkASSERT(parent);
     if (parent->width() > 0 && parent->height() > 0)
         this->onLayoutChildren(parent);
 }
 
 void SkView::Layout::inflate(const SkDOM& dom, const SkDOM::Node* node)
 {
-    SkASSERT(&dom && node);
+    SkASSERT(node);
     this->onInflate(dom, node);
 }
 
 void SkView::Layout::onInflate(const SkDOM&, const SkDOM::Node*)
 {
     // subclass should override this as needed
 }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2239,21 +2239,17 @@ WINNT|Darwin|Android)
   ;;
 esac
 
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
 MOZ_GCC_PR49911
 MOZ_GCC_PR39608
-if test "$OS_TARGET" != WINNT; then
-    # Only run this test with clang on non-Windows platforms, because clang
-    # cannot do enough code gen for now to make this test work correctly.
-    MOZ_LLVM_PR8927
-fi
+MOZ_LLVM_PR8927
 
 dnl Checks for header files.
 dnl ========================================================
 AC_HEADER_DIRENT
 case "$target_os" in
 freebsd*)
 # for stuff like -lXshm
     CPPFLAGS="${CPPFLAGS} ${X_CFLAGS}"
--- a/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul
+++ b/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul
@@ -91,18 +91,24 @@
 
       if (winLowerThanVista && !tests[testIndex].maximize) {
         ok(true, "Skipping non-maximized test " + testIndex + " on winLowerThanVista since the resizer causes overlapping layers");
         ++testIndex;
         nextTest();
         return;
       }
 
+      window.focus();
       // Run the test in a separate window so we get a clean browser window.
       win = window.open("data:text/html,<html style='overflow:scroll'>",
                 "", "scrollbars=yes,toolbar,menubar,width=500,height=500");
+      setTimeout(setupWindow, 0);
+    }
+
+    function setupWindow() {
       win.addEventListener("load", doTest, false);
+      win.focus();
     }
 
     nextTest();
   ]]>
   </script>
 </window>
new file mode 100644
--- /dev/null
+++ b/layout/generic/RubyReflowState.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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/. */
+
+/* states and methods used while laying out a ruby segment */
+
+#include "RubyReflowState.h"
+
+using namespace mozilla;
+
+RubyReflowState::RubyReflowState(
+  WritingMode aLineWM,
+  const nsTArray<nsRubyTextContainerFrame*>& aTextContainers)
+  : mCurrentContainerIndex(kBaseContainerIndex)
+{
+  uint32_t rtcCount = aTextContainers.Length();
+  mTextContainers.SetCapacity(rtcCount);
+  for (uint32_t i = 0; i < rtcCount; i++) {
+    mTextContainers.AppendElement(
+      TextContainerInfo(aLineWM, aTextContainers[i]));
+  }
+}
new file mode 100644
--- /dev/null
+++ b/layout/generic/RubyReflowState.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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/. */
+
+/* states and methods used while laying out a ruby segment */
+
+#ifndef mozilla_RubyReflowState_h_
+#define mozilla_RubyReflowState_h_
+
+#include "mozilla/Attributes.h"
+#include "WritingModes.h"
+#include "nsTArray.h"
+
+#define RTC_ARRAY_SIZE 1
+
+class nsRubyTextContainerFrame;
+
+namespace mozilla {
+
+class MOZ_STACK_CLASS RubyReflowState MOZ_FINAL
+{
+public:
+  explicit RubyReflowState(
+    WritingMode aLineWM,
+    const nsTArray<nsRubyTextContainerFrame*>& aTextContainers);
+
+  struct TextContainerInfo
+  {
+    nsRubyTextContainerFrame* mFrame;
+    LogicalSize mLineSize;
+
+    TextContainerInfo(WritingMode aLineWM, nsRubyTextContainerFrame* aFrame)
+      : mFrame(aFrame)
+      , mLineSize(aLineWM) { }
+  };
+
+  void AdvanceCurrentContainerIndex() { mCurrentContainerIndex++; }
+
+  void SetTextContainerInfo(int32_t aIndex,
+                            nsRubyTextContainerFrame* aContainer,
+                            const LogicalSize& aLineSize)
+  {
+    MOZ_ASSERT(mTextContainers[aIndex].mFrame == aContainer);
+    mTextContainers[aIndex].mLineSize = aLineSize;
+  }
+
+  const TextContainerInfo&
+    GetCurrentTextContainerInfo(nsRubyTextContainerFrame* aFrame) const
+  {
+    MOZ_ASSERT(mTextContainers[mCurrentContainerIndex].mFrame == aFrame);
+    return mTextContainers[mCurrentContainerIndex];
+  }
+
+private:
+  static MOZ_CONSTEXPR_VAR int32_t kBaseContainerIndex = -1;
+  // The index of the current reflowing container. When it equals to
+  // kBaseContainerIndex, we are reflowing ruby base. Otherwise, it
+  // stands for the index of text containers in the ruby segment.
+  int32_t mCurrentContainerIndex;
+
+  nsAutoTArray<TextContainerInfo, RTC_ARRAY_SIZE> mTextContainers;
+};
+
+}
+
+#endif // mozilla_RubyReflowState_h_
--- a/layout/generic/RubyUtils.cpp
+++ b/layout/generic/RubyUtils.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; 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/. */
 
 #include "RubyUtils.h"
-#include "nsIFrame.h"
 
 using namespace mozilla;
 
 NS_DECLARE_FRAME_PROPERTY(ReservedISize, nullptr);
 
 union NSCoordValue
 {
   nscoord mCoord;
@@ -37,8 +36,25 @@ RubyUtils::ClearReservedISize(nsIFrame* 
 /* static */ nscoord
 RubyUtils::GetReservedISize(nsIFrame* aFrame)
 {
   MOZ_ASSERT(IsExpandableRubyBox(aFrame));
   NSCoordValue value;
   value.mPointer = aFrame->Properties().Get(ReservedISize());
   return value.mCoord;
 }
+
+RubyTextContainerIterator::RubyTextContainerIterator(
+  nsRubyBaseContainerFrame* aBaseContainer)
+{
+  mFrame = aBaseContainer;
+  Next();
+}
+
+void
+RubyTextContainerIterator::Next()
+{
+  MOZ_ASSERT(mFrame, "Should have checked AtEnd()");
+  mFrame = mFrame->GetNextSibling();
+  if (mFrame && mFrame->GetType() != nsGkAtoms::rubyTextContainerFrame) {
+    mFrame = nullptr;
+  }
+}
--- a/layout/generic/RubyUtils.h
+++ b/layout/generic/RubyUtils.h
@@ -3,17 +3,18 @@
 /* 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 mozilla_RubyUtils_h_
 #define mozilla_RubyUtils_h_
 
 #include "nsGkAtoms.h"
-#include "nsIFrame.h"
+#include "nsRubyBaseContainerFrame.h"
+#include "nsRubyTextContainerFrame.h"
 
 namespace mozilla {
 
 /**
  * Reserved ISize
  *
  * With some exceptions, each ruby internal box has two isizes, which
  * are the reflowed isize and the final isize. The reflowed isize is
@@ -53,11 +54,31 @@ public:
            type == nsGkAtoms::rubyTextContainerFrame;
   }
 
   static void SetReservedISize(nsIFrame* aFrame, nscoord aISize);
   static void ClearReservedISize(nsIFrame* aFrame);
   static nscoord GetReservedISize(nsIFrame* aFrame);
 };
 
+/**
+ * This class iterates all ruby text containers paired with
+ * the given ruby base container.
+ */
+class MOZ_STACK_CLASS RubyTextContainerIterator
+{
+public:
+  explicit RubyTextContainerIterator(nsRubyBaseContainerFrame* aBaseContainer);
+
+  void Next();
+  bool AtEnd() const { return !mFrame; }
+  nsRubyTextContainerFrame* GetTextContainer() const
+  {
+    return static_cast<nsRubyTextContainerFrame*>(mFrame);
+  }
+
+private:
+  nsIFrame* mFrame;
+};
+
 }
 
 #endif /* !defined(mozilla_RubyUtils_h_) */
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -89,16 +89,17 @@ UNIFIED_SOURCES += [
     'nsSimplePageSequenceFrame.cpp',
     'nsSplittableFrame.cpp',
     'nsSubDocumentFrame.cpp',
     'nsTextFrame.cpp',
     'nsTextFrameUtils.cpp',
     'nsTextRunTransformations.cpp',
     'nsVideoFrame.cpp',
     'nsViewportFrame.cpp',
+    'RubyReflowState.cpp',
     'RubyUtils.cpp',
     'ScrollbarActivity.cpp',
     'StickyScrollContainer.cpp',
     'TextOverflow.cpp',
 ]
 
 # nsLineLayout.cpp needs to be built separately because it uses plarena.h.
 # nsPluginFrame.cpp needs to be built separately because of name clashes in the OS X headers.
--- a/layout/generic/nsFrameState.cpp
+++ b/layout/generic/nsFrameState.cpp
@@ -13,16 +13,17 @@
 #include "nsFlexContainerFrame.h"
 #include "nsGfxScrollFrame.h"
 #include "nsIFrame.h"
 #include "nsISVGChildFrame.h"
 #include "nsImageFrame.h"
 #include "nsInlineFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsRubyTextFrame.h"
+#include "nsRubyTextContainerFrame.h"
 #include "nsSVGContainerFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsTableRowFrame.h"
 #include "nsTableRowGroupFrame.h"
 #include "nsTextFrame.h"
 
 namespace mozilla {
 
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -518,16 +518,23 @@ FRAME_STATE_BIT(Inline, 23, NS_INLINE_FR
 // == Frame state bits that apply to ruby text frames =========================
 
 FRAME_STATE_GROUP(RubyText, nsRubyTextFrame)
 
 // inherits from nsInlineFrame
 FRAME_STATE_BIT(RubyText, 24, NS_RUBY_TEXT_FRAME_AUTOHIDE)
 
 
+// == Frame state bits that apply to ruby text container frames ===============
+
+FRAME_STATE_GROUP(RubyTextContainer, nsRubyTextContainerFrame)
+
+FRAME_STATE_BIT(RubyTextContainer, 20, NS_RUBY_TEXT_CONTAINER_IS_SPAN)
+
+
 // == Frame state bits that apply to placeholder frames =======================
 
 FRAME_STATE_GROUP(Placeholder, nsPlaceholderFrame)
 
 // Frame state bits that are used to keep track of what this is a
 // placeholder for.
 
 FRAME_STATE_BIT(Placeholder, 20, PLACEHOLDER_FOR_FLOAT)
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -67,16 +67,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
   MOZ_ASSERT(aPresContext, "no pres context");
   MOZ_ASSERT(aFrame, "no frame");
   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
   parentReflowState = nullptr;
   AvailableISize() = aAvailableSpace.ISize(mWritingMode);
   AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
   mFloatManager = nullptr;
   mLineLayout = nullptr;
+  mRubyReflowState = nullptr;
   memset(&mFlags, 0, sizeof(mFlags));
   mDiscoveredClearance = nullptr;
   mPercentHeightObserver = nullptr;
 
   if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
     mFlags.mDummyParentReflowState = true;
   }
 
@@ -202,16 +203,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
     }
   }
 
   mFloatManager = aParentReflowState.mFloatManager;
   if (frame->IsFrameOfType(nsIFrame::eLineParticipant))
     mLineLayout = aParentReflowState.mLineLayout;
   else
     mLineLayout = nullptr;
+  mRubyReflowState = nullptr;
 
   // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
   // this constructor's init list, so the only flags that we need to explicitly
   // initialize here are those that may need a value other than our parent's.
   mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
   mFlags.mHasClearance = false;
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -16,16 +16,20 @@
 
 class nsPresContext;
 class nsRenderingContext;
 class nsFloatManager;
 class nsLineLayout;
 class nsIPercentHeightObserver;
 struct nsHypotheticalBox;
 
+namespace mozilla {
+class RubyReflowState;
+}
+
 /**
  * @return aValue clamped to [aMinValue, aMaxValue].
  *
  * @note This function needs to handle aMinValue > aMaxValue. In that case,
  *       aMinValue is returned.
  * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
  * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-heights
  */
@@ -253,16 +257,19 @@ struct nsHTMLReflowState : public nsCSSO
   const nsHTMLReflowState* parentReflowState;
 
   // pointer to the float manager associated with this area
   nsFloatManager* mFloatManager;
 
   // LineLayout object (only for inline reflow; set to nullptr otherwise)
   nsLineLayout*    mLineLayout;
 
+  // RubyReflowState object (only for ruby reflow; set to nullptr otherwise)
+  mozilla::RubyReflowState* mRubyReflowState;
+
   // The appropriate reflow state for the containing block (for
   // percentage widths, etc.) of this reflow state's frame.
   const nsHTMLReflowState *mCBReflowState;
 
   // The type of frame, from css's perspective. This value is
   // initialized by the Init method below.
   nsCSSFrameType   mFrameType;
 
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -61,16 +61,17 @@ nsLineLayout::nsLineLayout(nsPresContext
     mLastOptionalBreakFrame(nullptr),
     mForceBreakFrame(nullptr),
     mBlockRS(nullptr),/* XXX temporary */
     mLastOptionalBreakPriority(gfxBreakPriority::eNoBreak),
     mLastOptionalBreakFrameOffset(-1),
     mForceBreakFrameOffset(-1),
     mMinLineBSize(0),
     mTextIndent(0),
+    mRubyReflowState(nullptr),
     mFirstLetterStyleOK(false),
     mIsTopOfPage(false),
     mImpactedByFloats(false),
     mLastFloatWasLetterFrame(false),
     mLineIsEmpty(false),
     mLineEndsInBR(false),
     mNeedBackup(false),
     mInFirstLine(false),
@@ -863,16 +864,20 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
     // includes room for the side margins.
     // For now, set the available block-size to unconstrained always.
     LogicalSize availSize = mBlockReflowState->ComputedSize(frameWM);
     availSize.BSize(frameWM) = NS_UNCONSTRAINEDSIZE;
     reflowStateHolder.emplace(mPresContext, *psd->mReflowState,
                               aFrame, availSize);
     nsHTMLReflowState& reflowState = *reflowStateHolder;
     reflowState.mLineLayout = this;
+    if (mRubyReflowState) {
+      reflowState.mRubyReflowState = mRubyReflowState;
+      mRubyReflowState = nullptr;
+    }
     reflowState.mFlags.mIsTopOfPage = mIsTopOfPage;
     if (reflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE) {
       reflowState.AvailableISize() = availableSpaceOnLine;
     }
     WritingMode stateWM = reflowState.GetWritingMode();
     pfd->mMargin =
       reflowState.ComputedLogicalMargin().ConvertTo(lineWM, stateWM);
     pfd->mBorderPadding =
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -22,16 +22,20 @@
 #include "plarena.h"
 #include "gfxTypes.h"
 #include "WritingModes.h"
 #include "JustificationUtils.h"
 
 class nsFloatManager;
 struct nsStyleText;
 
+namespace mozilla {
+class RubyReflowState;
+}
+
 class nsLineLayout {
 public:
   /**
    * @param aBaseLineLayout the nsLineLayout for ruby base,
    * nullptr if no separate base nsLineLayout is needed.
    */
   nsLineLayout(nsPresContext* aPresContext,
                nsFloatManager* aFloatManager,
@@ -93,16 +97,23 @@ public:
   }
 
   int32_t GetCurrentSpanCount() const;
 
   void SplitLineTo(int32_t aNewCount);
 
   bool IsZeroBSize();
 
+  // The ruby layout will be passed to the next frame to be reflowed
+  // via the HTML reflow state.
+  void SetRubyReflowState(mozilla::RubyReflowState* aRubyReflowState)
+  {
+    mRubyReflowState = aRubyReflowState;
+  }
+
   // Reflows the frame and returns the reflow status. aPushedFrame is true
   // if the frame is pushed to the next line because it doesn't fit.
   void ReflowFrame(nsIFrame* aFrame,
                    nsReflowStatus& aReflowStatus,
                    nsHTMLReflowMetrics* aMetrics,
                    bool& aPushedFrame);
 
   void AddBulletFrame(nsIFrame* aFrame, const nsHTMLReflowMetrics& aMetrics);
@@ -553,16 +564,20 @@ protected:
   // max-element-size calculation.
   nscoord mTextIndent;
 
   // This state varies during the reflow of a line but is line
   // "global" state not span "local" state.
   int32_t mLineNumber;
   mozilla::JustificationInfo mJustificationInfo;
 
+  // The ruby layout for the next frame to be reflowed.
+  // It is reset every time it is used.
+  mozilla::RubyReflowState* mRubyReflowState;
+
   int32_t mTotalPlacedFrames;
 
   nscoord mBStartEdge;
   nscoord mMaxStartBoxBSize;
   nscoord mMaxEndBoxBSize;
 
   nscoord mInflationMinFontSize;
 
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -50,170 +50,172 @@ nsRubyBaseContainerFrame::GetType() cons
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyBaseContainerFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyBaseContainer"), aResult);
 }
 #endif
 
-class MOZ_STACK_CLASS PairEnumerator
+/**
+ * Ruby column is a unit consists of one ruby base and all ruby
+ * annotations paired with it.
+ * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing
+ */
+struct MOZ_STACK_CLASS mozilla::RubyColumn
+{
+  nsIFrame* mBaseFrame;
+  nsAutoTArray<nsIFrame*, RTC_ARRAY_SIZE> mTextFrames;
+  RubyColumn() : mBaseFrame(nullptr) { }
+};
+
+class MOZ_STACK_CLASS RubyColumnEnumerator
 {
 public:
-  PairEnumerator(nsRubyBaseContainerFrame* aRBCFrame,
-                 const nsTArray<nsRubyTextContainerFrame*>& aRTCFrames);
+  RubyColumnEnumerator(nsRubyBaseContainerFrame* aRBCFrame,
+                       const nsTArray<nsRubyTextContainerFrame*>& aRTCFrames);
 
   void Next();
   bool AtEnd() const;
 
   uint32_t GetLevelCount() const { return mFrames.Length(); }
   nsIFrame* GetFrame(uint32_t aIndex) const { return mFrames[aIndex]; }
   nsIFrame* GetBaseFrame() const { return GetFrame(0); }
   nsIFrame* GetTextFrame(uint32_t aIndex) const { return GetFrame(aIndex + 1); }
-  void GetFrames(nsIFrame*& aBaseFrame, nsTArray<nsIFrame*>& aTextFrames) const;
+  void GetColumn(RubyColumn& aColumn) const;
 
 private:
   nsAutoTArray<nsIFrame*, RTC_ARRAY_SIZE + 1> mFrames;
 };
 
-PairEnumerator::PairEnumerator(
-    nsRubyBaseContainerFrame* aBaseContainer,
-    const nsTArray<nsRubyTextContainerFrame*>& aTextContainers)
+RubyColumnEnumerator::RubyColumnEnumerator(
+  nsRubyBaseContainerFrame* aBaseContainer,
+  const nsTArray<nsRubyTextContainerFrame*>& aTextContainers)
 {
   const uint32_t rtcCount = aTextContainers.Length();
   mFrames.SetCapacity(rtcCount + 1);
   mFrames.AppendElement(aBaseContainer->GetFirstPrincipalChild());
   for (uint32_t i = 0; i < rtcCount; i++) {
-    nsIFrame* rtFrame = aTextContainers[i]->GetFirstPrincipalChild();
+    nsRubyTextContainerFrame* container = aTextContainers[i];
+    // If the container is for span, leave a nullptr here.
+    // Spans do not take part in pairing.
+    nsIFrame* rtFrame = !container->IsSpanContainer() ?
+      aTextContainers[i]->GetFirstPrincipalChild() : nullptr;
     mFrames.AppendElement(rtFrame);
   }
 }
 
 void
-PairEnumerator::Next()
+RubyColumnEnumerator::Next()
 {
   for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
     if (mFrames[i]) {
       mFrames[i] = mFrames[i]->GetNextSibling();
     }
   }
 }
 
 bool
-PairEnumerator::AtEnd() const
+RubyColumnEnumerator::AtEnd() const
 {
   for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
     if (mFrames[i]) {
       return false;
     }
   }
   return true;
 }
 
 void
-PairEnumerator::GetFrames(nsIFrame*& aBaseFrame,
-                          nsTArray<nsIFrame*>& aTextFrames) const
+RubyColumnEnumerator::GetColumn(RubyColumn& aColumn) const
 {
-  aBaseFrame = mFrames[0];
-  aTextFrames.ClearAndRetainStorage();
+  aColumn.mBaseFrame = mFrames[0];
+  aColumn.mTextFrames.ClearAndRetainStorage();
   for (uint32_t i = 1, iend = mFrames.Length(); i < iend; i++) {
-    aTextFrames.AppendElement(mFrames[i]);
+    aColumn.mTextFrames.AppendElement(mFrames[i]);
   }
 }
 
-nscoord
-nsRubyBaseContainerFrame::CalculateMaxSpanISize(
-    nsRenderingContext* aRenderingContext)
-{
-  nscoord max = 0;
-  uint32_t spanCount = mSpanContainers.Length();
-  for (uint32_t i = 0; i < spanCount; i++) {
-    nsIFrame* frame = mSpanContainers[i]->GetFirstPrincipalChild();
-    nscoord isize = frame->GetPrefISize(aRenderingContext);
-    max = std::max(max, isize);
-  }
-  return max;
-}
-
 static nscoord
-CalculatePairPrefISize(nsRenderingContext* aRenderingContext,
-                       const PairEnumerator& aEnumerator)
+CalculateColumnPrefISize(nsRenderingContext* aRenderingContext,
+                         const RubyColumnEnumerator& aEnumerator)
 {
   nscoord max = 0;
   uint32_t levelCount = aEnumerator.GetLevelCount();
   for (uint32_t i = 0; i < levelCount; i++) {
     nsIFrame* frame = aEnumerator.GetFrame(i);
     if (frame) {
       max = std::max(max, frame->GetPrefISize(aRenderingContext));
     }
   }
   return max;
 }
 
 /* virtual */ void
 nsRubyBaseContainerFrame::AddInlineMinISize(
     nsRenderingContext *aRenderingContext, nsIFrame::InlineMinISizeData *aData)
 {
-  if (!mSpanContainers.IsEmpty()) {
-    // Since spans are not breakable internally, use our pref isize
-    // directly if there is any span.
-    aData->currentLine += GetPrefISize(aRenderingContext);
-    return;
+  AutoTextContainerArray textContainers;
+  GetTextContainers(textContainers);
+
+  for (uint32_t i = 0, iend = textContainers.Length(); i < iend; i++) {
+    if (textContainers[i]->IsSpanContainer()) {
+      // Since spans are not breakable internally, use our pref isize
+      // directly if there is any span.
+      aData->currentLine += GetPrefISize(aRenderingContext);
+      return;
+    }
   }
 
   nscoord max = 0;
-  PairEnumerator enumerator(this, mTextContainers);
+  RubyColumnEnumerator enumerator(this, textContainers);
   for (; !enumerator.AtEnd(); enumerator.Next()) {
-    // We use *pref* isize for computing the min isize of pairs
+    // We use *pref* isize for computing the min isize of columns
     // because ruby bases and texts are unbreakable internally.
-    max = std::max(max, CalculatePairPrefISize(aRenderingContext, enumerator));
+    max = std::max(max, CalculateColumnPrefISize(aRenderingContext,
+                                                 enumerator));
   }
   aData->currentLine += max;
 }
 
 /* virtual */ void
 nsRubyBaseContainerFrame::AddInlinePrefISize(
     nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefISizeData *aData)
 {
+  AutoTextContainerArray textContainers;
+  GetTextContainers(textContainers);
+
   nscoord sum = 0;
-  PairEnumerator enumerator(this, mTextContainers);
+  RubyColumnEnumerator enumerator(this, textContainers);
   for (; !enumerator.AtEnd(); enumerator.Next()) {
-    sum += CalculatePairPrefISize(aRenderingContext, enumerator);
+    sum += CalculateColumnPrefISize(aRenderingContext, enumerator);
   }
-  sum = std::max(sum, CalculateMaxSpanISize(aRenderingContext));
+  for (uint32_t i = 0, iend = textContainers.Length(); i < iend; i++) {
+    if (textContainers[i]->IsSpanContainer()) {
+      nsIFrame* frame = textContainers[i]->GetFirstPrincipalChild();
+      sum = std::max(sum, frame->GetPrefISize(aRenderingContext));
+    }
+  }
   aData->currentLine += sum;
 }
 
 /* virtual */ bool 
 nsRubyBaseContainerFrame::IsFrameOfType(uint32_t aFlags) const 
 {
   return nsContainerFrame::IsFrameOfType(aFlags & 
          ~(nsIFrame::eLineParticipant));
 }
 
-void nsRubyBaseContainerFrame::AppendTextContainer(nsIFrame* aFrame)
+void
+nsRubyBaseContainerFrame::GetTextContainers(TextContainerArray& aTextContainers)
 {
-  nsRubyTextContainerFrame* rtcFrame = do_QueryFrame(aFrame);
-  MOZ_ASSERT(rtcFrame, "Must provide a ruby text container.");
-
-  nsTArray<nsRubyTextContainerFrame*>* containers = &mTextContainers;
-  if (!GetPrevContinuation() && !GetNextContinuation()) {
-    nsIFrame* onlyChild = rtcFrame->PrincipalChildList().OnlyChild();
-    if (onlyChild && onlyChild->IsPseudoFrame(rtcFrame->GetContent())) {
-      // Per CSS Ruby spec, if the only child of an rtc frame is
-      // a pseudo rt frame, it spans all bases in the segment.
-      containers = &mSpanContainers;
-    }
+  MOZ_ASSERT(aTextContainers.IsEmpty());
+  for (RubyTextContainerIterator iter(this); !iter.AtEnd(); iter.Next()) {
+    aTextContainers.AppendElement(iter.GetTextContainer());
   }
-  containers->AppendElement(rtcFrame);
-}
-
-void nsRubyBaseContainerFrame::ClearTextContainers() {
-  mSpanContainers.Clear();
-  mTextContainers.Clear();
 }
 
 /* virtual */ bool
 nsRubyBaseContainerFrame::CanContinueTextRun() const
 {
   return true;
 }
 
@@ -233,16 +235,24 @@ nsRubyBaseContainerFrame::ComputeSize(ns
 }
 
 /* virtual */ nscoord
 nsRubyBaseContainerFrame::GetLogicalBaseline(WritingMode aWritingMode) const
 {
   return mBaseline;
 }
 
+struct nsRubyBaseContainerFrame::ReflowState
+{
+  bool mAllowLineBreak;
+  const TextContainerArray& mTextContainers;
+  const nsHTMLReflowState& mBaseReflowState;
+  const nsTArray<UniquePtr<nsHTMLReflowState>>& mTextReflowStates;
+};
+
 // Check whether the given extra isize can fit in the line in base level.
 static bool
 ShouldBreakBefore(const nsHTMLReflowState& aReflowState, nscoord aExtraISize)
 {
   nsLineLayout* lineLayout = aReflowState.mLineLayout;
   int32_t offset;
   gfxBreakPriority priority;
   nscoord icoord = lineLayout->GetCurrentICoord();
@@ -261,62 +271,55 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
   aStatus = NS_FRAME_COMPLETE;
 
   if (!aReflowState.mLineLayout) {
     NS_ASSERTION(
       aReflowState.mLineLayout,
       "No line layout provided to RubyBaseContainerFrame reflow method.");
     return;
   }
+  MOZ_ASSERT(aReflowState.mRubyReflowState, "No ruby reflow state provided");
+
+  AutoTextContainerArray textContainers;
+  GetTextContainers(textContainers);
 
   MoveOverflowToChildList();
   // Ask text containers to drain overflows
-  const uint32_t rtcCount = mTextContainers.Length();
+  const uint32_t rtcCount = textContainers.Length();
   for (uint32_t i = 0; i < rtcCount; i++) {
-    mTextContainers[i]->MoveOverflowToChildList();
+    textContainers[i]->MoveOverflowToChildList();
   }
 
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
                         aReflowState.AvailableHeight());
 
-  const uint32_t spanCount = mSpanContainers.Length();
-  const uint32_t totalCount = rtcCount + spanCount;
   // We have a reflow state and a line layout for each RTC.
   // They are conceptually the state of the RTCs, but we don't actually
   // reflow those RTCs in this code. These two arrays are holders of
   // the reflow states and line layouts.
   // Since there are pointers refer to reflow states and line layouts,
   // it is necessary to guarantee that they won't be moved. For this
   // reason, they are wrapped in UniquePtr here.
   nsAutoTArray<UniquePtr<nsHTMLReflowState>, RTC_ARRAY_SIZE> reflowStates;
   nsAutoTArray<UniquePtr<nsLineLayout>, RTC_ARRAY_SIZE> lineLayouts;
-  reflowStates.SetCapacity(totalCount);
-  lineLayouts.SetCapacity(totalCount);
-
-  nsAutoTArray<nsHTMLReflowState*, RTC_ARRAY_SIZE> rtcReflowStates;
-  nsAutoTArray<nsHTMLReflowState*, RTC_ARRAY_SIZE> spanReflowStates;
-  rtcReflowStates.SetCapacity(rtcCount);
-  spanReflowStates.SetCapacity(spanCount);
+  reflowStates.SetCapacity(rtcCount);
+  lineLayouts.SetCapacity(rtcCount);
 
   // Begin the line layout for each ruby text container in advance.
-  for (uint32_t i = 0; i < totalCount; i++) {
-    nsIFrame* textContainer;
-    nsTArray<nsHTMLReflowState*>* reflowStateArray;
-    if (i < rtcCount) {
-      textContainer = mTextContainers[i];
-      reflowStateArray = &rtcReflowStates;
-    } else {
-      textContainer = mSpanContainers[i - rtcCount];
-      reflowStateArray = &spanReflowStates;
+  bool hasSpan = false;
+  for (uint32_t i = 0; i < rtcCount; i++) {
+    nsRubyTextContainerFrame* textContainer = textContainers[i];
+    if (textContainer->IsSpanContainer()) {
+      hasSpan = true;
     }
+
     nsHTMLReflowState* reflowState = new nsHTMLReflowState(
       aPresContext, *aReflowState.parentReflowState, textContainer, availSize);
     reflowStates.AppendElement(reflowState);
-    reflowStateArray->AppendElement(reflowState);
     nsLineLayout* lineLayout = new nsLineLayout(aPresContext,
                                                 reflowState->mFloatManager,
                                                 reflowState, nullptr,
                                                 aReflowState.mLineLayout);
     lineLayouts.AppendElement(lineLayout);
 
     // Line number is useless for ruby text
     // XXX nullptr here may cause problem, see comments for
@@ -357,80 +360,82 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
       aReflowState.mLineLayout->NotifyOptionalBreakPosition(
         this, 0, startEdge <= aReflowState.AvailableISize(),
         gfxBreakPriority::eNormalBreak)) {
     aStatus = NS_INLINE_LINE_BREAK_BEFORE();
   }
 
   nscoord isize = 0;
   if (aStatus == NS_FRAME_COMPLETE) {
-    // Reflow pairs excluding any span
-    bool allowInternalLineBreak = allowLineBreak && mSpanContainers.IsEmpty();
-    isize = ReflowPairs(aPresContext, allowInternalLineBreak,
-                        aReflowState, rtcReflowStates, aStatus);
+    // Reflow columns excluding any span
+    ReflowState reflowState = {
+      allowLineBreak && !hasSpan, textContainers, aReflowState, reflowStates
+    };
+    isize = ReflowColumns(reflowState, aStatus);
   }
 
-  // If there exists any span, the pairs must either be completely
+  // If there exists any span, the columns must either be completely
   // reflowed, or be not reflowed at all.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
-             NS_FRAME_IS_COMPLETE(aStatus) || mSpanContainers.IsEmpty());
+             NS_FRAME_IS_COMPLETE(aStatus) || !hasSpan);
   if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) &&
-      NS_FRAME_IS_COMPLETE(aStatus) && !mSpanContainers.IsEmpty()) {
+      NS_FRAME_IS_COMPLETE(aStatus) && hasSpan) {
     // Reflow spans
-    nscoord spanISize = ReflowSpans(aPresContext, aReflowState,
-                                    spanReflowStates);
+    ReflowState reflowState = {
+      false, textContainers, aReflowState, reflowStates
+    };
+    nscoord spanISize = ReflowSpans(reflowState);
     nscoord deltaISize = spanISize - isize;
     if (deltaISize <= 0) {
       RubyUtils::ClearReservedISize(this);
     } else if (allowLineBreak && ShouldBreakBefore(aReflowState, deltaISize)) {
       aStatus = NS_INLINE_LINE_BREAK_BEFORE();
     } else {
       RubyUtils::SetReservedISize(this, deltaISize);
       aReflowState.mLineLayout->AdvanceICoord(deltaISize);
       isize = spanISize;
     }
-  }
-    // When there are spans, ReflowPairs and ReflowOnePair won't
+    // When there are spans, ReflowColumns and ReflowOneColumn won't
     // record any optional break position. We have to record one
     // at the end of this segment.
     if (!NS_INLINE_IS_BREAK(aStatus) && allowLineBreak &&
         aReflowState.mLineLayout->NotifyOptionalBreakPosition(
           this, INT32_MAX, startEdge + isize <= aReflowState.AvailableISize(),
           gfxBreakPriority::eNormalBreak)) {
       aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
     }
+  }
 
   DebugOnly<nscoord> lineSpanSize = aReflowState.mLineLayout->EndSpan(this);
   // When there are no frames inside the ruby base container, EndSpan
   // will return 0. However, in this case, the actual width of the
   // container could be non-zero because of non-empty ruby annotations.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
              isize == lineSpanSize || mFrames.IsEmpty());
-  for (uint32_t i = 0; i < totalCount; i++) {
+  for (uint32_t i = 0; i < rtcCount; i++) {
     // It happens before the ruby text container is reflowed, and that
     // when it is reflowed, it will just use this size.
-    nsRubyTextContainerFrame* textContainer = i < rtcCount ?
-      mTextContainers[i] : mSpanContainers[i - rtcCount];
+    nsRubyTextContainerFrame* textContainer = textContainers[i];
     nsLineLayout* lineLayout = lineLayouts[i].get();
 
     RubyUtils::ClearReservedISize(textContainer);
     nscoord rtcISize = lineLayout->GetCurrentICoord();
     // Only span containers and containers with collapsed annotations
     // need reserving isize. For normal ruby text containers, their
     // children will be expanded properly. We only need to expand their
     // own size.
-    if (i < rtcCount) {
+    if (!textContainer->IsSpanContainer()) {
       rtcISize = isize;
     } else if (isize > rtcISize) {
       RubyUtils::SetReservedISize(textContainer, isize - rtcISize);
     }
 
     lineLayout->VerticalAlignLine();
     LogicalSize lineSize(lineWM, isize, lineLayout->GetFinalLineBSize());
-    textContainer->SetLineSize(lineSize);
+    aReflowState.mRubyReflowState->SetTextContainerInfo(i, textContainer, lineSize);
     lineLayout->EndLineReflow();
   }
 
   aDesiredSize.ISize(lineWM) = isize;
   nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
                                          borderPadding, lineWM, frameWM);
 }
 
@@ -438,139 +443,139 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
  * This struct stores the continuations after this frame and
  * corresponding text containers. It is used to speed up looking
  * ahead for nonempty continuations.
  */
 struct MOZ_STACK_CLASS nsRubyBaseContainerFrame::PullFrameState
 {
   ContinuationTraversingState mBase;
   nsAutoTArray<ContinuationTraversingState, RTC_ARRAY_SIZE> mTexts;
+  const TextContainerArray& mTextContainers;
 
-  explicit PullFrameState(nsRubyBaseContainerFrame* aFrame);
+  PullFrameState(nsRubyBaseContainerFrame* aBaseContainer,
+                 const TextContainerArray& aTextContainers);
 };
 
 nscoord
-nsRubyBaseContainerFrame::ReflowPairs(nsPresContext* aPresContext,
-                                      bool aAllowLineBreak,
-                                      const nsHTMLReflowState& aReflowState,
-                                      nsTArray<nsHTMLReflowState*>& aReflowStates,
-                                      nsReflowStatus& aStatus)
+nsRubyBaseContainerFrame::ReflowColumns(const ReflowState& aReflowState,
+                                        nsReflowStatus& aStatus)
 {
-  nsLineLayout* lineLayout = aReflowState.mLineLayout;
-  const uint32_t rtcCount = mTextContainers.Length();
+  nsLineLayout* lineLayout = aReflowState.mBaseReflowState.mLineLayout;
+  const uint32_t rtcCount = aReflowState.mTextContainers.Length();
   nscoord istart = lineLayout->GetCurrentICoord();
   nscoord icoord = istart;
   nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
   aStatus = NS_FRAME_COMPLETE;
 
-  mPairCount = 0;
-  nsIFrame* baseFrame = nullptr;
-  nsAutoTArray<nsIFrame*, RTC_ARRAY_SIZE> textFrames;
-  textFrames.SetCapacity(rtcCount);
-  PairEnumerator e(this, mTextContainers);
+  uint32_t columnIndex = 0;
+  RubyColumn column;
+  column.mTextFrames.SetCapacity(rtcCount);
+  RubyColumnEnumerator e(this, aReflowState.mTextContainers);
   for (; !e.AtEnd(); e.Next()) {
-    e.GetFrames(baseFrame, textFrames);
-    icoord += ReflowOnePair(aPresContext, aAllowLineBreak,
-                            aReflowState, aReflowStates,
-                            baseFrame, textFrames, reflowStatus);
+    e.GetColumn(column);
+    icoord += ReflowOneColumn(aReflowState, columnIndex, column, reflowStatus);
+    if (!NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
+      columnIndex++;
+    }
     if (NS_INLINE_IS_BREAK(reflowStatus)) {
       break;
     }
     // We are not handling overflow here.
     MOZ_ASSERT(reflowStatus == NS_FRAME_COMPLETE);
   }
 
   bool isComplete = false;
-  PullFrameState pullFrameState(this);
+  PullFrameState pullFrameState(this, aReflowState.mTextContainers);
   while (!NS_INLINE_IS_BREAK(reflowStatus)) {
     // We are not handling overflow here.
     MOZ_ASSERT(reflowStatus == NS_FRAME_COMPLETE);
 
     // Try pull some frames from next continuations. This call replaces
-    // |baseFrame| and |textFrames| with the frame pulled in each level.
-    PullOnePair(lineLayout, pullFrameState, baseFrame, textFrames, isComplete);
+    // frames in |column| with the frame pulled in each level.
+    PullOneColumn(lineLayout, pullFrameState, column, isComplete);
     if (isComplete) {
       // No more frames can be pulled.
       break;
     }
-    icoord += ReflowOnePair(aPresContext, aAllowLineBreak,
-                            aReflowState, aReflowStates,
-                            baseFrame, textFrames, reflowStatus);
+    icoord += ReflowOneColumn(aReflowState, columnIndex, column, reflowStatus);
+    if (!NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
+      columnIndex++;
+    }
   }
 
   if (!e.AtEnd() && NS_INLINE_IS_BREAK_AFTER(reflowStatus)) {
-    // The current pair has been successfully placed.
-    // Skip to the next pair and mark break before.
+    // The current column has been successfully placed.
+    // Skip to the next column and mark break before.
     e.Next();
-    e.GetFrames(baseFrame, textFrames);
+    e.GetColumn(column);
     reflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
   }
   if (!e.AtEnd() || (GetNextInFlow() && !isComplete)) {
     NS_FRAME_SET_INCOMPLETE(aStatus);
   }
 
   if (NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
-    if (!mPairCount || !mSpanContainers.IsEmpty()) {
-      // If no pair has been placed yet, or we have any span,
+    if (!columnIndex || !aReflowState.mAllowLineBreak) {
+      // If no column has been placed yet, or we have any span,
       // the whole container should be in the next line.
       aStatus = NS_INLINE_LINE_BREAK_BEFORE();
       return 0;
     }
     aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
-    MOZ_ASSERT(NS_FRAME_IS_COMPLETE(aStatus) || mSpanContainers.IsEmpty());
+    MOZ_ASSERT(NS_FRAME_IS_COMPLETE(aStatus) || aReflowState.mAllowLineBreak);
 
-    if (baseFrame) {
-      PushChildren(baseFrame, baseFrame->GetPrevSibling());
+    if (column.mBaseFrame) {
+      PushChildren(column.mBaseFrame, column.mBaseFrame->GetPrevSibling());
     }
     for (uint32_t i = 0; i < rtcCount; i++) {
-      nsIFrame* textFrame = textFrames[i];
+      nsIFrame* textFrame = column.mTextFrames[i];
       if (textFrame) {
-        mTextContainers[i]->PushChildren(textFrame,
-                                         textFrame->GetPrevSibling());
+        aReflowState.mTextContainers[i]->PushChildren(
+          textFrame, textFrame->GetPrevSibling());
       }
     }
   } else if (NS_INLINE_IS_BREAK_AFTER(reflowStatus)) {
     // |reflowStatus| being break after here may only happen when
-    // there is a break after the pair just pulled, or the whole
+    // there is a break after the column just pulled, or the whole
     // segment has been completely reflowed. In those cases, we do
     // not need to push anything.
     MOZ_ASSERT(e.AtEnd());
     aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
   }
 
   return icoord - istart;
 }
 
 nscoord
-nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext,
-                                        bool aAllowLineBreak,
-                                        const nsHTMLReflowState& aReflowState,
-                                        nsTArray<nsHTMLReflowState*>& aReflowStates,
-                                        nsIFrame* aBaseFrame,
-                                        const nsTArray<nsIFrame*>& aTextFrames,
-                                        nsReflowStatus& aStatus)
+nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
+                                          uint32_t aColumnIndex,
+                                          const RubyColumn& aColumn,
+                                          nsReflowStatus& aStatus)
 {
-  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
-  const uint32_t rtcCount = mTextContainers.Length();
-  MOZ_ASSERT(aTextFrames.Length() == rtcCount);
-  MOZ_ASSERT(aReflowStates.Length() == rtcCount);
-  nscoord istart = aReflowState.mLineLayout->GetCurrentICoord();
-  nscoord pairISize = 0;
+  const nsHTMLReflowState& baseReflowState = aReflowState.mBaseReflowState;
+  const auto& textReflowStates = aReflowState.mTextReflowStates;
+
+  WritingMode lineWM = baseReflowState.mLineLayout->GetWritingMode();
+  const uint32_t rtcCount = aReflowState.mTextContainers.Length();
+  MOZ_ASSERT(aColumn.mTextFrames.Length() == rtcCount);
+  MOZ_ASSERT(textReflowStates.Length() == rtcCount);
+  nscoord istart = baseReflowState.mLineLayout->GetCurrentICoord();
+  nscoord columnISize = 0;
 
   nsAutoString baseText;
-  if (aBaseFrame) {
-    if (!nsContentUtils::GetNodeTextContent(aBaseFrame->GetContent(),
+  if (aColumn.mBaseFrame) {
+    if (!nsContentUtils::GetNodeTextContent(aColumn.mBaseFrame->GetContent(),
                                             true, baseText)) {
       NS_RUNTIMEABORT("OOM");
     }
   }
 
   // Reflow text frames
   for (uint32_t i = 0; i < rtcCount; i++) {
-    nsIFrame* textFrame = aTextFrames[i];
+    nsIFrame* textFrame = aColumn.mTextFrames[i];
     if (textFrame) {
       MOZ_ASSERT(textFrame->GetType() == nsGkAtoms::rubyTextFrame);
       nsAutoString annotationText;
       if (!nsContentUtils::GetNodeTextContent(textFrame->GetContent(),
                                               true, annotationText)) {
         NS_RUNTIMEABORT("OOM");
       }
       // Per CSS Ruby spec, the content comparison for auto-hiding
@@ -580,139 +585,147 @@ nsRubyBaseContainerFrame::ReflowOnePair(
       // using the content tree text comparison is correct.
       if (annotationText.Equals(baseText)) {
         textFrame->AddStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE);
       } else {
         textFrame->RemoveStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE);
       }
 
       nsReflowStatus reflowStatus;
-      nsHTMLReflowMetrics metrics(*aReflowStates[i]);
+      nsHTMLReflowMetrics metrics(*textReflowStates[i]);
       RubyUtils::ClearReservedISize(textFrame);
 
       bool pushedFrame;
-      aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus,
-                                                 &metrics, pushedFrame);
+      textReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus,
+                                                    &metrics, pushedFrame);
       MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
                  "Any line break inside ruby box should has been suppressed");
-      pairISize = std::max(pairISize, metrics.ISize(lineWM));
+      columnISize = std::max(columnISize, metrics.ISize(lineWM));
     }
   }
-  if (aAllowLineBreak && ShouldBreakBefore(aReflowState, pairISize)) {
+  if (aReflowState.mAllowLineBreak &&
+      ShouldBreakBefore(baseReflowState, columnISize)) {
     // Since ruby text container uses an independent line layout, it
     // may successfully place a frame because the line is empty while
     // the line of base container is not.
     aStatus = NS_INLINE_LINE_BREAK_BEFORE();
     return 0;
   }
 
   // Reflow the base frame
-  if (aBaseFrame) {
-    MOZ_ASSERT(aBaseFrame->GetType() == nsGkAtoms::rubyBaseFrame);
+  if (aColumn.mBaseFrame) {
+    MOZ_ASSERT(aColumn.mBaseFrame->GetType() == nsGkAtoms::rubyBaseFrame);
     nsReflowStatus reflowStatus;
-    nsHTMLReflowMetrics metrics(aReflowState);
-    RubyUtils::ClearReservedISize(aBaseFrame);
+    nsHTMLReflowMetrics metrics(baseReflowState);
+    RubyUtils::ClearReservedISize(aColumn.mBaseFrame);
 
     bool pushedFrame;
-    aReflowState.mLineLayout->ReflowFrame(aBaseFrame, reflowStatus,
-                                          &metrics, pushedFrame);
+    baseReflowState.mLineLayout->ReflowFrame(aColumn.mBaseFrame, reflowStatus,
+                                             &metrics, pushedFrame);
     MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
                "Any line break inside ruby box should has been suppressed");
-    pairISize = std::max(pairISize, metrics.ISize(lineWM));
+    columnISize = std::max(columnISize, metrics.ISize(lineWM));
   }
 
   // Align all the line layout to the new coordinate.
-  nscoord icoord = istart + pairISize;
-  nscoord deltaISize = icoord - aReflowState.mLineLayout->GetCurrentICoord();
+  nscoord icoord = istart + columnISize;
+  nscoord deltaISize = icoord - baseReflowState.mLineLayout->GetCurrentICoord();
   if (deltaISize > 0) {
-    aReflowState.mLineLayout->AdvanceICoord(deltaISize);
-    if (aBaseFrame) {
-      RubyUtils::SetReservedISize(aBaseFrame, deltaISize);
+    baseReflowState.mLineLayout->AdvanceICoord(deltaISize);
+    if (aColumn.mBaseFrame) {
+      RubyUtils::SetReservedISize(aColumn.mBaseFrame, deltaISize);
     }
   }
   for (uint32_t i = 0; i < rtcCount; i++) {
-    nsLineLayout* lineLayout = aReflowStates[i]->mLineLayout;
-    nsIFrame* textFrame = aTextFrames[i];
+    if (aReflowState.mTextContainers[i]->IsSpanContainer()) {
+      continue;
+    }
+    nsLineLayout* lineLayout = textReflowStates[i]->mLineLayout;
+    nsIFrame* textFrame = aColumn.mTextFrames[i];
     nscoord deltaISize = icoord - lineLayout->GetCurrentICoord();
     if (deltaISize > 0) {
       lineLayout->AdvanceICoord(deltaISize);
       if (textFrame) {
         RubyUtils::SetReservedISize(textFrame, deltaISize);
       }
     }
-    if (aBaseFrame && textFrame) {
+    if (aColumn.mBaseFrame && textFrame) {
       lineLayout->AttachLastFrameToBaseLineLayout();
     }
   }
 
-  mPairCount++;
-  if (aAllowLineBreak &&
-      aReflowState.mLineLayout->NotifyOptionalBreakPosition(
-        this, mPairCount, icoord <= aReflowState.AvailableISize(),
+  if (aReflowState.mAllowLineBreak &&
+      baseReflowState.mLineLayout->NotifyOptionalBreakPosition(
+        this, aColumnIndex + 1, icoord <= baseReflowState.AvailableISize(),
         gfxBreakPriority::eNormalBreak)) {
     aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
   }
 
-  return pairISize;
+  return columnISize;
 }
 
 nsRubyBaseContainerFrame::PullFrameState::PullFrameState(
-    nsRubyBaseContainerFrame* aFrame)
-  : mBase(aFrame)
+    nsRubyBaseContainerFrame* aBaseContainer,
+    const TextContainerArray& aTextContainers)
+  : mBase(aBaseContainer)
+  , mTextContainers(aTextContainers)
 {
-  const uint32_t rtcCount = aFrame->mTextContainers.Length();
+  const uint32_t rtcCount = aTextContainers.Length();
   for (uint32_t i = 0; i < rtcCount; i++) {
-    mTexts.AppendElement(aFrame->mTextContainers[i]);
+    mTexts.AppendElement(aTextContainers[i]);
   }
 }
 
 void
-nsRubyBaseContainerFrame::PullOnePair(nsLineLayout* aLineLayout,
-                                      PullFrameState& aPullFrameState,
-                                      nsIFrame*& aBaseFrame,
-                                      nsTArray<nsIFrame*>& aTextFrames,
-                                      bool& aIsComplete)
+nsRubyBaseContainerFrame::PullOneColumn(nsLineLayout* aLineLayout,
+                                        PullFrameState& aPullFrameState,
+                                        RubyColumn& aColumn,
+                                        bool& aIsComplete)
 {
-  const uint32_t rtcCount = mTextContainers.Length();
+  const TextContainerArray& textContainers = aPullFrameState.mTextContainers;
+  const uint32_t rtcCount = textContainers.Length();
 
-  aBaseFrame = PullNextInFlowChild(aPullFrameState.mBase);
-  aIsComplete = !aBaseFrame;
+  aColumn.mBaseFrame = PullNextInFlowChild(aPullFrameState.mBase);
+  aIsComplete = !aColumn.mBaseFrame;
 
-  aTextFrames.ClearAndRetainStorage();
+  aColumn.mTextFrames.ClearAndRetainStorage();
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsIFrame* nextText =
-      mTextContainers[i]->PullNextInFlowChild(aPullFrameState.mTexts[i]);
-    aTextFrames.AppendElement(nextText);
+      textContainers[i]->PullNextInFlowChild(aPullFrameState.mTexts[i]);
+    aColumn.mTextFrames.AppendElement(nextText);
     // If there exists any frame in continations, we haven't
     // completed the reflow process.
     aIsComplete = aIsComplete && !nextText;
   }
 
   if (!aIsComplete) {
     // We pulled frames from the next line, hence mark it dirty.
     aLineLayout->SetDirtyNextLine();
   }
 }
 
 nscoord
-nsRubyBaseContainerFrame::ReflowSpans(nsPresContext* aPresContext,
-                                      const nsHTMLReflowState& aReflowState,
-                                      nsTArray<nsHTMLReflowState*>& aReflowStates)
+nsRubyBaseContainerFrame::ReflowSpans(const ReflowState& aReflowState)
 {
-  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
-  const uint32_t spanCount = mSpanContainers.Length();
+  WritingMode lineWM =
+    aReflowState.mBaseReflowState.mLineLayout->GetWritingMode();
   nscoord spanISize = 0;
 
-  for (uint32_t i = 0; i < spanCount; i++) {
-    nsRubyTextContainerFrame* container = mSpanContainers[i];
+  for (uint32_t i = 0, iend = aReflowState.mTextContainers.Length();
+       i < iend; i++) {
+    nsRubyTextContainerFrame* container = aReflowState.mTextContainers[i];
+    if (!container->IsSpanContainer()) {
+      continue;
+    }
+
     nsIFrame* rtFrame = container->GetFirstPrincipalChild();
     nsReflowStatus reflowStatus;
-    nsHTMLReflowMetrics metrics(*aReflowStates[i]);
+    nsHTMLReflowMetrics metrics(*aReflowState.mTextReflowStates[i]);
     bool pushedFrame;
-    aReflowStates[i]->mLineLayout->ReflowFrame(rtFrame, reflowStatus,
-                                               &metrics, pushedFrame);
+    aReflowState.mTextReflowStates[i]->mLineLayout->
+      ReflowFrame(rtFrame, reflowStatus, &metrics, pushedFrame);
     MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
                "Any line break inside ruby box should has been suppressed");
     spanISize = std::max(spanISize, metrics.ISize(lineWM));
   }
 
   return spanISize;
 }
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -8,26 +8,29 @@
 
 #ifndef nsRubyBaseContainerFrame_h___
 #define nsRubyBaseContainerFrame_h___
 
 #include "nsContainerFrame.h"
 #include "nsRubyTextContainerFrame.h"
 #include "nsRubyBaseFrame.h"
 #include "nsRubyTextFrame.h"
-
-#define RTC_ARRAY_SIZE 1
+#include "RubyReflowState.h"
 
 /**
  * Factory function.
  * @return a newly allocated nsRubyBaseContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
+namespace mozilla {
+struct RubyColumn;
+}
+
 class nsRubyBaseContainerFrame MOZ_FINAL : public nsContainerFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyBaseContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
@@ -54,72 +57,40 @@ public:
 
   virtual nscoord
     GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
-#ifdef DEBUG
-  void AssertTextContainersEmpty()
-  {
-    MOZ_ASSERT(mSpanContainers.IsEmpty());
-    MOZ_ASSERT(mTextContainers.IsEmpty());
-  }
-#endif
-
-  void AppendTextContainer(nsIFrame* aFrame);
-  void ClearTextContainers();
-
 protected:
   friend nsContainerFrame*
     NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyBaseContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
 
-  nscoord CalculateMaxSpanISize(nsRenderingContext* aRenderingContext);
-
-  nscoord ReflowPairs(nsPresContext* aPresContext,
-                      bool aAllowLineBreak,
-                      const nsHTMLReflowState& aReflowState,
-                      nsTArray<nsHTMLReflowState*>& aReflowStates,
-                      nsReflowStatus& aStatus);
+  typedef nsTArray<nsRubyTextContainerFrame*> TextContainerArray;
+  typedef nsAutoTArray<nsRubyTextContainerFrame*, RTC_ARRAY_SIZE> AutoTextContainerArray;
+  void GetTextContainers(TextContainerArray& aTextContainers);
 
-  nscoord ReflowOnePair(nsPresContext* aPresContext,
-                        bool aAllowLineBreak,
-                        const nsHTMLReflowState& aReflowState,
-                        nsTArray<nsHTMLReflowState*>& aReflowStates,
-                        nsIFrame* aBaseFrame,
-                        const nsTArray<nsIFrame*>& aTextFrames,
+  struct ReflowState;
+  nscoord ReflowColumns(const ReflowState& aReflowState,
                         nsReflowStatus& aStatus);
-
-  nscoord ReflowSpans(nsPresContext* aPresContext,
-                      const nsHTMLReflowState& aReflowState,
-                      nsTArray<nsHTMLReflowState*>& aReflowStates);
+  nscoord ReflowOneColumn(const ReflowState& aReflowState,
+                          uint32_t aColumnIndex,
+                          const mozilla::RubyColumn& aColumn,
+                          nsReflowStatus& aStatus);
+  nscoord ReflowSpans(const ReflowState& aReflowState);
 
   struct PullFrameState;
 
   // Pull ruby base and corresponding ruby text frames from
   // continuations after them.
-  void PullOnePair(nsLineLayout* aLineLayout,
-                   PullFrameState& aPullFrameState,
-                   nsIFrame*& aBaseFrame,
-                   nsTArray<nsIFrame*>& aTextFrames,
-                   bool& aIsComplete);
-
-  /**
-   * The arrays of ruby text containers below are filled before the ruby
-   * frame (parent) starts reflowing this ruby segment, and cleared when
-   * the reflow finishes.
-   */
-
-  // The text containers that contain a span, which spans all ruby
-  // pairs in the ruby segment.
-  nsTArray<nsRubyTextContainerFrame*> mSpanContainers;
-  // Normal text containers that do not contain spans.
-  nsTArray<nsRubyTextContainerFrame*> mTextContainers;
+  void PullOneColumn(nsLineLayout* aLineLayout,
+                     PullFrameState& aPullFrameState,
+                     mozilla::RubyColumn& aColumn,
+                     bool& aIsComplete);
 
   nscoord mBaseline;
-  uint32_t mPairCount;
 };
 
 #endif /* nsRubyBaseContainerFrame_h___ */
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -5,16 +5,18 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby" */
 #include "nsRubyFrame.h"
 #include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "WritingModes.h"
+#include "RubyUtils.h"
+#include "RubyReflowState.h"
 #include "nsRubyBaseContainerFrame.h"
 #include "nsRubyTextContainerFrame.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
@@ -54,81 +56,16 @@ nsRubyFrame::IsFrameOfType(uint32_t aFla
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Ruby"), aResult);
 }
 #endif
 
-class MOZ_STACK_CLASS TextContainerIterator
-{
-public:
-  explicit TextContainerIterator(nsRubyBaseContainerFrame* aBaseContainer);
-  void Next();
-  bool AtEnd() const { return !mFrame; }
-  nsRubyTextContainerFrame* GetTextContainer() const
-  {
-    return static_cast<nsRubyTextContainerFrame*>(mFrame);
-  }
-
-private:
-  nsIFrame* mFrame;
-};
-
-TextContainerIterator::TextContainerIterator(
-    nsRubyBaseContainerFrame* aBaseContainer)
-{
-  mFrame = aBaseContainer;
-  Next();
-}
-
-void
-TextContainerIterator::Next()
-{
-  if (mFrame) {
-    mFrame = mFrame->GetNextSibling();
-    if (mFrame && mFrame->GetType() != nsGkAtoms::rubyTextContainerFrame) {
-      mFrame = nullptr;
-    }
-  }
-}
-
-/**
- * This class is responsible for appending and clearing
- * text container list of the base container.
- */
-class MOZ_STACK_CLASS AutoSetTextContainers
-{
-public:
-  explicit AutoSetTextContainers(nsRubyBaseContainerFrame* aBaseContainer);
-  ~AutoSetTextContainers();
-
-private:
-  nsRubyBaseContainerFrame* mBaseContainer;
-};
-
-AutoSetTextContainers::AutoSetTextContainers(
-    nsRubyBaseContainerFrame* aBaseContainer)
-  : mBaseContainer(aBaseContainer)
-{
-#ifdef DEBUG
-  aBaseContainer->AssertTextContainersEmpty();
-#endif
-  for (TextContainerIterator iter(aBaseContainer);
-       !iter.AtEnd(); iter.Next()) {
-    aBaseContainer->AppendTextContainer(iter.GetTextContainer());
-  }
-}
-
-AutoSetTextContainers::~AutoSetTextContainers()
-{
-  mBaseContainer->ClearTextContainers();
-}
-
 /**
  * This enumerator enumerates each segment.
  */
 class MOZ_STACK_CLASS SegmentEnumerator
 {
 public:
   explicit SegmentEnumerator(nsRubyFrame* aRubyFrame);
 
@@ -164,29 +101,27 @@ SegmentEnumerator::Next()
 }
 
 /* virtual */ void
 nsRubyFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
                                nsIFrame::InlineMinISizeData *aData)
 {
   nscoord max = 0;
   for (SegmentEnumerator e(this); !e.AtEnd(); e.Next()) {
-    AutoSetTextContainers holder(e.GetBaseContainer());
     max = std::max(max, e.GetBaseContainer()->GetMinISize(aRenderingContext));
   }
   aData->currentLine += max;
 }
 
 /* virtual */ void
 nsRubyFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
                                 nsIFrame::InlinePrefISizeData *aData)
 {
   nscoord sum = 0;
   for (SegmentEnumerator e(this); !e.AtEnd(); e.Next()) {
-    AutoSetTextContainers holder(e.GetBaseContainer());
     sum += e.GetBaseContainer()->GetPrefISize(aRenderingContext);
   }
   aData->currentLine += sum;
 }
 
 /* virtual */ LogicalSize
 nsRubyFrame::ComputeSize(nsRenderingContext *aRenderingContext,
                            WritingMode aWM,
@@ -289,29 +224,30 @@ SanityCheckRubyPosition(int8_t aRubyPosi
 #endif
 
 void
 nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
                            const nsHTMLReflowState& aReflowState,
                            nsRubyBaseContainerFrame* aBaseContainer,
                            nsReflowStatus& aStatus)
 {
-  AutoSetTextContainers holder(aBaseContainer);
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   LogicalSize availSize(lineWM, aReflowState.AvailableISize(),
                         aReflowState.AvailableBSize());
 
   nsAutoTArray<nsRubyTextContainerFrame*, RTC_ARRAY_SIZE> textContainers;
-  for (TextContainerIterator iter(aBaseContainer); !iter.AtEnd(); iter.Next()) {
+  for (RubyTextContainerIterator iter(aBaseContainer); !iter.AtEnd(); iter.Next()) {
     textContainers.AppendElement(iter.GetTextContainer());
   }
   const uint32_t rtcCount = textContainers.Length();
+  RubyReflowState rubyReflowState(lineWM, textContainers);
 
   nsHTMLReflowMetrics baseMetrics(aReflowState);
   bool pushedFrame;
+  aReflowState.mLineLayout->SetRubyReflowState(&rubyReflowState);
   aReflowState.mLineLayout->ReflowFrame(aBaseContainer, aStatus,
                                         &baseMetrics, pushedFrame);
 
   if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
     if (aBaseContainer != mFrames.FirstChild()) {
       // Some segments may have been reflowed before, hence it is not
       // a break-before for the ruby container.
       aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_NOT_COMPLETE);
@@ -380,20 +316,23 @@ nsRubyFrame::ReflowSegment(nsPresContext
   // lines, so we use 0 instead. (i.e. we assume that the base container
   // is adjacent to the ruby frame's block-start edge.)
   // XXX We may need to add border/padding here. See bug 1055667.
   (lineWM.IsVertical() ? baseRect.x : baseRect.y) = 0;
   // The rect for offsets of text containers.
   nsRect offsetRect = baseRect;
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsRubyTextContainerFrame* textContainer = textContainers[i];
+    rubyReflowState.AdvanceCurrentContainerIndex();
+
     nsReflowStatus textReflowStatus;
     nsHTMLReflowMetrics textMetrics(aReflowState);
     nsHTMLReflowState textReflowState(aPresContext, aReflowState,
                                       textContainer, availSize);
+    textReflowState.mRubyReflowState = &rubyReflowState;
     // FIXME We probably shouldn't be using the same nsLineLayout for
     //       the text containers. But it should be fine now as we are
     //       not actually using this line layout to reflow something,
     //       but just read the writing mode from it.
     textReflowState.mLineLayout = aReflowState.mLineLayout;
     textContainer->Reflow(aPresContext, textMetrics,
                           textReflowState, textReflowStatus);
     // Ruby text containers always return NS_FRAME_COMPLETE even when
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -5,16 +5,17 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-text-container" */
 
 #include "nsRubyTextContainerFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "WritingModes.h"
+#include "RubyReflowState.h"
 #include "mozilla/UniquePtr.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
@@ -57,28 +58,86 @@ nsRubyTextContainerFrame::IsFrameOfType(
 {
   if (aFlags & eSupportsCSSTransforms) {
     return false;
   }
   return nsRubyTextContainerFrameSuper::IsFrameOfType(aFlags);
 }
 
 /* virtual */ void
+nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
+                                              nsFrameList& aChildList)
+{
+  nsRubyTextContainerFrameSuper::SetInitialChildList(aListID, aChildList);
+  UpdateSpanFlag();
+}
+
+/* virtual */ void
+nsRubyTextContainerFrame::AppendFrames(ChildListID aListID,
+                                       nsFrameList& aFrameList)
+{
+  nsRubyTextContainerFrameSuper::AppendFrames(aListID, aFrameList);
+  UpdateSpanFlag();
+}
+
+/* virtual */ void
+nsRubyTextContainerFrame::InsertFrames(ChildListID aListID,
+                                       nsIFrame* aPrevFrame,
+                                       nsFrameList& aFrameList)
+{
+  nsRubyTextContainerFrameSuper::InsertFrames(aListID, aPrevFrame, aFrameList);
+  UpdateSpanFlag();
+}
+
+/* virtual */ void
+nsRubyTextContainerFrame::RemoveFrame(ChildListID aListID,
+                                      nsIFrame* aOldFrame)
+{
+  nsRubyTextContainerFrameSuper::RemoveFrame(aListID, aOldFrame);
+  UpdateSpanFlag();
+}
+
+void
+nsRubyTextContainerFrame::UpdateSpanFlag()
+{
+  bool isSpan = false;
+  // The continuation checks are safe here because spans never break.
+  if (!GetPrevContinuation() && !GetNextContinuation()) {
+    nsIFrame* onlyChild = mFrames.OnlyChild();
+    if (onlyChild && onlyChild->IsPseudoFrame(GetContent())) {
+      // Per CSS Ruby spec, if the only child of an rtc frame is
+      // a pseudo rt frame, it spans all bases in the segment.
+      isSpan = true;
+    }
+  }
+
+  if (isSpan) {
+    AddStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
+  } else {
+    RemoveStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
+  }
+}
+
+/* virtual */ void
 nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
                                  nsHTMLReflowMetrics& aDesiredSize,
                                  const nsHTMLReflowState& aReflowState,
                                  nsReflowStatus& aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 
+  MOZ_ASSERT(aReflowState.mRubyReflowState, "No ruby reflow state provided");
+
   // All rt children have already been reflowed. All we need to do is
   // to report complete and return the desired size provided by the
   // ruby base container.
 
   // Although a ruby text container may have continuations, returning
   // NS_FRAME_COMPLETE here is still safe, since its parent, ruby frame,
   // ignores the status, and continuations of the ruby base container
   // will take care of our continuations.
   aStatus = NS_FRAME_COMPLETE;
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
-  aDesiredSize.SetSize(lineWM, mLineSize);
+  const RubyReflowState::TextContainerInfo& info =
+    aReflowState.mRubyReflowState->GetCurrentTextContainerInfo(this);
+  aDesiredSize.SetSize(lineWM, info.mLineSize);
 }
--- a/layout/generic/nsRubyTextContainerFrame.h
+++ b/layout/generic/nsRubyTextContainerFrame.h
@@ -37,26 +37,37 @@ public:
                       nsHTMLReflowMetrics& aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus& aStatus) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
+  // nsContainerFrame overrides
+  virtual void SetInitialChildList(ChildListID aListID,
+                                   nsFrameList& aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID aListID,
+                            nsFrameList& aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
+                            nsFrameList& aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID aListID,
+                           nsIFrame* aOldFrame) MOZ_OVERRIDE;
+
+  bool IsSpanContainer() const
+  {
+    return GetStateBits() & NS_RUBY_TEXT_CONTAINER_IS_SPAN;
+  }
+
 protected:
   friend nsContainerFrame*
     NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyTextContainerFrame(nsStyleContext* aContext)
-    : nsRubyTextContainerFrameSuper(aContext)
-    , mLineSize(mozilla::WritingMode(aContext)) {}
+    : nsRubyTextContainerFrameSuper(aContext) {}
 
+  void UpdateSpanFlag();
+
+  // For MoveOverflowToChildList
   friend class nsRubyBaseContainerFrame;
-  void SetLineSize(const mozilla::LogicalSize& aSize) { mLineSize = aSize; }
-
-  // The intended dimensions of the ruby text container. It is set by
-  // the corresponding ruby base container when the segment is reflowed,
-  // and used when the ruby text container is reflowed by its parent.
-  mozilla::LogicalSize mLineSize;
 };
 
 #endif /* nsRubyTextContainerFrame_h___ */
--- a/media/libpng/CHANGES
+++ b/media/libpng/CHANGES
@@ -5092,16 +5092,43 @@ Version 1.6.15rc02 [November 14, 2014]
     is different from POSIX make and other make programs.  Surround the
     macro definitions with ifndef guards (Cosmin).
 
 Version 1.6.15rc03 [November 16, 2014]
   Added "-D_CRT_SECURE_NO_WARNINGS" to CFLAGS in scripts/makefile.vcwin32.
   Removed the obsolete $ARCH variable from scripts/makefile.darwin.
 
 Version 1.6.15 [November 20, 2014]
+  No changes.
+
+Version 1.6.16beta01 [December 14, 2014]
+  Added ".align 2" to arm/filter_neon.S to support old GAS assemblers that
+    don't do alignment correctly.
+  Revised Makefile.am and scripts/symbols.dfn to work with MinGW/MSYS
+    (Bob Friesenhahn).
+
+Version 1.6.16beta02 [December 15, 2014]
+  Revised Makefile.am and scripts/*.dfn again to work with MinGW/MSYS;
+    renamed scripts/*.dfn to scripts/*.c (John Bowler).
+
+Version 1.6.16beta03 [December 21, 2014]
+  Quiet a "comparison always true" warning in pngstest.c (John Bowler).
+
+Version 1.6.16rc01 [December 21, 2014]
+  Restored a test on width that was removed from png.c at libpng-1.6.9
+    (Bug report by Alex Eubanks).
+
+Version 1.6.16rc02 [December 21, 2014]
+  Undid the update to pngrutil.c in 1.6.16rc01.
+
+Version 1.6.16rc03 [December 21, 2014]
+  Fixed an overflow in png_combine_row with very wide interlaced images.
+
+Version 1.6.16 [December 22, 2014]
+  No changes.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
 to subscribe)
 or to glennrp at users.sourceforge.net
 
 Glenn R-P
--- a/media/libpng/LICENSE
+++ b/media/libpng/LICENSE
@@ -5,17 +5,17 @@ included in the libpng distribution, the
 
 COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
 
 If you modify libpng you may insert additional notices immediately following
 this sentence.
 
 This code is released under the libpng license.
 
-libpng versions 1.2.6, August 15, 2004, through 1.6.15, November 20, 2014, are
+libpng versions 1.2.6, August 15, 2004, through 1.6.16, December 22, 2014, are
 Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are
 distributed according to the same disclaimer and license as libpng-1.2.5
 with the following individual added to the list of Contributing Authors
 
    Cosmin Truta
 
 libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
 Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
@@ -103,9 +103,9 @@ boxes and the like:
 Also, the PNG logo (in PNG format, of course) is supplied in the
 files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
 
 Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
 certification mark of the Open Source Initiative.
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-November 20, 2014
+December 22, 2014
--- a/media/libpng/MOZCHANGES
+++ b/media/libpng/MOZCHANGES
@@ -1,37 +1,47 @@
 
 Changes made to pristine libpng source by mozilla.org developers.
 
+2014/12/22  -- Synced with libpng-1.6.16 (bug #1114360).
+               Added arm.patch file.
+
 2014/11/20  -- Synced with libpng-1.6.15 (bug #1102523).
 
 2014/10/23  -- Synced with libpng-1.6.14 (bug #1087841).
 
 2014/08/21  -- Synced with libpng-1.6.13 (bug #1021713).
                Renamed mozpngconf.h to pnglibconf.h.
+               Revised system arm/filter_neon.S to include the lines
+               #define PNG_READ_SUPPORTED and  #define MOZ_PNG_HAVE_ARM_NEON
+               because the moz.build system doesn't yet pass -DDefined
+               macros to the assembler.
 
 2014/03/21  -- Synced with libpng-1.6.10 (bug #980488) and disabled
                PNG_WARNINGS and PNG_ERROR_TEXT in non-debug builds.
                Limit image dimensions to 32767 (bug #251381, #591822,
                and #967656).
 
 2014/03/04  -- Enabled PNG_WARNINGS and other stuff in mozpngconf.h
                as part of enabling Freetype2 with PNG (bug #969814).
 
-2014/03/03  -- Fixed hang with empty IDAT (bug #974825).
+2014/03/03  -- Fixed hang with empty IDAT (bug #974825). This will be
+               fixed in libpng-1.6.10.
 
 2014/02/18  -- Exposed png_error(), etc. redefinitions to applications
-               (moved them from pngpriv.h to png.h).
+               (moved them from pngpriv.h to png.h). This will be fixed
+               in libpng-1.6.10.
 
 2014/02/18  -- Disabled PNG_FIXED_POINT_SUPPORTED in mozpngconf.h (we
                don't need both FIXED and FLOATING_POINT support).
 
 2014/02/15  -- Synced with libpng-1.6.9 (bug #952505).
 
 2014/02/11  -- Fixed crash with empty PLTE, CVE-2013-6954 (bug #945912).
+               This will be fixed in libpng-1.6.9.
 
 2013/12/11  -- Enable ARM support (bug #832390).
 
 2013/11/17  -- Synced with libpng-1.6.7 (bug #938740).
 
 2013/09/21  -- Synced with libpng-1.6.6 (bug #841734).
 
 2013/07/17  -- Synced with libpng-1.5.17 (bug #886499).
--- a/media/libpng/README
+++ b/media/libpng/README
@@ -1,9 +1,9 @@
-README for libpng version 1.6.15 - November 20, 2014 (shared library 16.0)
+README for libpng version 1.6.16 - December 22, 2014 (shared library 16.0)
 See the note about version numbers near the top of png.h
 
 See INSTALL for instructions on how to install libpng.
 
 Libpng comes in several distribution formats.  Get libpng-*.tar.gz or
 libpng-*.tar.xz or if you want UNIX-style line endings in the text files,
 or lpng*.7z or lpng*.zip if you want DOS-style line endings.
 
--- a/media/libpng/apng.patch
+++ b/media/libpng/apng.patch
@@ -273,28 +273,28 @@ Index: pngget.c
 +    return 0;
 +}
 +#endif /* APNG */
  #endif /* READ || WRITE */
 Index: png.h
 ===================================================================
 --- png.h
 +++ png.h
-@@ -473,6 +473,10 @@
+@@ -476,6 +476,10 @@
  #   include "pnglibconf.h"
  #endif
  
 +#define PNG_APNG_SUPPORTED
 +#define PNG_READ_APNG_SUPPORTED
 +#define PNG_WRITE_APNG_SUPPORTED
 +
  #ifndef PNG_VERSION_INFO_ONLY
     /* Machine specific configuration. */
  #  include "pngconf.h"
-@@ -563,6 +567,17 @@
+@@ -566,6 +570,17 @@
   * See pngconf.h for base types that vary by machine/system
   */
  
 +#ifdef PNG_APNG_SUPPORTED
 +/* dispose_op flags from inside fcTL */
 +#define PNG_DISPOSE_OP_NONE        0x00
 +#define PNG_DISPOSE_OP_BACKGROUND  0x01
 +#define PNG_DISPOSE_OP_PREVIOUS    0x02
@@ -302,39 +302,39 @@ Index: png.h
 +/* blend_op flags from inside fcTL */
 +#define PNG_BLEND_OP_SOURCE        0x00
 +#define PNG_BLEND_OP_OVER          0x01
 +#endif /* APNG */
 +
  /* This triggers a compiler error in png.c, if png.c and png.h
   * do not agree upon the version number.
   */
-@@ -883,6 +898,10 @@
+@@ -886,6 +901,10 @@
  #define PNG_INFO_sPLT 0x2000   /* ESR, 1.0.6 */
  #define PNG_INFO_sCAL 0x4000   /* ESR, 1.0.6 */
  #define PNG_INFO_IDAT 0x8000   /* ESR, 1.0.6 */
 +#ifdef PNG_APNG_SUPPORTED
 +#define PNG_INFO_acTL 0x10000
 +#define PNG_INFO_fcTL 0x20000
 +#endif
  
  /* This is used for the transformation routines, as some of them
   * change these values for the row.  It also should enable using
-@@ -920,6 +939,10 @@
+@@ -923,6 +942,10 @@
  #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
  typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
 +#ifdef PNG_APNG_SUPPORTED
 +typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
 +    png_uint_32));
 +#endif
  
  /* The following callback receives png_uint_32 row_number, int pass for the
   * png_bytep data of the row.  When transforming an interlaced image the
-@@ -3259,6 +3282,75 @@
+@@ -3262,6 +3285,75 @@
   *  END OF HARDWARE AND SOFTWARE OPTIONS
   ******************************************************************************/
  
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
 +   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
 +
 +PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
@@ -400,17 +400,17 @@ Index: png.h
 +PNG_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
 +   png_infop info_ptr));
 +#endif /* WRITE_APNG */
 +#endif /* APNG */
 +
  /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
   * defs, and in scripts/symbols.def.
   */
-@@ -3267,7 +3359,11 @@
+@@ -3270,7 +3362,11 @@
   * one to use is one more than this.)
   */
  #ifdef PNG_EXPORT_LAST_ORDINAL
 +#ifdef PNG_APNG_SUPPORTED
 +  PNG_EXPORT_LAST_ORDINAL(264);
 +#else
    PNG_EXPORT_LAST_ORDINAL(244);
 +#endif /* APNG */
@@ -1018,17 +1018,17 @@ Index: pngset.c
 +
  #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  static png_byte
  check_location(png_const_structrp png_ptr, int location)
 Index: pngrutil.c
 ===================================================================
 --- pngrutil.c
 +++ pngrutil.c
-@@ -818,6 +818,11 @@
+@@ -819,6 +819,11 @@
     filter_type = buf[11];
     interlace_type = buf[12];
  
 +#ifdef PNG_READ_APNG_SUPPORTED
 +   png_ptr->first_frame_width = width;
 +   png_ptr->first_frame_height = height;
 +#endif
 +
new file mode 100644
--- /dev/null
+++ b/media/libpng/arm.patch
@@ -0,0 +1,48 @@
+diff --git ../../../libpng-1.6.16/arm/arm_init.c arm/arm_init.c
+--- ../../../libpng-1.6.16/arm/arm_init.c	2014-12-21 22:08:08.000000000 -0500
++++ arm/arm_init.c	2014-12-22 17:33:57.556305506 -0500
+@@ -29,17 +29,17 @@
+  * You may set the macro PNG_ARM_NEON_FILE to the file name of file containing
+  * a fragment of C source code which defines the png_have_neon function.  There
+  * are a number of implementations in contrib/arm-neon, but the only one that
+  * has partial support is contrib/arm-neon/linux.c - a generic Linux
+  * implementation which reads /proc/cpufino.
+  */
+ #ifndef PNG_ARM_NEON_FILE
+ #  ifdef __linux__
+-#     define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
++#     define PNG_ARM_NEON_FILE "linux.c"
+ #  endif
+ #endif
+ 
+ #ifdef PNG_ARM_NEON_FILE
+ 
+ #include <signal.h> /* for sig_atomic_t */
+ static int png_have_neon(png_structp png_ptr);
+ #include PNG_ARM_NEON_FILE
+diff --git ../../../libpng-1.6.16/arm/filter_neon.S arm/filter_neon.S
+--- ../../../libpng-1.6.16/arm/filter_neon.S	2014-12-21 22:08:08.000000000 -0500
++++ arm/filter_neon.S	2014-12-22 17:43:31.588323649 -0500
+@@ -5,16 +5,22 @@
+  * Written by Mans Rullgard, 2011.
+  * Last changed in libpng 1.6.16 [December 22, 2014]
+  *
+  * This code is released under the libpng license.
+  * For conditions of distribution and use, see the disclaimer
+  * and license in png.h
+  */
+ 
++/* These are required because Mozilla's moz.build system doesn't pass
++ * -DDefined macros to the assembler.
++ */
++#define PNG_READ_SUPPORTED
++#define MOZ_PNG_HAVE_ARM_NEON
++
+ /* This is required to get the symbol renames, which are #defines, and the
+  * definitions (or not) of PNG_ARM_NEON_OPT and PNG_ARM_NEON_IMPLEMENTATION.
+  */
+ #define PNG_VERSION_INFO_ONLY
+ #include "../pngpriv.h"
+ 
+ #if defined(__linux__) && defined(__ELF__)
+ .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
--- a/media/libpng/arm/arm_init.c
+++ b/media/libpng/arm/arm_init.c
@@ -1,33 +1,34 @@
 
 /* arm_init.c - NEON optimised filter functions
  *
  * Copyright (c) 2014 Glenn Randers-Pehrson
  * Written by Mans Rullgard, 2011.
- * Last changed in libpng 1.6.10 [March 6, 2014]
+ * Last changed in libpng 1.6.16 [December 22, 2014]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 /* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
  * called.
  */
 #define _POSIX_SOURCE 1
 
 #include "../pngpriv.h"
 
 #ifdef PNG_READ_SUPPORTED
+
 #if PNG_ARM_NEON_OPT > 0
 #ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */
 /* WARNING: it is strongly recommended that you do not build libpng with
  * run-time checks for CPU features if at all possible.  In the case of the ARM
  * NEON instructions there is no processor-specific way of detecting the
- * presense of the required support, therefore run-time detectioon is extremely
+ * presence of the required support, therefore run-time detection is extremely
  * OS specific.
  *
  * You may set the macro PNG_ARM_NEON_FILE to the file name of file containing
  * a fragment of C source code which defines the png_have_neon function.  There
  * are a number of implementations in contrib/arm-neon, but the only one that
  * has partial support is contrib/arm-neon/linux.c - a generic Linux
  * implementation which reads /proc/cpufino.
  */
@@ -125,9 +126,9 @@ png_init_filter_functions_neon(png_struc
    {
       pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
       pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
       pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
           png_read_filter_row_paeth4_neon;
    }
 }
 #endif /* PNG_ARM_NEON_OPT > 0 */
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ */
--- a/media/libpng/arm/filter_neon.S
+++ b/media/libpng/arm/filter_neon.S
@@ -1,45 +1,45 @@
 
 /* filter_neon.S - NEON optimised filter functions
  *
- * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Copyright (c) 2014 Glenn Randers-Pehrson
  * Written by Mans Rullgard, 2011.
- * Last changed in libpng 1.6.8 [December 19, 2013]
+ * Last changed in libpng 1.6.16 [December 22, 2014]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
 /* These are required because Mozilla's moz.build system doesn't pass
  * -DDefined macros to the assembler.
  */
 #define PNG_READ_SUPPORTED
 #define MOZ_PNG_HAVE_ARM_NEON
 
-/* This is required to get the symbol renames, which are #defines, and also
- * includes the definition (or not) of PNG_ARM_NEON_OPT and
- * PNG_ARM_NEON_IMPLEMENTATION.
+/* This is required to get the symbol renames, which are #defines, and the
+ * definitions (or not) of PNG_ARM_NEON_OPT and PNG_ARM_NEON_IMPLEMENTATION.
  */
 #define PNG_VERSION_INFO_ONLY
 #include "../pngpriv.h"
 
 #if defined(__linux__) && defined(__ELF__)
 .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
 #endif
 
+#ifdef PNG_READ_SUPPORTED
+
 /* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for
  * ARM64).  The code in arm/filter_neon_intrinsics.c supports ARM64, however it
  * only works if -mfpu=neon is specified on the GCC command line.  See pngpriv.h
  * for the logic which sets PNG_USE_ARM_NEON_ASM:
  */
 #if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */
 
-#ifdef PNG_READ_SUPPORTED
 #if PNG_ARM_NEON_OPT > 0
 
 #ifdef __ELF__
 #   define ELF
 #else
 #   define ELF @
 #endif
 
@@ -50,19 +50,18 @@
     .macro endfunc
 ELF     .size   \name, . - \name
         .endfunc
         .purgem endfunc
     .endm
         .text
 
         /* Explicitly specifying alignment here because some versions of
-           gas don't align code correctly. See
-           http://lists.gnu.org/archive/html/bug-binutils/2011-06/msg00199.html
-           and https://bugzilla.mozilla.org/show_bug.cgi?id=920992
+         * GAS don't align code correctly.  This is harmless in correctly
+         * written versions of GAS.
          */
         .align 2
 
     .if \export
         .global \name
     .endif
 ELF     .type   \name, STT_FUNC
         .func   \name
@@ -251,10 +250,10 @@ 1:
         vadd.u8         d3,  d3,  d7
         vst1.32         {d3[0]},  [r1], r4
         subs            r12, r12, #12
         bgt             1b
 
         pop             {r4,pc}
 endfunc
 #endif /* PNG_ARM_NEON_OPT > 0 */
-#endif /* PNG_READ_SUPPORTED */
 #endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */
+#endif /* READ */
--- a/media/libpng/arm/filter_neon_intrinsics.c
+++ b/media/libpng/arm/filter_neon_intrinsics.c
@@ -1,24 +1,26 @@
 
 /* filter_neon_intrinsics.c - NEON optimised filter functions
  *
- * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Copyright (c) 2014 Glenn Randers-Pehrson
  * Written by James Yu <james.yu at linaro.org>, October 2013.
  * Based on filter_neon.S, written by Mans Rullgard, 2011.
  *
- * Last changed in libpng 1.6.8 [December 19, 2013]
+ * Last changed in libpng 1.6.16 [December 22, 2014]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
 #include "../pngpriv.h"
 
+#ifdef PNG_READ_SUPPORTED
+
 /* This code requires -mfpu=neon on the command line: */
 #if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */
 
 #include <arm_neon.h>
 
 /* libpng row pointers are not necessarily aligned to any particular boundary,
  * however this code will only work with appropriate alignment.  arm/arm_init.c
  * checks for this (and will not compile unless it is done). This code uses
@@ -30,17 +32,16 @@
 /* The following relies on a variable 'temp_pointer' being declared with type
  * 'type'.  This is written this way just to hide the GCC strict aliasing
  * warning; note that the code is safe because there never is an alias between
  * the input and output pointers.
  */
 #define png_ldr(type,pointer)\
    (temp_pointer = png_ptr(type,pointer), *temp_pointer)
 
-#ifdef PNG_READ_SUPPORTED
 #if PNG_ARM_NEON_OPT > 0
 
 void
 png_read_filter_row_up_neon(png_row_infop row_info, png_bytep row,
    png_const_bytep prev_row)
 {
    png_bytep rp = row;
    png_bytep rp_stop = row + row_info->rowbytes;
@@ -363,10 +364,10 @@ png_read_filter_row_paeth4_neon(png_row_
 
       vlast = vpp.val[3];
 
       vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0);
    }
 }
 
 #endif /* PNG_ARM_NEON_OPT > 0 */
-#endif /* PNG_READ_SUPPORTED */
 #endif /* PNG_ARM_NEON_IMPLEMENTATION == 1 (intrinsics) */
+#endif /* READ */
--- a/media/libpng/arm/linux.c
+++ b/media/libpng/arm/linux.c
@@ -1,28 +1,28 @@
 /* contrib/arm-neon/linux.c
  *
  * Copyright (c) 2014 Glenn Randers-Pehrson
  * Written by John Bowler, 2014.
- * Last changed in libpng 1.6.10 [March 6, 2014]
+ * Last changed in libpng 1.6.16 [December 22, 2014]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
  * SEE contrib/arm-neon/README before reporting bugs
  *
  * STATUS: SUPPORTED
  * BUG REPORTS: png-mng-implement@sourceforge.net
  *
  * png_have_neon implemented for Linux by reading the widely available
  * pseudo-file /proc/cpuinfo.
  *
- * This code is strict ANSI-C and is probably moderately portable, it does
- * however use <stdio.h> and assumes that /proc/cpuinfo is never localized.
+ * This code is strict ANSI-C and is probably moderately portable; it does
+ * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
  */
 #include <stdio.h>
 
 static int
 png_have_neon(png_structp png_ptr)
 {
    FILE *f = fopen("/proc/cpuinfo", "rb");
 
@@ -147,13 +147,15 @@ png_have_neon(png_structp png_ptr)
                break;
 
             default:
                png_error(png_ptr, "png_have_neon: internal error (bug)");
          }
       }
    }
 
+#ifdef PNG_WARNINGS_SUPPORTED
    else
       png_warning(png_ptr, "/proc/cpuinfo open failed");
+#endif
 
    return 0;
 }
--- a/media/libpng/libpng-manual.txt
+++ b/media/libpng/libpng-manual.txt
@@ -1,22 +1,22 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.6.15 - November 20, 2014
+ libpng version 1.6.16 - December 22, 2014
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2014 Glenn Randers-Pehrson
 
  This document is released under the libpng license.
  For conditions of distribution and use, see the disclaimer
  and license in png.h
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.6.15 - November 20, 2014
+ libpng versions 0.97, January 1998, through 1.6.16 - December 22, 2014
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2014 Glenn Randers-Pehrson
 
  libpng 1.0 beta 6 - version 0.96 - May 28, 1997
  Updated and distributed by Andreas Dilger
  Copyright (c) 1996, 1997 Andreas Dilger
 
  libpng 1.0 beta 2 - version 0.88 - January 26, 1996
@@ -643,25 +643,22 @@ callback function:
       png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks,
          (int)(sizeof unused_chunks)/5);
     #endif
 
 User limits
 
 The PNG specification allows the width and height of an image to be as
 large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns.
-Since very few applications really need to process such large images,
-we have imposed an arbitrary 1-million limit on rows and columns.
 Larger images will be rejected immediately with a png_error() call. If
-you wish to change this limit, you can use
+you wish to reduce these limits, you can use
 
    png_set_user_limits(png_ptr, width_max, height_max);
 
-to set your own limits, or use width_max = height_max = 0x7fffffffL
-to allow all valid dimensions (libpng may reject some very large images
+to set your own limits (libpng may reject some very wide images
 anyway because of potential buffer overflow conditions).
 
 You should put this statement after you create the PNG structure and
 before calling png_read_info(), png_read_png(), or png_process_data().
 
 When writing a PNG datastream, put this statement before calling
 png_write_info() or png_write_png().
 
@@ -5032,29 +5029,29 @@ The following have been removed:
 The signatures of many exported functions were changed, such that
    png_structp became png_structrp or png_const_structrp
    png_infop became png_inforp or png_const_inforp
 where "rp" indicates a "restricted pointer".
 
 Error detection in some chunks has improved; in particular the iCCP chunk
 reader now does pretty complete validation of the basic format.  Some bad
 profiles that were previously accepted are now accepted with a warning or
-rejected, depending upon the png_set_benign_errors() setting, in particular the
-very old broken Microsoft/HP 3144-byte sRGB profile.  Starting with
+rejected, depending upon the png_set_benign_errors() setting, in particular
+the very old broken Microsoft/HP 3144-byte sRGB profile.  Starting with
 libpng-1.6.11, recognizing and checking sRGB profiles can be avoided by
 means of
 
     #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && \
         defined(PNG_SET_OPTION_SUPPORTED)
        png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE,
            PNG_OPTION_ON);
     #endif
 
-It's not a good idea to do this if you are using the "simplified API",
-which needs to be able to recognize an sRGB profile conveyed via the iCCP
+It's not a good idea to do this if you are using the new "simplified API",
+which needs to be able to recognize sRGB profiles conveyed via the iCCP
 chunk.
 
 The PNG spec requirement that only grayscale profiles may appear in images
 with color type 0 or 4 and that even if the image only contains gray pixels,
 only RGB profiles may appear in images with color type 2, 3, or 6, is now
 enforced.  The sRGB chunk is allowed to appear in images with any color type
 and is interpreted by libpng to convey a one-tracer-curve gray profile or a
 three-tracer-curve RGB profile as appropriate.
@@ -5272,23 +5269,23 @@ over "if (something)" and if "(!somethin
 We do not use the TAB character for indentation in the C sources.
 
 Lines do not exceed 80 characters.
 
 Other rules can be inferred by inspecting the libpng source.
 
 XVI. Y2K Compliance in libpng
 
-November 20, 2014
+December 22, 2014
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
 
 This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.6.15 are Y2K compliant.  It is my belief that earlier
+upward through 1.6.16 are Y2K compliant.  It is my belief that earlier
 versions were also Y2K compliant.
 
 Libpng only has two year fields.  One is a 2-byte unsigned integer
 that will hold years up to 65535.  The other, which is deprecated,
 holds the date in text format, and will hold years up to 9999.
 
 The integer is
     "png_uint_16 year" in png_time_struct.
--- a/media/libpng/png.c
+++ b/media/libpng/png.c
@@ -1,25 +1,25 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.6.15 [November 20, 2014]
+ * Last changed in libpng 1.6.16 [December 22, 2014]
  * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_15 Your_png_h_is_not_version_1_6_15;
+typedef png_libpng_version_1_6_16 Your_png_h_is_not_version_1_6_16;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
  * stream we can set num_bytes = 8 so that libpng will not attempt to read
  * or write any of the magic bytes before it starts on the IHDR.
  */
 
 #ifdef PNG_READ_SUPPORTED
@@ -764,23 +764,23 @@ png_const_charp PNGAPI
 png_get_copyright(png_const_structrp png_ptr)
 {
    PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
 #ifdef PNG_STRING_COPYRIGHT
    return PNG_STRING_COPYRIGHT
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-     "libpng version 1.6.15 - November 20, 2014" PNG_STRING_NEWLINE \
+     "libpng version 1.6.16 - December 22, 2014" PNG_STRING_NEWLINE \
      "Copyright (c) 1998-2014 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
      PNG_STRING_NEWLINE;
 #  else
-      return "libpng version 1.6.15 - November 20, 2014\
+      return "libpng version 1.6.16 - December 22, 2014\
       Copyright (c) 1998-2014 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
 #  endif
 #endif
 }
 
 /* The following return the library version as a short string in the
@@ -1070,17 +1070,17 @@ png_colorspace_check_gamma(png_const_str
    return 1;
 }
 
 void /* PRIVATE */
 png_colorspace_set_gamma(png_const_structrp png_ptr,
    png_colorspacerp colorspace, png_fixed_point gAMA)
 {
    /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
-    * occur.  Since the fixed point representation is assymetrical it is
+    * occur.  Since the fixed point representation is asymetrical it is
     * possible for 1/gamma to overflow the limit of 21474 and this means the
     * gamma value must be at least 5/100000 and hence at most 20000.0.  For
     * safety the limits here are a little narrower.  The values are 0.00016 to
     * 6250.0, which are truly ridiculous gamma values (and will produce
     * displays that are all black or all white.)
     *
     * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
     * handling code, which only required the value to be >0.
@@ -1319,17 +1319,17 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_
     *
     * So this code uses the perhaps slightly less optimal but more
     * understandable and totally obvious approach of calculating color-scale.
     *
     * This algorithm depends on the precision in white-scale and that is
     * (1/white-y), so we can immediately see that as white-y approaches 0 the
     * accuracy inherent in the cHRM chunk drops off substantially.
     *
-    * libpng arithmetic: a simple invertion of the above equations
+    * libpng arithmetic: a simple inversion of the above equations
     * ------------------------------------------------------------
     *
     *    white_scale = 1/white-y
     *    white-X = white-x * white-scale
     *    white-Y = 1.0
     *    white-Z = (1 - white-x - white-y) * white_scale
     *
     *    white-C = red-C + green-C + blue-C
@@ -1812,17 +1812,17 @@ png_icc_profile_error(png_const_structrp
          pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/
       }
 #  endif
    /* The 'reason' is an arbitrary message, allow +79 maximum 195 */
    pos = png_safecat(message, (sizeof message), pos, reason);
    PNG_UNUSED(pos)
 
    /* This is recoverable, but make it unconditionally an app_error on write to
-    * avoid writing invalid ICC profiles into PNG files.  (I.e.  we handle them
+    * avoid writing invalid ICC profiles into PNG files (i.e., we handle them
     * on read, with a warning, but on write unless the app turns off
     * application errors the PNG won't be written.)
     */
    png_chunk_report(png_ptr, message,
       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
 
    return 0;
 }
@@ -1831,17 +1831,17 @@ png_icc_profile_error(png_const_structrp
 #ifdef PNG_sRGB_SUPPORTED
 int /* PRIVATE */
 png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
    int intent)
 {
    /* sRGB sets known gamma, end points and (from the chunk) intent. */
    /* IMPORTANT: these are not necessarily the values found in an ICC profile
     * because ICC profiles store values adapted to a D50 environment; it is
-    * expected that the ICC profile mediaWhitePointTag will be D50, see the
+    * expected that the ICC profile mediaWhitePointTag will be D50; see the
     * checks and code elsewhere to understand this better.
     *
     * These XYZ values, which are accurate to 5dp, produce rgb to gray
     * coefficients of (6968,23435,2366), which are reduced (because they add up
     * to 32769 not 32768) to (6968,23434,2366).  These are the values that
     * libpng has traditionally used (and are the best values given the 15bit
     * algorithm used by the rgb to gray code.)
     */
@@ -2456,16 +2456,27 @@ png_colorspace_set_rgb_coefficients(png_
       else
          png_error(png_ptr, "internal error handling cHRM->XYZ");
    }
 }
 #endif
 
 #endif /* COLORSPACE */
 
+#ifdef __GNUC__
+/* This exists solely to work round a warning from GNU C. */
+static int /* PRIVATE */
+png_gt(size_t a, size_t b)
+{
+    return a > b;
+}
+#else
+#   define png_gt(a,b) ((a) > (b))
+#endif
+
 void /* PRIVATE */
 png_check_IHDR(png_const_structrp png_ptr,
    png_uint_32 width, png_uint_32 height, int bit_depth,
    int color_type, int interlace_type, int compression_type,
    int filter_type)
 {
    int error = 0;
 
@@ -2475,16 +2486,38 @@ png_check_IHDR(png_const_structrp png_pt
       png_warning(png_ptr, "Image width is zero in IHDR");
       error = 1;
    }
    else if (width > PNG_UINT_31_MAX)
    {
       png_warning(png_ptr, "Invalid image width in IHDR");
       error = 1;
    }
+
+   else if (png_gt(width,
+                   (PNG_SIZE_MAX >> 3) /* 8-byte RGBA pixels */
+                   - 48                /* big_row_buf hack */
+                   - 1                 /* filter byte */
+                   - 7*8               /* rounding width to multiple of 8 pix */
+                   - 8))               /* extra max_pixel_depth pad */
+   {
+      /* The size of the row must be within the limits of this architecture.
+       * Because the read code can perform arbitrary transformations the
+       * maximum size is checked here.  Because the code in png_read_start_row
+       * adds extra space "for safety's sake" in several places a conservative
+       * limit is used here.
+       *
+       * NOTE: it would be far better to check the size that is actually used,
+       * but the effect in the real world is minor and the changes are more
+       * extensive, therefore much more dangerous and much more difficult to
+       * write in a way that avoids compiler warnings.
+       */
+      png_warning(png_ptr, "Image width is too large for this architecture");
+      error = 1;
+   }
    else
    {
 #     ifdef PNG_SET_USER_LIMITS_SUPPORTED
       if (width > png_ptr->user_width_max)
 #     else
       if (width > PNG_USER_WIDTH_MAX)
 #     endif
       {
--- a/media/libpng/png.h
+++ b/media/libpng/png.h
@@ -1,22 +1,22 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.15, November 20, 2014
+ * libpng version 1.6.16, December 22, 2014
  * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license (See LICENSE, below)
  *
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.6.15, November 20, 2014: Glenn
+ *   libpng versions 0.97, January 1998, through 1.6.16, December 22, 2014: Glenn
  *   See also "Contributing Authors", below.
  *
  * Note about libpng version numbers:
  *
  *   Due to various miscommunications, unforeseen code incompatibilities
  *   and occasional factors outside the authors' control, version numbering
  *   on the library has not always been consistent and straightforward.
  *   The following table summarizes matters since version 0.89c, which was
@@ -204,16 +204,19 @@
  *    1.6.13rc01-02           16    10613  16.so.16.13[.0]
  *    1.6.13                  16    10613  16.so.16.13[.0]
  *    1.6.14beta01-07         16    10614  16.so.16.14[.0]
  *    1.6.14rc01-02           16    10614  16.so.16.14[.0]
  *    1.6.14                  16    10614  16.so.16.14[.0]
  *    1.6.15beta01-08         16    10615  16.so.16.15[.0]
  *    1.6.15rc01-03           16    10615  16.so.16.15[.0]
  *    1.6.15                  16    10615  16.so.16.15[.0]
+ *    1.6.16beta01-03         16    10616  16.so.16.16[.0]
+ *    1.6.16rc01-02           16    10616  16.so.16.16[.0]
+ *    1.6.16                  16    10616  16.so.16.16[.0]
  *
  *   Henceforth the source version will match the shared-library major
  *   and minor numbers; the shared-library major version number will be
  *   used for changes in backward compatibility, as it is intended.  The
  *   PNG_LIBPNG_VER macro, which is not used within libpng but is available
  *   for applications, is an unsigned integer of the form xyyzz corresponding
  *   to the source version x.y.z (leading zeros in y and z).  Beta versions
  *   were given the previous public release number plus a letter, until
@@ -235,17 +238,17 @@
 /*
  * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
  *
  * If you modify libpng you may insert additional notices immediately following
  * this sentence.
  *
  * This code is released under the libpng license.
  *
- * libpng versions 1.2.6, August 15, 2004, through 1.6.15, November 20, 2014, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.6.16, December 22, 2014, are
  * Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are
  * distributed according to the same disclaimer and license as libpng-1.2.5
  * with the following individual added to the list of Contributing Authors:
  *
  *    Cosmin Truta
  *
  * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
  * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
@@ -347,23 +350,23 @@
  *
  * Thanks to Frank J. T. Wojcik for helping with the documentation.
  */
 
 /*
  * Y2K compliance in libpng:
  * =========================
  *
- *    November 20, 2014
+ *    December 22, 2014
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.6.15 are Y2K compliant.  It is my belief that
+ *    upward through 1.6.16 are Y2K compliant.  It is my belief that
  *    earlier versions were also Y2K compliant.
  *
  *    Libpng only has two year fields.  One is a 2-byte unsigned integer
  *    that will hold years up to 65535.  The other, which is deprecated,
  *    holds the date in text format, and will hold years up to 9999.
  *
  *    The integer is
  *        "png_uint_16 year" in png_time_struct.
@@ -415,27 +418,27 @@
  * file has been stripped from your copy of libpng, you can find it at
  * <http://www.libpng.org/pub/png/libpng-manual.txt>
  *
  * If you just need to read a PNG file and don't want to read the documentation
  * skip to the end of this file and read the section entitled 'simplified API'.
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.15"
+#define PNG_LIBPNG_VER_STRING "1.6.16"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.6.15 - November 20, 2014\n"
+     " libpng version 1.6.16 - December 22, 2014\n"
 
 #define PNG_LIBPNG_VER_SONUM   16
 #define PNG_LIBPNG_VER_DLLNUM  16
 
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 15
+#define PNG_LIBPNG_VER_RELEASE 16
 
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
  */
 
 #define PNG_LIBPNG_VER_BUILD  0
 
 /* Release Status */
@@ -456,17 +459,17 @@
 #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
 
 /* Careful here.  At one time, Guy wanted to use 082, but that would be octal.
  * We must not include leading zeros.
  * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10615 /* 1.6.15 */
+#define PNG_LIBPNG_VER 10616 /* 1.6.16 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
  */
 #ifndef PNGLCONF_H
     /* If pnglibconf.h is missing, you can
      * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h
      */
@@ -576,17 +579,17 @@ extern "C" {
 /* blend_op flags from inside fcTL */
 #define PNG_BLEND_OP_SOURCE        0x00
 #define PNG_BLEND_OP_OVER          0x01
 #endif /* APNG */
 
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_15;
+typedef char* png_libpng_version_1_6_16;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
  * png_struct is the cache of information used while reading or writing a single
  * PNG file.  One of these is always required, although the simplified API
  * (below) hides the creation and destruction of it.
  */
 typedef struct png_struct_def png_struct;
--- a/media/libpng/pngconf.h
+++ b/media/libpng/pngconf.h
@@ -1,12 +1,12 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.6.15,November 20, 2014
+ * libpng version 1.6.16,December 22, 2014
  *
  * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
--- a/media/libpng/pngrutil.c
+++ b/media/libpng/pngrutil.c
@@ -783,16 +783,17 @@ png_inflate_read(png_structrp png_ptr, p
    {
       png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
       return Z_STREAM_ERROR;
    }
 }
 #endif
 
 /* Read and check the IDHR chunk */
+
 void /* PRIVATE */
 png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[13];
    png_uint_32 width, height;
    int bit_depth, color_type, compression_type, filter_type;
    int interlace_type;
 
@@ -852,18 +853,17 @@ png_handle_IHDR(png_structrp png_ptr, pn
          break;
 
       case PNG_COLOR_TYPE_RGB_ALPHA:
          png_ptr->channels = 4;
          break;
    }
 
    /* Set up other useful info */
-   png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
-   png_ptr->channels);
+   png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels);
    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
    png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
    png_debug1(3, "channels = %d", png_ptr->channels);
    png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);
    png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
        color_type, interlace_type, compression_type, filter_type);
 }
 
@@ -3177,17 +3177,17 @@ png_check_chunk_name(png_structrp png_pt
  * (dp) is filled from the start by replicating the available pixels.  If
  * 'display' is false only those pixels present in the pass are filled in.
  */
 void /* PRIVATE */
 png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display)
 {
    unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
    png_const_bytep sp = png_ptr->row_buf + 1;
-   png_uint_32 row_width = png_ptr->width;
+   png_alloc_size_t row_width = png_ptr->width;
    unsigned int pass = png_ptr->pass;
    png_bytep end_ptr = 0;
    png_byte end_byte = 0;
    unsigned int end_mask;
 
    png_debug(1, "in png_combine_row");
 
    /* Added in 1.5.6: it should not be possible to enter this routine until at
@@ -3452,17 +3452,17 @@ png_combine_row(png_const_structrp png_p
             /* When doing the 'block' algorithm the pixel in the pass gets
              * replicated to adjacent pixels.  This is why the even (0,2,4,6)
              * passes are skipped above - the entire expanded row is copied.
              */
             bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;
 
             /* But don't allow this number to exceed the actual row width. */
             if (bytes_to_copy > row_width)
-               bytes_to_copy = row_width;
+               bytes_to_copy = (unsigned int)/*SAFE*/row_width;
          }
 
          else /* normal row; Adam7 only ever gives us one pixel to copy. */
             bytes_to_copy = pixel_depth;
 
          /* In Adam7 there is a constant offset between where the pixels go. */
          bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;
 
@@ -3632,17 +3632,17 @@ png_combine_row(png_const_structrp png_p
 
                   if (row_width <= bytes_to_jump)
                      return;
 
                   sp += bytes_to_jump;
                   dp += bytes_to_jump;
                   row_width -= bytes_to_jump;
                   if (bytes_to_copy > row_width)
-                     bytes_to_copy = row_width;
+                     bytes_to_copy = (unsigned int)/*SAFE*/row_width;
                }
          }
 
          /* NOT REACHED*/
       } /* pixel_depth >= 8 */
 
       /* Here if pixel_depth < 8 to check 'end_ptr' below. */
    }
@@ -4438,17 +4438,17 @@ png_read_start_row(png_structrp png_ptr)
    else
    {
       png_ptr->num_rows = png_ptr->height;
       png_ptr->iwidth = png_ptr->width;
    }
 
    max_pixel_depth = png_ptr->pixel_depth;
 
-   /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of
+   /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of
     * calculations to calculate the final pixel depth, then
     * png_do_read_transforms actually does the transforms.  This means that the
     * code which effectively calculates this value is actually repeated in three
     * separate places.  They must all match.  Innocent changes to the order of
     * transformations can and will break libpng in a way that causes memory
     * overwrites.
     *
     * TODO: fix this.