1/*
2 * Copyright 2011 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 "SkColor.h"
9#include "SkColorFilter.h"
10#include "SkColorPriv.h"
11#include "SkLumaColorFilter.h"
12#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
14#include "SkRandom.h"
15#include "SkXfermode.h"
16#include "Test.h"
17
18static SkColorFilter* reincarnate_colorfilter(SkFlattenable* obj) {
19    SkWriteBuffer wb;
20    wb.writeFlattenable(obj);
21
22    size_t size = wb.bytesWritten();
23    SkAutoSMalloc<1024> storage(size);
24    // make a copy into storage
25    wb.writeToMemory(storage.get());
26
27    SkReadBuffer rb(storage.get(), size);
28    return rb.readColorFilter();
29}
30
31///////////////////////////////////////////////////////////////////////////////
32
33#define ILLEGAL_MODE    ((SkXfermode::Mode)-1)
34
35DEF_TEST(ColorFilter, reporter) {
36    SkRandom rand;
37
38    for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) {
39        SkColor color = rand.nextU();
40
41        // ensure we always get a filter, by avoiding the possibility of a
42        // special case that would return NULL (if color's alpha is 0 or 0xFF)
43        color = SkColorSetA(color, 0x7F);
44
45        SkColorFilter* cf = SkColorFilter::CreateModeFilter(color,
46                                                        (SkXfermode::Mode)mode);
47
48        // allow for no filter if we're in Dst mode (its a no op)
49        if (SkXfermode::kDst_Mode == mode && NULL == cf) {
50            continue;
51        }
52
53        SkAutoUnref aur(cf);
54        REPORTER_ASSERT(reporter, cf);
55
56        SkColor c = ~color;
57        SkXfermode::Mode m = ILLEGAL_MODE;
58
59        SkColor expectedColor = color;
60        SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode;
61
62//        SkDebugf("--- mc [%d %x] ", mode, color);
63
64        REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m));
65        // handle special-case folding by the factory
66        if (SkXfermode::kClear_Mode == mode) {
67            if (c != expectedColor) {
68                expectedColor = 0;
69            }
70            if (m != expectedMode) {
71                expectedMode = SkXfermode::kSrc_Mode;
72            }
73        }
74
75//        SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor);
76
77        REPORTER_ASSERT(reporter, c == expectedColor);
78        REPORTER_ASSERT(reporter, m == expectedMode);
79
80        {
81            SkColorFilter* cf2 = reincarnate_colorfilter(cf);
82            SkAutoUnref aur2(cf2);
83            REPORTER_ASSERT(reporter, cf2);
84
85            SkColor c2 = ~color;
86            SkXfermode::Mode m2 = ILLEGAL_MODE;
87            REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2));
88            REPORTER_ASSERT(reporter, c2 == expectedColor);
89            REPORTER_ASSERT(reporter, m2 == expectedMode);
90        }
91    }
92}
93
94///////////////////////////////////////////////////////////////////////////////
95
96DEF_TEST(LumaColorFilter, reporter) {
97    SkPMColor in, out;
98    SkAutoTUnref<SkColorFilter> lf(SkLumaColorFilter::Create());
99
100    // Applying luma to white produces black with the same transparency.
101    for (unsigned i = 0; i < 256; ++i) {
102        in = SkPackARGB32(i, i, i, i);
103        lf->filterSpan(&in, 1, &out);
104        REPORTER_ASSERT(reporter, SkGetPackedA32(out) == i);
105        REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
106        REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
107        REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
108    }
109
110    // Applying luma to black yields transparent black (luminance(black) == 0)
111    for (unsigned i = 0; i < 256; ++i) {
112        in = SkPackARGB32(i, 0, 0, 0);
113        lf->filterSpan(&in, 1, &out);
114        REPORTER_ASSERT(reporter, out == SK_ColorTRANSPARENT);
115    }
116
117    // For general colors, a luma filter generates black with an attenuated alpha channel.
118    for (unsigned i = 1; i < 256; ++i) {
119        in = SkPackARGB32(i, i, i / 2, i / 3);
120        lf->filterSpan(&in, 1, &out);
121        REPORTER_ASSERT(reporter, out != in);
122        REPORTER_ASSERT(reporter, SkGetPackedA32(out) <= i);
123        REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
124        REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
125        REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
126    }
127}
128