| Index: third_party/WebKit/Source/core/html/HTMLImageElement.cpp
|
| diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
|
| index 6ad492963e8641a36d0b0cc8211d58aa936076a0..c317ebb48308ff454edefee3eace24cd98a81255 100644
|
| --- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
|
| +++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
|
| @@ -31,6 +31,7 @@
|
| #include "core/css/MediaValuesDynamic.h"
|
| #include "core/css/parser/SizesAttributeParser.h"
|
| #include "core/dom/Attribute.h"
|
| +#include "core/dom/DOMException.h"
|
| #include "core/dom/NodeTraversal.h"
|
| #include "core/dom/shadow/ShadowRoot.h"
|
| #include "core/frame/Deprecation.h"
|
| @@ -51,6 +52,7 @@
|
| #include "core/layout/LayoutImage.h"
|
| #include "core/layout/api/LayoutImageItem.h"
|
| #include "core/loader/resource/ImageResourceContent.h"
|
| +#include "core/page/ChromeClient.h"
|
| #include "core/page/Page.h"
|
| #include "core/style/ContentData.h"
|
| #include "core/svg/graphics/SVGImageForContainer.h"
|
| @@ -92,6 +94,7 @@ HTMLImageElement::HTMLImageElement(Document& document, bool created_by_parser)
|
| image_device_pixel_ratio_(1.0f),
|
| source_(nullptr),
|
| layout_disposition_(LayoutDisposition::kPrimaryContent),
|
| + decode_sequence_id_(0),
|
| form_was_set_by_parser_(false),
|
| element_created_by_parser_(created_by_parser),
|
| is_fallback_image_(false),
|
| @@ -115,6 +118,7 @@ DEFINE_TRACE(HTMLImageElement) {
|
| visitor->Trace(listener_);
|
| visitor->Trace(form_);
|
| visitor->Trace(source_);
|
| + visitor->Trace(decode_promise_resolvers_);
|
| HTMLElement::Trace(visitor);
|
| }
|
|
|
| @@ -125,6 +129,45 @@ void HTMLImageElement::NotifyViewportChanged() {
|
| SelectSourceURL(ImageLoader::kUpdateSizeChanged);
|
| }
|
|
|
| +void HTMLImageElement::RequestDecode() {
|
| + DCHECK(!decode_promise_resolvers_.IsEmpty());
|
| + LocalFrame* frame = GetDocument().GetFrame();
|
| + // If we don't have the image, or the document doesn't have a frame, then
|
| + // reject the decode, since we can't plumb the request to the correct place.
|
| + if (!GetImageLoader().GetImage() ||
|
| + !GetImageLoader().GetImage()->GetImage() || !frame) {
|
| + DecodeRequestFinished(decode_sequence_id_, false);
|
| + return;
|
| + }
|
| + Image* image = GetImageLoader().GetImage()->GetImage();
|
| + frame->GetChromeClient().RequestDecode(
|
| + frame, image->ImageForCurrentFrame(),
|
| + WTF::Bind(&HTMLImageElement::DecodeRequestFinished,
|
| + WrapWeakPersistent(this), decode_sequence_id_));
|
| +}
|
| +
|
| +void HTMLImageElement::DecodeRequestFinished(uint32_t sequence_id,
|
| + bool success) {
|
| + // If the sequence id attached with this callback doesn't match our current
|
| + // sequence id, then the source of the image has changed. In other words, the
|
| + // decode resolved/rejected by this callback was already rejected. Since we
|
| + // could have had a new decode request, we have to make sure not to
|
| + // resolve/reject those using the stale callback.
|
| + if (sequence_id != decode_sequence_id_)
|
| + return;
|
| +
|
| + if (success) {
|
| + for (auto& resolver : decode_promise_resolvers_)
|
| + resolver->Resolve();
|
| + } else {
|
| + for (auto& resolver : decode_promise_resolvers_) {
|
| + resolver->Reject(DOMException::Create(
|
| + kEncodingError, "The source image cannot be decoded"));
|
| + }
|
| + }
|
| + decode_promise_resolvers_.clear();
|
| +}
|
| +
|
| HTMLImageElement* HTMLImageElement::CreateForJSConstructor(Document& document) {
|
| HTMLImageElement* image = new HTMLImageElement(document);
|
| image->element_created_by_parser_ = false;
|
| @@ -260,6 +303,14 @@ void HTMLImageElement::ParseAttribute(
|
| }
|
| } else if (name == srcAttr || name == srcsetAttr || name == sizesAttr) {
|
| SelectSourceURL(ImageLoader::kUpdateIgnorePreviousError);
|
| + // Ensure to fail any pending decodes on possible source changes.
|
| + if (!decode_promise_resolvers_.IsEmpty() &&
|
| + params.old_value != params.new_value) {
|
| + DecodeRequestFinished(decode_sequence_id_, false);
|
| + // Increment the sequence id so that any in flight decode completion tasks
|
| + // will not trigger promise resolution for new decode requests.
|
| + ++decode_sequence_id_;
|
| + }
|
| } else if (name == usemapAttr) {
|
| SetIsLink(!params.new_value.IsNull());
|
| } else if (name == referrerpolicyAttr) {
|
| @@ -597,6 +648,22 @@ int HTMLImageElement::y() const {
|
| return abs_pos.Y();
|
| }
|
|
|
| +ScriptPromise HTMLImageElement::decode(ScriptState* script_state,
|
| + ExceptionState& exception_state) {
|
| + if (!script_state->ContextIsValid()) {
|
| + exception_state.ThrowDOMException(kEncodingError,
|
| + "The source image cannot be decoded");
|
| + return ScriptPromise();
|
| + }
|
| + exception_state.ClearException();
|
| + decode_promise_resolvers_.push_back(
|
| + ScriptPromiseResolver::Create(script_state));
|
| + ScriptPromise promise = decode_promise_resolvers_.back()->Promise();
|
| + if (complete())
|
| + RequestDecode();
|
| + return promise;
|
| +}
|
| +
|
| bool HTMLImageElement::complete() const {
|
| return GetImageLoader().ImageComplete();
|
| }
|
| @@ -613,8 +680,8 @@ bool HTMLImageElement::IsServerMap() const {
|
|
|
| const AtomicString& usemap = FastGetAttribute(usemapAttr);
|
|
|
| - // If the usemap attribute starts with '#', it refers to a map element in the
|
| - // document.
|
| + // If the usemap attribute starts with '#', it refers to a map element in
|
| + // the document.
|
| if (usemap[0] == '#')
|
| return false;
|
|
|
| @@ -812,6 +879,15 @@ PassRefPtr<ComputedStyle> HTMLImageElement::CustomStyleForLayoutObject() {
|
| }
|
| }
|
|
|
| +void HTMLImageElement::ImageNotifyFinished(bool success) {
|
| + if (decode_promise_resolvers_.IsEmpty())
|
| + return;
|
| + if (success)
|
| + RequestDecode();
|
| + else
|
| + DecodeRequestFinished(decode_sequence_id_, false);
|
| +}
|
| +
|
| void HTMLImageElement::AssociateWith(HTMLFormElement* form) {
|
| if (form && form->isConnected()) {
|
| form_ = form;
|
|
|