Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkBitmapProcState.cpp
index c3801e4..dad0ca9 100644 (file)
@@ -30,6 +30,8 @@ extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&,
 extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
 #endif
 
+extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState&, int, int, uint32_t*, int);
+
 #define   NAME_WRAP(x)  x
 #include "SkBitmapProcState_filter.h"
 #include "SkBitmapProcState_procs.h"
@@ -129,8 +131,6 @@ static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
 bool SkBitmapProcState::possiblyScaleImage() {
     SkASSERT(NULL == fBitmap);
 
-    fAdjustedMatrix = false;
-
     if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
         return false;
     }
@@ -144,13 +144,8 @@ bool SkBitmapProcState::possiblyScaleImage() {
     float trueDestWidth  = fOrigBitmap.width() / invScaleX;
     float trueDestHeight = fOrigBitmap.height() / invScaleY;
 
-#ifndef SK_IGNORE_PROPER_FRACTIONAL_SCALING
     float roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
     float roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
-#else
-    float roundedDestWidth = trueDestWidth;
-    float roundedDestHeight = trueDestHeight;
-#endif
 
     if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
         fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
@@ -196,19 +191,10 @@ bool SkBitmapProcState::possiblyScaleImage() {
         SkASSERT(fScaledBitmap.getPixels());
         fBitmap = &fScaledBitmap;
 
-        // set the inv matrix type to translate-only;
-        fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
-                                fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
+        // clean up the inverse matrix by incorporating the scale we just performed.
 
-#ifndef SK_IGNORE_PROPER_FRACTIONAL_SCALING
-        // reintroduce any fractional scaling missed by our integral scale done above.
-
-       float fractionalScaleX = roundedDestWidth/trueDestWidth;
-       float fractionalScaleY = roundedDestHeight/trueDestHeight;
-
-       fInvMatrix.postScale(fractionalScaleX, fractionalScaleY);
-#endif
-        fAdjustedMatrix = true;
+        fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(),
+                             roundedDestHeight / fOrigBitmap.height());
 
         // Set our filter level to low -- the only post-filtering this
         // image might require is some interpolation if the translation
@@ -252,9 +238,42 @@ bool SkBitmapProcState::possiblyScaleImage() {
 
     SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
 
-    // HACK: Disable use of mipmaps in M39 since they do not use discardable
-    // memory in the cache.
-    fFilterLevel = SkPaint::kLow_FilterLevel;
+    /**
+     *  Medium quality means use a mipmap for down-scaling, and just bilper
+     *  for upscaling. Since we're examining the inverse matrix, we look for
+     *  a scale > 1 to indicate down scaling by the CTM.
+     */
+    if (scaleSqd > SK_Scalar1) {
+        fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
+        if (NULL == fCurrMip.get()) {
+            fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap));
+            if (NULL == fCurrMip.get()) {
+                return false;
+            }
+        }
+        // diagnostic for a crasher...
+        if (NULL == fCurrMip->data()) {
+            sk_throw();
+        }
+
+        SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
+        SkMipMap::Level level;
+        if (fCurrMip->extractLevel(levelScale, &level)) {
+            SkScalar invScaleFixup = level.fScale;
+            fInvMatrix.postScale(invScaleFixup, invScaleFixup);
+
+            const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight);
+            // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
+            //       that here, and not need to explicitly track it ourselves.
+            fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
+            fBitmap = &fScaledBitmap;
+            fFilterLevel = SkPaint::kLow_FilterLevel;
+            return true;
+        } else {
+            // failed to extract, so release the mipmap
+            fCurrMip.reset(NULL);
+        }
+    }
 
     return false;
 }
@@ -339,8 +358,15 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
                       SkShader::kClamp_TileMode == fTileModeY;
 
-    if (!(fAdjustedMatrix || clampClamp || trivialMatrix)) {
-        fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
+    // Most of the scanline procs deal with "unit" texture coordinates, as this
+    // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
+    // those, we divide the matrix by its dimensions here.
+    //
+    // We don't do this if we're either trivial (can ignore the matrix) or clamping
+    // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
+
+    if (!(clampClamp || trivialMatrix)) {
+        fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height());
     }
 
     // Now that all possible changes to the matrix have taken place, check
@@ -556,6 +582,8 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
             }
         } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
             fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
+        } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
+            fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
         }
 
         if (NULL == fShaderProc32) {
@@ -986,3 +1014,58 @@ int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
 
     return size;
 }
+
+///////////////////////
+
+void  Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, int x, int y,
+                                                  SkPMColor* SK_RESTRICT dst, int count) {
+    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
+                             SkMatrix::kScale_Mask)) == 0);
+
+    const unsigned maxX = s.fBitmap->width() - 1;
+    SkFractionalInt fx;
+    int dstY;
+    {
+        SkPoint pt;
+        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf,
+                   &pt);
+        fx = SkScalarToFractionalInt(pt.fY);
+        const unsigned maxY = s.fBitmap->height() - 1;
+        dstY = SkClampMax(SkFractionalIntToInt(fx), maxY);
+        fx = SkScalarToFractionalInt(pt.fX);
+    }
+
+    const SkPMColor* SK_RESTRICT src = s.fBitmap->getAddr32(0, dstY);
+    const SkFractionalInt dx = s.fInvSxFractionalInt;
+
+    // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
+    //
+    if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
+        (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
+    {
+        int count4 = count >> 2;
+        for (int i = 0; i < count4; ++i) {
+            SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
+            SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
+            SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
+            SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
+            dst[0] = src0;
+            dst[1] = src1;
+            dst[2] = src2;
+            dst[3] = src3;
+            dst += 4;
+        }
+        for (int i = (count4 << 2); i < count; ++i) {
+            unsigned index = SkFractionalIntToInt(fx);
+            SkASSERT(index <= maxX);
+            *dst++ = src[index];
+            fx += dx;
+        }
+    } else {
+        for (int i = 0; i < count; ++i) {
+            dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
+            fx += dx;
+        }
+    }
+}
+