void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { if (alpha == 0 || fSrcA == 0) { return; } uint32_t* device = fDevice.getAddr32(x, y); uint32_t color = fPMColor; if (alpha != 255) { color = SkAlphaMulQ(color, SkAlpha255To256(alpha)); } unsigned dst_scale = 255 - SkGetPackedA32(color); uint32_t prevDst = ~device[0]; uint32_t result SK_INIT_TO_AVOID_WARNING; uint32_t rowBytes = fDevice.rowBytes(); while (--height >= 0) { uint32_t dst = device[0]; if (dst != prevDst) { result = color + SkAlphaMulQ(dst, dst_scale); prevDst = dst; } device[0] = result; device = (uint32_t*)((char*)device + rowBytes); } }
void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { if (fSrcA == 0) { return; } uint32_t color = fPMColor; uint32_t* device = fDevice.getAddr32(x, y); unsigned opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case for (;;) { int count = runs[0]; SkASSERT(count >= 0); if (count <= 0) { return; } unsigned aa = antialias[0]; if (aa) { if ((opaqueMask & aa) == 255) { sk_memset32(device, color, count); } else { uint32_t sc = SkAlphaMulQ(color, aa); unsigned dst_scale = 255 - SkGetPackedA32(sc); int n = count; do { --n; device[n] = sc + SkAlphaMulQ(device[n], dst_scale); } while (n > 0); } } runs += count; antialias += count; device += count; } }
void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { SkASSERT(mask.fBounds.contains(clip)); if (mask.fFormat == SkMask::kBW_Format) { SkARGB32_BlitBW(fDevice, mask, clip, fPMColor); return; } int x = clip.fLeft; int y = clip.fTop; int width = clip.width(); int height = clip.height(); uint32_t* device = fDevice.getAddr32(x, y); const uint8_t* alpha = mask.getAddr(x, y); uint32_t srcColor = fPMColor; unsigned devRB = fDevice.rowBytes() - (width << 2); unsigned maskRB = mask.fRowBytes - width; do { int w = width; do { unsigned aa = *alpha++; *device = SkAlphaMulQ(srcColor, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); device += 1; } while (--w != 0); device = (uint32_t*)((char*)device + devRB); alpha += maskRB; } while (--height != 0); }
void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader::Context* shaderContextA = fShaderContextA; SkShader::Context* shaderContextB = fShaderContextB; SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); SkPMColor tmp[TMP_COLOR_COUNT]; SkXfermode* xfer = SkXfermode::Peek(mode); if (nullptr == xfer) { // 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); xfer->xfer32(result, tmp, n, nullptr); 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); } }
void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader* shaderA = fShaderA; SkShader* shaderB = fShaderB; SkXfermode* mode = fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 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; } shaderA->shadeSpan(x, y, result, n); shaderB->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; } shaderA->shadeSpan(x, y, result, n); shaderB->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); } }
// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc] static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) { #if 0 // this is the old, more-correct way, but it doesn't guarantee that dst==255 // will always stay opaque return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); #else // this is slightly faster, but more importantly guarantees that dst==255 // will always stay opaque return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src)); #endif }
void TransparencyWin::compositeTextComposite() { if (!m_validLayer) return; const SkBitmap& bitmap = m_layerBuffer->context()->layerBitmap(GraphicsContext::ReadWrite); SkColor textColor = m_textCompositeColor.rgb(); for (int y = 0; y < m_layerSize.height(); y++) { uint32_t* row = bitmap.getAddr32(0, y); for (int x = 0; x < m_layerSize.width(); x++) { // The alpha is the average of the R, G, and B channels. int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3; // Apply that alpha to the text color and write the result. row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha)); } } // Now the layer has text with the proper color and opacity. m_destContext->save(); // We want to use Untransformed space (see above) SkMatrix identity; identity.reset(); m_destContext->setMatrix(identity); SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY() }; // Note that we need to specify the source layer subset, since the bitmap // may have been cached and it could be larger than what we're using. SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() }; m_destContext->drawBitmapRect(bitmap, &sourceRect, destRect, 0); m_destContext->restore(); }
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 { uint32_t* device = fDevice.getAddr32(clip.fLeft, clip.fTop); const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop); unsigned width = clip.width(); unsigned height = clip.height(); unsigned deviceRB = fDevice.rowBytes() - (width << 2); unsigned maskRB = mask.fRowBytes - width; SkASSERT((int)height > 0); SkASSERT((int)width > 0); SkASSERT((int)deviceRB >= 0); SkASSERT((int)maskRB >= 0); 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); } }
void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { if (fSrcA == 0) { return; } uint32_t color = fPMColor; uint32_t* device = fDevice.writable_addr32(x, y); unsigned opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case for (;;) { int count = runs[0]; SkASSERT(count >= 0); if (count <= 0) { return; } unsigned aa = antialias[0]; if (aa) { if ((opaqueMask & aa) == 255) { sk_memset32(device, color, count); } else { uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa)); SkBlitRow::Color32(device, device, count, sc); } } runs += count; antialias += count; device += count; } }
void SkARGB32_Blitter::blitH(int x, int y, int width) { SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); if (fSrcA == 0) { return; } uint32_t* device = fDevice.getAddr32(x, y); if (fSrcA == 255) { sk_memset32(device, fPMColor, width); } else { uint32_t color = fPMColor; unsigned dst_scale = SkAlpha255To256(255 - fSrcA); uint32_t prevDst = ~device[0]; // so we always fail the test the first time uint32_t result SK_INIT_TO_AVOID_WARNING; for (int i = 0; i < width; i++) { uint32_t currDst = device[i]; if (currDst != prevDst) { result = color + SkAlphaMulQ(currDst, dst_scale); prevDst = currDst; } device[i] = result; } } }
void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) { SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height()); if (fSrcA == 0) { return; } uint32_t* device = fDevice.getAddr32(x, y); uint32_t color = fPMColor; if (fSrcA == 255) { while (--height >= 0) { sk_memset32(device, color, width); device = (uint32_t*)((char*)device + fDevice.rowBytes()); } } else { unsigned dst_scale = SkAlpha255To256(255 - fSrcA); while (--height >= 0) { uint32_t prevDst = ~device[0]; uint32_t result SK_INIT_TO_AVOID_WARNING; for (int i = 0; i < width; i++) { uint32_t dst = device[i]; if (dst != prevDst) { result = color + SkAlphaMulQ(dst, dst_scale); prevDst = dst; } device[i] = result; } device = (uint32_t*)((char*)device + fDevice.rowBytes()); } } }
void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { uint32_t* device = fDevice.getAddr32(x, y); SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT); for (;;) { int count = runs[0]; SkASSERT(count >= 0); if (count <= 0) { return; } unsigned aa = antialias[0]; if (aa) { if (aa == 255) { sk_memset32(device, black, count); } else { SkPMColor src = aa << SK_A32_SHIFT; unsigned dst_scale = 256 - aa; int n = count; do { --n; device[n] = src + SkAlphaMulQ(device[n], dst_scale); } while (n > 0); } } runs += count; antialias += count; device += count; } }
void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) { SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); uint32_t* device = fDevice.getAddr32(x, y); if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { fShader->shadeSpan(x, y, device, width); } else { SkPMColor* span = fBuffer; fShader->shadeSpan(x, y, span, width); if (fXfermode) { fXfermode->xfer32(device, span, width, NULL); } else { for (int i = 0; i < width; i++) { uint32_t src = span[i]; if (src) { unsigned srcA = SkGetPackedA32(src); if (srcA != 0xFF) { src += SkAlphaMulQ(device[i], SkAlpha255To256(255 - srcA)); } device[i] = src; } } } } }
// extract the result vertices and indices from the GrAAConvexTessellator static void extract_verts(const GrAAConvexTessellator& tess, void* vertices, size_t vertexStride, GrColor color, uint16_t firstIndex, uint16_t* idxs, bool tweakAlphaForCoverage) { intptr_t verts = reinterpret_cast<intptr_t>(vertices); for (int i = 0; i < tess.numPts(); ++i) { *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i); } // Make 'verts' point to the colors verts += sizeof(SkPoint); for (int i = 0; i < tess.numPts(); ++i) { if (tweakAlphaForCoverage) { SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255); unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i)); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = tess.coverage(i); } } for (int i = 0; i < tess.numIndices(); ++i) { idxs[i] = tess.index(i) + firstIndex; } }
void SkTransparentShader::TransparentShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { unsigned scale = SkAlpha255To256(this->getPaintAlpha()); switch (fDevice->colorType()) { case kN32_SkColorType: 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 kRGB_565_SkColorType: { 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 = this->getPaintAlpha(); 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 kAlpha_8_SkColorType: { 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; } default: SkDEBUGFAIL("colorType not supported as a destination device"); break; } }
void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { if (alpha == 0 || fSrcA == 0) { return; } uint32_t* device = fDevice.getAddr32(x, y); uint32_t color = fPMColor; if (alpha != 255) { color = SkAlphaMulQ(color, SkAlpha255To256(alpha)); } unsigned dst_scale = 255 - SkGetPackedA32(color); uint32_t rowBytes = fDevice.rowBytes(); while (--height >= 0) { device[0] = color + SkAlphaMulQ(device[0], dst_scale); device = (uint32_t*)((char*)device + rowBytes); } }
virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor[], int count, const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && count >= 0); if (NULL == aa) { memset(dst, 0, count << 2); } else { for (int i = count - 1; i >= 0; --i) { unsigned a = aa[i]; if (0xFF == a) { dst[i] = 0; } else if (a != 0) { dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a)); } } } }
virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor src[], int count, const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && src); if (count <= 0) { return; } if (NULL != aa) { return this->INHERITED::xfer32(dst, src, count, aa); } do { unsigned a = SkGetPackedA32(*src); *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a)); dst++; src++; } while (--count != 0); }
// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) { return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); }
// kSrcIn_Mode, //!< [Sa * Da, Sc * Da] static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) { return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst))); }
// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc] static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) { // this is the reverse of srcover, just flipping src and dst // see srcover's comment about the 256 for opaqueness guarantees return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst)); }
void generateAAStrokeRectGeometry(void* vertices, size_t offset, size_t vertexStride, int outerVertexNum, int innerVertexNum, GrColor color, const SkRect& devOutside, const SkRect& devOutsideAssist, const SkRect& devInside, bool miterStroke, bool tweakAlphaForCoverage) const { intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset; // We create vertices for four nested rectangles. There are two ramps from 0 to full // coverage, one on the exterior of the stroke and the other on the interior. // The following pointers refer to the four rects, from outermost to innermost. SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride); SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride); SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vertexStride); #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX // TODO: this only really works if the X & Y margins are the same all around // the rect (or if they are all >= 1.0). SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); if (miterStroke) { inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); } else { inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); } SkASSERT(inset >= 0); #else SkScalar inset = SK_ScalarHalf; #endif if (miterStroke) { // outermost set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); // inner two set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); // innermost set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); } else { SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vertexStride); // outermost set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); // outer one of the inner two set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset); // inner one of the inner two set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); // innermost set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); } // Make verts point to vertex color and then set all the color and coverage vertex attrs // values. The outermost rect has 0 coverage verts += sizeof(SkPoint); for (int i = 0; i < outerVertexNum; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0; } } // scale is the coverage for the the inner two rects. int scale; if (inset < SK_ScalarHalf) { scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); SkASSERT(scale >= 0 && scale <= 255); } else { scale = 0xff; } float innerCoverage = GrNormalizeByteToFloat(scale); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); verts += outerVertexNum * vertexStride; for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage; } } // The innermost rect has 0 coverage verts += (outerVertexNum + innerVertexNum) * vertexStride; for (int i = 0; i < innerVertexNum; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0; } } }
static void generate_aa_fill_rect_geometry(intptr_t verts, size_t vertexStride, GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect& devRect, bool tweakAlphaForCoverage, const SkMatrix* localMatrix) { SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); SkScalar inset; if (viewMatrix.rectStaysRect()) { inset = SkMinScalar(devRect.width(), SK_Scalar1); inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); } else { // compute transformed (1, 0) and (0, 1) vectors SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]}, {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}}; SkScalar len1 = SkPoint::Normalize(&vec[0]); vec[0].scale(SK_ScalarHalf); SkScalar len2 = SkPoint::Normalize(&vec[1]); vec[1].scale(SK_ScalarHalf); inset = SkMinScalar(len1 * rect.width(), SK_Scalar1); inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height()); // create the rotated rect SkPointPriv::SetRectFan(fan0Pos, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); SkMatrixPriv::MapPointsWithStride(viewMatrix, fan0Pos, vertexStride, 4); // Now create the inset points and then outset the original // rotated points // TL *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1]; // BL *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1]; // BR *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1]; // TR *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1]; } if (localMatrix) { SkMatrix invViewMatrix; if (!viewMatrix.invert(&invViewMatrix)) { SkDebugf("View matrix is non-invertible, local coords will be wrong."); invViewMatrix = SkMatrix::I(); } SkMatrix localCoordMatrix; localCoordMatrix.setConcat(*localMatrix, invViewMatrix); SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor)); SkMatrixPriv::MapPointsWithStride(localCoordMatrix, fan0Loc, vertexStride, fan0Pos, vertexStride, 8); } // Make verts point to vertex color and then set all the color and coverage vertex attrs // values. verts += sizeof(SkPoint); // The coverage offset is always the last vertex attribute intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint); for (int i = 0; i < 4; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0; } } int scale; if (inset < SK_ScalarHalf) { scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); SkASSERT(scale >= 0 && scale <= 255); } else { scale = 0xff; } verts += 4 * vertexStride; float innerCoverage = GrNormalizeByteToFloat(scale); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); for (int i = 0; i < 4; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage; } } }
void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target, GrDrawState* drawState, GrColor color, const SkRect& rect, const SkMatrix& combinedMatrix, const SkRect& devRect) { GrDrawState::AutoRestoreEffects are(drawState); CoverageAttribType type; SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type)); size_t vertexStride = gp->getVertexStride(); GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0); if (!geo.succeeded()) { SkDebugf("Failed to get space for vertices!\n"); return; } if (NULL == fAAFillRectIndexBuffer) { fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect); } GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer; if (NULL == indexBuffer) { SkDebugf("Failed to create index buffer!\n"); return; } intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); if (combinedMatrix.rectStaysRect()) { // Temporarily #if'ed out. We don't want to pass in the devRect but // right now it is computed in GrContext::apply_aa_to_rect and we don't // want to throw away the work #if 0 SkRect devRect; combinedMatrix.mapRect(&devRect, rect); #endif set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); } else { // compute transformed (1, 0) and (0, 1) vectors SkVector vec[2] = { { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } }; vec[0].normalize(); vec[0].scale(SK_ScalarHalf); vec[1].normalize(); vec[1].scale(SK_ScalarHalf); // create the rotated rect fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); combinedMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4); // Now create the inset points and then outset the original // rotated points // TL *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1]; // BL *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1]; // BR *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1]; // TR *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1]; } // Make verts point to vertex color and then set all the color and coverage vertex attrs values. verts += sizeof(SkPoint); for (int i = 0; i < 4; ++i) { if (kUseCoverage_CoverageAttribType == type) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; } } int scale; if (inset < SK_ScalarHalf) { scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); SkASSERT(scale >= 0 && scale <= 255); } else { scale = 0xff; } verts += 4 * vertexStride; float innerCoverage = GrNormalizeByteToFloat(scale); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); for (int i = 0; i < 4; ++i) { if (kUseCoverage_CoverageAttribType == type) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; } } target->setIndexSourceToBuffer(indexBuffer); target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, 1, kVertsPerAAFillRect, kIndicesPerAAFillRect); target->resetIndexSource(); }
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; } }
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); } }
void generateAAFillRectGeometry(void* vertices, size_t offset, size_t vertexStride, GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect& devRect, bool tweakAlphaForCoverage) const { intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset; SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); if (viewMatrix.rectStaysRect()) { set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); } else { // compute transformed (1, 0) and (0, 1) vectors SkVector vec[2] = { { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] }, { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] } }; vec[0].normalize(); vec[0].scale(SK_ScalarHalf); vec[1].normalize(); vec[1].scale(SK_ScalarHalf); // create the rotated rect fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4); // Now create the inset points and then outset the original // rotated points // TL *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1]; // BL *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1]; // BR *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1]; // TR *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) = *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1]; } // Make verts point to vertex color and then set all the color and coverage vertex attrs // values. verts += sizeof(SkPoint); for (int i = 0; i < 4; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0; } } int scale; if (inset < SK_ScalarHalf) { scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); SkASSERT(scale >= 0 && scale <= 255); } else { scale = 0xff; } verts += 4 * vertexStride; float innerCoverage = GrNormalizeByteToFloat(scale); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); for (int i = 0; i < 4; ++i) { if (tweakAlphaForCoverage) { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; } else { *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage; } } }
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)); }
void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target, GrDrawState* drawState, GrColor color, const SkRect& devOutside, const SkRect& devOutsideAssist, const SkRect& devInside, bool miterStroke) { GrDrawState::AutoRestoreEffects are(drawState); CoverageAttribType type; SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type)); int innerVertexNum = 4; int outerVertexNum = miterStroke ? 4 : 8; int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; size_t vstride = gp->getVertexStride(); GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0); if (!geo.succeeded()) { SkDebugf("Failed to get space for vertices!\n"); return; } GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke); if (NULL == indexBuffer) { SkDebugf("Failed to create index buffer!\n"); return; } intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); // We create vertices for four nested rectangles. There are two ramps from 0 to full // coverage, one on the exterior of the stroke and the other on the interior. // The following pointers refer to the four rects, from outermost to innermost. SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride); SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride); SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride); #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX // TODO: this only really works if the X & Y margins are the same all around // the rect (or if they are all >= 1.0). SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); if (miterStroke) { inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); } else { inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); } SkASSERT(inset >= 0); #else SkScalar inset = SK_ScalarHalf; #endif if (miterStroke) { // outermost set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); // inner two set_inset_fan(fan1Pos, vstride, devOutside, inset, inset); set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset); // innermost set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf); } else { SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride); SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride); // outermost set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); // outer one of the inner two set_inset_fan(fan1Pos, vstride, devOutside, inset, inset); set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset); // inner one of the inner two set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset); // innermost set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf); } // Make verts point to vertex color and then set all the color and coverage vertex attrs values. // The outermost rect has 0 coverage verts += sizeof(SkPoint); for (int i = 0; i < outerVertexNum; ++i) { if (kUseCoverage_CoverageAttribType == type) { *reinterpret_cast<GrColor*>(verts + i * vstride) = color; *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vstride) = 0; } } // scale is the coverage for the the inner two rects. int scale; if (inset < SK_ScalarHalf) { scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); SkASSERT(scale >= 0 && scale <= 255); } else { scale = 0xff; } float innerCoverage = GrNormalizeByteToFloat(scale); GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); verts += outerVertexNum * vstride; for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { if (kUseCoverage_CoverageAttribType == type) { *reinterpret_cast<GrColor*>(verts + i * vstride) = color; *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage; } else { *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor; } } // The innermost rect has 0 coverage verts += (outerVertexNum + innerVertexNum) * vstride; for (int i = 0; i < innerVertexNum; ++i) { if (kUseCoverage_CoverageAttribType == type) { *reinterpret_cast<GrColor*>(verts + i * vstride) = color; *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0; } else { *reinterpret_cast<GrColor*>(verts + i * vstride) = 0; } } target->setIndexSourceToBuffer(indexBuffer); target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, 1, totalVertexNum, aa_stroke_rect_index_count(miterStroke)); target->resetIndexSource(); }