/** * Create a red & green stripes on black texture */ void createTexture() { if (fTextureCreated) { return; } static const int xSize = 16; static const int ySize = 16; fTexture.allocN32Pixels(xSize, ySize); SkPMColor* addr = fTexture.getAddr32(0, 0); for (int y = 0; y < ySize; ++y) { for (int x = 0; x < xSize; ++x) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorBLACK); if ((y % 5) == 0) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorRED); } if ((x % 7) == 0) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorGREEN); } } } fTextureCreated = true; }
static bool compare_procs(SkXfermodeProc proc32, SkXfermodeProc4f proc4f) { const float kTolerance = 1.0f / 255; const SkColor colors[] = { 0, 0xFF000000, 0xFFFFFFFF, 0x80FF0000 }; for (auto s32 : colors) { SkPMColor s_pm32 = SkPreMultiplyColor(s32); SkPM4f s_pm4f = SkColor4f::FromColor(s32).premul(); for (auto d32 : colors) { SkPMColor d_pm32 = SkPreMultiplyColor(d32); SkPM4f d_pm4f = SkColor4f::FromColor(d32).premul(); SkPMColor r32 = proc32(s_pm32, d_pm32); SkPM4f r4f = proc4f(s_pm4f, d_pm4f); SkPM4f r32_4f = SkPM4f::FromPMColor(r32); if (!nearly_equal(r4f, r32_4f, kTolerance)) { return false; } } } return true; }
/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge. The inner ring is red and the outer ring is blue. */ static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) { const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE); const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED); const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK); const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE); return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType, kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite); }
OvalTestView() { fSize.set(SK_Scalar1, SK_Scalar1); fBitmap.setConfig(SkBitmap::kARGB_8888_Config, kILimit, kILimit); fBitmap.allocPixels(); fInsideColor = SkPreMultiplyColor(SK_ColorRED); fOutsideColor = SkPreMultiplyColor(SK_ColorGREEN); }
/** Make the color version of the oversized texture-backed bitmap */ static bool make_ringed_oversized_color_texture_bitmap(GrContext* ctx, TestPixels* result, int width, int height) { static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE); static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED); static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK); static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE); static const SkPMColor kGreen = SkPreMultiplyColor(SK_ColorGREEN); return make_oversized_texture_bitmap<SkPMColor>( ctx, result, width, height, kSkia8888_GrPixelConfig, kBlue, kRed, kBlack, kWhite, kGreen); }
DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_NewFromTexture, reporter, context) { GrTextureProvider* provider = context->textureProvider(); const int w = 10; const int h = 10; SkPMColor storage[w * h]; const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED); sk_memset32(storage, expected0, w * h); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels(); desc.fOrigin = kDefault_GrSurfaceOrigin; desc.fWidth = w; desc.fHeight = h; desc.fConfig = kSkia8888_GrPixelConfig; desc.fSampleCnt = 0; SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4)); if (!tex) { REPORTER_ASSERT(reporter, false); return; } GrBackendTextureDesc backendDesc; backendDesc.fConfig = kSkia8888_GrPixelConfig; backendDesc.fFlags = kRenderTarget_GrBackendTextureFlag; backendDesc.fWidth = w; backendDesc.fHeight = h; backendDesc.fSampleCnt = 0; backendDesc.fTextureHandle = tex->getTextureHandle(); TextureReleaseChecker releaseChecker; SkAutoTUnref<SkImage> refImg( SkImage::NewFromTexture(context, backendDesc, kPremul_SkAlphaType, TextureReleaseChecker::Release, &releaseChecker)); SkAutoTUnref<SkImage> cpyImg(SkImage::NewFromTextureCopy(context, backendDesc, kPremul_SkAlphaType)); check_image_color(reporter, refImg, expected0); check_image_color(reporter, cpyImg, expected0); // Now lets jam new colors into our "external" texture, and see if the images notice const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE); sk_memset32(storage, expected1, w * h); tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp); // The cpy'd one should still see the old color #if 0 // There is no guarantee that refImg sees the new color. We are free to have made a copy. Our // write pixels call violated the contract with refImg and refImg is now undefined. check_image_color(reporter, refImg, expected1); #endif check_image_color(reporter, cpyImg, expected0); // Now exercise the release proc REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); refImg.reset(nullptr); // force a release of the image REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); }
static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { switch (mode) { case SkXfermode::kSrc_Mode: return src; case SkXfermode::kDst_Mode: return dst; default: { SkPMColor pmS = SkPreMultiplyColor(src); SkPMColor pmD = SkPreMultiplyColor(dst); SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD); return SkUnPreMultiply::PMColorToColor(result); } } }
static inline void test_fast_interp(skiatest::Reporter* reporter) { SkRandom r; U8CPU a0 = 0; U8CPU a255 = 255; for (int i = 0; i < 200; i++) { SkColor colorSrc = r.nextU(); SkColor colorDst = r.nextU(); SkPMColor src = SkPreMultiplyColor(colorSrc); SkPMColor dst = SkPreMultiplyColor(colorDst); REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst); REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src); } }
static void make_bm(SkBitmap* bm) { const SkPMColor colors[] = { SkPreMultiplyColor(SK_ColorRED), SkPreMultiplyColor(SK_ColorGREEN), SkPreMultiplyColor(SK_ColorBLUE), SkPreMultiplyColor(SK_ColorWHITE) }; SkColorTable* ctable = new SkColorTable(colors, 4); bm->allocPixels(SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kOpaque_SkAlphaType), nullptr, ctable); ctable->unref(); *bm->getAddr8(0, 0) = 0; *bm->getAddr8(1, 0) = 1; *bm->getAddr8(0, 1) = 2; *bm->getAddr8(1, 1) = 3; }
DEF_TEST(Color4f_colorfilter, reporter) { struct { SkColorFilter* (*fFact)(); bool fSupports4f; const char* fName; } recs[] = { { make_mode_cf, true, "mode" }, { make_mx_cf, true, "matrix" }, { make_compose_cf, true, "compose" }, }; // prepare the src const int N = 100; SkPMColor src4b[N]; SkPM4f src4f[N]; SkRandom rand; for (int i = 0; i < N; ++i) { src4b[i] = SkPreMultiplyColor(rand.nextU()); src4f[i] = SkPM4f::FromPMColor(src4b[i]); } // confirm that our srcs are (nearly) equal REPORTER_ASSERT(reporter, compare_spans(src4f, src4b, N)); for (const auto& rec : recs) { SkAutoTUnref<SkColorFilter> filter(rec.fFact()); SkPMColor dst4b[N]; filter->filterSpan(src4b, N, dst4b); SkPM4f dst4f[N]; filter->filterSpan4f(src4f, N, dst4f); REPORTER_ASSERT(reporter, compare_spans(dst4f, dst4b, N)); } }
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device) { // cache premultiplied versions in 4444 SkPMColor c = SkPreMultiplyColor(paint.getColor()); fPMColor16 = SkPixel32ToPixel4444(c); if (paint.isDither()) { fPMColor16Other = SkDitherPixel32To4444(c); } else { fPMColor16Other = fPMColor16; } // cache raw versions in 4444 fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4, SkColorGetG(c) >> 4, SkColorGetB(c) >> 4); if (paint.isDither()) { fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); } else { fRawColor16Other = fRawColor16; } #if 0 /// don't think this assertion is true, but need it be? // our dithered color will be the same or more opaque than the original // so use dithered to compute our scale SkASSERT(SkGetPackedA4444(fPMColor16Other) >= SkGetPackedA4444(fPMColor16)); #endif fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other)); if (16 == fScale16) { // force the original to also be opaque fPMColor16 |= (0xF << SK_A4444_SHIFT); } }
static SkShader* createChecker() { // SkColor colors[] = { 0xFFFDFDFD, 0xFFF4F4F4 }; SkColor colors[] = { 0xFFFFFFFF, 0xFFFFFFFF }; SkBitmap bm; bm.allocN32Pixels(2, 2); bm.lockPixels(); *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(colors[0]); *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(colors[1]); SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(12, 12); s->setLocalMatrix(m); return s; }
void SkGL::SetColor(SkColor c) { SkPMColor pm = SkPreMultiplyColor(c); gl_pmcolor(SkGetPackedR32(pm), SkGetPackedG32(pm), SkGetPackedB32(pm), SkGetPackedA32(pm)); }
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device) { // cache premultiplied versions in 4444 SkPMColor c = SkPreMultiplyColor(paint.getColor()); fPMColor16 = SkPixel32ToPixel4444(c); if (paint.isDither()) { fPMColor16Other = SkDitherPixel32To4444(c); } else { fPMColor16Other = fPMColor16; } // cache raw versions in 4444 fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4, SkColorGetG(c) >> 4, SkColorGetB(c) >> 4); if (paint.isDither()) { fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); } else { fRawColor16Other = fRawColor16; } fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other)); if (16 == fScale16) { // force the original to also be opaque fPMColor16 |= (0xF << SK_A4444_SHIFT); } }
static void FromColor_D32(void* dst, const SkColor src[], int width, int, int) { SkPMColor* d = (SkPMColor*)dst; for (int i = 0; i < width; i++) { *d++ = SkPreMultiplyColor(*src++); } }
void SkGL::SetRGBA(uint8_t rgba[], const SkColor src[], int count) { for (int i = 0; i < count; i++) { SkPMColor c = SkPreMultiplyColor(*src++); *rgba++ = SkGetPackedR32(c); *rgba++ = SkGetPackedG32(c); *rgba++ = SkGetPackedB32(c); *rgba++ = SkGetPackedA32(c); } }
static inline void test_premul(skiatest::Reporter* reporter) { for (int a = 0; a <= 255; a++) { for (int x = 0; x <= 255; x++) { SkColor c0 = SkColorSetARGB(a, x, x, x); SkPMColor p0 = SkPreMultiplyColor(c0); SkColor c1 = SkUnPreMultiply::PMColorToColor(p0); SkPMColor p1 = SkPreMultiplyColor(c1); // we can't promise that c0 == c1, since c0 -> p0 is a many to one // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1 REPORTER_ASSERT(reporter, p0 == p1); { int ax = SkMulDiv255Ceiling(x, a); REPORTER_ASSERT(reporter, ax <= a); } } } }
static void FromColor_D4444(void* dst, const SkColor src[], int width, int x, int y) { SkPMColor16* d = (SkPMColor16*)dst; DITHER_4444_SCAN(y); for (int stop = x + width; x < stop; x++) { SkPMColor c = SkPreMultiplyColor(*src++); *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x)); // *d++ = SkPixel32ToPixel4444(c); } }
void onDraw(const int loops, SkCanvas* canvas) override { // Unlike blackhole, junk can and probably will be a register. uint32_t junk = 0; uint32_t seed = 0; for (int i = 0; i < loops; i++) { SkPMColor colors[4]; #ifdef SK_DEBUG for (int i = 0; i < 4; i++) { // Our SkASSERTs will remind us that it's technically required that we premultiply. colors[i] = SkPreMultiplyColor(lcg_rand(&seed)); } #else // But it's a lot faster not to, and this code won't really mind the non-PM colors. (void)lcg_rand(&seed); colors[0] = seed + 0; colors[1] = seed + 1; colors[2] = seed + 2; colors[3] = seed + 3; #endif SkPMFloat fa,fb,fc,fd; if (kWide) { SkPMFloat::From4PMColors(colors, &fa, &fb, &fc, &fd); } else { fa = SkPMFloat::FromPMColor(colors[0]); fb = SkPMFloat::FromPMColor(colors[1]); fc = SkPMFloat::FromPMColor(colors[2]); fd = SkPMFloat::FromPMColor(colors[3]); } SkPMColor back[4]; switch (kClamp << 1 | kWide) { case 0: { back[0] = fa.get(); back[1] = fb.get(); back[2] = fc.get(); back[3] = fd.get(); } break; case 1: SkPMFloat::To4PMColors(fa, fb, fc, fd, back); break; case 2: { back[0] = fa.clamped(); back[1] = fb.clamped(); back[2] = fc.clamped(); back[3] = fd.clamped(); } break; case 3: SkPMFloat::ClampTo4PMColors(fa, fb, fc, fd, back); break; } for (int i = 0; i < 4; i++) { junk ^= back[i]; } } blackhole ^= junk; }
// https://bug.skia.org/4390 DEF_TEST(ImageFromIndex8Bitmap, r) { SkPMColor pmColors[1] = {SkPreMultiplyColor(SK_ColorWHITE)}; SkBitmap bm; SkAutoTUnref<SkColorTable> ctable( new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors))); SkImageInfo info = SkImageInfo::Make(1, 1, kIndex_8_SkColorType, kPremul_SkAlphaType); bm.allocPixels(info, nullptr, ctable); SkAutoLockPixels autoLockPixels(bm); *bm.getAddr8(0, 0) = 0; SkAutoTUnref<SkImage> img(SkImage::NewFromBitmap(bm)); REPORTER_ASSERT(r, img.get() != nullptr); }
static void make_bm(SkBitmap* bm) { const SkColor colors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE }; SkPMColor colorsPM[4]; for (size_t i = 0; i < SK_ARRAY_COUNT(colors); ++i) { colorsPM[i] = SkPreMultiplyColor(colors[i]); } bm->allocN32Pixels(2, 2, true); *bm->getAddr32(0, 0) = colorsPM[0]; *bm->getAddr32(1, 0) = colorsPM[1]; *bm->getAddr32(0, 1) = colorsPM[2]; *bm->getAddr32(1, 1) = colorsPM[3]; }
static void test_peek(skiatest::Reporter* reporter, SkImage* image, bool expectPeekSuccess) { SkImageInfo info; size_t rowBytes; const void* addr = image->peekPixels(&info, &rowBytes); bool success = SkToBool(addr); REPORTER_ASSERT(reporter, expectPeekSuccess == success); if (success) { REPORTER_ASSERT(reporter, 20 == info.width()); REPORTER_ASSERT(reporter, 20 == info.height()); REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || kOpaque_SkAlphaType == info.alphaType()); REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); REPORTER_ASSERT(reporter, SkPreMultiplyColor(SK_ColorWHITE) == *(const SkPMColor*)addr); } }
static void test_read_pixels(skiatest::Reporter* reporter, SkImage* image) { const SkPMColor expected = SkPreMultiplyColor(SK_ColorWHITE); const SkPMColor notExpected = ~expected; const int w = 2, h = 2; const size_t rowBytes = w * sizeof(SkPMColor); SkPMColor pixels[w*h]; SkImageInfo info; info = SkImageInfo::MakeUnknown(w, h); REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); // out-of-bounds should fail info = SkImageInfo::MakeN32Premul(w, h); REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); // top-left should succeed sk_memset32(pixels, notExpected, w*h); REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); // bottom-right should succeed sk_memset32(pixels, notExpected, w*h); REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, image->width() - w, image->height() - h)); REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); // partial top-left should succeed sk_memset32(pixels, notExpected, w*h); REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); REPORTER_ASSERT(reporter, pixels[3] == expected); REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); // partial bottom-right should succeed sk_memset32(pixels, notExpected, w*h); REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, image->width() - 1, image->height() - 1)); REPORTER_ASSERT(reporter, pixels[0] == expected); REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); }
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels, reporter, ctxInfo) { auto* ctx = ctxInfo.grContext(); if (!ctx->priv().caps()->mipMapSupport()) { return; } static constexpr auto kCreateWithMipMaps = true; auto surf = SkSurface::MakeRenderTarget( ctx, SkBudgeted::kYes, SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType), 1, kTopLeft_GrSurfaceOrigin, nullptr, kCreateWithMipMaps); if (!surf) { return; } surf->getCanvas()->drawColor(SK_ColorDKGRAY); auto img = surf->makeImageSnapshot(); if (!img) { return; } surf.reset(); GrBackendTexture btex; SkImage::BackendTextureReleaseProc texRelease; if (!SkImage::MakeBackendTextureFromSkImage(ctx, std::move(img), &btex, &texRelease)) { // Not all backends support stealing textures yet. // ERRORF(reporter, "Could not turn image into texture"); return; } REPORTER_ASSERT(reporter, btex.hasMipMaps()); // Reimport the texture as an image and perform a downsampling draw with medium quality which // should use the upper MIP levels. img = SkImage::MakeFromTexture(ctx, btex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); const auto singlePixelInfo = SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); surf = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, singlePixelInfo, 1, kTopLeft_GrSurfaceOrigin, nullptr); SkPaint paint; paint.setFilterQuality(kMedium_SkFilterQuality); surf->getCanvas()->drawImageRect(img, SkRect::MakeWH(1, 1), &paint); uint32_t pixel; surf->readPixels(singlePixelInfo, &pixel, sizeof(uint32_t), 0, 0); REPORTER_ASSERT(reporter, pixel == SkPreMultiplyColor(SK_ColorDKGRAY)); img.reset(); texRelease(btex); }
virtual void onDraw(SkCanvas* canvas) { drawBG(canvas); SkBitmap sprite; sprite.setConfig(SkBitmap::kARGB_8888_Config, 4, 4, 4*sizeof(SkColor)); const SkColor spriteData[16] = { SK_ColorBLACK, SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA, SK_ColorCYAN, SK_ColorBLACK }; sprite.allocPixels(); sprite.lockPixels(); SkPMColor* addr = sprite.getAddr32(0, 0); for (size_t i = 0; i < SK_ARRAY_COUNT(spriteData); ++i) { addr[i] = SkPreMultiplyColor(spriteData[i]); } sprite.unlockPixels(); // We draw a magnified subrect of the sprite // sample interpolation may cause color bleeding around edges // the subrect is a pure white area SkIRect srcRect; SkRect dstRect; SkPaint paint; paint.setFilterBitmap(true); //First row : full texture with and without filtering srcRect.setXYWH(0, 0, 4, 4); dstRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0) , SkIntToScalar(100), SkIntToScalar(100)); canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint); dstRect.setXYWH(SkIntToScalar(100), SkIntToScalar(0) , SkIntToScalar(100), SkIntToScalar(100)); canvas->drawBitmapRect(sprite, &srcRect, dstRect); //Second row : sub rect of texture with and without filtering srcRect.setXYWH(1, 1, 2, 2); dstRect.setXYWH(SkIntToScalar(25), SkIntToScalar(125) , SkIntToScalar(50), SkIntToScalar(50)); canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint); dstRect.setXYWH(SkIntToScalar(125), SkIntToScalar(125) , SkIntToScalar(50), SkIntToScalar(50)); canvas->drawBitmapRect(sprite, &srcRect, dstRect); }
void onDraw(const int loops, SkCanvas* canvas) override { // Unlike blackhole, junk can and probably will be a register. uint32_t junk = 0; uint32_t seed = 0; for (int i = 0; i < loops; i++) { SkPMColor color; #ifdef SK_DEBUG // Our SkASSERTs will remind us that it's technically required that we premultiply. color = SkPreMultiplyColor(lcg_rand(&seed)); #else // But it's a lot faster not to, and this code won't really mind the non-PM colors. color = lcg_rand(&seed); #endif auto f = SkPMFloat::FromPMColor(color); SkPMColor back = f.round(); junk ^= back; } blackhole ^= junk; }
static void make_bm(SkBitmap* bm) { const SkColor colors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE }; SkPMColor colorsPM[4]; for (size_t i = 0; i < SK_ARRAY_COUNT(colors); ++i) { colorsPM[i] = SkPreMultiplyColor(colors[i]); } SkColorTable* ctable = new SkColorTable(colorsPM, 4); bm->setConfig(SkBitmap::kIndex8_Config, 2, 2); bm->allocPixels(ctable); ctable->unref(); *bm->getAddr8(0, 0) = 0; *bm->getAddr8(1, 0) = 1; *bm->getAddr8(0, 1) = 2; *bm->getAddr8(1, 1) = 3; }
static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { switch (info.colorType()) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: break; default: return; // nothing to do } // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian, // and in either case, the alpha-byte is always in the same place, so we can safely call // SkPreMultiplyColor() // SkColor* row = (SkColor*)pixels; for (int y = 0; y < info.height(); ++y) { for (int x = 0; x < info.width(); ++x) { row[x] = SkPreMultiplyColor(row[x]); } } }
static void make_bm(SkBitmap* bm) { const SkColor colors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE }; SkPMColor colorsPM[4]; for (size_t i = 0; i < SK_ARRAY_COUNT(colors); ++i) { colorsPM[i] = SkPreMultiplyColor(colors[i]); } SkColorTable* ctable = new SkColorTable(colorsPM, 4); bm->allocPixels(SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kPremul_SkAlphaType), NULL, ctable); ctable->unref(); *bm->getAddr8(0, 0) = 0; *bm->getAddr8(1, 0) = 1; *bm->getAddr8(0, 1) = 2; *bm->getAddr8(1, 1) = 3; }
DEF_TEST(SkPMFloat, r) { // Test SkPMColor <-> SkPMFloat SkPMColor c = SkPreMultiplyColor(0xFFCC9933); SkPMFloat pmf; pmf.set(c); REPORTER_ASSERT(r, SkScalarNearlyEqual(1.0f, pmf.a())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.8f, pmf.r())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.6f, pmf.g())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.2f, pmf.b())); REPORTER_ASSERT(r, c == pmf.get()); // Test clamping. SkPMFloat unclamped; unclamped.setA(+2.0f); unclamped.setR(+0.2f); unclamped.setG(-0.2f); unclamped.setB(-5.0f); SkPMFloat clamped; clamped.set(unclamped.clamped()); REPORTER_ASSERT(r, SkScalarNearlyEqual(1.0f, clamped.a())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.2f, clamped.r())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.0f, clamped.g())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.0f, clamped.b())); // Test SkPMFloat <-> Sk4f conversion. Sk4f fs = clamped; SkPMFloat scaled = fs.multiply(Sk4f(4,4,4,4)); REPORTER_ASSERT(r, SkScalarNearlyEqual(4.0f, scaled.a())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.8f, scaled.r())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.0f, scaled.g())); REPORTER_ASSERT(r, SkScalarNearlyEqual(0.0f, scaled.b())); }