| Index: sky/engine/core/loader/ImageLoader.cpp
|
| diff --git a/sky/engine/core/loader/ImageLoader.cpp b/sky/engine/core/loader/ImageLoader.cpp
|
| deleted file mode 100644
|
| index a4ddc9acaffc17388c95251f49acd572457169c2..0000000000000000000000000000000000000000
|
| --- a/sky/engine/core/loader/ImageLoader.cpp
|
| +++ /dev/null
|
| @@ -1,464 +0,0 @@
|
| -/*
|
| - * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
|
| - * (C) 1999 Antti Koivisto (koivisto@kde.org)
|
| - * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 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
|
| - * License as published by the Free Software Foundation; either
|
| - * version 2 of the License, or (at your option) any later version.
|
| - *
|
| - * This library is distributed in the hope that it will be useful,
|
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| - * Library General Public License for more details.
|
| - *
|
| - * You should have received a copy of the GNU Library General Public License
|
| - * along with this library; see the file COPYING.LIB. If not, write to
|
| - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
| - * Boston, MA 02110-1301, USA.
|
| - */
|
| -
|
| -#include "sky/engine/core/loader/ImageLoader.h"
|
| -
|
| -#include "sky/engine/core/dom/Document.h"
|
| -#include "sky/engine/core/dom/Element.h"
|
| -#include "sky/engine/core/dom/IncrementLoadEventDelayCount.h"
|
| -#include "sky/engine/core/dom/Microtask.h"
|
| -#include "sky/engine/core/events/Event.h"
|
| -#include "sky/engine/core/events/EventSender.h"
|
| -#include "sky/engine/core/fetch/FetchRequest.h"
|
| -#include "sky/engine/core/fetch/MemoryCache.h"
|
| -#include "sky/engine/core/fetch/ResourceFetcher.h"
|
| -#include "sky/engine/core/frame/LocalFrame.h"
|
| -#include "sky/engine/core/html/parser/HTMLParserIdioms.h"
|
| -#include "sky/engine/platform/Logging.h"
|
| -#include "sky/engine/public/platform/WebURLRequest.h"
|
| -
|
| -namespace blink {
|
| -
|
| -static ImageEventSender& loadEventSender()
|
| -{
|
| - DEFINE_STATIC_LOCAL(ImageEventSender, sender, (EventTypeNames::load));
|
| - return sender;
|
| -}
|
| -
|
| -static ImageEventSender& errorEventSender()
|
| -{
|
| - DEFINE_STATIC_LOCAL(ImageEventSender, sender, (EventTypeNames::error));
|
| - return sender;
|
| -}
|
| -
|
| -static inline bool pageIsBeingDismissed(Document* document)
|
| -{
|
| - return document->pageDismissalEventBeingDispatched() != Document::NoDismissal;
|
| -}
|
| -
|
| -class ImageLoader::Task : public blink::WebThread::Task {
|
| -public:
|
| - static PassOwnPtr<Task> create(ImageLoader* loader, UpdateFromElementBehavior updateBehavior)
|
| - {
|
| - return adoptPtr(new Task(loader, updateBehavior));
|
| - }
|
| -
|
| - Task(ImageLoader* loader, UpdateFromElementBehavior updateBehavior)
|
| - : m_loader(loader)
|
| - , m_weakFactory(this)
|
| - , m_updateBehavior(updateBehavior)
|
| - {
|
| - }
|
| -
|
| - virtual void run() override
|
| - {
|
| - if (m_loader) {
|
| - m_loader->doUpdateFromElement(m_updateBehavior);
|
| - }
|
| - }
|
| -
|
| - void clearLoader()
|
| - {
|
| - m_loader = 0;
|
| - }
|
| -
|
| - WeakPtr<Task> createWeakPtr()
|
| - {
|
| - return m_weakFactory.createWeakPtr();
|
| - }
|
| -
|
| -private:
|
| - ImageLoader* m_loader;
|
| - WeakPtrFactory<Task> m_weakFactory;
|
| - UpdateFromElementBehavior m_updateBehavior;
|
| -};
|
| -
|
| -ImageLoader::ImageLoader(Element* element)
|
| - : m_element(element)
|
| - , m_image(0)
|
| - , m_derefElementTimer(this, &ImageLoader::timerFired)
|
| - , m_hasPendingLoadEvent(false)
|
| - , m_hasPendingErrorEvent(false)
|
| - , m_imageComplete(true)
|
| - , m_elementIsProtected(false)
|
| - , m_highPriorityClientCount(0)
|
| -{
|
| - WTF_LOG(Timers, "new ImageLoader %p", this);
|
| -}
|
| -
|
| -ImageLoader::~ImageLoader()
|
| -{
|
| - WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, m_hasPendingErrorEvent=%d",
|
| - this, m_hasPendingLoadEvent, m_hasPendingErrorEvent);
|
| -
|
| - if (m_pendingTask)
|
| - m_pendingTask->clearLoader();
|
| -
|
| - if (m_image)
|
| - m_image->removeClient(this);
|
| -
|
| - ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(this));
|
| - if (m_hasPendingLoadEvent)
|
| - loadEventSender().cancelEvent(this);
|
| -
|
| - ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(this));
|
| - if (m_hasPendingErrorEvent)
|
| - errorEventSender().cancelEvent(this);
|
| -}
|
| -
|
| -void ImageLoader::setImage(ImageResource* newImage)
|
| -{
|
| - setImageWithoutConsideringPendingLoadEvent(newImage);
|
| -
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| -}
|
| -
|
| -void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newImage)
|
| -{
|
| - ASSERT(m_failedLoadURL.isEmpty());
|
| - ImageResource* oldImage = m_image.get();
|
| - if (newImage != oldImage) {
|
| - sourceImageChanged();
|
| - m_image = newImage;
|
| - if (m_hasPendingLoadEvent) {
|
| - loadEventSender().cancelEvent(this);
|
| - m_hasPendingLoadEvent = false;
|
| - }
|
| - if (m_hasPendingErrorEvent) {
|
| - errorEventSender().cancelEvent(this);
|
| - m_hasPendingErrorEvent = false;
|
| - }
|
| - m_imageComplete = true;
|
| - if (newImage)
|
| - newImage->addClient(this);
|
| - if (oldImage)
|
| - oldImage->removeClient(this);
|
| - }
|
| -}
|
| -
|
| -inline void ImageLoader::crossSiteOrCSPViolationOccured(AtomicString imageSourceURL)
|
| -{
|
| - m_failedLoadURL = imageSourceURL;
|
| - m_hasPendingErrorEvent = true;
|
| - errorEventSender().dispatchEventSoon(this);
|
| -}
|
| -
|
| -inline void ImageLoader::clearFailedLoadURL()
|
| -{
|
| - m_failedLoadURL = AtomicString();
|
| -}
|
| -
|
| -inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior)
|
| -{
|
| - OwnPtr<Task> task = Task::create(this, updateBehavior);
|
| - m_pendingTask = task->createWeakPtr();
|
| - Microtask::enqueueMicrotask(task.release());
|
| - m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->document());
|
| -}
|
| -
|
| -void ImageLoader::doUpdateFromElement(UpdateFromElementBehavior updateBehavior)
|
| -{
|
| - // FIXME: According to
|
| - // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#the-img-element:the-img-element-55
|
| - // When "update image" is called due to environment changes and the load fails, onerror should not be called.
|
| - // That is currently not the case.
|
| - //
|
| - // We don't need to call clearLoader here: Either we were called from the
|
| - // task, or our caller updateFromElement cleared the task's loader (and set
|
| - // m_pendingTask to null).
|
| - m_pendingTask.clear();
|
| - // Make sure to only decrement the count when we exit this function
|
| - OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter;
|
| - loadDelayCounter.swap(m_loadDelayCounter);
|
| -
|
| - Document& document = m_element->document();
|
| - if (!document.isActive())
|
| - return;
|
| -
|
| - AtomicString imageSourceURL = m_element->imageSourceURL();
|
| - KURL url = imageSourceToKURL(imageSourceURL);
|
| - ResourcePtr<ImageResource> newImage = 0;
|
| - if (!url.isNull()) {
|
| - // Unlike raw <img>, we block mixed content inside of <picture> or <img srcset>.
|
| - ResourceLoaderOptions resourceLoaderOptions = ResourceFetcher::defaultResourceOptions();
|
| - ResourceRequest resourceRequest(url);
|
| - FetchRequest request(ResourceRequest(url), element()->localName(), resourceLoaderOptions);
|
| -
|
| - newImage = document.fetcher()->fetchImage(request);
|
| -
|
| - if (!newImage && !pageIsBeingDismissed(&document))
|
| - crossSiteOrCSPViolationOccured(imageSourceURL);
|
| - else
|
| - clearFailedLoadURL();
|
| - } else if (!imageSourceURL.isNull()) {
|
| - // Fire an error event if the url string is not empty, but the KURL is.
|
| - m_hasPendingErrorEvent = true;
|
| - errorEventSender().dispatchEventSoon(this);
|
| - }
|
| -
|
| - ImageResource* oldImage = m_image.get();
|
| - if (newImage != oldImage) {
|
| - sourceImageChanged();
|
| -
|
| - if (m_hasPendingLoadEvent) {
|
| - loadEventSender().cancelEvent(this);
|
| - m_hasPendingLoadEvent = false;
|
| - }
|
| -
|
| - // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute.
|
| - // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by
|
| - // this load and we should not cancel the event.
|
| - // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
|
| - if (m_hasPendingErrorEvent && newImage) {
|
| - errorEventSender().cancelEvent(this);
|
| - m_hasPendingErrorEvent = false;
|
| - }
|
| -
|
| - m_image = newImage;
|
| - m_hasPendingLoadEvent = newImage;
|
| - m_imageComplete = !newImage;
|
| -
|
| - updateRenderer();
|
| - // If newImage exists and is cached, addClient() will result in the load event
|
| - // being queued to fire. Ensure this happens after beforeload is dispatched.
|
| - if (newImage)
|
| - newImage->addClient(this);
|
| -
|
| - if (oldImage)
|
| - oldImage->removeClient(this);
|
| - }
|
| -
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| -}
|
| -
|
| -void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, LoadType loadType)
|
| -{
|
| - AtomicString imageSourceURL = m_element->imageSourceURL();
|
| -
|
| - if (updateBehavior == UpdateIgnorePreviousError)
|
| - clearFailedLoadURL();
|
| -
|
| - if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL)
|
| - return;
|
| -
|
| - // If we have a pending task, we have to clear it -- either we're
|
| - // now loading immediately, or we need to reset the task's state.
|
| - if (m_pendingTask) {
|
| - m_pendingTask->clearLoader();
|
| - m_pendingTask.clear();
|
| - }
|
| -
|
| - KURL url = imageSourceToKURL(imageSourceURL);
|
| - if (imageSourceURL.isNull() || url.isNull() || shouldLoadImmediately(url, loadType)) {
|
| - doUpdateFromElement(updateBehavior);
|
| - return;
|
| - }
|
| - enqueueImageLoadingMicroTask(updateBehavior);
|
| -}
|
| -
|
| -KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const
|
| -{
|
| - KURL url;
|
| -
|
| - // Don't load images for inactive documents. We don't want to slow down the
|
| - // raw HTML parsing case by loading images we don't intend to display.
|
| - Document& document = m_element->document();
|
| - if (!document.isActive())
|
| - return url;
|
| -
|
| - // Do not load any image if the 'src' attribute is missing or if it is
|
| - // an empty string.
|
| - if (!imageSourceURL.isNull() && !stripLeadingAndTrailingHTMLSpaces(imageSourceURL).isEmpty())
|
| - url = document.completeURL(sourceURI(imageSourceURL));
|
| - return url;
|
| -}
|
| -
|
| -bool ImageLoader::shouldLoadImmediately(const KURL& url, LoadType loadType) const
|
| -{
|
| - return url.protocolIsData()
|
| - || memoryCache()->resourceForURL(url)
|
| - || loadType == ForceLoadImmediately;
|
| -}
|
| -
|
| -void ImageLoader::notifyFinished(Resource* resource)
|
| -{
|
| - WTF_LOG(Timers, "ImageLoader::notifyFinished %p; m_hasPendingLoadEvent=%d",
|
| - this, m_hasPendingLoadEvent);
|
| -
|
| - ASSERT(m_failedLoadURL.isEmpty());
|
| - ASSERT(resource == m_image.get());
|
| -
|
| - m_imageComplete = true;
|
| - updateRenderer();
|
| -
|
| - if (!m_hasPendingLoadEvent)
|
| - return;
|
| -
|
| - if (resource->errorOccurred()) {
|
| - loadEventSender().cancelEvent(this);
|
| - m_hasPendingLoadEvent = false;
|
| -
|
| - m_hasPendingErrorEvent = true;
|
| - errorEventSender().dispatchEventSoon(this);
|
| -
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| - return;
|
| - }
|
| - if (resource->wasCanceled()) {
|
| - m_hasPendingLoadEvent = false;
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| - return;
|
| - }
|
| - loadEventSender().dispatchEventSoon(this);
|
| -}
|
| -
|
| -void ImageLoader::updateRenderer()
|
| -{
|
| -}
|
| -
|
| -void ImageLoader::updatedHasPendingEvent()
|
| -{
|
| - // If an Element that does image loading is removed from the DOM the load/error event for the image is still observable.
|
| - // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being
|
| - // destroyed by DOM manipulation or garbage collection.
|
| - // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
|
| - bool wasProtected = m_elementIsProtected;
|
| - m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent;
|
| - if (wasProtected == m_elementIsProtected)
|
| - return;
|
| -
|
| - if (m_elementIsProtected) {
|
| - if (m_derefElementTimer.isActive())
|
| - m_derefElementTimer.stop();
|
| - else
|
| - m_keepAlive = m_element;
|
| - } else {
|
| - ASSERT(!m_derefElementTimer.isActive());
|
| - m_derefElementTimer.startOneShot(0, FROM_HERE);
|
| - }
|
| -}
|
| -
|
| -void ImageLoader::timerFired(Timer<ImageLoader>*)
|
| -{
|
| - m_keepAlive.clear();
|
| -}
|
| -
|
| -void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender)
|
| -{
|
| - WTF_LOG(Timers, "ImageLoader::dispatchPendingEvent %p", this);
|
| - ASSERT(eventSender == &loadEventSender() || eventSender == &errorEventSender());
|
| - const AtomicString& eventType = eventSender->eventType();
|
| - if (eventType == EventTypeNames::load)
|
| - dispatchPendingLoadEvent();
|
| - if (eventType == EventTypeNames::error)
|
| - dispatchPendingErrorEvent();
|
| -}
|
| -
|
| -void ImageLoader::dispatchPendingLoadEvent()
|
| -{
|
| - if (!m_hasPendingLoadEvent)
|
| - return;
|
| - if (!m_image)
|
| - return;
|
| - m_hasPendingLoadEvent = false;
|
| - if (element()->document().frame())
|
| - dispatchLoadEvent();
|
| -
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| -}
|
| -
|
| -void ImageLoader::dispatchPendingErrorEvent()
|
| -{
|
| - if (!m_hasPendingErrorEvent)
|
| - return;
|
| - m_hasPendingErrorEvent = false;
|
| -
|
| - if (element()->document().frame())
|
| - element()->dispatchEvent(Event::create(EventTypeNames::error));
|
| -
|
| - // Only consider updating the protection ref-count of the Element immediately before returning
|
| - // from this function as doing so might result in the destruction of this ImageLoader.
|
| - updatedHasPendingEvent();
|
| -}
|
| -
|
| -void ImageLoader::addClient(ImageLoaderClient* client)
|
| -{
|
| - if (client->requestsHighLiveResourceCachePriority()) {
|
| - if (m_image && !m_highPriorityClientCount++)
|
| - memoryCache()->updateDecodedResource(m_image.get(), UpdateForPropertyChange, MemoryCacheLiveResourcePriorityHigh);
|
| - }
|
| - m_clients.add(client);
|
| -}
|
| -
|
| -void ImageLoader::willRemoveClient(ImageLoaderClient& client)
|
| -{
|
| - if (client.requestsHighLiveResourceCachePriority()) {
|
| - ASSERT(m_highPriorityClientCount);
|
| - m_highPriorityClientCount--;
|
| - if (m_image && !m_highPriorityClientCount)
|
| - memoryCache()->updateDecodedResource(m_image.get(), UpdateForPropertyChange, MemoryCacheLiveResourcePriorityLow);
|
| - }
|
| -}
|
| -
|
| -void ImageLoader::removeClient(ImageLoaderClient* client)
|
| -{
|
| - willRemoveClient(*client);
|
| - m_clients.remove(client);
|
| -}
|
| -
|
| -void ImageLoader::dispatchPendingLoadEvents()
|
| -{
|
| - loadEventSender().dispatchPendingEvents();
|
| -}
|
| -
|
| -void ImageLoader::dispatchPendingErrorEvents()
|
| -{
|
| - errorEventSender().dispatchPendingEvents();
|
| -}
|
| -
|
| -void ImageLoader::elementDidMoveToNewDocument()
|
| -{
|
| - if (m_loadDelayCounter)
|
| - m_loadDelayCounter->documentChanged(m_element->document());
|
| - clearFailedLoadURL();
|
| - setImage(0);
|
| -}
|
| -
|
| -void ImageLoader::sourceImageChanged()
|
| -{
|
| - HashSet<ImageLoaderClient*>::iterator end = m_clients.end();
|
| - for (HashSet<ImageLoaderClient*>::iterator it = m_clients.begin(); it != end; ++it) {
|
| - ImageLoaderClient* handle = *it;
|
| - handle->notifyImageSourceChanged();
|
| - }
|
| -}
|
| -
|
| -}
|
|
|