Avoid unnecessary data copies when loading subresources with DoNotBufferData option
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2013 10:59:11 +0000 (10:59 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2013 10:59:11 +0000 (10:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=115804

Reviewed by Darin Adler.

When DoNotBufferData option is used to load a resource its data
is always copied before sending it to the CachedResource. Most
of the cached resources ignore the incremental data and wait
until all data has been received to save the ResourceBuffer,
that will be NULL anyway when DoNotBufferData is used.
CachedRawResource notifies its clients about the incremental
data, but it doesn't save the data when DoNotBufferData option
is present. In those cases we are unnecessary copying the data.

CachedResource::data has been split into
CachedResource::addDataBuffer() used for incremental data chunks
when buffering data, CachedResource::addData() used for
incremental data chunks when not buffering and
CachedResource::finishLoading() used to finish the loading. This
way we get rid of the allDataReceived boolean parameter and cached
resources not interested in incremenetal data chunks only have to
implement finishLoading() without having to check if all data have
been received or not.

SubresourceLoader::sendDataToResource was always called after
checking if loading multipart content, and then it was checked
again to decided whether to copy the data or not. It has been
removed in favor of calling directly the resource methods,
finishLoading for multipart content, addDataBuffer for data chunks
when buffering and addData for data chunks when not buffering.

No new functionality, covered by existing tests.

* html/ImageDocument.cpp:
(WebCore::ImageDocumentParser::appendBytes): Update to API changes.
(WebCore::ImageDocumentParser::finish): Ditto.
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didReceiveResponse): Call
finishLoading() for multipart content.
(WebCore::SubresourceLoader::didReceiveDataOrBuffer): Add data to
the resource using addDataBuffer or addData depending on whether
we are buffering or not.
(WebCore::SubresourceLoader::didFinishLoading): Call
finishLoading() for the cached resource instead of data.
* loader/SubresourceLoader.h:
* loader/cache/CachedCSSStyleSheet.cpp:
(WebCore::CachedCSSStyleSheet::finishLoading):
* loader/cache/CachedCSSStyleSheet.h:
* loader/cache/CachedFont.cpp:
(WebCore::CachedFont::finishLoading):
* loader/cache/CachedFont.h:
* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::isValidDecodedImageSize): Helper function
to check if the image size is valid.
(WebCore::CachedImage::addIncrementalDataBuffer): Helper function
to add incremental data buffer.
(WebCore::CachedImage::addDataBuffer): Call
addIncrementalDataBuffer().
(WebCore::CachedImage::addData): Create a ResourceBuffer and call
addIncrementalDataBuffer().
(WebCore::CachedImage::finishLoading):
* loader/cache/CachedImage.h:
* loader/cache/CachedRawResource.cpp:
(WebCore::CachedRawResource::calculateIncrementalDataChunk):
Returns a pointer to the data corresponding to the current chunk
and its length.
(WebCore::CachedRawResource::addDataBuffer): Assert to make sure
this is only called when BufferData option is present. Use
calculateIncrementalDataChunk().
(WebCore::CachedRawResource::addData): Assert to make sure this is
only called when DoNotBufferData option is present.
(WebCore::CachedRawResource::finishLoading):
(WebCore::CachedRawResource::notifyClientsDataWasReceived): Helper
private function to notify the clients about data received.
* loader/cache/CachedRawResource.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::addDataBuffer):
(WebCore::CachedResource::addData):
(WebCore::CachedResource::finishLoading):
* loader/cache/CachedResource.h:
* loader/cache/CachedSVGDocument.cpp:
(WebCore::CachedSVGDocument::finishLoading):
* loader/cache/CachedSVGDocument.h:
* loader/cache/CachedScript.cpp:
(WebCore::CachedScript::finishLoading):
* loader/cache/CachedScript.h:
* loader/cache/CachedShader.cpp:
(WebCore::CachedShader::finishLoading):
* loader/cache/CachedShader.h:
* loader/cache/CachedTextTrack.cpp:
(WebCore::CachedTextTrack::addDataBuffer):
(WebCore::CachedTextTrack::finishLoading):
* loader/cache/CachedTextTrack.h:
* loader/cache/CachedXSLStyleSheet.cpp:
(WebCore::CachedXSLStyleSheet::finishLoading):
* loader/cache/CachedXSLStyleSheet.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@151586 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
Source/WebCore/ChangeLog
Source/WebCore/html/ImageDocument.cpp
Source/WebCore/loader/SubresourceLoader.cpp
Source/WebCore/loader/SubresourceLoader.h
Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
Source/WebCore/loader/cache/CachedCSSStyleSheet.h
Source/WebCore/loader/cache/CachedFont.cpp
Source/WebCore/loader/cache/CachedFont.h
Source/WebCore/loader/cache/CachedImage.cpp
Source/WebCore/loader/cache/CachedImage.h
Source/WebCore/loader/cache/CachedRawResource.cpp
Source/WebCore/loader/cache/CachedRawResource.h
Source/WebCore/loader/cache/CachedResource.cpp
Source/WebCore/loader/cache/CachedResource.h
Source/WebCore/loader/cache/CachedSVGDocument.cpp
Source/WebCore/loader/cache/CachedSVGDocument.h
Source/WebCore/loader/cache/CachedScript.cpp
Source/WebCore/loader/cache/CachedScript.h
Source/WebCore/loader/cache/CachedShader.cpp
Source/WebCore/loader/cache/CachedShader.h
Source/WebCore/loader/cache/CachedTextTrack.cpp
Source/WebCore/loader/cache/CachedTextTrack.h
Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
Source/WebCore/loader/cache/CachedXSLStyleSheet.h

