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