virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        unsigned addR = SkColorGetR(fAdd);
        unsigned addG = SkColorGetG(fAdd);
        unsigned addB = SkColorGetB(fAdd);

        for (int i = 0; i < count; i++) {
            SkPMColor c = shader[i];
            if (c) {
                unsigned a = SkGetPackedA32(c);
                unsigned scaleA = SkAlpha255To256(a);
                unsigned r = pin(SkGetPackedR32(c) + SkAlphaMul(addR, scaleA), a);
                unsigned g = pin(SkGetPackedG32(c) + SkAlphaMul(addG, scaleA), a);
                unsigned b = pin(SkGetPackedB32(c) + SkAlphaMul(addB, scaleA), a);
                c = SkPackARGB32(a, r, g, b);
            }
            result[i] = c;
        }
    }
Example #2
0
inline uint32_t blendSrcOverDstNonPremultiplied(uint32_t src, uint32_t dst) {
  uint8_t srcA = SkGetPackedA32(src);
  if (srcA == 0)
    return dst;

  uint8_t dstA = SkGetPackedA32(dst);
  uint8_t dstFactorA = (dstA * SkAlpha255To256(255 - srcA)) >> 8;
  ASSERT(srcA + dstFactorA < (1U << 8));
  uint8_t blendA = srcA + dstFactorA;
  unsigned scale = (1UL << 24) / blendA;

  uint8_t blendR = blendChannel(SkGetPackedR32(src), srcA, SkGetPackedR32(dst),
                                dstFactorA, scale);
  uint8_t blendG = blendChannel(SkGetPackedG32(src), srcA, SkGetPackedG32(dst),
                                dstFactorA, scale);
  uint8_t blendB = blendChannel(SkGetPackedB32(src), srcA, SkGetPackedB32(dst),
                                dstFactorA, scale);

  return SkPackARGB32NoCheck(blendA, blendR, blendG, blendB);
}
bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
                               const SkMatrix& matrix) {
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    SkColor c;
    unsigned a;
    
    if (fInheritColor) {
        c = paint.getColor();
        a = SkColorGetA(c);
    } else {
        c = fColor;
        a = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
    }

    unsigned r = SkColorGetR(c);
    unsigned g = SkColorGetG(c);
    unsigned b = SkColorGetB(c);

    // we want this before we apply any alpha
    fColor16 = SkPack888ToRGB16(r, g, b);

    if (a != 255) {
        r = SkMulDiv255Round(r, a);
        g = SkMulDiv255Round(g, a);
        b = SkMulDiv255Round(b, a);
    }
    fPMColor = SkPackARGB32(a, r, g, b);

    fFlags = kConstInY32_Flag;
    if (255 == a) {
        fFlags |= kOpaqueAlpha_Flag;
        if (paint.isDither() == false) {
            fFlags |= kHasSpan16_Flag;
        }
    }

    return true;
}
void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
                                int count, const SkAlpha aa[]) const {
    const SkPMColor* a = lumaOpA<SkPMColor>(fMode, src, dst);
    const SkPMColor* b = lumaOpB<SkPMColor>(fMode, src, dst);

    if (aa) {
        for (int i = 0; i < count; ++i) {
            unsigned cov = aa[i];
            if (cov) {
                unsigned resC = luma_proc(a[i], b[i]);
                if (cov < 255) {
                    resC = SkFastFourByteInterp256(resC, dst[i],
                                                   SkAlpha255To256(cov));
                }
                dst[i] = resC;
            }
        }
    } else {
        for (int i = 0; i < count; ++i) {
            dst[i] = luma_proc(a[i], b[i]);
        }
    }
}
Example #5
0
SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
                                                      const ContextRec& rec)
    : INHERITED(shader, rec)
{
    SkColor color = shader.fColor;
    unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));

    unsigned r = SkColorGetR(color);
    unsigned g = SkColorGetG(color);
    unsigned b = SkColorGetB(color);

    if (a != 255) {
        r = SkMulDiv255Round(r, a);
        g = SkMulDiv255Round(g, a);
        b = SkMulDiv255Round(b, a);
    }
    fPMColor = SkPackARGB32(a, r, g, b);

    fFlags = kConstInY32_Flag;
    if (255 == a) {
        fFlags |= kOpaqueAlpha_Flag;
    }
}
Example #6
0
void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    SkASSERT(mask.fBounds.contains(clip));

    if (mask.fFormat == SkMask::kBW_Format) {
        SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);

        SkARGB32_BlitBW(fDevice, mask, clip, black);
    } else if (SkMask::kARGB32_Format == mask.fFormat) {
		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
    } else if (SkMask::kLCD16_Format == mask.fFormat) {
        blitmask_lcd16(fDevice, mask, clip, fPMColor);
    } else if (SkMask::kLCD32_Format == mask.fFormat) {
        blitmask_lcd32(fDevice, mask, clip, fPMColor);
    } else {
        unsigned width = clip.width();
        unsigned height = clip.height();

        SkASSERT((int)height > 0);
        SkASSERT((int)width > 0);

        uint32_t*      device = fDevice.getAddr32(clip.fLeft, clip.fTop);
        unsigned       maskRB = mask.fRowBytes - width;
        unsigned       deviceRB = fDevice.rowBytes() - (width << 2);
        const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop);
        do {
            unsigned w = width;
            do {
                unsigned aa = *alpha++;
                *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
                device += 1;
            } while (--w != 0);
            device = (uint32_t*)((char*)device + deviceRB);
            alpha += maskRB;
        } while (--height != 0);
    }
}
Example #7
0
//  kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
    return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
}
Example #8
0
//  kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
    return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
}
            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
            fUnitInvMatrix.postScale(scale, scale);
            
            // now point here instead of fOrigBitmap
            fBitmap = &fMipBitmap;
        }
    }

    fInvMatrix      = m;
    fInvProc        = m->getMapXYProc();
    fInvType        = m->getType();
    fInvSx          = SkScalarToFixed(m->getScaleX());
    fInvKy          = SkScalarToFixed(m->getSkewY());

    fAlphaScale = SkAlpha255To256(paint.getAlpha());

    // pick-up filtering from the paint, but only if the matrix is
    // more complex than identity/translate (i.e. no need to pay the cost
    // of filtering if we're not scaled etc.).
    // note: we explicitly check inv, since m might be scaled due to unitinv
    //       trickery, but we don't want to see that for this test
    fDoFilter = paint.isFilterBitmap() &&
                (inv.getType() > SkMatrix::kTranslate_Mask &&
                 valid_for_filtering(fBitmap->width() | fBitmap->height()));

    fShaderProc32 = NULL;
    fShaderProc16 = NULL;
    fSampleProc32 = NULL;
    fSampleProc16 = NULL;
