blob: eb57d9dad49ed041e0c748d2db95718786357955 [file] [log] [blame]
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkDrawColor.h"
#ifdef SK_DEBUG
#include "SkDisplayList.h"
#endif
#include "SkDrawPaint.h"
#include "SkParse.h"
#include "SkScript.h"
enum HSV_Choice {
kGetHue,
kGetSaturation,
kGetValue
};
static SkScalar RGB_to_HSV(SkColor color, HSV_Choice choice) {
SkScalar red = SkIntToScalar(SkColorGetR(color));
SkScalar green = SkIntToScalar(SkColorGetG(color));
SkScalar blue = SkIntToScalar(SkColorGetB(color));
SkScalar min = SkMinScalar(SkMinScalar(red, green), blue);
SkScalar value = SkMaxScalar(SkMaxScalar(red, green), blue);
if (choice == kGetValue)
return value/255;
SkScalar delta = value - min;
SkScalar saturation = value == 0 ? 0 : SkScalarDiv(delta, value);
if (choice == kGetSaturation)
return saturation;
SkScalar hue;
if (saturation == 0)
hue = 0;
else {
SkScalar part60 = SkScalarDiv(60 * SK_Scalar1, delta);
if (red == value) {
hue = SkScalarMul(green - blue, part60);
if (hue < 0)
hue += 360 * SK_Scalar1;
}
else if (green == value)
hue = 120 * SK_Scalar1 + SkScalarMul(blue - red, part60);
else // blue == value
hue = 240 * SK_Scalar1 + SkScalarMul(red - green, part60);
}
SkASSERT(choice == kGetHue);
return hue;
}
#if defined _WIN32 && _MSC_VER >= 1300 // disable 'red', etc. may be used without having been initialized
#pragma warning ( push )
#pragma warning ( disable : 4701 )
#endif
static SkColor HSV_to_RGB(SkColor color, HSV_Choice choice, SkScalar hsv) {
SkScalar hue = choice == kGetHue ? hsv : RGB_to_HSV(color, kGetHue);
SkScalar saturation = choice == kGetSaturation ? hsv : RGB_to_HSV(color, kGetSaturation);
SkScalar value = choice == kGetValue ? hsv : RGB_to_HSV(color, kGetValue);
value *= 255;
SkScalar red SK_INIT_TO_AVOID_WARNING;
SkScalar green SK_INIT_TO_AVOID_WARNING;
SkScalar blue SK_INIT_TO_AVOID_WARNING;
if (saturation == 0) // color is on black-and-white center line
red = green = blue = value;
else {
//SkScalar fraction = SkScalarMod(hue, 60 * SK_Scalar1);
int sextant = SkScalarFloorToInt(hue / 60);
SkScalar fraction = hue / 60 - SkIntToScalar(sextant);
SkScalar p = SkScalarMul(value , SK_Scalar1 - saturation);
SkScalar q = SkScalarMul(value, SK_Scalar1 - SkScalarMul(saturation, fraction));
SkScalar t = SkScalarMul(value, SK_Scalar1 -
SkScalarMul(saturation, SK_Scalar1 - fraction));
switch (sextant % 6) {
case 0: red = value; green = t; blue = p; break;
case 1: red = q; green = value; blue = p; break;
case 2: red = p; green = value; blue = t; break;
case 3: red = p; green = q; blue = value; break;
case 4: red = t; green = p; blue = value; break;
case 5: red = value; green = p; blue = q; break;
}
}
//used to say SkToU8((U8CPU) red) etc
return SkColorSetARGB(SkColorGetA(color), SkScalarRoundToInt(red),
SkScalarRoundToInt(green), SkScalarRoundToInt(blue));
}
#if defined _WIN32 && _MSC_VER >= 1300
#pragma warning ( pop )
#endif
enum SkDrawColor_Properties {
SK_PROPERTY(alpha),
SK_PROPERTY(blue),
SK_PROPERTY(green),
SK_PROPERTY(hue),
SK_PROPERTY(red),
SK_PROPERTY(saturation),
SK_PROPERTY(value)
};
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkDrawColor::fInfo[] = {
SK_MEMBER_PROPERTY(alpha, Float),
SK_MEMBER_PROPERTY(blue, Float),
SK_MEMBER(color, ARGB),
SK_MEMBER_PROPERTY(green, Float),
SK_MEMBER_PROPERTY(hue, Float),
SK_MEMBER_PROPERTY(red, Float),
SK_MEMBER_PROPERTY(saturation, Float),
SK_MEMBER_PROPERTY(value, Float),
};
#endif
DEFINE_GET_MEMBER(SkDrawColor);
SkDrawColor::SkDrawColor() : fDirty(false) {
color = SK_ColorBLACK;
fHue = fSaturation = fValue = SK_ScalarNaN;
}
bool SkDrawColor::add() {
if (fPaint->color != NULL)
return true; // error (probably color in paint as attribute as well)
fPaint->color = this;
fPaint->fOwnsColor = true;
return false;
}
SkDisplayable* SkDrawColor::deepCopy(SkAnimateMaker*) {
SkDrawColor* copy = new SkDrawColor();
copy->color = color;
copy->fHue = fHue;
copy->fSaturation = fSaturation;
copy->fValue = fValue;
copy->fDirty = fDirty;
return copy;
}
void SkDrawColor::dirty(){
fDirty = true;
}
#ifdef SK_DUMP_ENABLED
void SkDrawColor::dump(SkAnimateMaker* maker) {
dumpBase(maker);
SkDebugf("alpha=\"%d\" red=\"%d\" green=\"%d\" blue=\"%d\" />\n",
SkColorGetA(color)/255, SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
}
#endif
SkColor SkDrawColor::getColor() {
if (fDirty) {
if (SkScalarIsNaN(fValue) == false)
color = HSV_to_RGB(color, kGetValue, fValue);
if (SkScalarIsNaN(fSaturation) == false)
color = HSV_to_RGB(color, kGetSaturation, fSaturation);
if (SkScalarIsNaN(fHue) == false)
color = HSV_to_RGB(color, kGetHue, fHue);
fDirty = false;
}
return color;
}
SkDisplayable* SkDrawColor::getParent() const {
return fPaint;
}
bool SkDrawColor::getProperty(int index, SkScriptValue* value) const {
value->fType = SkType_Float;
SkScalar result;
switch(index) {
case SK_PROPERTY(alpha):
result = SkIntToScalar(SkColorGetA(color)) / 255;
break;
case SK_PROPERTY(blue):
result = SkIntToScalar(SkColorGetB(color));
break;
case SK_PROPERTY(green):
result = SkIntToScalar(SkColorGetG(color));
break;
case SK_PROPERTY(hue):
result = RGB_to_HSV(color, kGetHue);
break;
case SK_PROPERTY(red):
result = SkIntToScalar(SkColorGetR(color));
break;
case SK_PROPERTY(saturation):
result = RGB_to_HSV(color, kGetSaturation);
break;
case SK_PROPERTY(value):
result = RGB_to_HSV(color, kGetValue);
break;
default:
SkASSERT(0);
return false;
}
value->fOperand.fScalar = result;
return true;
}
void SkDrawColor::onEndElement(SkAnimateMaker&) {
fDirty = true;
}
bool SkDrawColor::setParent(SkDisplayable* parent) {
SkASSERT(parent != NULL);
if (parent->getType() == SkType_DrawLinearGradient || parent->getType() == SkType_DrawRadialGradient)
return false;
if (parent->isPaint() == false)
return true;
fPaint = (SkDrawPaint*) parent;
return false;
}
bool SkDrawColor::setProperty(int index, SkScriptValue& value) {
SkASSERT(value.fType == SkType_Float);
SkScalar scalar = value.fOperand.fScalar;
switch (index) {
case SK_PROPERTY(alpha):
uint8_t alpha;
alpha = scalar == SK_Scalar1 ? 255 : SkToU8((U8CPU) (scalar * 256));
color = SkColorSetARGB(alpha, SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
break;
case SK_PROPERTY(blue):
scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color),
SkColorGetG(color), SkToU8((U8CPU) scalar));
break;
case SK_PROPERTY(green):
scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color),
SkToU8((U8CPU) scalar), SkColorGetB(color));
break;
case SK_PROPERTY(hue):
fHue = scalar;//RGB_to_HSV(color, kGetHue);
fDirty = true;
break;
case SK_PROPERTY(red):
scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
color = SkColorSetARGB(SkColorGetA(color), SkToU8((U8CPU) scalar),
SkColorGetG(color), SkColorGetB(color));
break;
case SK_PROPERTY(saturation):
fSaturation = scalar;//RGB_to_HSV(color, kGetSaturation);
fDirty = true;
break;
case SK_PROPERTY(value):
fValue = scalar;//RGB_to_HSV(color, kGetValue);
fDirty = true;
break;
default:
SkASSERT(0);
return false;
}
return true;
}