SkPaint SkColorSpaceXformer::apply(const SkPaint& src) { const AutoCachePurge autoPurge(this); SkPaint dst = src; // All SkColorSpaces have the same black point. if (src.getColor() & 0xffffff) { dst.setColor(this->apply(src.getColor())); } if (auto shader = src.getShader()) { dst.setShader(this->apply(shader)); } if (auto cf = src.getColorFilter()) { dst.setColorFilter(this->apply(cf)); } if (auto looper = src.getDrawLooper()) { dst.setDrawLooper(looper->makeColorSpace(this)); } if (auto imageFilter = src.getImageFilter()) { dst.setImageFilter(this->apply(imageFilter)); } return dst; }
bool SkPaint2GrPaint(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint, const SkMatrix& viewM, bool constantColor, GrPaint* grPaint) { SkShader* shader = skPaint.getShader(); if (NULL == shader) { return SkPaint2GrPaintNoShader(context, rt, skPaint, SkColor2GrColor(skPaint.getColor()), constantColor, grPaint); } GrColor paintColor = SkColor2GrColor(skPaint.getColor()); // Start a new block here in order to preserve our context state after calling // asFragmentProcessor(). Since these calls get passed back to the client, we don't really // want them messing around with the context. { // Allow the shader to modify paintColor and also create an effect to be installed as // the first color effect on the GrPaint. GrFragmentProcessor* fp = NULL; if (!shader->asFragmentProcessor(context, skPaint, viewM, NULL, &paintColor, grPaint->getProcessorDataManager(), &fp)) { return false; } if (fp) { grPaint->addColorProcessor(fp)->unref(); constantColor = false; } } // The grcolor is automatically set when calling asFragmentProcessor. // If the shader can be seen as an effect it returns true and adds its effect to the grpaint. return SkPaint2GrPaintNoShader(context, rt, skPaint, paintColor, constantColor, grPaint); }
bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { SaveLayer* saveLayer = pattern->first<SaveLayer>(); if (saveLayer->bounds != NULL) { // SaveLayer with bounds is too tricky for us. return false; } SkPaint* layerPaint = saveLayer->paint; if (NULL == layerPaint) { // There wasn't really any point to this SaveLayer at all. return KillSaveLayerAndRestore(record, begin); } SkPaint* drawPaint = pattern->second<SkPaint>(); if (drawPaint == NULL) { // We can just give the draw the SaveLayer's paint. // TODO(mtklein): figure out how to do this clearly return false; } const uint32_t layerColor = layerPaint->getColor(); const uint32_t drawColor = drawPaint->getColor(); if (!IsOnlyAlpha(layerColor) || !IsOpaque(drawColor) || HasAnyEffect(*layerPaint) || HasAnyEffect(*drawPaint)) { // Too fancy for us. Actually, as long as layerColor is just an alpha // we can blend it into drawColor's alpha; drawColor doesn't strictly have to be opaque. return false; } drawPaint->setColor(SkColorSetA(drawColor, SkColorGetA(layerColor))); return KillSaveLayerAndRestore(record, begin); }
bool SkBitmapProcShader::asFragmentProcessor(GrContext* context, const SkPaint& paint, const SkMatrix& viewM, const SkMatrix* localMatrix, GrColor* paintColor, GrProcessorDataManager* procDataManager, GrFragmentProcessor** fp) const { SkMatrix matrix; matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); SkMatrix lmInverse; if (!this->getLocalMatrix().invert(&lmInverse)) { return false; } if (localMatrix) { SkMatrix inv; if (!localMatrix->invert(&inv)) { return false; } lmInverse.postConcat(inv); } matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { (TileMode)fTileModeX, (TileMode)fTileModeY, }; // Must set wrap and filter on the sampler before requesting a texture. In two places below // we check the matrix scale factors to determine how to interpret the filter quality setting. // This completely ignores the complexity of the drawVertices case where explicit local coords // are provided by the caller. bool doBicubic; GrTextureParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewM, this->getLocalMatrix(), &doBicubic); GrTextureParams params(tm, textureFilterMode); SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, ¶ms)); if (!texture) { SkErrorInternals::SetError( kInternalError_SkError, "Couldn't convert bitmap to texture."); return false; } *paintColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ? SkColor2GrColor(paint.getColor()) : SkColor2GrColorJustAlpha(paint.getColor()); if (doBicubic) { *fp = GrBicubicEffect::Create(procDataManager, texture, matrix, tm); } else { *fp = GrSimpleTextureEffect::Create(procDataManager, texture, matrix, params); } return true; }
SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkPixmap& device, const SkPaint& paint) : INHERITED(device, paint) { SkASSERT(paint.getShader() == nullptr); SkASSERT(paint.getColorFilter() == nullptr); SkASSERT(paint.isSrcOver()); SkASSERT(paint.getColor() == SK_ColorBLACK); }
void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override { fDst = dst; fLeft = left; fTop = top; fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace()); SkRasterPipeline p(fAlloc); switch (fSource.colorType()) { case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, &fSrcPtr); break; case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, &fSrcPtr); break; case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, &fSrcPtr); break; case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break; case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break; case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break; case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, &fSrcPtr); break; default: SkASSERT(false); } if (fDst.colorSpace() && (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) { p.append_from_srgb(fSource.alphaType()); } if (fSource.colorType() == kAlpha_8_SkColorType) { p.append(SkRasterPipeline::set_rgb, &fPaintColor); p.append(SkRasterPipeline::premul); } append_gamut_transform(&p, fAlloc, fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType); if (fPaintColor.fA != 1.0f) { p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA); } bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f; fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc); }
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); } }
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; }
void SkOverdrawCanvas::onDrawPaint(const SkPaint& paint) { if (0 == paint.getColor() && !paint.getColorFilter() && !paint.getShader()) { // This is a clear, ignore it. } else { fList[0]->onDrawPaint(this->overdrawPaint(paint)); } }
void paintSkiaText(GraphicsContext* context, HFONT hfont, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint* origin) { HDC dc = GetDC(0); HGDIOBJ oldFont = SelectObject(dc, hfont); PlatformContextSkia* platformContext = context->platformContext(); SkCanvas* canvas = platformContext->canvas(); TextDrawingModeFlags textMode = platformContext->getTextDrawingMode(); // If platformContext is GPU-backed make its GL context current. platformContext->makeGrContextCurrent(); // Filling (if necessary). This is the common case. SkPaint paint; platformContext->setupPaintForFilling(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(hfont, &paint, platformContext); bool didFill = false; if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); didFill = true; } // Stroking on top (if necessary). if ((textMode & TextModeStroke) && platformContext->getStrokeStyle() != NoStroke && platformContext->getStrokeThickness() > 0) { paint.reset(); platformContext->setupPaintForStroking(&paint, 0, 0); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(hfont, &paint, platformContext); if (didFill) { // If there is a shadow and we filled above, there will already be // a shadow. We don't want to draw it again or it will be too dark // and it will go on top of the fill. // // Note that this isn't strictly correct, since the stroke could be // very thick and the shadow wouldn't account for this. The "right" // thing would be to draw to a new layer and then draw that layer // with a shadow. But this is a lot of extra work for something // that isn't normally an issue. paint.setLooper(0); } skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); } SelectObject(dc, oldFont); ReleaseDC(0, dc); }
static void lettersToBitmap2(SkBitmap* dst, const char chars[], const SkPaint& original, SkBitmap::Config config) { SkPath path; SkScalar x = 0; SkScalar width; SkPath p; for (size_t i = 0; i < strlen(chars); i++) { original.getTextPath(&chars[i], 1, x, 0, &p); path.addPath(p); original.getTextWidths(&chars[i], 1, &width); x += width; } SkRect bounds = path.getBounds(); SkScalar sw = -original.getStrokeWidth(); bounds.inset(sw, sw); path.offset(-bounds.fLeft, -bounds.fTop); bounds.offset(-bounds.fLeft, -bounds.fTop); int w = SkScalarRound(bounds.width()); int h = SkScalarRound(bounds.height()); SkPaint paint(original); paint.setAntiAlias(true); paint.setXfermodeMode(SkXfermode::kDstATop_Mode); paint.setColor(original.getColor()); paint.setStyle(SkPaint::kStroke_Style); dst->setConfig(config, w, h); dst->allocPixels(); dst->eraseColor(SK_ColorWHITE); SkCanvas canvas(*dst); canvas.drawPath(path, paint); }
SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device, paint) { SkASSERT(paint.getShader() == NULL); SkASSERT(paint.getColorFilter() == NULL); SkASSERT(paint.getXfermode() == NULL); SkASSERT(paint.getColor() == SK_ColorBLACK); }
// Check for: // SAVE_LAYER // SAVE // CLIP_RECT // DRAW_BITMAP_RECT_TO_RECT // RESTORE // RESTORE // where the saveLayer's color can be moved into the drawBitmapRect static bool check_1(SkDebugCanvas* canvas, int curCommand) { if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || canvas->getSize() <= curCommand+5 || SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() || CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() || RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() || RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) { return false; } SkSaveLayerCommand* saveLayer = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); const SkPaint* saveLayerPaint = saveLayer->paint(); SkPaint* dbmrPaint = dbmr->paint(); // For this optimization we only fold the saveLayer and drawBitmapRect // together if the saveLayer's draw is simple (i.e., no fancy effects) and // and the only difference in the colors is that the saveLayer's can have // an alpha while the drawBitmapRect's is opaque. // TODO: it should be possible to fold them together even if they both // have different non-255 alphas but this is low priority since we have // never seen that case // If either operation lacks a paint then the collapse is trivial SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque return NULL == saveLayerPaint || NULL == dbmrPaint || (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor); }
void drawShadowedPath(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams, const SkPaint& paint, SkScalar ambientAlpha, const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { if (!fShowAmbient) { ambientAlpha = 0; } if (!fShowSpot) { spotAlpha = 0; } uint32_t flags = 0; if (fUseAlt) { flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; } SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightWidth, ambientAlpha, spotAlpha, SK_ColorBLACK, flags); if (fShowObject) { canvas->drawPath(path, paint); } else { SkPaint strokePaint; strokePaint.setColor(paint.getColor()); strokePaint.setStyle(SkPaint::kStroke_Style); canvas->drawPath(path, strokePaint); } }
virtual void onDraw(SkCanvas* canvas) { const SkIPoint dim = this->getSize(); SkRandom rand; SkPaint paint(fPaint); this->setupPaint(&paint); // explicitly need these paint.setColor(fPaint.getColor()); paint.setAntiAlias(kBW != fFQ); paint.setLCDRenderText(kLCD == fFQ); const SkScalar x0 = SkIntToScalar(-10); const SkScalar y0 = SkIntToScalar(-10); if (fDoPos) { // realistically, the matrix is often at least translated, so we // do that since it exercises different code in drawPosText. canvas->translate(SK_Scalar1, SK_Scalar1); } for (int i = 0; i < N; i++) { if (fDoPos) { canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint); } else { SkScalar x = x0 + rand.nextUScalar1() * dim.fX; SkScalar y = y0 + rand.nextUScalar1() * dim.fY; canvas->drawText(fText.c_str(), fText.size(), x, y, paint); } } }
// 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 }
void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) { if (justAlpha) { SkGL::SetAlpha(paint.getAlpha()); } else { SkGL::SetColor(paint.getColor()); } GLenum sm = GL_ONE; GLenum dm = GL_ONE_MINUS_SRC_ALPHA; SkXfermode* mode = paint.getXfermode(); SkXfermode::Coeff sc, dc; if (mode && mode->asCoeff(&sc, &dc)) { sm = gXfermodeCoeff2Blend[sc]; dm = gXfermodeCoeff2Blend[dc]; } // hack for text, which is not-premul (afaik) if (!isPremul) { if (GL_ONE == sm) { sm = GL_SRC_ALPHA; } } glEnable(GL_BLEND); glBlendFunc(sm, dm); if (paint.isDither()) { glEnable(GL_DITHER); } else { glDisable(GL_DITHER); } }
// Check for: // SAVE_LAYER // DRAW_BITMAP_RECT_TO_RECT // RESTORE // where the saveLayer's color can be moved into the drawBitmapRect static bool check_0(SkDebugCanvas* canvas, int curCommand) { if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || canvas->getSize() <= curCommand+2 || DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || RESTORE != canvas->getDrawCommandAt(curCommand+2)->getType()) { return false; } SkSaveLayerCommand* saveLayer = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); const SkPaint* saveLayerPaint = saveLayer->paint(); SkPaint* dbmrPaint = dbmr->paint(); // For this optimization we only fold the saveLayer and drawBitmapRect // together if the saveLayer's draw is simple (i.e., no fancy effects) // and the only difference in the colors is their alpha value SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaque // If either operation lacks a paint then the collapse is trivial return NULL == saveLayerPaint || NULL == dbmrPaint || (is_simple(*saveLayerPaint) && dbmrColor == layerColor); }
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); } }
State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) { fXfer = paint.getXfermode(); if (shaderContext) { fBuffer.reset(info.width()); } else { fPM4f = SkColor4f::FromColor(paint.getColor()).premul(); } fFlags = 0; }
void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& resources) { SkPaint::Style style = paint.getStyle(); if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style) { this->addAttribute("fill", resources.fPaintServer); if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { this->addAttribute("fill-opacity", svg_opacity(paint.getColor())); } } else { SkASSERT(style == SkPaint::kStroke_Style); this->addAttribute("fill", "none"); } if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_Style) { this->addAttribute("stroke", resources.fPaintServer); SkScalar strokeWidth = paint.getStrokeWidth(); if (strokeWidth == 0) { // Hairline stroke strokeWidth = 1; this->addAttribute("vector-effect", "non-scaling-stroke"); } this->addAttribute("stroke-width", strokeWidth); if (const char* cap = svg_cap(paint.getStrokeCap())) { this->addAttribute("stroke-linecap", cap); } if (const char* join = svg_join(paint.getStrokeJoin())) { this->addAttribute("stroke-linejoin", join); } if (paint.getStrokeJoin() == SkPaint::kMiter_Join) { this->addAttribute("stroke-miterlimit", paint.getStrokeMiter()); } if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { this->addAttribute("stroke-opacity", svg_opacity(paint.getColor())); } } else { SkASSERT(style == SkPaint::kFill_Style); this->addAttribute("stroke", "none"); } }
static bool fold_opacity_layer_color_to_paint(const SkPaint& layerPaint, bool isSaveLayer, SkPaint* paint) { // We assume layerPaint is always from a saveLayer. If isSaveLayer is // true, we assume paint is too. // The alpha folding can proceed if the filter layer paint does not have properties which cause // the resulting filter layer to be "blended" in complex ways to the parent layer. For example, // looper drawing unmodulated filter layer twice and then modulating the result produces // different image to drawing modulated filter layer twice. // TODO: most likely the looper and only some xfer modes are the hard constraints if (paint->getXfermode() || paint->getLooper()) { return false; } if (!isSaveLayer && paint->getImageFilter()) { // For normal draws, the paint color is used as one input for the color for the draw. Image // filter will operate on the result, and thus we can not change the input. // For layer saves, the image filter is applied to the layer contents. The layer is then // modulated with the paint color, so it's fine to proceed with the fold for saveLayer // paints with image filters. return false; } if (paint->getColorFilter()) { // Filter input depends on the paint color. // Here we could filter the color if we knew the draw is going to be uniform color. This // should be detectable as drawPath/drawRect/.. without a shader being uniform, while // drawBitmap/drawSprite or a shader being non-uniform. However, current matchers don't // give the type out easily, so just do not optimize that at the moment. return false; } const uint32_t layerColor = layerPaint.getColor(); // The layer paint color must have only alpha component. if (SK_ColorTRANSPARENT != SkColorSetA(layerColor, SK_AlphaTRANSPARENT)) { return false; } // The layer paint can not have any effects. if (layerPaint.getPathEffect() || layerPaint.getShader() || layerPaint.getXfermode() || layerPaint.getMaskFilter() || layerPaint.getColorFilter() || layerPaint.getRasterizer() || layerPaint.getLooper() || layerPaint.getImageFilter()) { return false; } paint->setAlpha(SkMulDiv255Round(paint->getAlpha(), SkColorGetA(layerColor))); return true; }
const char* onGetName() override { fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize())); if (fDoPos) { fName.append("_pos"); } fName.appendf("_%s", fontQualityName(fPaint)); if (SK_ColorBLACK == fPaint.getColor()) { fName.append("_BK"); } else if (SK_ColorWHITE == fPaint.getColor()) { fName.append("_WT"); } else { fName.appendf("_%02X", fPaint.getAlpha()); } if (fDoColorEmoji) { fName.append("_ColorEmoji"); } return fName.c_str(); }
static void apply_paint_color(const SkPaint& paint, Json::Value* target) { SkColor color = paint.getColor(); if (color != SK_ColorBLACK) { Json::Value colorValue(Json::arrayValue); colorValue.append(Json::Value(SkColorGetA(color))); colorValue.append(Json::Value(SkColorGetR(color))); colorValue.append(Json::Value(SkColorGetG(color))); colorValue.append(Json::Value(SkColorGetB(color))); (*target)[SKJSONCANVAS_ATTRIBUTE_COLOR] = colorValue;; } }
void paintSkiaText(GraphicsContext* context, HFONT hfont, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint* origin) { PlatformContextSkia* platformContext = context->platformContext(); SkCanvas* canvas = platformContext->canvas(); TextDrawingModeFlags textMode = platformContext->getTextDrawingMode(); // Ensure font load for printing, because PDF device needs it. if (canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability) PlatformSupport::ensureFontLoaded(hfont); // Filling (if necessary). This is the common case. SkPaint paint; platformContext->setupPaintForFilling(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(hfont, &paint, platformContext); bool didFill = false; if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); didFill = true; } // Stroking on top (if necessary). if ((textMode & TextModeStroke) && platformContext->getStrokeStyle() != NoStroke && platformContext->getStrokeThickness() > 0) { paint.reset(); platformContext->setupPaintForStroking(&paint, 0, 0); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(hfont, &paint, platformContext); if (didFill) { // If there is a shadow and we filled above, there will already be // a shadow. We don't want to draw it again or it will be too dark // and it will go on top of the fill. // // Note that this isn't strictly correct, since the stroke could be // very thick and the shadow wouldn't account for this. The "right" // thing would be to draw to a new layer and then draw that layer // with a shadow. But this is a lot of extra work for something // that isn't normally an issue. paint.setLooper(0); } skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); } }
// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) return; StrokeStyle penStyle = strokeStyle(); if (penStyle == NoStroke) return; SkPaint paint; if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2)) return; platformContext()->prepareForSoftwareDraw(); FloatPoint p1 = point1; FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); int width = roundf(strokeThickness()); // We know these are vertical or horizontal lines, so the length will just // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. FloatSize disp = p2 - p1; int length = SkScalarRound(disp.width() + disp.height()); platformContext()->setupPaintForStroking(&paint, 0, length); if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. SkRect r1, r2; r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); if (isVerticalLine) { r1.offset(-width / 2, 0); r2.offset(-width / 2, -width); } else { r1.offset(0, -width / 2); r2.offset(-width, -width / 2); } SkPaint fillPaint; fillPaint.setColor(paint.getColor()); platformContext()->canvas()->drawRect(r1, fillPaint); platformContext()->canvas()->drawRect(r2, fillPaint); } adjustLineToPixelBoundaries(p1, p2, width, penStyle); SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); }
SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device) { uint32_t color = paint.getColor(); fSrcA = SkColorGetA(color); unsigned scale = SkAlpha255To256(fSrcA); fSrcR = SkAlphaMul(SkColorGetR(color), scale); fSrcG = SkAlphaMul(SkColorGetG(color), scale); fSrcB = SkAlphaMul(SkColorGetB(color), scale); fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB); }
static void paintSkiaText(GraphicsContext* context, HFONT hfont, SkTypeface* face, float size, uint32_t textFlags, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint& origin, const SkRect& textRect) { TextDrawingModeFlags textMode = context->textDrawingMode(); // Ensure font load for printing, because PDF device needs it. if (context->isPrintingDevice()) FontPlatformData::ensureFontLoaded(hfont); // Filling (if necessary). This is the common case. SkPaint paint; context->setupPaintForFilling(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(&paint, context, face, size, textFlags); bool didFill = false; if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); didFill = true; } // Stroking on top (if necessary). if ((textMode & TextModeStroke) && context->strokeStyle() != NoStroke && context->strokeThickness() > 0) { paint.reset(); context->setupPaintForStroking(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); setupPaintForFont(&paint, context, face, size, textFlags); if (didFill) { // If there is a shadow and we filled above, there will already be // a shadow. We don't want to draw it again or it will be too dark // and it will go on top of the fill. // // Note that this isn't strictly correct, since the stroke could be // very thick and the shadow wouldn't account for this. The "right" // thing would be to draw to a new layer and then draw that layer // with a shadow. But this is a lot of extra work for something // that isn't normally an issue. paint.setLooper(0); } skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); } }
virtual const char* onGetName() { fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize())); if (fDoPos) { fName.append("_pos"); } fName.appendf("_%s", fontQualityName(fPaint)); if (SK_ColorBLACK != fPaint.getColor()) { fName.appendf("_%02X", fPaint.getAlpha()); } else { fName.append("_BK"); } return fName.c_str(); }
static bool drawNeedsLayer(const SkPaint& paint) { if (SkColorGetA(paint.getColor()) < 255) return true; SkXfermode::Mode xfermode; if (SkXfermode::AsMode(paint.getXfermode(), &xfermode)) { if (xfermode != SkXfermode::kSrcOver_Mode) return true; } return false; }