diff options
Diffstat (limited to 'WebCore/loader/ImageLoader.cpp')
-rw-r--r-- | WebCore/loader/ImageLoader.cpp | 136 |
1 files changed, 115 insertions, 21 deletions
diff --git a/WebCore/loader/ImageLoader.cpp b/WebCore/loader/ImageLoader.cpp index 43e08c0..b183a66 100644 --- a/WebCore/loader/ImageLoader.cpp +++ b/WebCore/loader/ImageLoader.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,8 +31,33 @@ namespace WebCore { -ImageLoader::ImageLoader(Element* elt) - : m_element(elt) +class ImageLoadEventSender { +public: + ImageLoadEventSender(); + + void dispatchLoadEventSoon(ImageLoader*); + void cancelLoadEvent(ImageLoader*); + + void dispatchPendingLoadEvents(); + +private: + ~ImageLoadEventSender(); + + void timerFired(Timer<ImageLoadEventSender>*); + + Timer<ImageLoadEventSender> m_timer; + Vector<ImageLoader*> m_dispatchSoonList; + Vector<ImageLoader*> m_dispatchingList; +}; + +static ImageLoadEventSender& loadEventSender() +{ + DEFINE_STATIC_LOCAL(ImageLoadEventSender, sender, ()); + return sender; +} + +ImageLoader::ImageLoader(Element* element) + : m_element(element) , m_image(0) , m_firedLoad(true) , m_imageComplete(true) @@ -44,7 +69,7 @@ ImageLoader::~ImageLoader() { if (m_image) m_image->removeClient(this); - m_element->document()->removeImage(this); + loadEventSender().cancelLoadEvent(this); } void ImageLoader::setImage(CachedImage* newImage) @@ -61,11 +86,11 @@ void ImageLoader::setImage(CachedImage* newImage) oldImage->removeClient(this); } - if (RenderObject* renderer = element()->renderer()) { + if (RenderObject* renderer = m_element->renderer()) { if (!renderer->isImage()) return; - static_cast<RenderImage*>(renderer)->resetAnimation(); + toRenderImage(renderer)->resetAnimation(); } } @@ -80,12 +105,11 @@ void ImageLoader::updateFromElement() { // If we're not making renderers for the page, then don't load images. We don't want to slow // down the raw HTML parsing case by loading images we don't intend to display. - Element* elem = element(); - Document* doc = elem->document(); - if (!doc->renderer()) + Document* document = m_element->document(); + if (!document->renderer()) return; - AtomicString attr = elem->getAttribute(elem->imageSourceAttributeName()); + AtomicString attr = m_element->getAttribute(m_element->imageSourceAttributeName()); if (attr == m_failedLoadURL) return; @@ -95,15 +119,15 @@ void ImageLoader::updateFromElement() // a quirk that preserves old behavior that Dashboard widgets // need (<rdar://problem/5994621>). CachedImage* newImage = 0; - if (!(attr.isNull() || attr.isEmpty() && doc->baseURI().isLocalFile())) { + if (!(attr.isNull() || (attr.isEmpty() && document->baseURI().isLocalFile()))) { if (m_loadManually) { - doc->docLoader()->setAutoLoadImages(false); + document->docLoader()->setAutoLoadImages(false); newImage = new CachedImage(sourceURI(attr)); newImage->setLoading(true); - newImage->setDocLoader(doc->docLoader()); - doc->docLoader()->m_documentResources.set(newImage->url(), newImage); + newImage->setDocLoader(document->docLoader()); + document->docLoader()->m_documentResources.set(newImage->url(), newImage); } else - newImage = doc->docLoader()->requestImage(sourceURI(attr)); + newImage = document->docLoader()->requestImage(sourceURI(attr)); // If we do not have an image here, it means that a cross-site // violation occurred. @@ -119,11 +143,11 @@ void ImageLoader::updateFromElement() oldImage->removeClient(this); } - if (RenderObject* renderer = elem->renderer()) { + if (RenderObject* renderer = m_element->renderer()) { if (!renderer->isImage()) return; - static_cast<RenderImage*>(renderer)->resetAnimation(); + toRenderImage(renderer)->resetAnimation(); } } @@ -139,15 +163,85 @@ void ImageLoader::notifyFinished(CachedResource*) ASSERT(m_failedLoadURL.isEmpty()); m_imageComplete = true; - Element* elem = element(); - elem->document()->dispatchImageLoadEventSoon(this); + loadEventSender().dispatchLoadEventSoon(this); - if (RenderObject* renderer = elem->renderer()) { + if (RenderObject* renderer = m_element->renderer()) { if (!renderer->isImage()) return; - static_cast<RenderImage*>(renderer)->setCachedImage(m_image.get()); + toRenderImage(renderer)->setCachedImage(m_image.get()); } } +void ImageLoader::dispatchPendingLoadEvent() +{ + if (m_firedLoad) + return; + if (!m_image) + return; + if (!m_element->document()->attached()) + return; + m_firedLoad = true; + dispatchLoadEvent(); +} + +void ImageLoader::dispatchPendingLoadEvents() +{ + loadEventSender().dispatchPendingLoadEvents(); +} + +ImageLoadEventSender::ImageLoadEventSender() + : m_timer(this, &ImageLoadEventSender::timerFired) +{ +} + +void ImageLoadEventSender::dispatchLoadEventSoon(ImageLoader* loader) +{ + m_dispatchSoonList.append(loader); + if (!m_timer.isActive()) + m_timer.startOneShot(0); +} + +void ImageLoadEventSender::cancelLoadEvent(ImageLoader* loader) +{ + // Remove instances of this loader from both lists. + // Use loops because we allow multiple instances to get into the lists. + size_t size = m_dispatchSoonList.size(); + for (size_t i = 0; i < size; ++i) { + if (m_dispatchSoonList[i] == loader) + m_dispatchSoonList[i] = 0; + } + size = m_dispatchingList.size(); + for (size_t i = 0; i < size; ++i) { + if (m_dispatchingList[i] == loader) + m_dispatchingList[i] = 0; + } + if (m_dispatchSoonList.isEmpty()) + m_timer.stop(); +} + +void ImageLoadEventSender::dispatchPendingLoadEvents() +{ + // Need to avoid re-entering this function; if new dispatches are + // scheduled before the parent finishes processing the list, they + // will set a timer and eventually be processed. + if (!m_dispatchingList.isEmpty()) + return; + + m_timer.stop(); + + m_dispatchingList.swap(m_dispatchSoonList); + size_t size = m_dispatchingList.size(); + for (size_t i = 0; i < size; ++i) { + if (ImageLoader* loader = m_dispatchingList[i]) + loader->dispatchPendingLoadEvent(); + } + m_dispatchingList.clear(); +} + +void ImageLoadEventSender::timerFired(Timer<ImageLoadEventSender>*) +{ + dispatchPendingLoadEvents(); +} + } |