From 1cdf34486012f772d929cdc75c3c86f008050ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 5 May 2021 09:41:24 +0000 Subject: [PATCH] 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 --- dom/base/PointerLockManager.cpp | 2 +- dom/base/nsGlobalWindowOuter.cpp | 2 +- dom/base/nsImageLoadingContent.cpp | 26 ----- dom/base/nsImageLoadingContent.h | 3 - dom/events/EventStateManager.cpp | 19 ++-- dom/events/EventStateManager.h | 6 +- dom/html/HTMLImageElement.cpp | 41 ++++--- dom/html/HTMLImageElement.h | 7 +- dom/ipc/BrowserParent.cpp | 10 +- dom/ipc/BrowserParent.h | 7 +- dom/ipc/PBrowser.ipdl | 9 +- image/Resolution.h | 9 ++ layout/base/nsLayoutUtils.cpp | 33 +++--- layout/base/nsLayoutUtils.h | 27 +++-- layout/generic/nsImageFrame.cpp | 103 +++++++++--------- layout/generic/nsImageFrame.h | 7 +- layout/painting/nsImageRenderer.cpp | 20 ++-- layout/painting/nsImageRenderer.h | 2 +- layout/style/ServoStyleConstsForwards.h | 1 + layout/style/ServoStyleConstsInlines.h | 18 ++- layout/style/nsStyleStruct.cpp | 32 ++++-- layout/svg/SVGImageFrame.cpp | 8 +- layout/xul/nsImageBoxFrame.cpp | 33 ++++-- layout/xul/nsImageBoxFrame.h | 7 +- servo/ports/geckolib/cbindgen.toml | 9 +- .../meta/density-size-correction/__dir__.ini | 1 + ...density-corrected-image-in-canvas.html.ini | 4 - ...-corrected-image-svg-aspect-ratio.html.ini | 2 - .../density-corrected-image-svg.html.ini | 2 - .../density-corrected-natural-size.html.ini | 4 - .../density-corrected-size-bg.html.ini | 2 - .../density-corrected-size-img.html.ini | 2 - ...ty-corrected-size-pseudo-elements.html.ini | 2 - ...ensity-corrected-various-elements.html.ini | 2 - widget/PuppetWidget.cpp | 12 +- widget/gtk/nsWindow.cpp | 5 +- widget/nsBaseWidget.cpp | 5 +- widget/nsIWidget.h | 5 +- 38 files changed, 245 insertions(+), 244 deletions(-) create mode 100644 testing/web-platform/meta/density-size-correction/__dir__.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-image-in-canvas.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-image-svg-aspect-ratio.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-image-svg.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-natural-size.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-size-bg.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-size-img.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-size-pseudo-elements.html.ini delete mode 100644 testing/web-platform/meta/density-size-correction/density-corrected-various-elements.html.ini diff --git a/dom/base/PointerLockManager.cpp b/dom/base/PointerLockManager.cpp index ecfbb6a8d88d..770b1c9ebe40 100644 --- a/dom/base/PointerLockManager.cpp +++ b/dom/base/PointerLockManager.cpp @@ -288,7 +288,7 @@ bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument, // Hide the cursor and set pointer lock for future mouse events RefPtr esm = presContext->EventStateManager(); - esm->SetCursor(aCursorStyle, nullptr, 1.0f, Nothing(), widget, true); + esm->SetCursor(aCursorStyle, nullptr, {}, Nothing(), widget, true); EventStateManager::SetPointerLock(widget, aElement); return true; diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index f9cc9927520f..f0fe9f0629bd 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -7426,7 +7426,7 @@ void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor, // Call esm and set cursor. aError = presContext->EventStateManager()->SetCursor( - cursor, nullptr, 1.0f, Nothing(), widget, true); + cursor, nullptr, {}, Nothing(), widget, true); } } diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 9ec94edd6afa..27df92b40af8 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -1216,32 +1216,6 @@ void nsImageLoadingContent::ForceImageState(bool aForce, mForcedImageState = EventStates(aState); } -uint32_t nsImageLoadingContent::NaturalWidth() { - nsCOMPtr 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 image; - if (mCurrentRequest) { - mCurrentRequest->GetImage(getter_AddRefs(image)); - } - - int32_t size = 0; - if (image) { - Unused << image->GetHeight(&size); - } - return size; -} - CSSIntSize nsImageLoadingContent::GetWidthHeightForImage() { Element* element = AsContent()->AsElement(); if (nsIFrame* frame = element->GetPrimaryFrame(FlushType::Layout)) { diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index ec4286bed950..fc78872eb593 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -232,9 +232,6 @@ class nsImageLoadingContent : public nsIImageLoadingContent { // want a non-const nsIContent. 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 * attributes are unset. diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 95849a8709e3..43ed87383cb1 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -3906,7 +3906,7 @@ void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) { struct CursorImage { gfx::IntPoint mHotspot; nsCOMPtr mContainer; - float mResolution = 1.0f; + ImageResolution mResolution; bool mEarlierCursorLoading = false; }; @@ -3934,10 +3934,7 @@ static bool ShouldBlockCustomCursor(nsPresContext* aPresContext, int32_t height = 0; aCursor.mContainer->GetWidth(&width); aCursor.mContainer->GetHeight(&height); - if (aCursor.mResolution != 0.0f && aCursor.mResolution != 1.0f) { - width = std::round(width / aCursor.mResolution); - height = std::round(height / aCursor.mResolution); - } + aCursor.mResolution.ApplyTo(width, height); int32_t maxSize = StaticPrefs::layout_cursor_block_max_size(); @@ -4010,8 +4007,7 @@ static CursorImage ComputeCustomCursor(nsPresContext* aPresContext, MOZ_ASSERT(image.image.IsImageRequestType(), "Cursor image should only parse url() types"); uint32_t status; - auto [finalImage, resolution] = image.image.FinalImageAndResolution(); - imgRequestProxy* req = finalImage->GetImageRequest(); + imgRequestProxy* req = image.image.GetImageRequest(); if (!req || NS_FAILED(req->GetImageStatus(&status))) { continue; } @@ -4033,14 +4029,15 @@ static CursorImage ComputeCustomCursor(nsPresContext* aPresContext, image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y}) : Nothing(); 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)) { continue; } // This is the one we want! return result; } - return {{}, nullptr, 1.0f, loading}; + return {{}, nullptr, {}, loading}; } void EventStateManager::UpdateCursor(nsPresContext* aPresContext, @@ -4053,7 +4050,7 @@ void EventStateManager::UpdateCursor(nsPresContext* aPresContext, auto cursor = StyleCursorKind::Default; nsCOMPtr container; - float resolution = 1.0f; + ImageResolution resolution; Maybe hotspot; // If cursor is locked just use the locked one @@ -4138,7 +4135,7 @@ void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) { nsresult EventStateManager::SetCursor(StyleCursorKind aCursor, imgIContainer* aContainer, - float aResolution, + const ImageResolution& aResolution, const Maybe& aHotspot, nsIWidget* aWidget, bool aLockCursor) { EnsureDocument(mPresContext); diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index 75f097beba52..4a73ee5412a3 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -243,9 +243,9 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver { bool CheckIfEventMatchesAccessKey(WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext); - nsresult SetCursor(StyleCursorKind aCursor, imgIContainer* aContainer, - float aResolution, const Maybe& aHotspot, - nsIWidget* aWidget, bool aLockCursor); + nsresult SetCursor(StyleCursorKind, imgIContainer*, const ImageResolution&, + const Maybe& aHotspot, nsIWidget* aWidget, + bool aLockCursor); /** * Checks if the current mouse over element matches the given diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index e0ec18c528d0..2a4874b19524 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -710,28 +710,33 @@ uint32_t HTMLImageElement::Height() { return GetWidthHeightForImage().height; } uint32_t HTMLImageElement::Width() { return GetWidthHeightForImage().width; } -uint32_t HTMLImageElement::NaturalHeight() { - uint32_t height = nsImageLoadingContent::NaturalHeight(); - - if (mResponsiveSelector) { - double density = mResponsiveSelector->GetSelectedImageDensity(); - MOZ_ASSERT(density >= 0.0); - height = NSToIntRound(double(height) / density); +nsIntSize HTMLImageElement::NaturalSize() { + if (!mCurrentRequest) { + return {}; } - return height; -} - -uint32_t HTMLImageElement::NaturalWidth() { - uint32_t width = nsImageLoadingContent::NaturalWidth(); - - if (mResponsiveSelector) { - double density = mResponsiveSelector->GetSelectedImageDensity(); - MOZ_ASSERT(density >= 0.0); - width = NSToIntRound(double(width) / density); + nsCOMPtr image; + mCurrentRequest->GetImage(getter_AddRefs(image)); + if (!image) { + return {}; } - 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) { diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h index 8d78b466f999..6464ff7d0847 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -97,8 +97,11 @@ class HTMLImageElement final : public nsGenericHTMLElement, void SetHeight(uint32_t aHeight, ErrorResult& 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(); uint32_t Hspace() { return GetDimensionAttrAsUnsignedInt(nsGkAtoms::hspace, 0); diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 162971cf54c1..d5e806fef99c 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -2183,7 +2183,8 @@ mozilla::ipc::IPCResult BrowserParent::RecvAsyncMessage( mozilla::ipc::IPCResult BrowserParent::RecvSetCursor( const nsCursor& aCursor, const bool& aHasCustomCursor, 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 uint32_t& aHotspotY, const bool& aForce) { nsCOMPtr widget = GetWidget(); @@ -2212,8 +2213,11 @@ mozilla::ipc::IPCResult BrowserParent::RecvSetCursor( cursorImage = image::ImageOps::CreateFromDrawable(drawable); } - mCursor = nsIWidget::Cursor{aCursor, std::move(cursorImage), aHotspotX, - aHotspotY, aResolution}; + mCursor = nsIWidget::Cursor{aCursor, + std::move(cursorImage), + aHotspotX, + aHotspotY, + {aResolutionX, aResolutionY}}; if (!mRemoteTargetSetsCursor) { return IPC_OK(); } diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index fd42bd41dcf0..92c609d41232 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -386,9 +386,10 @@ class BrowserParent final : public PBrowserParent, mozilla::ipc::IPCResult RecvSetCursor( const nsCursor& aValue, const bool& aHasCustomCursor, const nsCString& aCursorData, const uint32_t& aWidth, - const uint32_t& aHeight, const float& aResolution, - const uint32_t& aStride, const gfx::SurfaceFormat& aFormat, - const uint32_t& aHotspotX, const uint32_t& aHotspotY, const bool& aForce); + const uint32_t& aHeight, const float& aResolutionX, + const float& aResolutionY, const uint32_t& aStride, + const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX, + const uint32_t& aHotspotY, const bool& aForce); mozilla::ipc::IPCResult RecvSetLinkStatus(const nsString& aStatus); diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 2e24fa6d8230..332b18fc6ecc 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -389,8 +389,10 @@ parent: * Width of the image. * @param height * Height of the image. - * @param resolution - * Resolution of the image in dppx units. + * @param resolutionX + * Resolution of the image X axis in dppx units. + * @param resolutionY + * Resolution of the image Y axis in dppx units. * @param stride * Stride used in the image data. * @param format @@ -407,7 +409,8 @@ parent: bool hasCustomCursor, nsCString customCursorData, 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); /** diff --git a/image/Resolution.h b/image/Resolution.h index 363af6dc5e61..d62022f67272 100644 --- a/image/Resolution.h +++ b/image/Resolution.h @@ -63,6 +63,15 @@ struct Resolution { ApplyXTo(aWidth); 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 diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 81ed7670f5a0..0128c1eff018 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6294,6 +6294,8 @@ ImgDrawResult nsLayoutUtils::DrawSingleUnscaledImage( CSSIntSize imageSize; aImage->GetWidth(&imageSize.width); aImage->GetHeight(&imageSize.height); + aImage->GetResolution().ApplyTo(imageSize.width, imageSize.height); + if (imageSize.width < 1 || imageSize.height < 1) { NS_WARNING("Image width or height is non-positive"); return ImgDrawResult::TEMPORARY_ERROR; @@ -6321,13 +6323,15 @@ ImgDrawResult nsLayoutUtils::DrawSingleUnscaledImage( /* static */ ImgDrawResult nsLayoutUtils::DrawSingleImage( gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, - float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest, - const nsRect& aDirty, const Maybe& aSVGContext, - uint32_t aImageFlags, const nsPoint* aAnchorPoint, - const nsRect* aSourceArea) { + SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty, + const Maybe& aSVGContext, uint32_t aImageFlags, + const nsPoint* aAnchorPoint, const nsRect* aSourceArea) { nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel(); - CSSIntSize pixelImageSize( - ComputeSizeForDrawingWithFallback(aImage, aResolution, aDest.Size())); + // NOTE(emilio): We can hardcode resolution to 1 here, since we're interested + // 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) { NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0, "Image width or height is negative"); @@ -6368,7 +6372,7 @@ ImgDrawResult nsLayoutUtils::DrawSingleImage( /* static */ void nsLayoutUtils::ComputeSizeForDrawing( - imgIContainer* aImage, float aResolution, + imgIContainer* aImage, const ImageResolution& aResolution, /* outparam */ CSSIntSize& aImageSize, /* outparam */ AspectRatio& aIntrinsicRatio, /* outparam */ bool& aGotWidth, @@ -6378,13 +6382,11 @@ void nsLayoutUtils::ComputeSizeForDrawing( Maybe 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) { + aResolution.ApplyXTo(aImageSize.width); + } + if (aGotHeight) { + aResolution.ApplyYTo(aImageSize.height); } if (!(aGotWidth && aGotHeight) && intrinsicRatio.isNothing()) { @@ -6397,7 +6399,8 @@ void nsLayoutUtils::ComputeSizeForDrawing( /* static */ CSSIntSize nsLayoutUtils::ComputeSizeForDrawingWithFallback( - imgIContainer* aImage, float aResolution, const nsSize& aFallbackSize) { + imgIContainer* aImage, const ImageResolution& aResolution, + const nsSize& aFallbackSize) { CSSIntSize imageSize; AspectRatio imageRatio; bool gotHeight, gotWidth; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 47477cbf3b86..4ab474cf0de5 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -103,6 +103,9 @@ namespace gfx { struct RectCornerRadii; enum class ShapedTextFlags : uint16_t; } // namespace gfx +namespace image { +struct Resolution; +} namespace layers { struct FrameMetrics; struct ScrollMetadata; @@ -1901,11 +1904,6 @@ 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. @@ -1927,9 +1925,9 @@ class nsLayoutUtils { */ static ImgDrawResult DrawSingleImage( gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, - float aResolution, SamplingFilter aSamplingFilter, const nsRect& aDest, - const nsRect& aDirty, const mozilla::Maybe& aSVGContext, - uint32_t aImageFlags, const nsPoint* aAnchorPoint = nullptr, + SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty, + const mozilla::Maybe& aSVGContext, uint32_t aImageFlags, + const nsPoint* aAnchorPoint = nullptr, const nsRect* aSourceArea = nullptr); /** @@ -1947,8 +1945,16 @@ class nsLayoutUtils { * NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The * difference is that this one is simpler and is suited to places where we * 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, AspectRatio& aIntrinsicRatio, bool& aGotWidth, bool& aGotHeight); @@ -1962,7 +1968,8 @@ class nsLayoutUtils { * dimensions, the corresponding dimension of aFallbackSize is used instead. */ 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 diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 0b72bbc2e816..3f9609973c28 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -356,6 +356,38 @@ static bool SizeIsAvailable(imgIRequest* aRequest) { 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(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, nsIFrame* aPrevInFlow) { MOZ_ASSERT_IF(aPrevInFlow, @@ -378,33 +410,11 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, // that it can register images. imageLoader->FrameCreated(this); } else { - uint32_t contentIndex = 0; - const nsStyleContent* styleContent = StyleContent(); - 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(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(), + const StyleImage* image = GetImageFromStyle(); + MOZ_ASSERT(image->IsImageRequestType(), "Content image should only parse url() type"); - auto [finalImage, resolution] = image.FinalImageAndResolution(); Document* doc = PresContext()->Document(); - if (imgRequestProxy* proxy = finalImage->GetImageRequest()) { - mContentURLRequestResolution = resolution; + if (imgRequestProxy* proxy = image->GetImageRequest()) { proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest)); SetupForContentURLRequest(); } @@ -457,34 +467,27 @@ void nsImageFrame::SetupForContentURLRequest() { } static void ScaleIntrinsicSizeForDensity(IntrinsicSize& aSize, - double aDensity) { - if (aDensity == 1.0) { - return; - } - + const ImageResolution& aResolution) { if (aSize.width) { - aSize.width = Some(NSToCoordRound(double(*aSize.width) / aDensity)); + aResolution.ApplyXTo(aSize.width.ref()); } 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) { - auto* image = HTMLImageElement::FromNode(aContent); - if (!image) { - return; + if (auto* image = HTMLImageElement::FromNode(aContent)) { + if (auto* selector = image->GetResponsiveImageSelector()) { + float density = selector->GetSelectedImageDensity(); + MOZ_ASSERT(density >= 0.0); + ScaleIntrinsicSizeForDensity(aSize, ImageResolution{density, density}); + return; + } } - - ResponsiveImageSelector* selector = image->GetResponsiveImageSelector(); - if (!selector) { - return; - } - - double density = selector->GetSelectedImageDensity(); - MOZ_ASSERT(density >= 0.0); - ScaleIntrinsicSizeForDensity(aSize, density); + ScaleIntrinsicSizeForDensity(aSize, aImage->GetResolution()); } static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage, @@ -502,10 +505,10 @@ static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage, intrinsicSize.width = size.width == -1 ? Nothing() : Some(size.width); intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height); if (aKind == nsImageFrame::Kind::ImageElement) { - ScaleIntrinsicSizeForDensity(*aFrame.GetContent(), intrinsicSize); + ScaleIntrinsicSizeForDensity(aImage, *aFrame.GetContent(), intrinsicSize); } else { ScaleIntrinsicSizeForDensity(intrinsicSize, - aFrame.GetContentURLRequestResolution()); + aFrame.GetImageFromStyle()->GetResolution()); } return intrinsicSize; } @@ -1486,7 +1489,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext, nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size, size); result = nsLayoutUtils::DrawSingleImage( - aRenderingContext, PresContext(), imgCon, /* aResolution = */ 1.0f, + aRenderingContext, PresContext(), imgCon, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect, /* no SVGImageContext */ Nothing(), aFlags); } @@ -2090,10 +2093,8 @@ ImgDrawResult nsImageFrame::PaintImage(gfxContext& aRenderingContext, Maybe 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, /* aResolution = */ 1.0f, + aRenderingContext, PresContext(), aImage, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect, svgContext, flags, &anchorPoint); diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 3bc90ecafb26..8b7908ae867f 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -103,11 +103,7 @@ 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; - } + const mozilla::StyleImage* GetImageFromStyle() const; #ifdef ACCESSIBILITY mozilla::a11y::AccType AccessibleType() override; @@ -359,7 +355,6 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback { // An image request created for content: url(..). RefPtr mContentURLRequest; - float mContentURLRequestResolution = 1.0f; nsCOMPtr mImage; nsCOMPtr mPrevImage; diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp index f32d50a2c808..1acada47b6a9 100644 --- a/layout/painting/nsImageRenderer.cpp +++ b/layout/painting/nsImageRenderer.cpp @@ -50,6 +50,9 @@ nsSize CSSSizeOrRatio::ComputeConcreteSize() const { nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage, uint32_t aFlags) : mForFrame(aForFrame), + mImage(&aImage->FinalImage()), + mImageResolution(aImage->GetResolution()), + mType(mImage->tag), mImageContainer(nullptr), mGradientData(nullptr), mPaintServerFrame(nullptr), @@ -57,12 +60,7 @@ nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage, mSize(0, 0), mFlags(aFlags), mExtendMode(ExtendMode::CLAMP), - mMaskOp(StyleMaskMode::MatchSource) { - auto pair = aImage->FinalImageAndResolution(); - mImage = pair.first; - mType = mImage->tag; - mImageResolution = pair.second; -} + mMaskOp(StyleMaskMode::MatchSource) {} bool nsImageRenderer::PrepareImage() { if (mImage->IsNone()) { @@ -940,9 +938,8 @@ ImgDrawResult nsImageRenderer::DrawBorderImageComponent( if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) { ImgDrawResult result = nsLayoutUtils::DrawSingleImage( - aRenderingContext, aPresContext, subImage, mImageResolution, - samplingFilter, aFill, aDirtyRect, - /* no SVGImageContext */ Nothing(), drawFlags); + aRenderingContext, aPresContext, subImage, samplingFilter, aFill, + aDirtyRect, /* no SVGImageContext */ Nothing(), drawFlags); if (!mImage->IsComplete()) { 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 // closest pixel in the image. return nsLayoutUtils::DrawSingleImage( - aRenderingContext, aPresContext, mImageContainer, mImageResolution, - SamplingFilter::POINT, dest, dest, Nothing(), drawFlags, nullptr, - nullptr); + aRenderingContext, aPresContext, mImageContainer, SamplingFilter::POINT, + dest, dest, Nothing(), drawFlags); } if (mImage->IsGradient()) { diff --git a/layout/painting/nsImageRenderer.h b/layout/painting/nsImageRenderer.h index fcff08d181e3..06eaa22ec30b 100644 --- a/layout/painting/nsImageRenderer.h +++ b/layout/painting/nsImageRenderer.h @@ -299,7 +299,7 @@ class nsImageRenderer { nsIFrame* mForFrame; const mozilla::StyleImage* mImage; - float mImageResolution; + ImageResolution mImageResolution; mozilla::StyleImage::Tag mType; nsCOMPtr mImageContainer; const mozilla::StyleGradient* mGradientData; diff --git a/layout/style/ServoStyleConstsForwards.h b/layout/style/ServoStyleConstsForwards.h index 58720ffb6baa..b830dfe7b666 100644 --- a/layout/style/ServoStyleConstsForwards.h +++ b/layout/style/ServoStyleConstsForwards.h @@ -30,6 +30,7 @@ # include "nsCSSPropertyID.h" # include "nsCompatibility.h" # include "nsIURI.h" +# include "mozilla/image/Resolution.h" # include struct RawServoAnimationValueTable; diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h index 8a344472fae4..33746e83a38c 100644 --- a/layout/style/ServoStyleConstsInlines.h +++ b/layout/style/ServoStyleConstsInlines.h @@ -942,20 +942,16 @@ inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const { } template <> -inline std::pair StyleImage::FinalImageAndResolution() - 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}; -} +ImageResolution StyleImage::GetResolution() const; template <> 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 <> diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 49fd1944f1e5..907e2d191b21 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1629,10 +1629,27 @@ void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) { const_cast(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 image; + request->GetImage(getter_AddRefs(image)); + if (image) { + return image->GetResolution(); + } + } + return {}; +} + template <> Maybe StyleImage::GetIntrinsicSize() const { - auto [finalImage, resolution] = FinalImageAndResolution(); - imgRequestProxy* request = finalImage->GetImageRequest(); + imgRequestProxy* request = GetImageRequest(); if (!request) { return Nothing(); } @@ -1647,10 +1664,7 @@ Maybe StyleImage::GetIntrinsicSize() const { 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); - } + GetResolution().ApplyTo(w, h); return Some(CSSIntSize{w, h}); } @@ -1909,9 +1923,9 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize, bool 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); + nsLayoutUtils::ComputeSizeForDrawing(imgContainer, ImageResolution(), + imageSize, imageRatio, hasWidth, + hasHeight); // If the image has a fixed width and height, rendering never depends on // the frame size. diff --git a/layout/svg/SVGImageFrame.cpp b/layout/svg/SVGImageFrame.cpp index 4c4e63c44ad7..ed0695c2f5f9 100644 --- a/layout/svg/SVGImageFrame.cpp +++ b/layout/svg/SVGImageFrame.cpp @@ -241,17 +241,21 @@ bool SVGImageFrame::GetIntrinsicImageDimensions( return false; } + ImageResolution resolution = mImageContainer->GetResolution(); + int32_t width, height; if (NS_FAILED(mImageContainer->GetWidth(&width))) { aSize.width = -1; } else { aSize.width = width; + resolution.ApplyXTo(aSize.width); } if (NS_FAILED(mImageContainer->GetHeight(&height))) { aSize.height = -1; } else { aSize.height = height; + resolution.ApplyYTo(aSize.height); } Maybe asp = mImageContainer->GetIntrinsicRatio(); @@ -272,6 +276,7 @@ bool SVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext, nativeWidth == 0 || nativeHeight == 0) { return false; } + mImageContainer->GetResolution().ApplyTo(nativeWidth, nativeHeight); imageTransform = GetRasterImageTransform(nativeWidth, nativeHeight) * 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, // and that's not always true for TYPE_VECTOR images. aImgParams.result &= nsLayoutUtils::DrawSingleImage( - aContext, PresContext(), mImageContainer, /* aResolution = */ 1.0f, + aContext, PresContext(), mImageContainer, nsLayoutUtils::GetSamplingFilterForFrame(this), destRect, aDirtyRect ? dirtyRect : destRect, context, flags); } else { // mImageContainer->GetType() == TYPE_RASTER @@ -674,6 +679,7 @@ nsIFrame* SVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) { nativeWidth == 0 || nativeHeight == 0) { return nullptr; } + mImageContainer->GetResolution().ApplyTo(nativeWidth, nativeHeight); Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform( rect.width, rect.height, 0, 0, nativeWidth, nativeHeight, element->mPreserveAspectRatio); diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index ee3e91cbed3a..d72388230f46 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -240,7 +240,6 @@ void nsImageBoxFrame::UpdateImage() { mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src); mUseSrcAttr = !src.IsEmpty(); if (mUseSrcAttr) { - mImageResolution = 1.0f; nsContentPolicyType contentPolicyType; nsCOMPtr triggeringPrincipal; uint64_t requestContextID = 0; @@ -270,9 +269,7 @@ void nsImageBoxFrame::UpdateImage() { } } } else if (auto* styleImage = GetImageFromStyle()) { - auto [finalImage, resolution] = styleImage->FinalImageAndResolution(); - mImageResolution = resolution; - if (auto* styleRequest = finalImage->GetImageRequest()) { + if (auto* styleRequest = styleImage->GetImageRequest()) { styleRequest->SyncClone(mListener, mContent->GetComposedDoc(), getter_AddRefs(mImageRequest)); } @@ -394,7 +391,7 @@ ImgDrawResult nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext, Maybe svgContext; SVGImageContext::MaybeStoreContextPaint(svgContext, this, imgCon); return nsLayoutUtils::DrawSingleImage( - aRenderingContext, PresContext(), imgCon, mImageResolution, + aRenderingContext, PresContext(), imgCon, nsLayoutUtils::GetSamplingFilterForFrame(this), dest, dirty, svgContext, aFlags, anchorPoint.ptrOr(nullptr), hasSubRect ? &mSubRect : nullptr); } @@ -610,11 +607,11 @@ bool nsImageBoxFrame::CanOptimizeToImageLayer() { } const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle( - const ComputedStyle& aStyle) { + const ComputedStyle& aStyle) const { const nsStyleDisplay* disp = aStyle.StyleDisplay(); if (disp->HasAppearance()) { nsPresContext* pc = PresContext(); - if (pc->Theme()->ThemeSupportsWidget(pc, this, + if (pc->Theme()->ThemeSupportsWidget(pc, const_cast(this), disp->EffectiveAppearance())) { return nullptr; } @@ -626,6 +623,21 @@ const mozilla::StyleImage* nsImageBoxFrame::GetImageFromStyle( return ℑ } +ImageResolution nsImageBoxFrame::GetImageResolution() const { + if (auto* image = GetImageFromStyle()) { + return image->GetResolution(); + } + if (!mImageRequest) { + return {}; + } + nsCOMPtr image; + mImageRequest->GetImage(getter_AddRefs(image)); + if (!image) { + return {}; + } + return image->GetResolution(); +} + /* virtual */ void nsImageBoxFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) { nsLeafBoxFrame::DidSetComputedStyle(aOldStyle); @@ -803,13 +815,10 @@ void nsImageBoxFrame::OnSizeAvailable(imgIRequest* aRequest, aImage->GetWidth(&w); 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)); + GetImageResolution().ApplyTo(mIntrinsicSize.width, mIntrinsicSize.height); + if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange, NS_FRAME_IS_DIRTY); diff --git a/layout/xul/nsImageBoxFrame.h b/layout/xul/nsImageBoxFrame.h index 75d25691ad3e..1e482d94d842 100644 --- a/layout/xul/nsImageBoxFrame.h +++ b/layout/xul/nsImageBoxFrame.h @@ -78,11 +78,13 @@ class nsImageBoxFrame final : public nsLeafBoxFrame { * * TODO(emilio): Maybe support list-style-image: linear-gradient() etc? */ - const mozilla::StyleImage* GetImageFromStyle(const ComputedStyle&); - const mozilla::StyleImage* GetImageFromStyle() { + const mozilla::StyleImage* GetImageFromStyle(const ComputedStyle&) const; + const mozilla::StyleImage* GetImageFromStyle() const { return GetImageFromStyle(*Style()); } + mozilla::ImageResolution GetImageResolution() const; + /** * Update mUseSrcAttr from appropriate content attributes or from * style, throw away the current image, and load the appropriate @@ -141,7 +143,6 @@ class nsImageBoxFrame final : public nsLeafBoxFrame { nsSize mImageSize; RefPtr mImageRequest; - float mImageResolution = 1.0f; nsCOMPtr mListener; int32_t mLoadFlags; diff --git a/servo/ports/geckolib/cbindgen.toml b/servo/ports/geckolib/cbindgen.toml index d2e60aa99548..d4cb4578f7e4 100644 --- a/servo/ports/geckolib/cbindgen.toml +++ b/servo/ports/geckolib/cbindgen.toml @@ -791,12 +791,11 @@ 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. + // Returns the intrinsic resolution of the image. // - // The resolution is in dppx, and should be used to impact the intrinsic size - // of the image. - std::pair FinalImageAndResolution() const; + // The resolution is in dppx, and should be used to impact the intrinsic + // size of the image. + ImageResolution GetResolution() const; // Returns the intrinsic size of the image, if there's one, accounting for // resolution as needed. diff --git a/testing/web-platform/meta/density-size-correction/__dir__.ini b/testing/web-platform/meta/density-size-correction/__dir__.ini new file mode 100644 index 000000000000..aeb4d9aa889e --- /dev/null +++ b/testing/web-platform/meta/density-size-correction/__dir__.ini @@ -0,0 +1 @@ +prefs: [image.exif-density-correction.enabled:true] diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-image-in-canvas.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-image-in-canvas.html.ini deleted file mode 100644 index 6c35650196de..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-image-in-canvas.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[density-corrected-image-in-canvas.html] - [Density corrected size: canvas] - expected: FAIL - diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-image-svg-aspect-ratio.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-image-svg-aspect-ratio.html.ini deleted file mode 100644 index 76fb6cfc9bd2..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-image-svg-aspect-ratio.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-image-svg-aspect-ratio.html] - expected: FAIL diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-image-svg.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-image-svg.html.ini deleted file mode 100644 index de7b23d2e5c6..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-image-svg.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-image-svg.html] - expected: FAIL diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-natural-size.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-natural-size.html.ini deleted file mode 100644 index ad5e8d8dccf5..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-natural-size.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[density-corrected-natural-size.html] - [density-corrected-natural-size] - expected: FAIL - diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-size-bg.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-size-bg.html.ini deleted file mode 100644 index e606f8a81fd3..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-size-bg.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-size-bg.html] - expected: FAIL diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-size-img.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-size-img.html.ini deleted file mode 100644 index d2680dafe306..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-size-img.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-size-img.html] - expected: FAIL diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-size-pseudo-elements.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-size-pseudo-elements.html.ini deleted file mode 100644 index 1e4cb6616188..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-size-pseudo-elements.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-size-pseudo-elements.html] - expected: FAIL diff --git a/testing/web-platform/meta/density-size-correction/density-corrected-various-elements.html.ini b/testing/web-platform/meta/density-size-correction/density-corrected-various-elements.html.ini deleted file mode 100644 index d1047f9a74d3..000000000000 --- a/testing/web-platform/meta/density-size-correction/density-corrected-various-elements.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[density-corrected-various-elements.html] - expected: FAIL diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 1c659ef20edc..efc9c99e4c56 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -925,7 +925,7 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) { IntSize customCursorSize; int32_t stride = 0; auto format = SurfaceFormat::B8G8R8A8; - float resolution = aCursor.mResolution; + ImageResolution resolution = aCursor.mResolution; if (aCursor.IsCustom()) { int32_t width = 0, height = 0; aCursor.mContainer->GetWidth(&width); @@ -936,9 +936,8 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) { if (width && height && aCursor.mContainer->GetType() == imgIContainer::TYPE_VECTOR) { // For vector images, scale to device pixels. - resolution *= GetDefaultScale().scale; - width = std::ceil(width * resolution); - height = std::ceil(height * resolution); + resolution.ScaleBy(GetDefaultScale().scale); + resolution.ApplyInverseTo(width, height); surface = aCursor.mContainer->GetFrameAtSize( {width, height}, imgIContainer::FRAME_CURRENT, flags); @@ -964,8 +963,9 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) { length); if (!mBrowserChild->SendSetCursor( aCursor.mDefaultCursor, hasCustomCursor, cursorData, - customCursorSize.width, customCursorSize.height, resolution, - stride, format, aCursor.mHotspotX, aCursor.mHotspotY, force)) { + customCursorSize.width, customCursorSize.height, + resolution.mX, resolution.mY, stride, format, + aCursor.mHotspotX, aCursor.mHotspotY, force)) { return; } mCursor = aCursor; diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 2f0479e906aa..83d45f66fc24 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -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 // the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland, // see bug 1707533. - int32_t gtkScale = - std::max(aWidgetScaleFactor, int32_t(std::ceil(aCursor.mResolution))); + int32_t gtkScale = std::max( + aWidgetScaleFactor, int32_t(std::ceil(std::max(aCursor.mResolution.mX, + aCursor.mResolution.mY)))); // Reject cursors greater than 128 pixels in some direction, to prevent // spoofing. diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index ab491a847fb2..5ce59cd3b4e6 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -529,10 +529,7 @@ nsIntSize nsIWidget::CustomCursorSize(const Cursor& aCursor) { int32_t height = 0; aCursor.mContainer->GetWidth(&width); aCursor.mContainer->GetHeight(&height); - if (aCursor.mResolution != 0.0f && aCursor.mResolution != 1.0f) { - width = std::round(float(width) / aCursor.mResolution); - height = std::round(float(height) / aCursor.mResolution); - } + aCursor.mResolution.ApplyTo(width, height); return {width, height}; } diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 85b7e3e1818e..e0127014212d 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -23,6 +23,7 @@ #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/ScrollableLayerGuid.h" #include "mozilla/layers/ZoomConstraints.h" +#include "mozilla/image/Resolution.h" #include "mozilla/widget/IMEData.h" #include "nsCOMPtr.h" #include "nsColor.h" @@ -992,7 +993,7 @@ class nsIWidget : public nsISupports { nsCOMPtr mContainer; uint32_t mHotspotX = 0; uint32_t mHotspotY = 0; - float mResolution = 1.0f; + mozilla::ImageResolution mResolution; bool IsCustom() const { return !!mContainer; } @@ -1003,7 +1004,7 @@ class nsIWidget : public nsISupports { mResolution == aOther.mResolution; } - bool operator!=(const Cursor& aOther) { return !(*this == aOther); } + bool operator!=(const Cursor& aOther) const { return !(*this == aOther); } }; /**