diff options
Diffstat (limited to 'libs/hwui/CanvasTransform.cpp')
-rw-r--r-- | libs/hwui/CanvasTransform.cpp | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp new file mode 100644 index 000000000000..06e937ab66f4 --- /dev/null +++ b/libs/hwui/CanvasTransform.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CanvasTransform.h" +#include "Properties.h" +#include "utils/Color.h" + +#include <SkColorFilter.h> +#include <SkGradientShader.h> +#include <SkPaint.h> +#include <SkShader.h> +#include <ui/ColorSpace.h> + +#include <algorithm> +#include <cmath> + +#include <log/log.h> +#include <SkHighContrastFilter.h> + +namespace android::uirenderer { + +static SkColor makeLight(SkColor color) { + Lab lab = sRGBToLab(color); + float invertedL = std::min(110 - lab.L, 100.0f); + if (invertedL > lab.L) { + lab.L = invertedL; + return LabToSRGB(lab, SkColorGetA(color)); + } else { + return color; + } +} + +static SkColor makeDark(SkColor color) { + Lab lab = sRGBToLab(color); + float invertedL = std::min(110 - lab.L, 100.0f); + if (invertedL < lab.L) { + lab.L = invertedL; + return LabToSRGB(lab, SkColorGetA(color)); + } else { + return color; + } +} + +static SkColor transformColor(ColorTransform transform, SkColor color) { + switch (transform) { + case ColorTransform::Light: + return makeLight(color); + case ColorTransform::Dark: + return makeDark(color); + default: + return color; + } +} + +static void applyColorTransform(ColorTransform transform, SkPaint& paint) { + if (transform == ColorTransform::None) return; + + SkColor newColor = transformColor(transform, paint.getColor()); + paint.setColor(newColor); + + if (paint.getShader()) { + SkShader::GradientInfo info; + std::array<SkColor, 10> _colorStorage; + std::array<SkScalar, _colorStorage.size()> _offsetStorage; + info.fColorCount = _colorStorage.size(); + info.fColors = _colorStorage.data(); + info.fColorOffsets = _offsetStorage.data(); + SkShader::GradientType type = paint.getShader()->asAGradient(&info); + + if (info.fColorCount <= 10) { + switch (type) { + case SkShader::kLinear_GradientType: + for (int i = 0; i < info.fColorCount; i++) { + info.fColors[i] = transformColor(transform, info.fColors[i]); + } + paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors, + info.fColorOffsets, info.fColorCount, + info.fTileMode, info.fGradientFlags, nullptr)); + break; + default:break; + } + + } + } + + if (paint.getColorFilter()) { + SkBlendMode mode; + SkColor color; + // TODO: LRU this or something to avoid spamming new color mode filters + if (paint.getColorFilter()->asColorMode(&color, &mode)) { + color = transformColor(transform, color); + paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); + } + } +} + +static BitmapPalette paletteForColorHSV(SkColor color) { + float hsv[3]; + SkColorToHSV(color, hsv); + return hsv[2] >= .5f ? BitmapPalette::Light : BitmapPalette::Dark; +} + +static BitmapPalette filterPalette(const SkPaint* paint, BitmapPalette palette) { + if (palette == BitmapPalette::Unknown || !paint || !paint->getColorFilter()) { + return palette; + } + + SkColor color = palette == BitmapPalette::Light ? SK_ColorWHITE : SK_ColorBLACK; + color = paint->getColorFilter()->filterColor(color); + return paletteForColorHSV(color); +} + +bool transformPaint(ColorTransform transform, SkPaint* paint) { + // TODO + applyColorTransform(transform, *paint); + return true; +} + +bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) { + palette = filterPalette(paint, palette); + bool shouldInvert = false; + if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) { + shouldInvert = true; + } + if (palette == BitmapPalette::Dark && transform == ColorTransform::Light) { + shouldInvert = true; + } + if (shouldInvert) { + SkHighContrastConfig config; + config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; + paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter())); + } + return shouldInvert; +} + +}; // namespace android::uirenderer
\ No newline at end of file |