diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index 9a5d142ec428..7aafd404a6ad 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -1693,10 +1693,7 @@ impl<'a> PictureUpdateState<'a> { 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 @@ -2646,7 +2643,7 @@ impl PicturePrimitive { // 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. @@ -2681,10 +2678,13 @@ impl PicturePrimitive { } // 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 diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 4e8f64eb6c39..57a203462f28 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -6528,36 +6528,12 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrame, } if (retargetEventDoc) { - nsCOMPtr 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(); - } + nsIFrame* frame = + GetFrameForHandlingEventWith(aGUIEvent, retargetEventDoc, aFrame); + if (!frame) { + return NS_OK; // Not need to return error. } - - 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; - + if (frame != aFrame) { nsCOMPtr shell = frame->PresContext()->GetPresShell(); return shell->HandleEvent(frame, aGUIEvent, true, aEventStatus); } @@ -7196,6 +7172,46 @@ bool PresShell::EventHandler::GetRetargetEventDocument( return true; } +nsIFrame* PresShell::EventHandler::GetFrameForHandlingEventWith( + WidgetGUIEvent* aGUIEvent, Document* aRetargetDocument, + nsIFrame* aFrameForPresShell) { + MOZ_ASSERT(aGUIEvent); + MOZ_ASSERT(aRetargetDocument); + + nsCOMPtr 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()) { diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 6e783cd811c1..45915c0042a1 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -592,6 +592,30 @@ class PresShell final : public nsIPresShell, 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); diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 65b20eacf69d..d923538561af 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -127,6 +127,8 @@ struct MOZ_STACK_CLASS BidiParagraphData { 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; @@ -138,12 +140,16 @@ struct MOZ_STACK_CLASS BidiParagraphData { 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; } @@ -1779,7 +1785,9 @@ void nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData* aBpd, // 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); diff --git a/layout/generic/ColumnSetWrapperFrame.cpp b/layout/generic/ColumnSetWrapperFrame.cpp index ad22c460732b..5b10d8542b0f 100644 --- a/layout/generic/ColumnSetWrapperFrame.cpp +++ b/layout/generic/ColumnSetWrapperFrame.cpp @@ -33,6 +33,15 @@ 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) { @@ -127,6 +136,16 @@ void ColumnSetWrapperFrame::RemoveFrame(ChildListID aListID, 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( diff --git a/layout/generic/ColumnSetWrapperFrame.h b/layout/generic/ColumnSetWrapperFrame.h index 79896dbd0d72..afd32c6976b8 100644 --- a/layout/generic/ColumnSetWrapperFrame.h +++ b/layout/generic/ColumnSetWrapperFrame.h @@ -32,6 +32,9 @@ class ColumnSetWrapperFrame final : public nsBlockFrame { ComputedStyle* aStyle, nsFrameState aStateFlags); + void Init(nsIContent* aContent, nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) override; + nsContainerFrame* GetContentInsertionFrame() override; void AppendDirectlyOwnedAnonBoxes(nsTArray& aResult) override; @@ -47,6 +50,8 @@ class ColumnSetWrapperFrame final : public nsBlockFrame { void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override; + void MarkIntrinsicISizesDirty() override; + private: explicit ColumnSetWrapperFrame(ComputedStyle* aStyle); ~ColumnSetWrapperFrame() override = default; diff --git a/layout/reftests/columns/column-span-bidi-1-ref.html b/layout/reftests/columns/column-span-bidi-1-ref.html new file mode 100644 index 000000000000..9bc890541f04 --- /dev/null +++ b/layout/reftests/columns/column-span-bidi-1-ref.html @@ -0,0 +1,22 @@ + + + + + + +

+ + ltr + ltr +
rtl
+
+ + diff --git a/layout/reftests/columns/column-span-bidi-1.html b/layout/reftests/columns/column-span-bidi-1.html new file mode 100644 index 000000000000..8e45f82fcf73 --- /dev/null +++ b/layout/reftests/columns/column-span-bidi-1.html @@ -0,0 +1,29 @@ + + + + + + +

+
+

+ + ltr + ltr +
rtl
+ + diff --git a/layout/reftests/columns/reftest.list b/layout/reftests/columns/reftest.list index f87e5bdd2215..4746eecf8cac 100644 --- a/layout/reftests/columns/reftest.list +++ b/layout/reftests/columns/reftest.list @@ -39,3 +39,4 @@ fuzzy-if(browserIsRemote&&winWidget,0-142,0-276) == fieldset-columns-001.html fi == 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 diff --git a/testing/web-platform/meta/css/css-multicol/multicol-span-all-008.html.ini b/testing/web-platform/meta/css/css-multicol/multicol-span-all-008.html.ini new file mode 100644 index 000000000000..e93713386dfe --- /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] diff --git a/testing/web-platform/tests/css/css-multicol/multicol-span-all-008-ref.html b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008-ref.html new file mode 100644 index 000000000000..ddc0b40bdd3b --- /dev/null +++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008-ref.html @@ -0,0 +1,26 @@ + + + + CSS Multi-column Layout Test Reference: Test a bidi-override multi-column container with a dir=rtl column-span:all child + + + + + + +
block1
+

spanner

+
block2
+ + diff --git a/testing/web-platform/tests/css/css-multicol/multicol-span-all-008.html b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008.html new file mode 100644 index 000000000000..82a24832b7c7 --- /dev/null +++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-008.html @@ -0,0 +1,30 @@ + + + + CSS Multi-column Layout Test: Test a bidi-override multi-column container with a dir=rtl column-span:all child + + + + + + + + +
+
block1
+

spanner

+
block2
+
+ diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js index 118833c5dbdf..88414b596f53 100644 --- a/toolkit/content/aboutSupport.js +++ b/toolkit/content/aboutSupport.js @@ -396,6 +396,7 @@ var snapshotFormatters = { return $.new("p", val); }))])]); } + delete data.failures; } else { $("graphics-failures-tbody").style.display = "none"; }