sk_sp<SkFont> SkFont::Testing_CreateFromPaint(const SkPaint& paint) { uint32_t flags = 0; if (paint.isVerticalText()) { flags |= kVertical_Flag; } if (paint.isEmbeddedBitmapText()) { flags |= kEmbeddedBitmaps_Flag; } if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { flags |= kGenA8FromLCD_Flag; } if (paint.isFakeBoldText()) { flags |= kEmbolden_Flag; } if (SkPaint::kFull_Hinting == paint.getHinting()) { flags |= kEnableByteCodeHints_Flag; } if (paint.isAutohinted()) { flags |= kEnableAutoHints_Flag; } if (paint.isSubpixelText() || paint.isLinearText()) { // this is our default } else { flags |= kUseNonlinearMetrics_Flag; } MaskType maskType = SkFont::kBW_MaskType; if (paint.isAntiAlias()) { maskType = paint.isLCDRenderText() ? kLCD_MaskType : kA8_MaskType; } return Make(sk_ref_sp(paint.getTypeface()), paint.getTextSize(), paint.getTextScaleX(), paint.getTextSkewX(), maskType, flags); }
void CrossfadeGeneratedImage::drawCrossfade( SkCanvas* canvas, const SkPaint& paint, ImageClampingMode clampMode, const ColorBehavior& colorBehavior) { FloatRect fromImageRect(FloatPoint(), FloatSize(m_fromImage->size())); FloatRect toImageRect(FloatPoint(), FloatSize(m_toImage->size())); FloatRect destRect((FloatPoint()), FloatSize(m_crossfadeSize)); // TODO(junov): The various effects encoded into paint should probably be // applied here instead of inside the layer. This probably faulty behavior // was maintained in order to preserve pre-existing behavior while refactoring // this code. This should be investigated further. crbug.com/472634 SkPaint layerPaint; layerPaint.setBlendMode(paint.getBlendMode()); SkAutoCanvasRestore ar(canvas, false); canvas->saveLayer(nullptr, &layerPaint); SkPaint imagePaint(paint); imagePaint.setBlendMode(SkBlendMode::kSrcOver); int imageAlpha = clampedAlphaForBlending(1 - m_percentage); imagePaint.setAlpha(imageAlpha > 255 ? 255 : imageAlpha); imagePaint.setAntiAlias(paint.isAntiAlias()); // TODO(junov): This code should probably be propagating the // RespectImageOrientationEnum from CrossfadeGeneratedImage::draw(). Code was // written this way during refactoring to avoid modifying existing behavior, // but this warrants further investigation. crbug.com/472634 m_fromImage->draw(canvas, imagePaint, destRect, fromImageRect, DoNotRespectImageOrientation, clampMode, colorBehavior); imagePaint.setBlendMode(SkBlendMode::kPlus); imageAlpha = clampedAlphaForBlending(m_percentage); imagePaint.setAlpha(imageAlpha > 255 ? 255 : imageAlpha); m_toImage->draw(canvas, imagePaint, destRect, toImageRect, DoNotRespectImageOrientation, clampMode, colorBehavior); }
TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint) : type(type) , aa(paint.isAntiAlias()) , cap(paint.getStrokeCap()) , style(paint.getStyle()) , strokeWidth(paint.getStrokeWidth()) { PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); memset(&shape, 0, sizeof(Shape)); }
uint32_t GrTextUtils::FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint) { uint32_t flags = paint.getFlags(); if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { return flags; } if (kUnknown_SkPixelGeometry == surfaceProps.pixelGeometry() || ShouldDisableLCD(paint)) { flags &= ~SkPaint::kLCDRenderText_Flag; flags |= SkPaint::kGenA8FromLCD_Flag; } return flags; }
uint32_t SkBaseDevice::filterTextFlags(const SkPaint& paint) const { uint32_t flags = paint.getFlags(); if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { return flags; } if (kUnknown_SkPixelGeometry == fSurfaceProps.pixelGeometry() || this->onShouldDisableLCD(paint)) { flags &= ~SkPaint::kLCDRenderText_Flag; flags |= SkPaint::kGenA8FromLCD_Flag; } return flags; }
void SkBaseDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { bool isNonTranslate = draw.fMatrix->getType() & ~(SkMatrix::kTranslate_Mask); bool complexPaint = paint.getStyle() != SkPaint::kFill_Style || paint.getMaskFilter() || paint.getPathEffect(); bool antiAlias = paint.isAntiAlias() && (!is_int(draw.fMatrix->getTranslateX()) || !is_int(draw.fMatrix->getTranslateY())); if (isNonTranslate || complexPaint || antiAlias) { SkPath path; region.getBoundaryPath(&path); return this->drawPath(draw, path, paint, nullptr, false); } SkRegion::Iterator it(region); while (!it.done()) { this->drawRect(draw, SkRect::Make(it.rect()), paint); it.next(); } }
static void paint_write(const SkPaint& paint, SkFlattenableWriteBuffer& buffer) { buffer.writeBool(paint.isAntiAlias()); buffer.write8(paint.getStyle()); buffer.write8(paint.getAlpha()); if (paint.getStyle() != SkPaint::kFill_Style) { buffer.writeScalar(paint.getStrokeWidth()); buffer.writeScalar(paint.getStrokeMiter()); buffer.write8(paint.getStrokeCap()); buffer.write8(paint.getStrokeJoin()); } buffer.writeFlattenable(paint.getMaskFilter()); buffer.writeFlattenable(paint.getPathEffect()); buffer.writeFlattenable(paint.getRasterizer()); buffer.writeFlattenable(paint.getXfermode()); }
static void drawAndTest(skiatest::Reporter* reporter, const SkPath& path, const SkPaint& paint, bool shouldDraw) { SkBitmap bm; bm.allocN32Pixels(DIMENSION, DIMENSION); SkASSERT(DIMENSION*4 == bm.rowBytes()); // ensure no padding on each row bm.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bm); SkPaint p(paint); p.setColor(SK_ColorWHITE); canvas.drawPath(path, p); size_t count = DIMENSION * DIMENSION; const SkPMColor* ptr = bm.getAddr32(0, 0); SkPMColor andValue = ~0U; SkPMColor orValue = 0; for (size_t i = 0; i < count; ++i) { SkPMColor c = ptr[i]; andValue &= c; orValue |= c; } // success means we drew everywhere or nowhere (depending on shouldDraw) bool success = shouldDraw ? (~0U == andValue) : (0 == orValue); if (!success) { const char* str; if (shouldDraw) { str = "Path expected to draw everywhere, but didn't. "; } else { str = "Path expected to draw nowhere, but did. "; } ERRORF(reporter, "%s style[%d] cap[%d] join[%d] antialias[%d]" " filltype[%d] ptcount[%d]", str, paint.getStyle(), paint.getStrokeCap(), paint.getStrokeJoin(), paint.isAntiAlias(), path.getFillType(), path.countPoints()); // uncomment this if you want to step in to see the failure // canvas.drawPath(path, p); } }
String LoggingCanvas::stringForSkPaintFlags(const SkPaint& paint) { if (!paint.getFlags()) return "none"; String flagsString = ""; appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias"); appendFlagToString(&flagsString, paint.isDither(), "Dither"); appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText"); appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText"); appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText"); appendFlagToString(&flagsString, paint.isLinearText(), "LinearText"); appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText"); appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText"); appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText"); appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText"); appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted"); appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText"); appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD"); return flagsString; }
static void cgSetPaintForText(CGContextRef cg, const SkPaint& paint) { SkColor c = paint.getColor(); CGFloat rgba[] = { SkColorGetB(c) / 255.0f, SkColorGetG(c) / 255.0f, SkColorGetR(c) / 255.0f, SkColorGetA(c) / 255.0f, }; CGContextSetRGBFillColor(cg, rgba[0], rgba[1], rgba[2], rgba[3]); CGContextSetTextDrawingMode(cg, kCGTextFill); CGContextSetFont(cg, typefaceToCGFont(paint.getTypeface())); CGContextSetFontSize(cg, SkScalarToFloat(paint.getTextSize())); CGContextSetAllowsFontSubpixelPositioning(cg, paint.isSubpixelText()); CGContextSetShouldSubpixelPositionFonts(cg, paint.isSubpixelText()); CGContextSetShouldAntialias(cg, paint.isAntiAlias()); CGContextSetShouldSmoothFonts(cg, paint.isLCDRenderText()); }
bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { // we're cool with the paint as is return false; } if (kN32_SkColorType != fBitmap.colorType() || paint.getRasterizer() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style || !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { // turn off lcd flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; flags->fHinting = paint.getHinting(); return true; } // we're cool with the paint as is return false; }
void SkSVGDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bm, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) { SkMatrix adjustedMatrix; adjustedMatrix.setRectToRect(srcOrNull ? *srcOrNull : SkRect::Make(bm.bounds()), dst, SkMatrix::kFill_ScaleToFit); adjustedMatrix.postConcat(*draw.fMatrix); SkDraw adjustedDraw(draw); adjustedDraw.fMatrix = &adjustedMatrix; SkClipStack adjustedClipStack; if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { adjustedClipStack = *draw.fClipStack; adjustedClipStack.clipRect(dst, *draw.fMatrix, SkCanvas::kIntersect_Op, paint.isAntiAlias()); adjustedDraw.fClipStack = &adjustedClipStack; } drawBitmapCommon(adjustedDraw, bm, paint); }
// Returns true if all pixels painted will be opaque. static inline bool paintIsOpaque(const SkPaint& paint, const SkBitmap* bitmap = 0, bool checkFillOnly = false) { if (paint.getAlpha() < 0xFF) return false; if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAntiAlias()) return false; SkShader* shader = paint.getShader(); if (shader && !shader->isOpaque()) return false; if (bitmap && !bitmap->isOpaque()) return false; if (paint.getLooper()) return false; if (paint.getImageFilter()) return false; if (paint.getMaskFilter()) return false; SkColorFilter* colorFilter = paint.getColorFilter(); if (colorFilter && !(colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag)) return false; return true; }
bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { // we're cool with the paint as is return false; } if (SkBitmap::kARGB_8888_Config != fBitmap.config() || paint.getShader() || paint.getXfermode() || // unless its srcover paint.getMaskFilter() || paint.getRasterizer() || paint.getColorFilter() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style) { // turn off lcd flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; flags->fHinting = paint.getHinting(); return true; } // we're cool with the paint as is return false; }
Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { Json::Value result(Json::objectValue); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(), SkPaintDefaults_MiterLimit); store_bool(&result, SKJSONCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(), SkPaintDefaults_TextSize); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f); apply_paint_color(paint, &result); apply_paint_style(paint, &result); apply_paint_cap(paint, &result); apply_paint_textalign(paint, &result); apply_paint_patheffect(paint, &result, fSendBinaries); apply_paint_maskfilter(paint, &result, fSendBinaries); apply_paint_shader(paint, &result, fSendBinaries); apply_paint_xfermode(paint, &result, fSendBinaries); apply_paint_imagefilter(paint, &result, fSendBinaries); apply_paint_colorfilter(paint, &result, fSendBinaries); apply_paint_typeface(paint, &result, fSendBinaries); return result; }
void SkSVGDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bm, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SK_VIRTUAL_CONSTRAINT_TYPE) { SkMatrix adjustedMatrix; adjustedMatrix.setRectToRect(srcOrNull ? *srcOrNull : SkRect::Make(bm.bounds()), dst, SkMatrix::kFill_ScaleToFit); adjustedMatrix.postConcat(*draw.fMatrix); SkDraw adjustedDraw(draw); adjustedDraw.fMatrix = &adjustedMatrix; SkClipStack adjustedClipStack; if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { SkRect devClipRect; draw.fMatrix->mapRect(&devClipRect, dst); adjustedClipStack = *draw.fClipStack; adjustedClipStack.clipDevRect(devClipRect, SkRegion::kIntersect_Op, paint.isAntiAlias()); adjustedDraw.fClipStack = &adjustedClipStack; } drawBitmapCommon(adjustedDraw, bm, paint); }
void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, const SkRect& clippedSrcRect, const SkRect& clippedDstRect, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, const SkMatrix& srcToDstMatrix, const GrClip& clip, const SkPaint& paint) { // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp // combining by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture // FP. In the future this should be an opaque optimization enabled by the combination of // GrDrawOp/GP and FP. const SkMaskFilter* mf = paint.getMaskFilter(); // The shader expects proper local coords, so we can't replace local coords with texture coords // if the shader will be used. If we have a mask filter we will change the underlying geometry // that is rendered. bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf; bool doBicubic; GrSamplerParams::FilterMode fm = GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix, &doBicubic); const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm; GrTextureProducer::FilterConstraint constraintMode; if (SkCanvas::kFast_SrcRectConstraint == constraint) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } else { constraintMode = GrTextureAdjuster::kYes_FilterConstraint; } // If we have to outset for AA then we will generate texture coords outside the src rect. The // same happens for any mask filter that extends the bounds rendered in the dst. // This is conservative as a mask filter does not have to expand the bounds rendered. bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf; // Check for optimization to drop the src rect constraint when on bilerp. if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode && GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) { SkMatrix combinedMatrix; combinedMatrix.setConcat(viewMatrix, srcToDstMatrix); if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix, fRenderTargetContext->isUnifiedMultisampled())) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } } const SkMatrix* textureMatrix; SkMatrix tempMatrix; if (canUseTextureCoordsAsLocalCoords) { textureMatrix = &SkMatrix::I(); } else { if (!srcToDstMatrix.invert(&tempMatrix)) { return; } textureMatrix = &tempMatrix; } sk_sp<GrFragmentProcessor> fp(producer->createFragmentProcessor( *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode, fRenderTargetContext->getColorSpace())); if (!fp) { return; } GrPaint grPaint; if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix, fp, producer->isAlphaOnly(), &grPaint)) { return; } GrAA aa = GrBoolToAA(paint.isAntiAlias()); if (canUseTextureCoordsAsLocalCoords) { fRenderTargetContext->fillRectToRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect, clippedSrcRect); return; } if (!mf) { fRenderTargetContext->drawRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect); return; } // First see if we can do the draw + mask filter direct to the dst. if (viewMatrix.isScaleTranslate()) { SkRect devClippedDstRect; viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); if (mf->directFilterRRectMaskGPU(fContext.get(), fRenderTargetContext.get(), std::move(grPaint), clip, viewMatrix, rec, SkRRect::MakeRect(clippedDstRect), SkRRect::MakeRect(devClippedDstRect))) { return; } } SkPath rectPath; rectPath.addRect(clippedDstRect); rectPath.setIsVolatile(true); GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), this->clip(), rectPath, std::move(grPaint), aa, viewMatrix, mf, GrStyle::SimpleFill(), true); }
bool SkPaint2GrPaintNoShader(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint, GrColor paintColor, bool constantColor, GrPaint* grPaint) { grPaint->setDither(skPaint.isDither()); grPaint->setAntiAlias(skPaint.isAntiAlias()); SkXfermode* mode = skPaint.getXfermode(); GrXPFactory* xpFactory = NULL; if (!SkXfermode::AsXPFactory(mode, &xpFactory)) { // Fall back to src-over // return false here? xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode); } SkASSERT(xpFactory); grPaint->setXPFactory(xpFactory)->unref(); //set the color of the paint to the one of the parameter grPaint->setColor(paintColor); SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { // if the source color is a constant then apply the filter here once rather than per pixel // in a shader. if (constantColor) { SkColor filtered = colorFilter->filterColor(skPaint.getColor()); grPaint->setColor(SkColor2GrColor(filtered)); } else { SkTDArray<GrFragmentProcessor*> array; // return false if failed? if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(), &array)) { for (int i = 0; i < array.count(); ++i) { grPaint->addColorProcessor(array[i]); array[i]->unref(); } } } } #ifndef SK_IGNORE_GPU_DITHER // If the dither flag is set, then we need to see if the underlying context // supports it. If not, then install a dither effect. if (skPaint.isDither() && grPaint->numColorStages() > 0) { // What are we rendering into? SkASSERT(rt); // Suspect the dithering flag has no effect on these configs, otherwise // fall back on setting the appropriate state. if (GrPixelConfigIs8888(rt->config()) || GrPixelConfigIs8888(rt->config())) { // The dither flag is set and the target is likely // not going to be dithered by the GPU. SkAutoTUnref<GrFragmentProcessor> fp(GrDitherEffect::Create()); if (fp.get()) { grPaint->addColorProcessor(fp); grPaint->setDither(false); } } } #endif return true; }
static inline bool skpaint_to_grpaint_impl(GrContext* context, const SkPaint& skPaint, const SkMatrix& viewM, const GrFragmentProcessor** shaderProcessor, SkXfermode::Mode* primColorMode, bool primitiveIsSrc, GrPaint* grPaint) { grPaint->setAntiAlias(skPaint.isAntiAlias()); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. SkAutoTUnref<const GrFragmentProcessor> aufp; const GrFragmentProcessor* shaderFP = nullptr; if (!primColorMode || blend_requires_shader(*primColorMode, primitiveIsSrc)) { if (shaderProcessor) { shaderFP = *shaderProcessor; } else if (const SkShader* shader = skPaint.getShader()) { aufp.reset(shader->asFragmentProcessor(context, viewM, nullptr, skPaint.getFilterQuality())); shaderFP = aufp; if (!shaderFP) { return false; } } } // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is // a known constant value. In that case we can simply apply a color filter during this // conversion without converting the color filter to a GrFragmentProcessor. bool applyColorFilterToPaintColor = false; if (shaderFP) { if (primColorMode) { // There is a blend between the primitive color and the shader color. The shader sees // the opaque paint color. The shader's output is blended using the provided mode by // the primitive color. The blended color is then modulated by the paint's alpha. // The geometry processor will insert the primitive color to start the color chain, so // the GrPaint color will be ignored. GrColor shaderInput = SkColorToOpaqueGrColor(skPaint.getColor()); shaderFP = GrFragmentProcessor::OverrideInput(shaderFP, shaderInput); aufp.reset(shaderFP); if (primitiveIsSrc) { shaderFP = GrXfermodeFragmentProcessor::CreateFromDstProcessor(shaderFP, *primColorMode); } else { shaderFP = GrXfermodeFragmentProcessor::CreateFromSrcProcessor(shaderFP, *primColorMode); } aufp.reset(shaderFP); // The above may return null if compose results in a pass through of the prim color. if (shaderFP) { grPaint->addColorFragmentProcessor(shaderFP); } GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create( paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref(); } } else { // The shader's FP sees the paint unpremul color grPaint->setColor(SkColorToUnpremulGrColor(skPaint.getColor())); grPaint->addColorFragmentProcessor(shaderFP); } } else { if (primColorMode) { // There is a blend between the primitive color and the paint color. The blend considers // the opaque paint color. The paint's alpha is applied to the post-blended color. SkAutoTUnref<const GrFragmentProcessor> processor( GrConstColorProcessor::Create(SkColorToOpaqueGrColor(skPaint.getColor()), GrConstColorProcessor::kIgnore_InputMode)); if (primitiveIsSrc) { processor.reset(GrXfermodeFragmentProcessor::CreateFromDstProcessor(processor, *primColorMode)); } else { processor.reset(GrXfermodeFragmentProcessor::CreateFromSrcProcessor(processor, *primColorMode)); } if (processor) { grPaint->addColorFragmentProcessor(processor); } grPaint->setColor(SkColorToOpaqueGrColor(skPaint.getColor())); GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create( paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref(); } } else { // No shader, no primitive color. grPaint->setColor(SkColorToPremulGrColor(skPaint.getColor())); applyColorFilterToPaintColor = true; } } SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor()))); } else { SkAutoTUnref<const GrFragmentProcessor> cfFP( colorFilter->asFragmentProcessor(context)); if (cfFP) { grPaint->addColorFragmentProcessor(cfFP); } else { return false; } } } SkXfermode* mode = skPaint.getXfermode(); GrXPFactory* xpFactory = nullptr; if (!SkXfermode::AsXPFactory(mode, &xpFactory)) { // Fall back to src-over // return false here? xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode); } SkASSERT(xpFactory); grPaint->setXPFactory(xpFactory)->unref(); #ifndef SK_IGNORE_GPU_DITHER if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) { grPaint->addColorFragmentProcessor(GrDitherEffect::Create())->unref(); } #endif return true; }