summaryrefslogtreecommitdiff
path: root/chromium/third_party/WebKit/Source/core/loader/cache
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/loader/cache')
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.cpp183
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.h67
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/CachePolicy.h41
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.cpp82
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.h62
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/DocumentResourceReference.h45
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorInfo.h49
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorTypeNames.in8
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.cpp78
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.h74
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FontResource.cpp164
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/FontResource.h87
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.cpp451
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.h120
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceClient.h52
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceTest.cpp157
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.cpp619
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.h210
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/MemoryCacheTest.cpp194
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/MockImageResourceClient.h72
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/RawResource.cpp196
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/RawResource.h90
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/Resource.cpp839
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/Resource.h361
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourceClient.h57
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourceClientWalker.h69
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.cpp1301
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.h236
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcherTest.cpp68
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.cpp42
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.h115
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.cpp92
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.h55
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.cpp61
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.h54
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/StyleSheetResourceClient.h46
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.cpp53
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.h43
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.cpp78
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.h55
40 files changed, 6726 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.cpp
new file mode 100644
index 00000000000..53398a20d92
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.cpp
@@ -0,0 +1,183 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "core/loader/cache/CSSStyleSheetResource.h"
+
+#include "core/css/StyleSheetContents.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/loader/cache/StyleSheetResourceClient.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/platform/network/HTTPParsers.h"
+#include "wtf/CurrentTime.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+CSSStyleSheetResource::CSSStyleSheetResource(const ResourceRequest& resourceRequest, const String& charset)
+ : Resource(resourceRequest, CSSStyleSheet)
+ , m_decoder(TextResourceDecoder::create("text/css", charset))
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, acceptCSS, ("text/css,*/*;q=0.1", AtomicString::ConstructFromLiteral));
+
+ // Prefer text/css but accept any type (dell.com serves a stylesheet
+ // as text/html; see <http://bugs.webkit.org/show_bug.cgi?id=11451>).
+ setAccept(acceptCSS);
+}
+
+CSSStyleSheetResource::~CSSStyleSheetResource()
+{
+ if (m_parsedStyleSheetCache)
+ m_parsedStyleSheetCache->removedFromMemoryCache();
+}
+
+void CSSStyleSheetResource::didAddClient(ResourceClient* c)
+{
+ ASSERT(c->resourceClientType() == StyleSheetResourceClient::expectedType());
+ // Resource::didAddClient() must be before setCSSStyleSheet(),
+ // because setCSSStyleSheet() may cause scripts to be executed, which could destroy 'c' if it is an instance of HTMLLinkElement.
+ // see the comment of HTMLLinkElement::setCSSStyleSheet.
+ Resource::didAddClient(c);
+
+ if (!isLoading())
+ static_cast<StyleSheetResourceClient*>(c)->setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
+}
+
+void CSSStyleSheetResource::setEncoding(const String& chs)
+{
+ m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
+}
+
+String CSSStyleSheetResource::encoding() const
+{
+ return m_decoder->encoding().name();
+}
+
+const String CSSStyleSheetResource::sheetText(bool enforceMIMEType, bool* hasValidMIMEType) const
+{
+ ASSERT(!isPurgeable());
+
+ if (!m_data || m_data->isEmpty() || !canUseSheet(enforceMIMEType, hasValidMIMEType))
+ return String();
+
+ if (!m_decodedSheetText.isNull())
+ return m_decodedSheetText;
+
+ // Don't cache the decoded text, regenerating is cheap and it can use quite a bit of memory
+ String sheetText = m_decoder->decode(m_data->data(), m_data->size());
+ sheetText.append(m_decoder->flush());
+ return sheetText;
+}
+
+void CSSStyleSheetResource::checkNotify()
+{
+ // Decode the data to find out the encoding and keep the sheet text around during checkNotify()
+ if (m_data) {
+ m_decodedSheetText = m_decoder->decode(m_data->data(), m_data->size());
+ m_decodedSheetText.append(m_decoder->flush());
+ }
+
+ ResourceClientWalker<StyleSheetResourceClient> w(m_clients);
+ while (StyleSheetResourceClient* c = w.next())
+ c->setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
+ // Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
+ m_decodedSheetText = String();
+}
+
+bool CSSStyleSheetResource::canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const
+{
+ if (errorOccurred())
+ return false;
+
+ if (!enforceMIMEType && !hasValidMIMEType)
+ return true;
+
+ // This check exactly matches Firefox. Note that we grab the Content-Type
+ // header directly because we want to see what the value is BEFORE content
+ // sniffing. Firefox does this by setting a "type hint" on the channel.
+ // This implementation should be observationally equivalent.
+ //
+ // This code defaults to allowing the stylesheet for non-HTTP protocols so
+ // folks can use standards mode for local HTML documents.
+ String mimeType = extractMIMETypeFromMediaType(response().httpHeaderField("Content-Type"));
+ bool typeOK = mimeType.isEmpty() || equalIgnoringCase(mimeType, "text/css") || equalIgnoringCase(mimeType, "application/x-unknown-content-type");
+ if (hasValidMIMEType)
+ *hasValidMIMEType = typeOK;
+ if (!enforceMIMEType)
+ return true;
+ return typeOK;
+}
+
+void CSSStyleSheetResource::destroyDecodedData()
+{
+ if (!m_parsedStyleSheetCache)
+ return;
+
+ m_parsedStyleSheetCache->removedFromMemoryCache();
+ m_parsedStyleSheetCache.clear();
+
+ setDecodedSize(0);
+
+ if (isSafeToMakePurgeable())
+ makePurgeable(true);
+}
+
+PassRefPtr<StyleSheetContents> CSSStyleSheetResource::restoreParsedStyleSheet(const CSSParserContext& context)
+{
+ if (!m_parsedStyleSheetCache)
+ return 0;
+ if (m_parsedStyleSheetCache->hasFailedOrCanceledSubresources()) {
+ m_parsedStyleSheetCache->removedFromMemoryCache();
+ m_parsedStyleSheetCache.clear();
+ return 0;
+ }
+
+ ASSERT(m_parsedStyleSheetCache->isCacheable());
+ ASSERT(m_parsedStyleSheetCache->isInMemoryCache());
+
+ // Contexts must be identical so we know we would get the same exact result if we parsed again.
+ if (m_parsedStyleSheetCache->parserContext() != context)
+ return 0;
+
+ didAccessDecodedData(currentTime());
+
+ return m_parsedStyleSheetCache;
+}
+
+void CSSStyleSheetResource::saveParsedStyleSheet(PassRefPtr<StyleSheetContents> sheet)
+{
+ ASSERT(sheet && sheet->isCacheable());
+
+ if (m_parsedStyleSheetCache)
+ m_parsedStyleSheetCache->removedFromMemoryCache();
+ m_parsedStyleSheetCache = sheet;
+ m_parsedStyleSheetCache->addedToMemoryCache();
+
+ setDecodedSize(m_parsedStyleSheetCache->estimatedSizeInBytes());
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.h
new file mode 100644
index 00000000000..b01fa8667f3
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/CSSStyleSheetResource.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef CSSStyleSheetResource_h
+#define CSSStyleSheetResource_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class ResourceClient;
+class StyleSheetContents;
+class TextResourceDecoder;
+struct CSSParserContext;
+
+class CSSStyleSheetResource : public Resource {
+public:
+ CSSStyleSheetResource(const ResourceRequest&, const String& charset);
+ virtual ~CSSStyleSheetResource();
+
+ const String sheetText(bool enforceMIMEType = true, bool* hasValidMIMEType = 0) const;
+
+ virtual void didAddClient(ResourceClient*);
+ virtual void setEncoding(const String&);
+ virtual String encoding() const;
+ virtual void destroyDecodedData() OVERRIDE;
+
+ PassRefPtr<StyleSheetContents> restoreParsedStyleSheet(const CSSParserContext&);
+ void saveParsedStyleSheet(PassRefPtr<StyleSheetContents>);
+
+private:
+ bool canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const;
+
+protected:
+ virtual void checkNotify();
+
+ RefPtr<TextResourceDecoder> m_decoder;
+ String m_decodedSheetText;
+
+ RefPtr<StyleSheetContents> m_parsedStyleSheetCache;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/CachePolicy.h b/chromium/third_party/WebKit/Source/core/loader/cache/CachePolicy.h
new file mode 100644
index 00000000000..a44c32d26cc
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/CachePolicy.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachePolicy_h
+#define CachePolicy_h
+
+namespace WebCore {
+
+ enum CachePolicy {
+ CachePolicyCache,
+ CachePolicyVerify,
+ CachePolicyRevalidate,
+ CachePolicyReload,
+ CachePolicyHistoryBuffer
+ };
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.cpp
new file mode 100644
index 00000000000..27503416f14
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.cpp
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
+ Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
+ Copyright (C) 2012 University of Szeged
+ Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
+
+ 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 "config.h"
+
+#include "core/loader/cache/DocumentResource.h"
+
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/svg/SVGDocument.h"
+#include "wtf/text/StringBuilder.h"
+
+namespace WebCore {
+
+DocumentResource::DocumentResource(const ResourceRequest& request, Type type)
+ : Resource(request, type)
+ , m_decoder(TextResourceDecoder::create("application/xml"))
+{
+ // FIXME: We'll support more types to support HTMLImports.
+ ASSERT(type == SVGDocument);
+}
+
+DocumentResource::~DocumentResource()
+{
+}
+
+void DocumentResource::setEncoding(const String& chs)
+{
+ m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
+}
+
+String DocumentResource::encoding() const
+{
+ return m_decoder->encoding().name();
+}
+
+void DocumentResource::checkNotify()
+{
+ if (m_data) {
+ StringBuilder decodedText;
+ decodedText.append(m_decoder->decode(m_data->data(), m_data->size()));
+ decodedText.append(m_decoder->flush());
+ // We don't need to create a new frame because the new document belongs to the parent UseElement.
+ m_document = createDocument(response().url());
+ m_document->setContent(decodedText.toString());
+ }
+ Resource::checkNotify();
+}
+
+PassRefPtr<Document> DocumentResource::createDocument(const KURL& url)
+{
+ switch (type()) {
+ case SVGDocument:
+ return SVGDocument::create(DocumentInit(url));
+ default:
+ // FIXME: We'll add more types to support HTMLImports.
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.h
new file mode 100644
index 00000000000..62379d70925
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResource.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
+ Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
+ Copyright (C) 2012 University of Szeged
+ Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
+
+ 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.
+*/
+
+#ifndef DocumentResource_h
+#define DocumentResource_h
+
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/Resource.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourcePtr.h"
+
+namespace WebCore {
+
+class Document;
+
+class DocumentResource : public Resource {
+public:
+ DocumentResource(const ResourceRequest&, Type);
+ virtual ~DocumentResource();
+
+ Document* document() const { return m_document.get(); }
+
+ virtual void setEncoding(const String&);
+ virtual String encoding() const;
+ virtual void checkNotify() OVERRIDE;
+
+private:
+ PassRefPtr<Document> createDocument(const KURL&);
+
+ RefPtr<Document> m_document;
+ RefPtr<TextResourceDecoder> m_decoder;
+};
+
+class DocumentResourceClient : public ResourceClient {
+public:
+ virtual ~DocumentResourceClient() { }
+ static ResourceClientType expectedType() { return DocumentType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+};
+
+}
+
+#endif // DocumentResource_h
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResourceReference.h b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResourceReference.h
new file mode 100644
index 00000000000..4d7009cb434
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/DocumentResourceReference.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DocumentResourceReference_h
+#define DocumentResourceReference_h
+
+#include "core/loader/cache/DocumentResource.h"
+#include "core/loader/cache/ResourcePtr.h"
+
+namespace WebCore {
+
+class DocumentResourceReference : public DocumentResourceClient {
+public:
+ DocumentResourceReference(DocumentResource* document) : m_document(document) { m_document->addClient(this); }
+ virtual ~DocumentResourceReference() { m_document->removeClient(this); }
+ DocumentResource* document() { return m_document.get(); }
+private:
+ ResourcePtr<DocumentResource> m_document;
+};
+
+};
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorInfo.h b/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorInfo.h
new file mode 100644
index 00000000000..c5e9b3a67b8
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorInfo.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FetchInitiatorInfo_h
+#define FetchInitiatorInfo_h
+
+#include "wtf/text/AtomicString.h"
+#include "wtf/text/TextPosition.h"
+
+namespace WebCore {
+
+struct FetchInitiatorInfo {
+ FetchInitiatorInfo()
+ : name()
+ , position(TextPosition::belowRangePosition())
+ , startTime(0.0)
+ {
+ }
+
+ AtomicString name;
+ TextPosition position;
+ double startTime;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorTypeNames.in b/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorTypeNames.in
new file mode 100644
index 00000000000..7356271ceb4
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FetchInitiatorTypeNames.in
@@ -0,0 +1,8 @@
+css
+document
+icon
+link
+processinginstruction
+texttrack
+xml
+xmlhttprequest
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.cpp
new file mode 100644
index 00000000000..57268b2979e
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/FetchRequest.h"
+
+#include "core/dom/Element.h"
+#include "core/loader/CrossOriginAccessControl.h"
+#include "core/loader/cache/FetchInitiatorInfo.h"
+#include "core/loader/cache/ResourceFetcher.h"
+
+namespace WebCore {
+
+FetchRequest::FetchRequest(const ResourceRequest& resourceRequest, const AtomicString& initiator, const String& charset, ResourceLoadPriority priority)
+ : m_resourceRequest(resourceRequest)
+ , m_charset(charset)
+ , m_options(ResourceFetcher::defaultResourceOptions())
+ , m_priority(priority)
+ , m_forPreload(false)
+ , m_defer(NoDefer)
+{
+ m_options.initiatorInfo.name = initiator;
+}
+
+FetchRequest::FetchRequest(const ResourceRequest& resourceRequest, const AtomicString& initiator, const ResourceLoaderOptions& options)
+ : m_resourceRequest(resourceRequest)
+ , m_options(options)
+ , m_priority(ResourceLoadPriorityUnresolved)
+ , m_forPreload(false)
+ , m_defer(NoDefer)
+{
+ m_options.initiatorInfo.name = initiator;
+}
+
+FetchRequest::FetchRequest(const ResourceRequest& resourceRequest, const FetchInitiatorInfo& initiator)
+ : m_resourceRequest(resourceRequest)
+ , m_options(ResourceFetcher::defaultResourceOptions())
+ , m_priority(ResourceLoadPriorityUnresolved)
+ , m_forPreload(false)
+ , m_defer(NoDefer)
+{
+ m_options.initiatorInfo = initiator;
+}
+
+FetchRequest::~FetchRequest()
+{
+}
+
+void FetchRequest::setPotentiallyCrossOriginEnabled(SecurityOrigin* origin, StoredCredentials allowCredentials)
+{
+ updateRequestForAccessControl(m_resourceRequest, origin, allowCredentials);
+ ASSERT(m_options.requestOriginPolicy == UseDefaultOriginRestrictionsForType); // Allows only tightening from the default value.
+ m_options.requestOriginPolicy = PotentiallyCrossOriginEnabled;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.h b/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.h
new file mode 100644
index 00000000000..974fff2b36b
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FetchRequest.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FetchRequest_h
+#define FetchRequest_h
+
+#include "core/dom/Element.h"
+#include "core/loader/ResourceLoaderOptions.h"
+#include "core/loader/cache/FetchInitiatorInfo.h"
+#include "core/platform/network/ResourceLoadPriority.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "wtf/text/AtomicString.h"
+
+namespace WebCore {
+class SecurityOrigin;
+
+class FetchRequest {
+public:
+ enum DeferOption { NoDefer, DeferredByClient };
+
+ explicit FetchRequest(const ResourceRequest&, const AtomicString& initiator, const String& charset = String(), ResourceLoadPriority = ResourceLoadPriorityUnresolved);
+ FetchRequest(const ResourceRequest&, const AtomicString& initiator, const ResourceLoaderOptions&);
+ FetchRequest(const ResourceRequest&, const FetchInitiatorInfo&);
+ ~FetchRequest();
+
+ ResourceRequest& mutableResourceRequest() { return m_resourceRequest; }
+ const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
+ const KURL& url() const { return m_resourceRequest.url(); }
+ const String& charset() const { return m_charset; }
+ void setCharset(const String& charset) { m_charset = charset; }
+ const ResourceLoaderOptions& options() const { return m_options; }
+ void setOptions(const ResourceLoaderOptions& options) { m_options = options; }
+ ResourceLoadPriority priority() const { return m_priority; }
+ bool forPreload() const { return m_forPreload; }
+ void setForPreload(bool forPreload) { m_forPreload = forPreload; }
+ DeferOption defer() const { return m_defer; }
+ void setDefer(DeferOption defer) { m_defer = defer; }
+ void setContentSecurityCheck(ContentSecurityPolicyCheck contentSecurityPolicyOption) { m_options.contentSecurityPolicyOption = contentSecurityPolicyOption; }
+ void setPotentiallyCrossOriginEnabled(SecurityOrigin*, StoredCredentials);
+
+private:
+ ResourceRequest m_resourceRequest;
+ String m_charset;
+ ResourceLoaderOptions m_options;
+ ResourceLoadPriority m_priority;
+ bool m_forPreload;
+ DeferOption m_defer;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.cpp
new file mode 100644
index 00000000000..90b527783bf
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/FontResource.h"
+
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/platform/graphics/FontCustomPlatformData.h"
+#include "core/platform/graphics/FontPlatformData.h"
+
+#if ENABLE(SVG_FONTS)
+#include "SVGNames.h"
+#include "core/dom/NodeList.h"
+#include "core/svg/SVGDocument.h"
+#include "core/svg/SVGFontElement.h"
+#endif
+
+namespace WebCore {
+
+FontResource::FontResource(const ResourceRequest& resourceRequest)
+ : Resource(resourceRequest, Font)
+ , m_loadInitiated(false)
+{
+}
+
+FontResource::~FontResource()
+{
+}
+
+void FontResource::load(ResourceFetcher*, const ResourceLoaderOptions& options)
+{
+ // Don't load the file yet. Wait for an access before triggering the load.
+ setLoading(true);
+ m_options = options;
+}
+
+void FontResource::didAddClient(ResourceClient* c)
+{
+ ASSERT(c->resourceClientType() == FontResourceClient::expectedType());
+ if (!isLoading())
+ static_cast<FontResourceClient*>(c)->fontLoaded(this);
+}
+
+void FontResource::beginLoadIfNeeded(ResourceFetcher* dl)
+{
+ if (!m_loadInitiated) {
+ m_loadInitiated = true;
+ Resource::load(dl, m_options);
+
+ ResourceClientWalker<FontResourceClient> walker(m_clients);
+ while (FontResourceClient* client = walker.next())
+ client->didStartFontLoad(this);
+ }
+}
+
+bool FontResource::ensureCustomFontData()
+{
+ if (!m_fontData && !errorOccurred() && !isLoading() && m_data) {
+ m_fontData = FontCustomPlatformData::create(m_data.get());
+ if (!m_fontData)
+ setStatus(DecodeError);
+ }
+ return m_fontData;
+}
+
+FontPlatformData FontResource::platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant widthVariant)
+{
+#if ENABLE(SVG_FONTS)
+ if (m_externalSVGDocument)
+ return FontPlatformData(size, bold, italic);
+#endif
+ ASSERT(m_fontData);
+ return m_fontData->fontPlatformData(static_cast<int>(size), bold, italic, orientation, widthVariant);
+}
+
+#if ENABLE(SVG_FONTS)
+bool FontResource::ensureSVGFontData()
+{
+ if (!m_externalSVGDocument && !errorOccurred() && !isLoading() && m_data) {
+ m_externalSVGDocument = SVGDocument::create();
+
+ RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
+ String svgSource = decoder->decode(m_data->data(), m_data->size());
+ svgSource.append(decoder->flush());
+
+ m_externalSVGDocument->setContent(svgSource);
+
+ if (decoder->sawError())
+ m_externalSVGDocument = 0;
+ }
+
+ return m_externalSVGDocument;
+}
+
+SVGFontElement* FontResource::getSVGFontById(const String& fontName) const
+{
+ RefPtr<NodeList> list = m_externalSVGDocument->getElementsByTagNameNS(SVGNames::fontTag.namespaceURI(), SVGNames::fontTag.localName());
+ if (!list)
+ return 0;
+
+ unsigned listLength = list->length();
+ if (!listLength)
+ return 0;
+
+#ifndef NDEBUG
+ for (unsigned i = 0; i < listLength; ++i) {
+ ASSERT(list->item(i));
+ ASSERT(list->item(i)->hasTagName(SVGNames::fontTag));
+ }
+#endif
+
+ if (fontName.isEmpty())
+ return toSVGFontElement(list->item(0));
+
+ for (unsigned i = 0; i < listLength; ++i) {
+ SVGFontElement* element = toSVGFontElement(list->item(i));
+ if (element->getIdAttribute() == fontName)
+ return element;
+ }
+
+ return 0;
+}
+#endif
+
+void FontResource::allClientsRemoved()
+{
+ m_fontData.clear();
+ Resource::allClientsRemoved();
+}
+
+void FontResource::checkNotify()
+{
+ ResourceClientWalker<FontResourceClient> w(m_clients);
+ while (FontResourceClient* c = w.next())
+ c->fontLoaded(this);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.h
new file mode 100644
index 00000000000..5997f1e9b98
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/FontResource.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontResource_h
+#define FontResource_h
+
+#include "core/loader/cache/Resource.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/platform/graphics/FontOrientation.h"
+#include "core/platform/graphics/FontWidthVariant.h"
+#include "wtf/OwnPtr.h"
+
+namespace WebCore {
+
+class ResourceFetcher;
+class FontPlatformData;
+class SVGDocument;
+class SVGFontElement;
+class FontCustomPlatformData;
+
+class FontResource : public Resource {
+public:
+ FontResource(const ResourceRequest&);
+ virtual ~FontResource();
+
+ virtual void load(ResourceFetcher*, const ResourceLoaderOptions&);
+
+ virtual void didAddClient(ResourceClient*);
+
+ virtual void allClientsRemoved();
+ void beginLoadIfNeeded(ResourceFetcher* dl);
+ bool stillNeedsLoad() const { return !m_loadInitiated; }
+
+ bool ensureCustomFontData();
+ FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth);
+
+#if ENABLE(SVG_FONTS)
+ bool ensureSVGFontData();
+ SVGFontElement* getSVGFontById(const String&) const;
+#endif
+
+private:
+ virtual void checkNotify();
+ OwnPtr<FontCustomPlatformData> m_fontData;
+ bool m_loadInitiated;
+
+#if ENABLE(SVG_FONTS)
+ RefPtr<WebCore::SVGDocument> m_externalSVGDocument;
+#endif
+
+ friend class MemoryCache;
+};
+
+class FontResourceClient : public ResourceClient {
+public:
+ virtual ~FontResourceClient() { }
+ static ResourceClientType expectedType() { return FontType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+ virtual void fontLoaded(FontResource*) { }
+ virtual void didStartFontLoad(FontResource*) { }
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.cpp
new file mode 100644
index 00000000000..c07d864d850
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.cpp
@@ -0,0 +1,451 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007 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 "config.h"
+#include "core/loader/cache/ImageResource.h"
+
+#include "core/loader/cache/ImageResourceClient.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/loader/cache/ResourceFetcher.h"
+#include "core/page/FrameView.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/platform/graphics/BitmapImage.h"
+#include "core/rendering/RenderObject.h"
+#include "core/svg/graphics/SVGImage.h"
+#include "wtf/CurrentTime.h"
+#include "wtf/StdLibExtras.h"
+#include "wtf/Vector.h"
+
+using namespace std;
+
+namespace WebCore {
+
+ImageResource::ImageResource(const ResourceRequest& resourceRequest)
+ : Resource(resourceRequest, Image)
+ , m_image(0)
+ , m_loadingMultipartContent(false)
+{
+ setStatus(Unknown);
+ setCustomAcceptHeader();
+}
+
+ImageResource::ImageResource(WebCore::Image* image)
+ : Resource(ResourceRequest(), Image)
+ , m_image(image)
+{
+ setStatus(Cached);
+ setLoading(false);
+ setCustomAcceptHeader();
+}
+
+ImageResource::~ImageResource()
+{
+ clearImage();
+}
+
+void ImageResource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& options)
+{
+ if (!fetcher || fetcher->autoLoadImages())
+ Resource::load(fetcher, options);
+ else
+ setLoading(false);
+}
+
+void ImageResource::didAddClient(ResourceClient* c)
+{
+ if (m_data && !m_image && !errorOccurred()) {
+ createImage();
+ m_image->setData(m_data, true);
+ }
+
+ ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
+ if (m_image && !m_image->isNull())
+ static_cast<ImageResourceClient*>(c)->imageChanged(this);
+
+ Resource::didAddClient(c);
+}
+
+void ImageResource::didRemoveClient(ResourceClient* c)
+{
+ ASSERT(c);
+ ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
+
+ m_pendingContainerSizeRequests.remove(static_cast<ImageResourceClient*>(c));
+ if (m_svgImageCache)
+ m_svgImageCache->removeClientFromCache(static_cast<ImageResourceClient*>(c));
+
+ Resource::didRemoveClient(c);
+}
+
+void ImageResource::switchClientsToRevalidatedResource()
+{
+ ASSERT(resourceToRevalidate());
+ ASSERT(resourceToRevalidate()->isImage());
+ // Pending container size requests need to be transferred to the revalidated resource.
+ if (!m_pendingContainerSizeRequests.isEmpty()) {
+ // A copy of pending size requests is needed as they are deleted during Resource::switchClientsToRevalidateResouce().
+ ContainerSizeRequests switchContainerSizeRequests;
+ for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequests.begin(); it != m_pendingContainerSizeRequests.end(); ++it)
+ switchContainerSizeRequests.set(it->key, it->value);
+ Resource::switchClientsToRevalidatedResource();
+ ImageResource* revalidatedImageResource = static_cast<ImageResource*>(resourceToRevalidate());
+ for (ContainerSizeRequests::iterator it = switchContainerSizeRequests.begin(); it != switchContainerSizeRequests.end(); ++it)
+ revalidatedImageResource->setContainerSizeForRenderer(it->key, it->value.first, it->value.second);
+ return;
+ }
+
+ Resource::switchClientsToRevalidatedResource();
+}
+
+void ImageResource::allClientsRemoved()
+{
+ m_pendingContainerSizeRequests.clear();
+ if (m_image && !errorOccurred())
+ m_image->resetAnimation();
+ Resource::allClientsRemoved();
+}
+
+pair<WebCore::Image*, float> ImageResource::brokenImage(float deviceScaleFactor) const
+{
+ if (deviceScaleFactor >= 2) {
+ DEFINE_STATIC_LOCAL(WebCore::Image*, brokenImageHiRes, (WebCore::Image::loadPlatformResource("missingImage@2x").leakRef()));
+ return std::make_pair(brokenImageHiRes, 2);
+ }
+
+ DEFINE_STATIC_LOCAL(WebCore::Image*, brokenImageLoRes, (WebCore::Image::loadPlatformResource("missingImage").leakRef()));
+ return std::make_pair(brokenImageLoRes, 1);
+}
+
+bool ImageResource::willPaintBrokenImage() const
+{
+ return errorOccurred();
+}
+
+WebCore::Image* ImageResource::image()
+{
+ ASSERT(!isPurgeable());
+
+ if (errorOccurred()) {
+ // Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
+ // deviceScaleFactor from here. It is critical that callers use ImageResource::brokenImage()
+ // when they need the real, deviceScaleFactor-appropriate broken image icon.
+ return brokenImage(1).first;
+ }
+
+ if (m_image)
+ return m_image.get();
+
+ return WebCore::Image::nullImage();
+}
+
+WebCore::Image* ImageResource::imageForRenderer(const RenderObject* renderer)
+{
+ ASSERT(!isPurgeable());
+
+ if (errorOccurred()) {
+ // Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
+ // deviceScaleFactor from here. It is critical that callers use ImageResource::brokenImage()
+ // when they need the real, deviceScaleFactor-appropriate broken image icon.
+ return brokenImage(1).first;
+ }
+
+ if (!m_image)
+ return WebCore::Image::nullImage();
+
+ if (m_image->isSVGImage()) {
+ WebCore::Image* image = m_svgImageCache->imageForRenderer(renderer);
+ if (image != WebCore::Image::nullImage())
+ return image;
+ }
+
+ return m_image.get();
+}
+
+void ImageResource::setContainerSizeForRenderer(const ImageResourceClient* renderer, const IntSize& containerSize, float containerZoom)
+{
+ if (containerSize.isEmpty())
+ return;
+ ASSERT(renderer);
+ ASSERT(containerZoom);
+ if (!m_image) {
+ m_pendingContainerSizeRequests.set(renderer, SizeAndZoom(containerSize, containerZoom));
+ return;
+ }
+ if (!m_image->isSVGImage()) {
+ m_image->setContainerSize(containerSize);
+ return;
+ }
+
+ m_svgImageCache->setContainerSizeForRenderer(renderer, containerSize, containerZoom);
+}
+
+bool ImageResource::usesImageContainerSize() const
+{
+ if (m_image)
+ return m_image->usesContainerSize();
+
+ return false;
+}
+
+bool ImageResource::imageHasRelativeWidth() const
+{
+ if (m_image)
+ return m_image->hasRelativeWidth();
+
+ return false;
+}
+
+bool ImageResource::imageHasRelativeHeight() const
+{
+ if (m_image)
+ return m_image->hasRelativeHeight();
+
+ return false;
+}
+
+LayoutSize ImageResource::imageSizeForRenderer(const RenderObject* renderer, float multiplier)
+{
+ ASSERT(!isPurgeable());
+
+ if (!m_image)
+ return IntSize();
+
+ LayoutSize imageSize;
+
+ if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
+ imageSize = static_cast<BitmapImage*>(m_image.get())->sizeRespectingOrientation();
+ else if (m_image->isSVGImage())
+ imageSize = m_svgImageCache->imageSizeForRenderer(renderer);
+ else
+ imageSize = m_image->size();
+
+ if (multiplier == 1.0f)
+ return imageSize;
+
+ // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
+ float widthScale = m_image->hasRelativeWidth() ? 1.0f : multiplier;
+ float heightScale = m_image->hasRelativeHeight() ? 1.0f : multiplier;
+ LayoutSize minimumSize(imageSize.width() > 0 ? 1 : 0, imageSize.height() > 0 ? 1 : 0);
+ imageSize.scale(widthScale, heightScale);
+ imageSize.clampToMinimumSize(minimumSize);
+ ASSERT(multiplier != 1.0f || (imageSize.width().fraction() == 0.0f && imageSize.height().fraction() == 0.0f));
+ return imageSize;
+}
+
+void ImageResource::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)
+{
+ if (m_image)
+ m_image->computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio);
+}
+
+void ImageResource::notifyObservers(const IntRect* changeRect)
+{
+ ResourceClientWalker<ImageResourceClient> w(m_clients);
+ while (ImageResourceClient* c = w.next())
+ c->imageChanged(this, changeRect);
+}
+
+void ImageResource::clear()
+{
+ destroyDecodedData();
+ clearImage();
+ m_pendingContainerSizeRequests.clear();
+ setEncodedSize(0);
+}
+
+void ImageResource::setCustomAcceptHeader()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, acceptWebP, ("image/webp,*/*;q=0.8", AtomicString::ConstructFromLiteral));
+ setAccept(acceptWebP);
+}
+
+inline void ImageResource::createImage()
+{
+ // Create the image if it doesn't yet exist.
+ if (m_image)
+ return;
+
+ if (m_response.mimeType() == "image/svg+xml") {
+ RefPtr<SVGImage> svgImage = SVGImage::create(this);
+ m_svgImageCache = SVGImageCache::create(svgImage.get());
+ m_image = svgImage.release();
+ } else {
+ m_image = BitmapImage::create(this);
+ }
+
+ if (m_image) {
+ // Send queued container size requests.
+ if (m_image->usesContainerSize()) {
+ for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequests.begin(); it != m_pendingContainerSizeRequests.end(); ++it)
+ setContainerSizeForRenderer(it->key, it->value.first, it->value.second);
+ }
+ m_pendingContainerSizeRequests.clear();
+ }
+}
+
+inline void ImageResource::clearImage()
+{
+ // If our Image has an observer, it's always us so we need to clear the back pointer
+ // before dropping our reference.
+ if (m_image)
+ m_image->setImageObserver(0);
+ m_image.clear();
+}
+
+void ImageResource::appendData(const char* data, int length)
+{
+ Resource::appendData(data, length);
+ if (!m_loadingMultipartContent)
+ updateImage(false);
+}
+
+void ImageResource::updateImage(bool allDataReceived)
+{
+ if (m_data)
+ createImage();
+
+ bool sizeAvailable = false;
+
+ // Have the image update its data from its internal buffer.
+ // It will not do anything now, but will delay decoding until
+ // queried for info (like size or specific image frames).
+ if (m_image)
+ sizeAvailable = m_image->setData(m_data, allDataReceived);
+
+ // Go ahead and tell our observers to try to draw if we have either
+ // received all the data or the size is known. Each chunk from the
+ // network causes observers to repaint, which will force that chunk
+ // to decode.
+ if (sizeAvailable || allDataReceived) {
+ if (!m_image || m_image->isNull()) {
+ error(errorOccurred() ? status() : DecodeError);
+ if (inCache())
+ memoryCache()->remove(this);
+ return;
+ }
+
+ // It would be nice to only redraw the decoded band of the image, but with the current design
+ // (decoding delayed until painting) that seems hard.
+ notifyObservers();
+ }
+}
+
+void ImageResource::finishOnePart()
+{
+ if (m_loadingMultipartContent)
+ clear();
+ updateImage(true);
+ if (m_loadingMultipartContent)
+ m_data.clear();
+ Resource::finishOnePart();
+}
+
+void ImageResource::error(Resource::Status status)
+{
+ clear();
+ Resource::error(status);
+ notifyObservers();
+}
+
+void ImageResource::responseReceived(const ResourceResponse& response)
+{
+ if (m_loadingMultipartContent && m_data)
+ finishOnePart();
+ else if (response.isMultipart())
+ m_loadingMultipartContent = true;
+ Resource::responseReceived(response);
+}
+
+void ImageResource::destroyDecodedData()
+{
+ bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
+ if (isSafeToMakePurgeable() && canDeleteImage && !isLoading()) {
+ // Image refs the data buffer so we should not make it purgeable while the image is alive.
+ // Invoking addClient() will reconstruct the image object.
+ m_image = 0;
+ setDecodedSize(0);
+ makePurgeable(true);
+ } else if (m_image && !errorOccurred()) {
+ m_image->destroyDecodedData();
+ }
+}
+
+void ImageResource::decodedSizeChanged(const WebCore::Image* image, int delta)
+{
+ if (!image || image != m_image)
+ return;
+
+ setDecodedSize(decodedSize() + delta);
+}
+
+void ImageResource::didDraw(const WebCore::Image* image)
+{
+ if (!image || image != m_image)
+ return;
+
+ double timeStamp = FrameView::currentPaintTimeStamp();
+ if (!timeStamp) // If didDraw is called outside of a Frame paint.
+ timeStamp = currentTime();
+
+ Resource::didAccessDecodedData(timeStamp);
+}
+
+bool ImageResource::shouldPauseAnimation(const WebCore::Image* image)
+{
+ if (!image || image != m_image)
+ return false;
+
+ ResourceClientWalker<ImageResourceClient> w(m_clients);
+ while (ImageResourceClient* c = w.next()) {
+ if (c->willRenderImage(this))
+ return false;
+ }
+
+ return true;
+}
+
+void ImageResource::animationAdvanced(const WebCore::Image* image)
+{
+ if (!image || image != m_image)
+ return;
+ notifyObservers();
+}
+
+void ImageResource::changedInRect(const WebCore::Image* image, const IntRect& rect)
+{
+ if (!image || image != m_image)
+ return;
+ notifyObservers(&rect);
+}
+
+bool ImageResource::currentFrameKnownToBeOpaque(const RenderObject* renderer)
+{
+ WebCore::Image* image = imageForRenderer(renderer);
+ if (image->isBitmapImage())
+ image->nativeImageForCurrentFrame(); // force decode
+ return image->currentFrameKnownToBeOpaque();
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.h
new file mode 100644
index 00000000000..5bee694c78c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResource.h
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007 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.
+*/
+
+#ifndef ImageResource_h
+#define ImageResource_h
+
+#include "core/loader/cache/Resource.h"
+#include "core/platform/graphics/ImageObserver.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/platform/graphics/IntSizeHash.h"
+#include "core/platform/graphics/LayoutSize.h"
+#include "core/svg/graphics/SVGImageCache.h"
+#include "wtf/HashMap.h"
+
+namespace WebCore {
+
+class ImageResourceClient;
+class ResourceFetcher;
+class FloatSize;
+class MemoryCache;
+class RenderObject;
+struct Length;
+
+class ImageResource : public Resource, public ImageObserver {
+ friend class MemoryCache;
+
+public:
+ ImageResource(const ResourceRequest&);
+ ImageResource(WebCore::Image*);
+ virtual ~ImageResource();
+
+ virtual void load(ResourceFetcher*, const ResourceLoaderOptions&);
+
+ WebCore::Image* image(); // Returns the nullImage() if the image is not available yet.
+ WebCore::Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
+ bool hasImage() const { return m_image.get(); }
+ bool currentFrameKnownToBeOpaque(const RenderObject*); // Side effect: ensures decoded image is in cache, therefore should only be called when about to draw the image.
+
+ std::pair<WebCore::Image*, float> brokenImage(float deviceScaleFactor) const; // Returns an image and the image's resolution scale factor.
+ bool willPaintBrokenImage() const;
+
+ bool canRender(const RenderObject* renderer, float multiplier) { return !errorOccurred() && !imageSizeForRenderer(renderer, multiplier).isEmpty(); }
+
+ void setContainerSizeForRenderer(const ImageResourceClient*, const IntSize&, float);
+ bool usesImageContainerSize() const;
+ bool imageHasRelativeWidth() const;
+ bool imageHasRelativeHeight() const;
+
+ // This method takes a zoom multiplier that can be used to increase the natural size of the image by the zoom.
+ LayoutSize imageSizeForRenderer(const RenderObject*, float multiplier); // returns the size of the complete image.
+ void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio);
+
+ virtual void didAddClient(ResourceClient*);
+ virtual void didRemoveClient(ResourceClient*);
+
+ virtual void allClientsRemoved();
+ virtual void destroyDecodedData();
+
+ virtual void appendData(const char*, int) OVERRIDE;
+ virtual void error(Resource::Status);
+ virtual void responseReceived(const ResourceResponse&);
+ virtual void finishOnePart() OVERRIDE;
+
+ // For compatibility, images keep loading even if there are HTTP errors.
+ virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return true; }
+
+ virtual bool isImage() const { return true; }
+ virtual bool stillNeedsLoad() const OVERRIDE { return !errorOccurred() && status() == Unknown && !isLoading(); }
+
+ // ImageObserver
+ virtual void decodedSizeChanged(const WebCore::Image*, int delta);
+ virtual void didDraw(const WebCore::Image*);
+
+ virtual bool shouldPauseAnimation(const WebCore::Image*);
+ virtual void animationAdvanced(const WebCore::Image*);
+ virtual void changedInRect(const WebCore::Image*, const IntRect&);
+
+private:
+ void clear();
+
+ void setCustomAcceptHeader();
+ void createImage();
+ void updateImage(bool allDataReceived);
+ void clearImage();
+ // If not null, changeRect is the changed part of the image.
+ void notifyObservers(const IntRect* changeRect = 0);
+
+ virtual void switchClientsToRevalidatedResource() OVERRIDE;
+
+ typedef pair<IntSize, float> SizeAndZoom;
+ typedef HashMap<const ImageResourceClient*, SizeAndZoom> ContainerSizeRequests;
+ ContainerSizeRequests m_pendingContainerSizeRequests;
+
+ RefPtr<WebCore::Image> m_image;
+ OwnPtr<SVGImageCache> m_svgImageCache;
+ bool m_loadingMultipartContent;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceClient.h b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceClient.h
new file mode 100644
index 00000000000..4cea375612c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceClient.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007 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.
+*/
+
+#ifndef ImageResourceClient_h
+#define ImageResourceClient_h
+
+#include "core/loader/cache/ResourceClient.h"
+
+namespace WebCore {
+
+class ImageResource;
+class IntRect;
+
+class ImageResourceClient : public ResourceClient {
+public:
+ virtual ~ImageResourceClient() { }
+ static ResourceClientType expectedType() { return ImageType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+
+ // Called whenever a frame of an image changes, either because we got more data from the network or
+ // because we are animating. If not null, the IntRect is the changed rect of the image.
+ virtual void imageChanged(ImageResource*, const IntRect* = 0) { }
+
+ // Called to find out if this client wants to actually display the image. Used to tell when we
+ // can halt animation. Content nodes that hold image refs for example would not render the image,
+ // but RenderImages would (assuming they have visibility: visible and their render tree isn't hidden
+ // e.g., in the b/f cache or in a background tab).
+ virtual bool willRenderImage(ImageResource*) { return false; }
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceTest.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceTest.cpp
new file mode 100644
index 00000000000..37d558b8d57
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ImageResourceTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/ImageResource.h"
+
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/EmptyClients.h"
+#include "core/loader/cache/ImageResourceClient.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/loader/cache/MockImageResourceClient.h"
+#include "core/loader/cache/ResourceFetcher.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/platform/SharedBuffer.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebThread.h"
+#include "public/platform/WebURL.h"
+#include "public/platform/WebURLResponse.h"
+#include "public/platform/WebUnitTestSupport.h"
+
+using namespace WebCore;
+
+namespace {
+
+class QuitTask : public WebKit::WebThread::Task {
+public:
+ virtual void run()
+ {
+ WebKit::Platform::current()->currentThread()->exitRunLoop();
+ }
+};
+
+void runPendingTasks()
+{
+ WebKit::Platform::current()->currentThread()->postTask(new QuitTask);
+ WebKit::Platform::current()->currentThread()->enterRunLoop();
+}
+
+TEST(ImageResourceTest, MultipartImage)
+{
+ ResourcePtr<ImageResource> cachedImage = new ImageResource(ResourceRequest());
+ cachedImage->setLoading(true);
+
+ MockImageResourceClient client;
+ cachedImage->addClient(&client);
+
+ // Send the multipart response. No image or data buffer is created.
+ cachedImage->responseReceived(ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, String(), String()));
+ ASSERT_FALSE(cachedImage->resourceBuffer());
+ ASSERT_FALSE(cachedImage->hasImage());
+ ASSERT_EQ(client.imageChangedCount(), 0);
+ ASSERT_FALSE(client.notifyFinishedCalled());
+
+ // Send the response for the first real part. No image or data buffer is created.
+ const char* svgData = "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect width='1' height='1' fill='green'/></svg>";
+ unsigned svgDataLength = strlen(svgData);
+ cachedImage->responseReceived(ResourceResponse(KURL(), "image/svg+xml", svgDataLength, String(), String()));
+ ASSERT_FALSE(cachedImage->resourceBuffer());
+ ASSERT_FALSE(cachedImage->hasImage());
+ ASSERT_EQ(client.imageChangedCount(), 0);
+ ASSERT_FALSE(client.notifyFinishedCalled());
+
+ // The first bytes arrive. The data buffer is created, but no image is created.
+ cachedImage->appendData(svgData, svgDataLength);
+ ASSERT_TRUE(cachedImage->resourceBuffer());
+ ASSERT_EQ(cachedImage->resourceBuffer()->size(), svgDataLength);
+ ASSERT_FALSE(cachedImage->hasImage());
+ ASSERT_EQ(client.imageChangedCount(), 0);
+ ASSERT_FALSE(client.notifyFinishedCalled());
+
+ // This part finishes. The image is created, callbacks are sent, and the data buffer is cleared.
+ cachedImage->finish();
+ ASSERT_FALSE(cachedImage->resourceBuffer());
+ ASSERT_FALSE(cachedImage->errorOccurred());
+ ASSERT_TRUE(cachedImage->hasImage());
+ ASSERT_FALSE(cachedImage->image()->isNull());
+ ASSERT_EQ(cachedImage->image()->width(), 1);
+ ASSERT_EQ(cachedImage->image()->height(), 1);
+ ASSERT_EQ(client.imageChangedCount(), 2);
+ ASSERT_TRUE(client.notifyFinishedCalled());
+}
+
+TEST(ImageResourceTest, CancelOnDetach)
+{
+ KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html");
+
+ WebKit::WebURLResponse response;
+ response.initialize();
+ response.setMIMEType("text/html");
+ WTF::String localPath = WebKit::Platform::current()->unitTestSupport()->webKitRootDir();
+ localPath.append("/Source/web/tests/data/cancelTest.html");
+ WebKit::Platform::current()->unitTestSupport()->registerMockedURL(testURL, response, localPath);
+
+ // Create enough of a mocked world to get a functioning ResourceLoader.
+ Page::PageClients pageClients;
+ fillWithEmptyClients(pageClients);
+ EmptyFrameLoaderClient frameLoaderClient;
+ Page page(pageClients);
+ RefPtr<Frame> frame = Frame::create(&page, 0, &frameLoaderClient);
+ frame->setView(FrameView::create(frame.get()));
+ frame->init();
+ RefPtr<DocumentLoader> documentLoader = DocumentLoader::create(ResourceRequest(testURL), SubstituteData());
+ documentLoader->setFrame(frame.get());
+
+ // Emulate starting a real load.
+ ResourcePtr<ImageResource> cachedImage = new ImageResource(ResourceRequest(testURL));
+ cachedImage->load(documentLoader->fetcher(), ResourceLoaderOptions());
+ memoryCache()->add(cachedImage.get());
+
+ MockImageResourceClient client;
+ cachedImage->addClient(&client);
+ EXPECT_EQ(Resource::Pending, cachedImage->status());
+
+ // The load should still be alive, but a timer should be started to cancel the load inside removeClient().
+ cachedImage->removeClient(&client);
+ EXPECT_EQ(Resource::Pending, cachedImage->status());
+ EXPECT_NE(reinterpret_cast<Resource*>(0), memoryCache()->resourceForURL(testURL));
+
+ // Trigger the cancel timer, ensure the load was cancelled and the resource was evicted from the cache.
+ runPendingTasks();
+ EXPECT_EQ(Resource::LoadError, cachedImage->status());
+ EXPECT_EQ(reinterpret_cast<Resource*>(0), memoryCache()->resourceForURL(testURL));
+
+ WebKit::Platform::current()->unitTestSupport()->unregisterMockedURL(testURL);
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.cpp
new file mode 100644
index 00000000000..c51f5446e3c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.cpp
@@ -0,0 +1,619 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "config.h"
+#include "core/loader/cache/MemoryCache.h"
+
+#include <stdio.h>
+#include "core/dom/CrossThreadTask.h"
+#include "core/dom/Document.h"
+#include "core/loader/cache/Resource.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/page/FrameView.h"
+#include "core/platform/Logging.h"
+#include "core/platform/chromium/TraceEvent.h"
+#include "core/workers/WorkerGlobalScope.h"
+#include "core/workers/WorkerLoaderProxy.h"
+#include "core/workers/WorkerThread.h"
+#include "weborigin/SecurityOrigin.h"
+#include "weborigin/SecurityOriginHash.h"
+#include "wtf/Assertions.h"
+#include "wtf/CurrentTime.h"
+#include "wtf/MathExtras.h"
+#include "wtf/TemporaryChange.h"
+#include "wtf/text/CString.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static MemoryCache* gMemoryCache;
+
+static const int cDefaultCacheCapacity = 8192 * 1024;
+static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
+static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
+
+MemoryCache* memoryCache()
+{
+ ASSERT(WTF::isMainThread());
+ if (!gMemoryCache)
+ gMemoryCache = new MemoryCache();
+ return gMemoryCache;
+}
+
+void setMemoryCacheForTesting(MemoryCache* memoryCache)
+{
+ gMemoryCache = memoryCache;
+}
+
+MemoryCache::MemoryCache()
+ : m_inPruneResources(false)
+ , m_capacity(cDefaultCacheCapacity)
+ , m_minDeadCapacity(0)
+ , m_maxDeadCapacity(cDefaultCacheCapacity)
+ , m_liveSize(0)
+ , m_deadSize(0)
+ , m_delayBeforeLiveDecodedPrune(cMinDelayBeforeLiveDecodedPrune)
+#ifdef MEMORY_CACHE_STATS
+ , m_statsTimer(this, &MemoryCache::dumpStats)
+#endif
+{
+#ifdef MEMORY_CACHE_STATS
+ const double statsIntervalInSeconds = 15;
+ m_statsTimer.startRepeating(statsIntervalInSeconds);
+#endif
+}
+
+KURL MemoryCache::removeFragmentIdentifierIfNeeded(const KURL& originalURL)
+{
+ if (!originalURL.hasFragmentIdentifier())
+ return originalURL;
+ // Strip away fragment identifier from HTTP URLs.
+ // Data URLs must be unmodified. For file and custom URLs clients may expect resources
+ // to be unique even when they differ by the fragment identifier only.
+ if (!originalURL.protocolIsInHTTPFamily())
+ return originalURL;
+ KURL url = originalURL;
+ url.removeFragmentIdentifier();
+ return url;
+}
+
+void MemoryCache::add(Resource* resource)
+{
+ ASSERT(WTF::isMainThread());
+ m_resources.set(resource->url(), resource);
+ resource->setInCache(true);
+ resource->updateForAccess();
+
+ LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource->url().string().latin1().data(), resource);
+}
+
+void MemoryCache::replace(Resource* newResource, Resource* oldResource)
+{
+ evict(oldResource);
+ ASSERT(!m_resources.get(newResource->url()));
+ m_resources.set(newResource->url(), newResource);
+ newResource->setInCache(true);
+ insertInLRUList(newResource);
+ int delta = newResource->size();
+ if (newResource->decodedSize() && newResource->hasClients())
+ insertInLiveDecodedResourcesList(newResource);
+ if (delta)
+ adjustSize(newResource->hasClients(), delta);
+}
+
+Resource* MemoryCache::resourceForURL(const KURL& resourceURL)
+{
+ ASSERT(WTF::isMainThread());
+ KURL url = removeFragmentIdentifierIfNeeded(resourceURL);
+ Resource* resource = m_resources.get(url);
+ if (resource && !resource->makePurgeable(false)) {
+ ASSERT(!resource->hasClients());
+ evict(resource);
+ return 0;
+ }
+ return resource;
+}
+
+unsigned MemoryCache::deadCapacity() const
+{
+ // Dead resource capacity is whatever space is not occupied by live resources, bounded by an independent minimum and maximum.
+ unsigned capacity = m_capacity - min(m_liveSize, m_capacity); // Start with available capacity.
+ capacity = max(capacity, m_minDeadCapacity); // Make sure it's above the minimum.
+ capacity = min(capacity, m_maxDeadCapacity); // Make sure it's below the maximum.
+ return capacity;
+}
+
+unsigned MemoryCache::liveCapacity() const
+{
+ // Live resource capacity is whatever is left over after calculating dead resource capacity.
+ return m_capacity - deadCapacity();
+}
+
+void MemoryCache::pruneLiveResources()
+{
+ unsigned capacity = liveCapacity();
+ if (!m_liveSize || (capacity && m_liveSize <= capacity))
+ return;
+
+ unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
+
+ double currentTime = FrameView::currentPaintTimeStamp();
+ if (!currentTime) // In case prune is called directly, outside of a Frame paint.
+ currentTime = WTF::currentTime();
+
+ // Destroy any decoded data in live objects that we can.
+ // Start from the tail, since this is the lowest priority
+ // and least recently accessed of the objects.
+
+ // The list might not be sorted by the m_lastDecodedAccessTime. The impact
+ // of this weaker invariant is minor as the below if statement to check the
+ // elapsedTime will evaluate to false as the currentTime will be a lot
+ // greater than the current->m_lastDecodedAccessTime.
+ // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209
+
+ // Start pruning from the lowest priority list.
+ for (int priority = Resource::CacheLiveResourcePriorityLow; priority <= Resource::CacheLiveResourcePriorityHigh; ++priority) {
+ Resource* current = m_liveDecodedResources[priority].m_tail;
+ while (current) {
+ Resource* prev = current->m_prevInLiveResourcesList;
+ ASSERT(current->hasClients());
+ if (current->isLoaded() && current->decodedSize()) {
+ // Check to see if the remaining resources are too new to prune.
+ double elapsedTime = currentTime - current->m_lastDecodedAccessTime;
+ if (elapsedTime < m_delayBeforeLiveDecodedPrune)
+ return;
+
+ // Destroy our decoded data. This will remove us from
+ // m_liveDecodedResources, and possibly move us to a different LRU
+ // list in m_allResources.
+ current->destroyDecodedData();
+
+ if (targetSize && m_liveSize <= targetSize)
+ return;
+ }
+ current = prev;
+ }
+ }
+}
+
+void MemoryCache::pruneDeadResources()
+{
+ unsigned capacity = deadCapacity();
+ if (!m_deadSize || (capacity && m_deadSize <= capacity))
+ return;
+
+ unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
+
+ int size = m_allResources.size();
+
+ // See if we have any purged resources we can evict.
+ for (int i = 0; i < size; i++) {
+ Resource* current = m_allResources[i].m_tail;
+ while (current) {
+ Resource* prev = current->m_prevInAllResourcesList;
+ if (current->wasPurged()) {
+ ASSERT(!current->hasClients());
+ ASSERT(!current->isPreloaded());
+ evict(current);
+ }
+ current = prev;
+ }
+ }
+ if (targetSize && m_deadSize <= targetSize)
+ return;
+
+ bool canShrinkLRULists = true;
+ for (int i = size - 1; i >= 0; i--) {
+ // Remove from the tail, since this is the least frequently accessed of the objects.
+ Resource* current = m_allResources[i].m_tail;
+
+ // First flush all the decoded data in this queue.
+ while (current) {
+ // Protect 'previous' so it can't get deleted during destroyDecodedData().
+ ResourcePtr<Resource> previous = current->m_prevInAllResourcesList;
+ ASSERT(!previous || previous->inCache());
+ if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) {
+ // Destroy our decoded data. This will remove us from
+ // m_liveDecodedResources, and possibly move us to a different
+ // LRU list in m_allResources.
+ current->destroyDecodedData();
+
+ if (targetSize && m_deadSize <= targetSize)
+ return;
+ }
+ // Decoded data may reference other resources. Stop iterating if 'previous' somehow got
+ // kicked out of cache during destroyDecodedData().
+ if (previous && !previous->inCache())
+ break;
+ current = previous.get();
+ }
+
+ // Now evict objects from this queue.
+ current = m_allResources[i].m_tail;
+ while (current) {
+ ResourcePtr<Resource> previous = current->m_prevInAllResourcesList;
+ ASSERT(!previous || previous->inCache());
+ if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) {
+ evict(current);
+ if (targetSize && m_deadSize <= targetSize)
+ return;
+ }
+ if (previous && !previous->inCache())
+ break;
+ current = previous.get();
+ }
+
+ // Shrink the vector back down so we don't waste time inspecting
+ // empty LRU lists on future prunes.
+ if (m_allResources[i].m_head)
+ canShrinkLRULists = false;
+ else if (canShrinkLRULists)
+ m_allResources.resize(i);
+ }
+}
+
+void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
+{
+ ASSERT(minDeadBytes <= maxDeadBytes);
+ ASSERT(maxDeadBytes <= totalBytes);
+ m_minDeadCapacity = minDeadBytes;
+ m_maxDeadCapacity = maxDeadBytes;
+ m_capacity = totalBytes;
+ prune();
+}
+
+void MemoryCache::evict(Resource* resource)
+{
+ ASSERT(WTF::isMainThread());
+ LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resource, resource->url().string().latin1().data());
+ // The resource may have already been removed by someone other than our caller,
+ // who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
+ if (resource->inCache()) {
+ // Remove from the resource map.
+ m_resources.remove(resource->url());
+ resource->setInCache(false);
+
+ // Remove from the appropriate LRU list.
+ removeFromLRUList(resource);
+ removeFromLiveDecodedResourcesList(resource);
+ adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
+ } else
+ ASSERT(m_resources.get(resource->url()) != resource);
+
+ resource->deleteIfPossible();
+}
+
+MemoryCache::LRUList* MemoryCache::lruListFor(Resource* resource)
+{
+ unsigned accessCount = max(resource->accessCount(), 1U);
+ unsigned queueIndex = WTF::fastLog2(resource->size() / accessCount);
+#ifndef NDEBUG
+ resource->m_lruIndex = queueIndex;
+#endif
+ if (m_allResources.size() <= queueIndex)
+ m_allResources.grow(queueIndex + 1);
+ return &m_allResources[queueIndex];
+}
+
+void MemoryCache::removeFromLRUList(Resource* resource)
+{
+ // If we've never been accessed, then we're brand new and not in any list.
+ if (resource->accessCount() == 0)
+ return;
+
+#if !ASSERT_DISABLED
+ unsigned oldListIndex = resource->m_lruIndex;
+#endif
+
+ LRUList* list = lruListFor(resource);
+
+#if !ASSERT_DISABLED
+ // Verify that the list we got is the list we want.
+ ASSERT(resource->m_lruIndex == oldListIndex);
+
+ // Verify that we are in fact in this list.
+ bool found = false;
+ for (Resource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
+ if (current == resource) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT(found);
+#endif
+
+ Resource* next = resource->m_nextInAllResourcesList;
+ Resource* prev = resource->m_prevInAllResourcesList;
+
+ if (next == 0 && prev == 0 && list->m_head != resource)
+ return;
+
+ resource->m_nextInAllResourcesList = 0;
+ resource->m_prevInAllResourcesList = 0;
+
+ if (next)
+ next->m_prevInAllResourcesList = prev;
+ else if (list->m_tail == resource)
+ list->m_tail = prev;
+
+ if (prev)
+ prev->m_nextInAllResourcesList = next;
+ else if (list->m_head == resource)
+ list->m_head = next;
+}
+
+void MemoryCache::insertInLRUList(Resource* resource)
+{
+ // Make sure we aren't in some list already.
+ ASSERT(!resource->m_nextInAllResourcesList && !resource->m_prevInAllResourcesList);
+ ASSERT(resource->inCache());
+ ASSERT(resource->accessCount() > 0);
+
+ LRUList* list = lruListFor(resource);
+
+ resource->m_nextInAllResourcesList = list->m_head;
+ if (list->m_head)
+ list->m_head->m_prevInAllResourcesList = resource;
+ list->m_head = resource;
+
+ if (!resource->m_nextInAllResourcesList)
+ list->m_tail = resource;
+
+#if !ASSERT_DISABLED
+ // Verify that we are in now in the list like we should be.
+ list = lruListFor(resource);
+ bool found = false;
+ for (Resource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
+ if (current == resource) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT(found);
+#endif
+
+}
+
+void MemoryCache::removeFromLiveDecodedResourcesList(Resource* resource)
+{
+ // If we've never been accessed, then we're brand new and not in any list.
+ if (!resource->m_inLiveDecodedResourcesList)
+ return;
+ resource->m_inLiveDecodedResourcesList = false;
+
+ LRUList* list = &m_liveDecodedResources[resource->cacheLiveResourcePriority()];
+
+#if !ASSERT_DISABLED
+ // Verify that we are in fact in this list.
+ bool found = false;
+ for (Resource* current = list->m_head; current; current = current->m_nextInLiveResourcesList) {
+ if (current == resource) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT(found);
+#endif
+
+ Resource* next = resource->m_nextInLiveResourcesList;
+ Resource* prev = resource->m_prevInLiveResourcesList;
+
+ if (!next && !prev && list->m_head != resource)
+ return;
+
+ resource->m_nextInLiveResourcesList = 0;
+ resource->m_prevInLiveResourcesList = 0;
+
+ if (next)
+ next->m_prevInLiveResourcesList = prev;
+ else if (list->m_tail == resource)
+ list->m_tail = prev;
+
+ if (prev)
+ prev->m_nextInLiveResourcesList = next;
+ else if (list->m_head == resource)
+ list->m_head = next;
+}
+
+void MemoryCache::insertInLiveDecodedResourcesList(Resource* resource)
+{
+ // Make sure we aren't in the list already.
+ ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResourcesList && !resource->m_inLiveDecodedResourcesList);
+ resource->m_inLiveDecodedResourcesList = true;
+
+ LRUList* list = &m_liveDecodedResources[resource->cacheLiveResourcePriority()];
+ resource->m_nextInLiveResourcesList = list->m_head;
+ if (list->m_head)
+ list->m_head->m_prevInLiveResourcesList = resource;
+ list->m_head = resource;
+
+ if (!resource->m_nextInLiveResourcesList)
+ list->m_tail = resource;
+
+#if !ASSERT_DISABLED
+ // Verify that we are in now in the list like we should be.
+ bool found = false;
+ for (Resource* current = list->m_head; current; current = current->m_nextInLiveResourcesList) {
+ if (current == resource) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT(found);
+#endif
+
+}
+
+void MemoryCache::addToLiveResourcesSize(Resource* resource)
+{
+ m_liveSize += resource->size();
+ m_deadSize -= resource->size();
+}
+
+void MemoryCache::removeFromLiveResourcesSize(Resource* resource)
+{
+ m_liveSize -= resource->size();
+ m_deadSize += resource->size();
+}
+
+void MemoryCache::adjustSize(bool live, int delta)
+{
+ if (live) {
+ ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
+ m_liveSize += delta;
+ } else {
+ ASSERT(delta >= 0 || ((int)m_deadSize + delta >= 0));
+ m_deadSize += delta;
+ }
+}
+
+void MemoryCache::removeURLFromCache(ScriptExecutionContext* context, const KURL& url)
+{
+ if (context->isWorkerGlobalScope()) {
+ WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
+ workerGlobalScope->thread()->workerLoaderProxy().postTaskToLoader(createCallbackTask(&removeURLFromCacheInternal, url));
+ return;
+ }
+ removeURLFromCacheInternal(context, url);
+}
+
+void MemoryCache::removeURLFromCacheInternal(ScriptExecutionContext*, const KURL& url)
+{
+ if (Resource* resource = memoryCache()->resourceForURL(url))
+ memoryCache()->remove(resource);
+}
+
+void MemoryCache::TypeStatistic::addResource(Resource* o)
+{
+ bool purged = o->wasPurged();
+ bool purgeable = o->isPurgeable() && !purged;
+ int pageSize = (o->encodedSize() + o->overheadSize() + 4095) & ~4095;
+ count++;
+ size += purged ? 0 : o->size();
+ liveSize += o->hasClients() ? o->size() : 0;
+ decodedSize += o->decodedSize();
+ encodedSize += o->encodedSize();
+ encodedSizeDuplicatedInDataURLs += o->url().protocolIsData() ? o->encodedSize() : 0;
+ purgeableSize += purgeable ? pageSize : 0;
+ purgedSize += purged ? pageSize : 0;
+}
+
+MemoryCache::Statistics MemoryCache::getStatistics()
+{
+ Statistics stats;
+ ResourceMap::iterator e = m_resources.end();
+ for (ResourceMap::iterator i = m_resources.begin(); i != e; ++i) {
+ Resource* resource = i->value;
+ switch (resource->type()) {
+ case Resource::Image:
+ stats.images.addResource(resource);
+ break;
+ case Resource::CSSStyleSheet:
+ stats.cssStyleSheets.addResource(resource);
+ break;
+ case Resource::Script:
+ stats.scripts.addResource(resource);
+ break;
+ case Resource::XSLStyleSheet:
+ stats.xslStyleSheets.addResource(resource);
+ break;
+ case Resource::Font:
+ stats.fonts.addResource(resource);
+ break;
+ default:
+ stats.other.addResource(resource);
+ break;
+ }
+ }
+ return stats;
+}
+
+void MemoryCache::evictResources()
+{
+ for (;;) {
+ ResourceMap::iterator i = m_resources.begin();
+ if (i == m_resources.end())
+ break;
+ evict(i->value);
+ }
+}
+
+void MemoryCache::prune()
+{
+ TRACE_EVENT0("renderer", "MemoryCache::prune()");
+ if (m_liveSize + m_deadSize <= m_capacity && m_maxDeadCapacity && m_deadSize <= m_maxDeadCapacity) // Fast path.
+ return;
+ if (m_inPruneResources)
+ return;
+ TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
+
+ pruneDeadResources(); // Prune dead first, in case it was "borrowing" capacity from live.
+ pruneLiveResources();
+}
+
+
+#ifdef MEMORY_CACHE_STATS
+
+void MemoryCache::dumpStats(Timer<MemoryCache>*)
+{
+ Statistics s = getStatistics();
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Other", s.other.count, s.other.size, s.other.liveSize, s.other.decodedSize, s.other.purgeableSize, s.other.purgedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
+
+ printf("Duplication of encoded data from data URLs\n");
+ printf("%-13s %13d of %13d\n", "Images", s.images.encodedSizeDuplicatedInDataURLs, s.images.encodedSize);
+ printf("%-13s %13d of %13d\n", "CSS", s.cssStyleSheets.encodedSizeDuplicatedInDataURLs, s.cssStyleSheets.encodedSize);
+ printf("%-13s %13d of %13d\n", "XSL", s.xslStyleSheets.encodedSizeDuplicatedInDataURLs, s.xslStyleSheets.encodedSize);
+ printf("%-13s %13d of %13d\n", "JavaScript", s.scripts.encodedSizeDuplicatedInDataURLs, s.scripts.encodedSize);
+ printf("%-13s %13d of %13d\n", "Fonts", s.fonts.encodedSizeDuplicatedInDataURLs, s.fonts.encodedSize);
+ printf("%-13s %13d of %13d\n", "Other", s.other.encodedSizeDuplicatedInDataURLs, s.other.encodedSize);
+}
+
+void MemoryCache::dumpLRULists(bool includeLive) const
+{
+ printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n");
+
+ int size = m_allResources.size();
+ for (int i = size - 1; i >= 0; i--) {
+ printf("\n\nList %d: ", i);
+ Resource* current = m_allResources[i].m_tail;
+ while (current) {
+ Resource* prev = current->m_prevInAllResourcesList;
+ if (includeLive || !current->hasClients())
+ printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged());
+
+ current = prev;
+ }
+ }
+}
+
+#endif // MEMORY_CACHE_STATS
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.h b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.h
new file mode 100644
index 00000000000..f174a11b9bf
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCache.h
@@ -0,0 +1,210 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef Cache_h
+#define Cache_h
+
+#include "core/loader/cache/Resource.h"
+#include "wtf/HashMap.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/Vector.h"
+#include "wtf/text/StringHash.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class CSSStyleSheetResource;
+class Resource;
+class ResourceFetcher;
+class KURL;
+class ScriptExecutionContext;
+class SecurityOrigin;
+struct SecurityOriginHash;
+
+// This cache holds subresources used by Web pages: images, scripts, stylesheets, etc.
+
+// The cache keeps a flexible but bounded window of dead resources that grows/shrinks
+// depending on the live resource load. Here's an example of cache growth over time,
+// with a min dead resource capacity of 25% and a max dead resource capacity of 50%:
+
+// |-----| Dead: -
+// |----------| Live: +
+// --|----------| Cache boundary: | (objects outside this mark have been evicted)
+// --|----------++++++++++|
+// -------|-----+++++++++++++++|
+// -------|-----+++++++++++++++|+++++
+
+// Enable this macro to periodically log information about the memory cache.
+#undef MEMORY_CACHE_STATS
+
+class MemoryCache {
+ WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_FAST_ALLOCATED;
+public:
+ MemoryCache();
+ ~MemoryCache() { }
+
+ typedef HashMap<String, Resource*> ResourceMap;
+
+ struct LRUList {
+ Resource* m_head;
+ Resource* m_tail;
+ LRUList() : m_head(0), m_tail(0) { }
+ };
+
+ struct TypeStatistic {
+ int count;
+ int size;
+ int liveSize;
+ int decodedSize;
+ int encodedSize;
+ int encodedSizeDuplicatedInDataURLs;
+ int purgeableSize;
+ int purgedSize;
+
+ TypeStatistic()
+ : count(0)
+ , size(0)
+ , liveSize(0)
+ , decodedSize(0)
+ , encodedSize(0)
+ , encodedSizeDuplicatedInDataURLs(0)
+ , purgeableSize(0)
+ , purgedSize(0)
+ {
+ }
+
+ void addResource(Resource*);
+ };
+
+ struct Statistics {
+ TypeStatistic images;
+ TypeStatistic cssStyleSheets;
+ TypeStatistic scripts;
+ TypeStatistic xslStyleSheets;
+ TypeStatistic fonts;
+ TypeStatistic other;
+ };
+
+ Resource* resourceForURL(const KURL&);
+
+ void add(Resource*);
+ void replace(Resource* newResource, Resource* oldResource);
+ void remove(Resource* resource) { evict(resource); }
+
+ static KURL removeFragmentIdentifierIfNeeded(const KURL& originalURL);
+
+ // Sets the cache's memory capacities, in bytes. These will hold only approximately,
+ // since the decoded cost of resources like scripts and stylesheets is not known.
+ // - minDeadBytes: The maximum number of bytes that dead resources should consume when the cache is under pressure.
+ // - maxDeadBytes: The maximum number of bytes that dead resources should consume when the cache is not under pressure.
+ // - totalBytes: The maximum number of bytes that the cache should consume overall.
+ void setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes);
+ void setDelayBeforeLiveDecodedPrune(unsigned seconds) { m_delayBeforeLiveDecodedPrune = seconds; }
+
+ void evictResources();
+
+ void prune();
+
+ // Calls to put the cached resource into and out of LRU lists.
+ void insertInLRUList(Resource*);
+ void removeFromLRUList(Resource*);
+
+ // Called to adjust the cache totals when a resource changes size.
+ void adjustSize(bool live, int delta);
+
+ // Track decoded resources that are in the cache and referenced by a Web page.
+ void insertInLiveDecodedResourcesList(Resource*);
+ void removeFromLiveDecodedResourcesList(Resource*);
+
+ void addToLiveResourcesSize(Resource*);
+ void removeFromLiveResourcesSize(Resource*);
+
+ static void removeURLFromCache(ScriptExecutionContext*, const KURL&);
+
+ Statistics getStatistics();
+
+ unsigned minDeadCapacity() const { return m_minDeadCapacity; }
+ unsigned maxDeadCapacity() const { return m_maxDeadCapacity; }
+ unsigned capacity() const { return m_capacity; }
+ unsigned liveSize() const { return m_liveSize; }
+ unsigned deadSize() const { return m_deadSize; }
+
+private:
+ LRUList* lruListFor(Resource*);
+
+#ifdef MEMORY_CACHE_STATS
+ void dumpStats(Timer<MemoryCache>*);
+ void dumpLRULists(bool includeLive) const;
+#endif
+
+ unsigned liveCapacity() const;
+ unsigned deadCapacity() const;
+
+ // pruneDeadResources() - Flush decoded and encoded data from resources not referenced by Web pages.
+ // pruneLiveResources() - Flush decoded data from resources still referenced by Web pages.
+ void pruneDeadResources(); // Automatically decide how much to prune.
+ void pruneLiveResources();
+
+ void evict(Resource*);
+
+ static void removeURLFromCacheInternal(ScriptExecutionContext*, const KURL&);
+
+ bool m_inPruneResources;
+
+ unsigned m_capacity;
+ unsigned m_minDeadCapacity;
+ unsigned m_maxDeadCapacity;
+ unsigned m_delayBeforeLiveDecodedPrune;
+ double m_deadDecodedDataDeletionInterval;
+
+ unsigned m_liveSize; // The number of bytes currently consumed by "live" resources in the cache.
+ unsigned m_deadSize; // The number of bytes currently consumed by "dead" resources in the cache.
+
+ // Size-adjusted and popularity-aware LRU list collection for cache objects. This collection can hold
+ // more resources than the cached resource map, since it can also hold "stale" multiple versions of objects that are
+ // waiting to die when the clients referencing them go away.
+ Vector<LRUList, 32> m_allResources;
+
+ // Lists just for live resources with decoded data. Access to this list is based off of painting the resource.
+ // The lists are ordered by decode priority, with higher indices having higher priorities.
+ LRUList m_liveDecodedResources[Resource::CacheLiveResourcePriorityHigh + 1];
+
+ // A URL-based map of all resources that are in the cache (including the freshest version of objects that are currently being
+ // referenced by a Web page).
+ HashMap<String, Resource*> m_resources;
+
+#ifdef MEMORY_CACHE_STATS
+ Timer<MemoryCache> m_statsTimer;
+#endif
+};
+
+// Returns the global cache.
+MemoryCache* memoryCache();
+
+// Sets the global cache, used to swap in a test instance.
+void setMemoryCacheForTesting(MemoryCache*);
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCacheTest.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCacheTest.cpp
new file mode 100644
index 00000000000..1a365179772
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/MemoryCacheTest.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/MemoryCache.h"
+
+#include "core/loader/cache/MockImageResourceClient.h"
+#include "core/loader/cache/RawResource.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "wtf/OwnPtr.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class MemoryCacheTest : public ::testing::Test {
+public:
+ class MockImageResource : public WebCore::Resource {
+ public:
+ MockImageResource(const ResourceRequest& request, Type type)
+ : Resource(request, type)
+ {
+ }
+
+ virtual void appendData(const char* data, int len)
+ {
+ Resource::appendData(data, len);
+ setDecodedSize(this->size());
+ }
+
+ virtual void destroyDecodedData()
+ {
+ setDecodedSize(0);
+ }
+ };
+
+protected:
+ virtual void SetUp()
+ {
+ // Save the global memory cache to restore it upon teardown.
+ m_globalMemoryCache = adoptPtr(memoryCache());
+ // Create the test memory cache instance and hook it in.
+ m_testingMemoryCache = adoptPtr(new MemoryCache());
+ setMemoryCacheForTesting(m_testingMemoryCache.leakPtr());
+ }
+
+ virtual void TearDown()
+ {
+ // Regain the ownership of testing memory cache, so that it will be
+ // destroyed.
+ m_testingMemoryCache = adoptPtr(memoryCache());
+ // Yield the ownership of the global memory cache back.
+ setMemoryCacheForTesting(m_globalMemoryCache.leakPtr());
+ }
+
+ OwnPtr<MemoryCache> m_testingMemoryCache;
+ OwnPtr<MemoryCache> m_globalMemoryCache;
+};
+
+// Verifies that setters and getters for cache capacities work correcty.
+TEST_F(MemoryCacheTest, CapacityAccounting)
+{
+ const unsigned totalCapacity = 100;
+ const unsigned minDeadCapacity = 10;
+ const unsigned maxDeadCapacity = 50;
+ memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
+
+ ASSERT_EQ(totalCapacity, memoryCache()->capacity());
+ ASSERT_EQ(minDeadCapacity, memoryCache()->minDeadCapacity());
+ ASSERT_EQ(maxDeadCapacity, memoryCache()->maxDeadCapacity());
+}
+
+// Verifies that dead resources that exceed dead resource capacity are evicted
+// from cache when pruning.
+TEST_F(MemoryCacheTest, DeadResourceEviction)
+{
+ const unsigned totalCapacity = 1000000;
+ const unsigned minDeadCapacity = 0;
+ const unsigned maxDeadCapacity = 0;
+ memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
+
+ ResourcePtr<Resource> cachedResource =
+ new Resource(ResourceRequest(""), Resource::Raw);
+ const char data[5] = "abcd";
+ cachedResource->appendData(data, 3);
+ // The resource size has to be nonzero for this test to be meaningful, but
+ // we do not rely on it having any particular value.
+ ASSERT_GT(cachedResource->size(), 0u);
+
+ ASSERT_EQ(0u, memoryCache()->deadSize());
+ ASSERT_EQ(0u, memoryCache()->liveSize());
+
+ memoryCache()->add(cachedResource.get());
+ ASSERT_EQ(cachedResource->size(), memoryCache()->deadSize());
+ ASSERT_EQ(0u, memoryCache()->liveSize());
+
+ memoryCache()->prune();
+ ASSERT_EQ(0u, memoryCache()->deadSize());
+ ASSERT_EQ(0u, memoryCache()->liveSize());
+}
+
+// Verifies that CachedResources are evicted from the decode cache
+// according to their DecodeCachePriority.
+TEST_F(MemoryCacheTest, DecodeCacheOrder)
+{
+ memoryCache()->setDelayBeforeLiveDecodedPrune(0);
+ ResourcePtr<MockImageResource> cachedImageLowPriority =
+ new MockImageResource(ResourceRequest(""), Resource::Raw);
+ ResourcePtr<MockImageResource> cachedImageHighPriority =
+ new MockImageResource(ResourceRequest(""), Resource::Raw);
+
+ MockImageResourceClient clientLowPriority;
+ MockImageResourceClient clientHighPriority;
+ cachedImageLowPriority->addClient(&clientLowPriority);
+ cachedImageHighPriority->addClient(&clientHighPriority);
+
+ const char data[5] = "abcd";
+ cachedImageLowPriority->appendData(data, 1);
+ cachedImageHighPriority->appendData(data, 4);
+ const unsigned lowPrioritySize = cachedImageLowPriority->size();
+ const unsigned highPrioritySize = cachedImageHighPriority->size();
+ const unsigned lowPriorityMockDecodeSize = cachedImageLowPriority->decodedSize();
+ const unsigned highPriorityMockDecodeSize = cachedImageHighPriority->decodedSize();
+ const unsigned totalSize = lowPrioritySize + highPrioritySize;
+
+ // Verify that the sizes are different to ensure that we can test eviction order.
+ ASSERT_GT(lowPrioritySize, 0u);
+ ASSERT_NE(lowPrioritySize, highPrioritySize);
+ ASSERT_GT(lowPriorityMockDecodeSize, 0u);
+ ASSERT_NE(lowPriorityMockDecodeSize, highPriorityMockDecodeSize);
+
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), 0u);
+
+ // Add the items. The item added first would normally be evicted first.
+ memoryCache()->add(cachedImageHighPriority.get());
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize);
+
+ memoryCache()->add(cachedImageLowPriority.get());
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize + lowPrioritySize);
+
+ // Insert all items in the decoded items list with the same priority
+ memoryCache()->insertInLiveDecodedResourcesList(cachedImageHighPriority.get());
+ memoryCache()->insertInLiveDecodedResourcesList(cachedImageLowPriority.get());
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), totalSize);
+
+ // Now we will assign their priority and make sure they are moved to the correct buckets.
+ cachedImageLowPriority->setCacheLiveResourcePriority(Resource::CacheLiveResourcePriorityLow);
+ cachedImageHighPriority->setCacheLiveResourcePriority(Resource::CacheLiveResourcePriorityHigh);
+
+ // Should first prune the LowPriority item.
+ memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
+ memoryCache()->prune();
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize);
+
+ // Should prune the HighPriority item.
+ memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
+ memoryCache()->prune();
+ ASSERT_EQ(memoryCache()->deadSize(), 0u);
+ ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize - highPriorityMockDecodeSize);
+}
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/MockImageResourceClient.h b/chromium/third_party/WebKit/Source/core/loader/cache/MockImageResourceClient.h
new file mode 100644
index 00000000000..adaa90f527a
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/MockImageResourceClient.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MockImageResourceClient_h
+#define MockImageResourceClient_h
+
+#include "core/loader/cache/ImageResourceClient.h"
+#include "core/page/Frame.h"
+#include "core/platform/graphics/Image.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class MockImageResourceClient : public WebCore::ImageResourceClient {
+public:
+ MockImageResourceClient()
+ : m_imageChangedCount(0)
+ , m_notifyFinishedCalled(false)
+ {
+ }
+
+ virtual ~MockImageResourceClient() { }
+ virtual void imageChanged(ImageResource*, const IntRect*)
+ {
+ m_imageChangedCount++;
+ }
+
+ virtual void notifyFinished(Resource*)
+ {
+ ASSERT_FALSE(m_notifyFinishedCalled);
+ m_notifyFinishedCalled = true;
+ }
+
+ int imageChangedCount() const { return m_imageChangedCount; }
+ bool notifyFinishedCalled() const { return m_notifyFinishedCalled; }
+
+private:
+ int m_imageChangedCount;
+ bool m_notifyFinishedCalled;
+};
+
+} // namespace WebCore
+
+#endif // ImageResourceTest_h
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.cpp
new file mode 100644
index 00000000000..a2a0dc4eacd
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 Google Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/RawResource.h"
+
+#include "core/loader/ResourceLoader.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/loader/cache/ResourceFetcher.h"
+#include "core/platform/SharedBuffer.h"
+
+namespace WebCore {
+
+RawResource::RawResource(const ResourceRequest& resourceRequest, Type type)
+ : Resource(resourceRequest, type)
+{
+}
+
+void RawResource::appendData(const char* data, int length)
+{
+ Resource::appendData(data, length);
+
+ ResourcePtr<RawResource> protect(this);
+ ResourceClientWalker<RawResourceClient> w(m_clients);
+ while (RawResourceClient* c = w.next())
+ c->dataReceived(this, data, length);
+}
+
+void RawResource::didAddClient(ResourceClient* c)
+{
+ if (!hasClient(c))
+ return;
+ // The calls to the client can result in events running, potentially causing
+ // this resource to be evicted from the cache and all clients to be removed,
+ // so a protector is necessary.
+ ResourcePtr<RawResource> protect(this);
+ RawResourceClient* client = static_cast<RawResourceClient*>(c);
+ size_t redirectCount = m_redirectChain.size();
+ for (size_t i = 0; i < redirectCount; i++) {
+ RedirectPair redirect = m_redirectChain[i];
+ ResourceRequest request(redirect.m_request);
+ client->redirectReceived(this, request, redirect.m_redirectResponse);
+ if (!hasClient(c))
+ return;
+ }
+ ASSERT(redirectCount == m_redirectChain.size());
+
+ if (!m_response.isNull())
+ client->responseReceived(this, m_response);
+ if (!hasClient(c))
+ return;
+ if (m_data)
+ client->dataReceived(this, m_data->data(), m_data->size());
+ if (!hasClient(c))
+ return;
+ Resource::didAddClient(client);
+}
+
+void RawResource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
+{
+ ResourcePtr<RawResource> protect(this);
+ if (!response.isNull()) {
+ ResourceClientWalker<RawResourceClient> w(m_clients);
+ while (RawResourceClient* c = w.next())
+ c->redirectReceived(this, request, response);
+ m_redirectChain.append(RedirectPair(request, response));
+ }
+ Resource::willSendRequest(request, response);
+}
+
+void RawResource::responseReceived(const ResourceResponse& response)
+{
+ ResourcePtr<RawResource> protect(this);
+ Resource::responseReceived(response);
+ ResourceClientWalker<RawResourceClient> w(m_clients);
+ while (RawResourceClient* c = w.next())
+ c->responseReceived(this, m_response);
+}
+
+void RawResource::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+{
+ ResourceClientWalker<RawResourceClient> w(m_clients);
+ while (RawResourceClient* c = w.next())
+ c->dataSent(this, bytesSent, totalBytesToBeSent);
+}
+
+void RawResource::didDownloadData(int dataLength)
+{
+ ResourceClientWalker<RawResourceClient> w(m_clients);
+ while (RawResourceClient* c = w.next())
+ c->dataDownloaded(this, dataLength);
+}
+
+void RawResource::setDefersLoading(bool defers)
+{
+ if (m_loader)
+ m_loader->setDefersLoading(defers);
+}
+
+void RawResource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
+{
+ m_options.dataBufferingPolicy = dataBufferingPolicy;
+ clear();
+}
+
+static bool shouldIgnoreHeaderForCacheReuse(AtomicString headerName)
+{
+ // FIXME: This list of headers that don't affect cache policy almost certainly isn't complete.
+ DEFINE_STATIC_LOCAL(HashSet<AtomicString>, m_headers, ());
+ if (m_headers.isEmpty()) {
+ m_headers.add("Accept");
+ m_headers.add("Cache-Control");
+ m_headers.add("If-Modified-Since");
+ m_headers.add("If-None-Match");
+ m_headers.add("Origin");
+ m_headers.add("Pragma");
+ m_headers.add("Purpose");
+ m_headers.add("Referer");
+ m_headers.add("User-Agent");
+ }
+ return m_headers.contains(headerName);
+}
+
+bool RawResource::canReuse(const ResourceRequest& newRequest) const
+{
+ if (m_options.dataBufferingPolicy == DoNotBufferData)
+ return false;
+
+ if (m_resourceRequest.httpMethod() != newRequest.httpMethod())
+ return false;
+
+ if (m_resourceRequest.httpBody() != newRequest.httpBody())
+ return false;
+
+ if (m_resourceRequest.allowCookies() != newRequest.allowCookies())
+ return false;
+
+ // Ensure most headers match the existing headers before continuing.
+ // Note that the list of ignored headers includes some headers explicitly related to caching.
+ // A more detailed check of caching policy will be performed later, this is simply a list of
+ // headers that we might permit to be different and still reuse the existing Resource.
+ const HTTPHeaderMap& newHeaders = newRequest.httpHeaderFields();
+ const HTTPHeaderMap& oldHeaders = m_resourceRequest.httpHeaderFields();
+
+ HTTPHeaderMap::const_iterator end = newHeaders.end();
+ for (HTTPHeaderMap::const_iterator i = newHeaders.begin(); i != end; ++i) {
+ AtomicString headerName = i->key;
+ if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != oldHeaders.get(headerName))
+ return false;
+ }
+
+ end = oldHeaders.end();
+ for (HTTPHeaderMap::const_iterator i = oldHeaders.begin(); i != end; ++i) {
+ AtomicString headerName = i->key;
+ if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != newHeaders.get(headerName))
+ return false;
+ }
+
+ for (size_t i = 0; i < m_redirectChain.size(); i++) {
+ if (m_redirectChain[i].m_redirectResponse.cacheControlContainsNoStore())
+ return false;
+ }
+
+ return true;
+}
+
+void RawResource::clear()
+{
+ m_data.clear();
+ setEncodedSize(0);
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.h
new file mode 100644
index 00000000000..05cf3f4d8bf
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/RawResource.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007 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.
+*/
+
+#ifndef RawResource_h
+#define RawResource_h
+
+#include "core/loader/cache/Resource.h"
+#include "core/loader/cache/ResourceClient.h"
+
+namespace WebCore {
+class RawResourceCallback;
+class RawResourceClient;
+
+class RawResource : public Resource {
+public:
+ RawResource(const ResourceRequest&, Type);
+
+ // FIXME: AssociatedURLLoader shouldn't be a DocumentThreadableLoader and therefore shouldn't
+ // use RawResource. However, it is, and it needs to be able to defer loading.
+ // This can be fixed by splitting CORS preflighting out of DocumentThreacableLoader.
+ virtual void setDefersLoading(bool);
+
+ virtual void setDataBufferingPolicy(DataBufferingPolicy);
+
+ void clear();
+
+ virtual bool canReuse(const ResourceRequest&) const;
+
+private:
+ virtual void didAddClient(ResourceClient*);
+ virtual void appendData(const char*, int) OVERRIDE;
+
+ virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return true; }
+
+ virtual void willSendRequest(ResourceRequest&, const ResourceResponse&);
+ virtual void responseReceived(const ResourceResponse&);
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
+ virtual void didDownloadData(int);
+
+ struct RedirectPair {
+ public:
+ explicit RedirectPair(const ResourceRequest& request, const ResourceResponse& redirectResponse)
+ : m_request(request)
+ , m_redirectResponse(redirectResponse)
+ {
+ }
+
+ const ResourceRequest m_request;
+ const ResourceResponse m_redirectResponse;
+ };
+
+ Vector<RedirectPair> m_redirectChain;
+};
+
+
+class RawResourceClient : public ResourceClient {
+public:
+ virtual ~RawResourceClient() { }
+ static ResourceClientType expectedType() { return RawResourceType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+
+ virtual void dataSent(Resource*, unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
+ virtual void responseReceived(Resource*, const ResourceResponse&) { }
+ virtual void dataReceived(Resource*, const char* /* data */, int /* length */) { }
+ virtual void redirectReceived(Resource*, ResourceRequest&, const ResourceResponse&) { }
+ virtual void dataDownloaded(Resource*, int) { }
+};
+
+}
+
+#endif // RawResource_h
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/Resource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/Resource.cpp
new file mode 100644
index 00000000000..ae832e127d3
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/Resource.cpp
@@ -0,0 +1,839 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "config.h"
+#include "core/loader/cache/Resource.h"
+
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/loader/CachedMetadata.h"
+#include "core/loader/CrossOriginAccessControl.h"
+#include "core/loader/ResourceLoader.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/loader/cache/ResourceFetcher.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/platform/Logging.h"
+#include "core/platform/PurgeableBuffer.h"
+#include "core/platform/SharedBuffer.h"
+#include "public/platform/Platform.h"
+#include "weborigin/KURL.h"
+#include "wtf/CurrentTime.h"
+#include "wtf/MathExtras.h"
+#include "wtf/RefCountedLeakCounter.h"
+#include "wtf/StdLibExtras.h"
+#include "wtf/Vector.h"
+#include "wtf/text/CString.h"
+
+using namespace WTF;
+
+namespace WebCore {
+
+// These response headers are not copied from a revalidated response to the
+// cached response headers. For compatibility, this list is based on Chromium's
+// net/http/http_response_headers.cc.
+const char* const headersToIgnoreAfterRevalidation[] = {
+ "allow",
+ "connection",
+ "etag",
+ "expires",
+ "keep-alive",
+ "last-modified"
+ "proxy-authenticate",
+ "proxy-connection",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "www-authenticate",
+ "x-frame-options",
+ "x-xss-protection",
+};
+
+// Some header prefixes mean "Don't copy this header from a 304 response.".
+// Rather than listing all the relevant headers, we can consolidate them into
+// this list, also grabbed from Chromium's net/http/http_response_headers.cc.
+const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
+ "content-",
+ "x-content-",
+ "x-webkit-"
+};
+
+static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& header)
+{
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i++) {
+ if (header == headersToIgnoreAfterRevalidation[i])
+ return false;
+ }
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
+ if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i]))
+ return false;
+ }
+ return true;
+}
+
+DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
+
+Resource::Resource(const ResourceRequest& request, Type type)
+ : m_resourceRequest(request)
+ , m_responseTimestamp(currentTime())
+ , m_cancelTimer(this, &Resource::cancelTimerFired)
+ , m_lastDecodedAccessTime(0)
+ , m_loadFinishTime(0)
+ , m_identifier(0)
+ , m_encodedSize(0)
+ , m_decodedSize(0)
+ , m_accessCount(0)
+ , m_handleCount(0)
+ , m_preloadCount(0)
+ , m_preloadResult(PreloadNotReferenced)
+ , m_cacheLiveResourcePriority(CacheLiveResourcePriorityLow)
+ , m_inLiveDecodedResourcesList(false)
+ , m_requestedFromNetworkingLayer(false)
+ , m_inCache(false)
+ , m_loading(false)
+ , m_switchingClientsToRevalidatedResource(false)
+ , m_type(type)
+ , m_status(Pending)
+#ifndef NDEBUG
+ , m_deleted(false)
+ , m_lruIndex(0)
+#endif
+ , m_nextInAllResourcesList(0)
+ , m_prevInAllResourcesList(0)
+ , m_nextInLiveResourcesList(0)
+ , m_prevInLiveResourcesList(0)
+ , m_resourceToRevalidate(0)
+ , m_proxyResource(0)
+{
+ ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
+#ifndef NDEBUG
+ cachedResourceLeakCounter.increment();
+#endif
+
+ if (!m_resourceRequest.url().hasFragmentIdentifier())
+ return;
+ KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
+ if (urlForCache.hasFragmentIdentifier())
+ return;
+ m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier();
+ m_resourceRequest.setURL(urlForCache);
+}
+
+Resource::~Resource()
+{
+ ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this.
+ ASSERT(canDelete());
+ ASSERT(!inCache());
+ ASSERT(!m_deleted);
+ ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
+
+#ifndef NDEBUG
+ m_deleted = true;
+ cachedResourceLeakCounter.decrement();
+#endif
+}
+
+void Resource::failBeforeStarting()
+{
+ LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
+ error(Resource::LoadError);
+}
+
+void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& options)
+{
+ if (!fetcher->frame()) {
+ failBeforeStarting();
+ return;
+ }
+
+ m_options = options;
+ m_loading = true;
+
+ if (!accept().isEmpty())
+ m_resourceRequest.setHTTPAccept(accept());
+
+ // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
+ // We should look into removing the expectation of that knowledge from the platform network stacks.
+ ResourceRequest request(m_resourceRequest);
+ if (!m_fragmentIdentifierForRequest.isNull()) {
+ KURL url = request.url();
+ url.setFragmentIdentifier(m_fragmentIdentifierForRequest);
+ request.setURL(url);
+ m_fragmentIdentifierForRequest = String();
+ }
+
+ m_loader = ResourceLoader::create(fetcher, this, request, options);
+ if (!m_loader) {
+ failBeforeStarting();
+ return;
+ }
+ m_status = Pending;
+}
+
+void Resource::checkNotify()
+{
+ if (isLoading())
+ return;
+
+ ResourceClientWalker<ResourceClient> w(m_clients);
+ while (ResourceClient* c = w.next())
+ c->notifyFinished(this);
+}
+
+void Resource::appendData(const char* data, int length)
+{
+ ASSERT(!m_resourceToRevalidate);
+ ASSERT(!errorOccurred());
+ if (m_options.dataBufferingPolicy == DoNotBufferData)
+ return;
+ if (m_data)
+ m_data->append(data, length);
+ else
+ m_data = SharedBuffer::create(data, length);
+ setEncodedSize(m_data->size());
+}
+
+void Resource::error(Resource::Status status)
+{
+ if (m_resourceToRevalidate)
+ revalidationFailed();
+
+ if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded()))
+ memoryCache()->remove(this);
+
+ setStatus(status);
+ ASSERT(errorOccurred());
+ m_data.clear();
+
+ setLoading(false);
+ checkNotify();
+}
+
+void Resource::finishOnePart()
+{
+ setLoading(false);
+ checkNotify();
+}
+
+void Resource::finish(double finishTime)
+{
+ ASSERT(!m_resourceToRevalidate);
+ ASSERT(!errorOccurred());
+ m_loadFinishTime = finishTime;
+ finishOnePart();
+ if (!errorOccurred())
+ m_status = Cached;
+}
+
+bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
+{
+ String ignoredErrorDescription;
+ return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
+}
+
+bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
+{
+ return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
+}
+
+bool Resource::isExpired() const
+{
+ if (m_response.isNull())
+ return false;
+
+ return currentAge() > freshnessLifetime();
+}
+
+double Resource::currentAge() const
+{
+ // RFC2616 13.2.3
+ // No compensation for latency as that is not terribly important in practice
+ double dateValue = m_response.date();
+ double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
+ double ageValue = m_response.age();
+ double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
+ double residentTime = currentTime() - m_responseTimestamp;
+ return correctedReceivedAge + residentTime;
+}
+
+double Resource::freshnessLifetime() const
+{
+ // Cache non-http resources liberally
+ if (!m_response.url().protocolIsInHTTPFamily())
+ return std::numeric_limits<double>::max();
+
+ // RFC2616 13.2.4
+ double maxAgeValue = m_response.cacheControlMaxAge();
+ if (std::isfinite(maxAgeValue))
+ return maxAgeValue;
+ double expiresValue = m_response.expires();
+ double dateValue = m_response.date();
+ double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
+ if (std::isfinite(expiresValue))
+ return expiresValue - creationTime;
+ double lastModifiedValue = m_response.lastModified();
+ if (std::isfinite(lastModifiedValue))
+ return (creationTime - lastModifiedValue) * 0.1;
+ // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
+ return 0;
+}
+
+void Resource::responseReceived(const ResourceResponse& response)
+{
+ setResponse(response);
+ m_responseTimestamp = currentTime();
+ String encoding = response.textEncodingName();
+ if (!encoding.isNull())
+ setEncoding(encoding);
+
+ if (!m_resourceToRevalidate)
+ return;
+ if (response.httpStatusCode() == 304)
+ revalidationSucceeded(response);
+ else
+ revalidationFailed();
+}
+
+void Resource::setSerializedCachedMetadata(const char* data, size_t size)
+{
+ // We only expect to receive cached metadata from the platform once.
+ // If this triggers, it indicates an efficiency problem which is most
+ // likely unexpected in code designed to improve performance.
+ ASSERT(!m_cachedMetadata);
+ ASSERT(!m_resourceToRevalidate);
+
+ m_cachedMetadata = CachedMetadata::deserialize(data, size);
+}
+
+void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
+{
+ // Currently, only one type of cached metadata per resource is supported.
+ // If the need arises for multiple types of metadata per resource this could
+ // be enhanced to store types of metadata in a map.
+ ASSERT(!m_cachedMetadata);
+
+ m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
+ const Vector<char>& serializedData = m_cachedMetadata->serialize();
+ WebKit::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
+}
+
+CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
+{
+ if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
+ return 0;
+ return m_cachedMetadata.get();
+}
+
+void Resource::setCacheLiveResourcePriority(CacheLiveResourcePriority priority)
+{
+ if (inCache() && m_inLiveDecodedResourcesList && m_cacheLiveResourcePriority != priority) {
+ memoryCache()->removeFromLiveDecodedResourcesList(this);
+ m_cacheLiveResourcePriority = priority;
+ memoryCache()->insertInLiveDecodedResourcesList(this);
+ memoryCache()->prune();
+ }
+}
+
+void Resource::clearLoader()
+{
+ m_loader = 0;
+}
+
+void Resource::addClient(ResourceClient* client)
+{
+ if (addClientToSet(client))
+ didAddClient(client);
+}
+
+void Resource::didAddClient(ResourceClient* c)
+{
+ if (m_clientsAwaitingCallback.contains(c)) {
+ m_clients.add(c);
+ m_clientsAwaitingCallback.remove(c);
+ }
+ if (!isLoading() && !stillNeedsLoad())
+ c->notifyFinished(this);
+}
+
+bool Resource::addClientToSet(ResourceClient* client)
+{
+ ASSERT(!isPurgeable());
+
+ if (m_preloadResult == PreloadNotReferenced) {
+ if (isLoaded())
+ m_preloadResult = PreloadReferencedWhileComplete;
+ else if (m_requestedFromNetworkingLayer)
+ m_preloadResult = PreloadReferencedWhileLoading;
+ else
+ m_preloadResult = PreloadReferenced;
+ }
+ if (!hasClients() && inCache())
+ memoryCache()->addToLiveResourcesSize(this);
+
+ if ((m_type == Raw || m_type == MainResource) && !m_response.isNull() && !m_proxyResource) {
+ // Certain resources (especially XHRs and main resources) do crazy things if an asynchronous load returns
+ // synchronously (e.g., scripts may not have set all the state they need to handle the load).
+ // Therefore, rather than immediately sending callbacks on a cache hit like other Resources,
+ // we schedule the callbacks and ensure we never finish synchronously.
+ ASSERT(!m_clientsAwaitingCallback.contains(client));
+ m_clientsAwaitingCallback.add(client, ResourceCallback::schedule(this, client));
+ return false;
+ }
+
+ m_clients.add(client);
+ return true;
+}
+
+void Resource::removeClient(ResourceClient* client)
+{
+ OwnPtr<ResourceCallback> callback = m_clientsAwaitingCallback.take(client);
+ if (callback) {
+ ASSERT(!m_clients.contains(client));
+ callback->cancel();
+ callback.clear();
+ } else {
+ ASSERT(m_clients.contains(client));
+ m_clients.remove(client);
+ didRemoveClient(client);
+ }
+
+ bool deleted = deleteIfPossible();
+ if (!deleted && !hasClients()) {
+ if (inCache()) {
+ memoryCache()->removeFromLiveResourcesSize(this);
+ memoryCache()->removeFromLiveDecodedResourcesList(this);
+ }
+ if (!m_switchingClientsToRevalidatedResource)
+ allClientsRemoved();
+ if (response().cacheControlContainsNoStore()) {
+ // RFC2616 14.9.2:
+ // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
+ // "... History buffers MAY store such responses as part of their normal operation."
+ // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
+ if (url().protocolIs("https"))
+ memoryCache()->remove(this);
+ } else {
+ memoryCache()->prune();
+ }
+ }
+ // This object may be dead here.
+}
+
+void Resource::allClientsRemoved()
+{
+ if (!m_loader)
+ return;
+ if (m_type == MainResource || m_type == Raw)
+ cancelTimerFired(&m_cancelTimer);
+ else if (!m_cancelTimer.isActive())
+ m_cancelTimer.startOneShot(0);
+}
+
+void Resource::cancelTimerFired(Timer<Resource>* timer)
+{
+ ASSERT_UNUSED(timer, timer == &m_cancelTimer);
+ if (hasClients() || !m_loader)
+ return;
+ ResourcePtr<Resource> protect(this);
+ m_loader->cancelIfNotFinishing();
+ if (m_status != Cached)
+ memoryCache()->remove(this);
+}
+
+bool Resource::deleteIfPossible()
+{
+ if (canDelete() && !inCache()) {
+ InspectorInstrumentation::willDestroyResource(this);
+ delete this;
+ return true;
+ }
+ return false;
+}
+
+void Resource::setDecodedSize(unsigned size)
+{
+ if (size == m_decodedSize)
+ return;
+
+ int delta = size - m_decodedSize;
+
+ // The object must now be moved to a different queue, since its size has been changed.
+ // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
+ // queue.
+ if (inCache())
+ memoryCache()->removeFromLRUList(this);
+
+ m_decodedSize = size;
+
+ if (inCache()) {
+ // Now insert into the new LRU list.
+ memoryCache()->insertInLRUList(this);
+
+ // Insert into or remove from the live decoded list if necessary.
+ // When inserting into the LiveDecodedResourcesList it is possible
+ // that the m_lastDecodedAccessTime is still zero or smaller than
+ // the m_lastDecodedAccessTime of the current list head. This is a
+ // violation of the invariant that the list is to be kept sorted
+ // by access time. The weakening of the invariant does not pose
+ // a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
+ if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
+ memoryCache()->insertInLiveDecodedResourcesList(this);
+ else if (!m_decodedSize && m_inLiveDecodedResourcesList)
+ memoryCache()->removeFromLiveDecodedResourcesList(this);
+
+ // Update the cache's size totals.
+ memoryCache()->adjustSize(hasClients(), delta);
+ }
+}
+
+void Resource::setEncodedSize(unsigned size)
+{
+ if (size == m_encodedSize)
+ return;
+
+ int delta = size - m_encodedSize;
+
+ // The object must now be moved to a different queue, since its size has been changed.
+ // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
+ // queue.
+ if (inCache())
+ memoryCache()->removeFromLRUList(this);
+
+ m_encodedSize = size;
+
+ if (inCache()) {
+ // Now insert into the new LRU list.
+ memoryCache()->insertInLRUList(this);
+
+ // Update the cache's size totals.
+ memoryCache()->adjustSize(hasClients(), delta);
+ }
+}
+
+void Resource::didAccessDecodedData(double timeStamp)
+{
+ m_lastDecodedAccessTime = timeStamp;
+ if (inCache()) {
+ if (m_inLiveDecodedResourcesList) {
+ memoryCache()->removeFromLiveDecodedResourcesList(this);
+ memoryCache()->insertInLiveDecodedResourcesList(this);
+ }
+ memoryCache()->prune();
+ }
+}
+
+void Resource::setResourceToRevalidate(Resource* resource)
+{
+ ASSERT(resource);
+ ASSERT(!m_resourceToRevalidate);
+ ASSERT(resource != this);
+ ASSERT(m_handlesToRevalidate.isEmpty());
+ ASSERT(resource->type() == type());
+
+ LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, resource);
+
+ // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
+ // https://bugs.webkit.org/show_bug.cgi?id=28604.
+ // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalidate.
+ ASSERT(!resource->m_proxyResource);
+
+ resource->m_proxyResource = this;
+ m_resourceToRevalidate = resource;
+}
+
+void Resource::clearResourceToRevalidate()
+{
+ ASSERT(m_resourceToRevalidate);
+ if (m_switchingClientsToRevalidatedResource)
+ return;
+
+ // A resource may start revalidation before this method has been called, so check that this resource is still the proxy resource before clearing it out.
+ if (m_resourceToRevalidate->m_proxyResource == this) {
+ m_resourceToRevalidate->m_proxyResource = 0;
+ m_resourceToRevalidate->deleteIfPossible();
+ }
+ m_handlesToRevalidate.clear();
+ m_resourceToRevalidate = 0;
+ deleteIfPossible();
+}
+
+void Resource::switchClientsToRevalidatedResource()
+{
+ ASSERT(m_resourceToRevalidate);
+ ASSERT(m_resourceToRevalidate->inCache());
+ ASSERT(!inCache());
+
+ LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
+
+ m_resourceToRevalidate->m_identifier = m_identifier;
+
+ m_switchingClientsToRevalidatedResource = true;
+ HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
+ for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
+ ResourcePtrBase* handle = *it;
+ handle->m_resource = m_resourceToRevalidate;
+ m_resourceToRevalidate->registerHandle(handle);
+ --m_handleCount;
+ }
+ ASSERT(!m_handleCount);
+ m_handlesToRevalidate.clear();
+
+ Vector<ResourceClient*> clientsToMove;
+ HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
+ for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
+ ResourceClient* client = it->key;
+ unsigned count = it->value;
+ while (count) {
+ clientsToMove.append(client);
+ --count;
+ }
+ }
+
+ unsigned moveCount = clientsToMove.size();
+ for (unsigned n = 0; n < moveCount; ++n)
+ removeClient(clientsToMove[n]);
+ ASSERT(m_clients.isEmpty());
+
+ for (unsigned n = 0; n < moveCount; ++n)
+ m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
+ for (unsigned n = 0; n < moveCount; ++n) {
+ // Calling didAddClient may do anything, including trying to cancel revalidation.
+ // Assert that it didn't succeed.
+ ASSERT(m_resourceToRevalidate);
+ // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
+ if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
+ m_resourceToRevalidate->didAddClient(clientsToMove[n]);
+ }
+ m_switchingClientsToRevalidatedResource = false;
+}
+
+void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
+{
+ m_responseTimestamp = currentTime();
+
+ // RFC2616 10.3.5
+ // Update cached headers from the 304 response
+ const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
+ HTTPHeaderMap::const_iterator end = newHeaders.end();
+ for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
+ // Entity headers should not be sent by servers when generating a 304
+ // response; misconfigured servers send them anyway. We shouldn't allow
+ // such headers to update the original request. We'll base this on the
+ // list defined by RFC2616 7.1, with a few additions for extension headers
+ // we care about.
+ if (!shouldUpdateHeaderAfterRevalidation(it->key))
+ continue;
+ m_response.setHTTPHeaderField(it->key, it->value);
+ }
+}
+
+void Resource::revalidationSucceeded(const ResourceResponse& response)
+{
+ ASSERT(m_resourceToRevalidate);
+ ASSERT(!m_resourceToRevalidate->inCache());
+ ASSERT(m_resourceToRevalidate->isLoaded());
+ ASSERT(inCache());
+
+ // Calling evict() can potentially delete revalidatingResource, which we use
+ // below. This mustn't be the case since revalidation means it is loaded
+ // and so canDelete() is false.
+ ASSERT(!canDelete());
+
+ m_resourceToRevalidate->updateResponseAfterRevalidation(response);
+ memoryCache()->replace(m_resourceToRevalidate, this);
+
+ switchClientsToRevalidatedResource();
+ ASSERT(!m_deleted);
+ // clearResourceToRevalidate deletes this.
+ clearResourceToRevalidate();
+}
+
+void Resource::revalidationFailed()
+{
+ ASSERT(WTF::isMainThread());
+ LOG(ResourceLoading, "Revalidation failed for %p", this);
+ ASSERT(resourceToRevalidate());
+ clearResourceToRevalidate();
+}
+
+void Resource::updateForAccess()
+{
+ ASSERT(inCache());
+
+ // Need to make sure to remove before we increase the access count, since
+ // the queue will possibly change.
+ memoryCache()->removeFromLRUList(this);
+
+ // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
+ if (!m_accessCount)
+ memoryCache()->adjustSize(hasClients(), size());
+
+ m_accessCount++;
+ memoryCache()->insertInLRUList(this);
+}
+
+void Resource::registerHandle(ResourcePtrBase* h)
+{
+ ++m_handleCount;
+ if (m_resourceToRevalidate)
+ m_handlesToRevalidate.add(h);
+}
+
+void Resource::unregisterHandle(ResourcePtrBase* h)
+{
+ ASSERT(m_handleCount > 0);
+ --m_handleCount;
+
+ if (m_resourceToRevalidate)
+ m_handlesToRevalidate.remove(h);
+
+ if (!m_handleCount)
+ deleteIfPossible();
+}
+
+bool Resource::canUseCacheValidator() const
+{
+ if (m_loading || errorOccurred())
+ return false;
+
+ if (m_response.cacheControlContainsNoStore())
+ return false;
+ return m_response.hasCacheValidatorFields();
+}
+
+bool Resource::mustRevalidateDueToCacheHeaders(CachePolicy cachePolicy) const
+{
+ ASSERT(cachePolicy == CachePolicyRevalidate || cachePolicy == CachePolicyCache || cachePolicy == CachePolicyVerify);
+
+ if (cachePolicy == CachePolicyRevalidate)
+ return true;
+
+ if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
+ LOG(ResourceLoading, "Resource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
+ return true;
+ }
+
+ if (cachePolicy == CachePolicyCache) {
+ if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
+ LOG(ResourceLoading, "Resource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
+ return true;
+ }
+ return false;
+ }
+
+ // CachePolicyVerify
+ if (isExpired()) {
+ LOG(ResourceLoading, "Resource %p mustRevalidate because of isExpired()\n", this);
+ return true;
+ }
+
+ return false;
+}
+
+bool Resource::isSafeToMakePurgeable() const
+{
+ return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
+}
+
+bool Resource::makePurgeable(bool purgeable)
+{
+ if (purgeable) {
+ ASSERT(isSafeToMakePurgeable());
+
+ if (m_purgeableData) {
+ ASSERT(!m_data);
+ return true;
+ }
+ if (!m_data)
+ return false;
+
+ // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
+ if (!m_data->hasOneRef())
+ return false;
+
+ m_data->createPurgeableBuffer();
+ if (!m_data->hasPurgeableBuffer())
+ return false;
+
+ m_purgeableData = m_data->releasePurgeableBuffer();
+ m_purgeableData->unlock();
+ m_data.clear();
+ return true;
+ }
+
+ if (!m_purgeableData)
+ return true;
+
+ ASSERT(!m_data);
+ ASSERT(!hasClients());
+
+ if (!m_purgeableData->lock())
+ return false;
+
+ m_data = SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release());
+ return true;
+}
+
+bool Resource::isPurgeable() const
+{
+ return m_purgeableData && m_purgeableData->isPurgeable();
+}
+
+bool Resource::wasPurged() const
+{
+ return m_purgeableData && m_purgeableData->wasPurged();
+}
+
+unsigned Resource::overheadSize() const
+{
+ static const int kAverageClientsHashMapSize = 384;
+ return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
+}
+
+void Resource::didChangePriority(ResourceLoadPriority loadPriority)
+{
+ if (m_loader)
+ m_loader->didChangePriority(loadPriority);
+}
+
+Resource::ResourceCallback::ResourceCallback(Resource* resource, ResourceClient* client)
+ : m_resource(resource)
+ , m_client(client)
+ , m_callbackTimer(this, &ResourceCallback::timerFired)
+{
+ m_callbackTimer.startOneShot(0);
+}
+
+void Resource::ResourceCallback::cancel()
+{
+ if (m_callbackTimer.isActive())
+ m_callbackTimer.stop();
+}
+
+void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
+{
+ m_resource->didAddClient(m_client);
+}
+
+}
+
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/Resource.h b/chromium/third_party/WebKit/Source/core/loader/cache/Resource.h
new file mode 100644
index 00000000000..dd092e3e9f9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/Resource.h
@@ -0,0 +1,361 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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.
+*/
+
+#ifndef Resource_h
+#define Resource_h
+
+#include "core/loader/ResourceLoaderOptions.h"
+#include "core/loader/cache/CachePolicy.h"
+#include "core/platform/Timer.h"
+#include "core/platform/network/ResourceError.h"
+#include "core/platform/network/ResourceLoadPriority.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/platform/network/ResourceResponse.h"
+#include "wtf/HashCountedSet.h"
+#include "wtf/HashSet.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class MemoryCache;
+class CachedMetadata;
+class ResourceClient;
+class ResourcePtrBase;
+class ResourceFetcher;
+class InspectorResource;
+class PurgeableBuffer;
+class ResourceLoader;
+class SecurityOrigin;
+class SharedBuffer;
+
+// A resource that is held in the cache. Classes who want to use this object should derive
+// from ResourceClient, to get the function calls in case the requested data has arrived.
+// This class also does the actual communication with the loader to obtain the resource from the network.
+class Resource {
+ WTF_MAKE_NONCOPYABLE(Resource); WTF_MAKE_FAST_ALLOCATED;
+ friend class MemoryCache;
+ friend class InspectorResource;
+
+public:
+ enum Type {
+ MainResource,
+ Image,
+ CSSStyleSheet,
+ Script,
+ Font,
+ Raw,
+ SVGDocument,
+ XSLStyleSheet,
+ LinkPrefetch,
+ LinkSubresource,
+ TextTrack,
+ Shader,
+ ImportResource
+ };
+
+ enum Status {
+ Unknown, // let cache decide what to do with it
+ Pending, // only partially loaded
+ Cached, // regular case
+ LoadError,
+ DecodeError
+ };
+
+ Resource(const ResourceRequest&, Type);
+ virtual ~Resource();
+
+ // Determines the order in which CachedResources are evicted
+ // from the decoded resources cache.
+ enum CacheLiveResourcePriority {
+ CacheLiveResourcePriorityLow = 0,
+ CacheLiveResourcePriorityHigh
+ };
+
+ virtual void load(ResourceFetcher*, const ResourceLoaderOptions&);
+
+ virtual void setEncoding(const String&) { }
+ virtual String encoding() const { return String(); }
+ virtual void appendData(const char*, int);
+ virtual void error(Resource::Status);
+
+ void setResourceError(const ResourceError& error) { m_error = error; }
+ const ResourceError& resourceError() const { return m_error; }
+
+ void setIdentifier(unsigned long identifier) { m_identifier = identifier; }
+ unsigned long identifier() const { return m_identifier; }
+
+ virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
+
+ ResourceRequest& resourceRequest() { return m_resourceRequest; }
+ const KURL& url() const { return m_resourceRequest.url();}
+ Type type() const { return static_cast<Type>(m_type); }
+ const ResourceLoaderOptions& options() const { return m_options; }
+
+ void didChangePriority(ResourceLoadPriority);
+
+ void addClient(ResourceClient*);
+ void removeClient(ResourceClient*);
+ bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); }
+ bool deleteIfPossible();
+
+ enum PreloadResult {
+ PreloadNotReferenced,
+ PreloadReferenced,
+ PreloadReferencedWhileLoading,
+ PreloadReferencedWhileComplete
+ };
+ PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
+
+ virtual void didAddClient(ResourceClient*);
+ virtual void didRemoveClient(ResourceClient*) { }
+ virtual void allClientsRemoved();
+
+ unsigned count() const { return m_clients.size(); }
+
+ Status status() const { return static_cast<Status>(m_status); }
+ void setStatus(Status status) { m_status = status; }
+
+ unsigned size() const { return encodedSize() + decodedSize() + overheadSize(); }
+ unsigned encodedSize() const { return m_encodedSize; }
+ unsigned decodedSize() const { return m_decodedSize; }
+ unsigned overheadSize() const;
+
+ bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
+
+ bool isLoading() const { return m_loading; }
+ void setLoading(bool b) { m_loading = b; }
+ virtual bool stillNeedsLoad() const { return false; }
+
+ ResourceLoader* loader() { return m_loader.get(); }
+
+ virtual bool isImage() const { return false; }
+ bool ignoreForRequestCount() const
+ {
+ return type() == MainResource
+ || type() == LinkPrefetch
+ || type() == LinkSubresource
+ || type() == Raw;
+ }
+
+ void updateForAccess();
+ unsigned accessCount() const { return m_accessCount; }
+
+ // Computes the status of an object after loading.
+ // Updates the expire date on the cache entry file
+ void finish(double finishTime = 0.0);
+
+ // FIXME: Remove the stringless variant once all the callsites' error messages are updated.
+ bool passesAccessControlCheck(SecurityOrigin*);
+ bool passesAccessControlCheck(SecurityOrigin*, String& errorDescription);
+
+ // Called by the cache if the object has been removed from the cache
+ // while still being referenced. This means the object should delete itself
+ // if the number of clients observing it ever drops to 0.
+ // The resource can be brought back to cache after successful revalidation.
+ void setInCache(bool inCache) { m_inCache = inCache; }
+ bool inCache() const { return m_inCache; }
+
+ void setCacheLiveResourcePriority(CacheLiveResourcePriority);
+ unsigned cacheLiveResourcePriority() const { return m_cacheLiveResourcePriority; }
+ bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; }
+
+ void clearLoader();
+
+ SharedBuffer* resourceBuffer() const { ASSERT(!m_purgeableData); return m_data.get(); }
+
+ virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) { m_requestedFromNetworkingLayer = true; }
+ virtual void responseReceived(const ResourceResponse&);
+ void setResponse(const ResourceResponse& response) { m_response = response; }
+ const ResourceResponse& response() const { return m_response; }
+
+ // Sets the serialized metadata retrieved from the platform's cache.
+ void setSerializedCachedMetadata(const char*, size_t);
+
+ // Caches the given metadata in association with this resource and suggests
+ // that the platform persist it. The dataTypeID is a pseudo-randomly chosen
+ // identifier that is used to distinguish data generated by the caller.
+ void setCachedMetadata(unsigned dataTypeID, const char*, size_t);
+
+ // Returns cached metadata of the given type associated with this resource.
+ CachedMetadata* cachedMetadata(unsigned dataTypeID) const;
+
+ bool canDelete() const { return !hasClients() && !m_loader && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; }
+ bool hasOneHandle() const { return m_handleCount == 1; }
+
+ bool isExpired() const;
+
+ // List of acceptable MIME types separated by ",".
+ // A MIME type may contain a wildcard, e.g. "text/*".
+ AtomicString accept() const { return m_accept; }
+ void setAccept(const AtomicString& accept) { m_accept = accept; }
+
+ bool wasCanceled() const { return m_error.isCancellation(); }
+ bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; }
+ bool loadFailedOrCanceled() { return !m_error.isNull(); }
+
+ bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
+ DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; }
+
+ virtual void destroyDecodedData() { }
+
+ bool isPreloaded() const { return m_preloadCount; }
+ void increasePreloadCount() { ++m_preloadCount; }
+ void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
+
+ void registerHandle(ResourcePtrBase* h);
+ void unregisterHandle(ResourcePtrBase* h);
+
+ bool canUseCacheValidator() const;
+ bool mustRevalidateDueToCacheHeaders(CachePolicy) const;
+ bool isCacheValidator() const { return m_resourceToRevalidate; }
+ Resource* resourceToRevalidate() const { return m_resourceToRevalidate; }
+ void setResourceToRevalidate(Resource*);
+
+ bool isPurgeable() const;
+ bool wasPurged() const;
+
+ // This is used by the archive machinery to get at a purged resource without
+ // triggering a load. We should make it protected again if we can find a
+ // better way to handle the archive case.
+ bool makePurgeable(bool purgeable);
+
+ virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
+ virtual void didDownloadData(int) { }
+
+ double loadFinishTime() const { return m_loadFinishTime; }
+
+ virtual bool canReuse(const ResourceRequest&) const { return true; }
+
+protected:
+ virtual void checkNotify();
+ virtual void finishOnePart();
+
+ void setEncodedSize(unsigned);
+ void setDecodedSize(unsigned);
+ void didAccessDecodedData(double timeStamp);
+
+ bool isSafeToMakePurgeable() const;
+
+ virtual void switchClientsToRevalidatedResource();
+ void clearResourceToRevalidate();
+ void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
+
+ HashCountedSet<ResourceClient*> m_clients;
+
+ class ResourceCallback {
+ public:
+ static PassOwnPtr<ResourceCallback> schedule(Resource* resource, ResourceClient* client) { return adoptPtr(new ResourceCallback(resource, client)); }
+ void cancel();
+ private:
+ ResourceCallback(Resource*, ResourceClient*);
+ void timerFired(Timer<ResourceCallback>*);
+
+ Resource* m_resource;
+ ResourceClient* m_client;
+ Timer<ResourceCallback> m_callbackTimer;
+ };
+ HashMap<ResourceClient*, OwnPtr<ResourceCallback> > m_clientsAwaitingCallback;
+
+ bool hasClient(ResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); }
+
+ ResourceRequest m_resourceRequest;
+ AtomicString m_accept;
+ RefPtr<ResourceLoader> m_loader;
+ ResourceLoaderOptions m_options;
+
+ ResourceResponse m_response;
+ double m_responseTimestamp;
+
+ RefPtr<SharedBuffer> m_data;
+ OwnPtr<PurgeableBuffer> m_purgeableData;
+ Timer<Resource> m_cancelTimer;
+
+private:
+ bool addClientToSet(ResourceClient*);
+ void cancelTimerFired(Timer<Resource>*);
+
+ void revalidationSucceeded(const ResourceResponse&);
+ void revalidationFailed();
+
+ double currentAge() const;
+ double freshnessLifetime() const;
+
+ void failBeforeStarting();
+
+ String m_fragmentIdentifierForRequest;
+
+ RefPtr<CachedMetadata> m_cachedMetadata;
+
+ ResourceError m_error;
+
+ double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
+ double m_loadFinishTime;
+
+ unsigned long m_identifier;
+
+ unsigned m_encodedSize;
+ unsigned m_decodedSize;
+ unsigned m_accessCount;
+ unsigned m_handleCount;
+ unsigned m_preloadCount;
+
+ unsigned m_preloadResult : 2; // PreloadResult
+ unsigned m_cacheLiveResourcePriority : 2; // CacheLiveResourcePriority
+ unsigned m_inLiveDecodedResourcesList : 1;
+ unsigned m_requestedFromNetworkingLayer : 1;
+
+ unsigned m_inCache : 1;
+ unsigned m_loading : 1;
+
+ unsigned m_switchingClientsToRevalidatedResource : 1;
+
+ unsigned m_type : 4; // Type
+ unsigned m_status : 3; // Status
+
+#ifndef NDEBUG
+ bool m_deleted;
+ unsigned m_lruIndex;
+#endif
+
+ Resource* m_nextInAllResourcesList;
+ Resource* m_prevInAllResourcesList;
+
+ Resource* m_nextInLiveResourcesList;
+ Resource* m_prevInLiveResourcesList;
+
+ // If this field is non-null we are using the resource as a proxy for checking whether an existing resource is still up to date
+ // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
+ // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
+ // resources becomes normal resource load.
+ Resource* m_resourceToRevalidate;
+
+ // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
+ Resource* m_proxyResource;
+
+ // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
+ HashSet<ResourcePtrBase*> m_handlesToRevalidate;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClient.h b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClient.h
new file mode 100644
index 00000000000..ae7b7bbcf0c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClient.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef ResourceClient_h
+#define ResourceClient_h
+
+#include "wtf/FastAllocBase.h"
+#include "wtf/Forward.h"
+
+namespace WebCore {
+class Resource;
+
+class ResourceClient {
+public:
+ enum ResourceClientType {
+ BaseResourceType,
+ ImageType,
+ FontType,
+ StyleSheetType,
+ DocumentType,
+ RawResourceType
+ };
+
+ virtual ~ResourceClient() { }
+ virtual void notifyFinished(Resource*) { }
+ virtual void deprecatedDidReceiveResource(Resource*) { }
+
+ static ResourceClientType expectedType() { return BaseResourceType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+
+protected:
+ ResourceClient() { }
+};
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClientWalker.h b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClientWalker.h
new file mode 100644
index 00000000000..aff5f1dcd0b
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceClientWalker.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2005, 2006, 2007 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef ResourceClientWalker_h
+#define ResourceClientWalker_h
+
+#include "core/loader/cache/ResourceClient.h"
+#include "wtf/HashCountedSet.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+// Call this "walker" instead of iterator so people won't expect Qt or STL-style iterator interface.
+// Just keep calling next() on this. It's safe from deletions of items.
+template<typename T> class ResourceClientWalker {
+public:
+ ResourceClientWalker(const HashCountedSet<ResourceClient*>& set)
+ : m_clientSet(set), m_clientVector(set.size()), m_index(0)
+ {
+ typedef HashCountedSet<ResourceClient*>::const_iterator Iterator;
+ Iterator end = set.end();
+ size_t clientIndex = 0;
+ for (Iterator current = set.begin(); current != end; ++current)
+ m_clientVector[clientIndex++] = current->key;
+ }
+
+ T* next()
+ {
+ size_t size = m_clientVector.size();
+ while (m_index < size) {
+ ResourceClient* next = m_clientVector[m_index++];
+ if (m_clientSet.contains(next)) {
+ ASSERT(T::expectedType() == ResourceClient::expectedType() || next->resourceClientType() == T::expectedType());
+ return static_cast<T*>(next);
+ }
+ }
+
+ return 0;
+ }
+private:
+ const HashCountedSet<ResourceClient*>& m_clientSet;
+ Vector<ResourceClient*> m_clientVector;
+ size_t m_index;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.cpp
new file mode 100644
index 00000000000..28d7c8ced74
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.cpp
@@ -0,0 +1,1301 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "core/loader/cache/ResourceFetcher.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/Document.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/html/HTMLImport.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/PingLoader.h"
+#include "core/loader/UniqueIdentifier.h"
+#include "core/loader/appcache/ApplicationCacheHost.h"
+#include "core/loader/cache/CSSStyleSheetResource.h"
+#include "core/loader/cache/DocumentResource.h"
+#include "core/loader/cache/FetchRequest.h"
+#include "core/loader/cache/FontResource.h"
+#include "core/loader/cache/ImageResource.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/loader/cache/RawResource.h"
+#include "core/loader/cache/ScriptResource.h"
+#include "core/loader/cache/ShaderResource.h"
+#include "core/loader/cache/TextTrackResource.h"
+#include "core/loader/cache/XSLStyleSheetResource.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/Performance.h"
+#include "core/page/ResourceTimingInfo.h"
+#include "core/page/Settings.h"
+#include "core/platform/Logging.h"
+#include "core/platform/chromium/TraceEvent.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebURL.h"
+#include "weborigin/SecurityOrigin.h"
+#include "weborigin/SecurityPolicy.h"
+#include "wtf/text/CString.h"
+#include "wtf/text/WTFString.h"
+
+#define PRELOAD_DEBUG 0
+
+namespace WebCore {
+
+static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
+{
+ switch (type) {
+ case Resource::Image:
+ return new ImageResource(request);
+ case Resource::CSSStyleSheet:
+ return new CSSStyleSheetResource(request, charset);
+ case Resource::Script:
+ return new ScriptResource(request, charset);
+ case Resource::SVGDocument:
+ return new DocumentResource(request, Resource::SVGDocument);
+ case Resource::Font:
+ return new FontResource(request);
+ case Resource::Raw:
+ case Resource::MainResource:
+ return new RawResource(request, type);
+ case Resource::XSLStyleSheet:
+ return new XSLStyleSheetResource(request);
+ case Resource::LinkPrefetch:
+ return new Resource(request, Resource::LinkPrefetch);
+ case Resource::LinkSubresource:
+ return new Resource(request, Resource::LinkSubresource);
+ case Resource::TextTrack:
+ return new TextTrackResource(request);
+ case Resource::Shader:
+ return new ShaderResource(request);
+ case Resource::ImportResource:
+ return new RawResource(request, type);
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
+{
+ if (request.priority() != ResourceLoadPriorityUnresolved)
+ return request.priority();
+
+ switch (type) {
+ case Resource::MainResource:
+ return ResourceLoadPriorityVeryHigh;
+ case Resource::CSSStyleSheet:
+ return ResourceLoadPriorityHigh;
+ case Resource::Script:
+ case Resource::Font:
+ case Resource::Raw:
+ case Resource::ImportResource:
+ return ResourceLoadPriorityMedium;
+ case Resource::Image:
+ return request.forPreload() ? ResourceLoadPriorityVeryLow : ResourceLoadPriorityLow;
+ case Resource::XSLStyleSheet:
+ return ResourceLoadPriorityHigh;
+ case Resource::SVGDocument:
+ return ResourceLoadPriorityLow;
+ case Resource::LinkPrefetch:
+ return ResourceLoadPriorityVeryLow;
+ case Resource::LinkSubresource:
+ return ResourceLoadPriorityLow;
+ case Resource::TextTrack:
+ return ResourceLoadPriorityLow;
+ case Resource::Shader:
+ return ResourceLoadPriorityMedium;
+ }
+ ASSERT_NOT_REACHED();
+ return ResourceLoadPriorityUnresolved;
+}
+
+static Resource* resourceFromDataURIRequest(const ResourceRequest& request)
+{
+ const KURL& url = request.url();
+ ASSERT(url.protocolIsData());
+
+ WebKit::WebString mimetype;
+ WebKit::WebString charset;
+ RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(WebKit::Platform::current()->parseDataURL(url, mimetype, charset));
+ if (!data)
+ return 0;
+ ResourceResponse response(url, mimetype, data->size(), charset, String());
+
+ Resource* resource = createResource(Resource::Image, request, charset);
+ resource->responseReceived(response);
+ // FIXME: AppendData causes an unnecessary memcpy.
+ if (data->size())
+ resource->appendData(data->data(), data->size());
+ resource->finish();
+ return resource;
+}
+
+ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
+ : m_document(0)
+ , m_documentLoader(documentLoader)
+ , m_requestCount(0)
+ , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
+ , m_autoLoadImages(true)
+ , m_imagesEnabled(true)
+ , m_allowStaleResources(false)
+{
+}
+
+ResourceFetcher::~ResourceFetcher()
+{
+ m_documentLoader = 0;
+ m_document = 0;
+
+ clearPreloads();
+
+ // Make sure no requests still point to this ResourceFetcher
+ ASSERT(!m_requestCount);
+}
+
+Resource* ResourceFetcher::cachedResource(const String& resourceURL) const
+{
+ KURL url = m_document->completeURL(resourceURL);
+ return cachedResource(url);
+}
+
+Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
+{
+ KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
+ return m_documentResources.get(url).get();
+}
+
+Frame* ResourceFetcher::frame() const
+{
+ if (m_documentLoader)
+ return m_documentLoader->frame();
+ if (m_document && m_document->import())
+ return m_document->import()->frame();
+ return 0;
+}
+
+ResourcePtr<ImageResource> ResourceFetcher::requestImage(FetchRequest& request)
+{
+ if (Frame* f = frame()) {
+ if (f->loader()->pageDismissalEventBeingDispatched() != FrameLoader::NoDismissal) {
+ KURL requestURL = request.resourceRequest().url();
+ if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload()))
+ PingLoader::loadImage(f, requestURL);
+ return 0;
+ }
+ }
+
+ if (request.resourceRequest().url().protocolIsData())
+ preCacheDataURIImage(request);
+
+ request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
+ return static_cast<ImageResource*>(requestResource(Resource::Image, request).get());
+}
+
+void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
+{
+ const KURL& url = request.resourceRequest().url();
+ ASSERT(url.protocolIsData());
+
+ if (Resource* existing = memoryCache()->resourceForURL(url))
+ return;
+
+ if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest()))
+ memoryCache()->add(resource);
+}
+
+ResourcePtr<FontResource> ResourceFetcher::requestFont(FetchRequest& request)
+{
+ return static_cast<FontResource*>(requestResource(Resource::Font, request).get());
+}
+
+ResourcePtr<TextTrackResource> ResourceFetcher::requestTextTrack(FetchRequest& request)
+{
+ return static_cast<TextTrackResource*>(requestResource(Resource::TextTrack, request).get());
+}
+
+ResourcePtr<ShaderResource> ResourceFetcher::requestShader(FetchRequest& request)
+{
+ return static_cast<ShaderResource*>(requestResource(Resource::Shader, request).get());
+}
+
+ResourcePtr<RawResource> ResourceFetcher::requestImport(FetchRequest& request)
+{
+ return static_cast<RawResource*>(requestResource(Resource::ImportResource, request).get());
+}
+
+ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestCSSStyleSheet(FetchRequest& request)
+{
+ return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
+}
+
+ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestUserCSSStyleSheet(FetchRequest& request)
+{
+ KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
+
+ if (Resource* existing = memoryCache()->resourceForURL(url)) {
+ if (existing->type() == Resource::CSSStyleSheet)
+ return static_cast<CSSStyleSheetResource*>(existing);
+ memoryCache()->remove(existing);
+ }
+
+ request.setOptions(ResourceLoaderOptions(DoNotSendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
+ return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
+}
+
+ResourcePtr<ScriptResource> ResourceFetcher::requestScript(FetchRequest& request)
+{
+ return static_cast<ScriptResource*>(requestResource(Resource::Script, request).get());
+}
+
+ResourcePtr<XSLStyleSheetResource> ResourceFetcher::requestXSLStyleSheet(FetchRequest& request)
+{
+ return static_cast<XSLStyleSheetResource*>(requestResource(Resource::XSLStyleSheet, request).get());
+}
+
+ResourcePtr<DocumentResource> ResourceFetcher::requestSVGDocument(FetchRequest& request)
+{
+ return static_cast<DocumentResource*>(requestResource(Resource::SVGDocument, request).get());
+}
+
+ResourcePtr<Resource> ResourceFetcher::requestLinkResource(Resource::Type type, FetchRequest& request)
+{
+ ASSERT(frame());
+ ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
+ return requestResource(type, request);
+}
+
+ResourcePtr<RawResource> ResourceFetcher::requestRawResource(FetchRequest& request)
+{
+ return static_cast<RawResource*>(requestResource(Resource::Raw, request).get());
+}
+
+ResourcePtr<RawResource> ResourceFetcher::requestMainResource(FetchRequest& request)
+{
+ return static_cast<RawResource*>(requestResource(Resource::MainResource, request).get());
+}
+
+bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url) const
+{
+ switch (type) {
+ case Resource::Script:
+ case Resource::XSLStyleSheet:
+ case Resource::SVGDocument:
+ case Resource::CSSStyleSheet:
+ case Resource::ImportResource:
+ // These resource can inject script into the current document (Script,
+ // XSL) or exfiltrate the content of the current document (CSS).
+ if (Frame* f = frame()) {
+ if (!f->loader()->mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
+ return false;
+ }
+
+ break;
+ case Resource::TextTrack:
+ case Resource::Shader:
+ case Resource::Raw:
+ case Resource::Image:
+ case Resource::Font: {
+ // These resources can corrupt only the frame's pixels.
+ if (Frame* f = frame()) {
+ Frame* top = f->tree()->top();
+ if (!top->loader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
+ return false;
+ }
+ break;
+ }
+ case Resource::MainResource:
+ case Resource::LinkPrefetch:
+ case Resource::LinkSubresource:
+ // Prefetch cannot affect the current document.
+ break;
+ }
+ return true;
+}
+
+bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload)
+{
+ if (document() && !document()->securityOrigin()->canDisplay(url)) {
+ if (!forPreload)
+ FrameLoader::reportLocalLoadFailed(frame(), url.elidedString());
+ LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
+ return 0;
+ }
+
+ // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
+ bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script()->shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
+
+ // Some types of resources can be loaded only from the same origin. Other
+ // types of resources, like Images, Scripts, and CSS, can be loaded from
+ // any URL.
+ switch (type) {
+ case Resource::MainResource:
+ case Resource::Image:
+ case Resource::CSSStyleSheet:
+ case Resource::Script:
+ case Resource::Font:
+ case Resource::Raw:
+ case Resource::LinkPrefetch:
+ case Resource::LinkSubresource:
+ case Resource::TextTrack:
+ case Resource::Shader:
+ case Resource::ImportResource:
+ // By default these types of resources can be loaded from any origin.
+ // FIXME: Are we sure about Resource::Font?
+ if (options.requestOriginPolicy == RestrictToSameOrigin && !m_document->securityOrigin()->canRequest(url)) {
+ printAccessDeniedMessage(url);
+ return false;
+ }
+ break;
+ case Resource::SVGDocument:
+ case Resource::XSLStyleSheet:
+ if (!m_document->securityOrigin()->canRequest(url)) {
+ printAccessDeniedMessage(url);
+ return false;
+ }
+ break;
+ }
+
+ switch (type) {
+ case Resource::XSLStyleSheet:
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
+ return false;
+ break;
+ case Resource::Script:
+ case Resource::ImportResource:
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
+ return false;
+
+ if (frame()) {
+ Settings* settings = frame()->settings();
+ if (!frame()->loader()->client()->allowScriptFromSource(!settings || settings->isScriptEnabled(), url)) {
+ frame()->loader()->client()->didNotAllowScript();
+ return false;
+ }
+ }
+ break;
+ case Resource::Shader:
+ // Since shaders are referenced from CSS Styles use the same rules here.
+ case Resource::CSSStyleSheet:
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
+ return false;
+ break;
+ case Resource::SVGDocument:
+ case Resource::Image:
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
+ return false;
+ break;
+ case Resource::Font: {
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
+ return false;
+ break;
+ }
+ case Resource::MainResource:
+ case Resource::Raw:
+ case Resource::LinkPrefetch:
+ case Resource::LinkSubresource:
+ break;
+ case Resource::TextTrack:
+ // Cues aren't called out in the CPS spec yet, but they only work with a media element
+ // so use the media policy.
+ if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
+ return false;
+ break;
+ }
+
+ // Last of all, check for insecure content. We do this last so that when
+ // folks block insecure content with a CSP policy, they don't get a warning.
+ // They'll still get a warning in the console about CSP blocking the load.
+
+ // FIXME: Should we consider forPreload here?
+ if (!checkInsecureContent(type, url))
+ return false;
+
+ return true;
+}
+
+bool ResourceFetcher::canAccess(Resource* resource)
+{
+ // Redirects can change the response URL different from one of request.
+ if (!canRequest(resource->type(), resource->response().url(), resource->options(), false))
+ return false;
+
+ String error;
+ switch (resource->type()) {
+ case Resource::Script:
+ case Resource::ImportResource:
+ if (resource->options().requestOriginPolicy == PotentiallyCrossOriginEnabled
+ && !m_document->securityOrigin()->canRequest(resource->response().url())
+ && !resource->passesAccessControlCheck(m_document->securityOrigin(), error)) {
+ if (frame() && frame()->document())
+ frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Script from origin '" + SecurityOrigin::create(resource->response().url())->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + error);
+ return false;
+ }
+
+ break;
+ default:
+ ASSERT_NOT_REACHED(); // FIXME: generalize to non-script resources
+ return false;
+ }
+
+ return true;
+}
+
+bool ResourceFetcher::shouldLoadNewResource() const
+{
+ if (!frame())
+ return false;
+ if (m_documentLoader) {
+ if (m_documentLoader != frame()->loader()->activeDocumentLoader())
+ return false;
+ if (m_documentLoader->isStopping())
+ return false;
+ }
+
+ return true;
+}
+
+ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
+{
+ KURL url = request.resourceRequest().url();
+
+ LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload());
+
+ // If only the fragment identifiers differ, it is the same resource.
+ url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
+
+ if (!url.isValid())
+ return 0;
+
+ if (!canRequest(type, url, request.options(), request.forPreload()))
+ return 0;
+
+ if (Frame* f = frame())
+ f->loader()->client()->dispatchWillRequestResource(&request);
+
+ // See if we can use an existing resource from the cache.
+ ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
+
+ const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer());
+ switch (policy) {
+ case Reload:
+ memoryCache()->remove(resource.get());
+ // Fall through
+ case Load:
+ resource = loadResource(type, request, request.charset());
+ break;
+ case Revalidate:
+ resource = revalidateResource(request, resource.get());
+ break;
+ case Use:
+ resource->updateForAccess();
+ notifyLoadedFromMemoryCache(resource.get());
+ break;
+ }
+
+ if (!resource)
+ return 0;
+
+ if (policy != Use)
+ resource->setIdentifier(createUniqueIdentifier());
+
+ if (!request.forPreload() || policy != Use) {
+ ResourceLoadPriority priority = loadPriority(type, request);
+ if (priority != resource->resourceRequest().priority()) {
+ resource->resourceRequest().setPriority(priority);
+ resource->didChangePriority(priority);
+ }
+ }
+
+ if ((policy != Use || resource->stillNeedsLoad()) && FetchRequest::NoDefer == request.defer()) {
+ if (!shouldLoadNewResource()) {
+ if (resource->inCache())
+ memoryCache()->remove(resource.get());
+ return 0;
+ }
+
+ if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
+ resource->load(this, request.options());
+
+ // We don't support immediate loads, but we do support immediate failure.
+ if (resource->errorOccurred()) {
+ if (resource->inCache())
+ memoryCache()->remove(resource.get());
+ return 0;
+ }
+ }
+
+ // FIXME: Temporarily leave main resource caching disabled for chromium,
+ // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
+ // resources, we should be sure to understand the implications for memory
+ // use.
+ //
+ // Ensure main resources aren't preloaded, and other main resource loads
+ // are removed from cache to prevent reuse.
+ if (type == Resource::MainResource) {
+ ASSERT(policy != Use);
+ ASSERT(policy != Revalidate);
+ memoryCache()->remove(resource.get());
+ if (request.forPreload())
+ return 0;
+ }
+
+ if (!request.resourceRequest().url().protocolIsData())
+ m_validatedURLs.add(request.resourceRequest().url());
+
+ ASSERT(resource->url() == url.string());
+ m_documentResources.set(resource->url(), resource);
+ return resource;
+}
+
+void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
+{
+ ResourceRequest::TargetType targetType;
+
+ switch (type) {
+ case Resource::MainResource:
+ if (frame()->tree()->parent())
+ targetType = ResourceRequest::TargetIsSubframe;
+ else
+ targetType = ResourceRequest::TargetIsMainFrame;
+ break;
+ case Resource::CSSStyleSheet:
+ case Resource::XSLStyleSheet:
+ targetType = ResourceRequest::TargetIsStyleSheet;
+ break;
+ case Resource::Script:
+ targetType = ResourceRequest::TargetIsScript;
+ break;
+ case Resource::Font:
+ targetType = ResourceRequest::TargetIsFont;
+ break;
+ case Resource::Image:
+ targetType = ResourceRequest::TargetIsImage;
+ break;
+ case Resource::Shader:
+ case Resource::Raw:
+ case Resource::ImportResource:
+ targetType = ResourceRequest::TargetIsSubresource;
+ break;
+ case Resource::LinkPrefetch:
+ targetType = ResourceRequest::TargetIsPrefetch;
+ break;
+ case Resource::LinkSubresource:
+ targetType = ResourceRequest::TargetIsSubresource;
+ break;
+ case Resource::TextTrack:
+ targetType = ResourceRequest::TargetIsTextTrack;
+ break;
+ case Resource::SVGDocument:
+ targetType = ResourceRequest::TargetIsImage;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ targetType = ResourceRequest::TargetIsSubresource;
+ break;
+ }
+ request.setTargetType(targetType);
+}
+
+ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
+{
+ if (type == Resource::MainResource) {
+ FrameLoadType frameLoadType = frame()->loader()->loadType();
+ bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
+ if (request.httpMethod() == "POST" && (isReload || frameLoadType == FrameLoadTypeBackForward))
+ return ReturnCacheDataDontLoad;
+ if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
+ return ReturnCacheDataElseLoad;
+ if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional())
+ return ReloadIgnoringCacheData;
+ return UseProtocolCachePolicy;
+ }
+
+ if (request.isConditional())
+ return ReloadIgnoringCacheData;
+
+ if (m_documentLoader && m_documentLoader->isLoadingInAPISense()) {
+ // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
+ // This policy should not be inherited by subresources.
+ ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
+ if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
+ return ReturnCacheDataElseLoad;
+ return mainResourceCachePolicy;
+ }
+ return UseProtocolCachePolicy;
+}
+
+void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
+{
+ if (!frame())
+ return;
+
+ bool isMainResource = type == Resource::MainResource;
+
+ FrameLoader* frameLoader = frame()->loader();
+
+ if (!isMainResource) {
+ String outgoingReferrer;
+ String outgoingOrigin;
+ if (request.httpReferrer().isNull()) {
+ outgoingReferrer = frameLoader->outgoingReferrer();
+ outgoingOrigin = frameLoader->outgoingOrigin();
+ } else {
+ outgoingReferrer = request.httpReferrer();
+ outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
+ }
+
+ outgoingReferrer = SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), request.url(), outgoingReferrer);
+ if (outgoingReferrer.isEmpty())
+ request.clearHTTPReferrer();
+ else if (!request.httpReferrer())
+ request.setHTTPReferrer(outgoingReferrer);
+
+ FrameLoader::addHTTPOriginIfNeeded(request, outgoingOrigin);
+ }
+
+ if (request.cachePolicy() == UseProtocolCachePolicy)
+ request.setCachePolicy(resourceRequestCachePolicy(request, type));
+ if (request.targetType() == ResourceRequest::TargetIsUnspecified)
+ determineTargetType(request, type);
+ if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
+ request.setHTTPHeaderField("Purpose", "prefetch");
+ frameLoader->addExtraFieldsToRequest(request);
+}
+
+ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
+{
+ ASSERT(resource);
+ ASSERT(resource->inCache());
+ ASSERT(resource->isLoaded());
+ ASSERT(resource->canUseCacheValidator());
+ ASSERT(!resource->resourceToRevalidate());
+
+ ResourceRequest revalidatingRequest(resource->resourceRequest());
+ addAdditionalRequestHeaders(revalidatingRequest, resource->type());
+
+ const String& lastModified = resource->response().httpHeaderField("Last-Modified");
+ const String& eTag = resource->response().httpHeaderField("ETag");
+ if (!lastModified.isEmpty() || !eTag.isEmpty()) {
+ ASSERT(cachePolicy(resource->type()) != CachePolicyReload);
+ if (cachePolicy(resource->type()) == CachePolicyRevalidate)
+ revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
+ if (!lastModified.isEmpty())
+ revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
+ if (!eTag.isEmpty())
+ revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
+ }
+
+ ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
+
+ LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
+ newResource->setResourceToRevalidate(resource);
+
+ memoryCache()->remove(resource);
+ memoryCache()->add(newResource.get());
+ storeResourceTimingInitiatorInformation(newResource, request);
+ TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
+ return newResource;
+}
+
+ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
+{
+ ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
+
+ LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
+
+ addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
+ ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
+
+ memoryCache()->add(resource.get());
+ storeResourceTimingInitiatorInformation(resource, request);
+ TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
+ return resource;
+}
+
+void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
+{
+ if (request.options().requestInitiatorContext != DocumentContext)
+ return;
+
+ RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
+
+ if (resource->type() == Resource::MainResource) {
+ // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
+ if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
+ info->setInitiatorType(frame()->ownerElement()->localName());
+ m_resourceTimingInfoMap.add(resource.get(), info);
+ frame()->ownerElement()->didLoadNonEmptyDocument();
+ }
+ } else {
+ m_resourceTimingInfoMap.add(resource.get(), info);
+ }
+}
+
+ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer) const
+{
+ if (!existingResource)
+ return Load;
+
+ // We already have a preload going for this URL.
+ if (forPreload && existingResource->isPreloaded())
+ return Use;
+
+ // If the same URL has been loaded as a different type, we need to reload.
+ if (existingResource->type() != type) {
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
+ return Reload;
+ }
+
+ // Do not load from cache if images are not enabled. The load for this image will be blocked
+ // in ImageResource::load.
+ if (FetchRequest::DeferredByClient == defer)
+ return Reload;
+
+ // Always use data uris.
+ // FIXME: Extend this to non-images.
+ if (type == Resource::Image && request.url().protocolIsData())
+ return Use;
+
+ if (!existingResource->canReuse(request))
+ return Reload;
+
+ // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
+ // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
+ // of things about how revalidation works that manual headers violate, so punt to Reload instead.
+ if (request.isConditional())
+ return Reload;
+
+ // Don't reload resources while pasting.
+ if (m_allowStaleResources)
+ return Use;
+
+ // Alwaus use preloads.
+ if (existingResource->isPreloaded())
+ return Use;
+
+ // CachePolicyHistoryBuffer uses the cache no matter what.
+ if (cachePolicy(type) == CachePolicyHistoryBuffer)
+ return Use;
+
+ // Don't reuse resources with Cache-control: no-store.
+ if (existingResource->response().cacheControlContainsNoStore()) {
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
+ return Reload;
+ }
+
+ // If credentials were sent with the previous request and won't be
+ // with this one, or vice versa, re-fetch the resource.
+ //
+ // This helps with the case where the server sends back
+ // "Access-Control-Allow-Origin: *" all the time, but some of the
+ // client's requests are made without CORS and some with.
+ if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) {
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
+ return Reload;
+ }
+
+ // During the initial load, avoid loading the same resource multiple times for a single document, even if the cache policies would tell us to.
+ if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
+ return Use;
+
+ // CachePolicyReload always reloads
+ if (cachePolicy(type) == CachePolicyReload) {
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
+ return Reload;
+ }
+
+ // We'll try to reload the resource if it failed last time.
+ if (existingResource->errorOccurred()) {
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
+ return Reload;
+ }
+
+ // For resources that are not yet loaded we ignore the cache policy.
+ if (existingResource->isLoading())
+ return Use;
+
+ // Check if the cache headers requires us to revalidate (cache expiration for example).
+ if (existingResource->mustRevalidateDueToCacheHeaders(cachePolicy(type))) {
+ // See if the resource has usable ETag or Last-modified headers.
+ if (existingResource->canUseCacheValidator())
+ return Revalidate;
+
+ // No, must reload.
+ LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
+ return Reload;
+ }
+
+ return Use;
+}
+
+void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
+{
+ if (url.isNull())
+ return;
+
+ if (!frame())
+ return;
+
+ String message;
+ if (!m_document || m_document->url().isNull())
+ message = "Unsafe attempt to load URL " + url.elidedString() + '.';
+ else
+ message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
+
+ frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
+}
+
+void ResourceFetcher::setAutoLoadImages(bool enable)
+{
+ if (enable == m_autoLoadImages)
+ return;
+
+ m_autoLoadImages = enable;
+
+ if (!m_autoLoadImages)
+ return;
+
+ reloadImagesIfNotDeferred();
+}
+
+void ResourceFetcher::setImagesEnabled(bool enable)
+{
+ if (enable == m_imagesEnabled)
+ return;
+
+ m_imagesEnabled = enable;
+
+ if (!m_imagesEnabled)
+ return;
+
+ reloadImagesIfNotDeferred();
+}
+
+bool ResourceFetcher::clientDefersImage(const KURL& url) const
+{
+ return frame() && !frame()->loader()->client()->allowImage(m_imagesEnabled, url);
+}
+
+bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
+{
+ return clientDefersImage(url) || !m_autoLoadImages;
+}
+
+void ResourceFetcher::reloadImagesIfNotDeferred()
+{
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
+ Resource* resource = it->value.get();
+ if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
+ const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
+ }
+}
+
+CachePolicy ResourceFetcher::cachePolicy(Resource::Type type) const
+{
+ if (!frame())
+ return CachePolicyVerify;
+
+ if (type != Resource::MainResource)
+ return frame()->loader()->subresourceCachePolicy();
+
+ if (frame()->loader()->loadType() == FrameLoadTypeReloadFromOrigin || frame()->loader()->loadType() == FrameLoadTypeReload)
+ return CachePolicyReload;
+ return CachePolicyVerify;
+}
+
+void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
+{
+ ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
+ if (it != m_resourceTimingInfoMap.end())
+ it->value->addRedirect(redirectResponse);
+}
+
+void ResourceFetcher::didLoadResource(Resource* resource)
+{
+ RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
+ RefPtr<Document> protectDocument(m_document);
+
+ if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
+ ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
+ if (it != m_resourceTimingInfoMap.end()) {
+ Document* initiatorDocument = document();
+ if (resource->type() == Resource::MainResource)
+ initiatorDocument = document()->parentDocument();
+ ASSERT(initiatorDocument);
+ RefPtr<ResourceTimingInfo> info = it->value;
+ info->setInitialRequest(resource->resourceRequest());
+ info->setFinalResponse(resource->response());
+ info->setLoadFinishTime(resource->loadFinishTime());
+ if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
+ initiatorWindow->performance()->addResourceTiming(*info, initiatorDocument);
+ m_resourceTimingInfoMap.remove(it);
+ }
+ }
+
+ if (frame())
+ frame()->loader()->loadDone();
+ performPostLoadActions();
+
+ if (!m_garbageCollectDocumentResourcesTimer.isActive())
+ m_garbageCollectDocumentResourcesTimer.startOneShot(0);
+}
+
+// Garbage collecting m_documentResources is a workaround for the
+// ResourcePtrs on the RHS being strong references. Ideally this
+// would be a weak map, however ResourcePtrs perform additional
+// bookkeeping on Resources, so instead pseudo-GC them -- when the
+// reference count reaches 1, m_documentResources is the only reference, so
+// remove it from the map.
+void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
+{
+ ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
+ garbageCollectDocumentResources();
+}
+
+void ResourceFetcher::garbageCollectDocumentResources()
+{
+ typedef Vector<String, 10> StringVector;
+ StringVector resourcesToDelete;
+
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
+ if (it->value->hasOneHandle())
+ resourcesToDelete.append(it->key);
+ }
+
+ for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
+ m_documentResources.remove(*it);
+}
+
+void ResourceFetcher::performPostLoadActions()
+{
+ checkForPendingPreloads();
+}
+
+void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
+{
+ if (!frame() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
+ return;
+
+ // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
+ frame()->loader()->loadedResourceFromMemoryCache(resource);
+}
+
+void ResourceFetcher::incrementRequestCount(const Resource* res)
+{
+ if (res->ignoreForRequestCount())
+ return;
+
+ ++m_requestCount;
+}
+
+void ResourceFetcher::decrementRequestCount(const Resource* res)
+{
+ if (res->ignoreForRequestCount())
+ return;
+
+ --m_requestCount;
+ ASSERT(m_requestCount > -1);
+}
+
+void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
+{
+ bool delaySubresourceLoad = true;
+ delaySubresourceLoad = false;
+ if (delaySubresourceLoad) {
+ bool hasRendering = m_document->body() && m_document->body()->renderer();
+ bool canBlockParser = type == Resource::Script || type == Resource::CSSStyleSheet;
+ if (!hasRendering && !canBlockParser) {
+ // Don't preload subresources that can't block the parser before we have something to draw.
+ // This helps prevent preloads from delaying first display when bandwidth is limited.
+ PendingPreload pendingPreload = { type, request, charset };
+ m_pendingPreloads.append(pendingPreload);
+ return;
+ }
+ }
+ requestPreload(type, request, charset);
+}
+
+void ResourceFetcher::checkForPendingPreloads()
+{
+ if (m_pendingPreloads.isEmpty() || !m_document->body() || !m_document->body()->renderer())
+ return;
+ while (!m_pendingPreloads.isEmpty()) {
+ PendingPreload preload = m_pendingPreloads.takeFirst();
+ // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
+ if (!cachedResource(preload.m_request.resourceRequest().url()))
+ requestPreload(preload.m_type, preload.m_request, preload.m_charset);
+ }
+ m_pendingPreloads.clear();
+}
+
+void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
+{
+ String encoding;
+ if (type == Resource::Script || type == Resource::CSSStyleSheet)
+ encoding = charset.isEmpty() ? m_document->charset() : charset;
+
+ request.setCharset(encoding);
+ request.setForPreload(true);
+
+ ResourcePtr<Resource> resource = requestResource(type, request);
+ if (!resource || (m_preloads && m_preloads->contains(resource.get())))
+ return;
+ TRACE_EVENT_ASYNC_STEP0("net", "Resource", resource.get(), "Preload");
+ resource->increasePreloadCount();
+
+ if (!m_preloads)
+ m_preloads = adoptPtr(new ListHashSet<Resource*>);
+ m_preloads->add(resource.get());
+
+#if PRELOAD_DEBUG
+ printf("PRELOADING %s\n", resource->url().latin1().data());
+#endif
+}
+
+bool ResourceFetcher::isPreloaded(const String& urlString) const
+{
+ const KURL& url = m_document->completeURL(urlString);
+
+ if (m_preloads) {
+ ListHashSet<Resource*>::iterator end = m_preloads->end();
+ for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
+ Resource* resource = *it;
+ if (resource->url() == url)
+ return true;
+ }
+ }
+
+ Deque<PendingPreload>::const_iterator dequeEnd = m_pendingPreloads.end();
+ for (Deque<PendingPreload>::const_iterator it = m_pendingPreloads.begin(); it != dequeEnd; ++it) {
+ PendingPreload pendingPreload = *it;
+ if (pendingPreload.m_request.resourceRequest().url() == url)
+ return true;
+ }
+ return false;
+}
+
+void ResourceFetcher::clearPreloads()
+{
+#if PRELOAD_DEBUG
+ printPreloadStats();
+#endif
+ if (!m_preloads)
+ return;
+
+ ListHashSet<Resource*>::iterator end = m_preloads->end();
+ for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
+ Resource* res = *it;
+ res->decreasePreloadCount();
+ bool deleted = res->deleteIfPossible();
+ if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
+ memoryCache()->remove(res);
+ }
+ m_preloads.clear();
+}
+
+void ResourceFetcher::clearPendingPreloads()
+{
+ m_pendingPreloads.clear();
+}
+
+inline FrameLoader* ResourceFetcher::frameLoader()
+{
+ if (Frame* frame = this->frame())
+ return frame->loader();
+ return 0;
+}
+
+void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, const ResourceLoaderOptions& options)
+{
+ TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
+ if (options.sendLoadCallbacks != SendCallbacks)
+ return;
+ if (FrameLoader* loader = frameLoader())
+ loader->notifier()->dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime);
+}
+
+void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority)
+{
+ TRACE_EVENT_ASYNC_STEP1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
+ if (FrameLoader* loader = frameLoader())
+ loader->client()->dispatchDidChangeResourcePriority(resource->identifier(), loadPriority);
+}
+
+void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error, const ResourceLoaderOptions& options)
+{
+ TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
+ if (options.sendLoadCallbacks != SendCallbacks)
+ return;
+ if (FrameLoader* loader = frameLoader())
+ loader->notifier()->dispatchDidFail(m_documentLoader, resource->identifier(), error);
+}
+
+void ResourceFetcher::willSendRequest(const Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, const ResourceLoaderOptions& options)
+{
+ if (options.sendLoadCallbacks == SendCallbacks) {
+ if (FrameLoader* loader = frameLoader())
+ loader->notifier()->dispatchWillSendRequest(m_documentLoader, resource->identifier(), request, redirectResponse, options.initiatorInfo);
+ } else {
+ InspectorInstrumentation::willSendRequest(frame(), resource->identifier(), m_documentLoader, request, redirectResponse, options.initiatorInfo);
+ }
+}
+
+void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response, const ResourceLoaderOptions& options)
+{
+ if (options.sendLoadCallbacks != SendCallbacks)
+ return;
+ if (FrameLoader* loader = frameLoader())
+ loader->notifier()->dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response);
+}
+
+void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength, const ResourceLoaderOptions& options)
+{
+ // FIXME: use frame of master document for imported documents.
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
+ if (options.sendLoadCallbacks != SendCallbacks)
+ return;
+ if (FrameLoader* loader = frameLoader())
+ loader->notifier()->dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
+ InspectorInstrumentation::didReceiveResourceData(cookie);
+}
+
+void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
+{
+ if (m_documentLoader)
+ m_documentLoader->subresourceLoaderFinishedLoadingOnePart(loader);
+}
+
+void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
+{
+ if (m_documentLoader)
+ m_documentLoader->addResourceLoader(loader);
+}
+
+void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
+{
+ if (m_documentLoader)
+ m_documentLoader->removeResourceLoader(loader);
+}
+
+void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
+{
+ if (m_documentLoader)
+ m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
+}
+
+bool ResourceFetcher::defersLoading() const
+{
+ if (Frame* frame = this->frame())
+ return frame->page()->defersLoading();
+ return false;
+}
+
+bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
+{
+ return this == possibleOwner;
+}
+
+bool ResourceFetcher::shouldRequest(Resource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
+{
+ if (!canRequest(resource->type(), request.url(), options))
+ return false;
+ if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
+ return false;
+ return true;
+}
+
+void ResourceFetcher::refResourceLoaderHost()
+{
+ ref();
+}
+
+void ResourceFetcher::derefResourceLoaderHost()
+{
+ deref();
+}
+
+#if PRELOAD_DEBUG
+void ResourceFetcher::printPreloadStats()
+{
+ unsigned scripts = 0;
+ unsigned scriptMisses = 0;
+ unsigned stylesheets = 0;
+ unsigned stylesheetMisses = 0;
+ unsigned images = 0;
+ unsigned imageMisses = 0;
+ ListHashSet<Resource*>::iterator end = m_preloads.end();
+ for (ListHashSet<Resource*>::iterator it = m_preloads.begin(); it != end; ++it) {
+ Resource* res = *it;
+ if (res->preloadResult() == Resource::PreloadNotReferenced)
+ printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
+ else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
+ printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
+ else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
+ printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
+
+ if (res->type() == Resource::Script) {
+ scripts++;
+ if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
+ scriptMisses++;
+ } else if (res->type() == Resource::CSSStyleSheet) {
+ stylesheets++;
+ if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
+ stylesheetMisses++;
+ } else {
+ images++;
+ if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
+ imageMisses++;
+ }
+
+ if (res->errorOccurred())
+ memoryCache()->remove(res);
+
+ res->decreasePreloadCount();
+ }
+ m_preloads.clear();
+
+ if (scripts)
+ printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
+ if (stylesheets)
+ printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
+ if (images)
+ printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
+}
+#endif
+
+const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
+{
+ DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, DoSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
+ return options;
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.h b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.h
new file mode 100644
index 00000000000..c2ffa7ade12
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcher.h
@@ -0,0 +1,236 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef ResourceFetcher_h
+#define ResourceFetcher_h
+
+#include "core/loader/ResourceLoaderHost.h"
+#include "core/loader/cache/CachePolicy.h"
+#include "core/loader/cache/FetchInitiatorInfo.h"
+#include "core/loader/cache/FetchRequest.h"
+#include "core/loader/cache/Resource.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/platform/Timer.h"
+#include "wtf/Deque.h"
+#include "wtf/HashMap.h"
+#include "wtf/HashSet.h"
+#include "wtf/ListHashSet.h"
+#include "wtf/text/StringHash.h"
+
+namespace WebCore {
+
+class CSSStyleSheetResource;
+class DocumentResource;
+class FontResource;
+class ImageResource;
+class RawResource;
+class ScriptResource;
+class ShaderResource;
+class TextTrackResource;
+class XSLStyleSheetResource;
+class Document;
+class DocumentLoader;
+class Frame;
+class FrameLoader;
+class ImageLoader;
+class KURL;
+class ResourceTimingInfo;
+
+// The ResourceFetcher provides a per-context interface to the MemoryCache
+// and enforces a bunch of security checks and rules for resource revalidation.
+// Its lifetime is roughly per-DocumentLoader, in that it is generally created
+// in the DocumentLoader constructor and loses its ability to generate network
+// requests when the DocumentLoader is destroyed. Documents also hold a
+// RefPtr<ResourceFetcher> for their lifetime (and will create one if they
+// are initialized without a Frame), so a Document can keep a ResourceFetcher
+// alive past detach if scripts still reference the Document.
+class ResourceFetcher : public RefCounted<ResourceFetcher>, public ResourceLoaderHost {
+ WTF_MAKE_NONCOPYABLE(ResourceFetcher); WTF_MAKE_FAST_ALLOCATED;
+friend class ImageLoader;
+friend class ResourceCacheValidationSuppressor;
+
+public:
+ static PassRefPtr<ResourceFetcher> create(DocumentLoader* documentLoader) { return adoptRef(new ResourceFetcher(documentLoader)); }
+ virtual ~ResourceFetcher();
+
+ using RefCounted<ResourceFetcher>::ref;
+ using RefCounted<ResourceFetcher>::deref;
+
+ ResourcePtr<ImageResource> requestImage(FetchRequest&);
+ ResourcePtr<CSSStyleSheetResource> requestCSSStyleSheet(FetchRequest&);
+ ResourcePtr<CSSStyleSheetResource> requestUserCSSStyleSheet(FetchRequest&);
+ ResourcePtr<ScriptResource> requestScript(FetchRequest&);
+ ResourcePtr<FontResource> requestFont(FetchRequest&);
+ ResourcePtr<RawResource> requestRawResource(FetchRequest&);
+ ResourcePtr<RawResource> requestMainResource(FetchRequest&);
+ ResourcePtr<DocumentResource> requestSVGDocument(FetchRequest&);
+ ResourcePtr<XSLStyleSheetResource> requestXSLStyleSheet(FetchRequest&);
+ ResourcePtr<Resource> requestLinkResource(Resource::Type, FetchRequest&);
+ ResourcePtr<TextTrackResource> requestTextTrack(FetchRequest&);
+ ResourcePtr<ShaderResource> requestShader(FetchRequest&);
+ ResourcePtr<RawResource> requestImport(FetchRequest&);
+
+ // Logs an access denied message to the console for the specified URL.
+ void printAccessDeniedMessage(const KURL&) const;
+
+ Resource* cachedResource(const String& url) const;
+ Resource* cachedResource(const KURL&) const;
+
+ typedef HashMap<String, ResourcePtr<Resource> > DocumentResourceMap;
+ const DocumentResourceMap& allResources() const { return m_documentResources; }
+
+ bool autoLoadImages() const { return m_autoLoadImages; }
+ void setAutoLoadImages(bool);
+
+ void setImagesEnabled(bool);
+
+ bool shouldDeferImageLoad(const KURL&) const;
+
+ CachePolicy cachePolicy(Resource::Type) const;
+
+ Frame* frame() const; // Can be null
+ Document* document() const { return m_document; } // Can be null
+ void setDocument(Document* document) { m_document = document; }
+
+ DocumentLoader* documentLoader() const { return m_documentLoader; }
+ void clearDocumentLoader() { m_documentLoader = 0; }
+
+ void garbageCollectDocumentResources();
+
+ int requestCount() const { return m_requestCount; }
+
+ bool isPreloaded(const String& urlString) const;
+ void clearPreloads();
+ void clearPendingPreloads();
+ void preload(Resource::Type, FetchRequest&, const String& charset);
+ void checkForPendingPreloads();
+ void printPreloadStats();
+ bool canRequest(Resource::Type, const KURL&, const ResourceLoaderOptions&, bool forPreload = false);
+ bool canAccess(Resource*);
+
+ // ResourceLoaderHost
+ virtual void incrementRequestCount(const Resource*) OVERRIDE;
+ virtual void decrementRequestCount(const Resource*) OVERRIDE;
+ virtual void didLoadResource(Resource*) OVERRIDE;
+ virtual void redirectReceived(Resource*, const ResourceResponse&) OVERRIDE;
+ virtual void didFinishLoading(const Resource*, double finishTime, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void didChangeLoadingPriority(const Resource*, ResourceLoadPriority) OVERRIDE;
+ virtual void didFailLoading(const Resource*, const ResourceError&, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void willSendRequest(const Resource*, ResourceRequest&, const ResourceResponse& redirectResponse, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void didReceiveResponse(const Resource*, const ResourceResponse&, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void didReceiveData(const Resource*, const char* data, int dataLength, int encodedDataLength, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void subresourceLoaderFinishedLoadingOnePart(ResourceLoader*) OVERRIDE;
+ virtual void didInitializeResourceLoader(ResourceLoader*) OVERRIDE;
+ virtual void willTerminateResourceLoader(ResourceLoader*) OVERRIDE;
+ virtual void willStartLoadingResource(ResourceRequest&) OVERRIDE;
+ virtual bool defersLoading() const OVERRIDE;
+ virtual bool isLoadedBy(ResourceLoaderHost*) const OVERRIDE;
+ virtual bool shouldRequest(Resource*, const ResourceRequest&, const ResourceLoaderOptions&) OVERRIDE;
+ virtual void refResourceLoaderHost() OVERRIDE;
+ virtual void derefResourceLoaderHost() OVERRIDE;
+
+ static const ResourceLoaderOptions& defaultResourceOptions();
+private:
+
+ explicit ResourceFetcher(DocumentLoader*);
+
+ FrameLoader* frameLoader();
+ bool shouldLoadNewResource() const;
+
+ ResourcePtr<Resource> requestResource(Resource::Type, FetchRequest&);
+ ResourcePtr<Resource> revalidateResource(const FetchRequest&, Resource*);
+ ResourcePtr<Resource> loadResource(Resource::Type, FetchRequest&, const String& charset);
+ void preCacheDataURIImage(const FetchRequest&);
+ void storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>&, const FetchRequest&);
+ void requestPreload(Resource::Type, FetchRequest&, const String& charset);
+
+ enum RevalidationPolicy { Use, Revalidate, Reload, Load };
+ RevalidationPolicy determineRevalidationPolicy(Resource::Type, ResourceRequest&, bool forPreload, Resource* existingResource, FetchRequest::DeferOption) const;
+
+ void determineTargetType(ResourceRequest&, Resource::Type);
+ ResourceRequestCachePolicy resourceRequestCachePolicy(const ResourceRequest&, Resource::Type);
+ void addAdditionalRequestHeaders(ResourceRequest&, Resource::Type);
+
+ void notifyLoadedFromMemoryCache(Resource*);
+ bool checkInsecureContent(Resource::Type, const KURL&) const;
+
+ void garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>*);
+ void performPostLoadActions();
+
+ bool clientDefersImage(const KURL&) const;
+ void reloadImagesIfNotDeferred();
+
+ HashSet<String> m_validatedURLs;
+ mutable DocumentResourceMap m_documentResources;
+ Document* m_document;
+ DocumentLoader* m_documentLoader;
+
+ int m_requestCount;
+
+ OwnPtr<ListHashSet<Resource*> > m_preloads;
+ struct PendingPreload {
+ Resource::Type m_type;
+ FetchRequest m_request;
+ String m_charset;
+ };
+ Deque<PendingPreload> m_pendingPreloads;
+
+ Timer<ResourceFetcher> m_garbageCollectDocumentResourcesTimer;
+
+ typedef HashMap<Resource*, RefPtr<ResourceTimingInfo> > ResourceTimingInfoMap;
+ ResourceTimingInfoMap m_resourceTimingInfoMap;
+
+ // 29 bits left
+ bool m_autoLoadImages : 1;
+ bool m_imagesEnabled : 1;
+ bool m_allowStaleResources : 1;
+};
+
+class ResourceCacheValidationSuppressor {
+ WTF_MAKE_NONCOPYABLE(ResourceCacheValidationSuppressor);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ResourceCacheValidationSuppressor(ResourceFetcher* loader)
+ : m_loader(loader)
+ , m_previousState(false)
+ {
+ if (m_loader) {
+ m_previousState = m_loader->m_allowStaleResources;
+ m_loader->m_allowStaleResources = true;
+ }
+ }
+ ~ResourceCacheValidationSuppressor()
+ {
+ if (m_loader)
+ m_loader->m_allowStaleResources = m_previousState;
+ }
+private:
+ ResourceFetcher* m_loader;
+ bool m_previousState;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcherTest.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcherTest.cpp
new file mode 100644
index 00000000000..977f519ee80
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourceFetcherTest.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/ResourceFetcher.h"
+
+#include "core/html/HTMLDocument.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/cache/FetchInitiatorInfo.h"
+#include "core/loader/cache/FetchRequest.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/loader/cache/ResourcePtr.h"
+#include "core/platform/network/ResourceRequest.h"
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+
+namespace {
+
+TEST(ResourceFetcherTest, StartLoadAfterFrameDetach)
+{
+ KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.jpg");
+
+ // Create a ResourceFetcher that has a real DocumentLoader and Document, but is not attached to a Frame.
+ // Technically, we're concerned about what happens after a Frame is detached (rather than before
+ // any attach occurs), but ResourceFetcher can't tell the difference.
+ RefPtr<DocumentLoader> documentLoader = DocumentLoader::create(ResourceRequest(testURL), SubstituteData());
+ RefPtr<HTMLDocument> document = HTMLDocument::create();
+ RefPtr<ResourceFetcher> fetcher(documentLoader->fetcher());
+ fetcher->setDocument(document.get());
+ EXPECT_EQ(fetcher->frame(), static_cast<Frame*>(0));
+
+ // Try to request a url. The request should fail, no resource should be returned,
+ // and no resource should be present in the cache.
+ FetchRequest fetchRequest = FetchRequest(ResourceRequest(testURL), FetchInitiatorInfo());
+ ResourcePtr<ImageResource> image = fetcher->requestImage(fetchRequest);
+ EXPECT_EQ(image.get(), static_cast<ImageResource*>(0));
+ EXPECT_EQ(memoryCache()->resourceForURL(testURL), static_cast<Resource*>(0));
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.cpp
new file mode 100644
index 00000000000..bbb43520d88
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/ResourcePtr.h"
+
+namespace WebCore {
+
+void ResourcePtrBase::setResource(Resource* resource)
+{
+ if (resource == m_resource)
+ return;
+ if (m_resource)
+ m_resource->unregisterHandle(this);
+ m_resource = resource;
+ if (m_resource)
+ m_resource->registerHandle(this);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.h b/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.h
new file mode 100644
index 00000000000..dda4d2d748b
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ResourcePtr.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ResourcePtr_h
+#define ResourcePtr_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class ResourcePtrBase {
+public:
+ ~ResourcePtrBase();
+
+ Resource* get() const { return m_resource; }
+ bool operator!() const { return !m_resource; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef Resource* ResourcePtrBase::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_resource ? &ResourcePtrBase::m_resource : 0; }
+
+protected:
+ ResourcePtrBase() : m_resource(0) { }
+ ResourcePtrBase(Resource*);
+ ResourcePtrBase(const ResourcePtrBase&);
+
+ void setResource(Resource*);
+
+private:
+ ResourcePtrBase& operator=(const ResourcePtrBase&) { return *this; }
+
+ friend class Resource;
+
+ Resource* m_resource;
+};
+
+inline ResourcePtrBase::ResourcePtrBase(Resource* res)
+ : m_resource(res)
+{
+ if (m_resource)
+ m_resource->registerHandle(this);
+}
+
+inline ResourcePtrBase::~ResourcePtrBase()
+{
+ if (m_resource)
+ m_resource->unregisterHandle(this);
+}
+
+inline ResourcePtrBase::ResourcePtrBase(const ResourcePtrBase& o)
+ : m_resource(o.m_resource)
+{
+ if (m_resource)
+ m_resource->registerHandle(this);
+}
+
+template <class R> class ResourcePtr : public ResourcePtrBase {
+public:
+ ResourcePtr() { }
+ ResourcePtr(R* res) : ResourcePtrBase(res) { }
+ ResourcePtr(const ResourcePtr<R>& o) : ResourcePtrBase(o) { }
+ template<typename U> ResourcePtr(const ResourcePtr<U>& o) : ResourcePtrBase(o.get()) { }
+
+ R* get() const { return reinterpret_cast<R*>(ResourcePtrBase::get()); }
+ R* operator->() const { return get(); }
+
+ ResourcePtr& operator=(R* res) { setResource(res); return *this; }
+ ResourcePtr& operator=(const ResourcePtr& o) { setResource(o.get()); return *this; }
+ template<typename U> ResourcePtr& operator=(const ResourcePtr<U>& o) { setResource(o.get()); return *this; }
+
+ bool operator==(const ResourcePtrBase& o) const { return get() == o.get(); }
+ bool operator!=(const ResourcePtrBase& o) const { return get() != o.get(); }
+};
+
+template <class R, class RR> bool operator==(const ResourcePtr<R>& h, const RR* res)
+{
+ return h.get() == res;
+}
+template <class R, class RR> bool operator==(const RR* res, const ResourcePtr<R>& h)
+{
+ return h.get() == res;
+}
+template <class R, class RR> bool operator!=(const ResourcePtr<R>& h, const RR* res)
+{
+ return h.get() != res;
+}
+template <class R, class RR> bool operator!=(const RR* res, const ResourcePtr<R>& h)
+{
+ return h.get() != res;
+}
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.cpp
new file mode 100644
index 00000000000..b6e9189bc26
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "core/loader/cache/ScriptResource.h"
+
+#include "core/loader/TextResourceDecoder.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/platform/network/HTTPParsers.h"
+
+namespace WebCore {
+
+ScriptResource::ScriptResource(const ResourceRequest& resourceRequest, const String& charset)
+ : Resource(resourceRequest, Script)
+ , m_decoder(TextResourceDecoder::create("application/javascript", charset))
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, acceptScript, ("*/*", AtomicString::ConstructFromLiteral));
+
+ // It's javascript we want.
+ // But some websites think their scripts are <some wrong mimetype here>
+ // and refuse to serve them if we only accept application/x-javascript.
+ setAccept(acceptScript);
+}
+
+ScriptResource::~ScriptResource()
+{
+}
+
+void ScriptResource::setEncoding(const String& chs)
+{
+ m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
+}
+
+String ScriptResource::encoding() const
+{
+ return m_decoder->encoding().name();
+}
+
+String ScriptResource::mimeType() const
+{
+ return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type")).lower();
+}
+
+const String& ScriptResource::script()
+{
+ ASSERT(!isPurgeable());
+ ASSERT(isLoaded());
+
+ if (!m_script && m_data) {
+ String script = m_decoder->decode(m_data->data(), encodedSize());
+ script.append(m_decoder->flush());
+ m_data.clear();
+ // We lie a it here and claim that script counts as encoded data (even though it's really decoded data).
+ // That's because the MemoryCache thinks that it can clear out decoded data by calling destroyDecodedData(),
+ // but we can't destroy script in destroyDecodedData because that's our only copy of the data!
+ setEncodedSize(script.sizeInBytes());
+ m_script = script;
+ }
+
+ return m_script.string();
+}
+
+bool ScriptResource::mimeTypeAllowedByNosniff() const
+{
+ return parseContentTypeOptionsHeader(m_response.httpHeaderField("X-Content-Type-Options")) != ContentTypeOptionsNosniff || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType());
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.h
new file mode 100644
index 00000000000..02d90ca986b
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ScriptResource.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef ScriptResource_h
+#define ScriptResource_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class ResourceFetcher;
+class TextResourceDecoder;
+
+class ScriptResource : public Resource {
+public:
+ ScriptResource(const ResourceRequest&, const String& charset);
+ virtual ~ScriptResource();
+
+ const String& script();
+
+ virtual void setEncoding(const String&);
+ virtual String encoding() const;
+ String mimeType() const;
+
+ bool mimeTypeAllowedByNosniff() const;
+
+private:
+ AtomicString m_script;
+ RefPtr<TextResourceDecoder> m_decoder;
+};
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.cpp
new file mode 100644
index 00000000000..ec60ae11bef
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/loader/cache/ShaderResource.h"
+
+#include "core/loader/TextResourceDecoder.h"
+#include "core/platform/SharedBuffer.h"
+#include "wtf/text/StringBuilder.h"
+
+namespace WebCore {
+
+ShaderResource::ShaderResource(const ResourceRequest& resourceRequest)
+ : Resource(resourceRequest, Shader)
+ , m_decoder(TextResourceDecoder::create("application/shader"))
+{
+}
+
+ShaderResource::~ShaderResource()
+{
+}
+
+const String& ShaderResource::shaderString()
+{
+ if (m_shaderString.isNull() && m_data) {
+ StringBuilder builder;
+ builder.append(m_decoder->decode(m_data->data(), m_data->size()));
+ builder.append(m_decoder->flush());
+ m_shaderString = builder.toString();
+ }
+
+ return m_shaderString;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.h
new file mode 100644
index 00000000000..f7d2ffe7fbb
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/ShaderResource.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ShaderResource_h
+#define ShaderResource_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class TextResourceDecoder;
+
+class ShaderResource : public Resource {
+public:
+ ShaderResource(const ResourceRequest&);
+ virtual ~ShaderResource();
+
+ const String& shaderString();
+
+private:
+ RefPtr<TextResourceDecoder> m_decoder;
+ String m_shaderString;
+};
+
+}
+
+
+#endif // ShaderResource_h
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/StyleSheetResourceClient.h b/chromium/third_party/WebKit/Source/core/loader/cache/StyleSheetResourceClient.h
new file mode 100644
index 00000000000..02dc5bcabc6
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/StyleSheetResourceClient.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2011 Google 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+ */
+
+#ifndef StyleSheetResourceClient_h
+#define StyleSheetResourceClient_h
+
+#include "core/loader/cache/ResourceClient.h"
+#include "weborigin/KURL.h"
+#include "wtf/Forward.h"
+
+namespace WebCore {
+class CSSStyleSheetResource;
+
+class StyleSheetResourceClient : public ResourceClient {
+public:
+ virtual ~StyleSheetResourceClient() { }
+ static ResourceClientType expectedType() { return StyleSheetType; }
+ virtual ResourceClientType resourceClientType() const { return expectedType(); }
+ virtual void setCSSStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* charset */, const CSSStyleSheetResource*) { }
+ virtual void setXSLStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* sheet */) { }
+};
+}
+
+#endif // StyleSheetResourceClient_h
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.cpp
new file mode 100644
index 00000000000..cf5e4a13f07
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "core/loader/cache/TextTrackResource.h"
+
+#include "core/loader/cache/ResourceClient.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+
+namespace WebCore {
+
+TextTrackResource::TextTrackResource(const ResourceRequest& resourceRequest)
+ : Resource(resourceRequest, TextTrack)
+{
+}
+
+TextTrackResource::~TextTrackResource()
+{
+}
+
+void TextTrackResource::appendData(const char* data, int length)
+{
+ Resource::appendData(data, length);
+ ResourceClientWalker<ResourceClient> walker(m_clients);
+ while (ResourceClient *client = walker.next())
+ client->deprecatedDidReceiveResource(this);
+}
+
+}
+
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.h
new file mode 100644
index 00000000000..c3c0eba0955
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/TextTrackResource.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextTrackResource_h
+#define TextTrackResource_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class TextTrackResource : public Resource {
+public:
+ TextTrackResource(const ResourceRequest&);
+ virtual ~TextTrackResource();
+
+ virtual void appendData(const char*, int) OVERRIDE;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.cpp b/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.cpp
new file mode 100644
index 00000000000..9d9a014b78e
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.cpp
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "core/loader/cache/XSLStyleSheetResource.h"
+
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/ResourceClientWalker.h"
+#include "core/loader/cache/StyleSheetResourceClient.h"
+#include "core/platform/SharedBuffer.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+XSLStyleSheetResource::XSLStyleSheetResource(const ResourceRequest& resourceRequest)
+ : Resource(resourceRequest, XSLStyleSheet)
+ , m_decoder(TextResourceDecoder::create("text/xsl"))
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, acceptXSLT, ("text/xml, application/xml, application/xhtml+xml, text/xsl, application/rss+xml, application/atom+xml", AtomicString::ConstructFromLiteral));
+
+ // It's XML we want.
+ // FIXME: This should accept more general xml formats */*+xml, image/svg+xml for example.
+ setAccept(acceptXSLT);
+}
+
+void XSLStyleSheetResource::didAddClient(ResourceClient* c)
+{
+ ASSERT(c->resourceClientType() == StyleSheetResourceClient::expectedType());
+ if (!isLoading())
+ static_cast<StyleSheetResourceClient*>(c)->setXSLStyleSheet(m_resourceRequest.url(), m_response.url(), m_sheet);
+}
+
+void XSLStyleSheetResource::setEncoding(const String& chs)
+{
+ m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
+}
+
+String XSLStyleSheetResource::encoding() const
+{
+ return m_decoder->encoding().name();
+}
+
+void XSLStyleSheetResource::checkNotify()
+{
+ if (m_data.get()) {
+ m_sheet = m_decoder->decode(m_data->data(), encodedSize());
+ m_sheet.append(m_decoder->flush());
+ }
+
+ ResourceClientWalker<StyleSheetResourceClient> w(m_clients);
+ while (StyleSheetResourceClient* c = w.next())
+ c->setXSLStyleSheet(m_resourceRequest.url(), m_response.url(), m_sheet);
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.h b/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.h
new file mode 100644
index 00000000000..4cab515a463
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/loader/cache/XSLStyleSheetResource.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#ifndef XSLStyleSheetResource_h
+#define XSLStyleSheetResource_h
+
+#include "core/loader/cache/Resource.h"
+
+namespace WebCore {
+
+class ResourceFetcher;
+class TextResourceDecoder;
+
+class XSLStyleSheetResource : public Resource {
+public:
+ XSLStyleSheetResource(const ResourceRequest&);
+
+ const String& sheet() const { return m_sheet; }
+
+ virtual void didAddClient(ResourceClient*);
+ virtual void setEncoding(const String&);
+ virtual String encoding() const;
+
+protected:
+ virtual void checkNotify();
+
+ String m_sheet;
+ RefPtr<TextResourceDecoder> m_decoder;
+};
+
+} // namespace WebCore
+
+#endif