Example #10
0
bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
    SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());

    fBitmap = NULL;
    fInvMatrix = inv;
    fFilterLevel = paint.getFilterLevel();

    // possiblyScaleImage will look to see if it can rescale the image as a
    // preprocess; either by scaling up to the target size, or by selecting
    // a nearby mipmap level.  If it does, it will adjust the working
    // matrix as well as the working bitmap.  It may also adjust the filter
    // quality to avoid re-filtering an already perfectly scaled image.
    if (!this->possiblyScaleImage()) {
        if (!this->lockBaseBitmap()) {
            return false;
        }
    }
    // The above logic should have always assigned fBitmap, but in case it
    // didn't, we check for that now...
    // TODO(dominikg): Ask [email protected] if we can just use an SkASSERT(fBitmap)?
    if (NULL == fBitmap) {
        return false;
    }

    // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale,
    // so we downgrade to kLow (so the rest of the sniffing code can assume that)
    if (SkPaint::kMedium_FilterLevel == fFilterLevel) {
        fFilterLevel = SkPaint::kLow_FilterLevel;
    }

    bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
    bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
                      SkShader::kClamp_TileMode == fTileModeY;

    if (!(fAdjustedMatrix || clampClamp || trivialMatrix)) {
        fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
    }

    // Now that all possible changes to the matrix have taken place, check
    // to see if we're really close to a no-scale matrix.  If so, explicitly
    // set it to be so.  Subsequent code may inspect this matrix to choose
    // a faster path in this case.

    // This code will only execute if the matrix has some scale component;
    // if it's already pure translate then we won't do this inversion.

    if (matrix_only_scale_translate(fInvMatrix)) {
        SkMatrix forward;
        if (fInvMatrix.invert(&forward)) {
            if (clampClamp ? just_trans_clamp(forward, *fBitmap)
                            : just_trans_general(forward)) {
                SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
                SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
                fInvMatrix.setTranslate(tx, ty);
            }
        }
    }

    fInvProc        = fInvMatrix.getMapXYProc();
    fInvType        = fInvMatrix.getType();
    fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());
    fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
    fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());
    fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());

    fAlphaScale = SkAlpha255To256(paint.getAlpha());

    fShaderProc32 = NULL;
    fShaderProc16 = NULL;
    fSampleProc32 = NULL;
    fSampleProc16 = NULL;

    // recompute the triviality of the matrix here because we may have
    // changed it!

    trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;

    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
        // If this is still set, that means we wanted HQ sampling
        // but couldn't do it as a preprocess.  Let's try to install
        // the scanline version of the HQ sampler.  If that process fails,
        // downgrade to bilerp.

        // NOTE: Might need to be careful here in the future when we want
        // to have the platform proc have a shot at this; it's possible that
        // the chooseBitmapFilterProc will fail to install a shader but a
        // platform-specific one might succeed, so it might be premature here
        // to fall back to bilerp.  This needs thought.

        if (!this->setBitmapFilterProcs()) {
            fFilterLevel = SkPaint::kLow_FilterLevel;
        }
    }

    if (SkPaint::kLow_FilterLevel == fFilterLevel) {
        // Only try bilerp if the matrix is "interesting" and
        // the image has a suitable size.

        if (fInvType <= SkMatrix::kTranslate_Mask ||
                !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
            fFilterLevel = SkPaint::kNone_FilterLevel;
        }
    }

    // At this point, we know exactly what kind of sampling the per-scanline
    // shader will perform.

    fMatrixProc = this->chooseMatrixProc(trivialMatrix);
    // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
    if (NULL == fMatrixProc) {
        return false;
    }

    ///////////////////////////////////////////////////////////////////////

    const SkAlphaType at = fBitmap->alphaType();

    // No need to do this if we're doing HQ sampling; if filter quality is
    // still set to HQ by the time we get here, then we must have installed
    // the shader procs above and can skip all this.

    if (fFilterLevel < SkPaint::kHigh_FilterLevel) {

        int index = 0;
        if (fAlphaScale < 256) {  // note: this distinction is not used for D16
            index |= 1;
        }
        if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
            index |= 2;
        }
        if (fFilterLevel > SkPaint::kNone_FilterLevel) {
            index |= 4;
        }
        // bits 3,4,5 encoding the source bitmap format
        switch (fBitmap->colorType()) {
            case kN32_SkColorType:
                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                    return false;
                }
                index |= 0;
                break;
            case kRGB_565_SkColorType:
                index |= 8;
                break;
            case kIndex_8_SkColorType:
                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                    return false;
                }
                index |= 16;
                break;
            case kARGB_4444_SkColorType:
                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                    return false;
                }
                index |= 24;
                break;
            case kAlpha_8_SkColorType:
                index |= 32;
                fPaintPMColor = SkPreMultiplyColor(paint.getColor());
                break;
            default:
                // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
                return false;
        }

    #if !SK_ARM_NEON_IS_ALWAYS
        static const SampleProc32 gSkBitmapProcStateSample32[] = {
            S32_opaque_D32_nofilter_DXDY,
            S32_alpha_D32_nofilter_DXDY,
            S32_opaque_D32_nofilter_DX,
            S32_alpha_D32_nofilter_DX,
            S32_opaque_D32_filter_DXDY,
            S32_alpha_D32_filter_DXDY,
            S32_opaque_D32_filter_DX,
            S32_alpha_D32_filter_DX,

            S16_opaque_D32_nofilter_DXDY,
            S16_alpha_D32_nofilter_DXDY,
            S16_opaque_D32_nofilter_DX,
            S16_alpha_D32_nofilter_DX,
            S16_opaque_D32_filter_DXDY,
            S16_alpha_D32_filter_DXDY,
            S16_opaque_D32_filter_DX,
            S16_alpha_D32_filter_DX,

            SI8_opaque_D32_nofilter_DXDY,
            SI8_alpha_D32_nofilter_DXDY,
            SI8_opaque_D32_nofilter_DX,
            SI8_alpha_D32_nofilter_DX,
            SI8_opaque_D32_filter_DXDY,
            SI8_alpha_D32_filter_DXDY,
            SI8_opaque_D32_filter_DX,
            SI8_alpha_D32_filter_DX,

            S4444_opaque_D32_nofilter_DXDY,
            S4444_alpha_D32_nofilter_DXDY,
            S4444_opaque_D32_nofilter_DX,
            S4444_alpha_D32_nofilter_DX,
            S4444_opaque_D32_filter_DXDY,
            S4444_alpha_D32_filter_DXDY,
            S4444_opaque_D32_filter_DX,
            S4444_alpha_D32_filter_DX,

            // A8 treats alpha/opaque the same (equally efficient)
            SA8_alpha_D32_nofilter_DXDY,
            SA8_alpha_D32_nofilter_DXDY,
            SA8_alpha_D32_nofilter_DX,
            SA8_alpha_D32_nofilter_DX,
            SA8_alpha_D32_filter_DXDY,
            SA8_alpha_D32_filter_DXDY,
            SA8_alpha_D32_filter_DX,
            SA8_alpha_D32_filter_DX
        };

        static const SampleProc16 gSkBitmapProcStateSample16[] = {
            S32_D16_nofilter_DXDY,
            S32_D16_nofilter_DX,
            S32_D16_filter_DXDY,
            S32_D16_filter_DX,

            S16_D16_nofilter_DXDY,
            S16_D16_nofilter_DX,
            S16_D16_filter_DXDY,
            S16_D16_filter_DX,

            SI8_D16_nofilter_DXDY,
            SI8_D16_nofilter_DX,
            SI8_D16_filter_DXDY,
            SI8_D16_filter_DX,

            // Don't support 4444 -> 565
            NULL, NULL, NULL, NULL,
            // Don't support A8 -> 565
            NULL, NULL, NULL, NULL
        };
    #endif

        fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
        index >>= 1;    // shift away any opaque/alpha distinction
        fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];

        // our special-case shaderprocs
        if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
            if (clampClamp) {
                fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
            } else if (SkShader::kRepeat_TileMode == fTileModeX &&
                       SkShader::kRepeat_TileMode == fTileModeY) {
                fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
            }
        } 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);
        }

        if (NULL == fShaderProc32) {
            fShaderProc32 = this->chooseShaderProc32();
        }
    }
