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

Side by Side Diff: Source/core/html/HTMLImageElement.cpp

Issue 200923002: Post a microtask to load <img> elements. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: all tests fixed Created 6 years, 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv ed. 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv ed.
5 * Copyright (C) 2010 Google Inc. All rights reserved. 5 * Copyright (C) 2010 Google Inc. All rights reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details. 15 * Library General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Library General Public License 17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to 18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA. 20 * Boston, MA 02110-1301, USA.
21 */ 21 */
22 22
23 #include "config.h" 23 #include "config.h"
24 #include "core/html/HTMLImageElement.h" 24 #include "core/html/HTMLImageElement.h"
25 25
26 #include "CSSPropertyNames.h" 26 #include "CSSPropertyNames.h"
27 #include "HTMLNames.h" 27 #include "HTMLNames.h"
28 #include "RuntimeEnabledFeatures.h" 28 #include "RuntimeEnabledFeatures.h"
29 #include "bindings/v8/DOMWrapperWorld.h"
29 #include "bindings/v8/ScriptEventListener.h" 30 #include "bindings/v8/ScriptEventListener.h"
30 #include "core/dom/Attribute.h" 31 #include "core/dom/Attribute.h"
32 #include "core/dom/Microtask.h"
31 #include "core/fetch/ImageResource.h" 33 #include "core/fetch/ImageResource.h"
32 #include "core/html/HTMLAnchorElement.h" 34 #include "core/html/HTMLAnchorElement.h"
33 #include "core/html/HTMLCanvasElement.h" 35 #include "core/html/HTMLCanvasElement.h"
34 #include "core/html/HTMLFormElement.h" 36 #include "core/html/HTMLFormElement.h"
35 #include "core/html/canvas/CanvasRenderingContext.h" 37 #include "core/html/canvas/CanvasRenderingContext.h"
36 #include "core/html/parser/HTMLParserIdioms.h" 38 #include "core/html/parser/HTMLParserIdioms.h"
37 #include "core/html/parser/HTMLSrcsetParser.h" 39 #include "core/html/parser/HTMLSrcsetParser.h"
38 #include "core/rendering/RenderImage.h" 40 #include "core/rendering/RenderImage.h"
41 #include "wtf/Vector.h"
42 #include <v8.h>
39 43
40 using namespace std; 44 using namespace std;
41 45
46 namespace {
47 typedef Vector<WebCore::HTMLImageElement*> PendingUpdateQueueType;
48 static PendingUpdateQueueType& PendingUpdateQueue()
49 {
50 DEFINE_STATIC_LOCAL(Vector<WebCore::HTMLImageElement*>, pendingUpdateFromEle mentCalls, ());
51 return pendingUpdateFromElementCalls;
52 }
53 }
54
42 namespace WebCore { 55 namespace WebCore {
43 56
44 using namespace HTMLNames; 57 using namespace HTMLNames;
45 58
46 HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form) 59 HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form)
47 : HTMLElement(imgTag, document) 60 : HTMLElement(imgTag, document)
48 , m_imageLoader(this) 61 , m_imageLoader(this)
49 , m_compositeOperator(CompositeSourceOver) 62 , m_compositeOperator(CompositeSourceOver)
50 , m_imageDevicePixelRatio(1.0f) 63 , m_imageDevicePixelRatio(1.0f)
51 , m_formWasSetByParser(false) 64 , m_formWasSetByParser(false)
65 , m_pendingUpdate(PendingUpdateNone)
52 { 66 {
53 ScriptWrappable::init(this); 67 ScriptWrappable::init(this);
54 if (form && form->inDocument()) { 68 if (form && form->inDocument()) {
55 m_form = form->createWeakPtr(); 69 m_form = form->createWeakPtr();
56 m_formWasSetByParser = true; 70 m_formWasSetByParser = true;
57 m_form->associate(*this); 71 m_form->associate(*this);
58 m_form->didAssociateByParser(); 72 m_form->didAssociateByParser();
59 } 73 }
60 } 74 }
61 75
62 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document) 76 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document)
63 { 77 {
64 return adoptRef(new HTMLImageElement(document)); 78 return adoptRef(new HTMLImageElement(document));
65 } 79 }
66 80
67 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document, HTMLFo rmElement* form) 81 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document, HTMLFo rmElement* form)
68 { 82 {
69 return adoptRef(new HTMLImageElement(document, form)); 83 return adoptRef(new HTMLImageElement(document, form));
70 } 84 }
71 85
72 HTMLImageElement::~HTMLImageElement() 86 HTMLImageElement::~HTMLImageElement()
73 { 87 {
74 if (m_form) 88 if (m_form)
75 m_form->disassociate(*this); 89 m_form->disassociate(*this);
90 cancelPendingUpdate();
abarth-chromium 2014/04/01 23:57:14 This algorithm is O(N^2) when tearing down the doc
76 } 91 }
77 92
78 PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width, int height) 93 PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width, int height)
79 { 94 {
80 RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(document)); 95 RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(document));
81 if (width) 96 if (width)
82 image->setWidth(width); 97 image->setWidth(width);
83 if (height) 98 if (height)
84 image->setHeight(height); 99 image->setHeight(height);
85 return image.release(); 100 return image.release();
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 } else if (name == srcAttr || name == srcsetAttr) { 171 } else if (name == srcAttr || name == srcsetAttr) {
157 if (RuntimeEnabledFeatures::srcsetEnabled()) { 172 if (RuntimeEnabledFeatures::srcsetEnabled()) {
158 ImageCandidate candidate = bestFitSourceForImageAttributes(document( ).devicePixelRatio(), fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr)); 173 ImageCandidate candidate = bestFitSourceForImageAttributes(document( ).devicePixelRatio(), fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr));
159 m_bestFitImageURL = candidate.toAtomicString(); 174 m_bestFitImageURL = candidate.toAtomicString();
160 float candidateScaleFactor = candidate.scaleFactor(); 175 float candidateScaleFactor = candidate.scaleFactor();
161 if (candidateScaleFactor > 0) 176 if (candidateScaleFactor > 0)
162 m_imageDevicePixelRatio = 1 / candidateScaleFactor; 177 m_imageDevicePixelRatio = 1 / candidateScaleFactor;
163 if (renderer() && renderer()->isImage()) 178 if (renderer() && renderer()->isImage())
164 toRenderImage(renderer())->setImageDevicePixelRatio(m_imageDevic ePixelRatio); 179 toRenderImage(renderer())->setImageDevicePixelRatio(m_imageDevic ePixelRatio);
165 } 180 }
166 m_imageLoader.updateFromElementIgnoringPreviousError(); 181 enqueueUpdate(PendingUpdateIgnoreError);
167 } else if (name == usemapAttr) { 182 } else if (name == usemapAttr) {
168 setIsLink(!value.isNull()); 183 setIsLink(!value.isNull());
169 } else if (name == compositeAttr) { 184 } else if (name == compositeAttr) {
170 // FIXME: images don't support blend modes in their compositing attribut e. 185 // FIXME: images don't support blend modes in their compositing attribut e.
171 blink::WebBlendMode blendOp = blink::WebBlendModeNormal; 186 blink::WebBlendMode blendOp = blink::WebBlendModeNormal;
172 if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp) ) 187 if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp) )
173 m_compositeOperator = CompositeSourceOver; 188 m_compositeOperator = CompositeSourceOver;
174 } else { 189 } else {
175 HTMLElement::parseAttribute(name, value); 190 HTMLElement::parseAttribute(name, value);
176 } 191 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 } 243 }
229 244
230 Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint) 245 Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
231 { 246 {
232 if (!m_formWasSetByParser || insertionPoint->highestAncestor() != m_form->hi ghestAncestor()) 247 if (!m_formWasSetByParser || insertionPoint->highestAncestor() != m_form->hi ghestAncestor())
233 resetFormOwner(); 248 resetFormOwner();
234 249
235 // If we have been inserted from a renderer-less document, 250 // If we have been inserted from a renderer-less document,
236 // our loader may have not fetched the image, so do it now. 251 // our loader may have not fetched the image, so do it now.
237 if (insertionPoint->inDocument() && !m_imageLoader.image()) 252 if (insertionPoint->inDocument() && !m_imageLoader.image())
238 m_imageLoader.updateFromElement(); 253 enqueueUpdate(PendingUpdateNormal);
239 254
240 return HTMLElement::insertedInto(insertionPoint); 255 return HTMLElement::insertedInto(insertionPoint);
241 } 256 }
242 257
243 void HTMLImageElement::removedFrom(ContainerNode* insertionPoint) 258 void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
244 { 259 {
245 if (!m_form || m_form->highestAncestor() != highestAncestor()) 260 if (!m_form || m_form->highestAncestor() != highestAncestor())
246 resetFormOwner(); 261 resetFormOwner();
247 HTMLElement::removedFrom(insertionPoint); 262 HTMLElement::removedFrom(insertionPoint);
248 } 263 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 if (!r) 391 if (!r)
377 return 0; 392 return 0;
378 393
379 // FIXME: This doesn't work correctly with transforms. 394 // FIXME: This doesn't work correctly with transforms.
380 FloatPoint absPos = r->localToAbsolute(); 395 FloatPoint absPos = r->localToAbsolute();
381 return absPos.y(); 396 return absPos.y();
382 } 397 }
383 398
384 bool HTMLImageElement::complete() const 399 bool HTMLImageElement::complete() const
385 { 400 {
386 return m_imageLoader.imageComplete(); 401 return m_imageLoader.imageComplete() && !hasPendingUpdate();
387 } 402 }
388 403
389 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument) 404 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument)
390 { 405 {
391 m_imageLoader.elementDidMoveToNewDocument(); 406 m_imageLoader.elementDidMoveToNewDocument();
392 HTMLElement::didMoveToNewDocument(oldDocument); 407 HTMLElement::didMoveToNewDocument(oldDocument);
408 if (hasPendingUpdate()) {
409 document().incrementLoadEventDelayCount();
410 oldDocument.decrementLoadEventDelayCount();
411 }
393 } 412 }
394 413
395 bool HTMLImageElement::isServerMap() const 414 bool HTMLImageElement::isServerMap() const
396 { 415 {
397 if (!fastHasAttribute(ismapAttr)) 416 if (!fastHasAttribute(ismapAttr))
398 return false; 417 return false;
399 418
400 const AtomicString& usemap = fastGetAttribute(usemapAttr); 419 const AtomicString& usemap = fastGetAttribute(usemapAttr);
401 420
402 // If the usemap attribute starts with '#', it refers to a map element in th e document. 421 // If the usemap attribute starts with '#', it refers to a map element in th e document.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 ImageResource* image = cachedImage(); 484 ImageResource* image = cachedImage();
466 if (!image) 485 if (!image)
467 return FloatSize(); 486 return FloatSize();
468 LayoutSize size; 487 LayoutSize size;
469 size = image->imageSizeForRenderer(renderer(), 1.0f); // FIXME: Not sure abo ut this. 488 size = image->imageSizeForRenderer(renderer(), 1.0f); // FIXME: Not sure abo ut this.
470 if (renderer() && renderer()->isRenderImage() && image->image() && !image->i mage()->hasRelativeWidth()) 489 if (renderer() && renderer()->isRenderImage() && image->image() && !image->i mage()->hasRelativeWidth())
471 size.scale(toRenderImage(renderer())->imageDevicePixelRatio()); 490 size.scale(toRenderImage(renderer())->imageDevicePixelRatio());
472 return size; 491 return size;
473 } 492 }
474 493
494 void HTMLImageElement::enqueueUpdate(PendingUpdateType type)
495 {
496 ASSERT(type != PendingUpdateNone);
497
498 v8::Isolate* isolate = v8::Isolate::GetCurrent();
499 bool isIsolatedWorld = false;
500 if (isolate && isolate->InContext()) {
501 if (DOMWrapperWorld::current(isolate).isIsolatedWorld())
502 isIsolatedWorld = true;
503 }
abarth-chromium 2014/04/01 23:57:14 The HTMLImageElement shouldn't have any knowledge
504
505 if (m_imageLoader.shouldLoadImmediately() || isIsolatedWorld) {
abarth-chromium 2014/04/01 23:57:14 It's wrong to make image loading work differently
506 if (hasPendingUpdate())
507 cancelPendingUpdate();
508 if (type == PendingUpdateNormal)
509 m_imageLoader.updateFromElement();
510 else
511 m_imageLoader.updateFromElementIgnoringPreviousError();
512 return;
513 }
514
515 if (hasPendingUpdate()) {
516 ASSERT(PendingUpdateQueue().contains(this));
517 if (m_pendingUpdate == PendingUpdateNormal && type == PendingUpdateIgnor eError)
518 m_pendingUpdate = PendingUpdateIgnoreError;
519 } else {
520 document().incrementLoadEventDelayCount();
521 PendingUpdateQueue().append(this);
522 m_pendingUpdate = type;
523 }
524 if (PendingUpdateQueue().size() == 1)
525 Microtask::enqueueMicrotask(&processUpdateFromElementQueue);
475 } 526 }
527
528 void HTMLImageElement::cancelPendingUpdate()
529 {
530 if (hasPendingUpdate()) {
531 size_t pos = PendingUpdateQueue().find(this);
532 ASSERT(pos != kNotFound);
533 PendingUpdateQueue().remove(pos);
534 m_pendingUpdate = PendingUpdateNone;
535 document().decrementLoadEventDelayCount();
536 }
537 }
538
539 /* static */ void HTMLImageElement::processUpdateFromElementQueue()
abarth-chromium 2014/04/01 23:57:14 We don't use /* static */ comments in Blink
540 {
541 PendingUpdateQueueType pending;
542 pending.swap(PendingUpdateQueue());
543
544 // We keep this vector separately, because we can only call
545 // decrementLoadEventDelayCount after we've updated all image elements
546 // because the load event may destroy image elements.
547 Vector<RefPtr<Document> > documents;
548
549 {
550 PendingUpdateQueueType::const_iterator i, end;
551 for (i = pending.begin(), end = pending.end(); i != end; ++i) {
552 RefPtr<HTMLImageElement> current = *i;
553 if (current->m_pendingUpdate == PendingUpdateIgnoreError) {
554 current->m_pendingUpdate = PendingUpdateNone;
555 current->m_imageLoader.updateFromElementIgnoringPreviousError();
556 documents.append(&current->document());
557 } else {
558 ASSERT(current->m_pendingUpdate == PendingUpdateNormal);
559 current->m_pendingUpdate = PendingUpdateNone;
560 current->m_imageLoader.updateFromElement();
561 documents.append(&current->document());
562 }
563 }
564 }
565 Vector<RefPtr<Document> >::const_iterator i, end;
566 for (i = documents.begin(), end = documents.end(); i != end; ++i) {
567 (*i)->decrementLoadEventDelayCount();
568 }
569 }
570 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698