|  | /* | 
|  | * Copyright 2013 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "SkCanvas.h" | 
|  | #include "SkColor.h" | 
|  | #include "SkGradientShader.h" | 
|  | #include "SkMatrix.h" | 
|  | #include "SkPaint.h" | 
|  | #include "SkPoint.h" | 
|  | #include "SkRect.h" | 
|  | #include "SkRefCnt.h" | 
|  | #include "SkScalar.h" | 
|  | #include "SkSize.h" | 
|  | #include "SkString.h" | 
|  |  | 
|  | #include "gm.h" | 
|  |  | 
|  | static const SkColor gColors[] = { | 
|  | SK_ColorRED, SK_ColorYELLOW | 
|  | }; | 
|  |  | 
|  | // These annoying defines are necessary, because the only other alternative | 
|  | // is to use SkIntToScalar(...) everywhere. | 
|  | static const SkScalar sZero = 0; | 
|  | static const SkScalar sHalf = SK_ScalarHalf; | 
|  | static const SkScalar sOne = SK_Scalar1; | 
|  |  | 
|  | // These arrays define the gradient stop points | 
|  | // as x1, y1, x2, y2 per gradient to draw. | 
|  | static const SkPoint linearPts[][2] = { | 
|  | {{sZero, sZero}, {sOne,  sZero}}, | 
|  | {{sZero, sZero}, {sZero, sOne}}, | 
|  | {{sOne,  sZero}, {sZero, sZero}}, | 
|  | {{sZero, sOne},  {sZero, sZero}}, | 
|  |  | 
|  | {{sZero, sZero}, {sOne,  sOne}}, | 
|  | {{sOne,  sOne},  {sZero, sZero}}, | 
|  | {{sOne,  sZero}, {sZero, sOne}}, | 
|  | {{sZero, sOne},  {sOne,  sZero}} | 
|  | }; | 
|  |  | 
|  | static const SkPoint radialPts[][2] = { | 
|  | {{sZero, sHalf}, {sOne,  sHalf}}, | 
|  | {{sHalf, sZero}, {sHalf, sOne}}, | 
|  | {{sOne,  sHalf}, {sZero, sHalf}}, | 
|  | {{sHalf, sOne},  {sHalf, sZero}}, | 
|  |  | 
|  | {{sZero, sZero}, {sOne,  sOne}}, | 
|  | {{sOne,  sOne},  {sZero, sZero}}, | 
|  | {{sOne,  sZero}, {sZero, sOne}}, | 
|  | {{sZero, sOne},  {sOne,  sZero}} | 
|  | }; | 
|  |  | 
|  | // These define the pixels allocated to each gradient image. | 
|  | static const SkScalar TESTGRID_X = SkIntToScalar(200); | 
|  | static const SkScalar TESTGRID_Y = SkIntToScalar(200); | 
|  |  | 
|  | static const int IMAGES_X = 4;             // number of images per row | 
|  |  | 
|  | static SkShader* make_linear_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) { | 
|  | return SkGradientShader::CreateLinear(pts, gColors, NULL, SK_ARRAY_COUNT(gColors), | 
|  | SkShader::kClamp_TileMode, 0, &localMatrix); | 
|  | } | 
|  |  | 
|  | static SkShader* make_radial_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) { | 
|  | SkPoint center; | 
|  | center.set(SkScalarAve(pts[0].fX, pts[1].fX), | 
|  | SkScalarAve(pts[0].fY, pts[1].fY)); | 
|  | float radius = (center - pts[0]).length(); | 
|  | return SkGradientShader::CreateRadial(center, radius, gColors, NULL, SK_ARRAY_COUNT(gColors), | 
|  | SkShader::kClamp_TileMode, 0, &localMatrix); | 
|  | } | 
|  |  | 
|  | static void draw_gradients(SkCanvas* canvas, | 
|  | SkShader* (*makeShader)(const SkPoint[2], const SkMatrix&), | 
|  | const SkPoint ptsArray[][2], int numImages) { | 
|  | // Use some nice prime numbers for the rectangle and matrix with | 
|  | // different scaling along the x and y axes (which is the bug this | 
|  | // test addresses, where incorrect order of operations mixed up the axes) | 
|  | SkRect rectGrad = { | 
|  | SkIntToScalar(43),  SkIntToScalar(61), | 
|  | SkIntToScalar(181), SkIntToScalar(167) }; | 
|  | SkMatrix shaderMat; | 
|  | shaderMat.setScale(rectGrad.width(), rectGrad.height()); | 
|  | shaderMat.postTranslate(rectGrad.left(), rectGrad.top()); | 
|  |  | 
|  | canvas->save(); | 
|  | for (int i = 0; i < numImages; i++) { | 
|  | // Advance line downwards if necessary. | 
|  | if (i % IMAGES_X == 0 && i != 0) { | 
|  | canvas->restore(); | 
|  | canvas->translate(0, TESTGRID_Y); | 
|  | canvas->save(); | 
|  | } | 
|  |  | 
|  | // Setup shader and draw. | 
|  | SkAutoTUnref<SkShader> shader(makeShader(*ptsArray, shaderMat)); | 
|  |  | 
|  | SkPaint paint; | 
|  | paint.setShader(shader); | 
|  | canvas->drawRect(rectGrad, paint); | 
|  |  | 
|  | // Advance to next position. | 
|  | canvas->translate(TESTGRID_X, 0); | 
|  | ptsArray++; | 
|  | } | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | namespace skiagm { | 
|  |  | 
|  | class GradientMatrixGM : public GM { | 
|  | public: | 
|  | GradientMatrixGM() { | 
|  | this->setBGColor(0xFFDDDDDD); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | virtual uint32_t onGetFlags() const SK_OVERRIDE { | 
|  | return kSkipTiled_Flag; | 
|  | } | 
|  |  | 
|  | SkString onShortName() SK_OVERRIDE { | 
|  | return SkString("gradient_matrix"); | 
|  | } | 
|  |  | 
|  | virtual SkISize onISize() SK_OVERRIDE { | 
|  | return SkISize::Make(800, 800); | 
|  | } | 
|  |  | 
|  | virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { | 
|  | draw_gradients(canvas, &make_linear_gradient, | 
|  | linearPts, SK_ARRAY_COUNT(linearPts)); | 
|  |  | 
|  | canvas->translate(0, TESTGRID_Y); | 
|  |  | 
|  | draw_gradients(canvas, &make_radial_gradient, | 
|  | radialPts, SK_ARRAY_COUNT(radialPts)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | typedef GM INHERITED; | 
|  | }; | 
|  |  | 
|  | DEF_GM( return new GradientMatrixGM; ) | 
|  | } |