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