Bug 1453747 - Use rounded dest rect in simplified image decode size calculations for WebRender. r=mstange

We are using the unrounded dest rect to calculate the image decode size
in ComputeImageContainerDrawingParameters, while passing the rounded
dest rect to WebRender. This mismatch causes images to be decoded to one
size and display at another, cause some visual distortions. Using the
correct rect seems to allow us to remove the extra snapping logic added
to work around this.

At this time, how we snap is different between WebRender and
non-WebRender in general. This patch will likely morph again once we
bring the two models closer together.

Differential Revision: https://phabricator.services.mozilla.com/D15739
This commit is contained in:
Andrew Osmond 2019-01-04 09:28:49 -05:00
Родитель 2d4a38b677
Коммит 6d9401a9e6
8 изменённых файлов: 29 добавлений и 53 удалений

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

@ -55,10 +55,6 @@ class MOZ_RAII StackingContextHelper {
// Export the inherited scale
gfx::Size GetInheritedScale() const { return mScale; }
const gfx::Matrix& GetInheritedTransform() const {
return mInheritedTransform;
}
const gfx::Matrix& GetSnappingSurfaceTransform() const {
return mSnappingSurfaceTransform;
}

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

@ -6361,8 +6361,6 @@ static SnappedImageDrawingParameters ComputeSnappedImageDrawingParameters(
// Snap even if we have a scale in the context. But don't snap if
// we have something that's not translation+scale, or if the scale flips in
// the X or Y direction, because snapped image drawing can't handle that yet.
// Any changes to this algorithm will need to be reflected in
// ComputeImageContainerDrawingParameters.
if (!currentMatrix.HasNonAxisAlignedTransform() && currentMatrix._11 > 0.0 &&
currentMatrix._22 > 0.0 && aCtx->UserToDevicePixelSnapped(fill, true) &&
aCtx->UserToDevicePixelSnapped(dest, true)) {
@ -6752,46 +6750,17 @@ static ImgDrawResult DrawImageInternal(
}
}
// Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters.
// Any changes to the algorithm here will need to be reflected there.
bool snapped = false;
gfxSize gfxLayerSize;
const gfx::Matrix& itm = aSc.GetInheritedTransform();
if (!itm.HasNonAxisAlignedTransform() && itm._11 > 0.0 && itm._22 > 0.0) {
gfxRect rect(gfxPoint(aDestRect.X(), aDestRect.Y()),
gfxSize(aDestRect.Width(), aDestRect.Height()));
// Compute our size in layer pixels. We may need to revisit this for Android
// because mobile websites are rarely displayed at a 1:1
// LayoutPixel:ScreenPixel ratio and the snapping here may be insufficient.
const LayerIntSize layerSize =
RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width,
aDestRect.Height() * scaleFactors.height));
gfxPoint p1 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopLeft())));
gfxPoint p2 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopRight())));
gfxPoint p3 = ThebesPoint(itm.TransformPoint(ToPoint(rect.BottomRight())));
if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) {
p1.Round();
p3.Round();
rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y)));
rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(),
std::max(p1.y, p3.y) - rect.Y()));
// An empty size is unacceptable so we ensure our suggested size is at
// least 1 pixel wide/tall.
gfxLayerSize =
gfxSize(std::max(rect.Width(), 1.0), std::max(rect.Height(), 1.0));
snapped = true;
}
}
if (!snapped) {
// Compute our size in layer pixels.
const LayerIntSize layerSize =
RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width,
aDestRect.Height() * scaleFactors.height));
// An empty size is unacceptable so we ensure our suggested size is at least
// 1 pixel wide/tall.
gfxLayerSize =
gfxSize(std::max(layerSize.width, 1), std::max(layerSize.height, 1));
}
// An empty size is unacceptable so we ensure our suggested size is at least
// 1 pixel wide/tall.
gfxSize gfxLayerSize =
gfxSize(std::max(layerSize.width, 1), std::max(layerSize.height, 1));
return aImage->OptimalImageSizeForDest(
gfxLayerSize, imgIContainer::FRAME_CURRENT, samplingFilter, aFlags);

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

@ -432,6 +432,8 @@ ImgDrawResult BulletRenderer::CreateWebRenderCommandsForImage(
aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
destRect.Round();
Maybe<SVGImageContext> svgContext;
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(
@ -454,7 +456,7 @@ ImgDrawResult BulletRenderer::CreateWebRenderCommandsForImage(
return drawResult;
}
wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
wr::LayoutRect dest = wr::ToLayoutRect(destRect);
aBuilder.PushImage(dest, dest, !aItem->BackfaceIsHidden(), rendering,
key.value());

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

@ -1618,8 +1618,10 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
size);
const int32_t factor = PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect(
LayoutDeviceRect destRect(
LayoutDeviceRect::FromAppUnits(dest, factor));
destRect.Round();
Maybe<SVGImageContext> svgContext;
IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(
@ -1896,8 +1898,10 @@ bool nsDisplayImage::CreateWebRenderCommands(
}
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect(
LayoutDeviceRect destRect(
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor));
destRect.Round();
Maybe<SVGImageContext> svgContext;
IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters(
mImage, mFrame, destRect, aSc, flags, svgContext);

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

@ -3553,7 +3553,8 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(mArea, appUnitsPerDevPixel);
wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
destRect.Round();
wr::LayoutRect dest = wr::ToLayoutRect(destRect);
wr::LayoutRect clip = dest;
if (!mClip.IsEmpty()) {

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

@ -567,6 +567,9 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
mForFrame->PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(aDest, appUnitsPerDevPixel);
auto stretchSize = wr::ToLayoutSize(destRect.Size());
destRect.Round();
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(
mImageContainer, mForFrame, destRect, aSc, containerFlags,
@ -600,8 +603,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
appUnitsPerDevPixel);
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
wr::LayoutRect roundedDest = wr::ToRoundedLayoutRect(destRect);
auto stretchSize = wr::ToLayoutSize(destRect.Size());
wr::LayoutRect roundedDest = wr::ToLayoutRect(destRect);
// WebRender special cases situations where stretchSize == fillSize to
// infer that it shouldn't use repeat sampling. This makes sure

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

@ -398,6 +398,8 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands(
const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect fillRect =
LayoutDeviceRect::FromAppUnits(dest, appUnitsPerDevPixel);
fillRect.Round();
Maybe<SVGImageContext> svgContext;
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(
@ -420,7 +422,7 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands(
if (key.isNothing()) {
return result;
}
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
wr::LayoutRect fill = wr::ToLayoutRect(fillRect);
LayoutDeviceSize gapSize(0, 0);
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),

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

@ -1,7 +1,7 @@
fails-if(Android) == textbox-multiline-noresize.xul textbox-multiline-ref.xul # reference is blank on Android (due to no native theme support?)
!= textbox-multiline-resize.xul textbox-multiline-ref.xul
== popup-explicit-size.xul popup-explicit-size-ref.xul
random-if(Android) fuzzy-if(webrender,128-128,168-168) == image-size.xul image-size-ref.xul
random-if(Android) == image-size.xul image-size-ref.xul
== image-scaling-min-height-1.xul image-scaling-min-height-1-ref.xul
== textbox-text-transform.xul textbox-text-transform-ref.xul