183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com/*
283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com * Copyright 2011 Google Inc.
383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com *
483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com * Use of this source code is governed by a BSD-style license that can be
583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com * found in the LICENSE file.
683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com */
7e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.org
88c0c7b0bcdf17ff672a972748f692a41c22aa0a1reed#include "SkCanvas.h"
983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com#include "SkColorShader.h"
1083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com#include "SkGradientShader.h"
111f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com#include "SkShader.h"
121f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com#include "SkTemplates.h"
138f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "Test.h"
1483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
1583226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstruct GradRec {
1683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    int             fColorCount;
1783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    const SkColor*  fColors;
1883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    const SkScalar* fPos;
1983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    const SkPoint*  fPoint;   // 2
2083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    const SkScalar* fRadius; // 2
2183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::TileMode fTileMode;
2283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
2383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    void gradCheck(skiatest::Reporter* reporter, SkShader* shader,
2483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                   SkShader::GradientInfo* info,
2583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                   SkShader::GradientType gt) const {
2683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        SkAutoTMalloc<SkColor> colorStorage(fColorCount);
2783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        SkAutoTMalloc<SkScalar> posStorage(fColorCount);
2883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
2983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        info->fColorCount = fColorCount;
3083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        info->fColors = colorStorage;
3183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        info->fColorOffsets = posStorage.get();
3283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        REPORTER_ASSERT(reporter, shader->asAGradient(info) == gt);
3383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
3483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        REPORTER_ASSERT(reporter, info->fColorCount == fColorCount);
3583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        REPORTER_ASSERT(reporter,
3683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                        !memcmp(info->fColors, fColors, fColorCount * sizeof(SkColor)));
3783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        REPORTER_ASSERT(reporter,
3883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                        !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(SkScalar)));
3983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        REPORTER_ASSERT(reporter, fTileMode == info->fTileMode);
4083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    }
4183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com};
4283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
4383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
44e0e385c1d4171e065348ba17c546b3463a0bd651sugoi@google.comstatic void none_gradproc(skiatest::Reporter* reporter, const GradRec&) {
45e1085e0381a4abfe440e664c1a0669f3676a8092reed    SkAutoTUnref<SkShader> s(SkShader::CreateEmptyShader());
4683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, SkShader::kNone_GradientType == s->asAGradient(NULL));
4783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
4883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
4983226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
5083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(new SkColorShader(rec.fColors[0]));
5183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, SkShader::kColor_GradientType == s->asAGradient(NULL));
5283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
5383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
5437ebe3fbf6c4a5728bc2c322cc0f626444f987bfrobertphillips@google.com    info.fColors = NULL;
5583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    info.fColorCount = 0;
5683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    s->asAGradient(&info);
5783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, 1 == info.fColorCount);
5883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
5983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
6083226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void linear_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
6183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(rec.fPoint,
6283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColors,
6383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fPos,
6483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColorCount,
6583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fTileMode));
66d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
6783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
6883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.gradCheck(reporter, s, &info, SkShader::kLinear_GradientType);
6983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
7083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
7183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
7283226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void radial_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
7383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(SkGradientShader::CreateRadial(rec.fPoint[0],
7483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fRadius[0],
7583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColors,
7683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fPos,
7783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColorCount,
7883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fTileMode));
79d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
8083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
8183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.gradCheck(reporter, s, &info, SkShader::kRadial_GradientType);
8283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]);
8383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, info.fRadius[0] == rec.fRadius[0]);
8483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
8583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
8683226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void radial2_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
8783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(SkGradientShader::CreateTwoPointRadial(rec.fPoint[0],
8883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fRadius[0],
8983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fPoint[1],
9083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fRadius[1],
9183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColors,
9283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fPos,
9383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fColorCount,
9483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                            rec.fTileMode));
95d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
9683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
9783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.gradCheck(reporter, s, &info, SkShader::kRadial2_GradientType);
9883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
9983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkScalar)));
10083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
10183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
10283226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
10383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(SkGradientShader::CreateSweep(rec.fPoint[0].fX,
10483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                           rec.fPoint[0].fY,
10583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                           rec.fColors,
10683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                           rec.fPos,
10783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                           rec.fColorCount));
108d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
10983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
11083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.gradCheck(reporter, s, &info, SkShader::kSweep_GradientType);
11183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]);
11283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
11383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
11483226976b532141b26ff3a40f381a5d08ce3259dreed@google.comstatic void conical_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
11583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkAutoTUnref<SkShader> s(SkGradientShader::CreateTwoPointConical(rec.fPoint[0],
11683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fRadius[0],
11783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fPoint[1],
11883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fRadius[1],
11983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fColors,
12083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fPos,
12183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fColorCount,
12283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com                                                             rec.fTileMode));
123d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
12483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    SkShader::GradientInfo info;
12583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.gradCheck(reporter, s, &info, SkShader::kConical_GradientType);
12683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
12783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkScalar)));
12883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
12983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
130e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org// Ensure that repeated color gradients behave like drawing a single color
131e0e385c1d4171e065348ba17c546b3463a0bd651sugoi@google.comstatic void TestConstantGradient(skiatest::Reporter*) {
132e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    const SkPoint pts[] = {
133e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org        { 0, 0 },
134e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org        { SkIntToScalar(10), 0 }
135e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    };
136e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE };
137e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    const SkScalar pos[] = { 0, SK_Scalar1 };
138e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(pts,
139e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org                                                            colors,
140e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org                                                            pos,
141e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org                                                            2,
142e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org                                                            SkShader::kClamp_TileMode));
143e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    SkBitmap outBitmap;
144deee496cd30070e52556dcb538c2e5eb39b66b81mike@reedtribe.org    outBitmap.allocN32Pixels(10, 1);
145e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    SkPaint paint;
146e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    paint.setShader(s.get());
147deee496cd30070e52556dcb538c2e5eb39b66b81mike@reedtribe.org    SkCanvas canvas(outBitmap);
148e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    canvas.drawPaint(paint);
149e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    SkAutoLockPixels alp(outBitmap);
150e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    for (int i = 0; i < 10; i++) {
151e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org        // The following is commented out because it currently fails
152e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org        // Related bug: https://code.google.com/p/skia/issues/detail?id=1098
153e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org
154e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org        // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0));
155e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    }
156e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org}
157e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org
15883226976b532141b26ff3a40f381a5d08ce3259dreed@google.comtypedef void (*GradProc)(skiatest::Reporter* reporter, const GradRec&);
15983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
160e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.orgstatic void TestGradientShaders(skiatest::Reporter* reporter) {
16183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    static const SkColor gColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
16283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    static const SkScalar gPos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
16383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    static const SkPoint gPts[] = {
16483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        { 0, 0 },
16583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        { SkIntToScalar(10), SkIntToScalar(20) }
16683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    };
16783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    static const SkScalar gRad[] = { SkIntToScalar(1), SkIntToScalar(2) };
16883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
16983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    GradRec rec;
17083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fColorCount = SK_ARRAY_COUNT(gColors);
17183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fColors = gColors;
17283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fPos = gPos;
17383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fPoint = gPts;
17483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fRadius = gRad;
17583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    rec.fTileMode = SkShader::kClamp_TileMode;
17683226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
17783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    static const GradProc gProcs[] = {
17883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        none_gradproc,
17983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        color_gradproc,
18083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        linear_gradproc,
18183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        radial_gradproc,
18283226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        radial2_gradproc,
18383226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        sweep_gradproc,
18483226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        conical_gradproc,
18583226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    };
186d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
18783226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    for (size_t i = 0; i < SK_ARRAY_COUNT(gProcs); ++i) {
18883226976b532141b26ff3a40f381a5d08ce3259dreed@google.com        gProcs[i](reporter, rec);
18983226976b532141b26ff3a40f381a5d08ce3259dreed@google.com    }
19083226976b532141b26ff3a40f381a5d08ce3259dreed@google.com}
19183226976b532141b26ff3a40f381a5d08ce3259dreed@google.com
192e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.orgDEF_TEST(Gradient, reporter) {
193e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    TestGradientShaders(reporter);
194e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org    TestConstantGradient(reporter);
195e94b5e40c5fb0e36eebcae1abfe04b9bc33583f4junov@chromium.org}
196