Bug 1149357: Make nsImageFrame::mIntrinsicSize account for density. r=dholbert

Only doing it in ComputeSize (via GetNaturalSize) is unsound, and the rest of
the users of mIntrinsicSize definitely do need scaling accounted for.

Move the adjustment to nsImageFrame for two reasons:

 * Prevents adding more dependencies from nsIImageLoadingContent, which
   otherwise would need to go away anyway in bug 215083.

 * Avoids having to duplicate the image orientation logic, since mImage is
   already an OrientedImage if needed.

MozReview-Commit-ID: EA0n0TctZhN
This commit is contained in:
Emilio Cobos Álvarez 2018-05-16 19:39:16 +02:00
Родитель 3ea22263c0
Коммит 5d4df42dc7
5 изменённых файлов: 103 добавлений и 39 удалений

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

@ -43,6 +43,11 @@ public:
virtual bool Draggable() const override;
ResponsiveImageSelector* GetResponsiveImageSelector()
{
return mResponsiveSelector.get();
}
// Element
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;

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

@ -18,6 +18,8 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Helpers.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/ResponsiveImageSelector.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Unused.h"
@ -294,6 +296,33 @@ nsImageFrame::Init(nsIContent* aContent,
}
}
static void
ScaleIntrinsicSizeForDensity(nsIContent& aContent, nsSize& aSize)
{
auto* image = HTMLImageElement::FromNode(aContent);
if (!image) {
return;
}
ResponsiveImageSelector* selector = image->GetResponsiveImageSelector();
if (!selector) {
return;
}
double density = selector->GetSelectedImageDensity();
MOZ_ASSERT(density > 0.0);
if (density == 1.0) {
return;
}
if (aSize.width != -1) {
aSize.width = NSToCoordRound(double(aSize.width) / density);
}
if (aSize.height != -1) {
aSize.height = NSToCoordRound(double(aSize.height) / density);
}
}
bool
nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage)
{
@ -307,6 +336,7 @@ nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage)
// Set intrinsic size to match aImage's reported intrinsic width & height.
nsSize intrinsicSize;
if (NS_SUCCEEDED(aImage->GetIntrinsicSize(&intrinsicSize))) {
ScaleIntrinsicSizeForDensity(*mContent, intrinsicSize);
// If the image has no intrinsic width, intrinsicSize.width will be -1, and
// we can leave mIntrinsicSize.width at its default value of eStyleUnit_None.
// Otherwise we use intrinsicSize.width. Height works the same way.
@ -859,46 +889,8 @@ nsImageFrame::ComputeSize(gfxContext *aRenderingContext,
ComputeSizeFlags aFlags)
{
EnsureIntrinsicSizeAndRatio();
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ASSERTION(imageLoader, "No content node??");
mozilla::IntrinsicSize intrinsicSize(mIntrinsicSize);
// XXX(seth): We may sometimes find ourselves in the situation where we have
// mImage, but imageLoader's current request does not have a size yet.
// This can happen when we load an image speculatively from cache, it fails
// to validate, and the new image load hasn't fired SIZE_AVAILABLE yet. In
// this situation we should always use mIntrinsicSize, because
// GetNaturalWidth/Height will return 0, so we check CurrentRequestHasSize()
// below. See bug 1019840. We will fix this in bug 1141395.
// Content may override our default dimensions. This is termed as overriding
// the intrinsic size by the spec, but all other consumers of mIntrinsic*
// values are being used to refer to the real/true size of the image data.
if (imageLoader && imageLoader->CurrentRequestHasSize() && mImage &&
intrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
intrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
uint32_t width;
uint32_t height;
if (NS_SUCCEEDED(imageLoader->GetNaturalWidth(&width)) &&
NS_SUCCEEDED(imageLoader->GetNaturalHeight(&height))) {
nscoord appWidth = nsPresContext::CSSPixelsToAppUnits((int32_t)width);
nscoord appHeight = nsPresContext::CSSPixelsToAppUnits((int32_t)height);
// If this image is rotated, we'll need to transpose the natural
// width/height.
bool coordFlip;
if (StyleVisibility()->mImageOrientation.IsFromImage()) {
coordFlip = mImage->GetOrientation().SwapsWidthAndHeight();
} else {
coordFlip = StyleVisibility()->mImageOrientation.SwapsWidthAndHeight();
}
intrinsicSize.width.SetCoordValue(coordFlip ? appHeight : appWidth);
intrinsicSize.height.SetCoordValue(coordFlip ? appWidth : appHeight);
}
}
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, mIntrinsicRatio,
mIntrinsicSize, mIntrinsicRatio,
aCBSize, aMargin, aBorder, aPadding,
aFlags);
}

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

@ -0,0 +1,25 @@
<!doctype html>
<html reftest-zoom="2">
<title>CSS Test Reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.image-container {
display: inline;
}
.content-container {
display: inline-block;
}
.flex-container {
align-items: center;
display: flex;
}
</style>
<div class="flex-container">
<div class="image-container">
<img src="200.png" width="100">
</div>
<div class="content-container">
Should see me right by the side of the image.
</div>
</div>
</html>

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

@ -0,0 +1,41 @@
<!doctype html>
<html reftest-zoom="2" class="reftest-wait">
<title>CSS Test: srcset intrinsic size isn't confused</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1149357">
<style>
.image-container {
display: inline;
}
.content-container {
display: inline-block;
}
.flex-container {
align-items: center;
display: flex;
}
</style>
<script>
// reftest-zoom is only applied at onload, so ensure the source-selection
// has happened after that
function clearWait() {
document.documentElement.classList.remove("reftest-wait");
}
window.addEventListener("load", function() {
setTimeout(function() {
var img = document.querySelector("img");
img.onload = clearWait;
img.onerror = clearWait;
img.src = img.src;
}, 0);
});
</script>
<div class="flex-container">
<div class="image-container">
<img srcset="50.png 0.5x, 100.png 1x, 200.png 2x, 300.png 3x, 400.png">
</div>
<div class="content-container">
Should see me right by the side of the image.
</div>
</div>
</html>

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

@ -118,6 +118,7 @@ fuzzy(1,1) == image-orientation-background.html?90&flip image-orientation-r
== image-srcset-default-1x.html image-srcset-default-1x-ref.html
== image-srcset-default-src-2x.html image-srcset-default-src-2x-ref.html
== image-srcset-default-src-1x.html image-srcset-default-src-1x-ref.html
== image-srcset-isize.html image-srcset-isize-ref.html
== image-srcset-orientation-2x.html image-srcset-orientation-2x-ref.html
== image-srcset-orientation-1x.html image-srcset-orientation-1x-ref.html
== image-srcset-svg-3x.html image-srcset-svg-3x-ref.html