示例#1
0
文件: SkFont.cpp 项目: C-Tillion/skia
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);
}
示例#2
0
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));
}
示例#4
0
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;
}
示例#5
0
文件: SkDevice.cpp 项目: OwenTan/skia
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;
}
示例#6
0
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());
}
示例#8
0
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);
    }
}
示例#9
0
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;
}
示例#10
0
文件: gammatext.cpp 项目: UIKit0/skia
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());
}
示例#11
0
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;
}
示例#12
0
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);
}
示例#13
0
// 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;
}
示例#14
0
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;
}
示例#15
0
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;
}
示例#16
0
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);
}
示例#18
0
文件: SkGr.cpp 项目: huqingyu/skia
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;
}
示例#19
0
文件: SkGr.cpp 项目: picmonkey/skia
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;
}