void Resource::addClient(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())
        memoryCache()->makeLive(this);

    if (!m_revalidatingRequest.isNull()) {
        m_clients.add(client);
        return;
    }

    // If we have existing data to send to the new client and the resource type supprts it, send it asynchronously.
    if (!m_response.isNull() && !shouldSendCachedDataSynchronouslyForType(type()) && !m_needsSynchronousCacheHit) {
        m_clientsAwaitingCallback.add(client);
        ResourceCallback::callbackHandler()->schedule(this);
        return;
    }

    m_clients.add(client);
    didAddClient(client);
    return;
}
void Resource::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail, WebProcessMemoryDump* memoryDump) const
{
    static const size_t kMaxURLReportLength = 128;
    static const int kMaxResourceClientToShowInMemoryInfra = 10;

    const String dumpName = getMemoryDumpName();
    WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dumpName);
    dump->addScalar("encoded_size", "bytes", m_encodedSize);
    if (canDelete()) {
        dump->addScalar("dead_size", "bytes", m_encodedSize);
    } else {
        dump->addScalar("live_size", "bytes", m_encodedSize);
    }

    if (m_data) {
        dump->addScalar("purgeable_size", "bytes", isPurgeable() && !wasPurged() ? encodedSize() + overheadSize() : 0);
        m_data->onMemoryDump(dumpName, memoryDump);
    }

    if (levelOfDetail == WebMemoryDumpLevelOfDetail::Detailed) {
        String urlToReport = url().string();
        if (urlToReport.length() > kMaxURLReportLength) {
            urlToReport.truncate(kMaxURLReportLength);
            urlToReport = urlToReport + "...";
        }
        dump->addString("url", "", urlToReport);

        dump->addString("reason_not_deletable", "", reasonNotDeletable());

        Vector<String> clientNames;
        ResourceClientWalker<ResourceClient> walker(m_clients);
        while (ResourceClient* client = walker.next())
            clientNames.append(client->debugName());
        ResourceClientWalker<ResourceClient> walker2(m_clientsAwaitingCallback);
        while (ResourceClient* client = walker2.next())
            clientNames.append("(awaiting) " + client->debugName());
        ResourceClientWalker<ResourceClient> walker3(m_finishedClients);
        while (ResourceClient* client = walker3.next())
            clientNames.append("(finished) " + client->debugName());
        std::sort(clientNames.begin(), clientNames.end(), codePointCompareLessThan);

        StringBuilder builder;
        for (size_t i = 0; i < clientNames.size() && i < kMaxResourceClientToShowInMemoryInfra; ++i) {
            if (i > 0)
                builder.append(" / ");
            builder.append(clientNames[i]);
        }
        if (clientNames.size() > kMaxResourceClientToShowInMemoryInfra) {
            builder.append(" / and ");
            builder.appendNumber(clientNames.size() - kMaxResourceClientToShowInMemoryInfra);
            builder.append(" more");
        }
        dump->addString("ResourceClient", "", builder.toString());
    }

    const String overheadName = dumpName + "/metadata";
    WebMemoryAllocatorDump* overheadDump = memoryDump->createMemoryAllocatorDump(overheadName);
    overheadDump->addScalar("size", "bytes", overheadSize());
    memoryDump->addSuballocation(overheadDump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
}
Beispiel #3
0
void Resource::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail, WebProcessMemoryDump* memoryDump) const
{
    static const size_t kMaxURLReportLength = 128;

    const String dumpName = getMemoryDumpName();
    WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dumpName);
    dump->addScalar("encoded_size", "bytes", m_encodedSize);
    if (canDelete()) {
        dump->addScalar("dead_size", "bytes", m_encodedSize);
    } else {
        dump->addScalar("live_size", "bytes", m_encodedSize);
    }

    if (m_data) {
        dump->addScalar("purgeable_size", "bytes", isPurgeable() && !wasPurged() ? encodedSize() + overheadSize() : 0);
        m_data->onMemoryDump(dumpName, memoryDump);
    }

    if (levelOfDetail == WebMemoryDumpLevelOfDetail::Detailed) {
        String urlToReport = url().string();
        if (urlToReport.length() > kMaxURLReportLength) {
            urlToReport.truncate(kMaxURLReportLength);
            urlToReport = urlToReport + "...";
        }
        dump->addString("url", "", urlToReport);
    }

    const String overheadName = dumpName + "/metadata";
    WebMemoryAllocatorDump* overheadDump = memoryDump->createMemoryAllocatorDump(overheadName);
    overheadDump->addScalar("size", "bytes", overheadSize());
    memoryDump->addSuballocation(overheadDump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
}
Beispiel #4
0
bool CachedResource::addClientToSet(CachedResourceClient* 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 == RawResource || 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 CachedResources,
        // we schedule the callbacks and ensure we never finish synchronously.
        ASSERT(!m_clientsAwaitingCallback.contains(client));
        m_clientsAwaitingCallback.add(client, CachedResourceCallback::schedule(this, client));
        return false;
    }

    m_clients.add(client);
    return true;
}
LayoutSize ImageResource::imageSizeForLayoutObject(const LayoutObject* layoutObject, float multiplier, SizeType sizeType)
{
    ASSERT(!isPurgeable());

    if (!m_image)
        return LayoutSize();

    LayoutSize imageSize;

    if (m_image->isBitmapImage() && (layoutObject && layoutObject->shouldRespectImageOrientation() == RespectImageOrientation))
        imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
    else if (m_image->isSVGImage() && sizeType == NormalSize)
        imageSize = LayoutSize(svgImageSizeForLayoutObject(layoutObject));
    else
        imageSize = LayoutSize(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;
}
Beispiel #6
0
const String& CachedScript::script()
{
    ASSERT(!isPurgeable());

    if (!m_script && m_data) {
        m_script = m_decoder->decode(m_data->data(), encodedSize());
        m_script.append(m_decoder->flush());
#if ENABLE(MEMORY_OUT_HANDLING)
        // If we fail to decode the script (because of lack of memory)
        // and return an empty string the Lexer will barf.  It
        // assumes that the data ptr is not going to be null.
        if (encodedSize() > 0 && m_script.length() == 0)
            m_script = " ";
#endif
        setDecodedSize(m_script.sizeInBytes());
    }
#if !ENABLE(MEMORY_OUT_HANDLING)
    // If memory out handling is enabled, don't delete the decoded data.
    // JS parser assumes that if a script has been decoded once we'll always
    // be able to decode it.
    m_decodedDataDeletionTimer.startOneShot(0);
#endif

    return m_script;
}
Beispiel #7
0
IntRect CachedImage::imageRect(float multiplier) const
{
    ASSERT(!isPurgeable());

    if (!m_image)
        return IntRect();
    if (multiplier == 1.0f || (!m_image->hasRelativeWidth() && !m_image->hasRelativeHeight()))
        return m_image->rect();

    float widthMultiplier = (m_image->hasRelativeWidth() ? 1.0f : multiplier);
    float heightMultiplier = (m_image->hasRelativeHeight() ? 1.0f : multiplier);

    // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
    bool hasWidth = m_image->rect().width() > 0;
    bool hasHeight = m_image->rect().height() > 0;

    int width = static_cast<int>(m_image->rect().width() * widthMultiplier);
    int height = static_cast<int>(m_image->rect().height() * heightMultiplier);
    if (hasWidth)
        width = max(1, width);
    if (hasHeight)
        height = max(1, height);

    int x = static_cast<int>(m_image->rect().x() * widthMultiplier);
    int y = static_cast<int>(m_image->rect().y() * heightMultiplier);

    return IntRect(x, y, width, height);
}
Beispiel #8
0
LayoutSize CachedImage::imageSizeForRenderer(const RenderObject* renderer, float multiplier, SizeType sizeType)
{
    ASSERT(!isPurgeable());

    if (!m_image)
        return LayoutSize();

    LayoutSize imageSize(m_image->size());

#if ENABLE(CSS_IMAGE_ORIENTATION)
    if (renderer && m_image->isBitmapImage()) {
        ImageOrientationDescription orientationDescription(renderer->shouldRespectImageOrientation(), renderer->style().imageOrientation());
        if (orientationDescription.respectImageOrientation() == RespectImageOrientation)
            imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation(orientationDescription));
    }
#else
    if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
#if !PLATFORM(IOS)
        imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
#else
    {
        // On iOS, the image may have been subsampled to accommodate our size restrictions. However
        // we should tell the renderer what the original size was.
        imageSize = LayoutSize(toBitmapImage(m_image.get())->originalSizeRespectingOrientation());
    } else if (m_image->isBitmapImage())
Beispiel #9
0
const String& CachedScript::script()
{
    ASSERT(!isPurgeable());

    if (!m_script && m_data) {
        m_script = m_decoder->decodeAndFlush(m_data->data(), encodedSize());
        setDecodedSize(m_script.sizeInBytes());
    }
    m_decodedDataDeletionTimer.restart();
    
    return m_script;
}
Beispiel #10
0
Image* CachedImage::image() const
{
    ASSERT(!isPurgeable());

    if (errorOccurred() && m_shouldPaintBrokenImage)
        return brokenImage();

    if (m_image)
        return m_image.get();

    return Image::nullImage();
}
Beispiel #11
0
const String& CachedScript::script()
{
    ASSERT(!isPurgeable());

    if (!m_script && m_data) {
        m_script = m_decoder->decode(m_data->data(), encodedSize());
        m_script += m_decoder->flush();
        setDecodedSize(m_script.length() * sizeof(UChar));
    }
    m_decodedDataDeletionTimer.startOneShot(0);
    return m_script;
}
Beispiel #12
0
Image* CachedImage::image() const
{
    ASSERT(!isPurgeable());

    if (m_errorOccurred)
        return brokenImage();

    if (m_image)
        return m_image.get();

    return nullImage();
}
Beispiel #13
0
const String& CachedScript::script()
{
    ASSERT(!isPurgeable());

    if (!m_script && m_data) {
        m_script = m_decoder->decode(m_data->data(), encodedSize());
        m_script.append(m_decoder->flush());
        setDecodedSize(m_script.sizeInBytes());
    }
    m_decodedDataDeletionTimer.startOneShot(0);

    return m_script;
}
Beispiel #14
0
const String CachedCSSStyleSheet::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 += m_decoder->flush();
    return sheetText;
}
Beispiel #15
0
Image* CachedImage::imageForRenderer(const RenderObject* renderer)
{
    ASSERT(!isPurgeable());

    if (errorOccurred() && m_shouldPaintBrokenImage) {
        // Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
        // deviceScaleFactor from here. It is critical that callers use CachedImage::brokenImage()
        // when they need the real, deviceScaleFactor-appropriate broken image icon.
        return brokenImage();
    }

    if (m_image)
        return lookupImageForRenderer(renderer);

    return Image::nullImage();
}
Beispiel #16
0
blink::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 blink::Image::nullImage();
}
Beispiel #17
0
const String& ScriptResource::script()
{
    ASSERT(!isPurgeable());
    ASSERT(isLoaded());

    if (!m_script && m_data) {
        String script = decodedText();
        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 = AtomicString(script);
    }

    return m_script.string();
}
Beispiel #18
0
Image* CachedImage::image(bool brokenImageNeeded) const  // CAPP_WEB_HIDE_BROKEN_IMAGE
{
    ASSERT(!isPurgeable());
    // CAPP_WEB_HIDE_BROKEN_IMAGE
    if (!brokenImageNeeded) {
        if (m_image&&!errorOccurred())
            return m_image.get();

        return Image::nullImage();
    }
    // CAPP_WEB_HIDE_BROKEN_IMAGE_END
    if (errorOccurred() && m_shouldPaintBrokenImage)
        return brokenImage();

    if (m_image)
        return m_image.get();

    return Image::nullImage();
}
Beispiel #19
0
IntSize CachedImage::imageSize(float multiplier) const
{
    ASSERT(!isPurgeable());

    if (!m_image)
        return IntSize();
    if (multiplier == 1.0f)
        return m_image->size();
        
    // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
    bool hasWidth = m_image->size().width() > 0;
    bool hasHeight = m_image->size().height() > 0;
    int width = m_image->size().width() * (m_image->hasRelativeWidth() ? 1.0f : multiplier);
    int height = m_image->size().height() * (m_image->hasRelativeHeight() ? 1.0f : multiplier);
    if (hasWidth)
        width = max(1, width);
    if (hasHeight)
        height = max(1, height);
    return IntSize(width, height);
}