/* * 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; }