1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkDrawColor.h"
11#ifdef SK_DEBUG
12#include "SkDisplayList.h"
13#endif
14#include "SkDrawPaint.h"
15#include "SkParse.h"
16#include "SkScript.h"
17
18enum HSV_Choice {
19    kGetHue,
20    kGetSaturation,
21    kGetValue
22};
23
24static SkScalar RGB_to_HSV(SkColor color, HSV_Choice choice) {
25    SkScalar red = SkIntToScalar(SkColorGetR(color));
26    SkScalar green = SkIntToScalar(SkColorGetG(color));
27    SkScalar blue = SkIntToScalar(SkColorGetB(color));
28    SkScalar min = SkMinScalar(SkMinScalar(red, green), blue);
29    SkScalar value = SkMaxScalar(SkMaxScalar(red, green), blue);
30    if (choice == kGetValue)
31        return value/255;
32    SkScalar delta = value - min;
33    SkScalar saturation = value == 0 ? 0 : SkScalarDiv(delta, value);
34    if (choice == kGetSaturation)
35        return saturation;
36    SkScalar hue;
37    if (saturation == 0)
38        hue = 0;
39    else {
40        SkScalar part60 = SkScalarDiv(60 * SK_Scalar1, delta);
41        if (red == value) {
42            hue = SkScalarMul(green - blue, part60);
43            if (hue < 0)
44                hue += 360 * SK_Scalar1;
45        }
46        else if (green == value)
47            hue = 120 * SK_Scalar1 + SkScalarMul(blue - red, part60);
48        else  // blue == value
49            hue = 240 * SK_Scalar1 + SkScalarMul(red - green, part60);
50    }
51    SkASSERT(choice == kGetHue);
52    return hue;
53}
54
55#if defined _WIN32 && _MSC_VER >= 1300  // disable 'red', etc. may be used without having been initialized
56#pragma warning ( push )
57#pragma warning ( disable : 4701 )
58#endif
59
60static SkColor HSV_to_RGB(SkColor color, HSV_Choice choice, SkScalar hsv) {
61    SkScalar hue = choice == kGetHue ? hsv : RGB_to_HSV(color, kGetHue);
62    SkScalar saturation = choice == kGetSaturation ? hsv : RGB_to_HSV(color, kGetSaturation);
63    SkScalar value = choice == kGetValue ? hsv : RGB_to_HSV(color, kGetValue);
64    value *= 255;
65    SkScalar red SK_INIT_TO_AVOID_WARNING;
66    SkScalar green SK_INIT_TO_AVOID_WARNING;
67    SkScalar blue SK_INIT_TO_AVOID_WARNING;
68    if (saturation == 0)    // color is on black-and-white center line
69        red = green = blue = value;
70    else {
71        //SkScalar fraction = SkScalarMod(hue, 60 * SK_Scalar1);
72        int sextant = SkScalarFloorToInt(hue / 60);
73        SkScalar fraction = hue / 60 - SkIntToScalar(sextant);
74        SkScalar p = SkScalarMul(value , SK_Scalar1 - saturation);
75        SkScalar q = SkScalarMul(value, SK_Scalar1 - SkScalarMul(saturation, fraction));
76        SkScalar t = SkScalarMul(value, SK_Scalar1 -
77            SkScalarMul(saturation, SK_Scalar1 - fraction));
78        switch (sextant % 6) {
79            case 0: red = value; green = t; blue = p; break;
80            case 1: red = q; green = value; blue = p; break;
81            case 2: red = p; green = value; blue = t; break;
82            case 3: red = p; green = q; blue = value; break;
83            case 4: red = t;  green = p; blue = value; break;
84            case 5: red = value; green = p; blue = q; break;
85        }
86    }
87    //used to say SkToU8((U8CPU) red) etc
88    return SkColorSetARGB(SkColorGetA(color), SkScalarRoundToInt(red),
89                          SkScalarRoundToInt(green), SkScalarRoundToInt(blue));
90}
91
92#if defined _WIN32 && _MSC_VER >= 1300
93#pragma warning ( pop )
94#endif
95
96enum SkDrawColor_Properties {
97    SK_PROPERTY(alpha),
98    SK_PROPERTY(blue),
99    SK_PROPERTY(green),
100    SK_PROPERTY(hue),
101    SK_PROPERTY(red),
102    SK_PROPERTY(saturation),
103    SK_PROPERTY(value)
104};
105
106#if SK_USE_CONDENSED_INFO == 0
107
108const SkMemberInfo SkDrawColor::fInfo[] = {
109    SK_MEMBER_PROPERTY(alpha, Float),
110    SK_MEMBER_PROPERTY(blue, Float),
111    SK_MEMBER(color, ARGB),
112    SK_MEMBER_PROPERTY(green, Float),
113    SK_MEMBER_PROPERTY(hue, Float),
114    SK_MEMBER_PROPERTY(red, Float),
115    SK_MEMBER_PROPERTY(saturation, Float),
116    SK_MEMBER_PROPERTY(value, Float),
117};
118
119#endif
120
121DEFINE_GET_MEMBER(SkDrawColor);
122
123SkDrawColor::SkDrawColor() : fDirty(false) {
124    color = SK_ColorBLACK;
125    fHue = fSaturation = fValue = SK_ScalarNaN;
126}
127
128bool SkDrawColor::add() {
129    if (fPaint->color != NULL)
130        return true; // error (probably color in paint as attribute as well)
131    fPaint->color = this;
132    fPaint->fOwnsColor = true;
133    return false;
134}
135
136SkDisplayable* SkDrawColor::deepCopy(SkAnimateMaker*) {
137    SkDrawColor* copy = new SkDrawColor();
138    copy->color = color;
139    copy->fHue = fHue;
140    copy->fSaturation = fSaturation;
141    copy->fValue = fValue;
142    copy->fDirty = fDirty;
143    return copy;
144}
145
146void SkDrawColor::dirty(){
147    fDirty = true;
148}
149
150#ifdef SK_DUMP_ENABLED
151void SkDrawColor::dump(SkAnimateMaker* maker) {
152    dumpBase(maker);
153    SkDebugf("alpha=\"%d\" red=\"%d\" green=\"%d\" blue=\"%d\" />\n",
154        SkColorGetA(color)/255, SkColorGetR(color),
155        SkColorGetG(color), SkColorGetB(color));
156}
157#endif
158
159SkColor SkDrawColor::getColor() {
160    if (fDirty) {
161        if (SkScalarIsNaN(fValue) == false)
162            color = HSV_to_RGB(color, kGetValue, fValue);
163        if (SkScalarIsNaN(fSaturation) == false)
164            color = HSV_to_RGB(color, kGetSaturation, fSaturation);
165        if (SkScalarIsNaN(fHue) == false)
166            color = HSV_to_RGB(color, kGetHue, fHue);
167        fDirty = false;
168    }
169    return color;
170}
171
172SkDisplayable* SkDrawColor::getParent() const {
173    return fPaint;
174}
175
176bool SkDrawColor::getProperty(int index, SkScriptValue* value) const {
177    value->fType = SkType_Float;
178    SkScalar result;
179    switch(index) {
180        case SK_PROPERTY(alpha):
181            result = SkIntToScalar(SkColorGetA(color)) / 255;
182            break;
183        case SK_PROPERTY(blue):
184            result = SkIntToScalar(SkColorGetB(color));
185            break;
186        case SK_PROPERTY(green):
187            result = SkIntToScalar(SkColorGetG(color));
188            break;
189        case SK_PROPERTY(hue):
190            result = RGB_to_HSV(color, kGetHue);
191            break;
192        case SK_PROPERTY(red):
193            result = SkIntToScalar(SkColorGetR(color));
194            break;
195        case SK_PROPERTY(saturation):
196            result = RGB_to_HSV(color, kGetSaturation);
197            break;
198        case SK_PROPERTY(value):
199            result = RGB_to_HSV(color, kGetValue);
200            break;
201        default:
202            SkASSERT(0);
203            return false;
204    }
205    value->fOperand.fScalar = result;
206    return true;
207}
208
209void SkDrawColor::onEndElement(SkAnimateMaker&) {
210    fDirty = true;
211}
212
213bool SkDrawColor::setParent(SkDisplayable* parent) {
214    SkASSERT(parent != NULL);
215    if (parent->getType() == SkType_DrawLinearGradient || parent->getType() == SkType_DrawRadialGradient)
216        return false;
217    if (parent->isPaint() == false)
218        return true;
219    fPaint = (SkDrawPaint*) parent;
220    return false;
221}
222
223bool SkDrawColor::setProperty(int index, SkScriptValue& value) {
224    SkASSERT(value.fType == SkType_Float);
225    SkScalar scalar = value.fOperand.fScalar;
226    switch (index) {
227        case SK_PROPERTY(alpha):
228            uint8_t alpha;
229            alpha = scalar == SK_Scalar1 ? 255 : SkToU8((U8CPU) (scalar * 256));
230            color = SkColorSetARGB(alpha, SkColorGetR(color),
231                SkColorGetG(color), SkColorGetB(color));
232            break;
233        case SK_PROPERTY(blue):
234            scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
235            color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color),
236                SkColorGetG(color), SkToU8((U8CPU) scalar));
237            break;
238        case SK_PROPERTY(green):
239            scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
240            color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color),
241                SkToU8((U8CPU) scalar), SkColorGetB(color));
242            break;
243        case SK_PROPERTY(hue):
244            fHue = scalar;//RGB_to_HSV(color, kGetHue);
245            fDirty = true;
246            break;
247        case SK_PROPERTY(red):
248            scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
249            color = SkColorSetARGB(SkColorGetA(color), SkToU8((U8CPU) scalar),
250                SkColorGetG(color), SkColorGetB(color));
251        break;
252        case SK_PROPERTY(saturation):
253            fSaturation = scalar;//RGB_to_HSV(color, kGetSaturation);
254            fDirty = true;
255            break;
256        case SK_PROPERTY(value):
257            fValue = scalar;//RGB_to_HSV(color, kGetValue);
258            fDirty = true;
259            break;
260        default:
261            SkASSERT(0);
262            return false;
263    }
264    return true;
265}
266