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

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

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

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

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

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

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

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

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