summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
Diffstat (limited to 'layout')
-rw-r--r--layout/base/nsCSSRendering.cpp88
-rw-r--r--layout/base/nsCSSRendering.h22
-rw-r--r--layout/base/nsLayoutUtils.cpp64
-rw-r--r--layout/base/nsLayoutUtils.h6
-rw-r--r--layout/generic/AspectRatio.h81
-rw-r--r--layout/generic/crashtests/1633434.html15
-rw-r--r--layout/generic/crashtests/crashtests.list1
-rw-r--r--layout/generic/moz.build1
-rw-r--r--layout/generic/nsFlexContainerFrame.cpp31
-rw-r--r--layout/generic/nsFrame.cpp57
-rw-r--r--layout/generic/nsFrame.h4
-rw-r--r--layout/generic/nsHTMLCanvasFrame.cpp31
-rw-r--r--layout/generic/nsHTMLCanvasFrame.h2
-rw-r--r--layout/generic/nsIFrame.h14
-rw-r--r--layout/generic/nsImageFrame.cpp265
-rw-r--r--layout/generic/nsImageFrame.h24
-rw-r--r--layout/generic/nsLineLayout.cpp2
-rw-r--r--layout/generic/nsSubDocumentFrame.cpp4
-rw-r--r--layout/generic/nsSubDocumentFrame.h2
-rw-r--r--layout/generic/nsVideoFrame.cpp18
-rw-r--r--layout/generic/nsVideoFrame.h2
-rw-r--r--layout/style/Loader.cpp28
-rw-r--r--layout/style/Loader.h13
-rw-r--r--layout/style/nsCSSPropAliasList.h5
-rw-r--r--layout/style/nsCSSPropList.h13
-rw-r--r--layout/style/nsRuleNode.cpp6
-rw-r--r--layout/style/nsStyleStruct.cpp11
-rw-r--r--layout/style/nsStyleStruct.h1
-rw-r--r--layout/style/test/ListCSSProperties.cpp1
-rw-r--r--layout/svg/nsSVGOuterSVGFrame.cpp38
-rw-r--r--layout/svg/nsSVGOuterSVGFrame.h2
-rw-r--r--layout/xul/nsImageBoxFrame.cpp4
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.