Commit b057987c authored by Fredrik Söderqvist's avatar Fredrik Söderqvist Committed by Commit Bot

Skip HTMLImageElement.decode() requests for SVG images

Per:

 "If decoding does not need to be performed for this image (for example
  because it is a vector graphic), resolve promise with undefined."

(https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode)

we can skip the decode request and just resolve the promise up front.
Since the SVG format is context sensitive (and, well, scalable),
decoding them outside of that context will likely just waste resources.

Fixed: 1073361
Change-Id: Iedf3a6636d9525e243ce9a8cf9c3835a1468b34b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2160915
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#762026}
parent 62dd4b24
......@@ -190,6 +190,15 @@ void ImageLoader::Dispose() {
}
}
static bool ImageTypeNeedsDecode(const Image& image) {
// SVG images are context sensitive, and decoding them without the proper
// context will just end up wasting memory (and CPU).
// TODO(vmpstr): Generalize this to be all non-lazy decoded images.
if (IsA<SVGImage>(image))
return false;
return true;
}
void ImageLoader::DispatchDecodeRequestsIfComplete() {
// If the current image isn't complete, then we can't dispatch any decodes.
// This function will be called again when the current image completes.
......@@ -206,14 +215,24 @@ void ImageLoader::DispatchDecodeRequestsIfComplete() {
}
LocalFrame* frame = GetElement()->GetDocument().GetFrame();
for (auto& request : decode_requests_) {
// If the image already in kDispatched state or still in kPEndingMicrotask
auto* it = decode_requests_.begin();
while (it != decode_requests_.end()) {
// If the image already in kDispatched state or still in kPendingMicrotask
// state, then we don't dispatch decodes for it. So, the only case to handle
// is if we're in kPendingLoad state.
if (request->state() != DecodeRequest::kPendingLoad)
auto& request = *it;
if (request->state() != DecodeRequest::kPendingLoad) {
++it;
continue;
}
Image* image = GetContent()->GetImage();
if (!ImageTypeNeedsDecode(*image)) {
// If the image is of a type that doesn't need decode, resolve the
// promise.
request->Resolve();
it = decode_requests_.erase(it);
continue;
}
// ImageLoader should be kept alive when decode is still pending. JS may
// invoke 'decode' without capturing the Image object. If GC kicks in,
// ImageLoader will be destroyed, leading to unresolved/unrejected Promise.
......@@ -222,6 +241,7 @@ void ImageLoader::DispatchDecodeRequestsIfComplete() {
WTF::Bind(&ImageLoader::DecodeRequestFinished,
WrapCrossThreadPersistent(this), request->request_id()));
request->NotifyDecodeDispatched();
++it;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment