gradient_matrix.cpp revision 910f694aefb0b671dd8522a9afe9b6be645701c1
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
22static 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.
28static const SkScalar sZero = 0;
29static const SkScalar sHalf = SK_ScalarHalf;
30static const SkScalar sOne = SK_Scalar1;
31
32// These arrays define the gradient stop points
33// as x1, y1, x2, y2 per gradient to draw.
34static 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
46static 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.
59static const SkScalar TESTGRID_X = SkIntToScalar(200);
60static const SkScalar TESTGRID_Y = SkIntToScalar(200);
61
62static const int IMAGES_X = 4;             // number of images per row
63
64static SkShader* make_linear_gradient(const SkPoint pts[2]) {
65    return SkGradientShader::CreateLinear(pts, gColors, NULL, SK_ARRAY_COUNT(gColors),
66                                          SkShader::kClamp_TileMode, NULL);
67}
68
69static SkShader* make_radial_gradient(const SkPoint pts[2]) {
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, NULL);
76}
77
78static void draw_gradients(SkCanvas* canvas, SkShader* (*makeShader)(const SkPoint[2]),
79                           const SkPoint ptsArray[][2], int numImages) {
80    // Use some nice prime numbers for the rectangle and matrix with
81    // different scaling along the x and y axes (which is the bug this
82    // test addresses, where incorrect order of operations mixed up the axes)
83    SkRect rectGrad = {
84        SkIntToScalar(43),  SkIntToScalar(61),
85        SkIntToScalar(181), SkIntToScalar(167) };
86    SkMatrix shaderMat;
87    shaderMat.setScale(rectGrad.width(), rectGrad.height());
88    shaderMat.postTranslate(rectGrad.left(), rectGrad.top());
89
90    canvas->save();
91    for (int i = 0; i < numImages; i++) {
92        // Advance line downwards if necessary.
93        if (i % IMAGES_X == 0 && i != 0) {
94            canvas->restore();
95            canvas->translate(0, TESTGRID_Y);
96            canvas->save();
97        }
98
99        // Setup shader and draw.
100        SkAutoTUnref<SkShader> shader(makeShader(*ptsArray));
101        shader->setLocalMatrix(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
114namespace skiagm {
115
116class GradientMatrixGM : public GM {
117public:
118    GradientMatrixGM() {
119        this->setBGColor(0xFFDDDDDD);
120    }
121
122protected:
123    SkString onShortName() SK_OVERRIDE {
124        return SkString("gradient_matrix");
125    }
126
127    virtual SkISize onISize() SK_OVERRIDE {
128        return SkISize::Make(800, 800);
129    }
130
131    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
132        draw_gradients(canvas, &make_linear_gradient,
133                      linearPts, SK_ARRAY_COUNT(linearPts));
134
135        canvas->translate(0, TESTGRID_Y);
136
137        draw_gradients(canvas, &make_radial_gradient,
138                      radialPts, SK_ARRAY_COUNT(radialPts));
139    }
140
141private:
142    typedef GM INHERITED;
143};
144
145DEF_GM( return new GradientMatrixGM; )
146}
147