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 22static 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 38static 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 54static 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->drawText(str.c_str(), str.size(), x, y + paint.getTextSize(), paint); 64 x += width + SkIntToScalar(10); 65 } 66} 67 68class ArithmodeGM : public skiagm::GM { 69public: 70 ArithmodeGM () {} 71 72protected: 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 SkPaint p; 143 p.setImageFilter(SkArithmeticImageFilter::Make(0, one / 2, -one, 1, true, 144 std::move(bg), dstFilter, nullptr)); 145 canvas->saveLayer(&rect, &p); 146 canvas->restore(); 147 canvas->translate(gap, 0); 148 149 // Label 150 SkPaint paint; 151 paint.setTextSize(SkIntToScalar(24)); 152 paint.setAntiAlias(true); 153 sk_tool_utils::set_portable_typeface(&paint); 154 SkString str(enforcePMColor ? "enforcePM" : "no enforcePM"); 155 canvas->drawText(str.c_str(), str.size(), 0, paint.getTextSize(), paint); 156 } 157 canvas->translate(0, HH + 12); 158 } 159 } 160 161private: 162 typedef GM INHERITED; 163}; 164 165/////////////////////////////////////////////////////////////////////////////// 166 167DEF_GM( return new ArithmodeGM; ) 168