static bool rgbPictureImport(const unsigned char* pixels, bool premultiplied, WebPImporter importRGBX, WebPImporter importRGB, WebPPicture* picture) { if (premultiplied) return importRGBX(picture, pixels, picture->width * 4); // Write the RGB pixels to an rgb data buffer, alpha premultiplied, then import the rgb data. Vector<unsigned char> rgb; size_t pixelCount = picture->height * picture->width; rgb.reserveInitialCapacity(pixelCount * 3); for (unsigned char* data = rgb.data(); pixelCount-- > 0; pixels += 4) { unsigned char alpha = pixels[3]; if (alpha != 255) { *data++ = SkMulDiv255Round(pixels[0], alpha); *data++ = SkMulDiv255Round(pixels[1], alpha); *data++ = SkMulDiv255Round(pixels[2], alpha); } else { *data++ = pixels[0]; *data++ = pixels[1]; *data++ = pixels[2]; } } return importRGB(picture, rgb.data(), picture->width * 3); }
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); // 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 (rec.fPaint->isDither() == false) { fFlags |= kHasSpan16_Flag; } } }
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); SkColor4f c4 = SkColor4f::FromColor(shader.fColor); c4.fA *= rec.fPaint->getAlpha() / 255.0f; fPM4f = c4.premul(); fFlags = kConstInY32_Flag; if (255 == a) { fFlags |= kOpaqueAlpha_Flag; } }
/* * Convert a row of CMYK samples to RGBX in place. * Note that this method moves the row pointer. * @param width the number of pixels in the row that is being converted * CMYK is stored as four bytes per pixel */ static void convert_CMYK_to_RGB(uint8_t* row, uint32_t width) { // We will implement a crude conversion from CMYK -> RGB using formulas // from easyrgb.com. // // CMYK -> CMY // C = C * (1 - K) + K // M = M * (1 - K) + K // Y = Y * (1 - K) + K // // libjpeg actually gives us inverted CMYK, so we must subtract the // original terms from 1. // CMYK -> CMY // C = (1 - C) * (1 - (1 - K)) + (1 - K) // M = (1 - M) * (1 - (1 - K)) + (1 - K) // Y = (1 - Y) * (1 - (1 - K)) + (1 - K) // // Simplifying the above expression. // CMYK -> CMY // C = 1 - CK // M = 1 - MK // Y = 1 - YK // // CMY -> RGB // R = (1 - C) * 255 // G = (1 - M) * 255 // B = (1 - Y) * 255 // // Therefore the full conversion is below. This can be verified at // www.rapidtables.com (assuming inverted CMYK). // CMYK -> RGB // R = C * K * 255 // G = M * K * 255 // B = Y * K * 255 // // As a final note, we have treated the CMYK values as if they were on // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. // We must divide each CMYK component by 255 to obtain the true conversion // we should perform. // CMYK -> RGB // R = C * K / 255 // G = M * K / 255 // B = Y * K / 255 for (uint32_t x = 0; x < width; x++, row += 4) { row[0] = SkMulDiv255Round(row[0], row[3]); row[1] = SkMulDiv255Round(row[1], row[3]); row[2] = SkMulDiv255Round(row[2], row[3]); row[3] = 0xFF; } }
SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { if (a != 255) { #if 0 unsigned scale = SkAlpha255To256(a); r = SkAlphaMul(r, scale); g = SkAlphaMul(g, scale); b = SkAlphaMul(b, scale); #else r = SkMulDiv255Round(r, a); g = SkMulDiv255Round(g, a); b = SkMulDiv255Round(b, a); #endif } return SkPackARGB32(a, r, g, b); }
static void clamp_with_orig(uint8_t dst[], int dstRowBytes, const uint8_t src[], int srcRowBytes, int sw, int sh, SkBlurMask::Style style) { int x; while (--sh >= 0) { switch (style) { case SkBlurMask::kSolid_Style: for (x = sw - 1; x >= 0; --x) { int s = *src; int d = *dst; *dst = SkToU8(s + d - SkMulDiv255Round(s, d)); dst += 1; src += 1; } break; case SkBlurMask::kOuter_Style: for (x = sw - 1; x >= 0; --x) { if (*src) { *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); } dst += 1; src += 1; } break; default: SkDEBUGFAIL("Unexpected blur style here"); break; } dst += dstRowBytes - sw; src += srcRowBytes - sw; } }
// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer // and restore static void apply_0(SkDebugCanvas* canvas, int curCommand) { SkSaveLayerCommand* saveLayer = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); const SkPaint* saveLayerPaint = saveLayer->paint(); // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed if (NULL != saveLayerPaint) { SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); SkPaint* dbmrPaint = dbmr->paint(); if (NULL == dbmrPaint) { // if the DBMR doesn't have a paint just use the saveLayer's dbmr->setPaint(*saveLayerPaint); } else if (NULL != saveLayerPaint) { // Both paints are present so their alphas need to be combined SkColor color = saveLayerPaint->getColor(); int a0 = SkColorGetA(color); color = dbmrPaint->getColor(); int a1 = SkColorGetA(color); int newA = SkMulDiv255Round(a0, a1); SkASSERT(newA <= 0xFF); SkColor newColor = SkColorSetA(color, newA); dbmrPaint->setColor(newColor); } } canvas->deleteDrawCommandAt(curCommand+2); // restore canvas->deleteDrawCommandAt(curCommand); // saveLayer }
static void RGBAtoRGB(const unsigned char* pixels, unsigned int pixelCount, unsigned char* output) { for (; pixelCount-- > 0; pixels += 4) { // Do source-over composition on black. unsigned char alpha = pixels[3]; if (alpha != 255) { *output++ = SkMulDiv255Round(pixels[0], alpha); *output++ = SkMulDiv255Round(pixels[1], alpha); *output++ = SkMulDiv255Round(pixels[2], alpha); } else { *output++ = pixels[0]; *output++ = pixels[1]; *output++ = pixels[2]; } } }
static void RGBAtoRGB(const unsigned char* pixels, unsigned pixelCount, unsigned char* output) { // Per <canvas> spec, composite the input image pixels source-over on black. for (; pixelCount-- > 0; pixels += 4) { unsigned char alpha = pixels[3]; if (alpha != 255) { *output++ = SkMulDiv255Round(pixels[0], alpha); *output++ = SkMulDiv255Round(pixels[1], alpha); *output++ = SkMulDiv255Round(pixels[2], alpha); } else { *output++ = pixels[0]; *output++ = pixels[1]; *output++ = pixels[2]; } } }
bool SkColorShader::asNewEffect(GrContext* context, const SkPaint& paint, const SkMatrix* localMatrix, GrColor* grColor, GrEffectRef** grEffect) const { *grEffect = NULL; SkColor skColor = fColor; U8CPU newA = SkMulDiv255Round(SkColorGetA(fColor), paint.getAlpha()); *grColor = SkColor2GrColor(SkColorSetA(skColor, newA)); return true; }
// Convert a scanline of CMYK samples to RGBX in place. Note that this // method moves the "scanline" pointer in its processing static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { // At this point we've received CMYK pixels from libjpeg. We // perform a crude conversion to RGB (based on the formulae // from easyrgb.com): // CMYK -> CMY // C = ( C * (1 - K) + K ) // for each CMY component // CMY -> RGB // R = ( 1 - C ) * 255 // for each RGB component // Unfortunately we are seeing inverted CMYK so all the original terms // are 1-. This yields: // CMYK -> CMY // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K // The conversion from CMY->RGB remains the same for (unsigned int x = 0; x < width; ++x, scanline += 4) { scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); scanline[3] = 255; } }
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; }
static inline bool S32A_D565_Blend_1(SkPMColor sc, uint16_t dc, U8CPU alpha) { unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha); unsigned dr = (SkMulS16(SkGetPackedR32(sc), alpha) >> 3) + SkMulS16(SkGetPackedR16(dc), dst_scale); unsigned dg = (SkMulS16(SkGetPackedG32(sc), alpha) >> 2) + SkMulS16(SkGetPackedG16(dc), dst_scale); unsigned rr = SkDiv255Round(dr); unsigned rg = SkDiv255Round(dg); if (rr <= 31 && rg <= 63) { return true; } return false; }
static inline bool S32A_D565_Blend_02(SkPMColor sc, uint16_t dc, U8CPU alpha) { unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha); unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(GetPackedR16As32(dc), dst_scale); unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(GetPackedG16As32(dc), dst_scale); unsigned db = SkMulS16(SkGetPackedB32(sc), alpha) + SkMulS16(GetPackedB16As32(dc), dst_scale); int rc = SkPack888ToRGB16(SkDiv255Round(dr), SkDiv255Round(dg), SkDiv255Round(db)); unsigned rr = SkGetPackedR16(rc); unsigned rg = SkGetPackedG16(rc); if (rr <= 31 && rg <= 63) { return true; } return false; }
void SkGradientShaderBase::GradientShaderCache::Build32bitCache( SkPMColor cache[], SkColor c0, SkColor c1, int count, U8CPU paintAlpha, uint32_t gradFlags) { SkASSERT(count > 1); // need to apply paintAlpha to our two endpoints uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha); const bool interpInPremul = SkToBool(gradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag); uint32_t r0 = SkColorGetR(c0); uint32_t g0 = SkColorGetG(c0); uint32_t b0 = SkColorGetB(c0); uint32_t r1 = SkColorGetR(c1); uint32_t g1 = SkColorGetG(c1); uint32_t b1 = SkColorGetB(c1); if (interpInPremul) { r0 = SkMulDiv255Round(r0, a0); g0 = SkMulDiv255Round(g0, a0); b0 = SkMulDiv255Round(b0, a0); r1 = SkMulDiv255Round(r1, a1); g1 = SkMulDiv255Round(g1, a1); b1 = SkMulDiv255Round(b1, a1); } SkFixed da = SkIntToFixed(a1 - a0) / (count - 1); SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1); SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1); SkFixed db = SkIntToFixed(b1 - b0) / (count - 1); /* We pre-add 1/8 to avoid having to add this to our [0] value each time in the loop. Without this, the bias for each would be 0x2000 0xA000 0xE000 0x6000 With this trick, we can add 0 for the first (no-op) and just adjust the others. */ SkUFixed a = SkIntToFixed(a0) + 0x2000; SkUFixed r = SkIntToFixed(r0) + 0x2000; SkUFixed g = SkIntToFixed(g0) + 0x2000; SkUFixed b = SkIntToFixed(b0) + 0x2000; /* * Our dither-cell (spatially) is * 0 2 * 3 1 * Where * [0] -> [-1/8 ... 1/8 ) values near 0 * [1] -> [ 1/8 ... 3/8 ) values near 1/4 * [2] -> [ 3/8 ... 5/8 ) values near 1/2 * [3] -> [ 5/8 ... 7/8 ) values near 3/4 */ if (0xFF == a0 && 0 == da) { do { cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16, (g + 0 ) >> 16, (b + 0 ) >> 16); cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + 0x8000) >> 16, (g + 0x8000) >> 16, (b + 0x8000) >> 16); cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + 0xC000) >> 16, (g + 0xC000) >> 16, (b + 0xC000) >> 16); cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + 0x4000) >> 16, (g + 0x4000) >> 16, (b + 0x4000) >> 16); cache += 1; r += dr; g += dg; b += db; } while (--count != 0); } else if (interpInPremul) {
bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, SkScalar provided_radius, Style style, SkIPoint *margin, SkMask::CreateMode createMode) { int profile_size; float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor)); // adjust blur radius to match interpretation from boxfilter code radius = (radius + .5f) * 2.f; profile_size = compute_profile_size(radius); int pad = profile_size/2; if (margin) { margin->set( pad, pad ); } dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), SkScalarRoundToInt(src.fTop - pad), SkScalarRoundToInt(src.fRight + pad), SkScalarRoundToInt(src.fBottom + pad)); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; int sw = SkScalarFloorToInt(src.width()); int sh = SkScalarFloorToInt(src.height()); if (createMode == SkMask::kJustComputeBounds_CreateMode) { if (style == kInner_Style) { dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } return true; } unsigned int *profile = NULL; compute_profile(radius, &profile); SkAutoTDeleteArray<unsigned int> ada(profile); size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } uint8_t* dp = SkMask::AllocImage(dstSize); dst->fImage = dp; int dstHeight = dst->fBounds.height(); int dstWidth = dst->fBounds.width(); // nearest odd number less than the profile size represents the center // of the (2x scaled) profile int center = ( profile_size & ~1 ) - 1; int w = sw - center; int h = sh - center; uint8_t *outptr = dp; SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); for (int x = 0 ; x < dstWidth ; ++x) { if (profile_size <= sw) { horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); } else { float span = float(sw)/radius; float giX = 1.5f - (x+.5f)/radius; horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); } } for (int y = 0 ; y < dstHeight ; ++y) { unsigned int profile_y; if (profile_size <= sh) { profile_y = profile_lookup(profile, y, dstHeight, h); } else { float span = float(sh)/radius; float giY = 1.5f - (y+.5f)/radius; profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span))); } for (int x = 0 ; x < dstWidth ; x++) { unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profile_y); *(outptr++) = maskval; } } if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = (size_t)(src.width() * src.height()); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); for (int y = 0 ; y < sh ; y++) { uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; uint8_t *inner_scanline = dst->fImage + y*sw; memcpy(inner_scanline, blur_scanline, sw); } SkMask::FreeImage(dp); dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } else if (style == kOuter_Style) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0, sw); } } else if (style == kSolid_Style) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0xff, sw); } } // normal and solid styles are the same for analytic rect blurs, so don't // need to handle solid specially. return true; }
void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, int count, U8CPU paintAlpha) { SkASSERT(count > 1); // need to apply paintAlpha to our two endpoints SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); SkFixed da; { int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha); da = SkIntToFixed(tmp - a) / (count - 1); } /* * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in * release builds, we saw a compiler error where the 0xFF parameter in * SkPackARGB32() was being totally ignored whenever it was called with * a non-zero add (e.g. 0x8000). * * We found two work-arounds: * 1. change r,g,b to unsigned (or just one of them) * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead * of using | * * We chose #1 just because it was more localized. * See http://code.google.com/p/skia/issues/detail?id=1113 */ uint32_t r = SkColorGetR(c0); uint32_t g = SkColorGetG(c0); uint32_t b = SkColorGetB(c0); SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1); SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1); SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1); /* We pre-add 1/8 to avoid having to add this to our [0] value each time in the loop. Without this, the bias for each would be 0x2000 0xA000 0xE000 0x6000 With this trick, we can add 0 for the first (no-op) and just adjust the others. */ r = SkIntToFixed(r) + 0x2000; g = SkIntToFixed(g) + 0x2000; b = SkIntToFixed(b) + 0x2000; /* * Our dither-cell (spatially) is * 0 2 * 3 1 * Where * [0] -> [-1/8 ... 1/8 ) values near 0 * [1] -> [ 1/8 ... 3/8 ) values near 1/4 * [2] -> [ 3/8 ... 5/8 ) values near 1/2 * [3] -> [ 5/8 ... 7/8 ) values near 3/4 */ if (0xFF == a && 0 == da) { do { cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16, (g + 0 ) >> 16, (b + 0 ) >> 16); cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + 0x8000) >> 16, (g + 0x8000) >> 16, (b + 0x8000) >> 16); cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + 0xC000) >> 16, (g + 0xC000) >> 16, (b + 0xC000) >> 16); cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + 0x4000) >> 16, (g + 0x4000) >> 16, (b + 0x4000) >> 16); cache += 1; r += dr; g += dg; b += db; } while (--count != 0); } else {
bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { if (nullptr == fPixels) { return false; } SkIRect area; if (!area.intersect(this->bounds(), inArea)) { return false; } U8CPU a = SkColorGetA(color); U8CPU r = SkColorGetR(color); U8CPU g = SkColorGetG(color); U8CPU b = SkColorGetB(color); int height = area.height(); const int width = area.width(); const int rowBytes = this->rowBytes(); switch (this->colorType()) { case kGray_8_SkColorType: { if (255 != a) { r = SkMulDiv255Round(r, a); g = SkMulDiv255Round(g, a); b = SkMulDiv255Round(b, a); } int gray = SkComputeLuminance(r, g, b); uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); while (--height >= 0) { memset(p, gray, width); p += rowBytes; } break; } case kAlpha_8_SkColorType: { uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); while (--height >= 0) { memset(p, a, width); p += rowBytes; } break; } case kARGB_4444_SkColorType: case kRGB_565_SkColorType: { uint16_t* p = this->writable_addr16(area.fLeft, area.fTop); uint16_t v; // make rgb premultiplied if (255 != a) { r = SkMulDiv255Round(r, a); g = SkMulDiv255Round(g, a); b = SkMulDiv255Round(b, a); } if (kARGB_4444_SkColorType == this->colorType()) { v = pack_8888_to_4444(a, r, g, b); } else { v = SkPackRGB16(r >> (8 - SK_R16_BITS), g >> (8 - SK_G16_BITS), b >> (8 - SK_B16_BITS)); } while (--height >= 0) { sk_memset16(p, v, width); p = (uint16_t*)((char*)p + rowBytes); } break; } case kBGRA_8888_SkColorType: case kRGBA_8888_SkColorType: { uint32_t* p = this->writable_addr32(area.fLeft, area.fTop); if (255 != a && kPremul_SkAlphaType == this->alphaType()) { r = SkMulDiv255Round(r, a); g = SkMulDiv255Round(g, a); b = SkMulDiv255Round(b, a); } uint32_t v = kRGBA_8888_SkColorType == this->colorType() ? SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b); while (--height >= 0) { sk_memset32(p, v, width); p = (uint32_t*)((char*)p + rowBytes); } break; } default: return false; // no change, so don't call notifyPixelsChanged() } return true; }
// slower "correct" static int test_srcover2(unsigned dst, unsigned alpha) { return alpha + SkMulDiv255Round(dst, 255 - alpha); }
// Reduce to a single drawBitmapRectToRect call by folding the clipRect's into // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's // paint. static void apply_7(SkDebugCanvas* canvas, int curCommand) { SkSaveLayerCommand* saveLayer0 = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); SkSaveLayerCommand* saveLayer1 = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); SkClipRectCommand* clip2 = (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft; SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop; SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, clip2->rect().width(), clip2->rect().height()); dbmr->setSrcRect(newSrc); dbmr->setDstRect(clip2->rect()); SkColor color = 0xFF000000; int a0, a1; const SkPaint* saveLayerPaint0 = saveLayer0->paint(); if (NULL != saveLayerPaint0) { color = saveLayerPaint0->getColor(); a0 = SkColorGetA(color); } else { a0 = 0xFF; } const SkPaint* saveLayerPaint1 = saveLayer1->paint(); if (NULL != saveLayerPaint1) { color = saveLayerPaint1->getColor(); a1 = SkColorGetA(color); } else { a1 = 0xFF; } int newA = SkMulDiv255Round(a0, a1); SkASSERT(newA <= 0xFF); SkPaint* dbmrPaint = dbmr->paint(); if (NULL != dbmrPaint) { SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); dbmrPaint->setColor(newColor); } else { SkColor newColor = SkColorSetA(color, newA); SkPaint newPaint; newPaint.setColor(newColor); dbmr->setPaint(newPaint); } // remove everything except the drawbitmaprect canvas->deleteDrawCommandAt(curCommand+13); // restore canvas->deleteDrawCommandAt(curCommand+12); // restore canvas->deleteDrawCommandAt(curCommand+11); // restore canvas->deleteDrawCommandAt(curCommand+10); // restore canvas->deleteDrawCommandAt(curCommand+9); // restore canvas->deleteDrawCommandAt(curCommand+7); // clipRect canvas->deleteDrawCommandAt(curCommand+6); // save canvas->deleteDrawCommandAt(curCommand+5); // saveLayer canvas->deleteDrawCommandAt(curCommand+4); // clipRect canvas->deleteDrawCommandAt(curCommand+3); // save canvas->deleteDrawCommandAt(curCommand+2); // saveLayer canvas->deleteDrawCommandAt(curCommand+1); // clipRect canvas->deleteDrawCommandAt(curCommand); // save }
bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, SkBlurStyle style, SkIPoint *margin, SkMask::CreateMode createMode) { int profile_size = SkScalarCeilToInt(6*sigma); int pad = profile_size/2; if (margin) { margin->set( pad, pad ); } dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), SkScalarRoundToInt(src.fTop - pad), SkScalarRoundToInt(src.fRight + pad), SkScalarRoundToInt(src.fBottom + pad)); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = nullptr; int sw = SkScalarFloorToInt(src.width()); int sh = SkScalarFloorToInt(src.height()); if (createMode == SkMask::kJustComputeBounds_CreateMode) { if (style == kInner_SkBlurStyle) { dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } return true; } std::unique_ptr<uint8_t[]> profile(ComputeBlurProfile(sigma)); size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } uint8_t* dp = SkMask::AllocImage(dstSize); dst->fImage = dp; int dstHeight = dst->fBounds.height(); int dstWidth = dst->fBounds.width(); uint8_t *outptr = dp; SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); ComputeBlurredScanline(horizontalScanline, profile.get(), dstWidth, sigma); ComputeBlurredScanline(verticalScanline, profile.get(), dstHeight, sigma); for (int y = 0 ; y < dstHeight ; ++y) { for (int x = 0 ; x < dstWidth ; x++) { unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]); *(outptr++) = maskval; } } if (style == kInner_SkBlurStyle) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = (size_t)(src.width() * src.height()); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); for (int y = 0 ; y < sh ; y++) { uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; uint8_t *inner_scanline = dst->fImage + y*sw; memcpy(inner_scanline, blur_scanline, sw); } SkMask::FreeImage(dp); dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } else if (style == kOuter_SkBlurStyle) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0, sw); } } else if (style == kSolid_SkBlurStyle) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0xff, sw); } } // normal and solid styles are the same for analytic rect blurs, so don't // need to handle solid specially. return true; }