1/*
2 * Copyright 2015 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 "include/core/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkColorFilter.h"
12#include "include/core/SkPaint.h"
13#include "include/core/SkRefCnt.h"
14#include "tests/Test.h"
15
16#include <cmath>
17#include <cstdlib>
18
19static inline void assert_color(skiatest::Reporter* reporter,
20                                SkColor expected, SkColor actual, int tolerance) {
21    REPORTER_ASSERT(reporter, abs((int)(SkColorGetA(expected) - SkColorGetA(actual))) <= tolerance);
22    REPORTER_ASSERT(reporter, abs((int)(SkColorGetR(expected) - SkColorGetR(actual))) <= tolerance);
23    REPORTER_ASSERT(reporter, abs((int)(SkColorGetG(expected) - SkColorGetG(actual))) <= tolerance);
24    REPORTER_ASSERT(reporter, abs((int)(SkColorGetB(expected) - SkColorGetB(actual))) <= tolerance);
25}
26
27static inline void assert_color(skiatest::Reporter* reporter, SkColor expected, SkColor actual) {
28    const int TOLERANCE = 1;
29    assert_color(reporter, expected, actual, TOLERANCE);
30}
31
32/**
33 * This test case is a mirror of the Android CTS tests for MatrixColorFilter
34 * found in the android.graphics.ColorMatrixColorFilterTest class.
35 */
36static inline void test_colorMatrixCTS(skiatest::Reporter* reporter) {
37
38    SkBitmap bitmap;
39    bitmap.allocN32Pixels(1,1);
40
41    SkCanvas canvas(bitmap);
42    SkPaint paint;
43
44    float blueToCyan[20] = {
45            1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
46            0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
47            0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
48            0.0f, 0.0f, 0.0f, 1.0f, 0.0f };
49    paint.setColorFilter(SkColorFilters::Matrix(blueToCyan));
50
51    paint.setColor(SK_ColorBLUE);
52    canvas.drawPoint(0, 0, paint);
53    assert_color(reporter, SK_ColorCYAN, bitmap.getColor(0, 0));
54
55    paint.setColor(SK_ColorGREEN);
56    canvas.drawPoint(0, 0, paint);
57    assert_color(reporter, SK_ColorGREEN, bitmap.getColor(0, 0));
58
59    paint.setColor(SK_ColorRED);
60    canvas.drawPoint(0, 0, paint);
61    assert_color(reporter, SK_ColorRED, bitmap.getColor(0, 0));
62
63    // color components are clipped, not scaled
64    paint.setColor(SK_ColorMAGENTA);
65    canvas.drawPoint(0, 0, paint);
66    assert_color(reporter, SK_ColorWHITE, bitmap.getColor(0, 0));
67
68    float transparentRedAddBlue[20] = {
69            1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
70            0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
71            0.0f, 0.0f, 1.0f, 0.0f, 64.0f/255,
72           -0.5f, 0.0f, 0.0f, 1.0f, 0.0f
73    };
74    paint.setColorFilter(SkColorFilters::Matrix(transparentRedAddBlue));
75    bitmap.eraseColor(SK_ColorTRANSPARENT);
76
77    paint.setColor(SK_ColorRED);
78    canvas.drawPoint(0, 0, paint);
79    assert_color(reporter, SkColorSetARGB(128, 255, 0, 64), bitmap.getColor(0, 0), 2);
80
81    paint.setColor(SK_ColorCYAN);
82    canvas.drawPoint(0, 0, paint);
83    // blue gets clipped
84    assert_color(reporter, SK_ColorCYAN, bitmap.getColor(0, 0));
85
86    // change array to filter out green
87    REPORTER_ASSERT(reporter, 1.0f == transparentRedAddBlue[6]);
88    transparentRedAddBlue[6] = 0.0f;
89
90    // check that changing the array has no effect
91    canvas.drawPoint(0, 0, paint);
92    assert_color(reporter, SK_ColorCYAN, bitmap.getColor(0, 0));
93
94    // create a new filter with the changed matrix
95    paint.setColorFilter(SkColorFilters::Matrix(transparentRedAddBlue));
96    canvas.drawPoint(0, 0, paint);
97    assert_color(reporter, SK_ColorBLUE, bitmap.getColor(0, 0));
98}
99
100DEF_TEST(ColorMatrix, reporter) {
101    test_colorMatrixCTS(reporter);
102}
103
104
105DEF_TEST(ColorMatrix_clamp_while_unpremul, r) {
106    // This matrix does green += 255/255 and alpha += 32/255.  We want to test
107    // that if we pass it opaque alpha and small red and blue values, red and
108    // blue stay unchanged, not pumped up by that ~1.12 intermediate alpha.
109    float m[] = {
110        1, 0, 0, 0, 0,
111        0, 1, 0, 0, 1,
112        0, 0, 1, 0, 0,
113        0, 0, 0, 1, 32.0f/255,
114    };
115    auto filter = SkColorFilters::Matrix(m);
116
117    SkColor filtered = filter->filterColor(0xff0a0b0c);
118    REPORTER_ASSERT(r, SkColorGetA(filtered) == 0xff);
119    REPORTER_ASSERT(r, SkColorGetR(filtered) == 0x0a);
120    REPORTER_ASSERT(r, SkColorGetG(filtered) == 0xff);
121    REPORTER_ASSERT(r, SkColorGetB(filtered) == 0x0c);
122}
123