Bug 1680387 - Apply intrinsic image resolution as appropriate in layout/style/dom, and update test expectations. r=tnikkel

This should be mostly straight-forward, since we have code for this
anyways for image-set() and srcset.

The only thing is that we were using floats for resolution, but since
EXIF allows you to scale each axis separately, we now need to pass an
image::Resolution instead.

The main outstanding issue is the spec comment mentioned in the previous
patch, about what happens if you have srcset/image-set and the image
density specified together. For now I've implemented what the
image-set() spec says, but this is subject to change before shipping of
course.

Differential Revision: https://phabricator.services.mozilla.com/D113265
This commit is contained in:
Emilio Cobos Álvarez 2021-05-05 09:41:24 +00:00
Родитель 6c4266f7f7
Коммит 1cdf344860
38 изменённых файлов: 245 добавлений и 244 удалений

Просмотреть файл

@ -288,7 +288,7 @@ bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument,
// Hide the cursor and set pointer lock for future mouse events // Hide the cursor and set pointer lock for future mouse events
RefPtr<EventStateManager> esm = presContext->EventStateManager(); RefPtr<EventStateManager> esm = presContext->EventStateManager();
esm->SetCursor(aCursorStyle, nullptr, 1.0f, Nothing(), widget, true); esm->SetCursor(aCursorStyle, nullptr, {}, Nothing(), widget, true);
EventStateManager::SetPointerLock(widget, aElement); EventStateManager::SetPointerLock(widget, aElement);
return true; return true;

Просмотреть файл

@ -7426,7 +7426,7 @@ void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
// Call esm and set cursor. // Call esm and set cursor.
aError = presContext->EventStateManager()->SetCursor( aError = presContext->EventStateManager()->SetCursor(
cursor, nullptr, 1.0f, Nothing(), widget, true); cursor, nullptr, {}, Nothing(), widget, true);
} }
} }

Просмотреть файл

