diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index c48d9f963019..d8afd51b974d 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -1681,6 +1681,14 @@ void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType( aAddChild(child); } +// Frames for these may not be leaves in the proper sense, but we still don't +// want to expose generated content on them. For the purposes of the page they +// should be leaves. +static bool HasUAWidget(const Element& aOriginatingElement) { + const ShadowRoot* sr = aOriginatingElement.GetShadowRoot(); + return sr && sr->IsUAWidget(); +} + /* * aParentFrame - the frame that should be the parent of the generated * content. This is the frame for the corresponding content node, @@ -1705,10 +1713,7 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem( aPseudoElement == PseudoStyleType::marker, "unexpected aPseudoElement"); - if (aParentFrame && (aParentFrame->IsHTMLVideoFrame() || - aParentFrame->IsDateTimeControlFrame())) { - // Video frames and date time control frames may not be leafs when backed by - // an UA widget, but we still don't want to expose generated content. + if (HasUAWidget(aOriginatingElement)) { return; } diff --git a/layout/generic/FrameClass.py b/layout/generic/FrameClass.py index 00a57abb7f27..0fae9e115efd 100644 --- a/layout/generic/FrameClass.py +++ b/layout/generic/FrameClass.py @@ -6,6 +6,7 @@ # Leaf constants to pass to Frame's leafness argument. LEAF = "Leaf" NOT_LEAF = "NotLeaf" +DYNAMIC_LEAF = "DynamicLeaf" class FrameClass: diff --git a/layout/generic/FrameClasses.py b/layout/generic/FrameClasses.py index e244974bfe9c..67f685a1460c 100644 --- a/layout/generic/FrameClasses.py +++ b/layout/generic/FrameClasses.py @@ -3,7 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # Frame class definitions, used to generate FrameIdList.h and FrameTypeList.h -from FrameClass import Frame, AbstractFrame, LEAF, NOT_LEAF +from FrameClass import Frame, AbstractFrame, LEAF, NOT_LEAF, DYNAMIC_LEAF FRAME_CLASSES = [ Frame("BRFrame", "Br", LEAF), @@ -41,7 +41,7 @@ FRAME_CLASSES = [ Frame("nsHTMLScrollFrame", "Scroll", NOT_LEAF), Frame("nsImageBoxFrame", "ImageBox", LEAF), Frame("nsImageControlFrame", "ImageControl", LEAF), - Frame("nsImageFrame", "Image", LEAF), + Frame("nsImageFrame", "Image", DYNAMIC_LEAF), Frame("nsInlineFrame", "Inline", NOT_LEAF), Frame("nsLeafBoxFrame", "LeafBox", LEAF), Frame("nsListControlFrame", "ListControl", NOT_LEAF), diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index a71d2ade036e..82a204e0bd20 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -171,11 +171,13 @@ const nsIFrame::FrameClassBits nsIFrame::sFrameClassBits[ 0] = { #define Leaf eFrameClassBitsLeaf #define NotLeaf eFrameClassBitsNone +#define DynamicLeaf eFrameClassBitsDynamicLeaf #define FRAME_ID(class_, type_, leaf_, ...) leaf_, #define ABSTRACT_FRAME_ID(...) #include "mozilla/FrameIdList.h" #undef Leaf #undef NotLeaf +#undef DynamicLeaf #undef FRAME_ID #undef ABSTRACT_FRAME_ID }; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index dcfba6cb8ee3..0110377976d3 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -3366,9 +3366,14 @@ class nsIFrame : public nsQueryFrame { bool IsLeaf() const { MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sFrameClassBits)); FrameClassBits bits = sFrameClassBits[uint8_t(mClass)]; + if (MOZ_UNLIKELY(bits & eFrameClassBitsDynamicLeaf)) { + return IsLeafDynamic(); + } return bits & eFrameClassBitsLeaf; } + virtual bool IsLeafDynamic() const { return false; } + /** * Marks all display items created by this frame as needing a repaint, * and calls SchedulePaint() if requested and one is not already pending. @@ -5413,6 +5418,7 @@ class nsIFrame : public nsQueryFrame { enum FrameClassBits { eFrameClassBitsNone = 0x0, eFrameClassBitsLeaf = 0x1, + eFrameClassBitsDynamicLeaf = 0x2, }; // Maps mClass to IsLeaf() flags. static const FrameClassBits sFrameClassBits[ diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 4a09b9991a19..da860cbc156d 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1209,6 +1209,31 @@ nscoord nsImageFrame::GetPrefISize(gfxContext* aRenderingContext) { return iSize.valueOr(0); } +void nsImageFrame::ReflowChildren(nsPresContext* aPresContext, + const ReflowInput& aReflowInput, + const LogicalSize& aImageSize) { + for (nsIFrame* child : mFrames) { + ReflowOutput childDesiredSize(aReflowInput); + WritingMode wm = GetWritingMode(); + // Shouldn't be hard to support if we want, but why bother. + MOZ_ASSERT( + wm == child->GetWritingMode(), + "We don't expect mismatched writing-modes in content we control"); + nsReflowStatus childStatus; + + LogicalPoint childOffset(wm); + ReflowInput childReflowInput(aPresContext, aReflowInput, child, aImageSize); + const nsSize containerSize = aImageSize.GetPhysicalSize(wm); + ReflowChild(child, aPresContext, childDesiredSize, childReflowInput, wm, + childOffset, containerSize, ReflowChildFlags::Default, + childStatus); + + FinishReflowChild(child, aPresContext, childDesiredSize, &childReflowInput, + wm, childOffset, containerSize, + ReflowChildFlags::Default); + } +} + void nsImageFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { @@ -1296,6 +1321,9 @@ void nsImageFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, } FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay); + // Reflow the child frames. Our children can't affect our size in any way. + ReflowChildren(aPresContext, aReflowInput, aMetrics.Size(GetWritingMode())); + if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && !mReflowCallbackPosted) { mReflowCallbackPosted = true; PresShell()->PostReflowCallback(this); @@ -2326,6 +2354,8 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, DisplaySelectionOverlay(aBuilder, aLists.Content(), nsISelectionDisplay::DISPLAY_IMAGES); } + + BuildDisplayListForNonBlockChildren(aBuilder, aLists); } bool nsImageFrame::ShouldDisplaySelection() { @@ -2400,6 +2430,19 @@ bool nsImageFrame::GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget, return status; } +bool nsImageFrame::IsLeafDynamic() const { + if (mKind != Kind::ImageElement) { + // Image frames created for "content: url()" could have an author-controlled + // shadow root, we want to be a regular leaf for those. + return true; + } + // For elements that create image frames, calling attachShadow() will throw, + // so the only ShadowRoot we could ever have is a UA widget. + const auto* shadow = mContent->AsElement()->GetShadowRoot(); + MOZ_ASSERT_IF(shadow, shadow->IsUAWidget()); + return !shadow; +} + nsresult nsImageFrame::GetContentForEvent(WidgetEvent* aEvent, nsIContent** aContent) { NS_ENSURE_ARG_POINTER(aContent); diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index e90c5c480055..2012cbfb5f1a 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -84,6 +84,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback { } void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&, nsReflowStatus&) override; + bool IsLeafDynamic() const override; nsresult GetContentForEvent(mozilla::WidgetEvent*, nsIContent** aContent) final; @@ -212,6 +213,9 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback { nsImageFrame(ComputedStyle*, nsPresContext* aPresContext, ClassID, Kind); + void ReflowChildren(nsPresContext*, const ReflowInput&, + const mozilla::LogicalSize& aImageSize); + protected: nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, ClassID aID) : nsImageFrame(aStyle, aPresContext, aID, Kind::ImageElement) {}