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 65a62298cce0df18ec5385e44e6dabffda759bac..9a283310240d920a3fa06eccad9c7b224430fe81 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" |
| @@ -95,7 +97,8 @@ HTMLImageElement::HTMLImageElement(Document& document, bool createdByParser) |
| m_formWasSetByParser(false), |
| m_elementCreatedByParser(createdByParser), |
| m_isFallbackImage(false), |
| - m_referrerPolicy(ReferrerPolicyDefault) { |
| + m_referrerPolicy(ReferrerPolicyDefault), |
| + m_weakPtrFactory(this) { |
| setHasCustomStyleCallbacks(); |
| } |
| @@ -108,13 +111,16 @@ HTMLImageElement* HTMLImageElement::create(Document& document, |
| return new HTMLImageElement(document, createdByParser); |
| } |
| -HTMLImageElement::~HTMLImageElement() {} |
| +HTMLImageElement::~HTMLImageElement() { |
| + m_weakPtrFactory.revokeAll(); |
| +} |
| DEFINE_TRACE(HTMLImageElement) { |
| visitor->trace(m_imageLoader); |
| visitor->trace(m_listener); |
| visitor->trace(m_form); |
| visitor->trace(m_source); |
| + visitor->trace(m_decodePromiseResolvers); |
| HTMLElement::trace(visitor); |
| } |
| @@ -125,6 +131,37 @@ void HTMLImageElement::notifyViewportChanged() { |
| selectSourceURL(ImageLoader::UpdateSizeChanged); |
| } |
| +void HTMLImageElement::requestDecode() { |
| + DCHECK(!m_decodePromiseResolvers.isEmpty()); |
| + if (!imageLoader().image() || !imageLoader().image()->getImage()) { |
| + didDecode(false); |
| + return; |
| + } |
| + Image* image = imageLoader().image()->getImage(); |
| + auto* page = document().page(); |
| + if (page) { |
| + page->chromeClient().requestDecode( |
|
dcheng
2017/04/12 06:53:16
After reading this through, I think it's fine to j
vmpstr
2017/04/17 18:13:11
Done. Let me know if this looks better...
|
| + image->imageForCurrentFrame(), |
| + WTF::bind(&HTMLImageElement::didDecode, |
| + m_weakPtrFactory.createWeakPtr())); |
|
kouhei (in TOK)
2017/04/07 14:26:28
wrapWeakPersistent(this)?
vmpstr
2017/04/07 20:43:43
Hmm, we have to revoke the weak ptrs if the src of
dcheng
2017/04/12 06:53:16
Other potential options:
- PostCancellableTask, wh
vmpstr
2017/04/17 18:13:11
Done, I used a sequence number here with wrapWeakP
|
| + } |
| +} |
| + |
| +void HTMLImageElement::didDecode(bool success) { |
| + if (m_decodePromiseResolvers.isEmpty()) |
| + return; |
| + if (success) { |
| + for (auto& resolver : m_decodePromiseResolvers) |
| + resolver->resolve(); |
| + } else { |
| + for (auto& resolver : m_decodePromiseResolvers) { |
| + resolver->reject(DOMException::create( |
| + EncodingError, "The source image cannot be decoded")); |
| + } |
| + } |
| + m_decodePromiseResolvers.clear(); |
| +} |
| + |
| HTMLImageElement* HTMLImageElement::createForJSConstructor(Document& document) { |
| HTMLImageElement* image = new HTMLImageElement(document); |
| image->m_elementCreatedByParser = false; |
| @@ -260,6 +297,12 @@ void HTMLImageElement::parseAttribute( |
| } |
| } else if (name == srcAttr || name == srcsetAttr || name == sizesAttr) { |
| selectSourceURL(ImageLoader::UpdateIgnorePreviousError); |
| + // Ensure to fail any pending decodes on possible source changes. |
| + if (!m_decodePromiseResolvers.isEmpty() && |
| + params.oldValue != params.newValue) { |
| + didDecode(false); |
| + m_weakPtrFactory.revokeAll(); |
| + } |
| } else if (name == usemapAttr) { |
| setIsLink(!params.newValue.isNull()); |
| } else if (name == referrerpolicyAttr) { |
| @@ -415,9 +458,8 @@ Node::InsertionNotificationRequest HTMLImageElement::insertedInto( |
| } |
| void HTMLImageElement::removedFrom(ContainerNode* insertionPoint) { |
| - if (!m_form || |
| - NodeTraversal::highestAncestorOrSelf(*m_form.get()) != |
| - NodeTraversal::highestAncestorOrSelf(*this)) |
| + if (!m_form || NodeTraversal::highestAncestorOrSelf(*m_form.get()) != |
| + NodeTraversal::highestAncestorOrSelf(*this)) |
| resetFormOwner(); |
| if (m_listener) { |
| document().mediaQueryMatcher().removeViewportListener(m_listener); |
| @@ -524,9 +566,9 @@ const String& HTMLImageElement::currentSrc() const { |
| // Return the picked URL string in case of load error. |
| if (imageLoader().hadError()) |
| return m_bestFitImageURL; |
| - // Initially, the pending request turns into current request when it is either |
| - // available or broken. We use the image's dimensions as a proxy to it being |
| - // in any of these states. |
| + // Initially, the pending request turns into current request when it is |
| + // either available or broken. We use the image's dimensions as a proxy to |
| + // it being in any of these states. |
| if (!imageLoader().image() || !imageLoader().image()->getImage() || |
| !imageLoader().image()->getImage()->width()) |
| return emptyAtom; |
| @@ -592,6 +634,17 @@ int HTMLImageElement::y() const { |
| return absPos.y(); |
| } |
| +ScriptPromise HTMLImageElement::decode(ScriptState* scriptState, |
| + ExceptionState& exceptionState) { |
| + exceptionState.clearException(); |
| + m_decodePromiseResolvers.push_back( |
| + ScriptPromiseResolver::create(scriptState)); |
| + ScriptPromise promise = m_decodePromiseResolvers.back()->promise(); |
| + if (complete()) |
| + requestDecode(); |
| + return promise; |
| +} |
| + |
| bool HTMLImageElement::complete() const { |
| return imageLoader().imageComplete(); |
| } |
| @@ -608,8 +661,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; |
| @@ -799,8 +852,8 @@ void HTMLImageElement::setLayoutDisposition(LayoutDisposition layoutDisposition, |
| m_layoutDisposition = layoutDisposition; |
| - // This can happen inside of attachLayoutTree() in the middle of a recalcStyle |
| - // so we need to reattach synchronously here. |
| + // This can happen inside of attachLayoutTree() in the middle of a |
| + // recalcStyle so we need to reattach synchronously here. |
| if (document().inStyleRecalc()) { |
| reattachLayoutTree(); |
| } else { |
| @@ -826,6 +879,15 @@ PassRefPtr<ComputedStyle> HTMLImageElement::customStyleForLayoutObject() { |
| } |
| } |
| +void HTMLImageElement::imageNotifyFinished(bool success) { |
| + if (m_decodePromiseResolvers.isEmpty()) |
| + return; |
| + if (success) |
| + requestDecode(); |
| + else |
| + didDecode(false); |
| +} |
| + |
| IntSize HTMLImageElement::bitmapSourceSize() const { |
| ImageResourceContent* image = cachedImage(); |
| if (!image) |