diff options
Diffstat (limited to 'layout')
32 files changed, 507 insertions, 349 deletions
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 9a827546f..d5df17020 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -3546,10 +3546,10 @@ ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize, imageSize.width = ComputeRoundedSize(imageSize.width, aBgPositioningArea.width); if (!isRepeatRoundInBothDimensions && aLayerSize.mHeightType == nsStyleImageLayers::Size::DimensionType::eAuto) { - // Restore intrinsic rato - if (aIntrinsicSize.mRatio.width) { - float scale = float(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width; - imageSize.height = NSCoordSaturatingNonnegativeMultiply(imageSize.width, scale); + // Restore intrinsic ratio + if (aIntrinsicSize.mRatio) { + imageSize.height = + aIntrinsicSize.mRatio.Inverted().ApplyTo(imageSize.width); } } } @@ -3560,10 +3560,9 @@ ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize, imageSize.height = ComputeRoundedSize(imageSize.height, aBgPositioningArea.height); if (!isRepeatRoundInBothDimensions && aLayerSize.mWidthType == nsStyleImageLayers::Size::DimensionType::eAuto) { - // Restore intrinsic rato - if (aIntrinsicSize.mRatio.height) { - float scale = float(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height; - imageSize.width = NSCoordSaturatingNonnegativeMultiply(imageSize.height, scale); + // Restore intrinsic ratio + if (aIntrinsicSize.mRatio) { + imageSize.width = aIntrinsicSize.mRatio.ApplyTo(imageSize.height); } } } @@ -5264,17 +5263,11 @@ CSSSizeOrRatio::ComputeConcreteSize() const return nsSize(mWidth, mHeight); } if (mHasWidth) { - nscoord height = NSCoordSaturatingNonnegativeMultiply( - mWidth, - double(mRatio.height) / mRatio.width); - return nsSize(mWidth, height); + return nsSize(mWidth, mRatio.Inverted().ApplyTo(mWidth)); } MOZ_ASSERT(mHasHeight); - nscoord width = NSCoordSaturatingNonnegativeMultiply( - mHeight, - double(mRatio.width) / mRatio.height); - return nsSize(width, mHeight); + return nsSize(mRatio.ApplyTo(mHeight), mHeight); } CSSSizeOrRatio @@ -5297,6 +5290,16 @@ nsImageRenderer::ComputeIntrinsicSize() if (haveHeight) { result.SetHeight(nsPresContext::CSSPixelsToAppUnits(imageIntSize.height)); } + + if (!haveHeight && haveWidth && result.mRatio) { + nscoord intrinsicHeight = + result.mRatio.Inverted().ApplyTo(imageIntSize.width); + result.SetHeight(nsPresContext::CSSPixelsToAppUnits(intrinsicHeight)); + } else if (haveHeight && !haveWidth && result.mRatio) { + nscoord intrinsicWidth = result.mRatio.ApplyTo(imageIntSize.height); + result.SetWidth(nsPresContext::CSSPixelsToAppUnits(intrinsicWidth)); + } + break; } case eStyleImageType_Element: @@ -5379,9 +5382,7 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize, if (aSpecifiedSize.mHasWidth) { nscoord height; if (aIntrinsicSize.HasRatio()) { - height = NSCoordSaturatingNonnegativeMultiply( - aSpecifiedSize.mWidth, - double(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width); + height = aIntrinsicSize.mRatio.Inverted().ApplyTo(aSpecifiedSize.mWidth); } else if (aIntrinsicSize.mHasHeight) { height = aIntrinsicSize.mHeight; } else { @@ -5393,9 +5394,7 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize, MOZ_ASSERT(aSpecifiedSize.mHasHeight); nscoord width; if (aIntrinsicSize.HasRatio()) { - width = NSCoordSaturatingNonnegativeMultiply( - aSpecifiedSize.mHeight, - double(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height); + width = aIntrinsicSize.mRatio.ApplyTo(aSpecifiedSize.mHeight); } else if (aIntrinsicSize.mHasWidth) { width = aIntrinsicSize.mWidth; } else { @@ -5406,32 +5405,57 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize, /* static */ nsSize nsImageRenderer::ComputeConstrainedSize(const nsSize& aConstrainingSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, FitType aFitType) { - if (aIntrinsicRatio.width <= 0 && aIntrinsicRatio.height <= 0) { + if (!aIntrinsicRatio) { return aConstrainingSize; } - float scaleX = double(aConstrainingSize.width) / aIntrinsicRatio.width; - float scaleY = double(aConstrainingSize.height) / aIntrinsicRatio.height; + // Suppose we're doing a "contain" fit. If the image's aspect ratio has a + // "fatter" shape than the constraint area, then we need to use the + // constraint area's full width, and we need to use the aspect ratio to + // produce a height. ON the other hand, if the aspect ratio is "skinnier", we + // use the constraint area's full height, and we use the aspect ratio to + // produce a width. (If instead we're doing a "cover" fit, then it can easily + // be seen that we should do precisely the opposite.) + // + // This is equivalent to the more descriptive alternative: + // + // AspectRatio::FromSize(aConstrainingSize) < aIntrinsicRatio + // + // But gracefully handling the case where one of the two dimensions from + // aConstrainingSize is zero. This is easy to prove since: + // + // aConstrainingSize.width / aConstrainingSize.height < aIntrinsicRatio + // + // Is trivially equivalent to: + // + // aIntrinsicRatio.width < aIntrinsicRatio * aConstrainingSize.height + // + // For the cases where height is not zero. + // + // We use float math here to avoid losing precision for very lareg backgrounds + // since we use saturating nscoord math otherwise. + const float constraintWidth = float(aConstrainingSize.width); + const float hypotheticalWidth = + aIntrinsicRatio.ApplyToFloat(aConstrainingSize.height); + nsSize size; - if ((aFitType == CONTAIN) == (scaleX < scaleY)) { + if ((aFitType == CONTAIN) == (constraintWidth < hypotheticalWidth)) { size.width = aConstrainingSize.width; - size.height = NSCoordSaturatingNonnegativeMultiply( - aIntrinsicRatio.height, scaleX); + size.height = aIntrinsicRatio.Inverted().ApplyTo(aConstrainingSize.width); // If we're reducing the size by less than one css pixel, then just use the // constraining size. if (aFitType == CONTAIN && aConstrainingSize.height - size.height < nsPresContext::AppUnitsPerCSSPixel()) { size.height = aConstrainingSize.height; } } else { - size.width = NSCoordSaturatingNonnegativeMultiply( - aIntrinsicRatio.width, scaleY); + size.height = aConstrainingSize.height; + size.width = aIntrinsicRatio.ApplyTo(aConstrainingSize.height); if (aFitType == CONTAIN && aConstrainingSize.width - size.width < nsPresContext::AppUnitsPerCSSPixel()) { size.width = aConstrainingSize.width; } - size.height = aConstrainingSize.height; } return size; } diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index 791e9656e..8ebeb7537 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -17,6 +17,7 @@ #include "nsLayoutUtils.h" #include "nsStyleStruct.h" #include "nsIFrame.h" +#include "mozilla/AspectRatio.h" class gfxDrawable; class nsStyleContext; @@ -41,8 +42,7 @@ class ImageContainer; struct CSSSizeOrRatio { CSSSizeOrRatio() - : mRatio(0, 0) - , mHasWidth(false) + : mHasWidth(false) , mHasHeight(false) {} bool CanComputeConcreteSize() const @@ -50,12 +50,12 @@ struct CSSSizeOrRatio return mHasWidth + mHasHeight + HasRatio() >= 2; } bool IsConcrete() const { return mHasWidth && mHasHeight; } - bool HasRatio() const { return mRatio.width > 0 && mRatio.height > 0; } + bool HasRatio() const { return !!mRatio; } bool IsEmpty() const { return (mHasWidth && mWidth <= 0) || (mHasHeight && mHeight <= 0) || - mRatio.width <= 0 || mRatio.height <= 0; + !mRatio; } // CanComputeConcreteSize must return true when ComputeConcreteSize is @@ -67,7 +67,7 @@ struct CSSSizeOrRatio mWidth = aWidth; mHasWidth = true; if (mHasHeight) { - mRatio = nsSize(mWidth, mHeight); + mRatio = AspectRatio::FromSize(mWidth, mHeight); } } void SetHeight(nscoord aHeight) @@ -75,7 +75,7 @@ struct CSSSizeOrRatio mHeight = aHeight; mHasHeight = true; if (mHasWidth) { - mRatio = nsSize(mWidth, mHeight); + mRatio = AspectRatio::FromSize(mWidth, mHeight); } } void SetSize(const nsSize& aSize) @@ -84,16 +84,16 @@ struct CSSSizeOrRatio mHeight = aSize.height; mHasWidth = true; mHasHeight = true; - mRatio = aSize; + mRatio = AspectRatio::FromSize(mWidth, mHeight); } - void SetRatio(const nsSize& aRatio) + void SetRatio(const AspectRatio& aRatio) { MOZ_ASSERT(!mHasWidth || !mHasHeight, "Probably shouldn't be setting a ratio if we have a concrete size"); mRatio = aRatio; } - nsSize mRatio; + AspectRatio mRatio; nscoord mWidth; nscoord mHeight; bool mHasWidth; @@ -184,11 +184,9 @@ public: /** * Compute the size of the rendered image using either the 'cover' or * 'contain' constraints (aFitType). - * aIntrinsicRatio may be an invalid ratio, that is one or both of its - * dimensions can be less than or equal to zero. */ static nsSize ComputeConstrainedSize(const nsSize& aConstrainingSize, - const nsSize& aIntrinsicRatio, + const mozilla::AspectRatio& aIntrinsicRatio, FitType aFitType); /** * Compute the size of the rendered image (the concrete size) where no cover/ diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index fb0b42a6c..5de6f2013 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4045,7 +4045,7 @@ nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect, enum ObjectDimensionType { eWidth, eHeight }; static nscoord ComputeMissingDimension(const nsSize& aDefaultObjectSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, const Maybe<nscoord>& aSpecifiedWidth, const Maybe<nscoord>& aSpecifiedHeight, ObjectDimensionType aDimensionToCompute) @@ -4056,21 +4056,15 @@ ComputeMissingDimension(const nsSize& aDefaultObjectSize, // 1. "If the object has an intrinsic aspect ratio, the missing dimension of // the concrete object size is calculated using the intrinsic aspect // ratio and the present dimension." - if (aIntrinsicRatio.width > 0 && aIntrinsicRatio.height > 0) { + if (aIntrinsicRatio) { // Fill in the missing dimension using the intrinsic aspect ratio. - nscoord knownDimensionSize; - float ratio; if (aDimensionToCompute == eWidth) { - knownDimensionSize = *aSpecifiedHeight; - ratio = aIntrinsicRatio.width / aIntrinsicRatio.height; - } else { - knownDimensionSize = *aSpecifiedWidth; - ratio = aIntrinsicRatio.height / aIntrinsicRatio.width; + return aIntrinsicRatio.ApplyTo(*aSpecifiedHeight); } - return NSCoordSaturatingNonnegativeMultiply(knownDimensionSize, ratio); + return aIntrinsicRatio.Inverted().ApplyTo(*aSpecifiedWidth); } - // 2. "Otherwise, if the missing dimension is present in the object’s + // 2. "Otherwise, if the missing dimension is present in the object's // intrinsic dimensions, [...]" // NOTE: *Skipping* this case, because we already know it's not true -- we're // in this function because the missing dimension is *not* present in @@ -4108,7 +4102,7 @@ ComputeMissingDimension(const nsSize& aDefaultObjectSize, static Maybe<nsSize> MaybeComputeObjectFitNoneSize(const nsSize& aDefaultObjectSize, const IntrinsicSize& aIntrinsicSize, - const nsSize& aIntrinsicRatio) + const AspectRatio& aIntrinsicRatio) { // "If the object has an intrinsic height or width, its size is resolved as // if its intrinsic dimensions were given as the specified size." @@ -4155,15 +4149,13 @@ MaybeComputeObjectFitNoneSize(const nsSize& aDefaultObjectSize, static nsSize ComputeConcreteObjectSize(const nsSize& aConstraintSize, const IntrinsicSize& aIntrinsicSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, uint8_t aObjectFit) { // Handle default behavior (filling the container) w/ fast early return. // (Also: if there's no valid intrinsic ratio, then we have the "fill" // behavior & just use the constraint size.) - if (MOZ_LIKELY(aObjectFit == NS_STYLE_OBJECT_FIT_FILL) || - aIntrinsicRatio.width == 0 || - aIntrinsicRatio.height == 0) { + if (MOZ_LIKELY(aObjectFit == NS_STYLE_OBJECT_FIT_FILL) || !aIntrinsicRatio) { return aConstraintSize; } @@ -4250,7 +4242,7 @@ HasInitialObjectFitAndPosition(const nsStylePosition* aStylePos) /* static */ nsRect nsLayoutUtils::ComputeObjectDestRect(const nsRect& aConstraintRect, const IntrinsicSize& aIntrinsicSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, const nsStylePosition* aStylePos, nsPoint* aAnchorPoint) { @@ -5172,10 +5164,12 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, styleMinBSize.GetCoordValue() == 0)) || styleMaxBSize.GetUnit() != eStyleUnit_None) { - nsSize ratio(aFrame->GetIntrinsicRatio()); - nscoord ratioISize = (horizontalAxis ? ratio.width : ratio.height); - nscoord ratioBSize = (horizontalAxis ? ratio.height : ratio.width); - if (ratioBSize != 0) { + AspectRatio ratio = aFrame->GetIntrinsicRatio(); + if (ratio) { + // Convert 'ratio' if necessary, so that it's storing ISize/BSize: + if (!horizontalAxis) { + ratio = ratio.Inverted(); + } AddStateBitToAncestors(aFrame, NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE); @@ -5191,14 +5185,14 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, (aPercentageBasis.isNothing() && GetPercentBSize(styleBSize, aFrame, horizontalAxis, h))) { h = std::max(0, h - bSizeTakenByBoxSizing); - result = NSCoordMulDiv(h, ratioISize, ratioBSize); + result = ratio.ApplyTo(h); } if (GetDefiniteSize(styleMaxBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) || (aPercentageBasis.isNothing() && GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) { h = std::max(0, h - bSizeTakenByBoxSizing); - nscoord maxISize = NSCoordMulDiv(h, ratioISize, ratioBSize); + nscoord maxISize = ratio.ApplyTo(h); if (maxISize < result) { result = maxISize; } @@ -5211,7 +5205,7 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, (aPercentageBasis.isNothing() && GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) { h = std::max(0, h - bSizeTakenByBoxSizing); - nscoord minISize = NSCoordMulDiv(h, ratioISize, ratioBSize); + nscoord minISize = ratio.ApplyTo(h); if (minISize > result) { result = minISize; } @@ -6674,12 +6668,12 @@ nsLayoutUtils::DrawSingleImage(gfxContext& aContext, /* static */ void nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage, CSSIntSize& aImageSize, /*outparam*/ - nsSize& aIntrinsicRatio, /*outparam*/ + AspectRatio& aIntrinsicRatio, /*outparam*/ bool& aGotWidth, /*outparam*/ bool& aGotHeight /*outparam*/) { aGotWidth = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width)); - aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height)); + aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height)); bool gotRatio = NS_SUCCEEDED(aImage->GetIntrinsicRatio(&aIntrinsicRatio)); if (!(aGotWidth && aGotHeight) && !gotRatio) { @@ -6687,7 +6681,7 @@ nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage, // decoded) and should return zero size. aGotWidth = aGotHeight = true; aImageSize = CSSIntSize(0, 0); - aIntrinsicRatio = nsSize(0, 0); + aIntrinsicRatio = AspectRatio(); } } @@ -6696,7 +6690,7 @@ nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage, const nsSize& aFallbackSize) { CSSIntSize imageSize; - nsSize imageRatio; + AspectRatio imageRatio; bool gotHeight, gotWidth; ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight); @@ -6704,19 +6698,13 @@ nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage, // intrinsic ratio of the image. if (gotWidth != gotHeight) { if (!gotWidth) { - if (imageRatio.height != 0) { - imageSize.width = - NSCoordSaturatingNonnegativeMultiply(imageSize.height, - float(imageRatio.width) / - float(imageRatio.height)); + if (imageRatio) { + imageSize.width = imageRatio.ApplyTo(imageSize.height); gotWidth = true; } } else { - if (imageRatio.width != 0) { - imageSize.height = - NSCoordSaturatingNonnegativeMultiply(imageSize.width, - float(imageRatio.height) / - float(imageRatio.width)); + if (imageRatio) { + imageSize.height = imageRatio.Inverted().ApplyTo(imageSize.width); gotHeight = true; } } diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index bba1f3265..f4471ce74 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -65,6 +65,7 @@ struct nsStyleImageOrientation; struct nsOverflowAreas; namespace mozilla { +struct aspectRatio; enum class CSSPseudoElementType : uint8_t; class EventListenerManager; class SVGImageContext; @@ -126,6 +127,7 @@ enum class RelativeTo { */ class nsLayoutUtils { + typedef mozilla::AspectRatio AspectRatio; typedef mozilla::dom::DOMRectList DOMRectList; typedef mozilla::layers::Layer Layer; typedef mozilla::ContainerLayerParameters ContainerLayerParameters; @@ -1258,7 +1260,7 @@ public: */ static nsRect ComputeObjectDestRect(const nsRect& aConstraintRect, const IntrinsicSize& aIntrinsicSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, const nsStylePosition* aStylePos, nsPoint* aAnchorPoint = nullptr); @@ -1878,7 +1880,7 @@ public: */ static void ComputeSizeForDrawing(imgIContainer* aImage, CSSIntSize& aImageSize, - nsSize& aIntrinsicRatio, + AspectRatio& aIntrinsicRatio, bool& aGotWidth, bool& aGotHeight); diff --git a/layout/generic/AspectRatio.h b/layout/generic/AspectRatio.h new file mode 100644 index 000000000..0056c0620 --- /dev/null +++ b/layout/generic/AspectRatio.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef mozilla_AspectRatio_h +#define mozilla_AspectRatio_h + +/* The aspect ratio of a box, in a "width / height" format. */ + +#include "mozilla/Attributes.h" +#include "nsCoord.h" +#include <algorithm> +#include <limits> + +namespace mozilla { + +struct AspectRatio { + AspectRatio() : mRatio(0.0f) {} + explicit AspectRatio(float aRatio) : mRatio(std::max(aRatio, 0.0f)) {} + + static AspectRatio FromSize(float aWidth, float aHeight) { + if (aWidth == 0.0f || aHeight == 0.0f) { + return AspectRatio(); + } + return AspectRatio(aWidth / aHeight); + } + + static AspectRatio FromSize(nsSize aSize) { + return FromSize(aSize.width, aSize.height); + } + + static AspectRatio FromSize(nsIntSize aSize) { + return FromSize(aSize.width, aSize.height); + } + + explicit operator bool() const { return mRatio != 0.0f; } + + nscoord ApplyTo(nscoord aCoord) const { + MOZ_DIAGNOSTIC_ASSERT(*this); + return NSCoordSaturatingNonnegativeMultiply(aCoord, mRatio); + } + + float ApplyToFloat(float aFloat) const { + MOZ_DIAGNOSTIC_ASSERT(*this); + return mRatio * aFloat; + } + + // Inverts the ratio, in order to get the height / width ratio. + MOZ_MUST_USE AspectRatio Inverted() const { + if (!*this) { + return AspectRatio(); + } + // Clamp to a small epsilon, in case mRatio is absurdly large & produces + // 0.0f in the division here (so that valid ratios always generate other + // valid ratios when inverted). + return AspectRatio( + std::max(std::numeric_limits<float>::epsilon(), 1.0f / mRatio)); + } + + bool operator==(const AspectRatio& aOther) const { + return mRatio == aOther.mRatio; + } + + bool operator!=(const AspectRatio& aOther) const { + return !(*this == aOther); + } + + bool operator<(const AspectRatio& aOther) const { + return mRatio < aOther.mRatio; + } + + private: + // 0.0f represents no aspect ratio. + float mRatio; +}; + +} // namespace mozilla + +#endif // mozilla_AspectRatio_h diff --git a/layout/generic/crashtests/1633434.html b/layout/generic/crashtests/1633434.html new file mode 100644 index 000000000..8a60b2072 --- /dev/null +++ b/layout/generic/crashtests/1633434.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script> + document.addEventListener('DOMContentLoaded', () => { + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') + svg.setAttribute('height', '6') + svg.setAttribute('width', '1pc') + document.documentElement.appendChild(svg) + svg.style.setProperty('height', '5%', undefined) + svg.width.baseVal.valueInSpecifiedUnits = 1.988164037240853e+38 + }) + </script> +</head> +</html> diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 183556ab9..ab371429c 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -642,3 +642,4 @@ load 1278461-1.html load 1278461-2.html load 1304441.html load 1316649.html +load 1633434.html diff --git a/layout/generic/moz.build b/layout/generic/moz.build index ad186ef7a..b830470a3 100644 --- a/layout/generic/moz.build +++ b/layout/generic/moz.build @@ -109,6 +109,7 @@ EXPORTS += [ ] EXPORTS.mozilla += [ + 'AspectRatio.h', 'CSSAlignUtils.h', 'ReflowInput.h', 'ReflowOutput.h', diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 69200117b..a03d777e7 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -557,8 +557,8 @@ public: return mFlexShrink * mFlexBaseSize; } - const nsSize& IntrinsicRatio() const { return mIntrinsicRatio; } - bool HasIntrinsicRatio() const { return mIntrinsicRatio != nsSize(); } + const AspectRatio IntrinsicRatio() const { return mIntrinsicRatio; } + bool HasIntrinsicRatio() const { return !!mIntrinsicRatio; } // Getters for margin: // =================== @@ -756,7 +756,7 @@ protected: const float mFlexGrow; const float mFlexShrink; - const nsSize mIntrinsicRatio; + const AspectRatio mIntrinsicRatio; const nsMargin mBorderPadding; nsMargin mMargin; // non-const because we need to resolve auto margins @@ -1520,22 +1520,20 @@ CrossSizeToUseWithRatio(const FlexItem& aFlexItem, } // Convenience function; returns a main-size, given a cross-size and an -// intrinsic ratio. The intrinsic ratio must not have 0 in its cross-axis -// component (or else we'll divide by 0). +// intrinsic ratio. The caller is responsible for ensuring that the passed-in +// intrinsic ratio is not zero. static nscoord MainSizeFromAspectRatio(nscoord aCrossSize, - const nsSize& aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, const FlexboxAxisTracker& aAxisTracker) { - MOZ_ASSERT(aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0, + MOZ_ASSERT(aIntrinsicRatio, "Invalid ratio; will divide by 0! Caller should've checked..."); + AspectRatio ratio = aAxisTracker.IsMainAxisHorizontal() ? + aIntrinsicRatio : + aIntrinsicRatio.Inverted(); - if (aAxisTracker.IsCrossAxisHorizontal()) { - // cross axis horiz --> aCrossSize is a width. Converting to height. - return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.height, aIntrinsicRatio.width); - } - // cross axis vert --> aCrossSize is a height. Converting to width. - return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.width, aIntrinsicRatio.height); + return ratio.ApplyTo(aCrossSize); } // Partially resolves "min-[width|height]:auto" and returns the resulting value. @@ -1584,7 +1582,7 @@ PartiallyResolveAutoMinSize(const FlexItem& aFlexItem, // * if the item has an intrinsic aspect ratio, the width (height) calculated // from the aspect ratio and any definite size constraints in the opposite // dimension. - if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) { + if (aFlexItem.IntrinsicRatio()) { // We have a usable aspect ratio. (not going to divide by 0) const bool useMinSizeIfCrossSizeIsIndefinite = true; nscoord crossSizeToUseWithRatio = @@ -1617,7 +1615,7 @@ ResolveAutoFlexBasisFromRatio(FlexItem& aFlexItem, // - a definite cross size // then the flex base size is calculated from its inner cross size and the // flex item’s intrinsic aspect ratio. - if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) { + if (aFlexItem.IntrinsicRatio()) { // We have a usable aspect ratio. (not going to divide by 0) const bool useMinSizeIfCrossSizeIsIndefinite = false; nscoord crossSizeToUseWithRatio = @@ -1693,8 +1691,7 @@ nsFlexContainerFrame:: // (We'll consider that later, if we need to.) resolvedMinSize = PartiallyResolveAutoMinSize(aFlexItem, aItemReflowInput, aAxisTracker); - if (resolvedMinSize > 0 && - aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) == 0) { + if (resolvedMinSize > 0 && !aFlexItem.IntrinsicRatio()) { // We don't have a usable aspect ratio, so we need to consider our // min-content size as another candidate min-size, which we'll have to // min() with the current resolvedMinSize. diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 07cdbd7e3..cb70f8b1e 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4643,10 +4643,10 @@ nsFrame::GetIntrinsicSize() return IntrinsicSize(); // default is width/height set to eStyleUnit_None } -/* virtual */ nsSize +/* virtual */ AspectRatio nsFrame::GetIntrinsicRatio() { - return nsSize(0, 0); + return AspectRatio(); } /* virtual */ @@ -4660,7 +4660,7 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext, const LogicalSize& aPadding, ComputeSizeFlags aFlags) { - MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0), + MOZ_ASSERT(!GetIntrinsicRatio(), "Please override this method and call " "nsFrame::ComputeSizeWithIntrinsicDimensions instead."); LogicalSize result = ComputeAutoSize(aRenderingContext, aWM, @@ -4916,13 +4916,15 @@ LogicalSize nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingContext, WritingMode aWM, const IntrinsicSize& aIntrinsicSize, - nsSize aIntrinsicRatio, + const AspectRatio& aIntrinsicRatio, const LogicalSize& aCBSize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, ComputeSizeFlags aFlags) { + auto logicalRatio = + aWM.IsVertical() ? aIntrinsicRatio.Inverted() : aIntrinsicRatio; const nsStylePosition* stylePos = StylePosition(); const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM); const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM); @@ -5183,10 +5185,6 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte intrinsicBSize = 0; } - NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0, - "Intrinsic ratio has a negative component!"); - LogicalSize logicalRatio(aWM, aIntrinsicRatio); - // Now calculate the used values for iSize and bSize: if (isAutoISize) { @@ -5200,9 +5198,9 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte if (hasIntrinsicISize) { tentISize = intrinsicISize; - } else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } else if (logicalRatio.ISize(aWM) > 0) { + } else if (hasIntrinsicBSize && logicalRatio) { + tentISize = logicalRatio.ApplyTo(intrinsicBSize); + } else if (logicalRatio) { tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar? if (tentISize < 0) tentISize = 0; } else { @@ -5219,8 +5217,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte if (hasIntrinsicBSize) { tentBSize = intrinsicBSize; - } else if (logicalRatio.ISize(aWM) > 0) { - tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + } else if (logicalRatio) { + tentBSize = logicalRatio.Inverted().ApplyTo(tentISize); } else { tentBSize = nsPresContext::CSSPixelsToAppUnits(150); } @@ -5231,46 +5229,39 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio); } - if (aIntrinsicRatio != nsSize(0, 0)) { + if (logicalRatio) { if (stretchI == eStretch) { tentISize = iSize; // * / 'stretch' if (stretchB == eStretch) { tentBSize = bSize; // 'stretch' / 'stretch' - } else if (stretchB == eStretchPreservingRatio && logicalRatio.ISize(aWM) > 0) { + } else if (stretchB == eStretchPreservingRatio) { // 'normal' / 'stretch' - tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + tentBSize = logicalRatio.Inverted().ApplyTo(iSize); } } else if (stretchB == eStretch) { tentBSize = bSize; // 'stretch' / * (except 'stretch') - if (stretchI == eStretchPreservingRatio && logicalRatio.BSize(aWM) > 0) { + if (stretchI == eStretchPreservingRatio) { // 'stretch' / 'normal' - tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + tentISize = logicalRatio.ApplyTo(bSize); } } else if (stretchI == eStretchPreservingRatio) { tentISize = iSize; // * (except 'stretch') / 'normal' - if (logicalRatio.ISize(aWM) > 0) { - tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); - } + tentBSize = logicalRatio.Inverted().ApplyTo(iSize); if (stretchB == eStretchPreservingRatio && tentBSize > bSize) { // Stretch within the CB size with preserved intrinsic ratio. tentBSize = bSize; // 'normal' / 'normal' - if (logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } + tentISize = logicalRatio.ApplyTo(bSize); } } else if (stretchB == eStretchPreservingRatio) { tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch') - if (logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } + tentISize = logicalRatio.ApplyTo(bSize); } } // ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when applying // the min/max-size. We don't want that when we have 'stretch' in either // axis because tentISize/tentBSize is likely not according to ratio now. - if (aIntrinsicRatio != nsSize(0, 0) && - stretchI != eStretch && stretchB != eStretch) { + if (logicalRatio && stretchI != eStretch && stretchB != eStretch) { nsSize autoSize = nsLayoutUtils:: ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize, maxISize, maxBSize, @@ -5291,8 +5282,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte // 'auto' iSize, non-'auto' bSize bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); if (stretchI != eStretch) { - if (logicalRatio.BSize(aWM) > 0) { - iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + if (logicalRatio) { + iSize = logicalRatio.ApplyTo(bSize); } else if (hasIntrinsicISize) { if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) && intrinsicISize > iSize)) { @@ -5311,8 +5302,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte // non-'auto' iSize, 'auto' bSize iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); if (stretchB != eStretch) { - if (logicalRatio.ISize(aWM) > 0) { - bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + if (logicalRatio) { + bSize = logicalRatio.Inverted().ApplyTo(iSize); } else if (hasIntrinsicBSize) { if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) && intrinsicBSize > bSize)) { diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 439e39856..d75555fec 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -264,7 +264,7 @@ public: IntrinsicISizeOffsetData IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual mozilla::LogicalSize ComputeSize(nsRenderingContext* aRenderingContext, @@ -285,7 +285,7 @@ public: nsRenderingContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::IntrinsicSize& aIntrinsicSize, - nsSize aIntrinsicRatio, + const mozilla::AspectRatio& aIntrinsicRatio, const mozilla::LogicalSize& aCBSize, const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index f86ec1136..f40f799ba 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -44,21 +44,6 @@ IntrinsicSizeFromCanvasSize(const nsIntSize& aCanvasSizeInPx) return intrinsicSize; } -/* Helper for our nsIFrame::GetIntrinsicRatio() impl. Takes the result of - * "GetCanvasSize()" as a parameter, which may help avoid redundant - * indirect calls to GetCanvasSize(). - * - * @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned - * by GetCanvasSize(). - * @return The canvas's intrinsic ratio, as a nsSize. - */ -static nsSize -IntrinsicRatioFromCanvasSize(const nsIntSize& aCanvasSizeInPx) -{ - return nsSize(nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width), - nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height)); -} - class nsDisplayCanvas : public nsDisplayItem { public: nsDisplayCanvas(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) @@ -92,7 +77,7 @@ public: // Need intrinsic size & ratio, for ComputeObjectDestRect: nsIntSize canvasSize = f->GetCanvasSize(); IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSize); - nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSize); + AspectRatio intrinsicRatio = AspectRatio::FromSize(canvasSize); const nsRect destRect = nsLayoutUtils::ComputeObjectDestRect(constraintRect, @@ -211,10 +196,16 @@ nsHTMLCanvasFrame::GetIntrinsicSize() return IntrinsicSizeFromCanvasSize(GetCanvasSize()); } -/* virtual */ nsSize +/* virtual */ AspectRatio nsHTMLCanvasFrame::GetIntrinsicRatio() { - return IntrinsicRatioFromCanvasSize(GetCanvasSize()); + // When 'contain: size' is implemented, make sure to check for it. +/* + if (StyleDisplay()->IsContainSize()) { + return AspectRatio(); + } + */ + return AspectRatio::FromSize(GetCanvasSize()); } /* virtual */ @@ -234,7 +225,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext, intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width)); intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height)); - nsSize intrinsicRatio = GetIntrinsicRatio(); // won't actually be used + AspectRatio intrinsicRatio = GetIntrinsicRatio(); return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, intrinsicSize, intrinsicRatio, @@ -340,7 +331,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx); - nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx); + AspectRatio intrinsicRatio = AspectRatio::FromSize(canvasSizeInPx); nsRect dest = nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio, diff --git a/layout/generic/nsHTMLCanvasFrame.h b/layout/generic/nsHTMLCanvasFrame.h index b2d159627..8432ad224 100644 --- a/layout/generic/nsHTMLCanvasFrame.h +++ b/layout/generic/nsHTMLCanvasFrame.h @@ -58,7 +58,7 @@ public: virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual mozilla::LogicalSize ComputeSize(nsRenderingContext *aRenderingContext, diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 82bcf563a..b3606d0b4 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -27,6 +27,7 @@ #include "FrameProperties.h" #include "LayoutConstants.h" #include "mozilla/layout/FrameChildList.h" +#include "mozilla/AspectRatio.h" #include "mozilla/Maybe.h" #include "mozilla/WritingModes.h" #include "nsDirection.h" @@ -2047,15 +2048,14 @@ public: virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0; /** - * Get the intrinsic ratio of this element, or nsSize(0,0) if it has - * no intrinsic ratio. The intrinsic ratio is the ratio of the - * height/width of a box with an intrinsic size or the intrinsic - * aspect ratio of a scalable vector image without an intrinsic size. + * Get the intrinsic ratio of this element, or a default-constructed + * AspectRatio if it has no intrinsic ratio. * - * Either one of the sides may be zero, indicating a zero or infinite - * ratio. + * The intrinsic ratio is the ratio of the width/height of a box with an + * intrinsic size or the intrinsic aspect ratio of a scalable vector image + * without an intrinsic size. */ - virtual nsSize GetIntrinsicRatio() = 0; + virtual mozilla::AspectRatio GetIntrinsicRatio() = 0; /** * Bit-flags to pass to ComputeSize in |aFlags| parameter. diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 03fcbd8e3..2646125c9 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -14,6 +14,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" #include "mozilla/gfx/PathHelpers.h" +#include "mozilla/dom/HTMLImageElement.h" #include "mozilla/MouseEvents.h" #include "mozilla/Unused.h" @@ -138,7 +139,6 @@ NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame) nsImageFrame::nsImageFrame(nsStyleContext* aContext) : nsAtomicContainerFrame(aContext), mComputedSize(0, 0), - mIntrinsicRatio(0, 0), mDisplayingIcon(false), mFirstFrameComplete(false), mReflowCallbackPosted(false), @@ -230,26 +230,26 @@ nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsAtomicContainerFrame::DidSetStyleContext(aOldStyleContext); - if (!mImage) { - // We'll pick this change up whenever we do get an image. - return; - } - nsStyleImageOrientation newOrientation = StyleVisibility()->mImageOrientation; // We need to update our orientation either if we had no style context before // because this is the first time it's been set, or if the image-orientation // property changed from its previous value. bool shouldUpdateOrientation = - !aOldStyleContext || - aOldStyleContext->StyleVisibility()->mImageOrientation != newOrientation; + mImage && + (!aOldStyleContext || + aOldStyleContext->StyleVisibility()->mImageOrientation != newOrientation); if (shouldUpdateOrientation) { nsCOMPtr<imgIContainer> image(mImage->Unwrap()); mImage = nsLayoutUtils::OrientImage(image, newOrientation); - UpdateIntrinsicSize(mImage); - UpdateIntrinsicRatio(mImage); + UpdateIntrinsicSize(); + UpdateIntrinsicRatio(); + } else if (!aOldStyleContext || + aOldStyleContext->StylePosition()->mAspectRatio != + StylePosition()->mAspectRatio) { + UpdateIntrinsicRatio(); } } @@ -287,50 +287,110 @@ nsImageFrame::Init(nsIContent* aContent, p->AdjustPriority(-1); } -bool -nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage) +static IntrinsicSize +ComputeIntrinsicSize(imgIContainer* aImage, + bool aUseMappedRatio, + const nsImageFrame& aFrame) { - NS_PRECONDITION(aImage, "null image"); - if (!aImage) - return false; + // When 'contain: size' is implemented, make sure to check for it. +/* + const ComputedStyle& style = *aFrame.Style(); + if (style.StyleDisplay()->IsContainSize()) { + return AspectRatio(); + } + */ + nsSize size; + IntrinsicSize intrinsicSize; + if (aImage && NS_SUCCEEDED(aImage->GetIntrinsicSize(&size))) { + if (size.width != -1) + intrinsicSize.width.SetCoordValue(size.width); + if (size.height != -1) + intrinsicSize.height.SetCoordValue(size.height); + return intrinsicSize; + } - IntrinsicSize oldIntrinsicSize = mIntrinsicSize; - mIntrinsicSize = IntrinsicSize(); - - // Set intrinsic size to match aImage's reported intrinsic width & height. - nsSize intrinsicSize; - if (NS_SUCCEEDED(aImage->GetIntrinsicSize(&intrinsicSize))) { - // If the image has no intrinsic width, intrinsicSize.width will be -1, and - // we can leave mIntrinsicSize.width at its default value of eStyleUnit_None. - // Otherwise we use intrinsicSize.width. Height works the same way. - if (intrinsicSize.width != -1) - mIntrinsicSize.width.SetCoordValue(intrinsicSize.width); - if (intrinsicSize.height != -1) - mIntrinsicSize.height.SetCoordValue(intrinsicSize.height); - } else { - // Failure means that the image hasn't loaded enough to report a result. We - // treat this case as if the image's intrinsic size was 0x0. - mIntrinsicSize.width.SetCoordValue(0); - mIntrinsicSize.height.SetCoordValue(0); + // If broken images should ever lose their size + /* + if (aFrame.ShouldShowBrokenImageIcon()) { + nscoord edgeLengthToUse = nsPresContext::CSSPixelsToAppUnits( + ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH))); + intrinsicSize.width.SetCoordValue(edgeLengthToUse); + intrinsicSize.height.SetCoordValue(edgeLengthToUse); + return intrinsicSize; } + */ - return mIntrinsicSize != oldIntrinsicSize; + if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) { + return IntrinsicSize(); + } + + intrinsicSize.width.SetCoordValue(0); + intrinsicSize.height.SetCoordValue(0); + return intrinsicSize; +} + +// For compat reasons, see bug 1602047, we don't use the intrinsic ratio from +// width="" and height="" for images with no src attribute (no request). +// +// If <img loading=lazy> ever gets implemented, this will need to check for it. +bool nsImageFrame::ShouldUseMappedAspectRatio() const { + nsCOMPtr<imgIRequest> currentRequest; + nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); + if (imageLoader) { + imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, + getter_AddRefs(currentRequest)); + } + if (!!currentRequest) { + return true; + } + // TODO(emilio): Investigate the compat situation of the above check, maybe we + // can just check for empty src attribute or something... + auto* image = static_cast<HTMLImageElement*>(mContent); + return image && image->IsAwaitingLoad(); } bool -nsImageFrame::UpdateIntrinsicRatio(imgIContainer* aImage) +nsImageFrame::UpdateIntrinsicSize() { - NS_PRECONDITION(aImage, "null image"); - - if (!aImage) - return false; + IntrinsicSize oldIntrinsicSize = mIntrinsicSize; + mIntrinsicSize = ComputeIntrinsicSize(mImage, ShouldUseMappedAspectRatio(), *this); + return mIntrinsicSize != oldIntrinsicSize; +} - nsSize oldIntrinsicRatio = mIntrinsicRatio; +static AspectRatio +ComputeAspectRatio(imgIContainer* aImage, + bool aUseMappedRatio, + const nsImageFrame& aFrame) +{ + // When 'contain: size' is implemented, make sure to check for it. +/* + const ComputedStyle& style = *aFrame.Style(); + if (style.StyleDisplay()->IsContainSize()) { + return AspectRatio(); + } + */ + if (aImage) { + AspectRatio fromImage; + if (NS_SUCCEEDED(aImage->GetIntrinsicRatio(&fromImage))) { + return fromImage; + } + } + if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) { + return AspectRatio(aFrame.StylePosition()->mAspectRatio); + } + if (aFrame.ShouldShowBrokenImageIcon()) { + return AspectRatio(1.0f); + } + return AspectRatio(); +} - // Set intrinsic ratio to match aImage's reported intrinsic ratio. - if (NS_FAILED(aImage->GetIntrinsicRatio(&mIntrinsicRatio))) - mIntrinsicRatio.SizeTo(0, 0); +bool +nsImageFrame::UpdateIntrinsicRatio() +{ + AspectRatio oldIntrinsicRatio = mIntrinsicRatio; + mIntrinsicRatio = + ComputeAspectRatio(mImage, ShouldUseMappedAspectRatio(), *this); return mIntrinsicRatio != oldIntrinsicRatio; } @@ -542,30 +602,38 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage) return NS_OK; } - bool intrinsicSizeChanged = false; + UpdateImage(aRequest, aImage); + return NS_OK; +} + +void nsImageFrame::UpdateImage(imgIRequest* aRequest, imgIContainer* aImage) { + MOZ_ASSERT(aRequest); if (SizeIsAvailable(aRequest)) { // This is valid and for the current request, so update our stored image // container, orienting according to our style. - mImage = nsLayoutUtils::OrientImage(aImage, StyleVisibility()->mImageOrientation); - - intrinsicSizeChanged = UpdateIntrinsicSize(mImage); - intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged; + mImage = nsLayoutUtils::OrientImage(aImage, + StyleVisibility()->mImageOrientation); + MOZ_ASSERT(mImage); } else { // We no longer have a valid image, so release our stored image container. mImage = mPrevImage = nullptr; - - // Have to size to 0,0 so that GetDesiredSize recalculates the size. - mIntrinsicSize.width.SetCoordValue(0); - mIntrinsicSize.height.SetCoordValue(0); - mIntrinsicRatio.SizeTo(0, 0); - intrinsicSizeChanged = true; + } + // NOTE(emilio): Intentionally using `|` instead of `||` to avoid + // short-circuiting. + bool intrinsicSizeChanged = + UpdateIntrinsicSize() | UpdateIntrinsicRatio(); + if (!(mState & IMAGE_GOTINITIALREFLOW)) { + return; } - if (intrinsicSizeChanged && (mState & IMAGE_GOTINITIALREFLOW)) { + // We're going to need to repaint now either way. + InvalidateFrame(); + + if (intrinsicSizeChanged) { // Now we need to reflow if we have an unconstrained size and have - // already gotten the initial reflow + // already gotten the initial reflow. if (!(mState & IMAGE_SIZECONSTRAINED)) { - nsIPresShell *presShell = presContext->GetPresShell(); + nsIPresShell *presShell = PresContext()->GetPresShell(); NS_ASSERTION(presShell, "No PresShell."); if (presShell) { presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange, @@ -579,8 +647,6 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage) mPrevImage = nullptr; } - - return NS_OK; } nsresult @@ -655,45 +721,9 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest, { nsCOMPtr<imgIContainer> image; aRequest->GetImage(getter_AddRefs(image)); - NS_ASSERTION(image || NS_FAILED(aStatus), "Successful load with no container?"); - - // May have to switch sizes here! - bool intrinsicSizeChanged = true; - if (NS_SUCCEEDED(aStatus) && image && SizeIsAvailable(aRequest)) { - // Update our stored image container, orienting according to our style. - mImage = nsLayoutUtils::OrientImage(image, StyleVisibility()->mImageOrientation); - - intrinsicSizeChanged = UpdateIntrinsicSize(mImage); - intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged; - } else { - // We no longer have a valid image, so release our stored image container. - mImage = mPrevImage = nullptr; - - // Have to size to 0,0 so that GetDesiredSize recalculates the size - mIntrinsicSize.width.SetCoordValue(0); - mIntrinsicSize.height.SetCoordValue(0); - mIntrinsicRatio.SizeTo(0, 0); - } - - if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet - if (intrinsicSizeChanged) { - if (!(mState & IMAGE_SIZECONSTRAINED)) { - nsIPresShell *presShell = PresContext()->GetPresShell(); - if (presShell) { - presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange, - NS_FRAME_IS_DIRTY); - } - } else { - // We've already gotten the initial reflow, and our size hasn't changed, - // so we're ready to request a decode. - MaybeDecodeForPredictedSize(); - } - - mPrevImage = nullptr; - } - // Update border+content to account for image change - InvalidateFrame(); - } + NS_ASSERTION(image || NS_FAILED(aStatus), + "Successful load with no container?"); + UpdateImage(aRequest, image); } void @@ -787,32 +817,27 @@ bool nsImageFrame::ShouldShowBrokenImageIcon() const void nsImageFrame::EnsureIntrinsicSizeAndRatio() { + // When 'contain: size' is implemented, make sure to check for it. +/* + if (StyleDisplay()->IsContainSize()) { + // If we have 'contain:size', then our intrinsic size and ratio are 0,0 + // regardless of what our underlying image may think. + mIntrinsicSize = IntrinsicSize(0, 0); + mIntrinsicRatio = AspectRatio(); + return; + } + */ + // If mIntrinsicSize.width and height are 0, then we need to update from the // image container. - if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && + if (!(mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && mIntrinsicSize.width.GetCoordValue() == 0 && mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord && - mIntrinsicSize.height.GetCoordValue() == 0) { - - if (mImage) { - UpdateIntrinsicSize(mImage); - UpdateIntrinsicRatio(mImage); - } else { - // Image request is null or image size not known. - if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) { - // Likely an invalid image. Check if we should display it as broken. - if (ShouldShowBrokenImageIcon()) { - // Invalid image specified. make the image big enough for the "broken" icon - nscoord edgeLengthToUse = - nsPresContext::CSSPixelsToAppUnits( - ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH))); - mIntrinsicSize.width.SetCoordValue(edgeLengthToUse); - mIntrinsicSize.height.SetCoordValue(edgeLengthToUse); - mIntrinsicRatio.SizeTo(1, 1); - } - } - } + mIntrinsicSize.height.GetCoordValue() == 0)) { + return; } + UpdateIntrinsicSize(); + UpdateIntrinsicRatio(); } /* virtual */ @@ -932,7 +957,7 @@ nsImageFrame::GetIntrinsicSize() return mIntrinsicSize; } -/* virtual */ nsSize +/* virtual */ AspectRatio nsImageFrame::GetIntrinsicRatio() { return mIntrinsicRatio; diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 59af1be32..5e9b67274 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -86,7 +86,7 @@ public: virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, @@ -273,21 +273,19 @@ private: void GetDocumentCharacterSet(nsACString& aCharset) const; bool ShouldDisplaySelection(); + // Whether the image frame should use the mapped aspect ratio from width="" + // and height="". + bool ShouldUseMappedAspectRatio() const; + /** * Recalculate mIntrinsicSize from the image. - * - * @return whether aImage's size did _not_ - * match our previous intrinsic size. */ - bool UpdateIntrinsicSize(imgIContainer* aImage); + bool UpdateIntrinsicSize(); /** * Recalculate mIntrinsicRatio from the image. - * - * @return whether aImage's ratio did _not_ - * match our previous intrinsic ratio. */ - bool UpdateIntrinsicRatio(imgIContainer* aImage); + bool UpdateIntrinsicRatio(); /** * This function calculates the transform for converting between @@ -308,6 +306,12 @@ private: bool IsPendingLoad(imgIRequest* aRequest) const; /** + * Updates mImage based on the current image request (cannot be null), and the + * image passed in (can be null), and invalidate layout and paint as needed. + */ + void UpdateImage(imgIRequest* aRequest, imgIContainer* aImage); + + /** * Function to convert a dirty rect in the source image to a dirty * rect for the image frame. */ @@ -333,7 +337,7 @@ private: nsCOMPtr<imgIContainer> mPrevImage; nsSize mComputedSize; mozilla::IntrinsicSize mIntrinsicSize; - nsSize mIntrinsicRatio; + mozilla::AspectRatio mIntrinsicRatio; bool mDisplayingIcon; bool mFirstFrameComplete; diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 6a15a9cfa..60e4e8c96 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -784,7 +784,7 @@ IsPercentageAware(const nsIFrame* aFrame) // is calculated from the constraint equation used for // block-level, non-replaced elements in normal flow. nsIFrame *f = const_cast<nsIFrame*>(aFrame); - if (f->GetIntrinsicRatio() != nsSize(0, 0) && + if (f->GetIntrinsicRatio() && // Some percents are treated like 'auto', so check != coord pos->mHeight.GetUnit() != eStyleUnit_Coord) { const IntrinsicSize &intrinsicSize = f->GetIntrinsicSize(); diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index fd9a7d32c..31d04a335 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -671,7 +671,7 @@ nsSubDocumentFrame::GetIntrinsicSize() return nsAtomicContainerFrame::GetIntrinsicSize(); } -/* virtual */ nsSize +/* virtual */ AspectRatio nsSubDocumentFrame::GetIntrinsicRatio() { nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame(); @@ -771,7 +771,7 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, // Size & position the view according to 'object-fit' & 'object-position'. nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame(); IntrinsicSize intrinsSize; - nsSize intrinsRatio; + AspectRatio intrinsRatio; if (subDocRoot) { intrinsSize = subDocRoot->GetIntrinsicSize(); intrinsRatio = subDocRoot->GetIntrinsicRatio(); diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index 93d908dcc..907d33710 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -51,7 +51,7 @@ public: virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual mozilla::LogicalSize ComputeAutoSize(nsRenderingContext* aRenderingContext, diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index cea209cb5..0472ebe62 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -217,12 +217,10 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, // Convert video size from pixel units into app units, to get an aspect-ratio // (which has to be represented as a nsSize) and an IntrinsicSize that we // can pass to ComputeObjectRenderRect. - nsSize aspectRatio(nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.width), - nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.height)); + auto aspectRatio = AspectRatio::FromSize(videoSizeInPx); IntrinsicSize intrinsicSize; - intrinsicSize.width.SetCoordValue(aspectRatio.width); - intrinsicSize.height.SetCoordValue(aspectRatio.height); - + intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.width)); + intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.height)); nsRect dest = nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, aspectRatio, @@ -533,7 +531,9 @@ nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext, intrinsicSize.height.SetCoordValue(size.height); // Only video elements have an intrinsic ratio. - nsSize intrinsicRatio = HasVideoElement() ? size : nsSize(0, 0); + auto intrinsicRatio = HasVideoElement() ? + AspectRatio::FromSize(size) : + AspectRatio(); return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, intrinsicSize, intrinsicRatio, @@ -557,14 +557,14 @@ nscoord nsVideoFrame::GetPrefISize(nsRenderingContext *aRenderingContext) return result; } -nsSize nsVideoFrame::GetIntrinsicRatio() +AspectRatio nsVideoFrame::GetIntrinsicRatio() { if (!HasVideoElement()) { // Audio elements have no intrinsic ratio. - return nsSize(0, 0); + return AspectRatio(); } - return GetVideoIntrinsicSize(nullptr); + return AspectRatio::FromSize(GetVideoIntrinsicSize(nullptr)); } bool nsVideoFrame::ShouldDisplayPoster() diff --git a/layout/generic/nsVideoFrame.h b/layout/generic/nsVideoFrame.h index d624ae6b9..f52cd8277 100644 --- a/layout/generic/nsVideoFrame.h +++ b/layout/generic/nsVideoFrame.h @@ -56,7 +56,7 @@ public: /* get the size of the video's display */ nsSize GetVideoIntrinsicSize(nsRenderingContext *aRenderingContext); - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual mozilla::LogicalSize ComputeSize(nsRenderingContext *aRenderingContext, mozilla::WritingMode aWritingMode, diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 0ce337e29..df523174d 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -1277,7 +1277,8 @@ Loader::PrepareSheet(StyleSheet* aSheet, const nsSubstring& aMediaString, nsMediaList* aMediaList, Element* aScopeElement, - bool isAlternate) + bool isAlternate, + bool isExplicitlyEnabled) { NS_PRECONDITION(aSheet, "Must have a sheet!"); @@ -1306,7 +1307,7 @@ Loader::PrepareSheet(StyleSheet* aSheet, sheet->SetMedia(mediaList); sheet->SetTitle(aTitle); - sheet->SetEnabled(!isAlternate); + sheet->SetEnabled(!isAlternate || isExplicitlyEnabled); sheet->SetScopeElement(aScopeElement); } @@ -1984,7 +1985,8 @@ Loader::LoadInlineStyle(nsIContent* aElement, Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, - bool* aIsAlternate) + bool* aIsAlternate, + bool* aIsExplicitlyEnabled) { LOG(("css::Loader::LoadInlineStyle")); NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?"); @@ -2016,8 +2018,9 @@ Loader::LoadInlineStyle(nsIContent* aElement, "Inline sheets should not be cached"); LOG((" Sheet is alternate: %d", *aIsAlternate)); + LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled)); - PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate); + PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate, *aIsExplicitlyEnabled); if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) { ShadowRoot* containingShadow = aElement->GetContainingShadow(); @@ -2058,7 +2061,8 @@ Loader::LoadStyleLink(nsIContent* aElement, ReferrerPolicy aReferrerPolicy, const nsAString& aIntegrity, nsICSSLoaderObserver* aObserver, - bool* aIsAlternate) + bool* aIsAlternate, + bool* aIsExplicitlyEnabled) { LOG(("css::Loader::LoadStyleLink")); NS_PRECONDITION(aURL, "Must have URL to load"); @@ -2111,8 +2115,9 @@ Loader::LoadStyleLink(nsIContent* aElement, NS_ENSURE_SUCCESS(rv, rv); LOG((" Sheet is alternate: %d", *aIsAlternate)); + LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled)); - PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate); + PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate, *aIsExplicitlyEnabled); rv = InsertSheetInDoc(sheet, aElement, mDocument); NS_ENSURE_SUCCESS(rv, rv); @@ -2137,9 +2142,10 @@ Loader::LoadStyleLink(nsIContent* aElement, aObserver, principal, requestingNode); NS_ADDREF(data); - // If we have to parse and it's an alternate non-inline, defer it + // If we have to parse and it's an alternate non-inline, defer it unless + // it's explicitly enabled. if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 && - *aIsAlternate) { + *aIsAlternate && !*aIsExplicitlyEnabled) { LOG((" Deferring alternate sheet load")); URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI, data->mLoaderPrincipal, @@ -2266,6 +2272,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet, state = eSheetComplete; } else { bool isAlternate; + bool isExplicitlyEnabled; const nsSubstring& empty = EmptyString(); // For now, use CORS_NONE for child sheets rv = CreateSheet(aURL, nullptr, principal, @@ -2276,7 +2283,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet, false, empty, state, &isAlternate, &sheet); NS_ENSURE_SUCCESS(rv, rv); - PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate); + PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate, isExplicitlyEnabled); } rv = InsertChildSheet(sheet, aParentSheet, aParentRule); @@ -2389,6 +2396,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL, StyleSheetState state; bool isAlternate; + bool isExplicitlyEnabled; RefPtr<StyleSheet> sheet; bool syncLoad = (aObserver == nullptr); const nsSubstring& empty = EmptyString(); @@ -2398,7 +2406,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL, false, empty, state, &isAlternate, &sheet); NS_ENSURE_SUCCESS(rv, rv); - PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate); + PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate, isExplicitlyEnabled); if (state == eSheetComplete) { LOG((" Sheet already complete")); diff --git a/layout/style/Loader.h b/layout/style/Loader.h index 209783a80..4a3088b6b 100644 --- a/layout/style/Loader.h +++ b/layout/style/Loader.h @@ -230,6 +230,8 @@ public: * @param [out] aCompleted whether parsing of the sheet completed. * @param [out] aIsAlternate whether the stylesheet ended up being an * alternate sheet. + * @param [out] aIsExplicitlyEnabled whether the stylesheet was explicitly + * enabled by having the disabled attribute removed. */ nsresult LoadInlineStyle(nsIContent* aElement, const nsAString& aBuffer, @@ -239,7 +241,8 @@ public: mozilla::dom::Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, - bool* aIsAlternate); + bool* aIsAlternate, + bool* aIsExplicitlyEnabled); /** * Load a linked (document) stylesheet. If a successful result is returned, @@ -260,6 +263,8 @@ public: * @param [out] aIsAlternate whether the stylesheet actually ended up beinga * an alternate sheet. Note that this need not match * aHasAlternateRel. + * @param [out] aIsExplicitlyEnabled whether the stylesheet was explicitly + * enabled by having the disabled attribute removed. */ nsresult LoadStyleLink(nsIContent* aElement, nsIURI* aURL, @@ -270,7 +275,8 @@ public: ReferrerPolicy aReferrerPolicy, const nsAString& aIntegrity, nsICSSLoaderObserver* aObserver, - bool* aIsAlternate); + bool* aIsAlternate, + bool* aIsExplicitlyEnabled); /** * Load a child (@import-ed) style sheet. In addition to loading the sheet, @@ -476,7 +482,8 @@ private: const nsAString& aMediaString, nsMediaList* aMediaList, dom::Element* aScopeElement, - bool isAlternate); + bool isAlternate, + bool isExplicitlyEnabled); nsresult InsertSheetInDoc(StyleSheet* aSheet, nsIContent* aLinkingContent, diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index f7938af9e..9ec71b2cf 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -264,6 +264,11 @@ CSS_PROP_ALIAS(-webkit-animation-timing-function, WebkitAnimationTimingFunction, WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-appearance, + appearance, + WebkitAppearance, + WEBKIT_PREFIX_PREF) + CSS_PROP_ALIAS(-webkit-filter, filter, WebkitFilter, diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 411f982a4..f62aa3827 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -470,6 +470,19 @@ CSS_PROP_DISPLAY( kAppearanceKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_Discrete) +#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL +CSS_PROP_POSITION( + aspect-ratio, + aspect_ratio, + AspectRatio, + CSS_PROPERTY_INTERNAL | + CSS_PROPERTY_PARSE_INACCESSIBLE, + "", + VARIANT_NUMBER, + nullptr, + offsetof(nsStylePosition, mAspectRatio), + eStyleAnimType_None) +#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL CSS_PROP_DISPLAY( backface-visibility, backface_visibility, diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index a0f65c069..1a451a2ef 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -8544,6 +8544,12 @@ nsRuleNode::ComputePositionData(void* aStartStruct, SETCOORD_UNSET_INITIAL, aContext, mPresContext, conditions); + // aspect-ratio: float, initial + SetFactor(*aRuleData->ValueForAspectRatio(), + pos->mAspectRatio, conditions, + parentPos->mAspectRatio, 0.0f, + SETFCT_UNSET_INITIAL | SETFCT_POSITIVE | SETFCT_NONE); + // box-sizing: enum, inherit, initial SetValue(*aRuleData->ValueForBoxSizing(), pos->mBoxSizing, conditions, diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 200f934c5..3b19a4418 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1408,6 +1408,7 @@ nsStylePosition::nsStylePosition(StyleStructContext aContext) , mGridAutoColumnsMax(eStyleUnit_Auto) , mGridAutoRowsMin(eStyleUnit_Auto) , mGridAutoRowsMax(eStyleUnit_Auto) + , mAspectRatio(0.0f) , mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW) , mBoxSizing(StyleBoxSizing::Content) , mAlignContent(NS_STYLE_ALIGN_NORMAL) @@ -1466,6 +1467,7 @@ nsStylePosition::nsStylePosition(const nsStylePosition& aSource) , mGridAutoColumnsMax(aSource.mGridAutoColumnsMax) , mGridAutoRowsMin(aSource.mGridAutoRowsMin) , mGridAutoRowsMax(aSource.mGridAutoRowsMax) + , mAspectRatio(aSource.mAspectRatio) , mGridAutoFlow(aSource.mGridAutoFlow) , mBoxSizing(aSource.mBoxSizing) , mAlignContent(aSource.mAlignContent) @@ -1636,6 +1638,11 @@ nsStylePosition::CalcDifference(const nsStylePosition& aNewData, if (isVertical ? heightChanged : widthChanged) { hint |= nsChangeHint_ReflowHintsForISizeChange; } + + if (mAspectRatio != aNewData.mAspectRatio) { + hint |= nsChangeHint_ReflowHintsForISizeChange | + nsChangeHint_ReflowHintsForBSizeChange; + } } else { if (widthChanged || heightChanged) { hint |= nsChangeHint_NeutralChange; @@ -2731,7 +2738,7 @@ nsStyleImageLayers::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImag } if (imgContainer) { CSSIntSize imageSize; - nsSize imageRatio; + AspectRatio imageRatio; bool hasWidth, hasHeight; nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio, hasWidth, hasHeight); @@ -2744,7 +2751,7 @@ nsStyleImageLayers::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImag // If the image has an intrinsic ratio, rendering will depend on frame // size when background-size is all auto. - if (imageRatio != nsSize(0, 0)) { + if (imageRatio) { return mWidthType == mHeightType; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index b257c6bb5..4bda817dd 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1815,6 +1815,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition nsStyleCoord mGridAutoColumnsMax; // [reset] coord, percent, enum, calc, flex nsStyleCoord mGridAutoRowsMin; // [reset] coord, percent, enum, calc, flex nsStyleCoord mGridAutoRowsMax; // [reset] coord, percent, enum, calc, flex + float mAspectRatio; // [reset] float uint8_t mGridAutoFlow; // [reset] enumerated. See nsStyleConsts.h mozilla::StyleBoxSizing mBoxSizing; // [reset] see nsStyleConsts.h diff --git a/layout/style/test/ListCSSProperties.cpp b/layout/style/test/ListCSSProperties.cpp index 718032f61..9f727104b 100644 --- a/layout/style/test/ListCSSProperties.cpp +++ b/layout/style/test/ListCSSProperties.cpp @@ -106,6 +106,7 @@ const char *gInaccessibleProperties[] = { "-x-span", "-x-system-font", "-x-text-zoom", + "aspect-ratio", // for now. "-moz-control-character-visibility", "-moz-script-level", // parsed by UA sheets only "-moz-script-size-multiplier", diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index 16dfc2b37..3f68245e2 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -232,28 +232,30 @@ nsSVGOuterSVGFrame::GetIntrinsicSize() return intrinsicSize; } -/* virtual */ nsSize +/* virtual */ AspectRatio nsSVGOuterSVGFrame::GetIntrinsicRatio() -{ +{ + // When 'contain: size' is implemented, make sure to check for it. +/* + if (this->GetContent->GetParent() && this->StyleDisplay()->IsContainSize()) { + return AspectRatio(); + } + */ + // We only have an intrinsic size/ratio if our width and height attributes // are both specified and set to non-percentage values, or we have a viewBox // rect: http://www.w3.org/TR/SVGMobile12/coords.html#IntrinsicSizing + // Unfortunately we have to return the ratio as two nscoords whereas what + // we have are two floats. Using app units allows for some floating point + // values to work but really small or large numbers will fail. SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent); nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH]; nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT]; if (!width.IsPercentage() && !height.IsPercentage()) { - nsSize ratio( - nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content)), - nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content))); - if (ratio.width < 0) { - ratio.width = 0; - } - if (ratio.height < 0) { - ratio.height = 0; - } - return ratio; + return AspectRatio::FromSize(width.GetAnimValue(content), + height.GetAnimValue(content)); } SVGViewElement* viewElement = content->GetCurrentViewElement(); @@ -267,17 +269,7 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio() } if (viewbox) { - float viewBoxWidth = viewbox->width; - float viewBoxHeight = viewbox->height; - - if (viewBoxWidth < 0.0f) { - viewBoxWidth = 0.0f; - } - if (viewBoxHeight < 0.0f) { - viewBoxHeight = 0.0f; - } - return nsSize(nsPresContext::CSSPixelsToAppUnits(viewBoxWidth), - nsPresContext::CSSPixelsToAppUnits(viewBoxHeight)); + return AspectRatio::FromSize(viewbox->width, viewbox->height); } return nsSVGDisplayContainerFrame::GetIntrinsicRatio(); diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h index ee59b7d1c..4705b6ebe 100644 --- a/layout/svg/nsSVGOuterSVGFrame.h +++ b/layout/svg/nsSVGOuterSVGFrame.h @@ -42,7 +42,7 @@ public: virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; - virtual nsSize GetIntrinsicRatio() override; + virtual mozilla::AspectRatio GetIntrinsicRatio() override; virtual mozilla::LogicalSize ComputeSize(nsRenderingContext *aRenderingContext, diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index e88b502ab..aa00c5174 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -402,12 +402,12 @@ nsImageBoxFrame::PaintImage(nsRenderingContext& aRenderingContext, // Determine dest rect based on intrinsic size & ratio, along with // 'object-fit' & 'object-position' properties: IntrinsicSize intrinsicSize; - nsSize intrinsicRatio; + AspectRatio intrinsicRatio; if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) { // Image has a valid size; use it as intrinsic size & ratio. intrinsicSize.width.SetCoordValue(mIntrinsicSize.width); intrinsicSize.height.SetCoordValue(mIntrinsicSize.height); - intrinsicRatio = mIntrinsicSize; + intrinsicRatio = AspectRatio::FromSize(mIntrinsicSize); } else { // Image doesn't have a (valid) intrinsic size. // Try to look up intrinsic ratio and use that at least. |