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..c198b3d6a20c2c1a8fddd564ba91963eda480194 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,38 @@ 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( |
+ image->imageForCurrentFrame(), |
+ WTF::bind(&HTMLImageElement::didDecode, |
+ m_weakPtrFactory.createWeakPtr())); |
+ } |
+} |
+ |
+void HTMLImageElement::didDecode(bool success) { |
+ if (m_decodePromiseResolvers.isEmpty()) |
+ return; |
+ static auto resolve = [](ScriptPromiseResolver* resolver) { |
+ resolver->resolve(); |
+ }; |
+ static auto reject = [](ScriptPromiseResolver* resolver) { |
+ resolver->reject(DOMException::create( |
+ EncodingError, "The source image cannot be decoded")); |
+ }; |
+ auto process = success ? resolve : reject; |
+ for (auto& resolver : m_decodePromiseResolvers) |
+ process(resolver); |
+ m_decodePromiseResolvers.clear(); |
+} |
+ |
HTMLImageElement* HTMLImageElement::createForJSConstructor(Document& document) { |
HTMLImageElement* image = new HTMLImageElement(document); |
image->m_elementCreatedByParser = false; |
@@ -260,6 +298,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 +459,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 +567,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 +635,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 +662,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 +853,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 +880,18 @@ PassRefPtr<ComputedStyle> HTMLImageElement::customStyleForLayoutObject() { |
} |
} |
+void HTMLImageElement::defaultEventHandler(Event* event) { |
+ HTMLElement::defaultEventHandler(event); |
+ if (m_decodePromiseResolvers.isEmpty()) |
+ return; |
+ |
+ if (event->type() == EventTypeNames::load) { |
+ requestDecode(); |
hiroshige
2017/03/31 08:24:24
This always causes ChromeClient's requestDecode()
vmpstr
2017/03/31 17:00:16
This only passes here if line 885 is false, which
|
+ } else if (event->type() == EventTypeNames::error) { |
+ didDecode(false); |
+ } |
+} |
+ |
IntSize HTMLImageElement::bitmapSourceSize() const { |
ImageResourceContent* image = cachedImage(); |
if (!image) |