Bug 1904048 - Add prototype for ImageBitmap's BindingJSObjectMallocBytes. r=aosmond

It looks like there was never a prototype for ImageBitmap's BindingJSObjectMallocBytes function.
Even though it was defined and expected to associate ImageBitmap's internally allocated surface
memory for the GC to track, the bindings generator never actually tried to call it because the
lack of the prototype caused the default non-specialized version of this function to be called
instead. With the protoype in place, this actually gets called and the GC is able to properly
clean out ImageBitmap's in a more timely fashion.

Differential Revision: https://phabricator.services.mozilla.com/D216250
This commit is contained in:
Lee Salzman 2024-07-13 02:12:55 +00:00
Родитель de8b5d0e01
Коммит 196ef8360e
2 изменённых файлов: 47 добавлений и 43 удалений

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

@ -38,6 +38,7 @@
#include "nsStreamUtils.h"
#include "imgLoader.h"
#include "imgTools.h"
#include "jsapi.h"
using namespace mozilla::gfx;
using namespace mozilla::layers;
@ -651,13 +652,14 @@ static already_AddRefed<SourceSurface> GetSurfaceFromElement(
}
ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
bool aWriteOnly, gfxAlphaType aAlphaType)
bool aAllocatedImageData, bool aWriteOnly,
gfxAlphaType aAlphaType)
: mParent(aGlobal),
mData(aData),
mSurface(nullptr),
mPictureRect(aData->GetPictureRect()),
mAlphaType(aAlphaType),
mAllocatedImageData(false),
mAllocatedImageData(aAllocatedImageData),
mWriteOnly(aWriteOnly) {
MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
@ -689,6 +691,7 @@ JSObject* ImageBitmap::WrapObject(JSContext* aCx,
}
void ImageBitmap::Close() {
RemoveAssociatedMemory();
mData = nullptr;
mSurface = nullptr;
mPictureRect.SetEmpty();
@ -969,8 +972,7 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateFromSourceSurface(
nsIGlobalObject* aGlobal, gfx::SourceSurface* aSource, ErrorResult& aRv) {
RefPtr<layers::Image> data = CreateImageFromSurface(aSource);
RefPtr<ImageBitmap> ret =
new ImageBitmap(aGlobal, data, false /* writeOnly */);
ret->mAllocatedImageData = true;
new ImageBitmap(aGlobal, data, true, false /* writeOnly */);
return ret.forget();
}
@ -979,10 +981,8 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateFromCloneData(
nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData) {
RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
RefPtr<ImageBitmap> ret =
new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mAlphaType);
ret->mAllocatedImageData = true;
RefPtr<ImageBitmap> ret = new ImageBitmap(
aGlobal, data, true, aData->mWriteOnly, aData->mAlphaType);
ErrorResult rv;
ret->SetPictureRect(aData->mPictureRect, rv);
@ -1010,9 +1010,7 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateFromOffscreenCanvas(
RefPtr<layers::Image> data = CreateImageFromSurface(surface);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
ret->mAllocatedImageData = true;
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, true, writeOnly);
return ret.forget();
}
@ -1128,12 +1126,8 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateImageBitmapInternal(
// Create an Image from the SourceSurface.
RefPtr<layers::Image> data = CreateImageFromSurface(surface);
RefPtr<ImageBitmap> ret =
new ImageBitmap(aGlobal, data, aWriteOnly, alphaType);
if (needToReportMemoryAllocation) {
ret->mAllocatedImageData = true;
}
RefPtr<ImageBitmap> ret = new ImageBitmap(
aGlobal, data, needToReportMemoryAllocation, aWriteOnly, alphaType);
// Set the picture rectangle.
ret->SetPictureRect(cropRect, aRv);
@ -1232,7 +1226,7 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
RefPtr<SourceSurface> surface = data->GetAsSourceSurface();
if (!surface) {
// preserve original behavior in case of unavailble surface
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false, writeOnly);
return ret.forget();
}
@ -1399,9 +1393,8 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
}
// Create an ImageBitmap.
RefPtr<ImageBitmap> ret =
new ImageBitmap(aGlobal, data, false /* write-only */, alphaType);
ret->mAllocatedImageData = true;
RefPtr<ImageBitmap> ret = new ImageBitmap(
aGlobal, data, true, false /* write-only */, alphaType);
// The cropping information has been handled in the
// CreateImageFromRawData() function.
@ -1911,7 +1904,7 @@ JSObject* ImageBitmap::ReadStructuredClone(
#endif
RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
RefPtr<ImageBitmap> imageBitmap =
new ImageBitmap(aParent, img, !!writeOnly, alphaType);
new ImageBitmap(aParent, img, true, !!writeOnly, alphaType);
ErrorResult error;
imageBitmap->SetPictureRect(
@ -1924,8 +1917,6 @@ JSObject* ImageBitmap::ReadStructuredClone(
if (!GetOrCreateDOMReflector(aCx, imageBitmap, &value)) {
return nullptr;
}
imageBitmap->mAllocatedImageData = true;
}
return &(value.toObject());
@ -2000,32 +1991,42 @@ void ImageBitmap::WriteStructuredClone(
}
size_t ImageBitmap::GetAllocatedSize() const {
if (!mAllocatedImageData) {
if (!mAllocatedImageData || !mData) {
return 0;
}
// Calculate how many bytes are used.
if (mData->GetFormat() == mozilla::ImageFormat::PLANAR_YCBCR) {
return mData->AsPlanarYCbCrImage()->GetDataSize();
switch (mData->GetFormat()) {
case ImageFormat::PLANAR_YCBCR:
return mData->AsPlanarYCbCrImage()->GetDataSize();
case ImageFormat::NV_IMAGE:
return mData->AsNVImage()->GetBufferSize();
default:
break;
}
if (mData->GetFormat() == mozilla::ImageFormat::NV_IMAGE) {
return mData->AsNVImage()->GetBufferSize();
}
RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
if (NS_WARN_IF(!surface)) {
return 0;
}
const int bytesPerPixel = BytesPerPixel(surface->GetFormat());
return surface->GetSize().height * surface->GetSize().width * bytesPerPixel;
IntSize size = mData->GetSize();
CheckedInt<uint32_t> bytes =
CheckedInt<uint32_t>(size.width) * size.height * 4;
return bytes.isValid() ? bytes.value() : 0;
}
size_t BindingJSObjectMallocBytes(ImageBitmap* aBitmap) {
return aBitmap->GetAllocatedSize();
}
void ImageBitmap::RemoveAssociatedMemory() {
if (!mAllocatedImageData) {
return;
}
if (JSObject* wrapper = GetWrapperMaybeDead()) {
if (size_t bytes = BindingJSObjectMallocBytes(this)) {
JS::RemoveAssociatedMemory(wrapper, bytes, JS::MemoryUse::DOMBinding);
}
}
mAllocatedImageData = false;
}
/* static */
already_AddRefed<CreateImageBitmapFromBlob> CreateImageBitmapFromBlob::Create(
Promise* aPromise, nsIGlobalObject* aGlobal, Blob& aBlob,
@ -2338,8 +2339,8 @@ void CreateImageBitmapFromBlob::
}
// Create ImageBitmap object.
RefPtr<ImageBitmap> imageBitmap =
new ImageBitmap(mGlobalObject, aImage, false /* write-only */, alphaType);
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(
mGlobalObject, aImage, true, false /* write-only */, alphaType);
if (mCropRect.isSome()) {
ErrorResult rv;
@ -2351,8 +2352,6 @@ void CreateImageBitmapFromBlob::
}
}
imageBitmap->mAllocatedImageData = true;
mPromise->MaybeResolve(imageBitmap);
}

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

@ -172,13 +172,16 @@ class ImageBitmap final : public nsISupports, public nsWrapperCache {
* the aIsPremultipliedAlpha to be false in the
* CreateInternal(from ImageData) method.
*/
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, bool aWriteOnly,
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
bool aAllocatedImageData, bool aWriteOnly,
gfxAlphaType aAlphaType = gfxAlphaType::Premult);
virtual ~ImageBitmap();
void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
void RemoveAssociatedMemory();
static already_AddRefed<ImageBitmap> CreateImageBitmapInternal(
nsIGlobalObject* aGlobal, gfx::SourceSurface* aSurface,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
@ -279,6 +282,8 @@ class ImageBitmap final : public nsISupports, public nsWrapperCache {
bool mWriteOnly;
};
size_t BindingJSObjectMallocBytes(ImageBitmap* aBitmap);
} // namespace dom
} // namespace mozilla