Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / skia / NativeImageSkia.cpp
index 6f36e51..ad09f19 100644 (file)
 
 #include "platform/PlatformInstrumentation.h"
 #include "platform/TraceEvent.h"
-#include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/FloatRect.h"
-#include "platform/geometry/FloatSize.h"
-#include "platform/graphics/GraphicsContext.h"
-#include "platform/graphics/Image.h"
 #include "platform/graphics/DeferredImageDecoder.h"
+#include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/skia/SkiaUtils.h"
-#include "skia/ext/image_operations.h"
+#include "platform/transforms/AffineTransform.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkRect.h"
 #include "third_party/skia/include/core/SkScalar.h"
 #include "third_party/skia/include/core/SkShader.h"
 
-#include <math.h>
-
 namespace blink {
 
-// 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);
-}
-
-NativeImageSkia::NativeImageSkia()
-    : m_resizeRequests(0)
-{
-}
-
-NativeImageSkia::NativeImageSkia(const SkBitmap& other)
-    : m_bitmap(other)
-    , m_resizeRequests(0)
-{
-}
-
-NativeImageSkia::~NativeImageSkia()
-{
-}
-
-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(bitmap()));
-
-    if (!hasResizedBitmap(scaledImageSize, scaledImageSubset)) {
-        bool shouldCache = isDataComplete()
-            && shouldCacheResampling(scaledImageSize, scaledImageSubset);
-
-        TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ResizeImage", "cached", shouldCache);
-        // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
-        PlatformInstrumentation::willResizeImage(shouldCache);
-        SkBitmap resizedImage = skia::ImageOperations::Resize(bitmap(), 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;
-}
-
 void NativeImageSkia::draw(
     GraphicsContext* context,
     const SkRect& srcRect,
@@ -164,9 +58,10 @@ void NativeImageSkia::draw(
     TRACE_EVENT0("skia", "NativeImageSkia::draw");
 
     bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
+    bool isOpaque = bitmap().isOpaque();
 
     SkPaint paint;
-    context->preparePaintForDrawRectToRect(&paint, srcRect, destRect, compositeOp, blendMode, isLazyDecoded, isDataComplete());
+    context->preparePaintForDrawRectToRect(&paint, srcRect, destRect, compositeOp, blendMode, !isOpaque, isLazyDecoded, isDataComplete());
     // 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
@@ -181,9 +76,7 @@ void NativeImageSkia::draw(
 static SkBitmap createBitmapWithSpace(const SkBitmap& bitmap, int spaceWidth, int spaceHeight)
 {
     SkImageInfo info = bitmap.info();
-    info.fWidth += spaceWidth;
-    info.fHeight += spaceHeight;
-    info.fAlphaType = kPremul_SkAlphaType;
+    info = SkImageInfo::Make(info.width() + spaceWidth, info.height() + spaceHeight, info.colorType(), kPremul_SkAlphaType);
 
     SkBitmap result;
     result.allocPixels(info);
@@ -236,6 +129,7 @@ void NativeImageSkia::drawPattern(
     resampling = limitInterpolationQuality(context, resampling);
 
     SkMatrix localMatrix;
+
     // 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
@@ -244,60 +138,25 @@ void NativeImageSkia::drawPattern(
     const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
     localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));
 
-    RefPtr<SkShader> shader;
-    SkPaint::FilterLevel filterLevel = static_cast<SkPaint::FilterLevel>(resampling);
-
-    // Bicubic filter is only applied to defer-decoded images, see
-    // NativeImageSkia::draw for details.
-    if (resampling == InterpolationHigh && !isLazyDecoded) {
-        // Do nice resampling.
-        filterLevel = SkPaint::kNone_FilterLevel;
-        float scaleX = destBitmapWidth / normSrcRect.width();
-        float scaleY = destBitmapHeight / normSrcRect.height();
-        SkRect scaledSrcRect;
-
-        // Since we are resizing the bitmap, we need to remove the scale
-        // applied to the pixels in the bitmap shader. This means we need
-        // CTM * localMatrix to have identity scale. Since we
-        // can't modify CTM (or the rectangle will be drawn in the wrong
-        // place), we must set localMatrix's scale to the inverse of
-        // CTM scale.
-        localMatrix.preScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1);
-
-        // 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, &localMatrix));
-        } else {
-            shader = adoptRef(SkShader::CreateBitmapShader(
-                createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
-                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
-        }
-    } else {
-        // Because no resizing occurred, the shader transform should be
-        // set to the pattern's transform, which just includes scale.
-        localMatrix.preScale(scale.width(), scale.height());
-
-        // 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, &localMatrix));
-        } else {
-            shader = adoptRef(SkShader::CreateBitmapShader(
-                createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
-                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
-        }
+    // Because no resizing occurred, the shader transform should be
+    // set to the pattern's transform, which just includes scale.
+    localMatrix.preScale(scale.width(), scale.height());
+
+    SkBitmap bitmapToPaint;
+    bitmap().extractSubset(&bitmapToPaint, enclosingIntRect(normSrcRect));
+    if (!repeatSpacing.isZero()) {
+        bitmapToPaint = createBitmapWithSpace(
+            bitmapToPaint,
+            repeatSpacing.width() * ctmScaleX / scale.width(),
+            repeatSpacing.height() * ctmScaleY / scale.height());
     }
+    RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(bitmapToPaint, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
 
     SkPaint paint;
     paint.setShader(shader.get());
-    paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).get());
+    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode));
     paint.setColorFilter(context->colorFilter());
-    paint.setFilterLevel(filterLevel);
+    paint.setFilterLevel(static_cast<SkPaint::FilterLevel>(resampling));
 
     if (isLazyDecoded)
         PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID());
@@ -305,76 +164,4 @@ void NativeImageSkia::drawPattern(
     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 blink