index c9b89f3..25e90a2 100644 (file)
@@ -1,3 +1,102 @@
+2013-06-13  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        Avoid unnecessary data copies when loading subresources with DoNotBufferData option
+        https://bugs.webkit.org/show_bug.cgi?id=115804
+
+        Reviewed by Darin Adler.
+
+        When DoNotBufferData option is used to load a resource its data
+        is always copied before sending it to the CachedResource. Most
+        of the cached resources ignore the incremental data and wait
+        until all data has been received to save the ResourceBuffer,
+        that will be NULL anyway when DoNotBufferData is used.
+        CachedRawResource notifies its clients about the incremental
+        data, but it doesn't save the data when DoNotBufferData option
+        is present. In those cases we are unnecessary copying the data.
+
+        CachedResource::data has been split into
+        CachedResource::addDataBuffer() used for incremental data chunks
+        when buffering data, CachedResource::addData() used for
+        incremental data chunks when not buffering and
+        CachedResource::finishLoading() used to finish the loading. This
+        way we get rid of the allDataReceived boolean parameter and cached
+        resources not interested in incremenetal data chunks only have to
+        implement finishLoading() without having to check if all data have
+        been received or not.
+
+        SubresourceLoader::sendDataToResource was always called after
+        checking if loading multipart content, and then it was checked
+        again to decided whether to copy the data or not. It has been
+        removed in favor of calling directly the resource methods,
+        finishLoading for multipart content, addDataBuffer for data chunks
+        when buffering and addData for data chunks when not buffering.
+
+        No new functionality, covered by existing tests.
+
+        * html/ImageDocument.cpp:
+        (WebCore::ImageDocumentParser::appendBytes): Update to API changes.
+        (WebCore::ImageDocumentParser::finish): Ditto.
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::didReceiveResponse): Call
+        finishLoading() for multipart content.
+        (WebCore::SubresourceLoader::didReceiveDataOrBuffer): Add data to
+        the resource using addDataBuffer or addData depending on whether
+        we are buffering or not.
+        (WebCore::SubresourceLoader::didFinishLoading): Call
+        finishLoading() for the cached resource instead of data.
+        * loader/SubresourceLoader.h:
+        * loader/cache/CachedCSSStyleSheet.cpp:
+        (WebCore::CachedCSSStyleSheet::finishLoading):
+        * loader/cache/CachedCSSStyleSheet.h:
+        * loader/cache/CachedFont.cpp:
+        (WebCore::CachedFont::finishLoading):
+        * loader/cache/CachedFont.h:
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::isValidDecodedImageSize): Helper function
+        to check if the image size is valid.
+        (WebCore::CachedImage::addIncrementalDataBuffer): Helper function
+        to add incremental data buffer.
+        (WebCore::CachedImage::addDataBuffer): Call
+        addIncrementalDataBuffer().
+        (WebCore::CachedImage::addData): Create a ResourceBuffer and call
+        addIncrementalDataBuffer().
+        (WebCore::CachedImage::finishLoading):
+        * loader/cache/CachedImage.h:
+        * loader/cache/CachedRawResource.cpp:
+        (WebCore::CachedRawResource::calculateIncrementalDataChunk):
+        Returns a pointer to the data corresponding to the current chunk
+        and its length.
+        (WebCore::CachedRawResource::addDataBuffer): Assert to make sure
+        this is only called when BufferData option is present. Use
+        calculateIncrementalDataChunk().
+        (WebCore::CachedRawResource::addData): Assert to make sure this is
+        only called when DoNotBufferData option is present.
+        (WebCore::CachedRawResource::finishLoading):
+        (WebCore::CachedRawResource::notifyClientsDataWasReceived): Helper
+        private function to notify the clients about data received.
+        * loader/cache/CachedRawResource.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::addDataBuffer):
+        (WebCore::CachedResource::addData):
+        (WebCore::CachedResource::finishLoading):
+        * loader/cache/CachedResource.h:
+        * loader/cache/CachedSVGDocument.cpp:
+        (WebCore::CachedSVGDocument::finishLoading):
+        * loader/cache/CachedSVGDocument.h:
+        * loader/cache/CachedScript.cpp:
+        (WebCore::CachedScript::finishLoading):
+        * loader/cache/CachedScript.h:
+        * loader/cache/CachedShader.cpp:
+        (WebCore::CachedShader::finishLoading):
+        * loader/cache/CachedShader.h:
+        * loader/cache/CachedTextTrack.cpp:
+        (WebCore::CachedTextTrack::addDataBuffer):
+        (WebCore::CachedTextTrack::finishLoading):
+        * loader/cache/CachedTextTrack.h:
+        * loader/cache/CachedXSLStyleSheet.cpp:
+        (WebCore::CachedXSLStyleSheet::finishLoading):
+        * loader/cache/CachedXSLStyleSheet.h:
+
 2013-06-14  Michał Pakuła vel Rutka  <m.pakula@samsung.com>
 
         [EFL] Fix build when DRAG_SUPPORT is set OFF
