1 /* 2 * Copyright 2013 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 "SkCanvas.h" 9 #include "SkColor.h" 10 #include "SkGradientShader.h" 11 #include "SkMatrix.h" 12 #include "SkPaint.h" 13 #include "SkPoint.h" 14 #include "SkRect.h" 15 #include "SkRefCnt.h" 16 #include "SkScalar.h" 17 #include "SkSize.h" 18 #include "SkString.h" 19 20 #include "gm.h" 21 #include "sk_tool_utils.h" 22 23 constexpr SkColor gColors[] = { 24 SK_ColorRED, SK_ColorYELLOW 25 }; 26 27 // These annoying defines are necessary, because the only other alternative 28 // is to use SkIntToScalar(...) everywhere. 29 constexpr SkScalar sZero = 0; 30 constexpr SkScalar sHalf = SK_ScalarHalf; 31 constexpr SkScalar sOne = SK_Scalar1; 32 33 // These arrays define the gradient stop points 34 // as x1, y1, x2, y2 per gradient to draw. 35 constexpr SkPoint linearPts[][2] = { 36 {{sZero, sZero}, {sOne, sZero}}, 37 {{sZero, sZero}, {sZero, sOne}}, 38 {{sOne, sZero}, {sZero, sZero}}, 39 {{sZero, sOne}, {sZero, sZero}}, 40 41 {{sZero, sZero}, {sOne, sOne}}, 42 {{sOne, sOne}, {sZero, sZero}}, 43 {{sOne, sZero}, {sZero, sOne}}, 44 {{sZero, sOne}, {sOne, sZero}} 45 }; 46 47 constexpr SkPoint radialPts[][2] = { 48 {{sZero, sHalf}, {sOne, sHalf}}, 49 {{sHalf, sZero}, {sHalf, sOne}}, 50 {{sOne, sHalf}, {sZero, sHalf}}, 51 {{sHalf, sOne}, {sHalf, sZero}}, 52 53 {{sZero, sZero}, {sOne, sOne}}, 54 {{sOne, sOne}, {sZero, sZero}}, 55 {{sOne, sZero}, {sZero, sOne}}, 56 {{sZero, sOne}, {sOne, sZero}} 57 }; 58 59 // These define the pixels allocated to each gradient image. 60 constexpr SkScalar TESTGRID_X = SkIntToScalar(200); 61 constexpr SkScalar TESTGRID_Y = SkIntToScalar(200); 62 63 constexpr int IMAGES_X = 4; // number of images per row 64 65 static sk_sp<SkShader> make_linear_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) { 66 return SkGradientShader::MakeLinear(pts, gColors, nullptr, SK_ARRAY_COUNT(gColors), 67 SkShader::kClamp_TileMode, 0, &localMatrix); 68 } 69 70 static sk_sp<SkShader> make_radial_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) { 71 SkPoint center; 72 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 73 SkScalarAve(pts[0].fY, pts[1].fY)); 74 float radius = (center - pts[0]).length(); 75 return SkGradientShader::MakeRadial(center, radius, gColors, nullptr, SK_ARRAY_COUNT(gColors), 76 SkShader::kClamp_TileMode, 0, &localMatrix); 77 } 78 79 static void draw_gradients(SkCanvas* canvas, 80 sk_sp<SkShader> (*makeShader)(const SkPoint[2], const SkMatrix&), 81 const SkPoint ptsArray[][2], int numImages) { 82 // Use some nice prime numbers for the rectangle and matrix with 83 // different scaling along the x and y axes (which is the bug this 84 // test addresses, where incorrect order of operations mixed up the axes) 85 SkRect rectGrad = { 86 SkIntToScalar(43), SkIntToScalar(61), 87 SkIntToScalar(181), SkIntToScalar(167) }; 88 SkMatrix shaderMat; 89 shaderMat.setScale(rectGrad.width(), rectGrad.height()); 90 shaderMat.postTranslate(rectGrad.left(), rectGrad.top()); 91 92 canvas->save(); 93 for (int i = 0; i < numImages; i++) { 94 // Advance line downwards if necessary. 95 if (i % IMAGES_X == 0 && i != 0) { 96 canvas->restore(); 97 canvas->translate(0, TESTGRID_Y); 98 canvas->save(); 99 } 100 101 SkPaint paint; 102 paint.setShader(makeShader(*ptsArray, shaderMat)); 103 canvas->drawRect(rectGrad, paint); 104 105 // Advance to next position. 106 canvas->translate(TESTGRID_X, 0); 107 ptsArray++; 108 } 109 canvas->restore(); 110 } 111 112 DEF_SIMPLE_GM_BG(gradient_matrix, canvas, 800, 800, 113 sk_tool_utils::color_to_565(0xFFDDDDDD)) { 114 draw_gradients(canvas, &make_linear_gradient, 115 linearPts, SK_ARRAY_COUNT(linearPts)); 116 117 canvas->translate(0, TESTGRID_Y); 118 119 draw_gradients(canvas, &make_radial_gradient, 120 radialPts, SK_ARRAY_COUNT(radialPts)); 121 } 122