/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { // Set the row int height = dstInfo.height(); int row; if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { row = height - y - 1; } else { row = y; } // Set the pixel based on destination color type switch (dstInfo.colorType()) { case kN32_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, row * (int) dstRowBytes); dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[x] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } }
/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue); break; } case kBGRA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } } }
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; } } }
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) { a = SkAlpha255To256(a); r = SkAlphaMul(r, a); g = SkAlphaMul(g, a); b = SkAlphaMul(b, a); } fPMColor = SkPackARGB32(a, r, g, b); return true; }
static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { #ifdef SK_SHOW_TEXT_BLIT_COVERAGE r = SkTMax(r, (U8CPU)0x40); g = SkTMax(g, (U8CPU)0x40); b = SkTMax(b, (U8CPU)0x40); #endif return SkPack888ToRGB16(r, g, b); }
void SkPowerMode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]) { for (int i = 0; i < count; i++) { SkPMColor c = src[i]; int r = SkGetPackedR32(c); int g = SkGetPackedG32(c); int b = SkGetPackedB32(c); r = fTable[r]; g = fTable[g]; b = fTable[b]; dst[i] = SkPack888ToRGB16(r, g, b); } }
static SkSwizzler::ResultAlpha swizzle_mask24_to_565( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination uint16_t* dstPtr = (uint16_t*) dstRow; for (int i = 0; i < 3*width; i += 3) { uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); dstPtr[i/3] = SkPack888ToRGB16(red, green, blue); } return SkSwizzler::kOpaque_ResultAlpha; }
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; }
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 void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst, const SkMaskGamma::PreBlend& maskPreBlend) { SkASSERT(SkBitmap::kA8_Config == src.config()); SkASSERT(SkMask::kLCD16_Format == dst.fFormat); const int width = dst.fBounds.width(); const int height = dst.fBounds.height(); uint16_t* dstP = (uint16_t*)dst.fImage; size_t dstRB = dst.fRowBytes; for (int y = 0; y < height; ++y) { const uint8_t* srcP = src.getAddr8(0, y); for (int x = 0; x < width; ++x) { U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); dstP[x] = SkPack888ToRGB16(r, g, b); } dstP = (uint16_t*)((char*)dstP + dstRB); } }
static void pack4xHToLCD16(const SkPixmap& src, const SkMask& dst, const SkMaskGamma::PreBlend& maskPreBlend) { #define SAMPLES_PER_PIXEL 4 #define LCD_PER_PIXEL 3 SkASSERT(kAlpha_8_SkColorType == src.colorType()); SkASSERT(SkMask::kLCD16_Format == dst.fFormat); const int sample_width = src.width(); const int height = src.height(); uint16_t* dstP = (uint16_t*)dst.fImage; size_t dstRB = dst.fRowBytes; // An N tap FIR is defined by // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] // or // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) // The strategy is to use one FIR (different coefficients) for each of r, g, and b. // This means using every 4th FIR output value of each FIR and discarding the rest. // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'. // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.) // These are in some fixed point repesentation. // Adding up to more than one simulates ink spread. // For implementation reasons, these should never add up to more than two. // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast'). // Calculated using tools/generate_fir_coeff.py // With this one almost no fringing is ever seen, but it is imperceptibly blurry. // The lcd smoothed text is almost imperceptibly different from gray, // but is still sharper on small stems and small rounded corners than gray. // This also seems to be about as wide as one can get and only have a three pixel kernel. // TODO: caculate these at runtime so parameters can be adjusted (esp contrast). static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = { //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted. { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, }, //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, }, //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted. { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, }, }; for (int y = 0; y < height; ++y) { const uint8_t* srcP = src.addr8(0, y); // TODO: this fir filter implementation is straight forward, but slow. // It should be possible to make it much faster. for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) { int fir[LCD_PER_PIXEL] = { 0 }; for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4) ; sample_index < SkMin32(sample_x + 8, sample_width) ; ++sample_index, ++coeff_index) { int sample_value = srcP[sample_index]; for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value; } } for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { fir[subpxl_index] /= 0x100; fir[subpxl_index] = SkMin32(fir[subpxl_index], 255); } U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR); U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG); U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB); #if SK_SHOW_TEXT_BLIT_COVERAGE r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); #endif dstP[pixel_x] = SkPack888ToRGB16(r, g, b); } dstP = (uint16_t*)((char*)dstP + dstRB); } }
static uint16_t grayToRGB16(U8CPU gray) { #ifdef SK_SHOW_TEXT_BLIT_COVERAGE gray = SkTMax(gray, (U8CPU)0x40); #endif return SkPack888ToRGB16(gray, gray, gray); }