Issue #2404 - Improvements to CSS aspect-ratio spec compliance
This commit is contained in:
1 parent
d0b61d4a68
commit
8add755c81
24 files changed
+573
-87
No files matched your search
@@ -1487,8 +1487,15 @@ nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttr
|
||||
}
|
||||
|
||||
if (w && h && *w != 0 && *h != 0) {
|
||||
nsCSSValue* aspect_ratio = aData->ValueForAspectRatio();
|
||||
aspect_ratio->SetFloatValue((float(*w) / float(*h)), eCSSUnit_Number);
|
||||
nsCSSValue width;
|
||||
width.SetFloatValue(float(*w), eCSSUnit_Number);
|
||||
nsCSSValue height;
|
||||
height.SetFloatValue(float(*h), eCSSUnit_Number);
|
||||
nsCSSValue ratio;
|
||||
ratio.SetPairValue(width, height);
|
||||
nsCSSValue autoValue;
|
||||
autoValue.SetAutoValue();
|
||||
aData->ValueForAspectRatio()->SetPairValue(autoValue, ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5107,19 +5107,28 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
|
||||
styleMinBSize.GetCoordValue() == 0)) ||
|
||||
styleMaxBSize.GetUnit() != eStyleUnit_None) {
|
||||
|
||||
AspectRatio ratio = aFrame->GetIntrinsicRatio();
|
||||
AspectRatio ratio = aFrame->GetAspectRatio();
|
||||
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);
|
||||
|
||||
const WritingMode wm = aFrame->GetWritingMode();
|
||||
LogicalSize boxSizingAdjust(wm);
|
||||
boxSizingAdjust.ISize(wm) =
|
||||
GetDefiniteSizeTakenByBoxSizing(boxSizing, aFrame, isInlineAxis,
|
||||
aFlags & IGNORE_PADDING,
|
||||
aPercentageBasis);
|
||||
nscoord bSizeTakenByBoxSizing =
|
||||
GetDefiniteSizeTakenByBoxSizing(boxSizing, aFrame, !isInlineAxis,
|
||||
aFlags & IGNORE_PADDING,
|
||||
aPercentageBasis);
|
||||
boxSizingAdjust.BSize(wm) = bSizeTakenByBoxSizing;
|
||||
auto iSizeFromBSize = [&](nscoord aBSize) {
|
||||
LogicalAxis dependentAxis =
|
||||
isInlineAxis ? eLogicalAxisInline : eLogicalAxisBlock;
|
||||
return ratio.ComputeRatioDependentSize(
|
||||
dependentAxis, wm, aBSize, boxSizingAdjust);
|
||||
};
|
||||
// NOTE: This is only the minContentSize if we've been passed MIN_INTRINSIC_ISIZE
|
||||
// (which is fine, because this should only be used inside a check for that flag).
|
||||
nscoord minContentSize = result;
|
||||
@@ -5128,14 +5137,14 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
|
||||
(aPercentageBasis.isNothing() &&
|
||||
GetPercentBSize(styleBSize, aFrame, horizontalAxis, h))) {
|
||||
h = std::max(0, h - bSizeTakenByBoxSizing);
|
||||
result = ratio.ApplyTo(h);
|
||||
result = iSizeFromBSize(h);
|
||||
}
|
||||
|
||||
if (GetDefiniteSize(styleMaxBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
|
||||
(aPercentageBasis.isNothing() &&
|
||||
GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) {
|
||||
h = std::max(0, h - bSizeTakenByBoxSizing);
|
||||
nscoord maxISize = ratio.ApplyTo(h);
|
||||
nscoord maxISize = iSizeFromBSize(h);
|
||||
if (maxISize < result) {
|
||||
result = maxISize;
|
||||
}
|
||||
@@ -5148,7 +5157,7 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
|
||||
(aPercentageBasis.isNothing() &&
|
||||
GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) {
|
||||
h = std::max(0, h - bSizeTakenByBoxSizing);
|
||||
nscoord minISize = ratio.ApplyTo(h);
|
||||
nscoord minISize = iSizeFromBSize(h);
|
||||
if (minISize > result) {
|
||||
result = minISize;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "mozilla/AspectRatio.h"
|
||||
|
||||
#include "mozilla/WritingModes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nscoord
|
||||
AspectRatio::ComputeRatioDependentSize(
|
||||
LogicalAxis aRatioDependentAxis,
|
||||
const WritingMode& aWM,
|
||||
nscoord aRatioDeterminingSize,
|
||||
const LogicalSize& aContentBoxToBoxSizingAdjust) const
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(*this);
|
||||
|
||||
LogicalSize adjust(aWM);
|
||||
if (mUseBoxSizing == UseBoxSizing::Yes) {
|
||||
adjust = aContentBoxToBoxSizingAdjust;
|
||||
}
|
||||
|
||||
AspectRatio logicalRatio = aWM.IsVertical() ? Inverted() : *this;
|
||||
nscoord result;
|
||||
if (aRatioDependentAxis == eLogicalAxisInline) {
|
||||
result = logicalRatio.ApplyTo(aRatioDeterminingSize +
|
||||
adjust.BSize(aWM)) -
|
||||
adjust.ISize(aWM);
|
||||
} else {
|
||||
result = logicalRatio.Inverted().ApplyTo(aRatioDeterminingSize +
|
||||
adjust.ISize(aWM)) -
|
||||
adjust.BSize(aWM);
|
||||
}
|
||||
return std::max(nscoord(0), result);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -10,20 +10,44 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct AspectRatio {
|
||||
AspectRatio() : mRatio(0.0f) {}
|
||||
explicit AspectRatio(float aRatio) : mRatio(std::max(aRatio, 0.0f)) {}
|
||||
class LogicalSize;
|
||||
class WritingMode;
|
||||
|
||||
static AspectRatio FromSize(float aWidth, float aHeight) {
|
||||
enum class UseBoxSizing : uint8_t {
|
||||
// Natural ratios and "auto <ratio>" always use content-box dimensions.
|
||||
No,
|
||||
// A specified <ratio> uses the dimensions selected by box-sizing.
|
||||
Yes,
|
||||
};
|
||||
|
||||
struct AspectRatio {
|
||||
AspectRatio()
|
||||
: mRatio(0.0f)
|
||||
, mUseBoxSizing(UseBoxSizing::No)
|
||||
{}
|
||||
|
||||
explicit AspectRatio(float aRatio,
|
||||
UseBoxSizing aUseBoxSizing = UseBoxSizing::No)
|
||||
: mRatio(std::max(aRatio, 0.0f))
|
||||
, mUseBoxSizing(aUseBoxSizing)
|
||||
{}
|
||||
|
||||
static AspectRatio FromSize(float aWidth, float aHeight,
|
||||
UseBoxSizing aUseBoxSizing = UseBoxSizing::No) {
|
||||
if (aWidth == 0.0f || aHeight == 0.0f) {
|
||||
return AspectRatio();
|
||||
}
|
||||
return AspectRatio(aWidth / aHeight);
|
||||
float ratio = aWidth / aHeight;
|
||||
if (!std::isfinite(ratio)) {
|
||||
return AspectRatio();
|
||||
}
|
||||
return AspectRatio(ratio, aUseBoxSizing);
|
||||
}
|
||||
|
||||
static AspectRatio FromSize(nsSize aSize) {
|
||||
@@ -55,11 +79,23 @@ struct AspectRatio {
|
||||
// 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));
|
||||
std::max(std::numeric_limits<float>::epsilon(), 1.0f / mRatio),
|
||||
mUseBoxSizing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a content-box size in the ratio-dependent axis from a
|
||||
* content-box size in the ratio-determining axis.
|
||||
*/
|
||||
nscoord ComputeRatioDependentSize(
|
||||
LogicalAxis aRatioDependentAxis,
|
||||
const WritingMode& aWM,
|
||||
nscoord aRatioDeterminingSize,
|
||||
const LogicalSize& aContentBoxToBoxSizingAdjust) const;
|
||||
|
||||
bool operator==(const AspectRatio& aOther) const {
|
||||
return mRatio == aOther.mRatio;
|
||||
return mRatio == aOther.mRatio &&
|
||||
mUseBoxSizing == aOther.mUseBoxSizing;
|
||||
}
|
||||
|
||||
bool operator!=(const AspectRatio& aOther) const {
|
||||
@@ -73,6 +109,7 @@ struct AspectRatio {
|
||||
private:
|
||||
// 0.0f represents no aspect ratio.
|
||||
float mRatio;
|
||||
UseBoxSizing mUseBoxSizing;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -124,6 +124,7 @@ EXPORTS.mozilla.layout += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AspectRatio.cpp',
|
||||
'AsyncScrollBase.cpp',
|
||||
'BlockReflowInput.cpp',
|
||||
'CSSAlignUtils.cpp',
|
||||
|
||||
@@ -1945,7 +1945,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
|
||||
: mFrame(aFlexItemReflowInput.mFrame),
|
||||
mFlexGrow(aFlexGrow),
|
||||
mFlexShrink(aFlexShrink),
|
||||
mIntrinsicRatio(mFrame->GetIntrinsicRatio()),
|
||||
mIntrinsicRatio(mFrame->GetAspectRatio()),
|
||||
mBorderPadding(aFlexItemReflowInput.ComputedPhysicalBorderPadding()),
|
||||
mMargin(aFlexItemReflowInput.ComputedPhysicalMargin()),
|
||||
mMainMinSize(aMainMinSize),
|
||||
|
||||
+65
-25
@@ -4655,10 +4655,44 @@ nsFrame::GetIntrinsicSize()
|
||||
/* virtual */ AspectRatio
|
||||
nsFrame::GetIntrinsicRatio()
|
||||
{
|
||||
const nsStylePosition* stylePos = StylePosition();
|
||||
return stylePos->mAspectRatio == 0.0f
|
||||
? AspectRatio()
|
||||
: AspectRatio(stylePos->mAspectRatio);
|
||||
return AspectRatio();
|
||||
}
|
||||
|
||||
AspectRatio
|
||||
nsIFrame::GetAspectRatio()
|
||||
{
|
||||
// The property does not apply to inline boxes or internal ruby/table boxes.
|
||||
nsIAtom* type = GetType();
|
||||
if (type == nsGkAtoms::inlineFrame ||
|
||||
RubyUtils::IsRubyBox(type) ||
|
||||
type == nsGkAtoms::tableCellFrame ||
|
||||
type == nsGkAtoms::tableColFrame ||
|
||||
type == nsGkAtoms::tableColGroupFrame ||
|
||||
type == nsGkAtoms::tableRowFrame ||
|
||||
type == nsGkAtoms::tableRowGroupFrame) {
|
||||
return AspectRatio();
|
||||
}
|
||||
|
||||
const StyleAspectRatio& styleRatio = StylePosition()->mAspectRatio;
|
||||
|
||||
// A non-auto, non-degenerate ratio overrides the natural ratio and uses the
|
||||
// box selected by box-sizing.
|
||||
if (!styleRatio.mAuto && styleRatio.HasUsableRatio()) {
|
||||
return AspectRatio::FromSize(styleRatio.mWidth, styleRatio.mHeight,
|
||||
UseBoxSizing::Yes);
|
||||
}
|
||||
|
||||
if (AspectRatio intrinsicRatio = GetIntrinsicRatio()) {
|
||||
return intrinsicRatio;
|
||||
}
|
||||
|
||||
// The fallback in "auto <ratio>" always operates on the content box.
|
||||
if (styleRatio.HasUsableRatio()) {
|
||||
return AspectRatio::FromSize(styleRatio.mWidth, styleRatio.mHeight,
|
||||
UseBoxSizing::No);
|
||||
}
|
||||
|
||||
return AspectRatio();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4727,11 +4761,11 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
|
||||
const LogicalSize& aPadding,
|
||||
ComputeSizeFlags aFlags)
|
||||
{
|
||||
AspectRatio intrinsicRatio = GetIntrinsicRatio();
|
||||
if (intrinsicRatio) {
|
||||
AspectRatio aspectRatio = GetAspectRatio();
|
||||
if (aspectRatio) {
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
GetIntrinsicSize(),
|
||||
intrinsicRatio,
|
||||
aspectRatio,
|
||||
aCBSize, aMargin,
|
||||
aBorder, aPadding,
|
||||
aFlags);
|
||||
@@ -4976,8 +5010,6 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
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);
|
||||
@@ -5039,6 +5071,14 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
|
||||
boxSizingAdjust = aBorder + aPadding;
|
||||
}
|
||||
auto iSizeFromBSize = [&](nscoord aBSize) {
|
||||
return aIntrinsicRatio.ComputeRatioDependentSize(
|
||||
eLogicalAxisInline, aWM, aBSize, boxSizingAdjust);
|
||||
};
|
||||
auto bSizeFromISize = [&](nscoord aISize) {
|
||||
return aIntrinsicRatio.ComputeRatioDependentSize(
|
||||
eLogicalAxisBlock, aWM, aISize, boxSizingAdjust);
|
||||
};
|
||||
nscoord boxSizingToMarginEdgeISize =
|
||||
aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
|
||||
boxSizingAdjust.ISize(aWM);
|
||||
@@ -5230,9 +5270,9 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
|
||||
if (hasIntrinsicISize) {
|
||||
tentISize = intrinsicISize;
|
||||
} else if (hasIntrinsicBSize && logicalRatio) {
|
||||
tentISize = logicalRatio.ApplyTo(intrinsicBSize);
|
||||
} else if (logicalRatio) {
|
||||
} else if (hasIntrinsicBSize && aIntrinsicRatio) {
|
||||
tentISize = iSizeFromBSize(intrinsicBSize);
|
||||
} else if (aIntrinsicRatio) {
|
||||
tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
|
||||
if (tentISize < 0) tentISize = 0;
|
||||
} else {
|
||||
@@ -5249,8 +5289,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
|
||||
if (hasIntrinsicBSize) {
|
||||
tentBSize = intrinsicBSize;
|
||||
} else if (logicalRatio) {
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(tentISize);
|
||||
} else if (aIntrinsicRatio) {
|
||||
tentBSize = bSizeFromISize(tentISize);
|
||||
} else {
|
||||
tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
|
||||
}
|
||||
@@ -5261,39 +5301,39 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
|
||||
}
|
||||
|
||||
if (logicalRatio) {
|
||||
if (aIntrinsicRatio) {
|
||||
if (stretchI == eStretch) {
|
||||
tentISize = iSize; // * / 'stretch'
|
||||
if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / 'stretch'
|
||||
} else if (stretchB == eStretchPreservingRatio) {
|
||||
// 'normal' / 'stretch'
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
tentBSize = bSizeFromISize(iSize);
|
||||
}
|
||||
} else if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / * (except 'stretch')
|
||||
if (stretchI == eStretchPreservingRatio) {
|
||||
// 'stretch' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
tentISize = iSizeFromBSize(bSize);
|
||||
}
|
||||
} else if (stretchI == eStretchPreservingRatio) {
|
||||
tentISize = iSize; // * (except 'stretch') / 'normal'
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
tentBSize = bSizeFromISize(iSize);
|
||||
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
|
||||
// Stretch within the CB size with preserved intrinsic ratio.
|
||||
tentBSize = bSize; // 'normal' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
tentISize = iSizeFromBSize(bSize);
|
||||
}
|
||||
} else if (stretchB == eStretchPreservingRatio) {
|
||||
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
tentISize = iSizeFromBSize(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 (logicalRatio && stretchI != eStretch && stretchB != eStretch) {
|
||||
if (aIntrinsicRatio && stretchI != eStretch && stretchB != eStretch) {
|
||||
nsSize autoSize = nsLayoutUtils::
|
||||
ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
|
||||
maxISize, maxBSize,
|
||||
@@ -5314,8 +5354,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
// 'auto' iSize, non-'auto' bSize
|
||||
bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
|
||||
if (stretchI != eStretch) {
|
||||
if (logicalRatio) {
|
||||
iSize = logicalRatio.ApplyTo(bSize);
|
||||
if (aIntrinsicRatio) {
|
||||
iSize = iSizeFromBSize(bSize);
|
||||
} else if (hasIntrinsicISize) {
|
||||
if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
|
||||
intrinsicISize > iSize)) {
|
||||
@@ -5334,8 +5374,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
|
||||
// non-'auto' iSize, 'auto' bSize
|
||||
iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
|
||||
if (stretchB != eStretch) {
|
||||
if (logicalRatio) {
|
||||
bSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
if (aIntrinsicRatio) {
|
||||
bSize = bSizeFromISize(iSize);
|
||||
} else if (hasIntrinsicBSize) {
|
||||
if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
|
||||
intrinsicBSize > bSize)) {
|
||||
|
||||
@@ -225,7 +225,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width));
|
||||
intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height));
|
||||
|
||||
AspectRatio intrinsicRatio = GetIntrinsicRatio();
|
||||
AspectRatio intrinsicRatio = GetAspectRatio();
|
||||
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
intrinsicSize, intrinsicRatio,
|
||||
@@ -424,4 +424,3 @@ nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const
|
||||
return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2078,6 +2078,12 @@ public:
|
||||
|
||||
virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0;
|
||||
|
||||
/**
|
||||
* Get the preferred aspect ratio after applying the aspect-ratio property
|
||||
* to this frame's natural ratio.
|
||||
*/
|
||||
mozilla::AspectRatio GetAspectRatio();
|
||||
|
||||
/**
|
||||
* Get the intrinsic ratio of this element, or a default-constructed
|
||||
* AspectRatio if it has no intrinsic ratio.
|
||||
|
||||
@@ -320,7 +320,7 @@ ComputeIntrinsicSize(imgIContainer* aImage,
|
||||
}
|
||||
*/
|
||||
|
||||
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) {
|
||||
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio.HasRatio()) {
|
||||
return IntrinsicSize();
|
||||
}
|
||||
|
||||
@@ -375,8 +375,10 @@ ComputeAspectRatio(imgIContainer* aImage,
|
||||
return fromImage;
|
||||
}
|
||||
}
|
||||
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) {
|
||||
return AspectRatio(aFrame.StylePosition()->mAspectRatio);
|
||||
if (aUseMappedRatio &&
|
||||
aFrame.StylePosition()->mAspectRatio.HasUsableRatio()) {
|
||||
const StyleAspectRatio& ratio = aFrame.StylePosition()->mAspectRatio;
|
||||
return AspectRatio::FromSize(ratio.mWidth, ratio.mHeight);
|
||||
}
|
||||
if (aFrame.ShouldShowBrokenImageIcon()) {
|
||||
return AspectRatio(1.0f);
|
||||
@@ -891,7 +893,7 @@ nsImageFrame::ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
}
|
||||
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
intrinsicSize, mIntrinsicRatio,
|
||||
intrinsicSize, GetAspectRatio(),
|
||||
aCBSize, aMargin, aBorder, aPadding,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
@@ -786,7 +786,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() &&
|
||||
if (f->GetAspectRatio() &&
|
||||
// Some percents are treated like 'auto', so check != coord
|
||||
pos->mHeight.GetUnit() != eStyleUnit_Coord) {
|
||||
const IntrinsicSize &intrinsicSize = f->GetIntrinsicSize();
|
||||
|
||||
@@ -721,7 +721,7 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext* aRenderingContext,
|
||||
if (subDocRoot) {
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
subDocRoot->GetIntrinsicSize(),
|
||||
subDocRoot->GetIntrinsicRatio(),
|
||||
GetAspectRatio(),
|
||||
aCBSize, aMargin, aBorder,
|
||||
aPadding, aFlags);
|
||||
}
|
||||
|
||||
@@ -543,13 +543,8 @@ nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
intrinsicSize.width.SetCoordValue(size.width);
|
||||
intrinsicSize.height.SetCoordValue(size.height);
|
||||
|
||||
// Only video elements have an intrinsic ratio.
|
||||
auto intrinsicRatio = HasVideoElement() ?
|
||||
AspectRatio::FromSize(size) :
|
||||
AspectRatio();
|
||||
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
intrinsicSize, intrinsicRatio,
|
||||
intrinsicSize, GetAspectRatio(),
|
||||
aCBSize, aMargin, aBorder, aPadding,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "nsIFrame.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
using namespace mozilla::gfx;
|
||||
@@ -39,6 +41,35 @@ using nsStyleTransformMatrix::Decompose2DMatrix;
|
||||
using nsStyleTransformMatrix::Decompose3DMatrix;
|
||||
using nsStyleTransformMatrix::ShearType;
|
||||
|
||||
static bool
|
||||
GetAspectRatioAnimationValue(const nsCSSValuePair* aPair,
|
||||
bool& aAuto,
|
||||
float& aRatio)
|
||||
{
|
||||
aAuto = aPair->mXValue.GetUnit() == eCSSUnit_Auto;
|
||||
if (aAuto) {
|
||||
if (aPair->mYValue.GetUnit() != eCSSUnit_Pair) {
|
||||
return false;
|
||||
}
|
||||
aPair = &aPair->mYValue.GetPairValue();
|
||||
}
|
||||
|
||||
if (aPair->mXValue.GetUnit() != eCSSUnit_Number ||
|
||||
aPair->mYValue.GetUnit() != eCSSUnit_Number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float width = aPair->mXValue.GetFloatValue();
|
||||
float height = aPair->mYValue.GetFloatValue();
|
||||
if (width <= 0.0f || height <= 0.0f ||
|
||||
!std::isfinite(width) || !std::isfinite(height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aRatio = width / height;
|
||||
return std::isfinite(aRatio) && aRatio > 0.0f;
|
||||
}
|
||||
|
||||
// HELPER METHODS
|
||||
// --------------
|
||||
/*
|
||||
@@ -1243,6 +1274,21 @@ StyleAnimationValue::ComputeDistance(nsCSSPropertyID aProperty,
|
||||
case eUnit_CSSValuePair: {
|
||||
const nsCSSValuePair *pair1 = aStartValue.GetCSSValuePairValue();
|
||||
const nsCSSValuePair *pair2 = aEndValue.GetCSSValuePairValue();
|
||||
if (aProperty == eCSSProperty_aspect_ratio) {
|
||||
bool auto1;
|
||||
bool auto2;
|
||||
float ratio1;
|
||||
float ratio2;
|
||||
if (!GetAspectRatioAnimationValue(pair1, auto1, ratio1) ||
|
||||
!GetAspectRatioAnimationValue(pair2, auto2, ratio2) ||
|
||||
auto1 != auto2) {
|
||||
return false;
|
||||
}
|
||||
aDistance = Abs(std::log(double(ratio2)) -
|
||||
std::log(double(ratio1)));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCSSUnit unit[2];
|
||||
unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(),
|
||||
pair2->mXValue.GetUnit());
|
||||
@@ -2821,6 +2867,42 @@ StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
|
||||
return true;
|
||||
}
|
||||
case eUnit_CSSValuePair: {
|
||||
if (aProperty == eCSSProperty_aspect_ratio) {
|
||||
bool auto1;
|
||||
bool auto2;
|
||||
float ratio1;
|
||||
float ratio2;
|
||||
if (!GetAspectRatioAnimationValue(aValue1.GetCSSValuePairValue(),
|
||||
auto1, ratio1) ||
|
||||
!GetAspectRatioAnimationValue(aValue2.GetCSSValuePairValue(),
|
||||
auto2, ratio2) ||
|
||||
auto1 != auto2 ||
|
||||
std::abs((aCoeff1 + aCoeff2) - 1.0) > 0.000001) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float resultRatio =
|
||||
std::exp(aCoeff1 * std::log(double(ratio1)) +
|
||||
aCoeff2 * std::log(double(ratio2)));
|
||||
nsCSSValue width;
|
||||
width.SetFloatValue(resultRatio, eCSSUnit_Number);
|
||||
nsCSSValue height;
|
||||
height.SetFloatValue(1.0f, eCSSUnit_Number);
|
||||
nsCSSValue ratio;
|
||||
ratio.SetPairValue(width, height);
|
||||
|
||||
auto result = MakeUnique<nsCSSValuePair>();
|
||||
if (auto1) {
|
||||
result->mXValue.SetAutoValue();
|
||||
result->mYValue = ratio;
|
||||
} else {
|
||||
*result = ratio.GetPairValue();
|
||||
}
|
||||
aResultValue.SetAndAdoptCSSValuePairValue(result.release(),
|
||||
eUnit_CSSValuePair);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty);
|
||||
Maybe<nsCSSValuePair> result =
|
||||
AddCSSValuePair(aProperty, restrictions,
|
||||
@@ -4031,6 +4113,33 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
|
||||
break;
|
||||
}
|
||||
|
||||
case eCSSProperty_aspect_ratio: {
|
||||
const StyleAspectRatio& ratio =
|
||||
static_cast<const nsStylePosition*>(styleStruct)->mAspectRatio;
|
||||
if (!ratio.HasRatio()) {
|
||||
aComputedValue.SetAutoValue();
|
||||
break;
|
||||
}
|
||||
|
||||
nsCSSValue width;
|
||||
width.SetFloatValue(ratio.mWidth, eCSSUnit_Number);
|
||||
nsCSSValue height;
|
||||
height.SetFloatValue(ratio.mHeight, eCSSUnit_Number);
|
||||
nsCSSValue ratioValue;
|
||||
ratioValue.SetPairValue(width, height);
|
||||
|
||||
auto pair = MakeUnique<nsCSSValuePair>();
|
||||
if (ratio.mAuto) {
|
||||
pair->mXValue.SetAutoValue();
|
||||
pair->mYValue = ratioValue;
|
||||
} else {
|
||||
*pair = ratioValue.GetPairValue();
|
||||
}
|
||||
aComputedValue.SetAndAdoptCSSValuePairValue(pair.release(),
|
||||
eUnit_CSSValuePair);
|
||||
break;
|
||||
}
|
||||
|
||||
case eCSSProperty_border_spacing: {
|
||||
const nsStyleTableBorder *styleTableBorder =
|
||||
static_cast<const nsStyleTableBorder*>(styleStruct);
|
||||
|
||||
@@ -13419,23 +13419,26 @@ bool
|
||||
CSSParserImpl::ParseAspectRatioRatio(nsCSSValue& aValue)
|
||||
{
|
||||
nsCSSValue width;
|
||||
if (!ParseNonNegativeNumber(width)) {
|
||||
if (!ParseSingleTokenNonNegativeVariant(width,
|
||||
VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float w = width.GetFloatValue();
|
||||
float h = 1.0f;
|
||||
nsCSSValue height;
|
||||
height.SetFloatValue(1.0f, eCSSUnit_Number);
|
||||
if (ExpectSymbol('/', true)) {
|
||||
nsCSSValue height;
|
||||
if (!ParseNonNegativeNumber(height)) {
|
||||
if (!ParseSingleTokenNonNegativeVariant(height,
|
||||
VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
h = height.GetFloatValue();
|
||||
}
|
||||
|
||||
// Degenerate ratios behave as auto in layout.
|
||||
aValue.SetFloatValue(w == 0.0f || h == 0.0f ? 0.0f : w / h,
|
||||
eCSSUnit_Number);
|
||||
// Keep both components: the computed value is a pair of numbers, and
|
||||
// degenerate ratios still serialize as ratios even though they behave as
|
||||
// auto during layout.
|
||||
aValue.SetPairValue(width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -13458,9 +13461,15 @@ CSSParserImpl::ParseAspectRatio(nsCSSValue& aValue)
|
||||
if (hasRatio) {
|
||||
if (!hasAuto) {
|
||||
// The grammar is "auto || <ratio>", so auto may appear after the ratio.
|
||||
ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
|
||||
hasAuto = ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
|
||||
}
|
||||
if (hasAuto) {
|
||||
nsCSSValue combined;
|
||||
combined.SetPairValue(autoValue, ratioValue);
|
||||
aValue = combined;
|
||||
} else {
|
||||
aValue = ratioValue;
|
||||
}
|
||||
aValue = ratioValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -479,8 +479,8 @@ CSS_PROP_POSITION(
|
||||
"",
|
||||
0,
|
||||
nullptr,
|
||||
offsetof(nsStylePosition, mAspectRatio),
|
||||
eStyleAnimType_None)
|
||||
CSS_PROP_NO_OFFSET,
|
||||
eStyleAnimType_Custom)
|
||||
CSS_PROP_DISPLAY(
|
||||
backface-visibility,
|
||||
backface_visibility,
|
||||
|
||||
@@ -2972,6 +2972,20 @@ nsCSSValuePair::AppendToString(nsCSSPropertyID aProperty,
|
||||
nsAString& aResult,
|
||||
nsCSSValue::Serialization aSerialization) const
|
||||
{
|
||||
if (aProperty == eCSSProperty_aspect_ratio) {
|
||||
if (mXValue.GetUnit() == eCSSUnit_Auto) {
|
||||
mXValue.AppendToString(aProperty, aResult, aSerialization);
|
||||
aResult.Append(char16_t(' '));
|
||||
mYValue.AppendToString(aProperty, aResult, aSerialization);
|
||||
return;
|
||||
}
|
||||
|
||||
mXValue.AppendToString(aProperty, aResult, aSerialization);
|
||||
aResult.AppendLiteral(" / ");
|
||||
mYValue.AppendToString(aProperty, aResult, aSerialization);
|
||||
return;
|
||||
}
|
||||
|
||||
mXValue.AppendToString(aProperty, aResult, aSerialization);
|
||||
if (mYValue.GetUnit() != eCSSUnit_Null) {
|
||||
aResult.Append(char16_t(' '));
|
||||
|
||||
@@ -968,13 +968,17 @@ already_AddRefed<CSSValue>
|
||||
nsComputedDOMStyle::DoGetAspectRatio()
|
||||
{
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
float ratio = StylePosition()->mAspectRatio;
|
||||
if (ratio == 0.0f) {
|
||||
const StyleAspectRatio& ratio = StylePosition()->mAspectRatio;
|
||||
if (!ratio.HasRatio()) {
|
||||
val->SetIdent(eCSSKeyword_auto);
|
||||
} else {
|
||||
nsAutoString ratioString;
|
||||
nsStyleUtil::AppendCSSNumber(ratio, ratioString);
|
||||
ratioString.AppendLiteral(" / 1");
|
||||
if (ratio.mAuto) {
|
||||
ratioString.AppendLiteral("auto ");
|
||||
}
|
||||
nsStyleUtil::AppendCSSNumber(ratio.mWidth, ratioString);
|
||||
ratioString.AppendLiteral(" / ");
|
||||
nsStyleUtil::AppendCSSNumber(ratio.mHeight, ratioString);
|
||||
val->SetString(ratioString);
|
||||
}
|
||||
return val.forget();
|
||||
|
||||
@@ -9607,15 +9607,54 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
|
||||
SETCOORD_UNSET_INITIAL,
|
||||
aContext, mPresContext, conditions);
|
||||
|
||||
// aspect-ratio: auto | <ratio>
|
||||
// aspect-ratio: auto || <ratio>
|
||||
const nsCSSValue* aspectRatio = aRuleData->ValueForAspectRatio();
|
||||
if (aspectRatio->GetUnit() == eCSSUnit_Auto) {
|
||||
pos->mAspectRatio = 0.0f;
|
||||
} else {
|
||||
SetFactor(*aspectRatio,
|
||||
pos->mAspectRatio, conditions,
|
||||
parentPos->mAspectRatio, 0.0f,
|
||||
SETFCT_UNSET_INITIAL | SETFCT_POSITIVE | SETFCT_NONE);
|
||||
switch (aspectRatio->GetUnit()) {
|
||||
case eCSSUnit_Null:
|
||||
break;
|
||||
|
||||
case eCSSUnit_Inherit:
|
||||
conditions.SetUncacheable();
|
||||
pos->mAspectRatio = parentPos->mAspectRatio;
|
||||
break;
|
||||
|
||||
case eCSSUnit_Auto:
|
||||
case eCSSUnit_Initial:
|
||||
case eCSSUnit_Unset:
|
||||
case eCSSUnit_Revert:
|
||||
case eCSSUnit_RevertLayer:
|
||||
pos->mAspectRatio = StyleAspectRatio();
|
||||
break;
|
||||
|
||||
case eCSSUnit_Number:
|
||||
// Animation normalizes a ratio to <number> / 1 when both components
|
||||
// would otherwise compare equal and the pair is collapsed.
|
||||
pos->mAspectRatio =
|
||||
StyleAspectRatio(aspectRatio->GetFloatValue(), 1.0f, false);
|
||||
break;
|
||||
|
||||
case eCSSUnit_Pair: {
|
||||
const nsCSSValuePair* ratio = &aspectRatio->GetPairValue();
|
||||
bool hasAuto = ratio->mXValue.GetUnit() == eCSSUnit_Auto;
|
||||
if (hasAuto) {
|
||||
MOZ_ASSERT(ratio->mYValue.GetUnit() == eCSSUnit_Pair,
|
||||
"auto must be followed by a ratio");
|
||||
ratio = &ratio->mYValue.GetPairValue();
|
||||
}
|
||||
|
||||
float width = 0.0f;
|
||||
float height = 0.0f;
|
||||
SetFactor(ratio->mXValue, width, conditions, 0.0f, 0.0f,
|
||||
SETFCT_POSITIVE);
|
||||
SetFactor(ratio->mYValue, height, conditions, 0.0f, 0.0f,
|
||||
SETFCT_POSITIVE);
|
||||
pos->mAspectRatio = StyleAspectRatio(width, height, hasAuto);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected aspect-ratio unit");
|
||||
break;
|
||||
}
|
||||
|
||||
// box-sizing: enum, inherit, initial
|
||||
|
||||
@@ -1372,7 +1372,7 @@ nsStylePosition::nsStylePosition(nsPresContext* aContext)
|
||||
, mGridAutoColumnsMax(eStyleUnit_Auto)
|
||||
, mGridAutoRowsMin(eStyleUnit_Auto)
|
||||
, mGridAutoRowsMax(eStyleUnit_Auto)
|
||||
, mAspectRatio(0.0f)
|
||||
, mAspectRatio()
|
||||
, mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW)
|
||||
, mBoxSizing(StyleBoxSizing::Content)
|
||||
, mAlignContent(NS_STYLE_ALIGN_NORMAL)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "imgRequestProxy.h"
|
||||
#include "Orientation.h"
|
||||
#include "CounterStyleManager.h"
|
||||
#include <cmath>
|
||||
#include <cstddef> // offsetof()
|
||||
#include <utility>
|
||||
#include "X11UndefineNone.h"
|
||||
@@ -1679,6 +1680,52 @@ struct nsStyleGridTemplate
|
||||
}
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct StyleAspectRatio {
|
||||
StyleAspectRatio()
|
||||
: mWidth(0.0f)
|
||||
, mHeight(1.0f)
|
||||
, mAuto(true)
|
||||
, mHasRatio(false)
|
||||
{}
|
||||
|
||||
StyleAspectRatio(float aWidth, float aHeight, bool aAuto)
|
||||
: mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mAuto(aAuto)
|
||||
, mHasRatio(true)
|
||||
{}
|
||||
|
||||
bool HasRatio() const { return mHasRatio; }
|
||||
|
||||
bool HasUsableRatio() const {
|
||||
return mHasRatio &&
|
||||
mWidth != 0.0f &&
|
||||
mHeight != 0.0f &&
|
||||
std::isfinite(mWidth) &&
|
||||
std::isfinite(mHeight);
|
||||
}
|
||||
|
||||
bool operator==(const StyleAspectRatio& aOther) const {
|
||||
return mWidth == aOther.mWidth &&
|
||||
mHeight == aOther.mHeight &&
|
||||
mAuto == aOther.mAuto &&
|
||||
mHasRatio == aOther.mHasRatio;
|
||||
}
|
||||
|
||||
bool operator!=(const StyleAspectRatio& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
float mWidth;
|
||||
float mHeight;
|
||||
bool mAuto;
|
||||
bool mHasRatio;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition
|
||||
{
|
||||
explicit nsStylePosition(nsPresContext* aContext);
|
||||
@@ -1743,7 +1790,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
|
||||
mozilla::StyleAspectRatio mAspectRatio; // [reset]
|
||||
uint8_t mGridAutoFlow; // [reset] enumerated. See nsStyleConsts.h
|
||||
mozilla::StyleBoxSizing mBoxSizing; // [reset] see nsStyleConsts.h
|
||||
|
||||
|
||||
@@ -1172,8 +1172,30 @@ var gCSSProperties = {
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: ["auto"],
|
||||
other_values: ["1", "2"],
|
||||
invalid_values: ["none", "-1", "1px", "1 / -1", "1 /", "auto auto"],
|
||||
other_values: [
|
||||
"1",
|
||||
"2",
|
||||
"3 / 2",
|
||||
"0",
|
||||
"0 / 1",
|
||||
"1 / 0",
|
||||
"auto 16 / 9",
|
||||
"16 / 9 auto",
|
||||
"calc(1 + 1)",
|
||||
"calc(6) / calc(4)",
|
||||
],
|
||||
invalid_values: [
|
||||
"none",
|
||||
"-1",
|
||||
"1px",
|
||||
"1 / -1",
|
||||
"1 /",
|
||||
"auto auto",
|
||||
"1 1",
|
||||
"1 / 1 / 1",
|
||||
"auto 1 auto",
|
||||
"infinity",
|
||||
],
|
||||
},
|
||||
"-moz-border-bottom-colors": {
|
||||
domProp: "MozBorderBottomColors",
|
||||
|
||||
@@ -4,29 +4,76 @@
|
||||
<title>Test CSS aspect-ratio property</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<style>
|
||||
@keyframes aspect-ratio-interpolation {
|
||||
from { aspect-ratio: 1; }
|
||||
to { aspect-ratio: 4; }
|
||||
}
|
||||
#animated-ratio {
|
||||
animation: aspect-ratio-interpolation 100s linear -50s paused;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="position:absolute; left:0; top:0; width:120px;">
|
||||
<div id="ratio" style="width:120px; aspect-ratio:3 / 2;"></div>
|
||||
<div id="bare-ratio" style="width:120px; aspect-ratio:2;"></div>
|
||||
<div id="wrapper" style="position:relative; width:120px; aspect-ratio:1 / 1;">
|
||||
<div style="position:absolute; inset:0;"></div>
|
||||
</div>
|
||||
<div id="zero-ratio" style="width:120px; aspect-ratio:0;"></div>
|
||||
<div id="border-box-ratio"
|
||||
style="box-sizing:border-box; width:120px; padding:10px;
|
||||
border:10px solid; aspect-ratio:2;"></div>
|
||||
<div id="content-box-ratio"
|
||||
style="box-sizing:content-box; width:120px; padding:10px;
|
||||
border:10px solid; aspect-ratio:2;"></div>
|
||||
<div id="auto-border-box-ratio"
|
||||
style="box-sizing:border-box; width:120px; padding:10px;
|
||||
border:10px solid; aspect-ratio:auto 2;"></div>
|
||||
<div id="animated-ratio" style="width:120px;"></div>
|
||||
<img id="override-natural-ratio"
|
||||
style="display:block; width:120px; height:auto; aspect-ratio:1;"
|
||||
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='20'%3E%3C/svg%3E">
|
||||
<img id="use-natural-ratio"
|
||||
style="display:block; width:120px; height:auto; aspect-ratio:auto 1;"
|
||||
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='20'%3E%3C/svg%3E">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
ok(CSS.supports("aspect-ratio", "1 / 1"),
|
||||
"aspect-ratio accepts ratio syntax");
|
||||
ok(CSS.supports("aspect-ratio", "2"),
|
||||
"aspect-ratio accepts a ratio with an omitted denominator");
|
||||
ok(CSS.supports("aspect-ratio", "auto"),
|
||||
"aspect-ratio accepts auto");
|
||||
ok(CSS.supports("aspect-ratio", "auto 16 / 9"),
|
||||
"aspect-ratio accepts auto plus ratio");
|
||||
ok(CSS.supports("aspect-ratio", "16 / 9 auto"),
|
||||
"aspect-ratio accepts ratio plus auto");
|
||||
ok(CSS.supports("aspect-ratio", "calc(1 + 1)"),
|
||||
"aspect-ratio accepts math functions as numbers");
|
||||
ok(CSS.supports("aspect-ratio", "0 / 1"),
|
||||
"aspect-ratio accepts degenerate ratios");
|
||||
ok(!CSS.supports("aspect-ratio", "1px"),
|
||||
"aspect-ratio rejects lengths");
|
||||
ok(!CSS.supports("aspect-ratio", "-1"),
|
||||
"aspect-ratio rejects negative numbers");
|
||||
ok(!CSS.supports("aspect-ratio", "auto auto"),
|
||||
"aspect-ratio rejects duplicate auto keywords");
|
||||
|
||||
var ratio = document.getElementById("ratio");
|
||||
is(ratio.getBoundingClientRect().height, 80,
|
||||
"aspect-ratio computes an automatic block size from inline size");
|
||||
is(getComputedStyle(ratio).aspectRatio, "3 / 2",
|
||||
"computed aspect-ratio preserves both ratio components");
|
||||
|
||||
var bareRatio = document.getElementById("bare-ratio");
|
||||
is(bareRatio.getBoundingClientRect().height, 60,
|
||||
"a bare number computes an automatic block size");
|
||||
is(getComputedStyle(bareRatio).aspectRatio, "2 / 1",
|
||||
"a ratio with an omitted denominator serializes with denominator 1");
|
||||
|
||||
var wrapper = document.getElementById("wrapper");
|
||||
is(wrapper.getBoundingClientRect().height, 120,
|
||||
@@ -35,6 +82,66 @@ is(wrapper.getBoundingClientRect().height, 120,
|
||||
is(getComputedStyle(wrapper).aspectRatio, "1 / 1",
|
||||
"computed aspect-ratio exposes a ratio value");
|
||||
|
||||
var zeroRatio = document.getElementById("zero-ratio");
|
||||
is(zeroRatio.getBoundingClientRect().height, 0,
|
||||
"a degenerate ratio behaves as auto during layout");
|
||||
is(getComputedStyle(zeroRatio).aspectRatio, "0 / 1",
|
||||
"a degenerate ratio remains a ratio in the computed value");
|
||||
|
||||
is(document.getElementById("border-box-ratio").getBoundingClientRect().height,
|
||||
60, "a specified ratio honors border-box sizing");
|
||||
is(document.getElementById("content-box-ratio").getBoundingClientRect().height,
|
||||
100, "a specified ratio honors content-box sizing");
|
||||
is(document.getElementById("auto-border-box-ratio")
|
||||
.getBoundingClientRect().height,
|
||||
80, "the fallback in auto plus ratio always uses the content box");
|
||||
|
||||
var animatedRatio = document.getElementById("animated-ratio");
|
||||
is(animatedRatio.getBoundingClientRect().height, 60,
|
||||
"aspect-ratio interpolation is logarithmic");
|
||||
is(getComputedStyle(animatedRatio).aspectRatio, "2 / 1",
|
||||
"an interpolated ratio is exposed as a pair of numbers");
|
||||
|
||||
var declaration = document.createElement("div").style;
|
||||
declaration.aspectRatio = "3 / 2 auto";
|
||||
is(declaration.aspectRatio, "auto 3 / 2",
|
||||
"specified aspect-ratio serializes in canonical order");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var images = [
|
||||
document.getElementById("override-natural-ratio"),
|
||||
document.getElementById("use-natural-ratio"),
|
||||
];
|
||||
var pendingImages = images.length;
|
||||
|
||||
function checkReplacedElements() {
|
||||
is(images[0].getBoundingClientRect().height, 120,
|
||||
"a ratio without auto overrides a replaced element's natural ratio");
|
||||
is(images[1].getBoundingClientRect().height, 60,
|
||||
"auto plus ratio uses a replaced element's natural ratio");
|
||||
is(getComputedStyle(images[1]).aspectRatio, "auto 1 / 1",
|
||||
"computed style preserves auto plus ratio");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function imageReady() {
|
||||
if (--pendingImages == 0) {
|
||||
checkReplacedElements();
|
||||
}
|
||||
}
|
||||
|
||||
images.forEach(function(image) {
|
||||
if (image.complete) {
|
||||
imageReady();
|
||||
} else {
|
||||
image.addEventListener("load", imageReady);
|
||||
image.addEventListener("error", function() {
|
||||
ok(false, "test image should load");
|
||||
imageReady();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
@@ -344,7 +344,7 @@ nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
}
|
||||
|
||||
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
|
||||
intrinsicSize, GetIntrinsicRatio(),
|
||||
intrinsicSize, GetAspectRatio(),
|
||||
cbSize, aMargin, aBorder, aPadding,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user