зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1705877 - image-set() should influence intrinsic size of the image. r=dholbert,layout-reviewers
https://drafts.csswg.org/css-images-4/#image-set-notation has: > [...] it also specifies the image’s natural resolution, overriding any other > source of data that might supply a natural resolution. Astounding that there was literally no WPT for this at all. I added three: one for backgrounds, one for list-style-image, and one for `content`. Cursor is not handled on this patch because that one requires a fair amount of extra work. Differential Revision: https://phabricator.services.mozilla.com/D112474
This commit is contained in:
Родитель
ca0d2c502e
Коммит
8e47e5abc2
|
@ -6322,13 +6322,13 @@ ImgDrawResult nsLayoutUtils::DrawSingleUnscaledImage(
|
|||
/* static */
|
||||
ImgDrawResult nsLayoutUtils::DrawSingleImage(
|
||||
gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
|
||||
const SamplingFilter aSamplingFilter, const nsRect& aDest,
|
||||
float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest,
|
||||
const nsRect& aDirty, const Maybe<SVGImageContext>& aSVGContext,
|
||||
uint32_t aImageFlags, const nsPoint* aAnchorPoint,
|
||||
const nsRect* aSourceArea) {
|
||||
nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
|
||||
CSSIntSize pixelImageSize(
|
||||
ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
|
||||
ComputeSizeForDrawingWithFallback(aImage, aResolution, aDest.Size()));
|
||||
if (pixelImageSize.width < 1 || pixelImageSize.height < 1) {
|
||||
NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0,
|
||||
"Image width or height is negative");
|
||||
|
@ -6369,7 +6369,8 @@ ImgDrawResult nsLayoutUtils::DrawSingleImage(
|
|||
|
||||
/* static */
|
||||
void nsLayoutUtils::ComputeSizeForDrawing(
|
||||
imgIContainer* aImage, /* outparam */ CSSIntSize& aImageSize,
|
||||
imgIContainer* aImage, float aResolution,
|
||||
/* outparam */ CSSIntSize& aImageSize,
|
||||
/* outparam */ AspectRatio& aIntrinsicRatio,
|
||||
/* outparam */ bool& aGotWidth,
|
||||
/* outparam */ bool& aGotHeight) {
|
||||
|
@ -6378,6 +6379,15 @@ void nsLayoutUtils::ComputeSizeForDrawing(
|
|||
Maybe<AspectRatio> intrinsicRatio = aImage->GetIntrinsicRatio();
|
||||
aIntrinsicRatio = intrinsicRatio.valueOr(AspectRatio());
|
||||
|
||||
if (aResolution != 0.0f && aResolution != 1.0f) {
|
||||
if (aGotWidth) {
|
||||
aImageSize.width = std::round(float(aImageSize.width) / aResolution);
|
||||
}
|
||||
if (aGotHeight) {
|
||||
aImageSize.height = std::round(float(aImageSize.height) / aResolution);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aGotWidth && aGotHeight) && intrinsicRatio.isNothing()) {
|
||||
// We hit an error (say, because the image failed to load or couldn't be
|
||||
// decoded) and should return zero size.
|
||||
|
@ -6388,11 +6398,12 @@ void nsLayoutUtils::ComputeSizeForDrawing(
|
|||
|
||||
/* static */
|
||||
CSSIntSize nsLayoutUtils::ComputeSizeForDrawingWithFallback(
|
||||
imgIContainer* aImage, const nsSize& aFallbackSize) {
|
||||
imgIContainer* aImage, float aResolution, const nsSize& aFallbackSize) {
|
||||
CSSIntSize imageSize;
|
||||
AspectRatio imageRatio;
|
||||
bool gotHeight, gotWidth;
|
||||
ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight);
|
||||
ComputeSizeForDrawing(aImage, aResolution, imageSize, imageRatio, gotWidth,
|
||||
gotHeight);
|
||||
|
||||
// If we didn't get both width and height, try to compute them using the
|
||||
// intrinsic ratio of the image.
|
||||
|
|
|
@ -1901,6 +1901,11 @@ class nsLayoutUtils {
|
|||
* appropriate scale and transform for drawing in
|
||||
* app units.
|
||||
* @param aImage The image.
|
||||
* @param aResolution The resolution specified by the author for the
|
||||
* image, in dppx. This will affect the intrinsic
|
||||
* size of the image (so e.g., if resolution is 2,
|
||||
* and the image is 100x100, the intrinsic size of
|
||||
* the image will be 50x50).
|
||||
* @param aDest The area that the image should fill.
|
||||
* @param aDirty Pixels outside this area may be skipped.
|
||||
* @param aSVGContext Optionally provides an SVGImageContext.
|
||||
|
@ -1922,7 +1927,7 @@ class nsLayoutUtils {
|
|||
*/
|
||||
static ImgDrawResult DrawSingleImage(
|
||||
gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
|
||||
const SamplingFilter aSamplingFilter, const nsRect& aDest,
|
||||
float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest,
|
||||
const nsRect& aDirty, const mozilla::Maybe<SVGImageContext>& aSVGContext,
|
||||
uint32_t aImageFlags, const nsPoint* aAnchorPoint = nullptr,
|
||||
const nsRect* aSourceArea = nullptr);
|
||||
|
@ -1943,7 +1948,7 @@ class nsLayoutUtils {
|
|||
* difference is that this one is simpler and is suited to places where we
|
||||
* have less information about the frame tree.
|
||||
*/
|
||||
static void ComputeSizeForDrawing(imgIContainer* aImage,
|
||||
static void ComputeSizeForDrawing(imgIContainer* aImage, float aResolution,
|
||||
CSSIntSize& aImageSize,
|
||||
AspectRatio& aIntrinsicRatio,
|
||||
bool& aGotWidth, bool& aGotHeight);
|
||||
|
@ -1957,7 +1962,7 @@ class nsLayoutUtils {
|
|||
* dimensions, the corresponding dimension of aFallbackSize is used instead.
|
||||
*/
|
||||
static CSSIntSize ComputeSizeForDrawingWithFallback(
|
||||
imgIContainer* aImage, const nsSize& aFallbackSize);
|
||||
imgIContainer* aImage, float aResolution, const nsSize& aFallbackSize);
|
||||
|
||||
/**
|
||||
* Given the image container, frame, and dest rect, determine the best fitting
|
||||
|
|
|
@ -781,12 +781,9 @@ void nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
|
|||
|
||||
RemoveStateBits(BULLET_FRAME_IMAGE_LOADING);
|
||||
|
||||
if (RefPtr<imgIContainer> image = GetImage()) {
|
||||
int32_t w = 0;
|
||||
int32_t h = 0;
|
||||
image->GetWidth(&w);
|
||||
image->GetHeight(&h);
|
||||
LogicalSize size(GetWritingMode(), CSSPixel::ToAppUnits(CSSIntSize(w, h)));
|
||||
if (Maybe<CSSIntSize> intrinsicSize =
|
||||
StyleList()->mListStyleImage.GetIntrinsicSize()) {
|
||||
LogicalSize size(GetWritingMode(), CSSPixel::ToAppUnits(*intrinsicSize));
|
||||
// auto size the image
|
||||
finalSize.ISize(wm) = size.ISize(wm);
|
||||
finalSize.BSize(wm) = size.BSize(wm);
|
||||
|
|
|
@ -398,11 +398,13 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
}
|
||||
MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
|
||||
MOZ_RELEASE_ASSERT(styleContent->ContentAt(contentIndex).IsImage());
|
||||
auto& imageUrl = styleContent->ContentAt(contentIndex).AsImage();
|
||||
MOZ_ASSERT(imageUrl.IsImageRequestType(),
|
||||
const StyleImage& image = styleContent->ContentAt(contentIndex).AsImage();
|
||||
MOZ_ASSERT(image.IsImageRequestType(),
|
||||
"Content image should only parse url() type");
|
||||
auto [finalImage, resolution] = image.FinalImageAndResolution();
|
||||
Document* doc = PresContext()->Document();
|
||||
if (imgRequestProxy* proxy = imageUrl.GetImageRequest()) {
|
||||
if (imgRequestProxy* proxy = finalImage->GetImageRequest()) {
|
||||
mContentURLRequestResolution = resolution;
|
||||
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
|
||||
SetupForContentURLRequest();
|
||||
}
|
||||
|
@ -454,6 +456,20 @@ void nsImageFrame::SetupForContentURLRequest() {
|
|||
}
|
||||
}
|
||||
|
||||
static void ScaleIntrinsicSizeForDensity(IntrinsicSize& aSize,
|
||||
double aDensity) {
|
||||
if (aDensity == 1.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSize.width) {
|
||||
aSize.width = Some(NSToCoordRound(double(*aSize.width) / aDensity));
|
||||
}
|
||||
if (aSize.height) {
|
||||
aSize.height = Some(NSToCoordRound(double(*aSize.height) / aDensity));
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleIntrinsicSizeForDensity(nsIContent& aContent,
|
||||
IntrinsicSize& aSize) {
|
||||
auto* image = HTMLImageElement::FromNode(aContent);
|
||||
|
@ -468,16 +484,7 @@ static void ScaleIntrinsicSizeForDensity(nsIContent& aContent,
|
|||
|
||||
double density = selector->GetSelectedImageDensity();
|
||||
MOZ_ASSERT(density >= 0.0);
|
||||
if (density == 1.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSize.width) {
|
||||
aSize.width = Some(NSToCoordRound(double(*aSize.width) / density));
|
||||
}
|
||||
if (aSize.height) {
|
||||
aSize.height = Some(NSToCoordRound(double(*aSize.height) / density));
|
||||
}
|
||||
ScaleIntrinsicSizeForDensity(aSize, density);
|
||||
}
|
||||
|
||||
static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
|
||||
|
@ -496,6 +503,9 @@ static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
|
|||
intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height);
|
||||
if (aKind == nsImageFrame::Kind::ImageElement) {
|
||||
ScaleIntrinsicSizeForDensity(*aFrame.GetContent(), intrinsicSize);
|
||||
} else {
|
||||
ScaleIntrinsicSizeForDensity(intrinsicSize,
|
||||
aFrame.GetContentURLRequestResolution());
|
||||
}
|
||||
return intrinsicSize;
|
||||
}
|
||||
|
@ -1476,7 +1486,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
|
|||
nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
|
||||
size);
|
||||
result = nsLayoutUtils::DrawSingleImage(
|
||||
aRenderingContext, PresContext(), imgCon,
|
||||
aRenderingContext, PresContext(), imgCon, /* aResolution = */ 1.0f,
|
||||
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
|
||||
/* no SVGImageContext */ Nothing(), aFlags);
|
||||
}
|
||||
|
@ -2080,8 +2090,10 @@ ImgDrawResult nsImageFrame::PaintImage(gfxContext& aRenderingContext,
|
|||
Maybe<SVGImageContext> svgContext;
|
||||
SVGImageContext::MaybeStoreContextPaint(svgContext, this, aImage);
|
||||
|
||||
// We've already accounted for resolution via mIntrinsicSize, which influences
|
||||
// the dest rect, so we don't need to worry about it here..
|
||||
ImgDrawResult result = nsLayoutUtils::DrawSingleImage(
|
||||
aRenderingContext, PresContext(), aImage,
|
||||
aRenderingContext, PresContext(), aImage, /* aResolution = */ 1.0f,
|
||||
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
|
||||
svgContext, flags, &anchorPoint);
|
||||
|
||||
|
|
|
@ -103,6 +103,12 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
|||
void SetupForContentURLRequest();
|
||||
bool ShouldShowBrokenImageIcon() const;
|
||||
|
||||
// Get the resolution, in dppx, for the image that mContentURLRequest
|
||||
// represents.
|
||||
float GetContentURLRequestResolution() const {
|
||||
return mContentURLRequestResolution;
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
@ -353,6 +359,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
|||
|
||||
// An image request created for content: url(..).
|
||||
RefPtr<imgRequestProxy> mContentURLRequest;
|
||||
float mContentURLRequestResolution = 1.0f;
|
||||
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
nsCOMPtr<imgIContainer> mPrevImage;
|
||||
|
|
|
@ -50,8 +50,6 @@ nsSize CSSSizeOrRatio::ComputeConcreteSize() const {
|
|||
nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage,
|
||||
uint32_t aFlags)
|
||||
: mForFrame(aForFrame),
|
||||
mImage(&aImage->FinalImage()),
|
||||
mType(mImage->tag),
|
||||
mImageContainer(nullptr),
|
||||
mGradientData(nullptr),
|
||||
mPaintServerFrame(nullptr),
|
||||
|
@ -59,7 +57,12 @@ nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage,
|
|||
mSize(0, 0),
|
||||
mFlags(aFlags),
|
||||
mExtendMode(ExtendMode::CLAMP),
|
||||
mMaskOp(StyleMaskMode::MatchSource) {}
|
||||
mMaskOp(StyleMaskMode::MatchSource) {
|
||||
auto pair = aImage->FinalImageAndResolution();
|
||||
mImage = pair.first;
|
||||
mType = mImage->tag;
|
||||
mImageResolution = pair.second;
|
||||
}
|
||||
|
||||
bool nsImageRenderer::PrepareImage() {
|
||||
if (mImage->IsNone()) {
|
||||
|
@ -198,14 +201,14 @@ CSSSizeOrRatio nsImageRenderer::ComputeIntrinsicSize() {
|
|||
case StyleImage::Tag::Url: {
|
||||
bool haveWidth, haveHeight;
|
||||
CSSIntSize imageIntSize;
|
||||
nsLayoutUtils::ComputeSizeForDrawing(
|
||||
mImageContainer, imageIntSize, result.mRatio, haveWidth, haveHeight);
|
||||
nsLayoutUtils::ComputeSizeForDrawing(mImageContainer, mImageResolution,
|
||||
imageIntSize, result.mRatio,
|
||||
haveWidth, haveHeight);
|
||||
if (haveWidth) {
|
||||
result.SetWidth(nsPresContext::CSSPixelsToAppUnits(imageIntSize.width));
|
||||
result.SetWidth(CSSPixel::ToAppUnits(imageIntSize.width));
|
||||
}
|
||||
if (haveHeight) {
|
||||
result.SetHeight(
|
||||
nsPresContext::CSSPixelsToAppUnits(imageIntSize.height));
|
||||
result.SetHeight(CSSPixel::ToAppUnits(imageIntSize.height));
|
||||
}
|
||||
|
||||
// If we know the aspect ratio and one of the dimensions,
|
||||
|
@ -937,8 +940,8 @@ ImgDrawResult nsImageRenderer::DrawBorderImageComponent(
|
|||
|
||||
if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
|
||||
ImgDrawResult result = nsLayoutUtils::DrawSingleImage(
|
||||
aRenderingContext, aPresContext, subImage, samplingFilter, aFill,
|
||||
aDirtyRect,
|
||||
aRenderingContext, aPresContext, subImage, mImageResolution,
|
||||
samplingFilter, aFill, aDirtyRect,
|
||||
/* no SVGImageContext */ Nothing(), drawFlags);
|
||||
|
||||
if (!mImage->IsComplete()) {
|
||||
|
@ -1007,8 +1010,9 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
|
|||
// rendered pixel has an alpha that precisely matches the alpha of the
|
||||
// closest pixel in the image.
|
||||
return nsLayoutUtils::DrawSingleImage(
|
||||
aRenderingContext, aPresContext, mImageContainer, SamplingFilter::POINT,
|
||||
dest, dest, Nothing(), drawFlags, nullptr, nullptr);
|
||||
aRenderingContext, aPresContext, mImageContainer, mImageResolution,
|
||||
SamplingFilter::POINT, dest, dest, Nothing(), drawFlags, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (mImage->IsGradient()) {
|
||||
|
|
|
@ -299,6 +299,7 @@ class nsImageRenderer {
|
|||
|
||||
nsIFrame* mForFrame;
|
||||
const mozilla::StyleImage* mImage;
|
||||
float mImageResolution;
|
||||
mozilla::StyleImage::Tag mType;
|
||||
nsCOMPtr<imgIContainer> mImageContainer;
|
||||
const mozilla::StyleGradient* mGradientData;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/css/DocumentMatchingFunction.h"
|
||||
#include "mozilla/css/SheetLoadData.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/ComputedTimingFunction.h"
|
||||
#include "mozilla/PreferenceSheet.h"
|
||||
|
|
|
@ -942,14 +942,25 @@ inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
|
|||
}
|
||||
|
||||
template <>
|
||||
inline const StyleImage& StyleImage::FinalImage() const {
|
||||
inline std::pair<const StyleImage*, float> StyleImage::FinalImageAndResolution()
|
||||
const {
|
||||
if (!IsImageSet()) {
|
||||
return *this;
|
||||
return {this, 1.0f};
|
||||
}
|
||||
auto& set = AsImageSet();
|
||||
return set->items.AsSpan()[set->selected_index].image.FinalImage();
|
||||
auto& selectedItem = set->items.AsSpan()[set->selected_index];
|
||||
return {selectedItem.image.FinalImageAndResolution().first,
|
||||
selectedItem.resolution._0};
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const StyleImage& StyleImage::FinalImage() const {
|
||||
return *FinalImageAndResolution().first;
|
||||
}
|
||||
|
||||
template <>
|
||||
Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const;
|
||||
|
||||
template <>
|
||||
inline bool StyleImage::IsImageRequestType() const {
|
||||
auto& finalImage = FinalImage();
|
||||
|
|
|
@ -1629,6 +1629,31 @@ void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) {
|
|||
const_cast<StyleComputedImageUrl*>(url)->ResolveImage(aDoc, old);
|
||||
}
|
||||
|
||||
template <>
|
||||
Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const {
|
||||
auto [finalImage, resolution] = FinalImageAndResolution();
|
||||
imgRequestProxy* request = finalImage->GetImageRequest();
|
||||
if (!request) {
|
||||
return Nothing();
|
||||
}
|
||||
RefPtr<imgIContainer> image;
|
||||
request->GetImage(getter_AddRefs(image));
|
||||
if (!image) {
|
||||
return Nothing();
|
||||
}
|
||||
// FIXME(emilio): Seems like this should be smarter about unspecified width /
|
||||
// height, aspect ratio, etc, but this preserves the current behavior of our
|
||||
// only caller for now...
|
||||
int32_t w = 0, h = 0;
|
||||
image->GetWidth(&w);
|
||||
image->GetHeight(&h);
|
||||
if (resolution != 0.0f && resolution != 1.0f) {
|
||||
w = std::round(float(w) / resolution);
|
||||
h = std::round(float(h) / resolution);
|
||||
}
|
||||
return Some(CSSIntSize{w, h});
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// nsStyleImageLayers
|
||||
//
|
||||
|
@ -1882,8 +1907,11 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
|
|||
CSSIntSize imageSize;
|
||||
AspectRatio imageRatio;
|
||||
bool hasWidth, hasHeight;
|
||||
nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio,
|
||||
hasWidth, hasHeight);
|
||||
// We could bother getting the right resolution here but it doesn't matter
|
||||
// since we ignore `imageSize`.
|
||||
nsLayoutUtils::ComputeSizeForDrawing(imgContainer,
|
||||
/* aResolution = */ 1.0f, imageSize,
|
||||
imageRatio, hasWidth, hasHeight);
|
||||
|
||||
// If the image has a fixed width and height, rendering never depends on
|
||||
// the frame size.
|
||||
|
|
|
@ -405,7 +405,7 @@ void SVGImageFrame::PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
|||
// That method needs our image to have a fixed native width & height,
|
||||
// and that's not always true for TYPE_VECTOR images.
|
||||
aImgParams.result &= nsLayoutUtils::DrawSingleImage(
|
||||
aContext, PresContext(), mImageContainer,
|
||||
aContext, PresContext(), mImageContainer, /* aResolution = */ 1.0f,
|
||||
nsLayoutUtils::GetSamplingFilterForFrame(this), destRect,
|
||||
aDirtyRect ? dirtyRect : destRect, context, flags);
|
||||
} else { // mImageContainer->GetType() == TYPE_RASTER
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "nsStyleConsts.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsBoxLayoutState.h"
|
||||
|
||||
|
@ -239,6 +240,7 @@ void nsImageBoxFrame::UpdateImage() {
|
|||
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
|
||||
mUseSrcAttr = !src.IsEmpty();
|
||||
if (mUseSrcAttr) {
|
||||
mImageResolution = 1.0f;
|
||||
nsContentPolicyType contentPolicyType;
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
uint64_t requestContextID = 0;
|
||||
|
@ -267,10 +269,14 @@ void nsImageBoxFrame::UpdateImage() {
|
|||
doc->ImageTracker()->Add(mImageRequest);
|
||||
}
|
||||
}
|
||||
} else if (auto* styleRequest = GetRequestFromStyle()) {
|
||||
} else if (auto* styleImage = GetImageFromStyle()) {
|
||||
auto [finalImage, resolution] = styleImage->FinalImageAndResolution();
|
||||
mImageResolution = resolution;
|
||||
if (auto* styleRequest = finalImage->GetImageRequest()) {
|
||||
styleRequest->SyncClone(mListener, mContent->GetComposedDoc(),
|
||||
getter_AddRefs(mImageRequest));
|
||||
}
|
||||
}
|
||||
|
||||
if (!mImageRequest) {
|
||||
// We have no image, so size to 0
|
||||
|
@ -388,7 +394,7 @@ ImgDrawResult nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
|
|||
Maybe<SVGImageContext> svgContext;
|
||||
SVGImageContext::MaybeStoreContextPaint(svgContext, this, imgCon);
|
||||
return nsLayoutUtils::DrawSingleImage(
|
||||
aRenderingContext, PresContext(), imgCon,
|
||||
aRenderingContext, PresContext(), imgCon, mImageResolution,
|
||||
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, dirty, svgContext,
|
||||
aFlags, anchorPoint.ptrOr(nullptr), hasSubRect ? &mSubRect : nullptr);
|
||||
}
|
||||
|
@ -603,8 +609,9 @@ bool nsImageBoxFrame::CanOptimizeToImageLayer() {
|
|||
return true;
|
||||
}
|
||||
|
||||
imgRequestProxy* nsImageBoxFrame::GetRequestFromStyle() {
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle(
|
||||
const ComputedStyle& aStyle) {
|
||||
const nsStyleDisplay* disp = aStyle.StyleDisplay();
|
||||
if (disp->HasAppearance()) {
|
||||
nsPresContext* pc = PresContext();
|
||||
if (pc->Theme()->ThemeSupportsWidget(pc, this,
|
||||
|
@ -612,7 +619,11 @@ imgRequestProxy* nsImageBoxFrame::GetRequestFromStyle() {
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
return StyleList()->mListStyleImage.GetImageRequest();
|
||||
auto& image = aStyle.StyleList()->mListStyleImage;
|
||||
if (!image.IsImageRequestType()) {
|
||||
return nullptr;
|
||||
}
|
||||
return ℑ
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
|
@ -623,26 +634,18 @@ void nsImageBoxFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
|||
const nsStyleList* myList = StyleList();
|
||||
mSubRect = myList->GetImageRegion(); // before |mSuppressStyleCheck| test!
|
||||
|
||||
if (mUseSrcAttr || mSuppressStyleCheck)
|
||||
if (mUseSrcAttr || mSuppressStyleCheck) {
|
||||
return; // No more work required, since the image isn't specified by style.
|
||||
}
|
||||
|
||||
// If the image to use changes, we have a new image.
|
||||
nsCOMPtr<nsIURI> oldURI, newURI;
|
||||
if (mImageRequest) {
|
||||
mImageRequest->GetURI(getter_AddRefs(oldURI));
|
||||
}
|
||||
if (auto* newImage = GetRequestFromStyle()) {
|
||||
newImage->GetURI(getter_AddRefs(newURI));
|
||||
}
|
||||
bool equal;
|
||||
if (newURI == oldURI || // handles null==null
|
||||
(newURI && oldURI && NS_SUCCEEDED(newURI->Equals(oldURI, &equal)) &&
|
||||
equal)) {
|
||||
auto* oldImage = aOldStyle ? GetImageFromStyle(*aOldStyle) : nullptr;
|
||||
auto* newImage = GetImageFromStyle();
|
||||
if (newImage == oldImage ||
|
||||
(newImage && oldImage && *oldImage == *newImage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateImage();
|
||||
} // DidSetComputedStyle
|
||||
}
|
||||
|
||||
void nsImageBoxFrame::GetImageSize() {
|
||||
if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) {
|
||||
|
@ -796,12 +799,16 @@ void nsImageBoxFrame::OnSizeAvailable(imgIRequest* aRequest,
|
|||
|
||||
aImage->SetAnimationMode(PresContext()->ImageAnimationMode());
|
||||
|
||||
nscoord w, h;
|
||||
int32_t w = 0, h = 0;
|
||||
aImage->GetWidth(&w);
|
||||
aImage->GetHeight(&h);
|
||||
|
||||
mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
|
||||
nsPresContext::CSSPixelsToAppUnits(h));
|
||||
if (mImageResolution != 0.0f && mImageResolution != 1.0f) {
|
||||
w = std::round(w / mImageResolution);
|
||||
h = std::round(h / mImageResolution);
|
||||
}
|
||||
|
||||
mIntrinsicSize.SizeTo(CSSPixel::ToAppUnits(w), CSSPixel::ToAppUnits(h));
|
||||
|
||||
if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
|
||||
PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange,
|
||||
|
|
|
@ -73,11 +73,15 @@ class nsImageBoxFrame final : public nsLeafBoxFrame {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* Gets the image request to be loaded from the current style.
|
||||
* Gets the image to be loaded from the current style. May be null if themed,
|
||||
* or if not an url image.
|
||||
*
|
||||
* May be null if themed.
|
||||
* TODO(emilio): Maybe support list-style-image: linear-gradient() etc?
|
||||
*/
|
||||
imgRequestProxy* GetRequestFromStyle();
|
||||
const mozilla::StyleImage* GetImageFromStyle(const ComputedStyle&);
|
||||
const mozilla::StyleImage* GetImageFromStyle() {
|
||||
return GetImageFromStyle(*Style());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update mUseSrcAttr from appropriate content attributes or from
|
||||
|
@ -137,6 +141,7 @@ class nsImageBoxFrame final : public nsLeafBoxFrame {
|
|||
nsSize mImageSize;
|
||||
|
||||
RefPtr<imgRequestProxy> mImageRequest;
|
||||
float mImageResolution = 1.0f;
|
||||
nsCOMPtr<imgINotificationObserver> mListener;
|
||||
|
||||
int32_t mLoadFlags;
|
||||
|
|
|
@ -790,6 +790,17 @@ renaming_overrides_prefixing = true
|
|||
|
||||
"GenericImage" = """
|
||||
public:
|
||||
// Returns the final image we've selected taken from the image-set, along with
|
||||
// its resolution, or `this` and `1.0` if this image is not an image-set.
|
||||
//
|
||||
// The resolution is in dppx, and should be used to impact the intrinsic size
|
||||
// of the image.
|
||||
std::pair<const StyleGenericImage*, float> FinalImageAndResolution() const;
|
||||
|
||||
// Returns the intrinsic size of the image, if there's one, accounting for
|
||||
// resolution as needed.
|
||||
Maybe<CSSIntSize> GetIntrinsicSize() const;
|
||||
|
||||
// If this is an image-set(), the final image we've selected, otherwise it
|
||||
// returns *this.
|
||||
const StyleGenericImage& FinalImage() const;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!doctype html>
|
||||
<title>CSS Test Reference</title>
|
||||
<style>
|
||||
body { margin: 0 }
|
||||
</style>
|
||||
<img srcset="/images/green.png 0.5x">
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<title>Image set resolution affects intrinsic size of the image</title>
|
||||
<link rel="match" href="image-set-resolution-001-ref.html">
|
||||
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
|
||||
<link rel="author" href="https://mozilla.org" title="Mozilla">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1705877">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#image-set-notation">
|
||||
<style>
|
||||
body { margin: 0 }
|
||||
div {
|
||||
/* green.png is 100x50, should be 200x100 instead */
|
||||
content: -webkit-image-set(url('/images/green.png') 0.5x);
|
||||
content: image-set(url('/images/green.png') 0.5x);
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<title>Image set resolution affects intrinsic size of the image</title>
|
||||
<link rel="match" href="image-set-resolution-001-ref.html">
|
||||
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
|
||||
<link rel="author" href="https://mozilla.org" title="Mozilla">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1705877">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#image-set-notation">
|
||||
<style>
|
||||
body { margin: 0 }
|
||||
div {
|
||||
/* green.png is 100x50, should be 200x100 instead */
|
||||
background-image: -webkit-image-set(url('/images/green.png') 0.5x);
|
||||
background-image: image-set(url('/images/green.png') 0.5x);
|
||||
background-repeat: no-repeat;
|
||||
background-origin: 0 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<title>Image set resolution affects intrinsic size of the image</title>
|
||||
<link rel="match" href="image-set-resolution-001-ref.html">
|
||||
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
|
||||
<link rel="author" href="https://mozilla.org" title="Mozilla">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1705877">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#image-set-notation">
|
||||
<style>
|
||||
body { margin: 0 }
|
||||
ul, li { margin: 0; padding: 0 }
|
||||
li {
|
||||
list-style-position: inside;
|
||||
/* green.png is 100x50, should be 200x100 instead */
|
||||
list-style-image: -webkit-image-set(url('/images/green.png') 0.5x);
|
||||
list-style-image: image-set(url('/images/green.png') 0.5x);
|
||||
}
|
||||
</style>
|
||||
<ul>
|
||||
<li></li>
|
||||
</ul>
|
Загрузка…
Ссылка в новой задаче