index 2b592bc..444bdb7 100644 (file)
@@ -136,7 +136,7 @@ void ImageDocumentParser::appendBytes(DocumentWriter*, const char*, size_t)
 
     CachedImage* cachedImage = document()->cachedImage();
     RefPtr<ResourceBuffer> resourceData = frame->loader()->documentLoader()->mainResourceData();
-    cachedImage->data(resourceData.get(), false);
+    cachedImage->addDataBuffer(resourceData.get());
 
     document()->imageUpdated();
 }
@@ -152,7 +152,7 @@ void ImageDocumentParser::finish()
         if (document()->frame()->loader()->documentLoader()->isLoadingMultipartContent())
             data = data->copy();
 
-        cachedImage->data(data.get(), true);
+        cachedImage->finishLoading(data.get());
         cachedImage->finish();
 
         cachedImage->setResponse(document()->frame()->loader()->documentLoader()->response());
index 9c1f0a2..f4fe72b 100644 (file)
@@ -205,7 +205,7 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
 
     RefPtr<ResourceBuffer> buffer = resourceData();
     if (m_loadingMultipartContent && buffer && buffer->size()) {
-        sendDataToResource(buffer->data(), buffer->size());
+        m_resource->finishLoading(buffer.get());
         clearResourceData();
         // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.        
         // After the first multipart section is complete, signal to delegates that this load is "finished" 
@@ -240,8 +240,12 @@ void SubresourceLoader::didReceiveDataOrBuffer(const char* data, int length, Pas
     
     ResourceLoader::didReceiveDataOrBuffer(data, length, buffer, encodedDataLength, dataPayloadType);
 
-    if (!m_loadingMultipartContent)
-        sendDataToResource(buffer ? buffer->data() : data, buffer ? buffer->size() : length);
+    if (!m_loadingMultipartContent) {
+        if (ResourceBuffer* resourceData = this->resourceData())
+            m_resource->addDataBuffer(resourceData);
+        else
+            m_resource->addData(buffer ? buffer->data() : data, buffer ? buffer->size() : length);
+    }
 }
 
 bool SubresourceLoader::checkForHTTPStatusCodeError()
@@ -256,21 +260,6 @@ bool SubresourceLoader::checkForHTTPStatusCodeError()
     return true;
 }
 