@ -1216,32 +1216,6 @@ void nsImageLoadingContent::ForceImageState(bool aForce,
mForcedImageState = EventStates(aState); mForcedImageState = EventStates(aState);
} }
uint32_t nsImageLoadingContent::NaturalWidth() {
nsCOMPtr<imgIContainer> image;
if (mCurrentRequest) {
mCurrentRequest->GetImage(getter_AddRefs(image));
}
int32_t size = 0;
if (image) {
Unused << image->GetWidth(&size);
}
return size;
}
uint32_t nsImageLoadingContent::NaturalHeight() {
nsCOMPtr<imgIContainer> image;
if (mCurrentRequest) {
mCurrentRequest->GetImage(getter_AddRefs(image));
}
int32_t size = 0;
if (image) {
Unused << image->GetHeight(&size);
}
return size;
}
CSSIntSize nsImageLoadingContent::GetWidthHeightForImage() { CSSIntSize nsImageLoadingContent::GetWidthHeightForImage() {
Element* element = AsContent()->AsElement(); Element* element = AsContent()->AsElement();
if (nsIFrame* frame = element->GetPrimaryFrame(FlushType::Layout)) { if (nsIFrame* frame = element->GetPrimaryFrame(FlushType::Layout)) {

Просмотреть файл

@ -232,9 +232,6 @@ class nsImageLoadingContent : public nsIImageLoadingContent {
// want a non-const nsIContent. // want a non-const nsIContent.
virtual nsIContent* AsContent() = 0; virtual nsIContent* AsContent() = 0;
// Hooks for subclasses to call to get the intrinsic width and height.
uint32_t NaturalWidth();
uint32_t NaturalHeight();
/** /**
* Get width and height of the current request, using given image request if * Get width and height of the current request, using given image request if
* attributes are unset. * attributes are unset.

Просмотреть файл

@ -3906,7 +3906,7 @@ void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
struct CursorImage { struct CursorImage {
gfx::IntPoint mHotspot; gfx::IntPoint mHotspot;
nsCOMPtr<imgIContainer> mContainer; nsCOMPtr<imgIContainer> mContainer;
float mResolution = 1.0f; ImageResolution mResolution;
bool mEarlierCursorLoading = false; bool mEarlierCursorLoading = false;
}; };
@ -3934,10 +3934,7 @@ static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
int32_t height = 0; int32_t height = 0;
aCursor.mContainer->GetWidth(&width); aCursor.mContainer->GetWidth(&width);
aCursor.mContainer->GetHeight(&height); aCursor.mContainer->GetHeight(&height);
if (aCursor.mResolution != 0.0f && aCursor.mResolution != 1.0f) { aCursor.mResolution.ApplyTo(width, height);
width = std::round(width / aCursor.mResolution);
height = std::round(height / aCursor.mResolution);
}
int32_t maxSize = StaticPrefs::layout_cursor_block_max_size(); int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
@ -4010,8 +4007,7 @@ static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
MOZ_ASSERT(image.image.IsImageRequestType(), MOZ_ASSERT(image.image.IsImageRequestType(),
"Cursor image should only parse url() types"); "Cursor image should only parse url() types");
uint32_t status; uint32_t status;
auto [finalImage, resolution] = image.image.FinalImageAndResolution(); imgRequestProxy* req = image.image.GetImageRequest();
imgRequestProxy* req = finalImage->GetImageRequest();
if (!req || NS_FAILED(req->GetImageStatus(&status))) { if (!req || NS_FAILED(req->GetImageStatus(&status))) {
continue; continue;
} }
@ -4033,14 +4029,15 @@ static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y}) image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
: Nothing(); : Nothing();
gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot); gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
CursorImage result{hotspot, std::move(container), resolution, loading}; CursorImage result{hotspot, std::move(container),
image.image.GetResolution(), loading};
if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) { if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
continue; continue;
} }
// This is the one we want! // This is the one we want!
return result; return result;
} }
return {{}, nullptr, 1.0f, loading}; return {{}, nullptr, {}, loading};
} }
void EventStateManager::UpdateCursor(nsPresContext* aPresContext, void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
@ -4053,7 +4050,7 @@ void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
auto cursor = StyleCursorKind::Default; auto cursor = StyleCursorKind::Default;
nsCOMPtr<imgIContainer> container; nsCOMPtr<imgIContainer> container;
float resolution = 1.0f; ImageResolution resolution;
Maybe<gfx::IntPoint> hotspot; Maybe<gfx::IntPoint> hotspot;
// If cursor is locked just use the locked one // If cursor is locked just use the locked one
@ -4138,7 +4135,7 @@ void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
nsresult EventStateManager::SetCursor(StyleCursorKind aCursor, nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
imgIContainer* aContainer, imgIContainer* aContainer,
float aResolution, const ImageResolution& aResolution,
const Maybe<gfx::IntPoint>& aHotspot, const Maybe<gfx::IntPoint>& aHotspot,
nsIWidget* aWidget, bool aLockCursor) { nsIWidget* aWidget, bool aLockCursor) {
EnsureDocument(mPresContext); EnsureDocument(mPresContext);

Просмотреть файл

@ -243,9 +243,9 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
bool CheckIfEventMatchesAccessKey(WidgetKeyboardEvent* aEvent, bool CheckIfEventMatchesAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext); nsPresContext* aPresContext);
nsresult SetCursor(StyleCursorKind aCursor, imgIContainer* aContainer, nsresult SetCursor(StyleCursorKind, imgIContainer*, const ImageResolution&,
float aResolution, const Maybe<gfx::IntPoint>& aHotspot, const Maybe<gfx::IntPoint>& aHotspot, nsIWidget* aWidget,
nsIWidget* aWidget, bool aLockCursor); bool aLockCursor);
/** /**
* Checks if the current mouse over element matches the given * Checks if the current mouse over element matches the given

Просмотреть файл

@ -710,28 +710,33 @@ uint32_t HTMLImageElement::Height() { return GetWidthHeightForImage().height; }
uint32_t HTMLImageElement::Width() { return GetWidthHeightForImage().width; } uint32_t HTMLImageElement::Width() { return GetWidthHeightForImage().width; }
uint32_t HTMLImageElement::NaturalHeight() { nsIntSize HTMLImageElement::NaturalSize() {
uint32_t height = nsImageLoadingContent::NaturalHeight(); if (!mCurrentRequest) {
return {};
if (mResponsiveSelector) {
double density = mResponsiveSelector->GetSelectedImageDensity();
MOZ_ASSERT(density >= 0.0);
height = NSToIntRound(double(height) / density);
} }
return height; nsCOMPtr<imgIContainer> image;
} mCurrentRequest->GetImage(getter_AddRefs(image));
if (!image) {
uint32_t HTMLImageElement::NaturalWidth() { return {};
uint32_t width = nsImageLoadingContent::NaturalWidth();
if (mResponsiveSelector) {
double density = mResponsiveSelector->GetSelectedImageDensity();
MOZ_ASSERT(density >= 0.0);
width = NSToIntRound(double(width) / density);
} }
return width; nsIntSize size;
Unused << image->GetHeight(&size.height);
Unused << image->GetWidth(&size.width);
ImageResolution resolution = image->GetResolution();
// NOTE(emilio): What we implement here matches the image-set() spec, but it's
// unclear whether this is the right thing to do, see
// https://github.com/whatwg/html/pull/5574#issuecomment-826335244.
if (mResponsiveSelector) {
float density = mResponsiveSelector->GetSelectedImageDensity();
MOZ_ASSERT(density >= 0.0);
resolution = {density, density};
}
resolution.ApplyTo(size.width, size.height);
return size;
} }
nsresult HTMLImageElement::CopyInnerTo(HTMLImageElement* aDest) { nsresult HTMLImageElement::CopyInnerTo(HTMLImageElement* aDest) {

Просмотреть файл

@ -97,8 +97,11 @@ class HTMLImageElement final : public nsGenericHTMLElement,
void SetHeight(uint32_t aHeight, ErrorResult& aError) { void SetHeight(uint32_t aHeight, ErrorResult& aError) {
SetUnsignedIntAttr(nsGkAtoms::height, aHeight, 0, aError); SetUnsignedIntAttr(nsGkAtoms::height, aHeight, 0, aError);
} }
uint32_t NaturalWidth();
uint32_t NaturalHeight(); nsIntSize NaturalSize();
uint32_t NaturalHeight() { return NaturalSize().height; }
uint32_t NaturalWidth() { return NaturalSize().width; }
bool Complete(); bool Complete();
uint32_t Hspace() { uint32_t Hspace() {
return GetDimensionAttrAsUnsignedInt(nsGkAtoms::hspace, 0); return GetDimensionAttrAsUnsignedInt(nsGkAtoms::hspace, 0);

Просмотреть файл

@ -2183,7 +2183,8 @@ mozilla::ipc::IPCResult BrowserParent::RecvAsyncMessage(
mozilla::ipc::IPCResult BrowserParent::RecvSetCursor( mozilla::ipc::IPCResult BrowserParent::RecvSetCursor(
const nsCursor& aCursor, const bool& aHasCustomCursor, const nsCursor& aCursor, const bool& aHasCustomCursor,
const nsCString& aCursorData, const uint32_t& aWidth, const nsCString& aCursorData, const uint32_t& aWidth,
const uint32_t& aHeight, const float& aResolution, const uint32_t& aStride, const uint32_t& aHeight, const float& aResolutionX,
const float& aResolutionY, const uint32_t& aStride,
const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX, const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
const uint32_t& aHotspotY, const bool& aForce) { const uint32_t& aHotspotY, const bool& aForce) {
nsCOMPtr<nsIWidget> widget = GetWidget(); nsCOMPtr<nsIWidget> widget = GetWidget();
@ -2212,8 +2213,11 @@ mozilla::ipc::IPCResult BrowserParent::RecvSetCursor(
cursorImage = image::ImageOps::CreateFromDrawable(drawable); cursorImage = image::ImageOps::CreateFromDrawable(drawable);
} }
mCursor = nsIWidget::Cursor{aCursor, std::move(cursorImage), aHotspotX, mCursor = nsIWidget::Cursor{aCursor,
aHotspotY, aResolution}; std::move(cursorImage),
aHotspotX,
aHotspotY,
{aResolutionX, aResolutionY}};
if (!mRemoteTargetSetsCursor) { if (!mRemoteTargetSetsCursor) {
return IPC_OK(); return IPC_OK();
} }

Просмотреть файл

@ -386,9 +386,10 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvSetCursor( mozilla::ipc::IPCResult RecvSetCursor(
const nsCursor& aValue, const bool& aHasCustomCursor, const nsCursor& aValue, const bool& aHasCustomCursor,
const nsCString& aCursorData, const uint32_t& aWidth, const nsCString& aCursorData, const uint32_t& aWidth,
const uint32_t& aHeight, const float& aResolution, const uint32_t& aHeight, const float& aResolutionX,
const uint32_t& aStride, const gfx::SurfaceFormat& aFormat, const float& aResolutionY, const uint32_t& aStride,
const uint32_t& aHotspotX, const uint32_t& aHotspotY, const bool& aForce); const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
const uint32_t& aHotspotY, const bool& aForce);
mozilla::ipc::IPCResult RecvSetLinkStatus(const nsString& aStatus); mozilla::ipc::IPCResult RecvSetLinkStatus(const nsString& aStatus);

Просмотреть файл

@ -389,8 +389,10 @@ parent:
* Width of the image. * Width of the image.
* @param height * @param height
* Height of the image. * Height of the image.
* @param resolution * @param resolutionX
* Resolution of the image in dppx units. * Resolution of the image X axis in dppx units.
* @param resolutionY
* Resolution of the image Y axis in dppx units.
* @param stride * @param stride
* Stride used in the image data. * Stride used in the image data.
* @param format * @param format
@ -407,7 +409,8 @@ parent:
bool hasCustomCursor, bool hasCustomCursor,
nsCString customCursorData, nsCString customCursorData,
uint32_t width, uint32_t height, uint32_t width, uint32_t height,
float resolution, uint32_t stride, SurfaceFormat format, float resolutionX, float resolutionY,
uint32_t stride, SurfaceFormat format,
uint32_t hotspotX, uint32_t hotspotY, bool force); uint32_t hotspotX, uint32_t hotspotY, bool force);
/** /**

Просмотреть файл

@ -63,6 +63,15 @@ struct Resolution {
ApplyXTo(aWidth); ApplyXTo(aWidth);
ApplyYTo(aHeight); ApplyYTo(aHeight);
} }
void ApplyInverseTo(int32_t& aWidth, int32_t& aHeight) {
if (mX != 1.0f) {
aWidth = std::round(float(aWidth) * mX);
}
if (mY != 1.0f) {
aHeight = std::round(float(aHeight) * mY);
}
}
}; };
} // namespace image } // namespace image

Просмотреть файл

@ -6294,6 +6294,8 @@ ImgDrawResult nsLayoutUtils::DrawSingleUnscaledImage(
CSSIntSize imageSize; CSSIntSize imageSize;
aImage->GetWidth(&imageSize.width); aImage->GetWidth(&imageSize.width);
aImage->GetHeight(&imageSize.height); aImage->GetHeight(&imageSize.height);
aImage->GetResolution().ApplyTo(imageSize.width, imageSize.height);
if (imageSize.width < 1 || imageSize.height < 1) { if (imageSize.width < 1 || imageSize.height < 1) {
NS_WARNING("Image width or height is non-positive"); NS_WARNING("Image width or height is non-positive");
return ImgDrawResult::TEMPORARY_ERROR; return ImgDrawResult::TEMPORARY_ERROR;
@ -6321,13 +6323,15 @@ ImgDrawResult nsLayoutUtils::DrawSingleUnscaledImage(
/* static */ /* static */
ImgDrawResult nsLayoutUtils::DrawSingleImage( ImgDrawResult nsLayoutUtils::DrawSingleImage(
gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest, SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty,
const nsRect& aDirty, const Maybe<SVGImageContext>& aSVGContext, const Maybe<SVGImageContext>& aSVGContext, uint32_t aImageFlags,
uint32_t aImageFlags, const nsPoint* aAnchorPoint, const nsPoint* aAnchorPoint, const nsRect* aSourceArea) {
const nsRect* aSourceArea) {
nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel(); nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
CSSIntSize pixelImageSize( // NOTE(emilio): We can hardcode resolution to 1 here, since we're interested
ComputeSizeForDrawingWithFallback(aImage, aResolution, aDest.Size())); // in the actual image pixels, for snapping purposes, not on the adjusted
// size.
CSSIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(
aImage, ImageResolution(), aDest.Size()));
if (pixelImageSize.width < 1 || pixelImageSize.height < 1) { if (pixelImageSize.width < 1 || pixelImageSize.height < 1) {
NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0, NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0,
"Image width or height is negative"); "Image width or height is negative");
@ -6368,7 +6372,7 @@ ImgDrawResult nsLayoutUtils::DrawSingleImage(
/* static */ /* static */
void nsLayoutUtils::ComputeSizeForDrawing( void nsLayoutUtils::ComputeSizeForDrawing(
imgIContainer* aImage, float aResolution, imgIContainer* aImage, const ImageResolution& aResolution,
/* outparam */ CSSIntSize& aImageSize, /* outparam */ CSSIntSize& aImageSize,
/* outparam */ AspectRatio& aIntrinsicRatio, /* outparam */ AspectRatio& aIntrinsicRatio,
/* outparam */ bool& aGotWidth, /* outparam */ bool& aGotWidth,
@ -6378,13 +6382,11 @@ void nsLayoutUtils::ComputeSizeForDrawing(
Maybe<AspectRatio> intrinsicRatio = aImage->GetIntrinsicRatio(); Maybe<AspectRatio> intrinsicRatio = aImage->GetIntrinsicRatio();
aIntrinsicRatio = intrinsicRatio.valueOr(AspectRatio()); aIntrinsicRatio = intrinsicRatio.valueOr(AspectRatio());
if (aResolution != 0.0f && aResolution != 1.0f) { if (aGotWidth) {
if (aGotWidth) { aResolution.ApplyXTo(aImageSize.width);
aImageSize.width = std::round(float(aImageSize.width) / aResolution); }
} if (aGotHeight) {
if (aGotHeight) { aResolution.ApplyYTo(aImageSize.height);
aImageSize.height = std::round(float(aImageSize.height) / aResolution);
}
} }
if (!(aGotWidth && aGotHeight) && intrinsicRatio.isNothing()) { if (!(aGotWidth && aGotHeight) && intrinsicRatio.isNothing()) {
@ -6397,7 +6399,8 @@ void nsLayoutUtils::ComputeSizeForDrawing(
/* static */ /* static */
CSSIntSize nsLayoutUtils::ComputeSizeForDrawingWithFallback( CSSIntSize nsLayoutUtils::ComputeSizeForDrawingWithFallback(
imgIContainer* aImage, float aResolution, const nsSize& aFallbackSize) { imgIContainer* aImage, const ImageResolution& aResolution,
const nsSize& aFallbackSize) {
CSSIntSize imageSize; CSSIntSize imageSize;
AspectRatio imageRatio; AspectRatio imageRatio;
bool gotHeight, gotWidth; bool gotHeight, gotWidth;

Просмотреть файл

@ -103,6 +103,9 @@ namespace gfx {
struct RectCornerRadii; struct RectCornerRadii;
enum class ShapedTextFlags : uint16_t; enum class ShapedTextFlags : uint16_t;
} // namespace gfx } // namespace gfx
namespace image {
struct Resolution;
}
namespace layers { namespace layers {
struct FrameMetrics; struct FrameMetrics;
struct ScrollMetadata; struct ScrollMetadata;
@ -1901,11 +1904,6 @@ class nsLayoutUtils {
* appropriate scale and transform for drawing in * appropriate scale and transform for drawing in
* app units. * app units.
* @param aImage The image. * @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 aDest The area that the image should fill.
* @param aDirty Pixels outside this area may be skipped. * @param aDirty Pixels outside this area may be skipped.
* @param aSVGContext Optionally provides an SVGImageContext. * @param aSVGContext Optionally provides an SVGImageContext.
@ -1927,9 +1925,9 @@ class nsLayoutUtils {
*/ */
static ImgDrawResult DrawSingleImage( static ImgDrawResult DrawSingleImage(
gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest, SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty,
const nsRect& aDirty, const mozilla::Maybe<SVGImageContext>& aSVGContext, const mozilla::Maybe<SVGImageContext>& aSVGContext, uint32_t aImageFlags,
uint32_t aImageFlags, const nsPoint* aAnchorPoint = nullptr, const nsPoint* aAnchorPoint = nullptr,
const nsRect* aSourceArea = nullptr); const nsRect* aSourceArea = nullptr);
/** /**
@ -1947,8 +1945,16 @@ class nsLayoutUtils {
* NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The * NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The
* difference is that this one is simpler and is suited to places where we * difference is that this one is simpler and is suited to places where we
* have less information about the frame tree. * have less information about the frame tree.
*
* @param aResolution The resolution specified by the author for the image, or
* its intrinsic resolution.
*
* This will affect the intrinsic size 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).
*/ */
static void ComputeSizeForDrawing(imgIContainer* aImage, float aResolution, static void ComputeSizeForDrawing(imgIContainer* aImage,
const mozilla::image::Resolution&,
CSSIntSize& aImageSize, CSSIntSize& aImageSize,
AspectRatio& aIntrinsicRatio, AspectRatio& aIntrinsicRatio,
bool& aGotWidth, bool& aGotHeight); bool& aGotWidth, bool& aGotHeight);
@ -1962,7 +1968,8 @@ class nsLayoutUtils {
* dimensions, the corresponding dimension of aFallbackSize is used instead. * dimensions, the corresponding dimension of aFallbackSize is used instead.
*/ */
static CSSIntSize ComputeSizeForDrawingWithFallback( static CSSIntSize ComputeSizeForDrawingWithFallback(
imgIContainer* aImage, float aResolution, const nsSize& aFallbackSize); imgIContainer* aImage, const mozilla::image::Resolution&,
const nsSize& aFallbackSize);
/** /**
* Given the image container, frame, and dest rect, determine the best fitting * Given the image container, frame, and dest rect, determine the best fitting

Просмотреть файл

@ -356,6 +356,38 @@ static bool SizeIsAvailable(imgIRequest* aRequest) {
return NS_SUCCEEDED(rv) && (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE); return NS_SUCCEEDED(rv) && (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE);
} }
const StyleImage* nsImageFrame::GetImageFromStyle() const {
if (mKind == Kind::ImageElement) {
return nullptr;
}
uint32_t contentIndex = 0;
const nsStyleContent* styleContent = StyleContent();
if (mKind == Kind::ContentPropertyAtIndex) {
MOZ_RELEASE_ASSERT(
mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage));
contentIndex = static_cast<GeneratedImageContent*>(mContent.get())->Index();
// TODO(emilio): Consider inheriting the `content` property instead of doing
// this parent traversal?
nsIFrame* parent = GetParent();
MOZ_DIAGNOSTIC_ASSERT(
parent->GetContent()->IsGeneratedContentContainerForMarker() ||
parent->GetContent()->IsGeneratedContentContainerForAfter() ||
parent->GetContent()->IsGeneratedContentContainerForBefore());
nsIFrame* nonAnonymousParent = parent;
while (nonAnonymousParent->Style()->IsAnonBox()) {
nonAnonymousParent = nonAnonymousParent->GetParent();
}
MOZ_DIAGNOSTIC_ASSERT(parent->GetContent() ==
nonAnonymousParent->GetContent());
styleContent = nonAnonymousParent->StyleContent();
}
MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
auto& contentItem = styleContent->ContentAt(contentIndex);
MOZ_RELEASE_ASSERT(contentItem.IsImage());
return &contentItem.AsImage();
}
void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) { nsIFrame* aPrevInFlow) {
MOZ_ASSERT_IF(aPrevInFlow, MOZ_ASSERT_IF(aPrevInFlow,
@ -378,33 +410,11 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
// that it can register images. // that it can register images.
imageLoader->FrameCreated(this); imageLoader->FrameCreated(this);
} else { } else {
uint32_t contentIndex = 0; const StyleImage* image = GetImageFromStyle();
const nsStyleContent* styleContent = StyleContent(); MOZ_ASSERT(image->IsImageRequestType(),
if (mKind == Kind::ContentPropertyAtIndex) {
MOZ_RELEASE_ASSERT(
aParent->GetContent()->IsGeneratedContentContainerForMarker() ||
aParent->GetContent()->IsGeneratedContentContainerForAfter() ||
aParent->GetContent()->IsGeneratedContentContainerForBefore());
MOZ_RELEASE_ASSERT(
aContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage));
nsIFrame* nonAnonymousParent = aParent;
while (nonAnonymousParent->Style()->IsAnonBox()) {
nonAnonymousParent = nonAnonymousParent->GetParent();
}
MOZ_RELEASE_ASSERT(aParent->GetContent() ==
nonAnonymousParent->GetContent());
styleContent = nonAnonymousParent->StyleContent();
contentIndex = static_cast<GeneratedImageContent*>(aContent)->Index();
}
MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
MOZ_RELEASE_ASSERT(styleContent->ContentAt(contentIndex).IsImage());
const StyleImage& image = styleContent->ContentAt(contentIndex).AsImage();
MOZ_ASSERT(image.IsImageRequestType(),
"Content image should only parse url() type"); "Content image should only parse url() type");
auto [finalImage, resolution] = image.FinalImageAndResolution();
Document* doc = PresContext()->Document(); Document* doc = PresContext()->Document();
if (imgRequestProxy* proxy = finalImage->GetImageRequest()) { if (imgRequestProxy* proxy = image->GetImageRequest()) {
mContentURLRequestResolution = resolution;
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest)); proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
SetupForContentURLRequest(); SetupForContentURLRequest();
} }
@ -457,34 +467,27 @@ void nsImageFrame::SetupForContentURLRequest() {
} }
static void ScaleIntrinsicSizeForDensity(IntrinsicSize& aSize, static void ScaleIntrinsicSizeForDensity(IntrinsicSize& aSize,
double aDensity) { const ImageResolution& aResolution) {
if (aDensity == 1.0) {
return;
}
if (aSize.width) { if (aSize.width) {
aSize.width = Some(NSToCoordRound(double(*aSize.width) / aDensity)); aResolution.ApplyXTo(aSize.width.ref());
} }
if (aSize.height) { if (aSize.height) {
aSize.height = Some(NSToCoordRound(double(*aSize.height) / aDensity)); aResolution.ApplyYTo(aSize.height.ref());
} }
} }
static void ScaleIntrinsicSizeForDensity(nsIContent& aContent, static void ScaleIntrinsicSizeForDensity(imgIContainer* aImage,
nsIContent& aContent,
IntrinsicSize& aSize) { IntrinsicSize& aSize) {
auto* image = HTMLImageElement::FromNode(aContent); if (auto* image = HTMLImageElement::FromNode(aContent)) {
if (!image) { if (auto* selector = image->GetResponsiveImageSelector()) {
return; float density = selector->GetSelectedImageDensity();
MOZ_ASSERT(density >= 0.0);
ScaleIntrinsicSizeForDensity(aSize, ImageResolution{density, density});
return;
}
} }
ScaleIntrinsicSizeForDensity(aSize, aImage->GetResolution());
ResponsiveImageSelector* selector = image->GetResponsiveImageSelector();
if (!selector) {
return;
}
double density = selector->GetSelectedImageDensity();
MOZ_ASSERT(density >= 0.0);
ScaleIntrinsicSizeForDensity(aSize, density);
} }
static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage, static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
@ -502,10 +505,10 @@ static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
intrinsicSize.width = size.width == -1 ? Nothing() : Some(size.width); intrinsicSize.width = size.width == -1 ? Nothing() : Some(size.width);
intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height); intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height);
if (aKind == nsImageFrame::Kind::ImageElement) { if (aKind == nsImageFrame::Kind::ImageElement) {
ScaleIntrinsicSizeForDensity(*aFrame.GetContent(), intrinsicSize); ScaleIntrinsicSizeForDensity(aImage, *aFrame.GetContent(), intrinsicSize);
} else { } else {
ScaleIntrinsicSizeForDensity(intrinsicSize, ScaleIntrinsicSizeForDensity(intrinsicSize,
aFrame.GetContentURLRequestResolution()); aFrame.GetImageFromStyle()->GetResolution());
} }
return intrinsicSize; return intrinsicSize;
} }
@ -1486,7 +1489,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size, nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
size); size);
result = nsLayoutUtils::DrawSingleImage( result = nsLayoutUtils::DrawSingleImage(
aRenderingContext, PresContext(), imgCon, /* aResolution = */ 1.0f, aRenderingContext, PresContext(), imgCon,
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
/* no SVGImageContext */ Nothing(), aFlags); /* no SVGImageContext */ Nothing(), aFlags);
} }
@ -2090,10 +2093,8 @@ ImgDrawResult nsImageFrame::PaintImage(gfxContext& aRenderingContext,
Maybe<SVGImageContext> svgContext; Maybe<SVGImageContext> svgContext;
SVGImageContext::MaybeStoreContextPaint(svgContext, this, aImage); 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( ImgDrawResult result = nsLayoutUtils::DrawSingleImage(
aRenderingContext, PresContext(), aImage, /* aResolution = */ 1.0f, aRenderingContext, PresContext(), aImage,
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
svgContext, flags, &anchorPoint); svgContext, flags, &anchorPoint);

Просмотреть файл

@ -103,11 +103,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
void SetupForContentURLRequest(); void SetupForContentURLRequest();
bool ShouldShowBrokenImageIcon() const; bool ShouldShowBrokenImageIcon() const;
// Get the resolution, in dppx, for the image that mContentURLRequest const mozilla::StyleImage* GetImageFromStyle() const;
// represents.
float GetContentURLRequestResolution() const {
return mContentURLRequestResolution;
}
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
mozilla::a11y::AccType AccessibleType() override; mozilla::a11y::AccType AccessibleType() override;
@ -359,7 +355,6 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
// An image request created for content: url(..). // An image request created for content: url(..).
RefPtr<imgRequestProxy> mContentURLRequest; RefPtr<imgRequestProxy> mContentURLRequest;
float mContentURLRequestResolution = 1.0f;
nsCOMPtr<imgIContainer> mImage; nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<imgIContainer> mPrevImage; nsCOMPtr<imgIContainer> mPrevImage;

Просмотреть файл

@ -50,6 +50,9 @@ nsSize CSSSizeOrRatio::ComputeConcreteSize() const {
nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage, nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage,
uint32_t aFlags) uint32_t aFlags)
: mForFrame(aForFrame), : mForFrame(aForFrame),
mImage(&aImage->FinalImage()),
mImageResolution(aImage->GetResolution()),
mType(mImage->tag),
mImageContainer(nullptr), mImageContainer(nullptr),
mGradientData(nullptr), mGradientData(nullptr),
mPaintServerFrame(nullptr), mPaintServerFrame(nullptr),
@ -57,12 +60,7 @@ nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage,
mSize(0, 0), mSize(0, 0),
mFlags(aFlags), mFlags(aFlags),
mExtendMode(ExtendMode::CLAMP), 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() { bool nsImageRenderer::PrepareImage() {
if (mImage->IsNone()) { if (mImage->IsNone()) {
@ -940,9 +938,8 @@ ImgDrawResult nsImageRenderer::DrawBorderImageComponent(
if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) { if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
ImgDrawResult result = nsLayoutUtils::DrawSingleImage( ImgDrawResult result = nsLayoutUtils::DrawSingleImage(
aRenderingContext, aPresContext, subImage, mImageResolution, aRenderingContext, aPresContext, subImage, samplingFilter, aFill,
samplingFilter, aFill, aDirtyRect, aDirtyRect, /* no SVGImageContext */ Nothing(), drawFlags);
/* no SVGImageContext */ Nothing(), drawFlags);
if (!mImage->IsComplete()) { if (!mImage->IsComplete()) {
result &= ImgDrawResult::SUCCESS_NOT_COMPLETE; result &= ImgDrawResult::SUCCESS_NOT_COMPLETE;
@ -1010,9 +1007,8 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
// rendered pixel has an alpha that precisely matches the alpha of the // rendered pixel has an alpha that precisely matches the alpha of the
// closest pixel in the image. // closest pixel in the image.
return nsLayoutUtils::DrawSingleImage( return nsLayoutUtils::DrawSingleImage(
aRenderingContext, aPresContext, mImageContainer, mImageResolution, aRenderingContext, aPresContext, mImageContainer, SamplingFilter::POINT,
SamplingFilter::POINT, dest, dest, Nothing(), drawFlags, nullptr, dest, dest, Nothing(), drawFlags);
nullptr);
} }
if (mImage->IsGradient()) { if (mImage->IsGradient()) {

Просмотреть файл

@ -299,7 +299,7 @@ class nsImageRenderer {
nsIFrame* mForFrame; nsIFrame* mForFrame;
const mozilla::StyleImage* mImage; const mozilla::StyleImage* mImage;
float mImageResolution; ImageResolution mImageResolution;
mozilla::StyleImage::Tag mType; mozilla::StyleImage::Tag mType;
nsCOMPtr<imgIContainer> mImageContainer; nsCOMPtr<imgIContainer> mImageContainer;
const mozilla::StyleGradient* mGradientData; const mozilla::StyleGradient* mGradientData;

Просмотреть файл

@ -30,6 +30,7 @@
# include "nsCSSPropertyID.h" # include "nsCSSPropertyID.h"
# include "nsCompatibility.h" # include "nsCompatibility.h"
# include "nsIURI.h" # include "nsIURI.h"
# include "mozilla/image/Resolution.h"
# include <atomic> # include <atomic>
struct RawServoAnimationValueTable; struct RawServoAnimationValueTable;

Просмотреть файл

@ -942,20 +942,16 @@ inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
} }
template <> template <>
inline std::pair<const StyleImage*, float> StyleImage::FinalImageAndResolution() ImageResolution StyleImage::GetResolution() const;
const {
if (!IsImageSet()) {
return {this, 1.0f};
}
auto& set = AsImageSet();
auto& selectedItem = set->items.AsSpan()[set->selected_index];
return {selectedItem.image.FinalImageAndResolution().first,
selectedItem.resolution._0};
}
template <> template <>
inline const StyleImage& StyleImage::FinalImage() const { inline const StyleImage& StyleImage::FinalImage() const {
return *FinalImageAndResolution().first; if (!IsImageSet()) {
return *this;
}
auto& set = AsImageSet();
auto& selectedItem = set->items.AsSpan()[set->selected_index];
return selectedItem.image.FinalImage();
} }
template <> template <>

Просмотреть файл

@ -1629,10 +1629,27 @@ void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) {
const_cast<StyleComputedImageUrl*>(url)->ResolveImage(aDoc, old); const_cast<StyleComputedImageUrl*>(url)->ResolveImage(aDoc, old);
} }
template <>
ImageResolution StyleImage::GetResolution() const {
if (IsImageSet()) {
auto& set = AsImageSet();
float r = set->items.AsSpan()[set->selected_index].resolution._0;
if (MOZ_LIKELY(r != 0.0f)) {
return ImageResolution(r, r);
}
} else if (imgRequestProxy* request = GetImageRequest()) {
RefPtr<imgIContainer> image;
request->GetImage(getter_AddRefs(image));
if (image) {
return image->GetResolution();
}
}
return {};
}
template <> template <>
Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const { Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const {
auto [finalImage, resolution] = FinalImageAndResolution(); imgRequestProxy* request = GetImageRequest();
imgRequestProxy* request = finalImage->GetImageRequest();
if (!request) { if (!request) {
return Nothing(); return Nothing();
} }
@ -1647,10 +1664,7 @@ Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const {
int32_t w = 0, h = 0; int32_t w = 0, h = 0;
image->GetWidth(&w); image->GetWidth(&w);
image->GetHeight(&h); image->GetHeight(&h);
if (resolution != 0.0f && resolution != 1.0f) { GetResolution().ApplyTo(w, h);
w = std::round(float(w) / resolution);
h = std::round(float(h) / resolution);
}
return Some(CSSIntSize{w, h}); return Some(CSSIntSize{w, h});
} }
@ -1909,9 +1923,9 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
bool hasWidth, hasHeight; bool hasWidth, hasHeight;
// We could bother getting the right resolution here but it doesn't matter // We could bother getting the right resolution here but it doesn't matter
// since we ignore `imageSize`. // since we ignore `imageSize`.
nsLayoutUtils::ComputeSizeForDrawing(imgContainer, nsLayoutUtils::ComputeSizeForDrawing(imgContainer, ImageResolution(),
/* aResolution = */ 1.0f, imageSize, imageSize, imageRatio, hasWidth,
imageRatio, hasWidth, hasHeight); hasHeight);
// If the image has a fixed width and height, rendering never depends on // If the image has a fixed width and height, rendering never depends on
// the frame size. // the frame size.

Просмотреть файл

@ -241,17 +241,21 @@ bool SVGImageFrame::GetIntrinsicImageDimensions(
return false; return false;
} }
ImageResolution resolution = mImageContainer->GetResolution();
int32_t width, height; int32_t width, height;
if (NS_FAILED(mImageContainer->GetWidth(&width))) { if (NS_FAILED(mImageContainer->GetWidth(&width))) {
aSize.width = -1; aSize.width = -1;
} else { } else {
aSize.width = width; aSize.width = width;
resolution.ApplyXTo(aSize.width);
} }
if (NS_FAILED(mImageContainer->GetHeight(&height))) { if (NS_FAILED(mImageContainer->GetHeight(&height))) {
aSize.height = -1; aSize.height = -1;
} else { } else {
aSize.height = height; aSize.height = height;
resolution.ApplyYTo(aSize.height);
} }
Maybe<AspectRatio> asp = mImageContainer->GetIntrinsicRatio(); Maybe<AspectRatio> asp = mImageContainer->GetIntrinsicRatio();
@ -272,6 +276,7 @@ bool SVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext,
nativeWidth == 0 || nativeHeight == 0) { nativeWidth == 0 || nativeHeight == 0) {
return false; return false;
} }
mImageContainer->GetResolution().ApplyTo(nativeWidth, nativeHeight);
imageTransform = GetRasterImageTransform(nativeWidth, nativeHeight) * imageTransform = GetRasterImageTransform(nativeWidth, nativeHeight) *
ToMatrix(aTransform); ToMatrix(aTransform);
@ -405,7 +410,7 @@ void SVGImageFrame::PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
// That method needs our image to have a fixed native width & height, // That method needs our image to have a fixed native width & height,
// and that's not always true for TYPE_VECTOR images. // and that's not always true for TYPE_VECTOR images.
aImgParams.result &= nsLayoutUtils::DrawSingleImage( aImgParams.result &= nsLayoutUtils::DrawSingleImage(
aContext, PresContext(), mImageContainer, /* aResolution = */ 1.0f, aContext, PresContext(), mImageContainer,
nsLayoutUtils::GetSamplingFilterForFrame(this), destRect, nsLayoutUtils::GetSamplingFilterForFrame(this), destRect,
aDirtyRect ? dirtyRect : destRect, context, flags); aDirtyRect ? dirtyRect : destRect, context, flags);
} else { // mImageContainer->GetType() == TYPE_RASTER } else { // mImageContainer->GetType() == TYPE_RASTER
@ -674,6 +679,7 @@ nsIFrame* SVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) {
nativeWidth == 0 || nativeHeight == 0) { nativeWidth == 0 || nativeHeight == 0) {
return nullptr; return nullptr;
} }
mImageContainer->GetResolution().ApplyTo(nativeWidth, nativeHeight);
Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform( Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
rect.width, rect.height, 0, 0, nativeWidth, nativeHeight, rect.width, rect.height, 0, 0, nativeWidth, nativeHeight,
element->mPreserveAspectRatio); element->mPreserveAspectRatio);

Просмотреть файл

@ -240,7 +240,6 @@ void nsImageBoxFrame::UpdateImage() {
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src); mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
mUseSrcAttr = !src.IsEmpty(); mUseSrcAttr = !src.IsEmpty();
if (mUseSrcAttr) { if (mUseSrcAttr) {
mImageResolution = 1.0f;
nsContentPolicyType contentPolicyType; nsContentPolicyType contentPolicyType;
nsCOMPtr<nsIPrincipal> triggeringPrincipal; nsCOMPtr<nsIPrincipal> triggeringPrincipal;
uint64_t requestContextID = 0; uint64_t requestContextID = 0;
@ -270,9 +269,7 @@ void nsImageBoxFrame::UpdateImage() {
} }
} }
} else if (auto* styleImage = GetImageFromStyle()) { } else if (auto* styleImage = GetImageFromStyle()) {
auto [finalImage, resolution] = styleImage->FinalImageAndResolution(); if (auto* styleRequest = styleImage->GetImageRequest()) {
mImageResolution = resolution;
if (auto* styleRequest = finalImage->GetImageRequest()) {
styleRequest->SyncClone(mListener, mContent->GetComposedDoc(), styleRequest->SyncClone(mListener, mContent->GetComposedDoc(),
getter_AddRefs(mImageRequest)); getter_AddRefs(mImageRequest));
} }
@ -394,7 +391,7 @@ ImgDrawResult nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
Maybe<SVGImageContext> svgContext; Maybe<SVGImageContext> svgContext;
SVGImageContext::MaybeStoreContextPaint(svgContext, this, imgCon); SVGImageContext::MaybeStoreContextPaint(svgContext, this, imgCon);
return nsLayoutUtils::DrawSingleImage( return nsLayoutUtils::DrawSingleImage(
aRenderingContext, PresContext(), imgCon, mImageResolution, aRenderingContext, PresContext(), imgCon,
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, dirty, svgContext, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, dirty, svgContext,
aFlags, anchorPoint.ptrOr(nullptr), hasSubRect ? &mSubRect : nullptr); aFlags, anchorPoint.ptrOr(nullptr), hasSubRect ? &mSubRect : nullptr);
} }
@ -610,11 +607,11 @@ bool nsImageBoxFrame::CanOptimizeToImageLayer() {
} }
const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle( const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle(
const ComputedStyle& aStyle) { const ComputedStyle& aStyle) const {
const nsStyleDisplay* disp = aStyle.StyleDisplay(); const nsStyleDisplay* disp = aStyle.StyleDisplay();
if (disp->HasAppearance()) { if (disp->HasAppearance()) {
nsPresContext* pc = PresContext(); nsPresContext* pc = PresContext();
if (pc->Theme()->ThemeSupportsWidget(pc, this, if (pc->Theme()->ThemeSupportsWidget(pc, const_cast<nsImageBoxFrame*>(this),
disp->EffectiveAppearance())) { disp->EffectiveAppearance())) {
return nullptr; return nullptr;
} }
@ -626,6 +623,21 @@ const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle(
return &image; return &image;
} }
ImageResolution nsImageBoxFrame::GetImageResolution() const {
if (auto* image = GetImageFromStyle()) {
return image->GetResolution();
}
if (!mImageRequest) {
return {};
}
nsCOMPtr<imgIContainer> image;
mImageRequest->GetImage(getter_AddRefs(image));
if (!image) {
return {};
}
return image->GetResolution();
}
/* virtual */ /* virtual */
void nsImageBoxFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) { void nsImageBoxFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
nsLeafBoxFrame::DidSetComputedStyle(aOldStyle); nsLeafBoxFrame::DidSetComputedStyle(aOldStyle);
@ -803,13 +815,10 @@ void nsImageBoxFrame::OnSizeAvailable(imgIRequest* aRequest,
aImage->GetWidth(&w); aImage->GetWidth(&w);
aImage->GetHeight(&h); aImage->GetHeight(&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)); mIntrinsicSize.SizeTo(CSSPixel::ToAppUnits(w), CSSPixel::ToAppUnits(h));
GetImageResolution().ApplyTo(mIntrinsicSize.width, mIntrinsicSize.height);
if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange, PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange,
NS_FRAME_IS_DIRTY); NS_FRAME_IS_DIRTY);

Просмотреть файл

@ -78,11 +78,13 @@ class nsImageBoxFrame final : public nsLeafBoxFrame {
* *
* TODO(emilio): Maybe support list-style-image: linear-gradient() etc? * TODO(emilio): Maybe support list-style-image: linear-gradient() etc?
*/ */
const mozilla::StyleImage* GetImageFromStyle(const ComputedStyle&); const mozilla::StyleImage* GetImageFromStyle(const ComputedStyle&) const;
const mozilla::StyleImage* GetImageFromStyle() { const mozilla::StyleImage* GetImageFromStyle() const {
return GetImageFromStyle(*Style()); return GetImageFromStyle(*Style());
} }
mozilla::ImageResolution GetImageResolution() const;
/** /**
* Update mUseSrcAttr from appropriate content attributes or from * Update mUseSrcAttr from appropriate content attributes or from
* style, throw away the current image, and load the appropriate * style, throw away the current image, and load the appropriate
@ -141,7 +143,6 @@ class nsImageBoxFrame final : public nsLeafBoxFrame {
nsSize mImageSize; nsSize mImageSize;
RefPtr<imgRequestProxy> mImageRequest; RefPtr<imgRequestProxy> mImageRequest;
float mImageResolution = 1.0f;
nsCOMPtr<imgINotificationObserver> mListener; nsCOMPtr<imgINotificationObserver> mListener;
int32_t mLoadFlags; int32_t mLoadFlags;

Просмотреть файл

@ -791,12 +791,11 @@ renaming_overrides_prefixing = true
"GenericImage" = """ "GenericImage" = """
public: public:
// Returns the final image we've selected taken from the image-set, along with // Returns the intrinsic resolution of the image.
// 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 // The resolution is in dppx, and should be used to impact the intrinsic
// of the image. // size of the image.
std::pair<const StyleGenericImage*, float> FinalImageAndResolution() const; ImageResolution GetResolution() const;
// Returns the intrinsic size of the image, if there's one, accounting for // Returns the intrinsic size of the image, if there's one, accounting for
// resolution as needed. // resolution as needed.

Просмотреть файл

@ -0,0 +1 @@
prefs: [image.exif-density-correction.enabled:true]

Просмотреть файл

@ -1,4 +0,0 @@
[density-corrected-image-in-canvas.html]
[Density corrected size: canvas]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-image-svg-aspect-ratio.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-image-svg.html]
expected: FAIL

Просмотреть файл

@ -1,4 +0,0 @@
[density-corrected-natural-size.html]
[density-corrected-natural-size]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-size-bg.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-size-img.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-size-pseudo-elements.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[density-corrected-various-elements.html]
expected: FAIL

Просмотреть файл

@ -925,7 +925,7 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) {
IntSize customCursorSize; IntSize customCursorSize;
int32_t stride = 0; int32_t stride = 0;
auto format = SurfaceFormat::B8G8R8A8; auto format = SurfaceFormat::B8G8R8A8;
float resolution = aCursor.mResolution; ImageResolution resolution = aCursor.mResolution;
if (aCursor.IsCustom()) { if (aCursor.IsCustom()) {
int32_t width = 0, height = 0; int32_t width = 0, height = 0;
aCursor.mContainer->GetWidth(&width); aCursor.mContainer->GetWidth(&width);
@ -936,9 +936,8 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) {
if (width && height && if (width && height &&
aCursor.mContainer->GetType() == imgIContainer::TYPE_VECTOR) { aCursor.mContainer->GetType() == imgIContainer::TYPE_VECTOR) {
// For vector images, scale to device pixels. // For vector images, scale to device pixels.
resolution *= GetDefaultScale().scale; resolution.ScaleBy(GetDefaultScale().scale);
width = std::ceil(width * resolution); resolution.ApplyInverseTo(width, height);
height = std::ceil(height * resolution);
surface = aCursor.mContainer->GetFrameAtSize( surface = aCursor.mContainer->GetFrameAtSize(
{width, height}, {width, height},
imgIContainer::FRAME_CURRENT, flags); imgIContainer::FRAME_CURRENT, flags);
@ -964,8 +963,9 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) {
length); length);
if (!mBrowserChild->SendSetCursor( if (!mBrowserChild->SendSetCursor(
aCursor.mDefaultCursor, hasCustomCursor, cursorData, aCursor.mDefaultCursor, hasCustomCursor, cursorData,
customCursorSize.width, customCursorSize.height, resolution, customCursorSize.width, customCursorSize.height,
stride, format, aCursor.mHotspotX, aCursor.mHotspotY, force)) { resolution.mX, resolution.mY, stride, format,
aCursor.mHotspotX, aCursor.mHotspotY, force)) {
return; return;
} }
mCursor = aCursor; mCursor = aCursor;

Просмотреть файл

@ -2351,8 +2351,9 @@ static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
// factor and then tell gtk to scale it down. We ensure to scale at least to // factor and then tell gtk to scale it down. We ensure to scale at least to
// the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland, // the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland,
// see bug 1707533. // see bug 1707533.
int32_t gtkScale = int32_t gtkScale = std::max(
std::max(aWidgetScaleFactor, int32_t(std::ceil(aCursor.mResolution))); aWidgetScaleFactor, int32_t(std::ceil(std::max(aCursor.mResolution.mX,
aCursor.mResolution.mY))));
// Reject cursors greater than 128 pixels in some direction, to prevent // Reject cursors greater than 128 pixels in some direction, to prevent
// spoofing. // spoofing.

Просмотреть файл

@ -529,10 +529,7 @@ nsIntSize nsIWidget::CustomCursorSize(const Cursor& aCursor) {
int32_t height = 0; int32_t height = 0;
aCursor.mContainer->GetWidth(&width); aCursor.mContainer->GetWidth(&width);
aCursor.mContainer->GetHeight(&height); aCursor.mContainer->GetHeight(&height);
if (aCursor.mResolution != 0.0f && aCursor.mResolution != 1.0f) { aCursor.mResolution.ApplyTo(width, height);
width = std::round(float(width) / aCursor.mResolution);
height = std::round(float(height) / aCursor.mResolution);
}
return {width, height}; return {width, height};
} }

Просмотреть файл

@ -23,6 +23,7 @@
#include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/ScrollableLayerGuid.h" #include "mozilla/layers/ScrollableLayerGuid.h"
#include "mozilla/layers/ZoomConstraints.h" #include "mozilla/layers/ZoomConstraints.h"
#include "mozilla/image/Resolution.h"
#include "mozilla/widget/IMEData.h" #include "mozilla/widget/IMEData.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsColor.h" #include "nsColor.h"
@ -992,7 +993,7 @@ class nsIWidget : public nsISupports {
nsCOMPtr<imgIContainer> mContainer; nsCOMPtr<imgIContainer> mContainer;
uint32_t mHotspotX = 0; uint32_t mHotspotX = 0;
uint32_t mHotspotY = 0; uint32_t mHotspotY = 0;
float mResolution = 1.0f; mozilla::ImageResolution mResolution;
bool IsCustom() const { return !!mContainer; } bool IsCustom() const { return !!mContainer; }
@ -1003,7 +1004,7 @@ class nsIWidget : public nsISupports {
mResolution == aOther.mResolution; mResolution == aOther.mResolution;
} }
bool operator!=(const Cursor& aOther) { return !(*this == aOther); } bool operator!=(const Cursor& aOther) const { return !(*this == aOther); }
}; };
/** /**