From 5f4c3c9c154ff0f092a0285f9cd7fec3c7d30ea0 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sun, 8 Apr 2018 09:12:03 -0700 Subject: [PATCH] #493: image max-width M823483 M1247929 --- dom/base/nsGkAtomList.h | 2 + layout/base/nsLayoutUtils.cpp | 63 ++++++++++++++++++++++++----- layout/forms/nsMeterFrame.cpp | 6 +++ layout/forms/nsMeterFrame.h | 2 + layout/forms/nsProgressFrame.cpp | 6 +++ layout/forms/nsProgressFrame.h | 2 + layout/generic/nsHTMLCanvasFrame.h | 3 +- layout/generic/nsIFrame.h | 5 +++ layout/generic/nsImageFrame.h | 3 +- layout/generic/nsPluginFrame.h | 3 +- layout/generic/nsSubDocumentFrame.h | 4 +- layout/generic/nsVideoFrame.h | 3 +- 12 files changed, 86 insertions(+), 16 deletions(-) diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index c63a97f64..106d42527 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -1971,6 +1971,7 @@ GK_ATOM(letterFrame, "LetterFrame") GK_ATOM(lineFrame, "LineFrame") GK_ATOM(listControlFrame,"ListControlFrame") GK_ATOM(menuFrame,"MenuFrame") +GK_ATOM(meterFrame, "MeterFrame") GK_ATOM(menuPopupFrame,"MenuPopupFrame") GK_ATOM(numberControlFrame, "NumberControlFrame") GK_ATOM(objectFrame, "ObjectFrame") @@ -1979,6 +1980,7 @@ GK_ATOM(pageBreakFrame, "PageBreakFrame") GK_ATOM(pageContentFrame, "PageContentFrame") GK_ATOM(placeholderFrame, "PlaceholderFrame") GK_ATOM(popupSetFrame, "PopupSetFrame") +GK_ATOM(progressFrame, "ProgressFrame") GK_ATOM(canvasFrame, "CanvasFrame") GK_ATOM(rangeFrame, "RangeFrame") GK_ATOM(rootFrame, "RootFrame") diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index b4673a099..6f3a3b6f4 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4489,6 +4489,43 @@ GetIntrinsicCoord(const nsStyleCoord& aStyle, static int32_t gNoiseIndent = 0; #endif +// Return true for form controls whose minimum intrinsic inline-size +// shrinks to 0 when they have a percentage inline-size (but not +// percentage max-inline-size). (Proper replaced elements, whose +// intrinsic minimium inline-size shrinks to 0 for both percentage +// inline-size and percentage max-inline-size, are handled elsewhere.) +inline static bool +FormControlShrinksForPercentISize(nsIFrame* aFrame) +{ + if (!aFrame->IsFrameOfType(nsIFrame::eReplaced)) { + // Quick test to reject most frames. + return false; + } + + nsIAtom* fType = aFrame->GetType(); + if (fType == nsGkAtoms::meterFrame || fType == nsGkAtoms::progressFrame) { + // progress and meter do have this shrinking behavior + // FIXME: Maybe these should be nsIFormControlFrame? + return true; + } + + if (!static_cast(do_QueryFrame(aFrame))) { + // Not a form control. This includes fieldsets, which do not + // shrink. + return false; + } + + if (fType == nsGkAtoms::gfxButtonControlFrame || + fType == nsGkAtoms::HTMLButtonControlFrame) { + // Buttons don't have this shrinking behavior. (Note that color + // inputs do, even though they inherit from button, so we can't use + // do_QueryFrame here.) + return false; + } + + return true; +} + /** * Add aOffsets which describes what to add on outside of the content box * aContentSize (controlled by 'box-sizing') and apply min/max properties. @@ -4565,19 +4602,23 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, pctTotal += pctOutsideSize; nscoord size; - if (GetAbsoluteCoord(aStyleSize, size) || - GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame, - PROP_WIDTH, size)) { + if (aType == nsLayoutUtils::MIN_ISIZE && + (((aStyleSize.HasPercent() || aStyleMaxSize.HasPercent()) && + aFrame->IsFrameOfType(nsIFrame::eReplacedSizing)) || + (aStyleSize.HasPercent() && + FormControlShrinksForPercentISize(aFrame)))) { + // A percentage width or max-width on replaced elements means they + // can shrink to 0. + // This is also true for percentage widths (but not max-widths) on + // text inputs. + // Note that if this is max-width, this overrides the fixed-width + // rule in the next condition. + result = 0; // let |min| handle padding/border/margin + } else if (GetAbsoluteCoord(aStyleSize, size) || + GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame, + PROP_WIDTH, size)) { result = nsLayoutUtils::AddPercents(aType, size + coordOutsideSize, pctOutsideSize); - } else if (aType == nsLayoutUtils::MIN_ISIZE && - // The only cases of coord-percent-calc() units that - // GetAbsoluteCoord didn't handle are percent and calc()s - // containing percent. - aStyleSize.IsCoordPercentCalcUnit() && - aFrame->IsFrameOfType(nsIFrame::eReplaced)) { - // A percentage width on replaced elements means they can shrink to 0. - result = 0; // let |min| handle padding/border/margin } else { // NOTE: We could really do a lot better for percents and for some // cases of calc() containing percent (certainly including any where diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp index d2797278b..465f3ee4e 100644 --- a/layout/forms/nsMeterFrame.cpp +++ b/layout/forms/nsMeterFrame.cpp @@ -56,6 +56,12 @@ nsMeterFrame::DestroyFrom(nsIFrame* aDestructRoot) nsContainerFrame::DestroyFrom(aDestructRoot); } +nsIAtom* +nsMeterFrame::GetType() const +{ + return nsGkAtoms::meterFrame; +} + nsresult nsMeterFrame::CreateAnonymousContent(nsTArray& aElements) { diff --git a/layout/forms/nsMeterFrame.h b/layout/forms/nsMeterFrame.h index d7cc32470..985b3fd83 100644 --- a/layout/forms/nsMeterFrame.h +++ b/layout/forms/nsMeterFrame.h @@ -32,6 +32,8 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) override; + virtual nsIAtom* GetType() const override; + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("Meter"), aResult); diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp index d093bc26a..941efa90c 100644 --- a/layout/forms/nsProgressFrame.cpp +++ b/layout/forms/nsProgressFrame.cpp @@ -55,6 +55,12 @@ nsProgressFrame::DestroyFrom(nsIFrame* aDestructRoot) nsContainerFrame::DestroyFrom(aDestructRoot); } +nsIAtom* +nsProgressFrame::GetType() const +{ + return nsGkAtoms::progressFrame; +} + nsresult nsProgressFrame::CreateAnonymousContent(nsTArray& aElements) { diff --git a/layout/forms/nsProgressFrame.h b/layout/forms/nsProgressFrame.h index 980e8ba9e..349d76ae3 100644 --- a/layout/forms/nsProgressFrame.h +++ b/layout/forms/nsProgressFrame.h @@ -35,6 +35,8 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) override; + virtual nsIAtom* GetType() const override; + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("Progress"), aResult); diff --git a/layout/generic/nsHTMLCanvasFrame.h b/layout/generic/nsHTMLCanvasFrame.h index e3bbf731c..a783aa36d 100644 --- a/layout/generic/nsHTMLCanvasFrame.h +++ b/layout/generic/nsHTMLCanvasFrame.h @@ -86,7 +86,8 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsSplittableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); + return nsSplittableFrame::IsFrameOfType(aFlags & + ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } #ifdef DEBUG_FRAME_DUMP diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 9ec946e3c..d8c1e8c3b 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -2123,6 +2123,11 @@ public: eExcludesIgnorableWhitespace = 1 << 14, eSupportsCSSTransforms = 1 << 15, + // A replaced element that has replaced-element sizing + // characteristics (i.e., like images or iframes), as opposed to + // inline-block sizing characteristics (like form controls). + eReplacedSizing = 1 << 16, + // These are to allow nsFrame::Init to assert that IsFrameOfType // implementations all call the base class method. They are only // meaningful in DEBUG builds. diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index d0cef751b..4fc61d713 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -112,7 +112,8 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return ImageFrameSuper::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); + return ImageFrameSuper::IsFrameOfType(aFlags & + ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } #ifdef DEBUG_FRAME_DUMP diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index b04bcd977..1758b8404 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -91,7 +91,8 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsPluginFrameSuper::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); + return nsPluginFrameSuper::IsFrameOfType(aFlags & + ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } virtual bool NeedsView() override { return true; } diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index 0a0aaf677..2251ba4df 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -37,7 +37,9 @@ public: { // nsLeafFrame is already eReplacedContainsBlock, but that's somewhat bogus return nsLeafFrame::IsFrameOfType(aFlags & - ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); + ~(nsIFrame::eReplaced | + nsIFrame::eReplacedSizing | + nsIFrame::eReplacedContainsBlock)); } virtual void Init(nsIContent* aContent, diff --git a/layout/generic/nsVideoFrame.h b/layout/generic/nsVideoFrame.h index 9c5a9973c..f01f07ccd 100644 --- a/layout/generic/nsVideoFrame.h +++ b/layout/generic/nsVideoFrame.h @@ -77,7 +77,8 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsSplittableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); + return nsSplittableFrame::IsFrameOfType(aFlags & + ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } virtual nsresult CreateAnonymousContent(nsTArray& aElements) override;