Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Unified Diff: third_party/WebKit/Source/core/html/HTMLImageElement.cpp

Issue 2769823002: Add decode() functionality to image elements. (Closed)
Patch Set: update Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..93254134c7b635d8de58024051fc5b9511452238 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,39 @@ 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;
+ using ResolverFunc = void (*)(ScriptPromiseResolver*);
+ static ResolverFunc resolve = [](ScriptPromiseResolver* resolver) {
+ resolver->resolve();
+ };
+ static ResolverFunc reject = [](ScriptPromiseResolver* resolver) {
+ resolver->reject(DOMException::create(
+ EncodingError, "The source image cannot be decoded"));
+ };
+ ResolverFunc process = success ? resolve : reject;
+ for (auto& resolver : m_decodePromiseResolvers)
kouhei (in TOK) 2017/04/04 02:55:14 Can we simply if (success) and do two for loops?
vmpstr 2017/04/04 20:52:22 Done.
+ process(resolver);
+ m_decodePromiseResolvers.clear();
+}
+
HTMLImageElement* HTMLImageElement::createForJSConstructor(Document& document) {
HTMLImageElement* image = new HTMLImageElement(document);
image->m_elementCreatedByParser = false;
@@ -260,6 +299,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 +460,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 +568,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 +636,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 +663,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 +854,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 +881,22 @@ PassRefPtr<ComputedStyle> HTMLImageElement::customStyleForLayoutObject() {
}
}
+void HTMLImageElement::defaultEventHandler(Event* event) {
kouhei (in TOK) 2017/04/04 02:55:14 This is hook too generic to use. How about using {
vmpstr 2017/04/04 20:52:22 Done. I forwarded the call here (to a new HTMLImag
+ HTMLElement::defaultEventHandler(event);
+
+ // Note that the rest of the function here deals with events that can trigger
+ // a decode internally. We only need to check the events if we have a decode
+ // promise resolver (ie, ::decode was called).
+ if (m_decodePromiseResolvers.isEmpty())
+ return;
+
+ if (event->type() == EventTypeNames::load) {
+ requestDecode();
+ } else if (event->type() == EventTypeNames::error) {
+ didDecode(false);
+ }
+}
+
IntSize HTMLImageElement::bitmapSourceSize() const {
ImageResourceContent* image = cachedImage();
if (!image)
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLImageElement.h ('k') | third_party/WebKit/Source/core/html/HTMLImageElement.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698