Index: Source/core/platform/graphics/skia/NativeImageSkia.cpp |
diff --git a/Source/core/platform/graphics/skia/NativeImageSkia.cpp b/Source/core/platform/graphics/skia/NativeImageSkia.cpp |
deleted file mode 100644 |
index 89d0d737e4d960d5096b69df22d1a43e4dc8df1c..0000000000000000000000000000000000000000 |
--- a/Source/core/platform/graphics/skia/NativeImageSkia.cpp |
+++ /dev/null |
@@ -1,582 +0,0 @@ |
-/* |
- * Copyright (c) 2008, Google Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are |
- * met: |
- * |
- * * Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * * Redistributions in binary form must reproduce the above |
- * copyright notice, this list of conditions and the following disclaimer |
- * in the documentation and/or other materials provided with the |
- * distribution. |
- * * Neither the name of Google Inc. nor the names of its |
- * contributors may be used to endorse or promote products derived from |
- * this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
-#include "core/platform/graphics/skia/NativeImageSkia.h" |
- |
-#include "core/platform/graphics/GraphicsContext.h" |
-#include "core/platform/graphics/Image.h" |
-#include "core/platform/graphics/DeferredImageDecoder.h" |
-#include "core/platform/graphics/skia/SkiaUtils.h" |
-#include "platform/PlatformInstrumentation.h" |
-#include "platform/TraceEvent.h" |
-#include "platform/geometry/FloatPoint.h" |
-#include "platform/geometry/FloatRect.h" |
-#include "platform/geometry/FloatSize.h" |
-#include "skia/ext/image_operations.h" |
-#include "third_party/skia/include/core/SkMatrix.h" |
-#include "third_party/skia/include/core/SkPaint.h" |
-#include "third_party/skia/include/core/SkScalar.h" |
-#include "third_party/skia/include/core/SkShader.h" |
- |
-#include <math.h> |
-#include <limits> |
- |
-namespace WebCore { |
- |
-static bool nearlyIntegral(float value) |
-{ |
- return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon(); |
-} |
- |
-ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, float srcWidth, float srcHeight, float destWidth, float destHeight) const |
-{ |
- // The percent change below which we will not resample. This usually means |
- // an off-by-one error on the web page, and just doing nearest neighbor |
- // sampling is usually good enough. |
- const float kFractionalChangeThreshold = 0.025f; |
- |
- // Images smaller than this in either direction are considered "small" and |
- // are not resampled ever (see below). |
- const int kSmallImageSizeThreshold = 8; |
- |
- // The amount an image can be stretched in a single direction before we |
- // say that it is being stretched so much that it must be a line or |
- // background that doesn't need resampling. |
- const float kLargeStretch = 3.0f; |
- |
- // Figure out if we should resample this image. We try to prune out some |
- // common cases where resampling won't give us anything, since it is much |
- // slower than drawing stretched. |
- float diffWidth = fabs(destWidth - srcWidth); |
- float diffHeight = fabs(destHeight - srcHeight); |
- bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon(); |
- bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon(); |
- // We don't need to resample if the source and destination are the same. |
- if (widthNearlyEqual && heightNearlyEqual) |
- return NoResampling; |
- |
- if (srcWidth <= kSmallImageSizeThreshold |
- || srcHeight <= kSmallImageSizeThreshold |
- || destWidth <= kSmallImageSizeThreshold |
- || destHeight <= kSmallImageSizeThreshold) { |
- // Small image detected. |
- |
- // Resample in the case where the new size would be non-integral. |
- // This can cause noticeable breaks in repeating patterns, except |
- // when the source image is only one pixel wide in that dimension. |
- if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<float>::epsilon()) |
- || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limits<float>::epsilon())) |
- return LinearResampling; |
- |
- // Otherwise, don't resample small images. These are often used for |
- // borders and rules (think 1x1 images used to make lines). |
- return NoResampling; |
- } |
- |
- if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) { |
- // Large image detected. |
- |
- // Don't resample if it is being stretched a lot in only one direction. |
- // This is trying to catch cases where somebody has created a border |
- // (which might be large) and then is stretching it to fill some part |
- // of the page. |
- if (widthNearlyEqual || heightNearlyEqual) |
- return NoResampling; |
- |
- // The image is growing a lot and in more than one direction. Resampling |
- // is slow and doesn't give us very much when growing a lot. |
- return LinearResampling; |
- } |
- |
- if ((diffWidth / srcWidth < kFractionalChangeThreshold) |
- && (diffHeight / srcHeight < kFractionalChangeThreshold)) { |
- // It is disappointingly common on the web for image sizes to be off by |
- // one or two pixels. We don't bother resampling if the size difference |
- // is a small fraction of the original size. |
- return NoResampling; |
- } |
- |
- // When the image is not yet done loading, use linear. We don't cache the |
- // partially resampled images, and as they come in incrementally, it causes |
- // us to have to resample the whole thing every time. |
- if (!isDataComplete()) |
- return LinearResampling; |
- |
- // Everything else gets resampled. |
- // High quality interpolation only enabled for scaling and translation. |
- if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) |
- return AwesomeResampling; |
- |
- return LinearResampling; |
-} |
- |
-static ResamplingMode limitResamplingMode(GraphicsContext* context, ResamplingMode resampling) |
-{ |
- switch (context->imageInterpolationQuality()) { |
- case InterpolationNone: |
- return NoResampling; |
- case InterpolationMedium: |
- // For now we treat InterpolationMedium and InterpolationLow the same. |
- case InterpolationLow: |
- if (resampling == AwesomeResampling) |
- return LinearResampling; |
- break; |
- case InterpolationHigh: |
- case InterpolationDefault: |
- break; |
- } |
- |
- return resampling; |
-} |
- |
-// This function is used to scale an image and extract a scaled fragment. |
-// |
-// ALGORITHM |
-// |
-// Because the scaled image size has to be integers, we approximate the real |
-// scale with the following formula (only X direction is shown): |
-// |
-// scaledImageWidth = round(scaleX * imageRect.width()) |
-// approximateScaleX = scaledImageWidth / imageRect.width() |
-// |
-// With this method we maintain a constant scale factor among fragments in |
-// the scaled image. This allows fragments to stitch together to form the |
-// full scaled image. The downside is there will be a small difference |
-// between |scaleX| and |approximateScaleX|. |
-// |
-// A scaled image fragment is identified by: |
-// |
-// - Scaled image size |
-// - Scaled image fragment rectangle (IntRect) |
-// |
-// Scaled image size has been determined and the next step is to compute the |
-// rectangle for the scaled image fragment which needs to be an IntRect. |
-// |
-// scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY) |
-// enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect) |
-// |
-// Finally we extract the scaled image fragment using |
-// (scaledImageSize, enclosingScaledSrcRect). |
-// |
-SkBitmap NativeImageSkia::extractScaledImageFragment(const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect) const |
-{ |
- SkISize imageSize = SkISize::Make(bitmap().width(), bitmap().height()); |
- SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.width() * scaleX)), |
- clampToInteger(roundf(imageSize.height() * scaleY))); |
- |
- SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height()); |
- SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImageSize.height()); |
- |
- SkMatrix scaleTransform; |
- scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_ScaleToFit); |
- scaleTransform.mapRect(scaledSrcRect, srcRect); |
- |
- scaledSrcRect->intersect(scaledImageRect); |
- SkIRect enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect); |
- |
- // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because |
- // of float inaccuracy so clip to get inside. |
- enclosingScaledSrcRect.intersect(SkIRect::MakeSize(scaledImageSize)); |
- |
- // scaledSrcRect is relative to the pixel snapped fragment we're extracting. |
- scaledSrcRect->offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y()); |
- |
- return resizedBitmap(scaledImageSize, enclosingScaledSrcRect); |
-} |
- |
-// This does a lot of computation to resample only the portion of the bitmap |
-// that will only be drawn. This is critical for performance since when we are |
-// scrolling, for example, we are only drawing a small strip of the image. |
-// Resampling the whole image every time is very slow, so this speeds up things |
-// dramatically. |
-// |
-// Note: this code is only used when the canvas transformation is limited to |
-// scaling or translation. |
-void NativeImageSkia::drawResampledBitmap(GraphicsContext* context, SkPaint& paint, const SkRect& srcRect, const SkRect& destRect) const |
-{ |
- TRACE_EVENT0("skia", "drawResampledBitmap"); |
- // We want to scale |destRect| with transformation in the canvas to obtain |
- // the final scale. The final scale is a combination of scale transform |
- // in canvas and explicit scaling (srcRect and destRect). |
- SkRect screenRect; |
- context->getTotalMatrix().mapRect(&screenRect, destRect); |
- float realScaleX = screenRect.width() / srcRect.width(); |
- float realScaleY = screenRect.height() / srcRect.height(); |
- |
- // This part of code limits scaling only to visible portion in the |
- SkRect destRectVisibleSubset; |
- ClipRectToCanvas(context, destRect, &destRectVisibleSubset); |
- |
- // ClipRectToCanvas often overshoots, resulting in a larger region than our |
- // original destRect. Intersecting gets us back inside. |
- if (!destRectVisibleSubset.intersect(destRect)) |
- return; // Nothing visible in destRect. |
- |
- // Find the corresponding rect in the source image. |
- SkMatrix destToSrcTransform; |
- SkRect srcRectVisibleSubset; |
- destToSrcTransform.setRectToRect(destRect, srcRect, SkMatrix::kFill_ScaleToFit); |
- destToSrcTransform.mapRect(&srcRectVisibleSubset, destRectVisibleSubset); |
- |
- SkRect scaledSrcRect; |
- SkBitmap scaledImageFragment = extractScaledImageFragment(srcRectVisibleSubset, realScaleX, realScaleY, &scaledSrcRect); |
- |
- context->drawBitmapRect(scaledImageFragment, &scaledSrcRect, destRectVisibleSubset, &paint); |
-} |
- |
-NativeImageSkia::NativeImageSkia() |
- : m_resolutionScale(1) |
- , m_resizeRequests(0) |
-{ |
-} |
- |
-NativeImageSkia::NativeImageSkia(const SkBitmap& other, float resolutionScale) |
- : m_image(other) |
- , m_resolutionScale(resolutionScale) |
- , m_resizeRequests(0) |
-{ |
-} |
- |
-NativeImageSkia::NativeImageSkia(const SkBitmap& image, float resolutionScale, const SkBitmap& resizedImage, const ImageResourceInfo& cachedImageInfo, int resizeRequests) |
- : m_image(image) |
- , m_resolutionScale(resolutionScale) |
- , m_resizedImage(resizedImage) |
- , m_cachedImageInfo(cachedImageInfo) |
- , m_resizeRequests(resizeRequests) |
-{ |
-} |
- |
-NativeImageSkia::~NativeImageSkia() |
-{ |
-} |
- |
-int NativeImageSkia::decodedSize() const |
-{ |
- return m_image.getSize() + m_resizedImage.getSize(); |
-} |
- |
-bool NativeImageSkia::hasResizedBitmap(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const |
-{ |
- bool imageScaleEqual = m_cachedImageInfo.scaledImageSize == scaledImageSize; |
- bool scaledImageSubsetAvailable = m_cachedImageInfo.scaledImageSubset.contains(scaledImageSubset); |
- return imageScaleEqual && scaledImageSubsetAvailable && !m_resizedImage.empty(); |
-} |
- |
-SkBitmap NativeImageSkia::resizedBitmap(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const |
-{ |
- ASSERT(!DeferredImageDecoder::isLazyDecoded(m_image)); |
- |
- if (!hasResizedBitmap(scaledImageSize, scaledImageSubset)) { |
- bool shouldCache = isDataComplete() |
- && shouldCacheResampling(scaledImageSize, scaledImageSubset); |
- |
- PlatformInstrumentation::willResizeImage(shouldCache); |
- SkBitmap resizedImage = skia::ImageOperations::Resize(m_image, skia::ImageOperations::RESIZE_LANCZOS3, scaledImageSize.width(), scaledImageSize.height(), scaledImageSubset); |
- resizedImage.setImmutable(); |
- PlatformInstrumentation::didResizeImage(); |
- |
- if (!shouldCache) |
- return resizedImage; |
- |
- m_resizedImage = resizedImage; |
- } |
- |
- SkBitmap resizedSubset; |
- SkIRect resizedSubsetRect = m_cachedImageInfo.rectInSubset(scaledImageSubset); |
- m_resizedImage.extractSubset(&resizedSubset, resizedSubsetRect); |
- return resizedSubset; |
-} |
- |
-static bool hasNon90rotation(GraphicsContext* context) |
-{ |
- return !context->getTotalMatrix().rectStaysRect(); |
-} |
- |
-void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, const SkRect& destRect, PassRefPtr<SkXfermode> compOp) const |
-{ |
- TRACE_EVENT0("skia", "NativeImageSkia::draw"); |
- SkPaint paint; |
- paint.setXfermode(compOp.get()); |
- paint.setColorFilter(context->colorFilter()); |
- paint.setAlpha(context->getNormalizedAlpha()); |
- paint.setLooper(context->drawLooper()); |
- // only antialias if we're rotated or skewed |
- paint.setAntiAlias(hasNon90rotation(context)); |
- |
- ResamplingMode resampling; |
- if (context->isAccelerated()) { |
- resampling = LinearResampling; |
- } else if (context->printing()) { |
- resampling = NoResampling; |
- } else { |
- // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale). |
- SkRect destRectTarget = destRect; |
- SkMatrix totalMatrix = context->getTotalMatrix(); |
- if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) |
- totalMatrix.mapRect(&destRectTarget, destRect); |
- |
- resampling = computeResamplingMode(totalMatrix, |
- SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()), |
- SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height())); |
- } |
- |
- if (resampling == NoResampling) { |
- // FIXME: This is to not break tests (it results in the filter bitmap flag |
- // being set to true). We need to decide if we respect NoResampling |
- // being returned from computeResamplingMode. |
- resampling = LinearResampling; |
- } |
- resampling = limitResamplingMode(context, resampling); |
- paint.setFilterBitmap(resampling == LinearResampling); |
- |
- bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); |
- // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images |
- // as an experiment. Once this filtering code path becomes stable we should |
- // turn this on for all cases, including non-defer-decoded images. |
- bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; |
- |
- if (useBicubicFilter) |
- paint.setFilterLevel(SkPaint::kHigh_FilterLevel); |
- |
- if (resampling == AwesomeResampling && !useBicubicFilter) { |
- // Resample the image and then draw the result to canvas with bilinear |
- // filtering. |
- drawResampledBitmap(context, paint, srcRect, destRect); |
- } else { |
- // We want to filter it if we decided to do interpolation above, or if |
- // there is something interesting going on with the matrix (like a rotation). |
- // Note: for serialization, we will want to subset the bitmap first so we |
- // don't send extra pixels. |
- context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint); |
- } |
- if (isLazyDecoded) |
- PlatformInstrumentation::didDrawLazyPixelRef(reinterpret_cast<unsigned long long>(bitmap().pixelRef())); |
- context->didDrawRect(destRect, paint, &bitmap()); |
-} |
- |
-static SkBitmap createBitmapWithSpace(const SkBitmap& bitmap, int spaceWidth, int spaceHeight) |
-{ |
- SkBitmap result; |
- result.setConfig(bitmap.config(), |
- bitmap.width() + spaceWidth, |
- bitmap.height() + spaceHeight); |
- result.allocPixels(); |
- |
- result.eraseColor(SK_ColorTRANSPARENT); |
- bitmap.copyPixelsTo(reinterpret_cast<uint8_t*>(result.getPixels()), result.rowBytes() * result.height(), result.rowBytes()); |
- |
- return result; |
-} |
- |
-void NativeImageSkia::drawPattern( |
- GraphicsContext* context, |
- const FloatRect& floatSrcRect, |
- const FloatSize& scale, |
- const FloatPoint& phase, |
- CompositeOperator compositeOp, |
- const FloatRect& destRect, |
- blink::WebBlendMode blendMode, |
- const IntSize& repeatSpacing) const |
-{ |
- FloatRect normSrcRect = floatSrcRect; |
- normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height())); |
- if (destRect.isEmpty() || normSrcRect.isEmpty()) |
- return; // nothing to draw |
- |
- SkMatrix totalMatrix = context->getTotalMatrix(); |
- SkScalar ctmScaleX = totalMatrix.getScaleX(); |
- SkScalar ctmScaleY = totalMatrix.getScaleY(); |
- totalMatrix.preScale(scale.width(), scale.height()); |
- |
- // Figure out what size the bitmap will be in the destination. The |
- // destination rect is the bounds of the pattern, we need to use the |
- // matrix to see how big it will be. |
- SkRect destRectTarget; |
- totalMatrix.mapRect(&destRectTarget, normSrcRect); |
- |
- float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); |
- float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); |
- |
- // Compute the resampling mode. |
- ResamplingMode resampling; |
- if (context->isAccelerated() || context->printing()) |
- resampling = LinearResampling; |
- else |
- resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); |
- resampling = limitResamplingMode(context, resampling); |
- |
- SkMatrix shaderTransform; |
- RefPtr<SkShader> shader; |
- |
- bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); |
- // Bicubic filter is only applied to defer-decoded images, see |
- // NativeImageSkia::draw for details. |
- bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; |
- |
- if (resampling == AwesomeResampling && !useBicubicFilter) { |
- // Do nice resampling. |
- float scaleX = destBitmapWidth / normSrcRect.width(); |
- float scaleY = destBitmapHeight / normSrcRect.height(); |
- SkRect scaledSrcRect; |
- |
- // The image fragment generated here is not exactly what is |
- // requested. The scale factor used is approximated and image |
- // fragment is slightly larger to align to integer |
- // boundaries. |
- SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect); |
- if (repeatSpacing.isZero()) { |
- shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); |
- } else { |
- shader = adoptRef(SkShader::CreateBitmapShader( |
- createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), |
- SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); |
- } |
- |
- // Since we just resized the bitmap, we need to remove the scale |
- // applied to the pixels in the bitmap shader. This means we need |
- // CTM * shaderTransform to have identity scale. Since we |
- // can't modify CTM (or the rectangle will be drawn in the wrong |
- // place), we must set shaderTransform's scale to the inverse of |
- // CTM scale. |
- shaderTransform.setScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1); |
- } else { |
- // No need to resample before drawing. |
- SkBitmap srcSubset; |
- bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect)); |
- if (repeatSpacing.isZero()) { |
- shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); |
- } else { |
- shader = adoptRef(SkShader::CreateBitmapShader( |
- createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), |
- SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); |
- } |
- |
- // Because no resizing occurred, the shader transform should be |
- // set to the pattern's transform, which just includes scale. |
- shaderTransform.setScale(scale.width(), scale.height()); |
- } |
- |
- // We also need to translate it such that the origin of the pattern is the |
- // origin of the destination rect, which is what WebKit expects. Skia uses |
- // the coordinate system origin as the base for the pattern. If WebKit wants |
- // a shifted image, it will shift it from there using the shaderTransform. |
- float adjustedX = phase.x() + normSrcRect.x() * scale.width(); |
- float adjustedY = phase.y() + normSrcRect.y() * scale.height(); |
- shaderTransform.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); |
- shader->setLocalMatrix(shaderTransform); |
- |
- SkPaint paint; |
- paint.setShader(shader.get()); |
- paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).get()); |
- paint.setColorFilter(context->colorFilter()); |
- |
- paint.setFilterBitmap(resampling == LinearResampling); |
- if (useBicubicFilter) |
- paint.setFilterLevel(SkPaint::kHigh_FilterLevel); |
- if (isLazyDecoded) |
- PlatformInstrumentation::didDrawLazyPixelRef(reinterpret_cast<unsigned long long>(bitmap().pixelRef())); |
- |
- context->drawRect(destRect, paint); |
-} |
- |
-bool NativeImageSkia::shouldCacheResampling(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const |
-{ |
- // Check whether the requested dimensions match previous request. |
- bool matchesPreviousRequest = m_cachedImageInfo.isEqual(scaledImageSize, scaledImageSubset); |
- if (matchesPreviousRequest) |
- ++m_resizeRequests; |
- else { |
- m_cachedImageInfo.set(scaledImageSize, scaledImageSubset); |
- m_resizeRequests = 0; |
- // Reset m_resizedImage now, because we don't distinguish |
- // between the last requested resize info and m_resizedImage's |
- // resize info. |
- m_resizedImage.reset(); |
- } |
- |
- // We can not cache incomplete frames. This might be a good optimization in |
- // the future, were we know how much of the frame has been decoded, so when |
- // we incrementally draw more of the image, we only have to resample the |
- // parts that are changed. |
- if (!isDataComplete()) |
- return false; |
- |
- // If the destination bitmap is excessively large, we'll never allow caching. |
- static const unsigned long long kLargeBitmapSize = 4096ULL * 4096ULL; |
- unsigned long long fullSize = static_cast<unsigned long long>(scaledImageSize.width()) * static_cast<unsigned long long>(scaledImageSize.height()); |
- unsigned long long fragmentSize = static_cast<unsigned long long>(scaledImageSubset.width()) * static_cast<unsigned long long>(scaledImageSubset.height()); |
- |
- if (fragmentSize > kLargeBitmapSize) |
- return false; |
- |
- // If the destination bitmap is small, we'll always allow caching, since |
- // there is not very much penalty for computing it and it may come in handy. |
- static const unsigned kSmallBitmapSize = 4096; |
- if (fragmentSize <= kSmallBitmapSize) |
- return true; |
- |
- // If "too many" requests have been made for this bitmap, we assume that |
- // many more will be made as well, and we'll go ahead and cache it. |
- static const int kManyRequestThreshold = 4; |
- if (m_resizeRequests >= kManyRequestThreshold) |
- return true; |
- |
- // If more than 1/4 of the resized image is requested, it's worth caching. |
- return fragmentSize > fullSize / 4; |
-} |
- |
-NativeImageSkia::ImageResourceInfo::ImageResourceInfo() |
-{ |
- scaledImageSize.setEmpty(); |
- scaledImageSubset.setEmpty(); |
-} |
- |
-bool NativeImageSkia::ImageResourceInfo::isEqual(const SkISize& otherScaledImageSize, const SkIRect& otherScaledImageSubset) const |
-{ |
- return scaledImageSize == otherScaledImageSize && scaledImageSubset == otherScaledImageSubset; |
-} |
- |
-void NativeImageSkia::ImageResourceInfo::set(const SkISize& otherScaledImageSize, const SkIRect& otherScaledImageSubset) |
-{ |
- scaledImageSize = otherScaledImageSize; |
- scaledImageSubset = otherScaledImageSubset; |
-} |
- |
-SkIRect NativeImageSkia::ImageResourceInfo::rectInSubset(const SkIRect& otherScaledImageSubset) |
-{ |
- if (!scaledImageSubset.contains(otherScaledImageSubset)) |
- return SkIRect::MakeEmpty(); |
- SkIRect subsetRect = otherScaledImageSubset; |
- subsetRect.offset(-scaledImageSubset.x(), -scaledImageSubset.y()); |
- return subsetRect; |
-} |
- |
-} // namespace WebCore |