Merge autoland to mozilla-central. a=merge
authorOana Pop Rus <opoprus@mozilla.com>
Fri, 01 Feb 2019 11:32:06 +0200
changeset 456392 9e6217a541aa84c3bd635459d842b6fbfed311de
parent 456381 200859112d0d6b8d39fcb661d7c60163421880e5 (current diff)
parent 456391 1617ad03a14ef357d9e68c103f9291ea8982759a (diff)
child 456401 d58901c5036ffa06da6144f22a31479116ee0835
push id19
push usermdeboer@mozilla.com
push dateFri, 01 Feb 2019 10:05:45 +0000
reviewersmerge
milestone67.0a1
Merge autoland to mozilla-central. a=merge
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -1688,20 +1688,17 @@ impl<'a> PictureUpdateState<'a> {
         let picture = &picture_primitives[pic_index.0];
         if !picture.is_visible() {
             return
         }
 
         let new_fallback = match picture.raster_config {
             Some(ref config) => {
                 let surface = &mut self.surfaces[config.surface_index.0];
-                if surface.surface_spatial_node_index == surface.raster_spatial_node_index && (
-                    surface.rect.size.width > MAX_SURFACE_SIZE ||
-                    surface.rect.size.height > MAX_SURFACE_SIZE
-                ) {
+                if !config.establishes_raster_root {
                     surface.raster_spatial_node_index = fallback_raster_spatial_node;
                 }
                 surface.raster_spatial_node_index
             }
             None => fallback_raster_spatial_node,
         };
 
         for child_pic_index in &picture.prim_list.pictures {
@@ -2641,17 +2638,17 @@ impl PicturePrimitive {
         }
 
         // Restore the pictures list used during recursion.
         self.prim_list.pictures = child_pictures;
 
         // If this picture establishes a surface, then map the surface bounding
         // rect into the parent surface coordinate space, and propagate that up
         // to the parent.
-        if let Some(ref raster_config) = self.raster_config {
+        if let Some(ref mut raster_config) = self.raster_config {
             let mut surface_rect = {
                 let surface = state.current_surface_mut();
                 // Inflate the local bounding rect if required by the filter effect.
                 // This inflaction factor is to be applied to the surface itsefl.
                 let inflation_size = match raster_config.composite_mode {
                     PictureCompositeMode::Filter(FilterOp::Blur(_)) => surface.inflation_factor,
                     PictureCompositeMode::Filter(FilterOp::DropShadow(_, blur_radius, _)) =>
                         (blur_radius * BLUR_SAMPLE_SCALE).ceil(),
@@ -2676,20 +2673,23 @@ impl PicturePrimitive {
                 gpu_cache.invalidate(&self.gpu_location);
                 if let PictureCompositeMode::Filter(FilterOp::DropShadow(..)) = raster_config.composite_mode {
                     gpu_cache.invalidate(&self.extra_gpu_data_handle);
                 }
                 self.local_rect = surface_rect;
             }
 
             // Check if any of the surfaces can't be rasterized in local space but want to.
-            if raster_config.establishes_raster_root && state.are_raster_roots_assigned {
-                state.are_raster_roots_assigned =
-                    surface_rect.size.width <= MAX_SURFACE_SIZE &&
-                    surface_rect.size.height <= MAX_SURFACE_SIZE;
+            if raster_config.establishes_raster_root {
+                if surface_rect.size.width > MAX_SURFACE_SIZE ||
+                    surface_rect.size.height > MAX_SURFACE_SIZE
+                {
+                    raster_config.establishes_raster_root = false;
+                    state.are_raster_roots_assigned = false;
+                }
             }
 
             // Drop shadows draw both a content and shadow rect, so need to expand the local
             // rect of any surfaces to be composited in parent surfaces correctly.
             if let PictureCompositeMode::Filter(FilterOp::DropShadow(offset, ..)) = raster_config.composite_mode {
                 let content_rect = surface_rect;
                 let shadow_rect = surface_rect.translate(&offset);
                 surface_rect = content_rect.union(&shadow_rect);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6523,46 +6523,22 @@ nsresult PresShell::EventHandler::Handle
   if (!aDontRetargetEvents) {
     RefPtr<Document> retargetEventDoc;
     if (!GetRetargetEventDocument(aGUIEvent,
                                   getter_AddRefs(retargetEventDoc))) {
       return NS_OK;  // Not need to return error.
     }
 
     if (retargetEventDoc) {
-      nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
-      // Even if the document doesn't have PresShell, i.e., it's invisible, we
-      // need to dispatch only KeyboardEvent in its nearest visible document
-      // because key focus shouldn't be caught by invisible document.
-      if (!presShell) {
-        if (!aGUIEvent->HasKeyEventMessage()) {
-          return NS_OK;
-        }
-        while (!presShell) {
-          retargetEventDoc = retargetEventDoc->GetParentDocument();
-          if (!retargetEventDoc) {
-            return NS_OK;
-          }
-          presShell = retargetEventDoc->GetShell();
-        }
-      }
-
-      if (presShell != mPresShell) {
-        nsIFrame* frame = presShell->GetRootFrame();
-        if (!frame) {
-          if (aGUIEvent->mMessage == eQueryTextContent ||
-              aGUIEvent->IsContentCommandEvent()) {
-            return NS_OK;
-          }
-
-          frame = GetNearestFrameContainingPresShell(presShell);
-        }
-
-        if (!frame) return NS_OK;
-
+      nsIFrame* frame =
+          GetFrameForHandlingEventWith(aGUIEvent, retargetEventDoc, aFrame);
+      if (!frame) {
+        return NS_OK;  // Not need to return error.
+      }
+      if (frame != aFrame) {
         nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
         return shell->HandleEvent(frame, aGUIEvent, true, aEventStatus);
       }
     }
   }
 
   if (aGUIEvent->mClass == eKeyboardEventClass && GetDocument() &&
       GetDocument()->EventHandlingSuppressed()) {
@@ -7191,16 +7167,56 @@ bool PresShell::EventHandler::GetRetarge
   }
 #endif  // #ifdef ANDROID
 
   // When we don't find another document to handle the event, we need to keep
   // handling the event by ourselves.
   return true;
 }
 
+nsIFrame* PresShell::EventHandler::GetFrameForHandlingEventWith(
+    WidgetGUIEvent* aGUIEvent, Document* aRetargetDocument,
+    nsIFrame* aFrameForPresShell) {
+  MOZ_ASSERT(aGUIEvent);
+  MOZ_ASSERT(aRetargetDocument);
+
+  nsCOMPtr<nsIPresShell> presShell = aRetargetDocument->GetShell();
+  // Even if the document doesn't have PresShell, i.e., it's invisible, we
+  // need to dispatch only KeyboardEvent in its nearest visible document
+  // because key focus shouldn't be caught by invisible document.
+  if (!presShell) {
+    if (!aGUIEvent->HasKeyEventMessage()) {
+      return nullptr;
+    }
+    Document* retargetEventDoc = aRetargetDocument;
+    while (!presShell) {
+      retargetEventDoc = retargetEventDoc->GetParentDocument();
+      if (!retargetEventDoc) {
+        return nullptr;
+      }
+      presShell = retargetEventDoc->GetShell();
+    }
+  }
+
+  if (presShell != mPresShell) {
+    nsIFrame* frame = presShell->GetRootFrame();
+    if (!frame) {
+      if (aGUIEvent->mMessage == eQueryTextContent ||
+          aGUIEvent->IsContentCommandEvent()) {
+        return nullptr;
+      }
+
+      frame = GetNearestFrameContainingPresShell(presShell);
+    }
+
+    return frame;
+  }
+  return aFrameForPresShell;
+}
+
 Document* PresShell::GetPrimaryContentDocument() {
   nsPresContext* context = GetPresContext();
   if (!context || !context->IsRoot()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell();
   if (!shellAsTreeItem) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -587,16 +587,40 @@ class PresShell final : public nsIPresSh
      * @param aGUIEvent                 Handling event.
      * @param aRetargetEventDocument    Document which should handle aGUIEvent.
      * @return                          true if caller can keep handling
      *                                  aGUIEvent.
      */
     bool GetRetargetEventDocument(WidgetGUIEvent* aGUIEvent,
                                   Document** aRetargetEventDocument);
 
+    /**
+     * GetFrameForHandlingEventWith() returns a frame which should be used as
+     * aFrame of HandleEvent().  See @return for the detail.
+     *
+     * @param aGUIEvent                 Handling event.
+     * @param aRetargetDocument         Document which aGUIEvent should be
+     *                                  fired on.  Typically, should be result
+     *                                  of GetRetargetEventDocument().
+     * @param aFrameForPresShell        The frame if we need to handle the
+     *                                  event with current instance.  I.e.,
+     *                                  typically, caller sets aFrame of
+     *                                  HandleEvent().
+     * @return                          nullptr if caller should stop handling
+     *                                  the event.
+     *                                  aFrameForPresShell if caller should
+     *                                  keep handling the event by itself.
+     *                                  Otherwise, caller should handle it with
+     *                                  another PresShell which is result of
+     *                                  nsIFrame::PresContext()->GetPresShell().
+     */
+    nsIFrame* GetFrameForHandlingEventWith(WidgetGUIEvent* aGUIEvent,
+                                           Document* aRetargetDocument,
+                                           nsIFrame* aFrameForPresShell);
+
     MOZ_CAN_RUN_SCRIPT
     nsresult RetargetEventToParent(WidgetGUIEvent* aGUIEvent,
                                    nsEventStatus* aEventStatus);
 
     /**
      * MaybeHandleEventWithAccessibleCaret() may handle aGUIEvent with
      * AccessibleCaretEventHub if it's necessary.
      *
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -122,33 +122,39 @@ struct MOZ_STACK_CLASS BidiParagraphData
   nsDataHashtable<nsPtrHashKey<const nsIContent>, int32_t> mContentToFrameIndex;
   // Cached presentation context for the frames we're processing.
   nsPresContext* mPresContext;
   bool mIsVisual;
   bool mRequiresBidi;
   nsBidiLevel mParaLevel;
   nsIContent* mPrevContent;
   nsIFrame* mPrevFrame;
+  // Cache the block frame which needs bidi resolution.
+  const nsIFrame* mBlock;
 #ifdef DEBUG
   // Only used for NOISY debug output.
   nsBlockFrame* mCurrentBlock;
 #endif
 
   explicit BidiParagraphData(nsBlockFrame* aBlockFrame)
       : mPresContext(aBlockFrame->PresContext()),
         mIsVisual(mPresContext->IsVisualMode()),
         mRequiresBidi(false),
         mParaLevel(nsBidiPresUtils::BidiLevelFromStyle(aBlockFrame->Style())),
         mPrevContent(nullptr),
-        mPrevFrame(nullptr)
+        mPrevFrame(nullptr),
+        mBlock(aBlockFrame)
 #ifdef DEBUG
         ,
         mCurrentBlock(aBlockFrame)
 #endif
   {
+    MOZ_ASSERT(mBlock->FirstContinuation() == mBlock,
+               "mBlock must be the first continuation!");
+
     if (mParaLevel > 0) {
       mRequiresBidi = true;
     }
 
     if (mIsVisual) {
       /**
        * Drill up in content to detect whether this is an element that needs to
        * be rendered with logical order even on visual pages.
@@ -1774,17 +1780,19 @@ void nsBidiPresUtils::RemoveBidiContinua
   bidiData.precedingControl = kBidiLevelNone;
   for (int32_t index = aFirstIndex + 1; index <= aLastIndex; index++) {
     nsIFrame* frame = aBpd->FrameAt(index);
     if (frame != NS_BIDI_CONTROL_FRAME) {
       // Make the frame and its continuation ancestors fluid,
       // so they can be reused or deleted by normal reflow code
       frame->SetProperty(nsIFrame::BidiDataProperty(), bidiData);
       frame->AddStateBits(NS_FRAME_IS_BIDI);
-      while (frame) {
+
+      // Go no further than the block which needs resolution.
+      while (frame && aBpd->mBlock != frame->FirstContinuation()) {
         nsIFrame* prev = frame->GetPrevContinuation();
         if (prev) {
           MakeContinuationFluid(prev, frame);
           frame = frame->GetParent();
         } else {
           break;
         }
       }
--- a/layout/generic/ColumnSetWrapperFrame.cpp
+++ b/layout/generic/ColumnSetWrapperFrame.cpp
@@ -28,16 +28,25 @@ NS_IMPL_FRAMEARENA_HELPERS(ColumnSetWrap
 
 NS_QUERYFRAME_HEAD(ColumnSetWrapperFrame)
   NS_QUERYFRAME_ENTRY(ColumnSetWrapperFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
 
 ColumnSetWrapperFrame::ColumnSetWrapperFrame(ComputedStyle* aStyle)
     : nsBlockFrame(aStyle, kClassID) {}
 
+void ColumnSetWrapperFrame::Init(nsIContent* aContent,
+                                 nsContainerFrame* aParent,
+                                 nsIFrame* aPrevInFlow) {
+  nsBlockFrame::Init(aContent, aParent, aPrevInFlow);
+
+  // ColumnSetWrapperFrame doesn't need to call ResolveBidi().
+  RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
+}
+
 nsContainerFrame* ColumnSetWrapperFrame::GetContentInsertionFrame() {
   nsIFrame* columnSet = PrincipalChildList().OnlyChild();
   if (columnSet) {
     // We have only one child, which means we don't have any column-span
     // descendants. Thus we can safely return our only ColumnSet child's
     // insertion frame as ours.
     MOZ_ASSERT(columnSet->IsColumnSetFrame());
     return columnSet->GetContentInsertionFrame();
@@ -122,16 +131,26 @@ void ColumnSetWrapperFrame::InsertFrames
 }
 
 void ColumnSetWrapperFrame::RemoveFrame(ChildListID aListID,
                                         nsIFrame* aOldFrame) {
   MOZ_ASSERT_UNREACHABLE("Unsupported operation!");
   nsBlockFrame::RemoveFrame(aListID, aOldFrame);
 }
 
+void ColumnSetWrapperFrame::MarkIntrinsicISizesDirty() {
+  nsBlockFrame::MarkIntrinsicISizesDirty();
+
+  // The parent's method adds NS_BLOCK_NEEDS_BIDI_RESOLUTION to all our
+  // continuations. Clear the bit because we don't want to call ResolveBidi().
+  for (nsIFrame* f = FirstContinuation(); f; f = f->GetNextContinuation()) {
+    f->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
+  }
+}
+
 #ifdef DEBUG
 
 /* static */ void ColumnSetWrapperFrame::AssertColumnSpanWrapperSubtreeIsSane(
     const nsIFrame* aFrame) {
   MOZ_ASSERT(aFrame->IsColumnSpan(), "aFrame is not column-span?");
 
   if (!nsLayoutUtils::GetStyleFrame(const_cast<nsIFrame*>(aFrame))
            ->Style()
--- a/layout/generic/ColumnSetWrapperFrame.h
+++ b/layout/generic/ColumnSetWrapperFrame.h
@@ -27,31 +27,36 @@ class ColumnSetWrapperFrame final : publ
  public:
   NS_DECL_FRAMEARENA_HELPERS(ColumnSetWrapperFrame)
   NS_DECL_QUERYFRAME
 
   friend nsBlockFrame* ::NS_NewColumnSetWrapperFrame(nsIPresShell* aPresShell,
                                                      ComputedStyle* aStyle,
                                                      nsFrameState aStateFlags);
 
+  void Init(nsIContent* aContent, nsContainerFrame* aParent,
+            nsIFrame* aPrevInFlow) override;
+
   nsContainerFrame* GetContentInsertionFrame() override;
 
   void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override;
 
   void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
                     nsFrameList& aFrameList) override;
 
   void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
 
+  void MarkIntrinsicISizesDirty() override;
+
  private:
   explicit ColumnSetWrapperFrame(ComputedStyle* aStyle);
   ~ColumnSetWrapperFrame() override = default;
 
 #ifdef DEBUG
   static void AssertColumnSpanWrapperSubtreeIsSane(const nsIFrame* aFrame);
 
   // True if frame constructor has finished building this frame and all of
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/column-span-bidi-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <style>
+  h3 {
+    column-span: all;
+  }
+  html {
+    columns: 3em;
+  }
+  </style>
+
+  <body onload=go()>
+    <h3></h3>
+    <!-- The following content will be in a -moz-column-content frame where it's
+         parent is a hard continuation of a nsColumnSetFrame. -->
+    ltr
+    ltr
+    <div dir="rtl">rtl</div>
+    <div></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/column-span-bidi-1.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <meta charset="utf-8">
+  <style>
+  h3 {
+    column-span: all;
+  }
+  html {
+    columns: 3em;
+  }
+  </style>
+  <script>
+  function go() {
+    document.body.offsetHeight;
+    document.body.appendChild(a);
+    document.documentElement.removeAttribute("class");
+  }
+  </script>
+  <body onload=go()>
+    <h3>
+      <div id="a"></div>
+    </h3>
+    <!-- The following content will be in a -moz-column-content frame where it's
+         parent is a hard continuation of a nsColumnSetFrame. -->
+    ltr
+    ltr
+    <div dir="rtl">rtl</div>
+  </body>
+</html>
--- a/layout/reftests/columns/reftest.list
+++ b/layout/reftests/columns/reftest.list
@@ -34,8 +34,9 @@ fuzzy-if(OSX,0-32,0-1000) == columnfill-
 == columnrule-overflow.html columnrule-overflow-ref.html
 == columns-table-caption-000.html columns-table-caption-000-ref.html
 == positioning-transforms-bug1112501.html positioning-transforms-bug1112501-ref.html
 fuzzy-if(browserIsRemote&&winWidget,0-142,0-276) == fieldset-columns-001.html fieldset-columns-001-ref.html
 == dynamic-change-with-overflow-1.html dynamic-change-with-overflow-1-ref.html
 == dynamic-text-indent-1.html dynamic-text-indent-1-ref.html
 == dynamic-text-indent-2.html dynamic-text-indent-2-ref.html
 == break-avoid-line-position-1.html break-avoid-line-position-1-ref.html
+pref(layout.css.column-span.enabled,true) == column-span-bidi-1.html column-span-bidi-1-ref.html
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-multicol/multicol-span-all-008.html.ini
@@ -0,0 +1,2 @@
+[multicol-span-all-008.html]
+  prefs: [layout.css.column-span.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test a bidi-override multi-column container with a dir=rtl column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  body {
+    column-count: 1;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+  }
+  h3 {
+    /* "column-count: 1" makes this behave like a real spanner. */
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <body>
+    <div>block1</div>
+    <h3 dir="rtl">spanner</h3>
+    <div>block2</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a bidi-override multi-column container with a dir=rtl column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-008-ref.html">
+  <meta name="assert" content="This test checks the page is rendered correctly for a bidi-override multi-column container with a dir=rtl column-span:all child.">
+
+  <style>
+  article {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+    unicode-bidi: bidi-override; /* Needed to trigger bidi resolution. */
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <article>
+    <div>block1</div>
+    <h3 dir="rtl">spanner</h3>
+    <div>block2</div>
+  </article>
+</html>
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -391,16 +391,17 @@ var snapshotFormatters = {
         delete data.indices;
       } else {
         $.append($("graphics-failures-tbody"),
           [$.new("tr", [$.new("th", "LogFailure", "column"),
                         $.new("td", data.failures.map(function(val) {
                           return $.new("p", val);
                        }))])]);
       }
+      delete data.failures;
     } else {
       $("graphics-failures-tbody").style.display = "none";
     }
 
     // Add a new row to the table, and take the key (or keys) out of data.
     //
     // @where        Table section to add to.
     // @key          Data key to use.