1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "CanvasTransform.h" 18 #include "Properties.h" 19 #include "utils/Color.h" 20 21 #include <SkColorFilter.h> 22 #include <SkGradientShader.h> 23 #include <SkPaint.h> 24 #include <SkShader.h> 25 #include <ui/ColorSpace.h> 26 27 #include <algorithm> 28 #include <cmath> 29 30 #include <log/log.h> 31 #include <SkHighContrastFilter.h> 32 33 namespace android::uirenderer { 34 35 static SkColor makeLight(SkColor color) { 36 Lab lab = sRGBToLab(color); 37 float invertedL = std::min(110 - lab.L, 100.0f); 38 if (invertedL > lab.L) { 39 lab.L = invertedL; 40 return LabToSRGB(lab, SkColorGetA(color)); 41 } else { 42 return color; 43 } 44 } 45 46 static SkColor makeDark(SkColor color) { 47 Lab lab = sRGBToLab(color); 48 float invertedL = std::min(110 - lab.L, 100.0f); 49 if (invertedL < lab.L) { 50 lab.L = invertedL; 51 return LabToSRGB(lab, SkColorGetA(color)); 52 } else { 53 return color; 54 } 55 } 56 57 static SkColor transformColor(ColorTransform transform, SkColor color) { 58 switch (transform) { 59 case ColorTransform::Light: 60 return makeLight(color); 61 case ColorTransform::Dark: 62 return makeDark(color); 63 default: 64 return color; 65 } 66 } 67 68 static void applyColorTransform(ColorTransform transform, SkPaint& paint) { 69 if (transform == ColorTransform::None) return; 70 71 SkColor newColor = transformColor(transform, paint.getColor()); 72 paint.setColor(newColor); 73 74 if (paint.getShader()) { 75 SkShader::GradientInfo info; 76 std::array<SkColor, 10> _colorStorage; 77 std::array<SkScalar, _colorStorage.size()> _offsetStorage; 78 info.fColorCount = _colorStorage.size(); 79 info.fColors = _colorStorage.data(); 80 info.fColorOffsets = _offsetStorage.data(); 81 SkShader::GradientType type = paint.getShader()->asAGradient(&info); 82 83 if (info.fColorCount <= 10) { 84 switch (type) { 85 case SkShader::kLinear_GradientType: 86 for (int i = 0; i < info.fColorCount; i++) { 87 info.fColors[i] = transformColor(transform, info.fColors[i]); 88 } 89 paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors, 90 info.fColorOffsets, info.fColorCount, 91 info.fTileMode, info.fGradientFlags, nullptr)); 92 break; 93 default:break; 94 } 95 96 } 97 } 98 99 if (paint.getColorFilter()) { 100 SkBlendMode mode; 101 SkColor color; 102 // TODO: LRU this or something to avoid spamming new color mode filters 103 if (paint.getColorFilter()->asColorMode(&color, &mode)) { 104 color = transformColor(transform, color); 105 paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); 106 } 107 } 108 } 109 110 static BitmapPalette paletteForColorHSV(SkColor color) { 111 float hsv[3]; 112 SkColorToHSV(color, hsv); 113 return hsv[2] >= .5f ? BitmapPalette::Light : BitmapPalette::Dark; 114 } 115 116 static BitmapPalette filterPalette(const SkPaint* paint, BitmapPalette palette) { 117 if (palette == BitmapPalette::Unknown || !paint || !paint->getColorFilter()) { 118 return palette; 119 } 120 121 SkColor color = palette == BitmapPalette::Light ? SK_ColorWHITE : SK_ColorBLACK; 122 color = paint->getColorFilter()->filterColor(color); 123 return paletteForColorHSV(color); 124 } 125 126 bool transformPaint(ColorTransform transform, SkPaint* paint) { 127 // TODO 128 applyColorTransform(transform, *paint); 129 return true; 130 } 131 132 bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) { 133 palette = filterPalette(paint, palette); 134 bool shouldInvert = false; 135 if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) { 136 shouldInvert = true; 137 } 138 if (palette == BitmapPalette::Dark && transform == ColorTransform::Light) { 139 shouldInvert = true; 140 } 141 if (shouldInvert) { 142 SkHighContrastConfig config; 143 config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; 144 paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter())); 145 } 146 return shouldInvert; 147 } 148 149 } // namespace android::uirenderer 150