1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 11cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 12cb93a386Sopenharmony_ci#include "include/core/SkFontTypes.h" 13cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 14cb93a386Sopenharmony_ci#include "include/core/SkImageFilter.h" 15cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 17cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 18cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 19cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 20cb93a386Sopenharmony_ci#include "include/core/SkShader.h" 21cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 22cb93a386Sopenharmony_ci#include "include/core/SkString.h" 23cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 24cb93a386Sopenharmony_ci#include "include/core/SkTileMode.h" 25cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 26cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 27cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 28cb93a386Sopenharmony_ci#include "include/effects/SkImageFilters.h" 29cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#include <utility> 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cistatic sk_sp<SkImage> make_src(int w, int h) { 34cb93a386Sopenharmony_ci sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(w, h)); 35cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci SkPaint paint; 38cb93a386Sopenharmony_ci SkPoint pts[] = { {0, 0}, {SkIntToScalar(w), SkIntToScalar(h)} }; 39cb93a386Sopenharmony_ci SkColor colors[] = { 40cb93a386Sopenharmony_ci SK_ColorTRANSPARENT, SK_ColorGREEN, SK_ColorCYAN, 41cb93a386Sopenharmony_ci SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE, 42cb93a386Sopenharmony_ci }; 43cb93a386Sopenharmony_ci paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), 44cb93a386Sopenharmony_ci SkTileMode::kClamp)); 45cb93a386Sopenharmony_ci canvas->drawPaint(paint); 46cb93a386Sopenharmony_ci return surface->makeImageSnapshot(); 47cb93a386Sopenharmony_ci} 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cistatic sk_sp<SkImage> make_dst(int w, int h) { 50cb93a386Sopenharmony_ci sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(w, h)); 51cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci SkPaint paint; 54cb93a386Sopenharmony_ci SkPoint pts[] = { {0, SkIntToScalar(h)}, {SkIntToScalar(w), 0} }; 55cb93a386Sopenharmony_ci SkColor colors[] = { 56cb93a386Sopenharmony_ci SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, 57cb93a386Sopenharmony_ci SK_ColorGRAY, 58cb93a386Sopenharmony_ci }; 59cb93a386Sopenharmony_ci paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), 60cb93a386Sopenharmony_ci SkTileMode::kClamp)); 61cb93a386Sopenharmony_ci canvas->drawPaint(paint); 62cb93a386Sopenharmony_ci return surface->makeImageSnapshot(); 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_cistatic void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) { 66cb93a386Sopenharmony_ci SkFont font(ToolUtils::create_portable_typeface(), 24); 67cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAntiAlias); 68cb93a386Sopenharmony_ci SkPaint paint; 69cb93a386Sopenharmony_ci paint.setAntiAlias(true); 70cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 71cb93a386Sopenharmony_ci SkString str; 72cb93a386Sopenharmony_ci str.appendScalar(k[i]); 73cb93a386Sopenharmony_ci SkScalar width = font.measureText(str.c_str(), str.size(), SkTextEncoding::kUTF8); 74cb93a386Sopenharmony_ci canvas->drawString(str, x, y + font.getSize(), font, paint); 75cb93a386Sopenharmony_ci x += width + SkIntToScalar(10); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci} 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ciclass ArithmodeGM : public skiagm::GM { 80cb93a386Sopenharmony_ci SkString onShortName() override { return SkString("arithmode"); } 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci SkISize onISize() override { return {640, 572}; } 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci void onDraw(SkCanvas* canvas) override { 85cb93a386Sopenharmony_ci constexpr int WW = 100, 86cb93a386Sopenharmony_ci HH = 32; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci sk_sp<SkImage> src = make_src(WW, HH); 89cb93a386Sopenharmony_ci sk_sp<SkImage> dst = make_dst(WW, HH); 90cb93a386Sopenharmony_ci sk_sp<SkImageFilter> srcFilter = SkImageFilters::Image(src); 91cb93a386Sopenharmony_ci sk_sp<SkImageFilter> dstFilter = SkImageFilters::Image(dst); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci constexpr SkScalar one = SK_Scalar1; 94cb93a386Sopenharmony_ci constexpr SkScalar K[] = { 95cb93a386Sopenharmony_ci 0, 0, 0, 0, 96cb93a386Sopenharmony_ci 0, 0, 0, one, 97cb93a386Sopenharmony_ci 0, one, 0, 0, 98cb93a386Sopenharmony_ci 0, 0, one, 0, 99cb93a386Sopenharmony_ci 0, one, one, 0, 100cb93a386Sopenharmony_ci 0, one, -one, 0, 101cb93a386Sopenharmony_ci 0, one/2, one/2, 0, 102cb93a386Sopenharmony_ci 0, one/2, one/2, one/4, 103cb93a386Sopenharmony_ci 0, one/2, one/2, -one/4, 104cb93a386Sopenharmony_ci one/4, one/2, one/2, 0, 105cb93a386Sopenharmony_ci -one/4, one/2, one/2, 0, 106cb93a386Sopenharmony_ci }; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci const SkScalar* k = K; 109cb93a386Sopenharmony_ci const SkScalar* stop = k + SK_ARRAY_COUNT(K); 110cb93a386Sopenharmony_ci const SkRect rect = SkRect::MakeWH(WW, HH); 111cb93a386Sopenharmony_ci SkScalar gap = SkIntToScalar(WW + 20); 112cb93a386Sopenharmony_ci while (k < stop) { 113cb93a386Sopenharmony_ci { 114cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(canvas, true); 115cb93a386Sopenharmony_ci canvas->drawImage(src, 0, 0); 116cb93a386Sopenharmony_ci canvas->translate(gap, 0); 117cb93a386Sopenharmony_ci canvas->drawImage(dst, 0, 0); 118cb93a386Sopenharmony_ci canvas->translate(gap, 0); 119cb93a386Sopenharmony_ci SkPaint paint; 120cb93a386Sopenharmony_ci paint.setImageFilter(SkImageFilters::Arithmetic(k[0], k[1], k[2], k[3], true, 121cb93a386Sopenharmony_ci dstFilter, srcFilter, nullptr)); 122cb93a386Sopenharmony_ci canvas->saveLayer(&rect, &paint); 123cb93a386Sopenharmony_ci canvas->restore(); 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci canvas->translate(gap, 0); 126cb93a386Sopenharmony_ci show_k_text(canvas, 0, 0, k); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci k += 4; 130cb93a386Sopenharmony_ci canvas->translate(0, HH + 12); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // Draw two special cases to test enforcePMColor. In these cases, we 134cb93a386Sopenharmony_ci // draw the dst bitmap twice, the first time it is halved and inverted, 135cb93a386Sopenharmony_ci // leading to invalid premultiplied colors. If we enforcePMColor, these 136cb93a386Sopenharmony_ci // invalid values should be clamped, and will not contribute to the 137cb93a386Sopenharmony_ci // second draw. 138cb93a386Sopenharmony_ci for (int i = 0; i < 2; i++) { 139cb93a386Sopenharmony_ci const bool enforcePMColor = (i == 0); 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci { 142cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(canvas, true); 143cb93a386Sopenharmony_ci canvas->translate(gap, 0); 144cb93a386Sopenharmony_ci canvas->drawImage(dst, 0, 0); 145cb93a386Sopenharmony_ci canvas->translate(gap, 0); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci sk_sp<SkImageFilter> bg = 148cb93a386Sopenharmony_ci SkImageFilters::Arithmetic(0, 0, -one / 2, 1, enforcePMColor, dstFilter, 149cb93a386Sopenharmony_ci nullptr, nullptr); 150cb93a386Sopenharmony_ci SkPaint p; 151cb93a386Sopenharmony_ci p.setImageFilter(SkImageFilters::Arithmetic(0, one / 2, -one, 1, true, 152cb93a386Sopenharmony_ci std::move(bg), dstFilter, nullptr)); 153cb93a386Sopenharmony_ci canvas->saveLayer(&rect, &p); 154cb93a386Sopenharmony_ci canvas->restore(); 155cb93a386Sopenharmony_ci canvas->translate(gap, 0); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci // Label 158cb93a386Sopenharmony_ci SkFont font(ToolUtils::create_portable_typeface(), 24); 159cb93a386Sopenharmony_ci SkString str(enforcePMColor ? "enforcePM" : "no enforcePM"); 160cb93a386Sopenharmony_ci canvas->drawString(str, 0, font.getSize(), font, SkPaint()); 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci canvas->translate(0, HH + 12); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ciprivate: 167cb93a386Sopenharmony_ci using INHERITED = GM; 168cb93a386Sopenharmony_ci}; 169cb93a386Sopenharmony_ciDEF_GM( return new ArithmodeGM; ) 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci#include "include/effects/SkBlenders.h" 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ciclass Arithmode2GM : public skiagm::GM { 176cb93a386Sopenharmony_ci float fK1, fK2, fK3, fK4; 177cb93a386Sopenharmony_ci sk_sp<SkImage> fSrc, fDst, fChecker; 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci SkString onShortName() override { return SkString("arithmode_blender"); } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci SkISize onISize() override { return {430, 430}; } 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci enum { 184cb93a386Sopenharmony_ci W = 200, 185cb93a386Sopenharmony_ci H = 200, 186cb93a386Sopenharmony_ci }; 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci void onOnceBeforeDraw() override { 189cb93a386Sopenharmony_ci // need something interesting, in case we're drawn w/o calling animate() 190cb93a386Sopenharmony_ci fK1 = -0.25f; 191cb93a386Sopenharmony_ci fK2 = 0.25f; 192cb93a386Sopenharmony_ci fK3 = 0.25f; 193cb93a386Sopenharmony_ci fK4 = 0; 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci fSrc = make_src(W, H); 196cb93a386Sopenharmony_ci fDst = make_dst(W, H); 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci fChecker = ToolUtils::create_checkerboard_image(W, H, 0xFFBBBBBB, 0xFFEEEEEE, 8); 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci bool onAnimate(double nanos) override { 202cb93a386Sopenharmony_ci double theta = nanos * 1e-6 * 0.001; 203cb93a386Sopenharmony_ci fK1 = sin(theta + 0) * 0.25; 204cb93a386Sopenharmony_ci fK2 = cos(theta + 1) * 0.25; 205cb93a386Sopenharmony_ci fK3 = sin(theta + 2) * 0.25; 206cb93a386Sopenharmony_ci fK4 = 0.5; 207cb93a386Sopenharmony_ci return true; 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci void onDraw(SkCanvas* canvas) override { 211cb93a386Sopenharmony_ci const SkRect rect = SkRect::MakeWH(W, H); 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci canvas->drawImage(fSrc, 10, 10); 214cb93a386Sopenharmony_ci canvas->drawImage(fDst, 10, 10 + fSrc->height() + 10); 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci auto sampling = SkSamplingOptions(); 217cb93a386Sopenharmony_ci auto blender = SkBlenders::Arithmetic(fK1, fK2, fK3, fK4, true); 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci SkPaint paint; 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci canvas->translate(10 + fSrc->width() + 10, 10); 222cb93a386Sopenharmony_ci canvas->drawImage(fChecker, 0, 0); 223cb93a386Sopenharmony_ci 224cb93a386Sopenharmony_ci // Draw via blend step 225cb93a386Sopenharmony_ci canvas->saveLayer(&rect, nullptr); 226cb93a386Sopenharmony_ci canvas->drawImage(fDst, 0, 0); 227cb93a386Sopenharmony_ci paint.setBlender(blender); 228cb93a386Sopenharmony_ci canvas->drawImage(fSrc, 0, 0, sampling, &paint); 229cb93a386Sopenharmony_ci canvas->restore(); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci canvas->translate(0, 10 + fSrc->height()); 232cb93a386Sopenharmony_ci canvas->drawImage(fChecker, 0, 0); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci // Draw via imagefilter (should appear the same as above) 235cb93a386Sopenharmony_ci paint.setBlender(nullptr); 236cb93a386Sopenharmony_ci paint.setImageFilter(SkImageFilters::Blend(blender, 237cb93a386Sopenharmony_ci /* dst imagefilter */nullptr, 238cb93a386Sopenharmony_ci SkImageFilters::Image(fSrc, sampling))); 239cb93a386Sopenharmony_ci canvas->drawImage(fDst, 0, 0, sampling, &paint); 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ciprivate: 243cb93a386Sopenharmony_ci using INHERITED = GM; 244cb93a386Sopenharmony_ci}; 245cb93a386Sopenharmony_ciDEF_GM( return new Arithmode2GM; ) 246