Example #11
0
void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
    unsigned scale = SkAlpha255To256(fAlpha);

    switch (fDevice->getConfig()) {
        case SkBitmap::kARGB_8888_Config:
            if (scale == 256) {
                SkPMColor* src = fDevice->getAddr32(x, y);
                if (src != span) {
                    memcpy(span, src, count * sizeof(SkPMColor));
                }
            } else {
                const SkPMColor* src = fDevice->getAddr32(x, y);
                for (int i = count - 1; i >= 0; --i) {
                    span[i] = SkAlphaMulQ(src[i], scale);
                }
            }
            break;
        case SkBitmap::kRGB_565_Config: {
            const uint16_t* src = fDevice->getAddr16(x, y);
            if (scale == 256) {
                for (int i = count - 1; i >= 0; --i) {
                    span[i] = SkPixel16ToPixel32(src[i]);
                }
            } else {
                unsigned alpha = fAlpha;
                for (int i = count - 1; i >= 0; --i) {
                    uint16_t c = src[i];
                    unsigned r = SkPacked16ToR32(c);
                    unsigned g = SkPacked16ToG32(c);
                    unsigned b = SkPacked16ToB32(c);

                    span[i] = SkPackARGB32( alpha,
                                            SkAlphaMul(r, scale),
                                            SkAlphaMul(g, scale),
                                            SkAlphaMul(b, scale));
                }
            }
            break;
        }
        case SkBitmap::kARGB_4444_Config: {
            const uint16_t* src = fDevice->getAddr16(x, y);
            if (scale == 256) {
                for (int i = count - 1; i >= 0; --i) {
                    span[i] = SkPixel4444ToPixel32(src[i]);
                }
            } else {
                unsigned scale16 = scale >> 4;
                for (int i = count - 1; i >= 0; --i) {
                    uint32_t c = SkExpand_4444(src[i]) * scale16;
                    span[i] = SkCompact_8888(c);
                }
            }
            break;
        }
        case SkBitmap::kIndex8_Config:
            SkDEBUGFAIL("index8 not supported as a destination device");
            break;
        case SkBitmap::kA8_Config: {
            const uint8_t* src = fDevice->getAddr8(x, y);
            if (scale == 256) {
                for (int i = count - 1; i >= 0; --i) {
                    span[i] = SkPackARGB32(src[i], 0, 0, 0);
                }
            } else {
                for (int i = count - 1; i >= 0; --i) {
                    span[i] = SkPackARGB32(SkAlphaMul(src[i], scale), 0, 0, 0);
                }
            }
            break;
        }
        case SkBitmap::kA1_Config:
            SkDEBUGFAIL("kA1_Config umimplemented at this time");
            break;
        default:    // to avoid warnings
            break;
    }
}
Example #12
0
// our std SkAlpha255To256
static int test_srcover0(unsigned dst, unsigned alpha) {
    return alpha + SkAlphaMul(dst, SkAlpha255To256(255 - alpha));
}
Example #13
0
void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
    SkShader::Context* shaderContextA = fShaderContextA;
    SkShader::Context* shaderContextB = fShaderContextB;
    SkXfermode*        mode = static_cast<const SkComposeShader&>(fShader).fMode;
    unsigned           scale = SkAlpha255To256(this->getPaintAlpha());

