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 22 static const 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. 28 static const SkScalar sZero = 0; 29 static const SkScalar sHalf = SK_ScalarHalf; 30 static const SkScalar sOne = SK_Scalar1; 31 32 // These arrays define the gradient stop points 33 // as x1, y1, x2, y2 per gradient to draw. 34 static const 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 46 static const 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. 59 static const SkScalar TESTGRID_X = SkIntToScalar(200); 60 static const SkScalar TESTGRID_Y = SkIntToScalar(200); 61 62 static const int IMAGES_X = 4; // number of images per row 63 64 static SkShader* make_linear_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) { 65 return SkGradientShader::CreateLinear(pts, gColors, NULL, SK_ARRAY_COUNT(gColors), 66 SkShader::kClamp_TileMode, 0, &localMatrix); 67 } 68 69 static 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::CreateRadial(center, radius, gColors, NULL, SK_ARRAY_COUNT(gColors), 75 SkShader::kClamp_TileMode, 0, &localMatrix); 76 } 77 78 static void draw_gradients(SkCanvas* canvas, 79 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 // Setup shader and draw. 101 SkAutoTUnref<SkShader> shader(makeShader(*ptsArray, shaderMat)); 102 103 SkPaint paint; 104 paint.setShader(shader); 105 canvas->drawRect(rectGrad, paint); 106 107 // Advance to next position. 108 canvas->translate(TESTGRID_X, 0); 109 ptsArray++; 110 } 111 canvas->restore(); 112 } 113 114 namespace skiagm { 115 116 class GradientMatrixGM : public GM { 117 public: 118 GradientMatrixGM() { 119 this->setBGColor(0xFFDDDDDD); 120 } 121 122 protected: 123 virtual uint32_t onGetFlags() const SK_OVERRIDE { 124 return kSkipTiled_Flag; 125 } 126 127 SkString onShortName() SK_OVERRIDE { 128 return SkString("gradient_matrix"); 129 } 130 131 virtual SkISize onISize() SK_OVERRIDE { 132 return SkISize::Make(800, 800); 133 } 134 135 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { 136 draw_gradients(canvas, &make_linear_gradient, 137 linearPts, SK_ARRAY_COUNT(linearPts)); 138 139 canvas->translate(0, TESTGRID_Y); 140 141 draw_gradients(canvas, &make_radial_gradient, 142 radialPts, SK_ARRAY_COUNT(radialPts)); 143 } 144 145 private: 146 typedef GM INHERITED; 147 }; 148 149 DEF_GM( return new GradientMatrixGM; ) 150 } 151