void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*) { if (m_pendingSubstituteResources.isEmpty()) return; ASSERT(m_frame && m_frame->page()); if (m_frame->page()->defersLoading()) return; SubstituteResourceMap copy; copy.swap(m_pendingSubstituteResources); SubstituteResourceMap::const_iterator end = copy.end(); for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) { RefPtr<ResourceLoader> loader = it->first; SubstituteResource* resource = it->second.get(); if (resource) { SharedBuffer* data = resource->data(); loader->didReceiveResponse(resource->response()); loader->didReceiveData(data->data(), data->size(), data->size(), true); loader->didFinishLoading(); } else { // A null resource means that we should fail the load. // FIXME: Maybe we should use another error here - something like "not in cache". loader->didFail(loader->cannotShowURLError()); } } }
size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count) { SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); size_t availBytes = count; if (offset + count > sharedBuffer->size()) availBytes -= (offset + count) - sharedBuffer->size(); memcpy(buffer, sharedBuffer->data() + offset, availBytes); return availBytes; }
void TextTrackLoader::processNewCueData(CachedResource* resource) { ASSERT(m_cachedCueData == resource); if (m_state == Failed || !resource->data()) return; SharedBuffer* buffer = resource->data(); if (m_parseOffset == buffer->size()) return; const char* data; unsigned length; if (!m_cueParser) { if (resource->response().mimeType() == "text/vtt") m_cueParser = WebVTTParser::create(this, m_scriptExecutionContext); else { // Don't proceed until we have enough data to check for the WebVTT magic identifier. unsigned identifierLength = WebVTTParser::fileIdentifierMaximumLength(); if (buffer->size() < identifierLength) return; Vector<char> identifier; unsigned offset = 0; while (offset < identifierLength && (length = buffer->getSomeData(data, offset))) { if (length > identifierLength) length = identifierLength; identifier.append(data, length); offset += length; } if (!WebVTTParser::hasRequiredFileIdentifier(identifier.data(), identifier.size())) { LOG(Media, "TextTrackLoader::didReceiveData - file \"%s\" does not have WebVTT magic header", resource->response().url().string().utf8().data()); m_state = Failed; m_cueLoadTimer.startOneShot(0); return; } m_cueParser = WebVTTParser::create(this, m_scriptExecutionContext); } } ASSERT(m_cueParser); while ((length = buffer->getSomeData(data, m_parseOffset))) { m_cueParser->parseBytes(data, length); m_parseOffset += length; } }
static bool canHandleImage(const SharedBuffer& _data) { // We need at least 4 bytes to figure out what kind of image we're dealing with. if (_data.size() < 4) return false; QByteArray data = QByteArray::fromRawData(_data.data(), _data.size()); QBuffer buffer(&data); if (!buffer.open(QBuffer::ReadOnly)) return false; return !QImageReader::imageFormat(&buffer).isEmpty(); }
bool InspectorPageAgent::cachedResourceContent(Resource* cachedResource, String* result, bool* base64Encoded) { bool hasZeroSize; bool prepared = prepareResourceBuffer(cachedResource, &hasZeroSize); if (!prepared) return false; *base64Encoded = !hasTextContent(cachedResource); if (*base64Encoded) { RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer(); if (!buffer) return false; *result = base64Encode(buffer->data(), buffer->size()); return true; } if (hasZeroSize) { *result = ""; return true; } if (cachedResource) { switch (cachedResource->type()) { case Resource::CSSStyleSheet: *result = toCSSStyleSheetResource(cachedResource)->sheetText(false); return true; case Resource::Script: *result = toScriptResource(cachedResource)->script(); return true; case Resource::MainResource: return false; case Resource::Raw: { SharedBuffer* buffer = cachedResource->resourceBuffer(); if (!buffer) return false; OwnPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName()); String content = decoder->decode(buffer->data(), buffer->size()); *result = content + decoder->flush(); return true; } default: SharedBuffer* buffer = cachedResource->resourceBuffer(); return decodeBuffer(buffer ? buffer->data() : 0, buffer ? buffer->size() : 0, cachedResource->response().textEncodingName(), result); } } return false; }
SkData* ImageFrameGenerator::refEncodedData() { // SkData is returned only when full image (encoded) data is received. This is important // since DeferredImageDecoder::setData is called only once with allDataReceived set to true, // and after that m_data->m_readBuffer.data() is not changed. See also RELEASE_ASSERT used in // ThreadSafeDataTransport::data(). SharedBuffer* buffer = 0; bool allDataReceived = false; m_data->data(&buffer, &allDataReceived); if (!allDataReceived) return nullptr; { // Prevents concurrent access to m_encodedData creation. MutexLocker lock(m_decodeMutex); if (m_encodedData) { m_encodedData->ref(); return m_encodedData; } // m_encodedData is created with initial reference count == 1. ImageFrameGenerator always holds one // reference to m_encodedData, as it prevents write access in SkData::writable_data. m_encodedData = SkData::NewWithProc(buffer->data(), buffer->size(), sharedSkDataReleaseCallback, m_data.get()); // While m_encodedData is referenced, prevent disposing m_data and its content. // it is dereferenced in sharedSkDataReleaseCallback, called when m_encodedData gets dereferenced. m_data->ref(); } // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released // in destructor. m_encodedData->ref(); return m_encodedData; }
static void writeImageToDataObject( DataObjectJava* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file CachedImage* cachedImage = getCachedImage(element); if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->image()->data(); if (!imageBuffer || !imageBuffer->size()) return; dataObject->fileContent = imageBuffer; // Determine the filename for the file contents of the image. We try to // use the alt tag if one exists, otherwise we fall back on the suggested // filename in the http header, and finally we resort to using the filename // in the URL. //String title = element->getAttribute(altAttr); //if (title.isEmpty()) // title = cachedImage->response().suggestedFilename(); //TODO: do we need it? dataObject->fileContentFilename = cachedImage->response().suggestedFilename(); }
static void* ensureCapacity(void* data, size_t nmemb, size_t size) { SharedBuffer* buf; size_t currentSize; if (data != NULL) { buf = SharedBuffer::bufferFromData(data); currentSize = buf->size(); } else { buf = NULL; currentSize = 0; } size_t minSize = nmemb * size; if (minSize > currentSize) { unsigned int requestSize = roundUpPower2(minSize); if (buf == NULL) { buf = SharedBuffer::alloc(requestSize); } else { buf = buf->editResize(requestSize); } memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize); } return buf->data(); }
void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived) { if (m_actualDecoder) { const bool firstData = !m_data; const bool moreData = data.size() > m_lastDataSize; m_dataChanged = firstData || moreData; m_data = RefPtr<SharedBuffer>(data); m_lastDataSize = data.size(); m_allDataReceived = allDataReceived; m_actualDecoder->setData(&data, allDataReceived); prepareLazyDecodedFrames(); } if (m_frameGenerator) m_frameGenerator->setData(&data, allDataReceived); }
void DocLoader::checkCacheObjectStatus(CachedResource* resource) { // Return from the function for objects that we didn't load from the cache. if (!resource) return; switch (resource->status()) { case CachedResource::Cached: break; case CachedResource::NotCached: case CachedResource::Unknown: case CachedResource::New: case CachedResource::Pending: return; } // Notify the caller that we "loaded". if (!m_frame || m_frame->loader()->haveToldBridgeAboutLoad(resource->url())) return; ResourceRequest request(resource->url()); const ResourceResponse& response = resource->response(); SharedBuffer* data = resource->data(); if (resource->sendResourceLoadCallbacks()) { // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load. m_frame->loader()->loadedResourceFromMemoryCache(request, response, data ? data->size() : 0); } m_frame->loader()->didTellBridgeAboutLoad(resource->url()); }
size_t EOTStream::read(void* buffer, size_t count) { size_t bytesToRead = count; if (m_inHeader) { size_t bytesFromHeader = min(m_eotHeader.size() - m_offset, count); memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); m_offset += bytesFromHeader; bytesToRead -= bytesFromHeader; if (m_offset == m_eotHeader.size()) { m_inHeader = false; m_offset = 0; } } if (bytesToRead && !m_inHeader) { size_t bytesFromData = min(m_fontData->size() - m_offset, bytesToRead); memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { size_t dstOffset = max<int>(m_overlayDst - m_offset, 0); size_t srcOffset = max<int>(0, m_offset - m_overlayDst); size_t bytesToCopy = min(bytesFromData - dstOffset, m_overlayLength - srcOffset); memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); } m_offset += bytesFromData; bytesToRead -= bytesFromData; } return count - bytesToRead; }
static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file CachedImage* cachedImage = getCachedImage(element); if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->image()->data(); if (!imageBuffer || !imageBuffer->size()) return; dataObject->fileContent = imageBuffer; // Determine the filename for the file contents of the image. We try to // use the alt tag if one exists, otherwise we fall back on the suggested // filename in the http header, and finally we resort to using the filename // in the URL. String extension("."); extension += MIMETypeRegistry::getPreferredExtensionForMIMEType( cachedImage->response().mimeType()); String title = element->getAttribute(altAttr); if (title.isEmpty()) { title = cachedImage->response().suggestedFilename(); // FIXME: If title is empty, get the filename from the URL. } dataObject->fileContentFilename = title + extension; }
static void writeImageToDataObject(IDataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file CachedImage* cachedImage = getCachedImage(element); if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->image()->data(); if (!imageBuffer || !imageBuffer->size()) return; HGLOBAL imageFileDescriptor = createGlobalImageFileDescriptor(url.string(), element->getAttribute(altAttr), cachedImage); if (!imageFileDescriptor) return; HGLOBAL imageFileContent = createGlobalImageFileContent(imageBuffer); if (!imageFileContent) { GlobalFree(imageFileDescriptor); return; } String fileName = cachedImage->response().suggestedFilename(); HGLOBAL hDropContent = createGlobalHDropContent(url, fileName, imageBuffer); if (!hDropContent) { GlobalFree(hDropContent); return; } writeFileToDataObject(dataObject, imageFileDescriptor, imageFileContent, hDropContent); }
static void writeImageToDataObject(DataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file CachedImage* cachedImage = getCachedImage(element); if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->image()->data(); if (!imageBuffer || !imageBuffer->size()) return; dataObject->fileContent = imageBuffer; // Determine the filename for the file contents of the image. We try to // use the alt tag if one exists, otherwise we fall back on the suggested // filename in the http header, and finally we resort to using the filename // in the URL. /*String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType( cachedImage->response().mimeType());*/ String extension = "png"; dataObject->fileExtension = extension.isEmpty() ? "" : "." + extension; String title = element->getAttribute(altAttr); if (title.isEmpty()) title = cachedImage->response().suggestedFilename(); //title = ClipboardBal::validateFileName(title, dataObject); dataObject->fileContentFilename = title + dataObject->fileExtension; }
void SynchronousNetworkLoaderClient::sendDelayedReply(NetworkResourceLoader& loader) { ASSERT(m_delayedReply); if (m_response.isNull()) { ASSERT(!m_error.isNull()); //platformSynthesizeErrorResponse(); } Vector<char> responseData; SharedBuffer* buffer = loader.bufferedData(); if (buffer && buffer->size()) responseData.append(buffer->data(), buffer->size()); m_delayedReply->send(m_error, m_response, responseData); m_delayedReply = nullptr; }
size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) { SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); size_t sourceSize = sharedBuffer->size(); if (position >= sourceSize) return 0; const char* source = sharedBuffer->data() + position; size_t amount = min<size_t>(count, sourceSize - position); memcpy(buffer, source, amount); return amount; }
static void clearEntriesByType(uint32_t** entriesByType) { SharedBuffer* buf = SharedBuffer::bufferFromData(entriesByType); const size_t N = buf->size() / sizeof(entriesByType[0]); for (size_t i = 0; i < N; i++) { uint32_t* entries = entriesByType[i]; if (entries != NULL) { SharedBuffer::bufferFromData(entries)->release(); } } buf->release(); }
void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived) { if (m_actualDecoder) { m_data = RefPtr<SharedBuffer>(data); m_lastDataSize = data.size(); m_allDataReceived = allDataReceived; m_actualDecoder->setData(&data, allDataReceived); prepareLazyDecodedFrames(); } if (m_frameGenerator) m_frameGenerator->setData(&data, allDataReceived); }
std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer) { static FT_Library library; if (!library && FT_Init_FreeType(&library)) { library = nullptr; return nullptr; } FT_Face freeTypeFace; if (FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer.data()), buffer.size(), 0, &freeTypeFace)) return nullptr; return std::make_unique<FontCustomPlatformData>(freeTypeFace, buffer); }
static xmlDocPtr docLoaderFunc(const xmlChar* uri, xmlDictPtr, int options, void* ctxt, xsltLoadType type) { if (!globalProcessor) return 0; switch (type) { case XSLT_LOAD_DOCUMENT: { xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt; xmlChar* base = xmlNodeGetBase(context->document->doc, context->node); KURL url(KURL(ParsedURLString, reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri)); xmlFree(base); ResourceLoaderOptions fetchOptions(ResourceFetcher::defaultResourceOptions()); FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::xml, fetchOptions); request.setOriginRestriction(FetchRequest::RestrictToSameOrigin); ResourcePtr<Resource> resource = globalResourceFetcher->fetchSynchronously(request); if (!resource || !globalProcessor) return 0; PageConsole* console = 0; Frame* frame = globalProcessor->xslStylesheet()->ownerDocument()->frame(); if (frame && frame->page()) console = &frame->page()->console(); xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc); xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc); // We don't specify an encoding here. Neither Gecko nor WinIE respects // the encoding specified in the HTTP headers. SharedBuffer* data = resource->resourceBuffer(); xmlDocPtr doc = data ? xmlReadMemory(data->data(), data->size(), (const char*)uri, 0, options) : 0; xmlSetStructuredErrorFunc(0, 0); xmlSetGenericErrorFunc(0, 0); return doc; } case XSLT_LOAD_STYLESHEET: return globalProcessor->xslStylesheet()->locateStylesheetSubResource(((xsltStylesheetPtr)ctxt)->doc, uri); default: break; } return 0; }
void CachedResource::tryReplaceEncodedData(SharedBuffer& newBuffer) { if (!m_data) return; if (!mayTryReplaceEncodedData()) return; // We have to do the memcmp because we can't tell if the replacement file backed data is for the // same resource or if we made a second request with the same URL which gave us a different // resource. We have seen this happen for cached POST resources. if (m_data->size() != newBuffer.size() || memcmp(m_data->data(), newBuffer.data(), m_data->size())) return; if (m_data->tryReplaceContentsWithPlatformBuffer(newBuffer)) didReplaceSharedBufferContents(); }
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->imageForLayoutObject(element->layoutObject()) || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->imageForLayoutObject(element->layoutObject())->data(); if (!imageBuffer || !imageBuffer->size()) return; String imageExtension = cachedImage->image()->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); }
void CachedRawResource::addDataBuffer(SharedBuffer& data) { CachedResourceHandle<CachedRawResource> protect(this); ASSERT(dataBufferingPolicy() == BufferData); m_data = &data; unsigned incrementalDataLength; const char* incrementalData = calculateIncrementalDataChunk(&data, incrementalDataLength); setEncodedSize(data.size()); notifyClientsDataWasReceived(incrementalData, incrementalDataLength); if (dataBufferingPolicy() == DoNotBufferData) { if (m_loader) m_loader->setDataBufferingPolicy(DoNotBufferData); clear(); return; } CachedResource::addDataBuffer(data); }
bool DocumentLoader::scheduleArchiveLoad(Resource* cachedResource, const ResourceRequest& request) { if (!m_archive) return false; ASSERT(m_archiveResourceCollection); ArchiveResource* archiveResource = m_archiveResourceCollection->archiveResourceForURL(request.url()); if (!archiveResource) { cachedResource->error(Resource::LoadError); return true; } cachedResource->setLoading(true); cachedResource->responseReceived(archiveResource->response(), nullptr); SharedBuffer* data = archiveResource->data(); if (data) cachedResource->appendData(data->data(), data->size()); cachedResource->finish(); return true; }
void ImageDecoder::setData(SharedBuffer& data, bool allDataReceived) { if (!allDataReceived) return; COMPtr<IWICStream> stream; HRESULT hr = systemImagingFactory()->CreateStream(&stream); if (!SUCCEEDED(hr)) return; char* dataPtr = const_cast<char*>(data.data()); hr = stream->InitializeFromMemory(reinterpret_cast<BYTE*>(dataPtr), data.size()); if (!SUCCEEDED(hr)) return; m_nativeDecoder = nullptr; hr = systemImagingFactory()->CreateDecoderFromStream(stream.get(), nullptr, WICDecodeMetadataCacheOnDemand, &m_nativeDecoder); ASSERT(SUCCEEDED(hr)); }
size_t EOTStream::read(void* buffer, size_t count) { size_t bytesToRead = count; if (m_inHeader) { size_t bytesFromHeader = min(m_eotHeader.size() - m_offset, count); memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); m_offset += bytesFromHeader; bytesToRead -= bytesFromHeader; if (m_offset == m_eotHeader.size()) { m_inHeader = false; m_offset = 0; } } if (bytesToRead && !m_inHeader) { size_t bytesFromData = min(m_fontData->size() - m_offset, bytesToRead); memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); m_offset += bytesFromData; bytesToRead -= bytesFromData; } return count - bytesToRead; }
void TextTrackLoader::processNewCueData(CachedResource* resource) { ASSERT(m_cachedCueData == resource); if (m_state == Failed || !resource->data()) return; SharedBuffer* buffer = resource->data(); if (m_parseOffset == buffer->size()) return; if (!m_cueParser) m_cueParser = WebVTTParser::create(this, m_scriptExecutionContext); const char* data; unsigned length; while ((length = buffer->getSomeData(data, m_parseOffset))) { m_cueParser->parseBytes(data, length); m_parseOffset += length; } }
static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file CachedImage* cachedImage = getCachedImage(element); if (!cachedImage || !cachedImage->imageForRenderer(element->renderer()) || !cachedImage->isLoaded()) return; SharedBuffer* imageBuffer = cachedImage->imageForRenderer(element->renderer())->data(); if (!imageBuffer || !imageBuffer->size()) return; dataObject->setFileContent(imageBuffer); // Determine the filename for the file contents of the image. String filename = cachedImage->response().suggestedFilename(); if (filename.isEmpty()) filename = url.lastPathComponent(); if (filename.isEmpty()) filename = element->getAttribute(altAttr); else { // Strip any existing extension. Assume that alt text is usually not a filename. int extensionIndex = filename.reverseFind('.'); if (extensionIndex != -1) filename.truncate(extensionIndex); } String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType( cachedImage->response().mimeType()); extension = extension.isEmpty() ? emptyString() : "." + extension; ClipboardChromium::validateFilename(filename, extension); dataObject->setFileContentFilename(filename + extension); dataObject->setFileExtension(extension); }
bool decode(const SharedBuffer& data, bool onlySize) { unsigned newByteCount = data.size() - m_bufferLength; unsigned readOffset = m_bufferLength - m_info.src->bytes_in_buffer; m_info.src->bytes_in_buffer += newByteCount; m_info.src->next_input_byte = (JOCTET*)(data.data()) + readOffset; // If we still have bytes to skip, try to skip those now. if (m_bytesToSkip) skipBytes(m_bytesToSkip); m_bufferLength = data.size(); // We need to do the setjmp here. Otherwise bad things will happen if (setjmp(m_err.setjmp_buffer)) return m_decoder->setFailed(); switch (m_state) { case JPEG_HEADER: // Read file parameters with jpeg_read_header(). if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) return false; // I/O suspension. switch (m_info.jpeg_color_space) { case JCS_GRAYSCALE: case JCS_RGB: case JCS_YCbCr: // libjpeg can convert GRAYSCALE and YCbCr image pixels to RGB. m_info.out_color_space = rgbOutputColorSpace(); #if defined(TURBO_JPEG_RGB_SWIZZLE) if (m_info.saw_JFIF_marker) break; // FIXME: Swizzle decoding does not support Adobe transform=0 // images (yet), so revert to using JSC_RGB in that case. if (m_info.saw_Adobe_marker && !m_info.Adobe_transform) m_info.out_color_space = JCS_RGB; #endif break; case JCS_CMYK: case JCS_YCCK: // libjpeg can convert YCCK to CMYK, but neither to RGB, so we // manually convert CMKY to RGB. m_info.out_color_space = JCS_CMYK; break; default: return m_decoder->setFailed(); } m_state = JPEG_START_DECOMPRESS; // We can fill in the size now that the header is available. if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) return false; // Calculate and set decoded size. m_info.scale_num = m_decoder->desiredScaleNumerator(); m_info.scale_denom = scaleDenominator; jpeg_calc_output_dimensions(&m_info); m_decoder->setDecodedSize(m_info.output_width, m_info.output_height); m_decoder->setOrientation(readImageOrientation(info())); #if USE(QCMSLIB) // Allow color management of the decoded RGBA pixels if possible. if (!m_decoder->ignoresGammaAndColorProfile()) { ColorProfile colorProfile; readColorProfile(info(), colorProfile); createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out_color_space)); #if defined(TURBO_JPEG_RGB_SWIZZLE) // Input RGBA data to qcms. Note: restored to BGRA on output. if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) m_info.out_color_space = JCS_EXT_RGBA; #endif } #endif // Don't allocate a giant and superfluous memory buffer when the // image is a sequential JPEG. m_info.buffered_image = jpeg_has_multiple_scans(&m_info); if (onlySize) { // We can stop here. Reduce our buffer length and available data. m_bufferLength -= m_info.src->bytes_in_buffer; m_info.src->bytes_in_buffer = 0; return true; } // FALL THROUGH case JPEG_START_DECOMPRESS: // Set parameters for decompression. // FIXME -- Should reset dct_method and dither mode for final pass // of progressive JPEG. m_info.dct_method = dctMethod(); m_info.dither_mode = ditherMode(); m_info.do_fancy_upsampling = doFancyUpsampling(); m_info.enable_2pass_quant = false; m_info.do_block_smoothing = true; // Make a one-row-high sample array that will go away when done with // image. Always make it big enough to hold an RGB row. Since this // uses the IJG memory manager, it must be allocated before the call // to jpeg_start_compress(). // FIXME: note that some output color spaces do not need the samples // buffer. Remove this allocation for those color spaces. m_samples = (*m_info.mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(&m_info), JPOOL_IMAGE, m_info.output_width * 4, 1); // Start decompressor. if (!jpeg_start_decompress(&m_info)) return false; // I/O suspension. // If this is a progressive JPEG ... m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL; // FALL THROUGH case JPEG_DECOMPRESS_SEQUENTIAL: if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) { if (!m_decoder->outputScanlines()) return false; // I/O suspension. // If we've completed image output... ASSERT(m_info.output_scanline == m_info.output_height); m_state = JPEG_DONE; } // FALL THROUGH case JPEG_DECOMPRESS_PROGRESSIVE: if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) { int status; do { status = jpeg_consume_input(&m_info); } while ((status != JPEG_SUSPENDED) && (status != JPEG_REACHED_EOI)); for (;;) { if (!m_info.output_scanline) { int scan = m_info.input_scan_number; // If we haven't displayed anything yet // (output_scan_number == 0) and we have enough data for // a complete scan, force output of the last full scan. if (!m_info.output_scan_number && (scan > 1) && (status != JPEG_REACHED_EOI)) --scan; if (!jpeg_start_output(&m_info, scan)) return false; // I/O suspension. } if (m_info.output_scanline == 0xffffff) m_info.output_scanline = 0; // If outputScanlines() fails, it deletes |this|. Therefore, // copy the decoder pointer and use it to check for failure // to avoid member access in the failure case. JPEGImageDecoder* decoder = m_decoder; if (!decoder->outputScanlines()) { if (decoder->failed()) // Careful; |this| is deleted. return false; if (!m_info.output_scanline) // Didn't manage to read any lines - flag so we // don't call jpeg_start_output() multiple times for // the same scan. m_info.output_scanline = 0xffffff; return false; // I/O suspension. } if (m_info.output_scanline == m_info.output_height) { if (!jpeg_finish_output(&m_info)) return false; // I/O suspension. if (jpeg_input_complete(&m_info) && (m_info.input_scan_number == m_info.output_scan_number)) break; m_info.output_scanline = 0; } } m_state = JPEG_DONE; } // FALL THROUGH case JPEG_DONE: // Finish decompression. return jpeg_finish_decompress(&m_info); case JPEG_ERROR: // We can get here if the constructor failed. return m_decoder->setFailed(); } return true; }
void ImageDecoder::setData(SharedBuffer& data, bool allDataReceived) { m_isAllDataReceived = allDataReceived; #if PLATFORM(COCOA) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. // We use SharedBuffer's ability to wrap itself inside CFData to get around this, ensuring that ImageIO is // really looking at the SharedBuffer. CGImageSourceUpdateData(m_nativeDecoder.get(), data.createCFData().get(), allDataReceived); #else // Create a CGDataProvider to wrap the SharedBuffer. data.ref(); // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer // does not provide a way to lock down the byte pointer and guarantee that it won't move, which // is a requirement for using the GetBytePointer callback. CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease }; RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateDirect(&data, data.size(), &providerCallbacks)); CGImageSourceUpdateDataProvider(m_nativeDecoder.get(), dataProvider.get(), allDataReceived); #endif }