#ifdef SK_BUILD_FOR_ANDROID
    scale = 256;    // ugh -- maintain old bug/behavior for now
#endif

    SkPMColor   tmp[TMP_COLOR_COUNT];

    if (NULL == mode) {   // implied SRC_OVER
        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
        // for these loops
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);

            if (256 == scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkPMSrcOver(tmp[i], result[i]);
                }
            } else {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
                                            scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    } else {    // use mode for the composition
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);
            mode->xfer32(result, tmp, n, NULL);

            if (256 != scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(result[i], scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    }
}
Example #14
0
/*
 *  Analyze filter-quality and matrix, and decide how to implement that.
 *
 *  In general, we cascade down the request level [ High ... None ]
 *  - for a given level, if we can fulfill it, fine, else
 *    - else we downgrade to the next lower level and try again.
 *  We can always fulfill requests for Low and None
 *  - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
 *    and may be removed.
 */
bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
    fPixmap.reset();
    fInvMatrix = inv;
    fFilterLevel = paint.getFilterQuality();

    const int origW = fProvider.info().width();
    const int origH = fProvider.info().height();
    bool allow_ignore_fractional_translate = true;  // historical default
    if (kMedium_SkFilterQuality == fFilterLevel) {
        allow_ignore_fractional_translate = false;
    }

    SkDefaultBitmapController controller;
    fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(),
                                        fBMStateStorage.get(), fBMStateStorage.size());
    // Note : we allow the controller to return an empty (zero-dimension) result. Should we?
    if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
        return false;
    }
    fPixmap = fBMState->pixmap();
    fInvMatrix = fBMState->invMatrix();
    fFilterLevel = fBMState->quality();
    SkASSERT(fPixmap.addr());
    
    bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
    bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
                      SkShader::kClamp_TileMode == fTileModeY;

    // 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(fPixmap.width(), fPixmap.height());
    }

    // Now that all possible changes to the matrix have taken place, check
    // to see if we're really close to a no-scale matrix.  If so, explicitly
    // set it to be so.  Subsequent code may inspect this matrix to choose
    // a faster path in this case.

    // This code will only execute if the matrix has some scale component;
    // if it's already pure translate then we won't do this inversion.

    if (matrix_only_scale_translate(fInvMatrix)) {
        SkMatrix forward;
        if (fInvMatrix.invert(&forward)) {
            if ((clampClamp && allow_ignore_fractional_translate)
                           ? just_trans_clamp(forward, fPixmap)
                           : just_trans_general(forward)) {
                fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
            }
        }
    }

    fInvProc        = fInvMatrix.getMapXYProc();
    fInvType        = fInvMatrix.getType();
    fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());
    fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
    fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());
    fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());

    fAlphaScale = SkAlpha255To256(paint.getAlpha());

    fShaderProc32 = nullptr;
    fShaderProc16 = nullptr;
    fSampleProc32 = nullptr;

    // recompute the triviality of the matrix here because we may have
    // changed it!

    trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;

    // If our target pixmap is the same as the original, then we revert back to legacy behavior
    // and allow the code to ignore fractional translate.
    //
    // The width/height check allows allow_ignore_fractional_translate to stay false if we
    // previously set it that way (e.g. we started in kMedium).
    //
    if (fPixmap.width() == origW && fPixmap.height() == origH) {
        allow_ignore_fractional_translate = true;
    }

    if (kLow_SkFilterQuality == fFilterLevel && allow_ignore_fractional_translate) {
        // Only try bilerp if the matrix is "interesting" and
        // the image has a suitable size.

        if (fInvType <= SkMatrix::kTranslate_Mask ||
            !valid_for_filtering(fPixmap.width() | fPixmap.height()))
        {
            fFilterLevel = kNone_SkFilterQuality;
        }
    }

    return this->chooseScanlineProcs(trivialMatrix, clampClamp, paint);
}
Example #15
0
            }
        }
        runs += count;
        antialias += count;
        device += count;
    }
}

///////////////////////////////////////////////////////////////////////////////

// Special version of SkBlitRow::Factory32 that knows we're in kSrc_Mode,
// instead of kSrcOver_Mode
static void blend_srcmode(SkPMColor* SK_RESTRICT device,
                          const SkPMColor* SK_RESTRICT span,
                          int count, U8CPU aa) {
    int aa256 = SkAlpha255To256(aa);
    for (int i = 0; i < count; ++i) {
        device[i] = SkFourByteInterp256(span[i], device[i], aa256);
    }
}

SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
                            const SkPaint& paint) : INHERITED(device, paint) {
    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));

    fXfermode = paint.getXfermode();
    SkSafeRef(fXfermode);

    int flags = 0;
    if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
        flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
static inline SkPMColor luma_proc(const SkPMColor a, const SkPMColor b) {
    unsigned luma = SkComputeLuminance(SkGetPackedR32(b),
                                       SkGetPackedG32(b),
                                       SkGetPackedB32(b));
    return SkAlphaMulQ(a, SkAlpha255To256(luma));
}