TEST(ImageResourceTest, DecodedDataRemainsWhileHasClients) { ImageResource* cachedImage = ImageResource::create(ResourceRequest()); cachedImage->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); // Send the image response. cachedImage->responseReceived(ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()), nullptr); Vector<unsigned char> jpeg = jpegImage(); cachedImage->responseReceived(ResourceResponse(KURL(), "image/jpeg", jpeg.size(), nullAtom, String()), nullptr); cachedImage->appendData(reinterpret_cast<const char*>(jpeg.data()), jpeg.size()); cachedImage->finish(); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->getImage()->isNull()); ASSERT_TRUE(client->notifyFinishedCalled()); // The prune comes when the ImageResource still has clients. The image should not be deleted. cachedImage->prune(); ASSERT_TRUE(cachedImage->hasClientsOrObservers()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->getImage()->isNull()); // The ImageResource no longer has clients. The image should be deleted by prune. client->removeAsClient(); cachedImage->prune(); ASSERT_FALSE(cachedImage->hasClientsOrObservers()); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_TRUE(cachedImage->getImage()->isNull()); }
LayoutReplaced* LayoutImage::embeddedReplacedContent() const { if (!m_imageResource) return nullptr; ImageResource* cachedImage = m_imageResource->cachedImage(); if (cachedImage && cachedImage->getImage() && cachedImage->getImage()->isSVGImage()) return toSVGImage(cachedImage->getImage())->embeddedReplacedContent(); return nullptr; }
TEST(ImageResourceTest, FailedRevalidationSvgToSvg) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo"); ImageResource* imageResource = ImageResource::create(ResourceRequest(url)); Persistent<MockImageResourceClient> client = new MockImageResourceClient(imageResource); receiveResponse(imageResource, url, "image/svg+xml", svgImage()); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(client->imageChangedCount(), 1); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_FALSE(imageResource->getImage()->isBitmapImage()); EXPECT_EQ(200, imageResource->getImage()->width()); EXPECT_EQ(200, imageResource->getImage()->height()); imageResource->setRevalidatingRequest(ResourceRequest(url)); receiveResponse(imageResource, url, "image/svg+xml", svgImage2()); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(2, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_FALSE(imageResource->getImage()->isBitmapImage()); EXPECT_EQ(300, imageResource->getImage()->width()); EXPECT_EQ(300, imageResource->getImage()->height()); }
TEST(ImageResourceTest, SuccessfulRevalidationSvg) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo"); ImageResource* imageResource = ImageResource::create(ResourceRequest(url)); Persistent<MockImageResourceClient> client = new MockImageResourceClient(imageResource); receiveResponse(imageResource, url, "image/svg+xml", svgImage()); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_FALSE(imageResource->getImage()->isBitmapImage()); EXPECT_EQ(200, imageResource->getImage()->width()); EXPECT_EQ(200, imageResource->getImage()->height()); imageResource->setRevalidatingRequest(ResourceRequest(url)); ResourceResponse response; response.setURL(url); response.setHTTPStatusCode(304); imageResource->responseReceived(response, nullptr); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_FALSE(imageResource->getImage()->isBitmapImage()); EXPECT_EQ(200, imageResource->getImage()->width()); EXPECT_EQ(200, imageResource->getImage()->height()); }
TEST(ImageResourceTest, SVGImage) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo"); ImageResource* imageResource = ImageResource::create(ResourceRequest(url)); Persistent<MockImageResourceClient> client = new MockImageResourceClient(imageResource); receiveResponse(imageResource, url, "image/svg+xml", svgImage()); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_FALSE(imageResource->getImage()->isBitmapImage()); }
static void writeImageToDataObject(DataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file ImageResource* cachedImage = getImageResource(element); if (!cachedImage || !cachedImage->getImage() || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->getImage()->data(); if (!imageBuffer || !imageBuffer->size()) return; String imageExtension = cachedImage->getImage()->filenameExtension(); ASSERT(!imageExtension.isEmpty()); // Determine the filename for the file contents of the image. String filename = cachedImage->response().suggestedFilename(); if (filename.isEmpty()) filename = url.lastPathComponent(); String fileExtension; if (filename.isEmpty()) { filename = element->getAttribute(HTMLNames::altAttr); } else { // Strip any existing extension. Assume that alt text is usually not a filename. int extensionIndex = filename.reverseFind('.'); if (extensionIndex != -1) { fileExtension = filename.substring(extensionIndex + 1); filename.truncate(extensionIndex); } } if (!fileExtension.isEmpty() && fileExtension != imageExtension) { String imageMimeType = MIMETypeRegistry::getMIMETypeForExtension(imageExtension); ASSERT(imageMimeType.startsWith("image/")); // Use the file extension only if it has imageMimeType: it's untrustworthy otherwise. if (imageMimeType == MIMETypeRegistry::getMIMETypeForExtension(fileExtension)) imageExtension = fileExtension; } imageExtension = "." + imageExtension; validateFilename(filename, imageExtension); dataObject->addSharedBuffer(filename + imageExtension, imageBuffer); }
TEST(ImageResourceTest, UpdateBitmapImages) { ImageResource* cachedImage = ImageResource::create(ResourceRequest()); cachedImage->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); // Send the image response. Vector<unsigned char> jpeg = jpegImage(); cachedImage->responseReceived(ResourceResponse(KURL(), "image/jpeg", jpeg.size(), nullAtom, String()), nullptr); cachedImage->appendData(reinterpret_cast<const char*>(jpeg.data()), jpeg.size()); cachedImage->finish(); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->getImage()->isNull()); ASSERT_EQ(client->imageChangedCount(), 2); ASSERT_TRUE(client->notifyFinishedCalled()); ASSERT_TRUE(cachedImage->getImage()->isBitmapImage()); }
TEST(ImageResourceTest, AddClientAfterPrune) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo"); ImageResource* imageResource = ImageResource::create(ResourceRequest(url)); // Adds a ResourceClient but not ImageResourceObserver. Persistent<MockResourceClient> client1 = new MockResourceClient(imageResource); receiveResponse(imageResource, url, "image/jpeg", jpegImage()); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, imageResource->getImage()->width()); EXPECT_EQ(1, imageResource->getImage()->height()); EXPECT_TRUE(client1->notifyFinishedCalled()); client1->removeAsClient(); EXPECT_FALSE(imageResource->isAlive()); imageResource->prune(); EXPECT_TRUE(imageResource->hasImage()); // Re-adds a ResourceClient but not ImageResourceObserver. Persistent<MockResourceClient> client2 = new MockResourceClient(imageResource); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, imageResource->getImage()->width()); EXPECT_EQ(1, imageResource->getImage()->height()); EXPECT_TRUE(client2->notifyFinishedCalled()); }
// Verifies that ImageBitmaps constructed from HTMLImageElements hold a reference to the original Image if the HTMLImageElement src is changed. TEST_F(ImageBitmapTest, ImageBitmapSourceChanged) { HTMLImageElement* image = HTMLImageElement::create(*Document::create()); ImageResource* originalImageResource = ImageResource::create( StaticBitmapImage::create(m_image).get()); image->setImageResource(originalImageResource); const ImageBitmapOptions defaultOptions; ImageBitmap* imageBitmap = ImageBitmap::create(image, IntRect(0, 0, m_image->width(), m_image->height()), &(image->document()), defaultOptions); ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), originalImageResource->getImage()->imageForCurrentFrame()); ImageResource* newImageResource = ImageResource::create( StaticBitmapImage::create(m_image2).get()); image->setImageResource(newImageResource); // The ImageBitmap should contain the same data as the original cached image { ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), originalImageResource->getImage()->imageForCurrentFrame()); SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get(); ASSERT_NE(image1, nullptr); SkImage* image2 = originalImageResource->getImage()->imageForCurrentFrame().get(); ASSERT_NE(image2, nullptr); ASSERT_EQ(image1, image2); } { ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(), newImageResource->getImage()->imageForCurrentFrame()); SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get(); ASSERT_NE(image1, nullptr); SkImage* image2 = newImageResource->getImage()->imageForCurrentFrame().get(); ASSERT_NE(image2, nullptr); ASSERT_NE(image1, image2); } }
TEST(ImageResourceTest, ReloadIfLoFi) { KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); URLTestHelpers::registerMockedURLLoad(testURL, "cancelTest.html", "text/html"); ResourceRequest request = ResourceRequest(testURL); request.setLoFiState(WebURLRequest::LoFiOn); ImageResource* cachedImage = ImageResource::create(request); cachedImage->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); // Send the image response. Vector<unsigned char> jpeg = jpegImage(); ResourceResponse resourceResponse(KURL(), "image/jpeg", jpeg.size(), nullAtom, String()); resourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); cachedImage->responseReceived(resourceResponse, nullptr); cachedImage->appendData(reinterpret_cast<const char*>(jpeg.data()), jpeg.size()); cachedImage->finish(); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->getImage()->isNull()); ASSERT_EQ(client->imageChangedCount(), 2); ASSERT_TRUE(client->notifyFinishedCalled()); ASSERT_TRUE(cachedImage->getImage()->isBitmapImage()); EXPECT_EQ(1, cachedImage->getImage()->width()); EXPECT_EQ(1, cachedImage->getImage()->height()); cachedImage->reloadIfLoFi(fetcher); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_FALSE(cachedImage->resourceBuffer()); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_EQ(client->imageChangedCount(), 3); cachedImage->loader()->didReceiveResponse(nullptr, WrappedResourceResponse(resourceResponse), nullptr); cachedImage->loader()->didReceiveData(nullptr, reinterpret_cast<const char*>(jpeg.data()), jpeg.size(), jpeg.size()); cachedImage->loader()->didFinishLoading(nullptr, 0.0, jpeg.size()); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->getImage()->isNull()); ASSERT_TRUE(client->notifyFinishedCalled()); ASSERT_TRUE(cachedImage->getImage()->isBitmapImage()); }
TEST(ImageResourceTest, AddClientAfterPrune) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo"); ImageResource* imageResource = ImageResource::create(ResourceRequest(url)); // Adds a ResourceClient but not ImageResourceObserver. Persistent<MockResourceClient> client1 = new MockResourceClient(imageResource); Vector<unsigned char> jpeg = jpegImage(); ResourceResponse response; response.setURL(url); response.setHTTPStatusCode(200); response.setMimeType("image/jpeg"); imageResource->responseReceived(response, nullptr); imageResource->appendData(reinterpret_cast<const char*>(jpeg.data()), jpeg.size()); imageResource->finish(); EXPECT_FALSE(imageResource->errorOccurred()); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, imageResource->getImage()->width()); EXPECT_EQ(1, imageResource->getImage()->height()); EXPECT_TRUE(client1->notifyFinishedCalled()); client1->removeAsClient(); EXPECT_FALSE(imageResource->hasClientsOrObservers()); imageResource->prune(); EXPECT_FALSE(imageResource->hasImage()); // Re-adds a ResourceClient but not ImageResourceObserver. Persistent<MockResourceClient> client2 = new MockResourceClient(imageResource); ASSERT_TRUE(imageResource->hasImage()); EXPECT_FALSE(imageResource->getImage()->isNull()); EXPECT_EQ(1, imageResource->getImage()->width()); EXPECT_EQ(1, imageResource->getImage()->height()); EXPECT_TRUE(client2->notifyFinishedCalled()); }
TEST(ImageResourceTest, ReloadIfLoFiDuringFetch) { KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); ScopedRegisteredURL scopedRegisteredURL(testURL); ResourceRequest request(testURL); request.setLoFiState(WebURLRequest::LoFiOn); FetchRequest fetchRequest(request, FetchInitiatorInfo()); ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); ImageResource* cachedImage = ImageResource::fetch(fetchRequest, fetcher); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); // Send the image response. Vector<unsigned char> jpeg = jpegImage(); ResourceResponse initialResourceResponse(testURL, "image/jpeg", jpeg.size(), nullAtom, String()); initialResourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); cachedImage->loader()->didReceiveResponse( nullptr, WrappedResourceResponse(initialResourceResponse)); cachedImage->loader()->didReceiveData( nullptr, reinterpret_cast<const char*>(jpeg.data()), jpeg.size(), jpeg.size(), jpeg.size()); EXPECT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); EXPECT_FALSE(cachedImage->getImage()->isNull()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_EQ(jpeg.size(), client->encodedSizeOnLastImageChanged()); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_TRUE(cachedImage->getImage()->isBitmapImage()); EXPECT_EQ(1, cachedImage->getImage()->width()); EXPECT_EQ(1, cachedImage->getImage()->height()); // Call reloadIfLoFi() while the image is still loading. cachedImage->reloadIfLoFi(fetcher); EXPECT_FALSE(cachedImage->errorOccurred()); EXPECT_FALSE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(2, client->imageChangedCount()); EXPECT_EQ(0U, client->encodedSizeOnLastImageChanged()); // The client should not have been notified of completion yet, since the image // is still loading. EXPECT_FALSE(client->notifyFinishedCalled()); Vector<unsigned char> jpeg2 = jpegImage2(); cachedImage->loader()->didReceiveResponse( nullptr, WrappedResourceResponse(ResourceResponse( testURL, "image/jpeg", jpeg.size(), nullAtom, String())), nullptr); cachedImage->loader()->didReceiveData( nullptr, reinterpret_cast<const char*>(jpeg2.data()), jpeg2.size(), jpeg2.size(), jpeg2.size()); cachedImage->loader()->didFinishLoading(nullptr, 0.0, jpeg2.size()); EXPECT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); EXPECT_FALSE(cachedImage->getImage()->isNull()); EXPECT_EQ(jpeg2.size(), client->encodedSizeOnLastImageChanged()); // The client should have been notified of completion only after the reload // completed. EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(jpeg2.size(), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(jpeg2.size(), client->encodedSizeOnImageNotifyFinished()); EXPECT_TRUE(cachedImage->getImage()->isBitmapImage()); EXPECT_EQ(50, cachedImage->getImage()->width()); EXPECT_EQ(50, cachedImage->getImage()->height()); }
TEST(ImageResourceTest, MultipartImage) { ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); ScopedRegisteredURL scopedRegisteredURL(testURL); // Emulate starting a real load, but don't expect any "real" // WebURLLoaderClient callbacks. ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); cachedImage->setIdentifier(createUniqueIdentifier()); fetcher->startLoad(cachedImage); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); // Send the multipart response. No image or data buffer is created. Note that // the response must be routed through ResourceLoader to ensure the load is // flagged as multipart. ResourceResponse multipartResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()); multipartResponse.setMultipartBoundary("boundary", strlen("boundary")); cachedImage->loader()->didReceiveResponse( nullptr, WrappedResourceResponse(multipartResponse), nullptr); EXPECT_FALSE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_EQ("multipart/x-mixed-replace", cachedImage->response().mimeType()); const char firstPart[] = "--boundary\n" "Content-Type: image/svg+xml\n\n"; cachedImage->appendData(firstPart, strlen(firstPart)); // Send the response for the first real part. No image or data buffer is // created. EXPECT_FALSE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_EQ("image/svg+xml", cachedImage->response().mimeType()); const char secondPart[] = "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect " "width='1' height='1' fill='green'/></svg>\n"; // The first bytes arrive. The data buffer is created, but no image is // created. cachedImage->appendData(secondPart, strlen(secondPart)); EXPECT_TRUE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); // Add a client to check an assertion error doesn't happen // (crbug.com/630983). Persistent<MockImageResourceClient> client2 = new MockImageResourceClient(cachedImage); EXPECT_EQ(0, client2->imageChangedCount()); EXPECT_FALSE(client2->notifyFinishedCalled()); const char thirdPart[] = "--boundary"; cachedImage->appendData(thirdPart, strlen(thirdPart)); ASSERT_TRUE(cachedImage->resourceBuffer()); EXPECT_EQ(strlen(secondPart) - 1, cachedImage->resourceBuffer()->size()); // This part finishes. The image is created, callbacks are sent, and the data // buffer is cleared. cachedImage->loader()->didFinishLoading(nullptr, 0.0, 0); EXPECT_TRUE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); EXPECT_FALSE(cachedImage->getImage()->isNull()); EXPECT_EQ(1, cachedImage->getImage()->width()); EXPECT_EQ(1, cachedImage->getImage()->height()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(1, client2->imageChangedCount()); EXPECT_TRUE(client2->notifyFinishedCalled()); }