| /* | |
| * 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 : delta / value; | |
| if (choice == kGetSaturation) | |
| return saturation; | |
| SkScalar hue; | |
| if (saturation == 0) | |
| hue = 0; | |
| else { | |
| SkScalar part60 = 60 / 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 != nullptr) | |
| 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 != nullptr); | |
| 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; | |
| } |