1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm.h" 9 #include "sk_tool_utils.h" 10 #include "SkArithmeticImageFilter.h" 11 #include "SkCanvas.h" 12 #include "SkColorPriv.h" 13 #include "SkGradientShader.h" 14 #include "SkImage.h" 15 #include "SkImageSource.h" 16 #include "SkShader.h" 17 #include "SkSurface.h" 18 19 #define WW 100 20 #define HH 32 21 22 static sk_sp<SkImage> make_src() { 23 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(WW, HH)); 24 SkCanvas* canvas = surface->getCanvas(); 25 26 SkPaint paint; 27 SkPoint pts[] = { {0, 0}, {SkIntToScalar(WW), SkIntToScalar(HH)} }; 28 SkColor colors[] = { 29 SK_ColorTRANSPARENT, SK_ColorGREEN, SK_ColorCYAN, 30 SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE, 31 }; 32 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), 33 SkShader::kClamp_TileMode)); 34 canvas->drawPaint(paint); 35 return surface->makeImageSnapshot(); 36 } 37 38 static sk_sp<SkImage> make_dst() { 39 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(WW, HH)); 40 SkCanvas* canvas = surface->getCanvas(); 41 42 SkPaint paint; 43 SkPoint pts[] = { {0, SkIntToScalar(HH)}, {SkIntToScalar(WW), 0} }; 44 SkColor colors[] = { 45 SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, 46 sk_tool_utils::color_to_565(SK_ColorGRAY) 47 }; 48 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), 49 SkShader::kClamp_TileMode)); 50 canvas->drawPaint(paint); 51 return surface->makeImageSnapshot(); 52 } 53 54 static void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) { 55 SkPaint paint; 56 paint.setTextSize(SkIntToScalar(24)); 57 paint.setAntiAlias(true); 58 sk_tool_utils::set_portable_typeface(&paint); 59 for (int i = 0; i < 4; ++i) { 60 SkString str; 61 str.appendScalar(k[i]); 62 SkScalar width = paint.measureText(str.c_str(), str.size()); 63 canvas->drawString(str, x, y + paint.getTextSize(), paint); 64 x += width + SkIntToScalar(10); 65 } 66 } 67 68 class ArithmodeGM : public skiagm::GM { 69 public: 70 ArithmodeGM () {} 71 72 protected: 73 74 virtual SkString onShortName() { 75 return SkString("arithmode"); 76 } 77 78 virtual SkISize onISize() { return SkISize::Make(640, 572); } 79 80 virtual void onDraw(SkCanvas* canvas) { 81 sk_sp<SkImage> src = make_src(); 82 sk_sp<SkImage> dst = make_dst(); 83 sk_sp<SkImageFilter> srcFilter = SkImageSource::Make(src); 84 sk_sp<SkImageFilter> dstFilter = SkImageSource::Make(dst); 85 86 constexpr SkScalar one = SK_Scalar1; 87 constexpr SkScalar K[] = { 88 0, 0, 0, 0, 89 0, 0, 0, one, 90 0, one, 0, 0, 91 0, 0, one, 0, 92 0, one, one, 0, 93 0, one, -one, 0, 94 0, one/2, one/2, 0, 95 0, one/2, one/2, one/4, 96 0, one/2, one/2, -one/4, 97 one/4, one/2, one/2, 0, 98 -one/4, one/2, one/2, 0, 99 }; 100 101 const SkScalar* k = K; 102 const SkScalar* stop = k + SK_ARRAY_COUNT(K); 103 const SkRect rect = SkRect::MakeWH(WW, HH); 104 SkScalar gap = SkIntToScalar(WW + 20); 105 while (k < stop) { 106 { 107 SkAutoCanvasRestore acr(canvas, true); 108 canvas->drawImage(src, 0, 0); 109 canvas->translate(gap, 0); 110 canvas->drawImage(dst, 0, 0); 111 canvas->translate(gap, 0); 112 SkPaint paint; 113 paint.setImageFilter(SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], true, 114 dstFilter, srcFilter, nullptr)); 115 canvas->saveLayer(&rect, &paint); 116 canvas->restore(); 117 118 canvas->translate(gap, 0); 119 show_k_text(canvas, 0, 0, k); 120 } 121 122 k += 4; 123 canvas->translate(0, HH + 12); 124 } 125 126 // Draw two special cases to test enforcePMColor. In these cases, we 127 // draw the dst bitmap twice, the first time it is halved and inverted, 128 // leading to invalid premultiplied colors. If we enforcePMColor, these 129 // invalid values should be clamped, and will not contribute to the 130 // second draw. 131 for (int i = 0; i < 2; i++) { 132 const bool enforcePMColor = (i == 0); 133 134 { 135 SkAutoCanvasRestore acr(canvas, true); 136 canvas->translate(gap, 0); 137 canvas->drawImage(dst, 0, 0); 138 canvas->translate(gap, 0); 139 140 sk_sp<SkImageFilter> bg = 141 SkArithmeticImageFilter::Make(0, 0, -one / 2, 1, enforcePMColor, dstFilter, 142 nullptr, nullptr); 143 SkPaint p; 144 p.setImageFilter(SkArithmeticImageFilter::Make(0, one / 2, -one, 1, true, 145 std::move(bg), dstFilter, nullptr)); 146 canvas->saveLayer(&rect, &p); 147 canvas->restore(); 148 canvas->translate(gap, 0); 149 150 // Label 151 SkPaint paint; 152 paint.setTextSize(SkIntToScalar(24)); 153 paint.setAntiAlias(true); 154 sk_tool_utils::set_portable_typeface(&paint); 155 SkString str(enforcePMColor ? "enforcePM" : "no enforcePM"); 156 canvas->drawString(str, 0, paint.getTextSize(), paint); 157 } 158 canvas->translate(0, HH + 12); 159 } 160 } 161 162 private: 163 typedef GM INHERITED; 164 }; 165 166 /////////////////////////////////////////////////////////////////////////////// 167 168 DEF_GM( return new ArithmodeGM; ) 169