DEF_TEST(ColorFilter, reporter) { SkRandom rand; for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { SkColor color = rand.nextU(); // ensure we always get a filter, by avoiding the possibility of a // special case that would return NULL (if color's alpha is 0 or 0xFF) color = SkColorSetA(color, 0x7F); SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, (SkXfermode::Mode)mode); // allow for no filter if we're in Dst mode (its a no op) if (SkXfermode::kDst_Mode == mode && NULL == cf) { continue; } SkAutoUnref aur(cf); REPORTER_ASSERT(reporter, cf); SkColor c = ~color; SkXfermode::Mode m = ILLEGAL_MODE; SkColor expectedColor = color; SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode; // SkDebugf("--- mc [%d %x] ", mode, color); REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m)); // handle special-case folding by the factory if (SkXfermode::kClear_Mode == mode) { if (c != expectedColor) { expectedColor = 0; } if (m != expectedMode) { expectedMode = SkXfermode::kSrc_Mode; } } // SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor); REPORTER_ASSERT(reporter, c == expectedColor); REPORTER_ASSERT(reporter, m == expectedMode); { SkColorFilter* cf2 = reincarnate_colorfilter(cf); SkAutoUnref aur2(cf2); REPORTER_ASSERT(reporter, cf2); SkColor c2 = ~color; SkXfermode::Mode m2 = ILLEGAL_MODE; REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2)); REPORTER_ASSERT(reporter, c2 == expectedColor); REPORTER_ASSERT(reporter, m2 == expectedMode); } } test_composecolorfilter_limit(reporter); }
virtual void blitRect(int x, int y, int width, int height) { SkASSERT(width > 0 && height > 0); SK_RESTRICT SkPMColor* dst = fDevice->getAddr32(x, y); const SK_RESTRICT SkPMColor16* src = fSource->getAddr16(x - fLeft, y - fTop); unsigned dstRB = fDevice->rowBytes(); unsigned srcRB = fSource->rowBytes(); SK_RESTRICT SkPMColor* buffer = fBuffer; SkColorFilter* colorFilter = fColorFilter; SkXfermode* xfermode = fXfermode; do { fillbuffer(buffer, src, width); if (NULL != colorFilter) { colorFilter->filterSpan(buffer, width, buffer); } if (NULL != xfermode) { xfermode->xfer32(dst, buffer, width, NULL); } else { fProc32(dst, buffer, width, fAlpha); } dst = (SK_RESTRICT SkPMColor*)((char*)dst + dstRB); src = (const SK_RESTRICT SkPMColor16*)((const char*)src + srcRB); } while (--height != 0); }
void GrDistanceFieldTextContext::flush() { if (NULL == fDrawTarget) { return; } if (fCurrVertex > 0) { GrPipelineBuilder pipelineBuilder; pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip); // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); // get our current color SkColor filteredColor; SkColorFilter* colorFilter = fSkPaint.getColorFilter(); if (colorFilter) { filteredColor = colorFilter->filterColor(fSkPaint.getColor()); } else { filteredColor = fSkPaint.getColor(); } this->setupCoverageEffect(filteredColor); // Set draw state if (fUseLCDText) { // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD // processor if the xp can support it. For now we will simply assume that if // fUseLCDText is true, then we have a known color output. const GrXPFactory* xpFactory = pipelineBuilder.getXPFactory(); if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!fCachedGeometryProcessor->hasVertexColor()); } else { // We're using per-vertex color. SkASSERT(fCachedGeometryProcessor->hasVertexColor()); } int nGlyphs = fCurrVertex / kVerticesPerGlyph; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(&pipelineBuilder, fCachedGeometryProcessor.get(), kTriangles_GrPrimitiveType, nGlyphs, kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds); fDrawTarget->resetVertexSource(); fVertices = NULL; fTotalVertexCount -= fCurrVertex; fCurrVertex = 0; SkSafeSetNull(fCurrTexture); fVertexBounds.setLargestInverted(); } }
inline GrDrawBatch* GrAtlasTextBlob::createBatch( const Run::SubRunInfo& info, int glyphCount, int run, int subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, const SkPaint& skPaint, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, bool useGammaCorrectDistanceTable, GrBatchFontCache* cache) { GrMaskFormat format = info.maskFormat(); GrColor subRunColor; if (kARGB_GrMaskFormat == format) { uint8_t paintAlpha = skPaint.getAlpha(); subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); } else { subRunColor = color; } GrAtlasTextBatch* batch; if (info.drawAsDistanceFields()) { SkColor filteredColor; SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { filteredColor = colorFilter->filterColor(skPaint.getColor()); } else { filteredColor = skPaint.getColor(); } bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry()); batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache, distanceAdjustTable, useGammaCorrectDistanceTable, filteredColor, info.hasUseLCDText(), useBGR); } else { batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache); } GrAtlasTextBatch::Geometry& geometry = batch->geometry(); geometry.fViewMatrix = viewMatrix; geometry.fBlob = SkRef(this); geometry.fRun = run; geometry.fSubRun = subRun; geometry.fColor = subRunColor; geometry.fX = x; geometry.fY = y; batch->init(); return batch; }
SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, SkImageFilter* input) { SkASSERT(cf); SkScalar colorMatrix[20], inputMatrix[20]; SkColorFilter* inputColorFilter; if (input && cf->asColorMatrix(colorMatrix) && (inputColorFilter = input->asColorFilter()) && inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clamping(inputMatrix)) { SkScalar combinedMatrix[20]; mult_color_matrix(inputMatrix, colorMatrix, combinedMatrix); SkAutoTUnref<SkColorFilter> newCF(SkNEW_ARGS(SkColorMatrixFilter, (combinedMatrix))); return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0))); } else { return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input)); } }
SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, SkImageFilter* input, const CropRect* cropRect) { SkASSERT(cf); SkScalar colorMatrix[20], inputMatrix[20]; SkColorFilter* inputColorFilter; if (input && cf->asColorMatrix(colorMatrix) && input->asColorFilter(&inputColorFilter) && (NULL != inputColorFilter)) { SkAutoUnref autoUnref(inputColorFilter); if (inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clamping(inputMatrix)) { SkScalar combinedMatrix[20]; mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix); SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combinedMatrix)); return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect)); } } return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect)); }
SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) { if (NULL == cf) { return NULL; } SkColorFilter* inputColorFilter; if (input && input->asColorFilter(&inputColorFilter) && inputColorFilter) { SkAutoUnref autoUnref(inputColorFilter); // Try to collapse two consecutive matrix filters SkScalar colorMatrix[20], inputMatrix[20]; if (cf->asColorMatrix(colorMatrix) && inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clamping(inputMatrix)) { SkScalar combinedMatrix[20]; mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix); SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combinedMatrix)); return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect, 0)); } // Try to collapse two consecutive table filters SkBitmap colorTable, inputTable; if (cf->asComponentTable(&colorTable) && inputColorFilter->asComponentTable(&inputTable)) { uint8_t combinedTable[4 * 256]; SkAutoLockPixels colorLock(colorTable); SkAutoLockPixels inputLock(inputTable); combine_color_tables(colorTable.getAddr8(0, 0), inputTable.getAddr8(0, 0), combinedTable); SkAutoTUnref<SkColorFilter> newCF(SkTableColorFilter::CreateARGB( &combinedTable[256 * 0], &combinedTable[256 * 1], &combinedTable[256 * 2], &combinedTable[256 * 3]) ); return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect, 0)); } } return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID)); }
// 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; }
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; }
static bool changes_alpha(const SkPaint& paint) { SkColorFilter* cf = paint.getColorFilter(); return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); }
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; }
SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, const SkPaint& paint, const SkMatrix& ctm, SkArenaAlloc* alloc) { auto blitter = alloc->make<SkRasterPipelineBlitter>( dst, paint.getBlendMode(), SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace())); SkBlendMode* blend = &blitter->fBlend; SkPM4f* paintColor = &blitter->fPaintColor; SkRasterPipeline* pipeline = &blitter->fShader; SkShader* shader = paint.getShader(); SkColorFilter* colorFilter = paint.getColorFilter(); // TODO: all temporary if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) { return nullptr; } bool is_opaque = paintColor->a() == 1.0f, is_constant = true; if (shader) { pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY); if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) { return nullptr; } if (!is_opaque) { pipeline->append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]); } is_opaque = is_opaque && shader->isOpaque(); is_constant = shader->isConstant(); } else { pipeline->append(SkRasterPipeline::constant_color, paintColor); } if (colorFilter) { if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) { return nullptr; } is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); } if (is_constant) { pipeline->append(SkRasterPipeline::store_f32, &paintColor); pipeline->run(0,1); *pipeline = SkRasterPipeline(); pipeline->append(SkRasterPipeline::constant_color, paintColor); is_opaque = paintColor->a() == 1.0f; } if (is_opaque && *blend == SkBlendMode::kSrcOver) { *blend = SkBlendMode::kSrc; } if (is_constant && *blend == SkBlendMode::kSrc) { SkRasterPipeline p; p.extend(*pipeline); blitter->fDstPtr = &blitter->fMemsetColor; blitter->append_store(&p); p.run(0,1); blitter->fCanMemsetInBlitH = true; } return blitter; }
void GrDistanceFieldTextContext::flush() { if (NULL == fDrawTarget) { return; } if (fCurrVertex > 0) { GrDrawState drawState; drawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget()); bool useColorVerts = !fUseLCDText; set_vertex_attributes(&drawState, useColorVerts); // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); // get our current color SkColor filteredColor; SkColorFilter* colorFilter = fSkPaint.getColorFilter(); if (colorFilter) { filteredColor = colorFilter->filterColor(fSkPaint.getColor()); } else { filteredColor = fSkPaint.getColor(); } this->setupCoverageEffect(filteredColor); // Effects could be stored with one of the cache objects (atlas?) drawState.setGeometryProcessor(fCachedGeometryProcessor.get()); // Set draw state if (fUseLCDText) { GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || fPaint.numColorStages()) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState.hasColorVertexAttribute()); // We don't use the GrPaint's color in this case because it's been premultiplied by // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by // the mask texture color. The end result is that we get // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor int a = SkColorGetA(fSkPaint.getColor()); // paintAlpha drawState.setColor(SkColorSetARGB(a, a, a, a)); // paintColor drawState.setBlendConstant(colorNoPreMul); drawState.setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); } else { if (0xFF == GrColorUnpackA(fPaint.getColor())) { drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true); } // set back to normal in case we took LCD path previously. drawState.setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); // We're using per-vertex color. SkASSERT(drawState.hasColorVertexAttribute()); } int nGlyphs = fCurrVertex / kVerticesPerGlyph; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(&drawState, kTriangles_GrPrimitiveType, nGlyphs, kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds); fDrawTarget->resetVertexSource(); fVertices = NULL; fTotalVertexCount -= fCurrVertex; fCurrVertex = 0; SkSafeSetNull(fCurrTexture); fVertexBounds.setLargestInverted(); } }
static inline bool skpaint_to_grpaint_impl(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo, const SkPaint& skPaint, const SkMatrix& viewM, std::unique_ptr<GrFragmentProcessor>* shaderProcessor, SkBlendMode* primColorMode, GrPaint* grPaint) { grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect()); // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion. GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo); const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. std::unique_ptr<GrFragmentProcessor> shaderFP; if (!primColorMode || blend_requires_shader(*primColorMode)) { if (shaderProcessor) { shaderFP = std::move(*shaderProcessor); } else if (const auto* shader = as_SB(skPaint.getShader())) { shaderFP = shader->asFragmentProcessor(fpArgs); 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. GrColor4f shaderInput = origColor.opaque(); shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput); shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP), *primColorMode); // The above may return null if compose results in a pass through of the prim color. if (shaderFP) { grPaint->addColorFragmentProcessor(std::move(shaderFP)); } // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // The shader's FP sees the paint unpremul color grPaint->setColor4f(origColor); grPaint->addColorFragmentProcessor(std::move(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. auto processor = GrConstColorProcessor::Make(origColor.opaque(), GrConstColorProcessor::InputMode::kIgnore); processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor), *primColorMode); if (processor) { grPaint->addColorFragmentProcessor(std::move(processor)); } grPaint->setColor4f(origColor.opaque()); // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // No shader, no primitive color. grPaint->setColor4f(origColor.premul()); applyColorFilterToPaintColor = true; } } SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { // If we're in legacy mode, we *must* avoid using the 4f version of the color filter, // because that will combine with the linearized version of the stored color. if (colorSpaceInfo.isGammaCorrect()) { grPaint->setColor4f(GrColor4f::FromSkColor4f( colorFilter->filterColor4f(origColor.toSkColor4f())).premul()); } else { grPaint->setColor4f(SkColorToPremulGrColor4fLegacy( colorFilter->filterColor(skPaint.getColor()))); } } else { auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo); if (cfFP) { grPaint->addColorFragmentProcessor(std::move(cfFP)); } else { return false; } } } SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter()); if (maskFilter) { if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) { grPaint->addCoverageFragmentProcessor(std::move(mfFP)); } } // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on // the GrPaint to also be null (also kSrcOver). SkASSERT(!grPaint->getXPFactory()); if (!skPaint.isSrcOver()) { grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode())); } #ifndef SK_IGNORE_GPU_DITHER // Conservative default, in case GrPixelConfigToColorType() fails. SkColorType ct = SkColorType::kRGB_565_SkColorType; GrPixelConfigToColorType(colorSpaceInfo.config(), &ct); if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 && !colorSpaceInfo.isGammaCorrect()) { auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config()); if (ditherFP) { grPaint->addColorFragmentProcessor(std::move(ditherFP)); } } #endif return true; }