Chromium Code Reviews| Index: Source/core/html/HTMLImageElement.cpp |
| diff --git a/Source/core/html/HTMLImageElement.cpp b/Source/core/html/HTMLImageElement.cpp |
| index ff90239a68388aead040d64d21e63c905971801b..a759371bb146c40320a204e9c745075e42cbf070 100644 |
| --- a/Source/core/html/HTMLImageElement.cpp |
| +++ b/Source/core/html/HTMLImageElement.cpp |
| @@ -26,8 +26,10 @@ |
| #include "CSSPropertyNames.h" |
| #include "HTMLNames.h" |
| #include "RuntimeEnabledFeatures.h" |
| +#include "bindings/v8/DOMWrapperWorld.h" |
| #include "bindings/v8/ScriptEventListener.h" |
| #include "core/dom/Attribute.h" |
| +#include "core/dom/Microtask.h" |
| #include "core/fetch/ImageResource.h" |
| #include "core/html/HTMLAnchorElement.h" |
| #include "core/html/HTMLCanvasElement.h" |
| @@ -36,9 +38,20 @@ |
| #include "core/html/parser/HTMLParserIdioms.h" |
| #include "core/html/parser/HTMLSrcsetParser.h" |
| #include "core/rendering/RenderImage.h" |
| +#include "wtf/Vector.h" |
| +#include <v8.h> |
| using namespace std; |
| +namespace { |
| +typedef Vector<WebCore::HTMLImageElement*> PendingUpdateQueueType; |
| +static PendingUpdateQueueType& PendingUpdateQueue() |
| +{ |
| + DEFINE_STATIC_LOCAL(Vector<WebCore::HTMLImageElement*>, pendingUpdateFromElementCalls, ()); |
| + return pendingUpdateFromElementCalls; |
| +} |
| +} |
| + |
| namespace WebCore { |
| using namespace HTMLNames; |
| @@ -49,6 +62,7 @@ HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form) |
| , m_compositeOperator(CompositeSourceOver) |
| , m_imageDevicePixelRatio(1.0f) |
| , m_formWasSetByParser(false) |
| + , m_pendingUpdate(PendingUpdateNone) |
| { |
| ScriptWrappable::init(this); |
| if (form && form->inDocument()) { |
| @@ -73,6 +87,7 @@ HTMLImageElement::~HTMLImageElement() |
| { |
| if (m_form) |
| m_form->disassociate(*this); |
| + cancelPendingUpdate(); |
|
abarth-chromium
2014/04/01 23:57:14
This algorithm is O(N^2) when tearing down the doc
|
| } |
| PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width, int height) |
| @@ -163,7 +178,7 @@ void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr |
| if (renderer() && renderer()->isImage()) |
| toRenderImage(renderer())->setImageDevicePixelRatio(m_imageDevicePixelRatio); |
| } |
| - m_imageLoader.updateFromElementIgnoringPreviousError(); |
| + enqueueUpdate(PendingUpdateIgnoreError); |
| } else if (name == usemapAttr) { |
| setIsLink(!value.isNull()); |
| } else if (name == compositeAttr) { |
| @@ -235,7 +250,7 @@ Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* |
| // If we have been inserted from a renderer-less document, |
| // our loader may have not fetched the image, so do it now. |
| if (insertionPoint->inDocument() && !m_imageLoader.image()) |
| - m_imageLoader.updateFromElement(); |
| + enqueueUpdate(PendingUpdateNormal); |
| return HTMLElement::insertedInto(insertionPoint); |
| } |
| @@ -383,13 +398,17 @@ int HTMLImageElement::y() const |
| bool HTMLImageElement::complete() const |
| { |
| - return m_imageLoader.imageComplete(); |
| + return m_imageLoader.imageComplete() && !hasPendingUpdate(); |
| } |
| void HTMLImageElement::didMoveToNewDocument(Document& oldDocument) |
| { |
| m_imageLoader.elementDidMoveToNewDocument(); |
| HTMLElement::didMoveToNewDocument(oldDocument); |
| + if (hasPendingUpdate()) { |
| + document().incrementLoadEventDelayCount(); |
| + oldDocument.decrementLoadEventDelayCount(); |
| + } |
| } |
| bool HTMLImageElement::isServerMap() const |
| @@ -472,4 +491,80 @@ FloatSize HTMLImageElement::defaultDestinationSize() const |
| return size; |
| } |
| +void HTMLImageElement::enqueueUpdate(PendingUpdateType type) |
| +{ |
| + ASSERT(type != PendingUpdateNone); |
| + |
| + v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| + bool isIsolatedWorld = false; |
| + if (isolate && isolate->InContext()) { |
| + if (DOMWrapperWorld::current(isolate).isIsolatedWorld()) |
| + isIsolatedWorld = true; |
| + } |
|
abarth-chromium
2014/04/01 23:57:14
The HTMLImageElement shouldn't have any knowledge
|
| + |
| + if (m_imageLoader.shouldLoadImmediately() || isIsolatedWorld) { |
|
abarth-chromium
2014/04/01 23:57:14
It's wrong to make image loading work differently
|
| + if (hasPendingUpdate()) |
| + cancelPendingUpdate(); |
| + if (type == PendingUpdateNormal) |
| + m_imageLoader.updateFromElement(); |
| + else |
| + m_imageLoader.updateFromElementIgnoringPreviousError(); |
| + return; |
| + } |
| + |
| + if (hasPendingUpdate()) { |
| + ASSERT(PendingUpdateQueue().contains(this)); |
| + if (m_pendingUpdate == PendingUpdateNormal && type == PendingUpdateIgnoreError) |
| + m_pendingUpdate = PendingUpdateIgnoreError; |
| + } else { |
| + document().incrementLoadEventDelayCount(); |
| + PendingUpdateQueue().append(this); |
| + m_pendingUpdate = type; |
| + } |
| + if (PendingUpdateQueue().size() == 1) |
| + Microtask::enqueueMicrotask(&processUpdateFromElementQueue); |
| +} |
| + |
| +void HTMLImageElement::cancelPendingUpdate() |
| +{ |
| + if (hasPendingUpdate()) { |
| + size_t pos = PendingUpdateQueue().find(this); |
| + ASSERT(pos != kNotFound); |
| + PendingUpdateQueue().remove(pos); |
| + m_pendingUpdate = PendingUpdateNone; |
| + document().decrementLoadEventDelayCount(); |
| + } |
| +} |
| + |
| +/* static */ void HTMLImageElement::processUpdateFromElementQueue() |
|
abarth-chromium
2014/04/01 23:57:14
We don't use /* static */ comments in Blink
|
| +{ |
| + PendingUpdateQueueType pending; |
| + pending.swap(PendingUpdateQueue()); |
| + |
| + // We keep this vector separately, because we can only call |
| + // decrementLoadEventDelayCount after we've updated all image elements |
| + // because the load event may destroy image elements. |
| + Vector<RefPtr<Document> > documents; |
| + |
| + { |
| + PendingUpdateQueueType::const_iterator i, end; |
| + for (i = pending.begin(), end = pending.end(); i != end; ++i) { |
| + RefPtr<HTMLImageElement> current = *i; |
| + if (current->m_pendingUpdate == PendingUpdateIgnoreError) { |
| + current->m_pendingUpdate = PendingUpdateNone; |
| + current->m_imageLoader.updateFromElementIgnoringPreviousError(); |
| + documents.append(¤t->document()); |
| + } else { |
| + ASSERT(current->m_pendingUpdate == PendingUpdateNormal); |
| + current->m_pendingUpdate = PendingUpdateNone; |
| + current->m_imageLoader.updateFromElement(); |
| + documents.append(¤t->document()); |
| + } |
| + } |
| + } |
| + Vector<RefPtr<Document> >::const_iterator i, end; |
| + for (i = documents.begin(), end = documents.end(); i != end; ++i) { |
| + (*i)->decrementLoadEventDelayCount(); |
| + } |
| +} |
| } |