Chromium Code Reviews| 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 54cb6398f39bbe0b44d7e9ec637f1c15d4378e72..12ab4a212a276b764febd69289ef401c8a9ff701 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,42 @@ void HTMLImageElement::NotifyViewportChanged() { |
| SelectSourceURL(ImageLoader::kUpdateSizeChanged); |
| } |
| +void HTMLImageElement::RequestDecode() { |
| + DCHECK(!decode_promise_resolvers_.IsEmpty()); |
| + if (!GetImageLoader().GetImage() || |
| + !GetImageLoader().GetImage()->GetImage()) { |
| + DidDecode(decode_sequence_id_, false); |
| + return; |
| + } |
| + Image* image = GetImageLoader().GetImage()->GetImage(); |
| + LocalFrame* frame = GetDocument().GetFrame(); |
|
dcheng
2017/04/17 18:48:02
Hmm. I think we might need to null check here.
I
vmpstr
2017/04/17 20:51:25
Done.
|
| + frame->GetChromeClient().RequestDecode( |
| + frame, image->ImageForCurrentFrame(), |
| + WTF::Bind(&HTMLImageElement::DidDecode, WrapWeakPersistent(this), |
| + decode_sequence_id_)); |
| +} |
| + |
| +void HTMLImageElement::DidDecode(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 +300,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) { |
| + DidDecode(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) { |
| @@ -596,6 +644,17 @@ int HTMLImageElement::y() const { |
| return abs_pos.Y(); |
| } |
| +ScriptPromise HTMLImageElement::decode(ScriptState* scriptState, |
| + ExceptionState& exceptionState) { |
| + exceptionState.ClearException(); |
| + decode_promise_resolvers_.push_back( |
| + ScriptPromiseResolver::Create(scriptState)); |
| + ScriptPromise promise = decode_promise_resolvers_.back()->Promise(); |
| + if (complete()) |
| + RequestDecode(); |
| + return promise; |
| +} |
| + |
| bool HTMLImageElement::complete() const { |
| return GetImageLoader().ImageComplete(); |
| } |
| @@ -612,8 +671,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; |
| @@ -833,6 +892,15 @@ PassRefPtr<ComputedStyle> HTMLImageElement::CustomStyleForLayoutObject() { |
| } |
| } |
| +void HTMLImageElement::ImageNotifyFinished(bool success) { |
| + if (decode_promise_resolvers_.IsEmpty()) |
| + return; |
| + if (success) |
| + RequestDecode(); |
| + else |
| + DidDecode(decode_sequence_id_, false); |
| +} |
| + |
| IntSize HTMLImageElement::BitmapSourceSize() const { |
| ImageResourceContent* image = CachedImage(); |
| if (!image) |