-void SubresourceLoader::sendDataToResource(const char* data, int length)
-{
-    // There are two cases where we might need to create our own SharedBuffer instead of copying the one in ResourceLoader. 
-    // (1) Multipart content: The loader delivers the data in a multipart section all at once, then sends eof. 
-    //     The resource data will change as the next part is loaded, so we need to make a copy. 
-    // (2) Our client requested that the data not be buffered at the ResourceLoader level via ResourceLoaderOptions. In this case, 
-    //     ResourceLoader::resourceData() will be null. However, unlike the multipart case, we don't want to tell the CachedResource 
-    //     that all data has been received yet. 
-    if (m_loadingMultipartContent || !resourceData()) { 
-        RefPtr<ResourceBuffer> copiedData = ResourceBuffer::create(data, length); 
-        m_resource->data(copiedData.get(), m_loadingMultipartContent);
-    } else 
-        m_resource->data(resourceData(), false);
-}
-
 void SubresourceLoader::didFinishLoading(double finishTime)
 {
     if (m_state != Initialized)
@@ -285,7 +274,7 @@ void SubresourceLoader::didFinishLoading(double finishTime)
     m_state = Finishing;
     m_activityAssertion.clear();
     m_resource->setLoadFinishTime(finishTime);
-    m_resource->data(resourceData(), true);
+    m_resource->finishLoading(resourceData());
 
     if (wasCancelled())
         return;
index 1cc4cae..a4a8d1c 100644 (file)
@@ -74,7 +74,6 @@ private:
     virtual void releaseResources() OVERRIDE;
 
     bool checkForHTTPStatusCodeError();
-    void sendDataToResource(const char*, int);
 
     void didReceiveDataOrBuffer(const char*, int, PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType);
 
index c1bc438..436777e 100644 (file)
@@ -93,11 +93,8 @@ const String CachedCSSStyleSheet::sheetText(bool enforceMIMEType, bool* hasValid
     return sheetText;
 }
 
-void CachedCSSStyleSheet::data(ResourceBuffer* data, bool allDataReceived)
+void CachedCSSStyleSheet::finishLoading(ResourceBuffer* data)
 {
-    if (!allDataReceived)
-        return;
-
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
     // Decode the data to find out the encoding and keep the sheet text around during checkNotify()
index 4bf4db9..73bf787 100644 (file)
@@ -55,7 +55,7 @@ namespace WebCore {
 
         virtual void setEncoding(const String&) OVERRIDE;
         virtual String encoding() const OVERRIDE;
-        virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+        virtual void finishLoading(ResourceBuffer*) OVERRIDE;
         virtual void destroyDecodedData() OVERRIDE;
 
     protected:
index f6e47b4..969b949 100644 (file)
@@ -75,11 +75,8 @@ void CachedFont::didAddClient(CachedResourceClient* c)
         static_cast<CachedFontClient*>(c)->fontLoaded(this);
 }
 
-void CachedFont::data(ResourceBuffer* data, bool allDataReceived)
+void CachedFont::finishLoading(ResourceBuffer* data)
 {
-    if (!allDataReceived)
-        return;
-
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
     setLoading(false);
index 8ad81ab..fae0039 100644 (file)
@@ -63,7 +63,7 @@ private:
     virtual void load(CachedResourceLoader*, const ResourceLoaderOptions&) OVERRIDE;
 
     virtual void didAddClient(CachedResourceClient*) OVERRIDE;
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 
     virtual void allClientsRemoved() OVERRIDE;
 
index 63829f3..77158fe 100644 (file)
@@ -344,56 +344,88 @@ inline void CachedImage::clearImage()
     m_image.clear();
 }
 
-size_t CachedImage::maximumDecodedImageSize()
+bool CachedImage::canBeDrawn() const
 {
+    if (!m_image || m_image->isNull())
+        return false;
+
     if (!m_loader || m_loader->reachedTerminalState())
-        return 0;
+        return true;
+
     Settings* settings = m_loader->frameLoader()->frame()->settings();
-    return settings ? settings->maximumDecodedImageSize() : 0;
+    if (!settings)
+        return true;
+
+    size_t estimatedDecodedImageSize = m_image->width() * m_image->height() * 4; // no overflow check
+    return estimatedDecodedImageSize <= settings->maximumDecodedImageSize();
 }
 
-void CachedImage::data(ResourceBuffer* data, bool allDataReceived)
+void CachedImage::addIncrementalDataBuffer(ResourceBuffer* data)
 {
     m_data = data;
+    if (!data)
+        return;
 
-    if (m_data)
-        createImage();
-
-    bool sizeAvailable = false;
+    createImage();
 
     // Have the image update its data from its internal buffer.
-    // It will not do anything now, but will delay decoding until 
+    // 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 ? m_data->sharedBuffer() : 0, 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) {
-        size_t maxDecodedImageSize = maximumDecodedImageSize();
-        IntSize s = m_image ? m_image->size() : IntSize();
-        size_t estimatedDecodedImageSize = s.width() * s.height() * 4; // no overflow check
-        if (!m_image || m_image->isNull() || (maxDecodedImageSize > 0 && estimatedDecodedImageSize > maxDecodedImageSize)) {
-            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();
+    bool sizeAvailable = m_image->setData(m_data->sharedBuffer(), false);
+    if (!sizeAvailable)
+        return;
 
-        if (m_image)
-            setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
+    if (!canBeDrawn()) {
+        // There's no image to draw or its decoded size is bigger than the maximum allowed.
+        error(errorOccurred() ? status() : DecodeError);
+        if (inCache())
+            memoryCache()->remove(this);
+        return;
     }
-    
-    if (allDataReceived) {
-        setLoading(false);
-        checkNotify();
+
+    // Go ahead and tell our observers to try to draw.
+    // Each chunk from the network causes observers to repaint, which will
+    // force that chunk to decode.
+    // 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();
+
+    setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
+}
+
+void CachedImage::addDataBuffer(ResourceBuffer* data)
+{
+    ASSERT(m_options.dataBufferingPolicy == BufferData);
+    addIncrementalDataBuffer(data);
+}
+
+void CachedImage::addData(const char* data, unsigned length)
+{
+    ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
+    addIncrementalDataBuffer(ResourceBuffer::create(data, length).get());
+}
+
+void CachedImage::finishLoading(ResourceBuffer* data)
+{
+    m_data = data;
+    if (!m_image && data)
+        createImage();
+
+    if (m_image)
+        m_image->setData(m_data->sharedBuffer(), true);
+
+    if (!canBeDrawn()) {
+        // There's no image to draw or its decoded size is bigger than the maximum allowed.
+        error(errorOccurred() ? status() : DecodeError);
+        if (inCache())
+            memoryCache()->remove(this);
+        return;
     }
+
+    notifyObservers();
+    if (m_image)
+        setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
+    CachedResource::finishLoading(data);
 }
 
 void CachedImage::error(CachedResource::Status status)
index cc56632..7edd5b5 100644 (file)
@@ -64,7 +64,8 @@ public:
     bool imageHasRelativeWidth() const;
     bool imageHasRelativeHeight() const;
 
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void addDataBuffer(ResourceBuffer*) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 
     // 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.
@@ -79,7 +80,7 @@ private:
 
     void createImage();
     void clearImage();
-    size_t maximumDecodedImageSize();
+    bool canBeDrawn() const;
     // If not null, changeRect is the changed part of the image.
     void notifyObservers(const IntRect* changeRect = 0);
     virtual PurgePriority purgePriority() const OVERRIDE { return PurgeFirst; }
@@ -94,6 +95,7 @@ private:
     virtual void allClientsRemoved() OVERRIDE;
     virtual void destroyDecodedData() OVERRIDE;
 
+    virtual void addData(const char* data, unsigned length) OVERRIDE;
     virtual void error(CachedResource::Status) OVERRIDE;
     virtual void responseReceived(const ResourceResponse&) OVERRIDE;
 
@@ -111,6 +113,8 @@ private:
     virtual void animationAdvanced(const Image*) OVERRIDE;
     virtual void changedInRect(const Image*, const IntRect&) OVERRIDE;
 
+    void addIncrementalDataBuffer(ResourceBuffer*);
+
     typedef pair<IntSize, float> SizeAndZoom;
     typedef HashMap<const CachedImageClient*, SizeAndZoom> ContainerSizeRequests;
     ContainerSizeRequests m_pendingContainerSizeRequests;
index f8086c1..44128d1 100644 (file)
@@ -41,35 +41,57 @@ CachedRawResource::CachedRawResource(ResourceRequest& resourceRequest, Type type
 {
 }
 
-void CachedRawResource::data(ResourceBuffer* data, bool allDataReceived)
+const char* CachedRawResource::calculateIncrementalDataChunk(ResourceBuffer* data, unsigned& incrementalDataLength)
+{
+    incrementalDataLength = 0;
+    if (!data)
+        return 0;
+
+    unsigned previousDataLength = encodedSize();
+    ASSERT(data->size() >= previousDataLength);
+    incrementalDataLength = data->size() - previousDataLength;
+    return data->data() + previousDataLength;
+}
+
+void CachedRawResource::addDataBuffer(ResourceBuffer* data)
 {
     CachedResourceHandle<CachedRawResource> protect(this);
-    const char* incrementalData = 0;
-    size_t incrementalDataLength = 0;
-    if (data) {
-        // If we are buffering data, then we are saving the buffer in m_data and need to manually
-        // calculate the incremental data. If we are not buffering, then m_data will be null and
-        // the buffer contains only the incremental data.
-        size_t previousDataLength = (m_options.dataBufferingPolicy == BufferData) ? encodedSize() : 0;
-        ASSERT(data->size() >= previousDataLength);
-        incrementalData = data->data() + previousDataLength;
-        incrementalDataLength = data->size() - previousDataLength;
-    }
+    ASSERT(m_options.dataBufferingPolicy == BufferData);
+    m_data = data;
 
-    if (m_options.dataBufferingPolicy == BufferData) {
-        if (data)
-            setEncodedSize(data->size());
-        m_data = data;
+    unsigned incrementalDataLength;
+    const char* incrementalData = calculateIncrementalDataChunk(data, incrementalDataLength);
+    if (data)
+        setEncodedSize(data->size());
+    notifyClientsDataWasReceived(incrementalData, incrementalDataLength);
+    if (m_options.dataBufferingPolicy == DoNotBufferData) {
+        if (m_loader)
+            m_loader->setDataBufferingPolicy(DoNotBufferData);
+        clear();
     }
+}
 
+void CachedRawResource::addData(const char* data, unsigned length)
+{
+    ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
+    notifyClientsDataWasReceived(data, length);
+}
+
+void CachedRawResource::finishLoading(ResourceBuffer* data)
+{
+    CachedResourceHandle<CachedRawResource> protect(this);
     DataBufferingPolicy dataBufferingPolicy = m_options.dataBufferingPolicy;
-    if (incrementalDataLength) {
-        CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
-        while (CachedRawResourceClient* c = w.next())
-            c->dataReceived(this, incrementalData, incrementalDataLength);
+    if (dataBufferingPolicy == BufferData) {
+        m_data = data;
+
+        unsigned incrementalDataLength;
+        const char* incrementalData = calculateIncrementalDataChunk(data, incrementalDataLength);
+        if (data)
+            setEncodedSize(data->size());
+        notifyClientsDataWasReceived(incrementalData, incrementalDataLength);
     }
-    CachedResource::data(data, allDataReceived);
 
+    CachedResource::finishLoading(data);
     if (dataBufferingPolicy == BufferData && m_options.dataBufferingPolicy == DoNotBufferData) {
         if (m_loader)
             m_loader->setDataBufferingPolicy(DoNotBufferData);
@@ -77,6 +99,17 @@ void CachedRawResource::data(ResourceBuffer* data, bool allDataReceived)
     }
 }
 
+void CachedRawResource::notifyClientsDataWasReceived(const char* data, unsigned length)
+{
+    if (!length)
+        return;
+
+    CachedResourceHandle<CachedRawResource> protect(this);
+    CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
+    while (CachedRawResourceClient* c = w.next())
+        c->dataReceived(this, data, length);
+}
+
 void CachedRawResource::didAddClient(CachedResourceClient* c)
 {
     if (!hasClient(c))
index 5ef50b0..15eb670 100644 (file)
@@ -48,7 +48,9 @@ public:
 
 private:
     virtual void didAddClient(CachedResourceClient*) OVERRIDE;
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void addDataBuffer(ResourceBuffer*) OVERRIDE;
+    virtual void addData(const char* data, unsigned length) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 
     virtual bool shouldIgnoreHTTPStatusCodeErrors() const OVERRIDE { return true; }
     virtual void allClientsRemoved() OVERRIDE;
@@ -62,6 +64,9 @@ private:
 
     virtual bool canReuse(const ResourceRequest&) const OVERRIDE;
 
+    const char* calculateIncrementalDataChunk(ResourceBuffer*, unsigned& incrementalDataLength);
+    void notifyClientsDataWasReceived(const char* data, unsigned length);
+
     unsigned long m_identifier;
 
     struct RedirectPair {
index 2ef2bc1..3db92ab 100644 (file)
@@ -362,11 +362,18 @@ void CachedResource::checkNotify()
         c->notifyFinished(this);
 }
 
-void CachedResource::data(ResourceBuffer*, bool allDataReceived)
+void CachedResource::addDataBuffer(ResourceBuffer*)
+{
+    ASSERT(m_options.dataBufferingPolicy == BufferData);
+}
+
+void CachedResource::addData(const char*, unsigned)
+{
+    ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
+}
+
+void CachedResource::finishLoading(ResourceBuffer*)
 {
-    if (!allDataReceived)
-        return;
-    
     setLoading(false);
     checkNotify();
 }
index 9e9e655..eacbfdb 100644 (file)
@@ -101,7 +101,9 @@ public:
 
     virtual void setEncoding(const String&) { }
     virtual String encoding() const { return String(); }
-    virtual void data(ResourceBuffer*, bool allDataReceived);
+    virtual void addDataBuffer(ResourceBuffer*);
+    virtual void addData(const char* data, unsigned length);
+    virtual void finishLoading(ResourceBuffer*);
     virtual void error(CachedResource::Status);
 
     void setResourceError(const ResourceError& error) { m_error = error; }
index 6720b98..1594626 100644 (file)
@@ -53,11 +53,8 @@ String CachedSVGDocument::encoding() const
     return m_decoder->encoding().name();
 }
 
-void CachedSVGDocument::data(ResourceBuffer* data, bool allDataReceived)
+void CachedSVGDocument::finishLoading(ResourceBuffer* data)
 {
-    if (!allDataReceived)
-        return;
-
     if (data) {
         StringBuilder decodedText;
         decodedText.append(m_decoder->decode(data->data(), data->size()));
@@ -66,9 +63,7 @@ void CachedSVGDocument::data(ResourceBuffer* data, bool allDataReceived)
         m_document = SVGDocument::create(0, response().url());
         m_document->setContent(decodedText.toString());
     }
-
-    setLoading(false);
-    checkNotify();
+    CachedResource::finishLoading(data);
 }
 
 }
index baf9c63..b57f9d6 100644 (file)
@@ -46,7 +46,7 @@ private:
     virtual bool mayTryReplaceEncodedData() const OVERRIDE { return true; }
     virtual void setEncoding(const String&) OVERRIDE;
     virtual String encoding() const OVERRIDE;
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 };
 
 } // namespace WebCore
index 42e1228..e73fe54 100644 (file)
@@ -82,15 +82,11 @@ const String& CachedScript::script()
     return m_script;
 }
 
-void CachedScript::data(ResourceBuffer* data, bool allDataReceived)
+void CachedScript::finishLoading(ResourceBuffer* data)
 {
-    if (!allDataReceived)
-        return;
-
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
-    setLoading(false);
-    checkNotify();
+    CachedResource::finishLoading(data);
 }
 
 void CachedScript::destroyDecodedData()
index 1e8e906..733b535 100644 (file)
@@ -54,7 +54,7 @@ namespace WebCore {
 
         virtual void setEncoding(const String&) OVERRIDE;
         virtual String encoding() const OVERRIDE;
-        virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+        virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 
         virtual void destroyDecodedData() OVERRIDE;
 
index 8ce37f2..a5748fe 100644 (file)
@@ -60,11 +60,10 @@ const String& CachedShader::shaderString()
     return m_shaderString;
 }
 
-void CachedShader::data(ResourceBuffer* data, bool allDataReceived)
+void CachedShader::finishLoading(ResourceBuffer* data)
 {
-    if (allDataReceived)
-        m_data = data;
-    CachedResource::data(data, allDataReceived);
+    m_data = data;
+    CachedResource::finishLoading(0);
 }
 
 } // namespace WebCore
index 3292285..23c898a 100644 (file)
@@ -47,7 +47,7 @@ public:
 
 private:
     virtual bool mayTryReplaceEncodedData() const OVERRIDE { return true; }
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 
     RefPtr<TextResourceDecoder> m_decoder;
     String m_shaderString;
index 8634156..94974a5 100644 (file)
@@ -48,20 +48,21 @@ CachedTextTrack::~CachedTextTrack()
 {
 }
 
-void CachedTextTrack::data(ResourceBuffer* data, bool allDataReceived)
+void CachedTextTrack::addDataBuffer(ResourceBuffer* data)
 {
+    ASSERT(m_options.dataBufferingPolicy == BufferData);
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
 
     CachedResourceClientWalker<CachedResourceClient> walker(m_clients);
     while (CachedResourceClient *client = walker.next())
         client->deprecatedDidReceiveCachedResource(this);
+}
 
-    if (!allDataReceived)
-        return;
-    
-    setLoading(false);
-    checkNotify();
+void CachedTextTrack::finishLoading(ResourceBuffer* data)
+{
+    addDataBuffer(data);
+    CachedResource::finishLoading(data);
 }
 
 }
index 8ae8620..e0a85ca 100644 (file)
@@ -40,7 +40,8 @@ public:
 
 private:
     virtual bool mayTryReplaceEncodedData() const OVERRIDE { return true; }
-    virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+    virtual void addDataBuffer(ResourceBuffer*) OVERRIDE;
+    virtual void finishLoading(ResourceBuffer*) OVERRIDE;
 };
 
 }
index e5ae41a..eb6c8e1 100644 (file)
@@ -63,11 +63,8 @@ String CachedXSLStyleSheet::encoding() const
     return m_decoder->encoding().name();
 }
 
-void CachedXSLStyleSheet::data(ResourceBuffer* data, bool allDataReceived)
+void CachedXSLStyleSheet::finishLoading(ResourceBuffer* data)
 {
-    if (!allDataReceived)
-        return;
-
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
     if (m_data.get()) {
index 8b7374e..264d663 100644 (file)
@@ -54,7 +54,7 @@ namespace WebCore {
 
         virtual void setEncoding(const String&) OVERRIDE;
         virtual String encoding() const OVERRIDE;
-        virtual void data(ResourceBuffer*, bool allDataReceived) OVERRIDE;
+        virtual void finishLoading(ResourceBuffer*) OVERRIDE;
     };
 
 #endif