void PDFDocumentImage::updateCachedImageIfNeeded(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect) { // If we have an existing image, reuse it if we're doing a low-quality paint, even if cache parameters don't match; // we'll rerender when we do the subsequent high-quality paint. InterpolationQuality interpolationQuality = context->imageInterpolationQuality(); bool useLowQualityInterpolation = interpolationQuality == InterpolationNone || interpolationQuality == InterpolationLow; if (!m_cachedImageBuffer || (!cacheParametersMatch(context, dstRect, srcRect) && !useLowQualityInterpolation)) { m_cachedImageBuffer = context->createCompatibleBuffer(enclosingIntRect(dstRect).size()); if (!m_cachedImageBuffer) return; GraphicsContext* bufferContext = m_cachedImageBuffer->context(); if (!bufferContext) { m_cachedImageBuffer = nullptr; return; } transformContextForPainting(bufferContext, dstRect, srcRect); drawPDFPage(bufferContext); m_cachedTransform = context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); m_cachedDestinationSize = dstRect.size(); m_cachedSourceRect = srcRect; IntSize internalSize = m_cachedImageBuffer->internalSize(); size_t oldCachedBytes = m_cachedBytes; m_cachedBytes = internalSize.width() * internalSize.height() * 4; if (imageObserver()) imageObserver()->decodedSizeChanged(this, safeCast<int>(m_cachedBytes) - safeCast<int>(oldCachedBytes)); } }
void PDFDocumentImage::updateCachedImageIfNeeded(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect) { #if PLATFORM(IOS) // On iOS, if the physical memory is less than 1GB, do not allocate more than 16MB for the PDF cachedImage. const size_t memoryThreshold = WTF::GB; const size_t maxArea = 16 * WTF::MB / 4; // 16 MB maximum size, divided by a rough cost of 4 bytes per pixel of area. if (ramSize() <= memoryThreshold && ImageBuffer::compatibleBufferSize(dstRect.size(), context).area() >= maxArea) { m_cachedImageBuffer = nullptr; return; } // On iOS, some clients use low-quality image interpolation always, which throws off this optimization, // as we never get the subsequent high-quality paint. Since live resize is rare on iOS, disable the optimization. // FIXME (136593): It's also possible to do the wrong thing here if CSS specifies low-quality interpolation via the "image-rendering" // property, on all platforms. We should only do this optimization if we're actually in a ImageQualityController live resize, // and are guaranteed to do a high-quality paint later. bool repaintIfNecessary = true; #else // If we have an existing image, reuse it if we're doing a low-quality paint, even if cache parameters don't match; // we'll rerender when we do the subsequent high-quality paint. InterpolationQuality interpolationQuality = context.imageInterpolationQuality(); bool repaintIfNecessary = interpolationQuality != InterpolationNone && interpolationQuality != InterpolationLow; #endif if (m_cachedImageBuffer && (!repaintIfNecessary || cacheParametersMatch(context, dstRect, srcRect))) return; m_cachedImageBuffer = ImageBuffer::createCompatibleBuffer(FloatRect(enclosingIntRect(dstRect)).size(), context); if (!m_cachedImageBuffer) return; auto& bufferContext = m_cachedImageBuffer->context(); transformContextForPainting(bufferContext, dstRect, srcRect); drawPDFPage(bufferContext); m_cachedTransform = context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); m_cachedDestinationSize = dstRect.size(); m_cachedSourceRect = srcRect; IntSize internalSize = m_cachedImageBuffer->internalSize(); size_t oldCachedBytes = m_cachedBytes; m_cachedBytes = safeCast<size_t>(internalSize.width()) * internalSize.height() * 4; if (imageObserver()) imageObserver()->decodedSizeChanged(this, safeCast<int>(m_cachedBytes) - safeCast<int>(oldCachedBytes)); }
void PDFDocumentImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op, BlendMode, ImageOrientationDescription) { if (!m_document || !m_hasPage) return; updateCachedImageIfNeeded(context, dstRect, srcRect); { GraphicsContextStateSaver stateSaver(context); context.setCompositeOperation(op); if (m_cachedImageBuffer) context.drawImageBuffer(*m_cachedImageBuffer, dstRect); else { transformContextForPainting(context, dstRect, srcRect); drawPDFPage(context); } } if (imageObserver()) imageObserver()->didDraw(this); }