⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*    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 "Cache.h"#include "CachedCSSStyleSheet.h"#include "CachedFont.h"#include "CachedImage.h"#include "CachedScript.h"#include "CachedXSLStyleSheet.h"#include "DocLoader.h"#include "Document.h"#include "FrameLoader.h"#include "FrameView.h"#include "Image.h"#include "ResourceHandle.h"#include <stdio.h>#include <wtf/CurrentTime.h>using namespace std;namespace WebCore {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.static const double cDefaultDecodedDataDeletionInterval = 0;Cache* cache(){    static Cache* staticCache = new Cache;    return staticCache;}Cache::Cache()    : m_disabled(false)    , m_pruneEnabled(true)    , m_inPruneDeadResources(false)    , m_capacity(cDefaultCacheCapacity)    , m_minDeadCapacity(0)    , m_maxDeadCapacity(cDefaultCacheCapacity)    , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval)    , m_liveSize(0)    , m_deadSize(0){}static CachedResource* createResource(CachedResource::Type type, const KURL& url, const String& charset){    switch (type) {    case CachedResource::ImageResource:        return new CachedImage(url.string());    case CachedResource::CSSStyleSheet:        return new CachedCSSStyleSheet(url.string(), charset);    case CachedResource::Script:        return new CachedScript(url.string(), charset);    case CachedResource::FontResource:        return new CachedFont(url.string());#if ENABLE(XSLT)    case CachedResource::XSLStyleSheet:        return new CachedXSLStyleSheet(url.string());#endif#if ENABLE(XBL)    case CachedResource::XBLStyleSheet:        return new CachedXBLDocument(url.string());#endif    default:        break;    }    return 0;}CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Type type, const KURL& url, const String& charset, bool requestIsPreload){    // FIXME: Do we really need to special-case an empty URL?    // Would it be better to just go on with the cache code and let it fail later?    if (url.isEmpty())        return 0;        // Look up the resource in our map.    CachedResource* resource = resourceForURL(url.string());        if (resource && requestIsPreload && !resource->isPreloaded())        return 0;        if (FrameLoader::restrictAccessToLocal() && !FrameLoader::canLoad(url, String(), docLoader->doc())) {        Document* doc = docLoader->doc();        if (doc && !requestIsPreload)            FrameLoader::reportLocalLoadFailed(doc->frame(), url.string());        return 0;    }        if (!resource) {        // The resource does not exist. Create it.        resource = createResource(type, url, charset);        ASSERT(resource);        // Pretend the resource is in the cache, to prevent it from being deleted during the load() call.        // FIXME: CachedResource should just use normal refcounting instead.        resource->setInCache(true);                resource->load(docLoader);                if (!disabled())            m_resources.set(url.string(), resource);  // The size will be added in later once the resource is loaded and calls back to us with the new size.        else {            // Kick the resource out of the cache, because the cache is disabled.            resource->setInCache(false);            resource->setDocLoader(docLoader);            if (resource->errorOccurred()) {                // We don't support immediate loads, but we do support immediate failure.                // In that case we should to delete the resource now and return 0 because otherwise                // it would leak if no ref/deref was ever done on it.                delete resource;                return 0;            }        }    }    if (resource->type() != type)        return 0;    if (!disabled()) {        // This will move the resource to the front of its LRU list and increase its access count.        resourceAccessed(resource);    }    return resource;}    CachedCSSStyleSheet* Cache::requestUserCSSStyleSheet(DocLoader* docLoader, const String& url, const String& charset){    CachedCSSStyleSheet* userSheet;    if (CachedResource* existing = resourceForURL(url)) {        if (existing->type() != CachedResource::CSSStyleSheet)            return 0;        userSheet = static_cast<CachedCSSStyleSheet*>(existing);    } else {        userSheet = new CachedCSSStyleSheet(url, charset);        // Pretend the resource is in the cache, to prevent it from being deleted during the load() call.        // FIXME: CachedResource should just use normal refcounting instead.        userSheet->setInCache(true);        // Don't load incrementally, skip load checks, don't send resource load callbacks.        userSheet->load(docLoader, false, true, false);        if (!disabled())            m_resources.set(url, userSheet);        else            userSheet->setInCache(false);    }    if (!disabled()) {        // This will move the resource to the front of its LRU list and increase its access count.        resourceAccessed(userSheet);    }    return userSheet;}    void Cache::revalidateResource(CachedResource* resource, DocLoader* docLoader){    ASSERT(resource);    ASSERT(!disabled());    if (resource->resourceToRevalidate())        return;    if (!resource->canUseCacheValidator()) {        evict(resource);        return;    }    const String& url = resource->url();    CachedResource* newResource = createResource(resource->type(), KURL(url), resource->encoding());    newResource->setResourceToRevalidate(resource);    evict(resource);    m_resources.set(url, newResource);    newResource->setInCache(true);    resourceAccessed(newResource);    newResource->load(docLoader);}    void Cache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response){    CachedResource* resource = revalidatingResource->resourceToRevalidate();    ASSERT(resource);    ASSERT(!resource->inCache());    ASSERT(resource->isLoaded());        evict(revalidatingResource);    ASSERT(!m_resources.get(resource->url()));    m_resources.set(resource->url(), resource);    resource->setInCache(true);    resource->setExpirationDate(response.expirationDate());    insertInLRUList(resource);    int delta = resource->size();    if (resource->decodedSize() && resource->hasClients())        insertInLiveDecodedResourcesList(resource);    if (delta)        adjustSize(resource->hasClients(), delta);        revalidatingResource->switchClientsToRevalidatedResource();    // this deletes the revalidating resource    revalidatingResource->clearResourceToRevalidate();}void Cache::revalidationFailed(CachedResource* revalidatingResource){    ASSERT(revalidatingResource->resourceToRevalidate());    revalidatingResource->clearResourceToRevalidate();}CachedResource* Cache::resourceForURL(const String& url){    CachedResource* resource = m_resources.get(url);    if (resource && !resource->makePurgeable(false)) {        ASSERT(!resource->hasClients());        evict(resource);        return 0;    }    return resource;}unsigned Cache::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 Cache::liveCapacity() const {     // Live resource capacity is whatever is left over after calculating dead resource capacity.    return m_capacity - deadCapacity();}void Cache::pruneLiveResources(){    if (!m_pruneEnabled)        return;    unsigned capacity = liveCapacity();    if (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 least recently accessed of the objects.    CachedResource* current = m_liveDecodedResources.m_tail;    while (current) {        CachedResource* 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 < cMinDelayBeforeLiveDecodedPrune)                return;            // Destroy our decoded data. This will remove us from             // m_liveDecodedResources, and possibly move us to a differnt LRU             // list in m_allResources.            current->destroyDecodedData();            if (targetSize && m_liveSize <= targetSize)                return;        }        current = prev;    }}void Cache::pruneDeadResources(){    if (!m_pruneEnabled)        return;    unsigned capacity = deadCapacity();    if (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();        if (!m_inPruneDeadResources) {        // See if we have any purged resources we can evict.        for (int i = 0; i < size; i++) {            CachedResource* current = m_allResources[i].m_tail;            while (current) {                CachedResource* 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;    m_inPruneDeadResources = true;    for (int i = size - 1; i >= 0; i--) {        // Remove from the tail, since this is the least frequently accessed of the objects.        CachedResource* current = m_allResources[i].m_tail;                // First flush all the decoded data in this queue.        while (current) {            CachedResource* prev = current->m_prevInAllResourcesList;            if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) {                // Destroy our decoded data. This will remove us from                 // m_liveDecodedResources, and possibly move us to a differnt                 // LRU list in m_allResources.                current->destroyDecodedData();                                if (targetSize && m_deadSize <= targetSize) {                    m_inPruneDeadResources = false;                    return;                }            }            current = prev;        }        // Now evict objects from this queue.        current = m_allResources[i].m_tail;        while (current) {            CachedResource* prev = current->m_prevInAllResourcesList;            if (!current->hasClients() && !current->isPreloaded()) {                evict(current);                // If evict() caused pruneDeadResources() to be re-entered, bail out. This can happen when removing an                // SVG CachedImage that has subresources.                if (!m_inPruneDeadResources)                    return;                if (targetSize && m_deadSize <= targetSize) {                    m_inPruneDeadResources = false;                    return;                }            }            current = prev;        }                    // 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);    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -