From 0530c88067211818f7ce7bbfc0e92f3bdebc1f2b Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Mon, 26 Sep 2016 15:33:00 -0400 Subject: [PATCH] replace Arithmetic xfermode with imagefilter chrome pre-cl: https://codereview.chromium.org/2369023002/ BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2595 Change-Id: Ia3f3b721854c516f3b7f8c44f71f40a8a2eeb9b4 Reviewed-on: https://skia-review.googlesource.com/2595 Commit-Queue: Mike Reed Reviewed-by: Florin Malita Reviewed-by: Robert Phillips --- bench/XfermodeBench.cpp | 16 -- gm/aaxfermodes.cpp | 29 +-- gm/arithmode.cpp | 2 + gm/imagefiltersgraph.cpp | 3 +- gm/xfermodeimagefilter.cpp | 5 +- gm/xfermodes.cpp | 44 +---- include/effects/SkArithmeticMode.h | 4 + include/effects/SkXfermodeImageFilter.h | 12 ++ src/effects/SkArithmeticMode.cpp | 2 +- src/effects/SkArithmeticModePriv.h | 42 +++++ src/effects/SkXfermodeImageFilter.cpp | 256 ++++++++++++++++++++++++--- src/ports/SkGlobalInitialization_default.cpp | 2 +- 12 files changed, 305 insertions(+), 112 deletions(-) create mode 100644 src/effects/SkArithmeticModePriv.h diff --git a/bench/XfermodeBench.cpp b/bench/XfermodeBench.cpp index 7d00f41..60879d6 100644 --- a/bench/XfermodeBench.cpp +++ b/bench/XfermodeBench.cpp @@ -6,7 +6,6 @@ */ #include "Benchmark.h" -#include "SkArithmeticMode.h" #include "SkCanvas.h" #include "SkPaint.h" #include "SkRandom.h" @@ -23,12 +22,6 @@ public: fName.printf("Xfermode_%s%s", SkXfermode::ModeName(mode), aa ? "_aa" : ""); } - XfermodeBench(sk_sp xferMode, const char* name, bool aa) { - fXfermode = xferMode; - fAA = aa; - fName.printf("Xfermode_%s%s", name, aa ? "_aa" : ""); - } - protected: const char* onGetName() override { return fName.c_str(); } @@ -135,13 +128,4 @@ BENCH(SkXfermode::kSaturation_Mode) BENCH(SkXfermode::kColor_Mode) BENCH(SkXfermode::kLuminosity_Mode) -DEF_BENCH( return new XfermodeBench(SkArithmeticMode::Make(0.2f, -0.3f, 1.5f, -0.7f, false), \ - "arithmetic", false); ) -DEF_BENCH( return new XfermodeBench(SkArithmeticMode::Make(0.2f, -0.3f, 1.5f, -0.7f, true), \ - "arithmetic_enforce_pm", false); ) -DEF_BENCH( return new XfermodeBench(SkArithmeticMode::Make(0.2f, -0.3f, 1.5f, -0.7f, false), \ - "arithmetic", true); ) -DEF_BENCH( return new XfermodeBench(SkArithmeticMode::Make(0.2f, -0.3f, 1.5f, -0.7f, true), \ - "arithmetic_enforce_pm", true); ) - DEF_BENCH(return new XferCreateBench;) diff --git a/gm/aaxfermodes.cpp b/gm/aaxfermodes.cpp index 78f7d3e..678a837 100644 --- a/gm/aaxfermodes.cpp +++ b/gm/aaxfermodes.cpp @@ -39,13 +39,11 @@ enum Shape { kLast_Shape = kConcave_Shape }; -namespace skiagm { - /** * Verifies AA works properly on all Xfermodes, including arithmetic, with both opaque and unknown * src colors. */ -class AAXfermodesGM : public GM { +class AAXfermodesGM : public skiagm::GM { public: AAXfermodesGM() {} @@ -120,6 +118,9 @@ protected: canvas->translate(0, kSubtitleSpacing + kShapeSpacing/2); for (size_t m = 0; m <= SkXfermode::kLastCoeffMode; m++) { + if (firstMode + m > SkXfermode::kLastMode) { + break; + } SkXfermode::Mode mode = static_cast(firstMode + m); canvas->save(); @@ -210,7 +211,7 @@ protected: if (maxSum > 255) { SkPaint dimPaint; dimPaint.setAntiAlias(false); - dimPaint.setXfermode(SkXfermode::Make(SkXfermode::kDstIn_Mode)); + dimPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); if (255 != paint->getAlpha()) { // Dim the src and dst colors. dimPaint.setARGB(255 * 255 / maxSum, 0, 0, 0); @@ -227,16 +228,10 @@ protected: } void drawShape(SkCanvas* canvas, Shape shape, const SkPaint& paint, SkXfermode::Mode mode) { + SkASSERT(mode <= SkXfermode::kLastMode); SkPaint shapePaint(paint); shapePaint.setAntiAlias(kSquare_Shape != shape); - - sk_sp xfermode; - if (mode <= SkXfermode::kLastMode) { - xfermode = SkXfermode::Make(mode); - } else { - xfermode = SkArithmeticMode::Make(+1.0f, +0.25f, -0.5f, +0.1f); - } - shapePaint.setXfermode(std::move(xfermode)); + shapePaint.setXfermodeMode(mode); switch (shape) { case kSquare_Shape: @@ -273,12 +268,6 @@ private: SkPath fOval; SkPath fConcave; - typedef GM INHERITED; + typedef skiagm::GM INHERITED; }; - -////////////////////////////////////////////////////////////////////////////// - -static GM* MyFactory(void*) { return new AAXfermodesGM; } -static GMRegistry reg(MyFactory); - -} +DEF_GM( return new AAXfermodesGM; ) diff --git a/gm/arithmode.cpp b/gm/arithmode.cpp index 70661a0..f98fbf7 100644 --- a/gm/arithmode.cpp +++ b/gm/arithmode.cpp @@ -15,6 +15,7 @@ #define WW 100 #define HH 32 +#ifdef SK_SUPPORT_LEGACY_ARITHMETICMODE static SkBitmap make_bm() { SkBitmap bm; bm.allocN32Pixels(WW, HH); @@ -160,3 +161,4 @@ private: /////////////////////////////////////////////////////////////////////////////// DEF_GM( return new ArithmodeGM; ) +#endif diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp index 0f3dcd1..9803989 100644 --- a/gm/imagefiltersgraph.cpp +++ b/gm/imagefiltersgraph.cpp @@ -7,7 +7,6 @@ #include "gm.h" -#include "SkArithmeticMode.h" #include "SkBlurImageFilter.h" #include "SkColorFilter.h" #include "SkColorFilterImageFilter.h" @@ -90,7 +89,7 @@ protected: SkPaint paint; paint.setImageFilter( - SkXfermodeImageFilter::Make(SkArithmeticMode::Make(0, SK_Scalar1, SK_Scalar1, 0), + SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true, std::move(matrixFilter), std::move(offsetFilter), nullptr)); diff --git a/gm/xfermodeimagefilter.cpp b/gm/xfermodeimagefilter.cpp index 0ff0ea9..a0677c7 100644 --- a/gm/xfermodeimagefilter.cpp +++ b/gm/xfermodeimagefilter.cpp @@ -7,7 +7,6 @@ #include "gm.h" #include "sk_tool_utils.h" -#include "SkArithmeticMode.h" #include "SkImage.h" #include "SkImageSource.h" #include "SkOffsetImageFilter.h" @@ -97,9 +96,7 @@ protected: } } // Test arithmetic mode as image filter - paint.setImageFilter(SkXfermodeImageFilter::Make( - SkArithmeticMode::Make(0, SK_Scalar1, SK_Scalar1, 0), - background)); + paint.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true, background)); DrawClippedBitmap(canvas, fBitmap, paint, x, y); x += fBitmap.width() + MARGIN; if (x + fBitmap.width() > WIDTH) { diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp index 68d267b..8fbbdbe 100644 --- a/gm/xfermodes.cpp +++ b/gm/xfermodes.cpp @@ -11,31 +11,6 @@ #include "SkXfermode.h" #include "SkPM4f.h" -#include "SkArithmeticMode.h" - -#define kCustomShift 16 -#define kCustomMask (~0xFFFF) - -enum CustomModes { - kArithmetic_CustomMode = 1 << kCustomShift, -}; - -static sk_sp make_custom(int customMode) { - switch (customMode) { - case kArithmetic_CustomMode: { - const SkScalar k1 = 0.25; - const SkScalar k2 = 0.75; - const SkScalar k3 = 0.75; - const SkScalar k4 = -0.25; - return SkArithmeticMode::Make(k1, k2, k3, k4); - } - default: - break; - } - SkASSERT(false); - return nullptr; -} - enum SrcType { //! A WxH image with a rectangle in the lower right. kRectangleImage_SrcType = 0x01, @@ -98,8 +73,6 @@ const struct { { SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType }, { SkXfermode::kColor_Mode, "Color", kBasic_SrcType }, { SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType }, - - { SkXfermode::Mode(0xFFFF), "Arithmetic", kBasic_SrcType + kArithmetic_CustomMode }, }; static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst, @@ -145,7 +118,7 @@ class XfermodesGM : public skiagm::GM { * uses the implied shape of the drawing command and these modes * demonstrate that. */ - void draw_mode(SkCanvas* canvas, sk_sp mode, SrcType srcType, + void draw_mode(SkCanvas* canvas, SkXfermode::Mode mode, SrcType srcType, SkScalar x, SkScalar y) { SkPaint p; SkMatrix m; @@ -153,7 +126,7 @@ class XfermodesGM : public skiagm::GM { m.setTranslate(x, y); canvas->drawBitmap(fSrcB, x, y, &p); - p.setXfermode(std::move(mode)); + p.setXfermodeMode(mode); switch (srcType) { case kSmallTransparentImage_SrcType: { m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y); @@ -241,7 +214,7 @@ protected: } SkISize onISize() override { - return SkISize::Make(1990, 660); + return SkISize::Make(1990, 570); } void onDraw(SkCanvas* canvas) override { @@ -269,14 +242,7 @@ protected: if ((gModes[i].fSourceTypeMask & sourceType) == 0) { continue; } - sk_sp mode; - if (gModes[i].fSourceTypeMask & kCustomMask) { - mode = make_custom(gModes[i].fSourceTypeMask & kCustomMask); - } else { - mode = SkXfermode::Make(gModes[i].fMode); - } - SkRect r; - r.set(x, y, x+w, y+h); + SkRect r{ x, y, x+w, y+h }; SkPaint p; p.setStyle(SkPaint::kFill_Style); @@ -284,7 +250,7 @@ protected: canvas->drawRect(r, p); canvas->saveLayer(&r, nullptr); - draw_mode(canvas, std::move(mode), static_cast(sourceType), + draw_mode(canvas, gModes[i].fMode, static_cast(sourceType), r.fLeft, r.fTop); canvas->restore(); diff --git a/include/effects/SkArithmeticMode.h b/include/effects/SkArithmeticMode.h index b160dc7..81b9f85 100644 --- a/include/effects/SkArithmeticMode.h +++ b/include/effects/SkArithmeticMode.h @@ -12,6 +12,8 @@ #include "SkScalar.h" #include "SkXfermode.h" +#ifdef SK_SUPPORT_LEGACY_ARITHMETICMODE + class SK_API SkArithmeticMode { public: /** @@ -38,3 +40,5 @@ private: }; #endif + +#endif diff --git a/include/effects/SkXfermodeImageFilter.h b/include/effects/SkXfermodeImageFilter.h index e391575..6066b8d 100644 --- a/include/effects/SkXfermodeImageFilter.h +++ b/include/effects/SkXfermodeImageFilter.h @@ -26,6 +26,18 @@ public: return Make(std::move(mode), std::move(background), nullptr, nullptr); } + static sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); + static sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background) { + return MakeArithmetic(k1, k2, k3, k4, enforcePMColor, std::move(background), + nullptr, nullptr); + } + #ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR static SkImageFilter* Create(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground = NULL, diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp index b8aa368..876f34b 100644 --- a/src/effects/SkArithmeticMode.cpp +++ b/src/effects/SkArithmeticMode.cpp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "SkArithmeticMode.h" +#include "SkArithmeticModePriv.h" #include "SkColorPriv.h" #include "SkNx.h" #include "SkRasterPipeline.h" diff --git a/src/effects/SkArithmeticModePriv.h b/src/effects/SkArithmeticModePriv.h new file mode 100644 index 0000000..04bd90e --- /dev/null +++ b/src/effects/SkArithmeticModePriv.h @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkArithmeticModePriv_DEFINED +#define SkArithmeticModePriv_DEFINED + +#include "SkArithmeticMode.h" + +#ifndef SK_SUPPORT_LEGACY_ARITHMETICMODE + +class SK_API SkArithmeticMode { +public: + /** + * result = clamp[k1 * src * dst + k2 * src + k3 * dst + k4] + * + * k1=k2=k3=0, k4=1.0 results in returning opaque white + * k1=k3=k4=0, k2=1.0 results in returning the src + * k1=k2=k4=0, k3=1.0 results in returning the dst + */ + static sk_sp Make(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, + bool enforcePMColor = true); +#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR + static SkXfermode* Create(SkScalar k1, SkScalar k2, + SkScalar k3, SkScalar k4, + bool enforcePMColor = true) { + return Make(k1, k2, k3, k4, enforcePMColor).release(); + } +#endif + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); + +private: + SkArithmeticMode(); // can't be instantiated +}; + +#endif + +#endif diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp index c602a4a..655c48c 100644 --- a/src/effects/SkXfermodeImageFilter.cpp +++ b/src/effects/SkXfermodeImageFilter.cpp @@ -20,11 +20,12 @@ #include "effects/GrConstColorProcessor.h" #include "effects/GrTextureDomain.h" #include "effects/GrSimpleTextureEffect.h" +#include "SkArithmeticMode_gpu.h" #include "SkGr.h" #include "SkGrPriv.h" #endif -class SK_API SkXfermodeImageFilter_Base : public SkImageFilter { +class SkXfermodeImageFilter_Base : public SkImageFilter { public: SkXfermodeImageFilter_Base(sk_sp mode, sk_sp inputs[2], const CropRect* cropRect); @@ -48,6 +49,8 @@ protected: void flatten(SkWriteBuffer&) const override; + virtual void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const; + virtual sk_sp makeFGFrag(sk_sp bgFP) const; private: sk_sp fMode; @@ -138,31 +141,33 @@ sk_sp SkXfermodeImageFilter_Base::onFilterImage(SkSpecialImage* SkASSERT(canvas); canvas->clear(0x0); // can't count on background to fully clear the background - canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - if (background) { + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); background->draw(canvas, SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY), &paint); } - paint.setXfermode(fMode); + this->drawForeground(canvas, foreground.get(), foregroundBounds); - if (foreground) { - foreground->draw(canvas, - SkIntToScalar(foregroundOffset.fX), SkIntToScalar(foregroundOffset.fY), - &paint); + return surf->makeImageSnapshot(); +} + +void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage* img, + const SkIRect& fgBounds) const { + SkPaint paint; + paint.setXfermode(fMode); + if (img) { + img->draw(canvas, SkIntToScalar(fgBounds.fLeft), SkIntToScalar(fgBounds.fTop), &paint); } - canvas->clipRect(SkRect::Make(foregroundBounds), SkCanvas::kDifference_Op); - paint.setColor(SK_ColorTRANSPARENT); + SkAutoCanvasRestore acr(canvas, true); + canvas->clipRect(SkRect::Make(fgBounds), SkCanvas::kDifference_Op); + paint.setColor(0); canvas->drawPaint(paint); - - return surf->makeImageSnapshot(); } #ifndef SK_IGNORE_TO_STRING @@ -249,21 +254,7 @@ sk_sp SkXfermodeImageFilter_Base::filterImageGPU( paint.addColorFragmentProcessor(std::move(foregroundFP)); - // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). - SkAutoTUnref mode(SkSafeRef(fMode.get())); - if (!mode) { - // It would be awesome to use SkXfermode::Create here but it knows better - // than us and won't return a kSrcOver_Mode SkXfermode. That means we - // have to get one the hard way. - struct ProcCoeff rec; - rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); - SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); - - mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); - } - - sk_sp xferFP( - mode->makeFragmentProcessorForImageFilter(std::move(bgFP))); + sk_sp xferFP = this->makeFGFrag(bgFP); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { @@ -294,13 +285,220 @@ sk_sp SkXfermodeImageFilter_Base::filterImageGPU( sk_ref_sp(drawContext->getColorSpace())); } +sk_sp +SkXfermodeImageFilter_Base::makeFGFrag(sk_sp bgFP) const { + // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). + SkAutoTUnref mode(SkSafeRef(fMode.get())); + if (!mode) { + // It would be awesome to use SkXfermode::Create here but it knows better + // than us and won't return a kSrcOver_Mode SkXfermode. That means we + // have to get one the hard way. + struct ProcCoeff rec; + rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); + SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); + + mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); + } + return mode->makeFragmentProcessorForImageFilter(std::move(bgFP)); +} + #endif /////////////////////////////////////////////////////////////////////////////////////////////////// +class SkArithmeticImageFilter : public SkXfermodeImageFilter_Base { +public: + SkArithmeticImageFilter(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp inputs[2], const CropRect* cropRect) + : SkXfermodeImageFilter_Base(nullptr, inputs, cropRect) + , fK{ k1, k2, k3, k4 } + , fEnforcePMColor(enforcePMColor) + {} + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticImageFilter) + +protected: + void flatten(SkWriteBuffer& buffer) const override { + this->INHERITED::flatten(buffer); + for (int i = 0; i < 4; ++i) { + buffer.writeScalar(fK[i]); + } + buffer.writeBool(fEnforcePMColor); + } + void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const override; + sk_sp makeFGFrag(sk_sp bgFP) const override; + +private: + const float fK[4]; + const bool fEnforcePMColor; + + friend class SkXfermodeImageFilter; + + typedef SkXfermodeImageFilter_Base INHERITED; +}; + +sk_sp SkArithmeticImageFilter::CreateProc(SkReadBuffer& buffer) { + SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); + + // skip the mode (srcover) our parent-class wrote + sk_sp mode(buffer.readXfermode()); + SkASSERT(nullptr == mode); + + float k[4]; + for (int i = 0; i < 4; ++i) { + k[i] = buffer.readScalar(); + } + const bool enforcePMColor = buffer.readBool(); + return SkXfermodeImageFilter::MakeArithmetic(k[0], k[1], k[2], k[3], enforcePMColor, + common.getInput(0), common.getInput(1), + &common.cropRect()); +} + +#include "SkNx.h" + +static Sk4f pin(float min, const Sk4f& val, float max) { + return Sk4f::Max(min, Sk4f::Min(val, max)); +} + +template void arith_span(const float k[], SkPMColor dst[], + const SkPMColor src[], int count) { + const Sk4f k1 = k[0] * (1/255.0f), + k2 = k[1], + k3 = k[2], + k4 = k[3] * 255.0f + 0.5f; + + for (int i = 0; i < count; i++) { + Sk4f s = SkNx_cast(Sk4b::Load(src+i)), + d = SkNx_cast(Sk4b::Load(dst+i)), + r = pin(0, k1*s*d + k2*s + k3*d + k4, 255); + if (EnforcePMColor) { + Sk4f a = SkNx_shuffle<3,3,3,3>(r); + r = Sk4f::Min(a, r); + } + SkNx_cast(r).store(dst+i); + } +} + +// apply mode to src==transparent (0) +template void arith_transparent(const float k[], SkPMColor dst[], int count) { + const Sk4f k3 = k[2], + k4 = k[3] * 255.0f + 0.5f; + + for (int i = 0; i < count; i++) { + Sk4f d = SkNx_cast(Sk4b::Load(dst+i)), + r = pin(0, k3*d + k4, 255); + if (EnforcePMColor) { + Sk4f a = SkNx_shuffle<3,3,3,3>(r); + r = Sk4f::Min(a, r); + } + SkNx_cast(r).store(dst+i); + } +} + +static bool intersect(SkPixmap* dst, SkPixmap* src, SkIPoint srcOffset) { + SkIRect dstR = SkIRect::MakeWH(dst->width(), dst->height()); + SkIRect srcR = SkIRect::MakeXYWH(srcOffset.x(), srcOffset.y(), src->width(), src->height()); + SkIRect sect; + if (!sect.intersect(dstR, srcR)) { + return false; + } + *dst = SkPixmap(dst->info().makeWH(sect.width(), sect.height()), + dst->addr(sect.fLeft, sect.fTop), + dst->rowBytes()); + *src = SkPixmap(src->info().makeWH(sect.width(), sect.height()), + src->addr(SkTMax(0, -srcOffset.x()), SkTMax(0, -srcOffset.y())), + src->rowBytes()); + return true; +} + +void SkArithmeticImageFilter::drawForeground(SkCanvas* canvas, SkSpecialImage* img, + const SkIRect& fgBounds) const { + SkPixmap dst; + if (!canvas->peekPixels(&dst)) { + return; + } + + if (img) { + SkBitmap srcBM; + SkPixmap src; + if (!img->getROPixels(&srcBM)) { + return; + } + srcBM.lockPixels(); + if (!srcBM.peekPixels(&src)) { + return; + } + + auto proc = fEnforcePMColor ? arith_span : arith_span; + const SkMatrix& ctm = canvas->getTotalMatrix(); + SkASSERT(ctm.getType() <= SkMatrix::kTranslate_Mask); + SkIPoint offset { + fgBounds.fLeft + SkScalarRoundToInt(ctm.getTranslateX()), + fgBounds.fTop + SkScalarRoundToInt(ctm.getTranslateY()), + }; + SkPixmap tmpDst = dst; + if (intersect(&tmpDst, &src, offset)) { + for (int y = 0; y < tmpDst.height(); ++y) { + proc(fK, tmpDst.writable_addr32(0, y), src.addr32(0, y), tmpDst.width()); + } + } + } + + // Now apply the mode with transparent-color to the outside of the fg image + SkRegion outside(SkIRect::MakeWH(dst.width(), dst.height())); + outside.op(fgBounds, SkRegion::kDifference_Op); + auto proc = fEnforcePMColor ? arith_transparent : arith_transparent; + for (SkRegion::Iterator iter(outside); !iter.done(); iter.next()) { + const SkIRect r = iter.rect(); + for (int y = r.fTop; y < r.fBottom; ++y) { + proc(fK, dst.writable_addr32(r.fLeft, y), r.width()); + } + } +} + +sk_sp +SkArithmeticImageFilter::makeFGFrag(sk_sp bgFP) const { + return GrArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP)); +} + +sk_sp SkXfermodeImageFilter::MakeArithmetic(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* crop) { + if (!SkScalarIsFinite(k1) || !SkScalarIsFinite(k2) || + !SkScalarIsFinite(k3) || !SkScalarIsFinite(k4)) { + return nullptr; + } + + // are we nearly some other "std" mode? + int mode = -1; // illegal mode + if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && + SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { + mode = SkXfermode::kSrc_Mode; + } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && + SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) { + mode = SkXfermode::kDst_Mode; + } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && + SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { + mode = SkXfermode::kClear_Mode; + } + if (mode >= 0) { + return SkXfermodeImageFilter::Make(SkXfermode::Make((SkXfermode::Mode)mode), + std::move(background), std::move(foreground), crop); + } + + sk_sp inputs[2] = { std::move(background), std::move(foreground) }; + return sk_sp(new SkArithmeticImageFilter(k1, k2, k3, k4, enforcePMColor, + inputs, crop)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermodeImageFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter_Base) // manually register the legacy serialized name "SkXfermodeImageFilter" SkFlattenable::Register("SkXfermodeImageFilter", SkXfermodeImageFilter_Base::CreateProc, SkFlattenable::kSkImageFilter_Type); + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticImageFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp index be41422..499e9bf 100644 --- a/src/ports/SkGlobalInitialization_default.cpp +++ b/src/ports/SkGlobalInitialization_default.cpp @@ -8,7 +8,7 @@ #include "Sk1DPathEffect.h" #include "Sk2DPathEffect.h" #include "SkAlphaThresholdFilter.h" -#include "SkArithmeticMode.h" +#include "../../src/effects/SkArithmeticModePriv.h" #include "SkArcToPathEffect.h" #include "SkBitmapSourceDeserializer.h" #include "SkBlurDrawLooper.h" -- 2.7.4