Bug 1560979 - Account for video element's intrinsic size in CanvasRenderingContext2D::DrawImage. r=jib,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D35782

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Pehrson 2019-07-12 12:46:03 +00:00
Родитель c16328f6e2
Коммит 8a56ba7a99
6 изменённых файлов: 35 добавлений и 32 удалений

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

@ -42,7 +42,8 @@ struct ImageCacheEntryData {
: mImage(aOther.mImage),
mCanvas(aOther.mCanvas),
mSourceSurface(aOther.mSourceSurface),
mSize(aOther.mSize) {}
mSize(aOther.mSize),
mIntrinsicSize(aOther.mIntrinsicSize) {}
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
: mImage(aKey.mImage), mCanvas(aKey.mCanvas) {}
@ -55,6 +56,7 @@ struct ImageCacheEntryData {
// Value
RefPtr<SourceSurface> mSourceSurface;
IntSize mSize;
IntSize mIntrinsicSize;
nsExpirationState mState;
};
@ -257,7 +259,8 @@ static already_AddRefed<imgIContainer> GetImageContainer(dom::Element* aImage) {
void CanvasImageCache::NotifyDrawImage(Element* aImage,
HTMLCanvasElement* aCanvas,
SourceSurface* aSource,
const IntSize& aSize) {
const IntSize& aSize,
const IntSize& aIntrinsicSize) {
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(
@ -284,6 +287,7 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
gImageCache->AddObject(entry->mData);
entry->mData->mSourceSurface = aSource;
entry->mData->mSize = aSize;
entry->mData->mIntrinsicSize = aIntrinsicSize;
gImageCache->mTotal += entry->mData->SizeInBytes();
AllCanvasImageCacheEntry* allEntry =
@ -321,7 +325,8 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) {
SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
HTMLCanvasElement* aCanvas,
IntSize* aSizeOut) {
IntSize* aSizeOut,
IntSize* aIntrinsicSizeOut) {
if (!gImageCache) {
return nullptr;
}
@ -341,6 +346,7 @@ SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
gImageCache->MarkUsed(entry->mData);
*aSizeOut = entry->mData->mSize;
*aIntrinsicSizeOut = entry->mData->mIntrinsicSize;
return entry->mData->mSourceSurface;
}

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

@ -29,12 +29,13 @@ class CanvasImageCache {
/**
* Notify that image element aImage was drawn to aCanvas element
* using the first frame of aRequest's image. The data for the surface is
* in aSurface, and the image size is in aSize.
* in aSurface, and the image size is in aSize. aIntrinsicSize is the size
* the surface is intended to be rendered at.
*/
static void NotifyDrawImage(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
SourceSurface* aSource,
const gfx::IntSize& aSize);
SourceSurface* aSource, const gfx::IntSize& aSize,
const gfx::IntSize& aIntrinsicSize);
/**
* Check whether aImage has recently been drawn any canvas. If we return
@ -48,7 +49,8 @@ class CanvasImageCache {
*/
static SourceSurface* LookupCanvas(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
gfx::IntSize* aSizeOut);
gfx::IntSize* aSizeOut,
gfx::IntSize* aIntrinsicSizeOut);
};
} // namespace mozilla

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

@ -4288,7 +4288,7 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
res.mCORSUsed = corsmode != imgIRequest::CORS_NONE;
}
res.mSize = res.mSourceSurface->GetSize();
res.mSize = res.mIntrinsicSize = res.mSourceSurface->GetSize();
res.mPrincipal = principal.forget();
res.mImageRequest = imgRequest.forget();
res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal,
@ -4331,6 +4331,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
RefPtr<SourceSurface> srcSurf;
gfx::IntSize imgSize;
gfx::IntSize intrinsicImgSize;
Element* element = nullptr;
@ -4363,7 +4364,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
SetWriteOnly();
}
imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
imgSize = intrinsicImgSize =
gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
} else {
if (aImage.IsHTMLImageElement()) {
HTMLImageElement* img = &aImage.GetAsHTMLImageElement();
@ -4378,7 +4380,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
element = video;
}
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize);
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize,
&intrinsicImgSize);
}
nsLayoutUtils::DirectDrawInfo drawInfo;
@ -4408,18 +4411,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
}
imgSize = res.mSize;
// Scale sw/sh based on aspect ratio
if (aImage.IsHTMLVideoElement()) {
HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
int32_t displayWidth = video->VideoWidth();
int32_t displayHeight = video->VideoHeight();
if (displayWidth == 0 || displayHeight == 0) {
return;
}
aSw *= (double)imgSize.width / (double)displayWidth;
aSh *= (double)imgSize.height / (double)displayHeight;
}
intrinsicImgSize = res.mIntrinsicSize;
if (mCanvasElement) {
CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, res.mPrincipal,
@ -4429,7 +4421,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
if (res.mSourceSurface) {
if (res.mImageRequest) {
CanvasImageCache::NotifyDrawImage(element, mCanvasElement,
res.mSourceSurface, imgSize);
res.mSourceSurface, imgSize,
intrinsicImgSize);
}
srcSurf = res.mSourceSurface;
} else {
@ -4439,8 +4432,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
if (aOptional_argc == 0) {
aSx = aSy = 0.0;
aDw = aSw = (double)imgSize.width;
aDh = aSh = (double)imgSize.height;
aSw = (double)imgSize.width;
aSh = (double)imgSize.height;
aDw = (double)intrinsicImgSize.width;
aDh = (double)intrinsicImgSize.height;
} else if (aOptional_argc == 2) {
aSx = aSy = 0.0;
aSw = (double)imgSize.width;

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

@ -7497,6 +7497,7 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas,
result.mHasSize = true;
result.mSize = size;
result.mIntrinsicSize = size;
result.mIsWriteOnly = aOffscreenCanvas->IsWriteOnly();
return result;
@ -7577,6 +7578,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
if (NS_FAILED(rv) || NS_FAILED(rv2)) return result;
}
result.mSize = IntSize(imgWidth, imgHeight);
result.mIntrinsicSize = IntSize(imgWidth, imgHeight);
if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
if (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) {
@ -7674,6 +7676,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
result.mHasSize = true;
result.mSize = size;
result.mIntrinsicSize = size;
result.mPrincipal = aElement->NodePrincipal();
result.mHadCrossOriginRedirects = false;
result.mIsWriteOnly = aElement->IsWriteOnly();
@ -7721,6 +7724,8 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
result.mHasSize = true;
result.mSize = result.mLayersImage->GetSize();
result.mIntrinsicSize =
gfx::IntSize(aElement->VideoWidth(), aElement->VideoHeight());
result.mPrincipal = principal.forget();
result.mHadCrossOriginRedirects = aElement->HadCrossOriginRedirects();
result.mIsWriteOnly = CanvasUtils::CheckWriteOnlySecurity(

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

@ -2155,6 +2155,8 @@ class nsLayoutUtils {
/* The size of the surface */
mozilla::gfx::IntSize mSize;
/* The size the surface is intended to be rendered at */
mozilla::gfx::IntSize mIntrinsicSize;
/* The principal associated with the element whose surface was returned.
If there is a surface, this will never be null. */
nsCOMPtr<nsIPrincipal> mPrincipal;

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

@ -1,7 +0,0 @@
[MediaStreamTrack-MediaElement-disabled-video-is-black.https.html]
[Tests that a disabled video track in a MediaStream is rendered as blackness]
expected: FAIL
[A disabled video track is rendered as blackness]
expected: FAIL