134 lines
5.2 KiB
C++
134 lines
5.2 KiB
C++
/*
|
|
* Copyright (C) 2003-2020 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "ColorBlending.h"
|
|
|
|
#include "AnimationUtilities.h"
|
|
#include "Color.h"
|
|
|
|
namespace WebCore {
|
|
|
|
Color blendSourceOver(const Color& backdrop, const Color& source)
|
|
{
|
|
if (!backdrop.isVisible() || source.isOpaque())
|
|
return source;
|
|
|
|
if (!source.isVisible())
|
|
return backdrop;
|
|
|
|
auto [backdropR, backdropG, backdropB, backdropA] = backdrop.toSRGBALossy<uint8_t>();
|
|
auto [sourceR, sourceG, sourceB, sourceA] = source.toSRGBALossy<uint8_t>();
|
|
|
|
int d = 0xFF * (backdropA + sourceA) - backdropA * sourceA;
|
|
int a = d / 0xFF;
|
|
int r = (backdropR * backdropA * (0xFF - sourceA) + 0xFF * sourceA * sourceR) / d;
|
|
int g = (backdropG * backdropA * (0xFF - sourceA) + 0xFF * sourceA * sourceG) / d;
|
|
int b = (backdropB * backdropA * (0xFF - sourceA) + 0xFF * sourceA * sourceB) / d;
|
|
|
|
return makeFromComponentsClamping<SRGBA<uint8_t>>(r, g, b, a);
|
|
}
|
|
|
|
Color blendWithWhite(const Color& color)
|
|
{
|
|
constexpr int startAlpha = 153; // 60%
|
|
constexpr int endAlpha = 204; // 80%;
|
|
constexpr int alphaIncrement = 17;
|
|
|
|
auto blendComponent = [](int c, int a) -> int {
|
|
float alpha = a / 255.0f;
|
|
int whiteBlend = 255 - a;
|
|
c -= whiteBlend;
|
|
return static_cast<int>(c / alpha);
|
|
};
|
|
|
|
// If the color contains alpha already, we leave it alone.
|
|
if (!color.isOpaque())
|
|
return color;
|
|
|
|
auto [existingR, existingG, existingB, existingAlpha] = color.toSRGBALossy<uint8_t>();
|
|
|
|
SRGBA<uint8_t> result;
|
|
for (int alpha = startAlpha; alpha <= endAlpha; alpha += alphaIncrement) {
|
|
// We have a solid color. Convert to an equivalent color that looks the same when blended with white
|
|
// at the current alpha. Try using less transparency if the numbers end up being negative.
|
|
int r = blendComponent(existingR, alpha);
|
|
int g = blendComponent(existingG, alpha);
|
|
int b = blendComponent(existingB, alpha);
|
|
|
|
result = makeFromComponentsClamping<SRGBA<uint8_t>>(r, g, b, alpha);
|
|
|
|
if (r >= 0 && g >= 0 && b >= 0)
|
|
break;
|
|
}
|
|
|
|
// FIXME: Why is preserving the semantic bit desired and/or correct here?
|
|
if (color.isSemantic())
|
|
return { result, Color::Flags::Semantic };
|
|
return result;
|
|
}
|
|
|
|
Color blend(const Color& from, const Color& to, const BlendingContext& context)
|
|
{
|
|
// FIXME: ExtendedColor - needs to handle color spaces.
|
|
// We need to preserve the state of the valid flag at the end of the animation
|
|
if (context.progress == 1 && !to.isValid())
|
|
return { };
|
|
|
|
auto premultipliedFrom = premultiplied(from.toColorTypeLossy<SRGBA<float>>());
|
|
auto premultipliedTo = premultiplied(to.toColorTypeLossy<SRGBA<float>>());
|
|
|
|
auto premultipliedBlended = makeFromComponentsClamping<SRGBA<float>>(
|
|
WebCore::blend(premultipliedFrom.red, premultipliedTo.red, context),
|
|
WebCore::blend(premultipliedFrom.green, premultipliedTo.green, context),
|
|
WebCore::blend(premultipliedFrom.blue, premultipliedTo.blue, context),
|
|
WebCore::blend(premultipliedFrom.alpha, premultipliedTo.alpha, context)
|
|
);
|
|
|
|
return convertColor<SRGBA<uint8_t>>(unpremultiplied(premultipliedBlended));
|
|
}
|
|
|
|
Color blendWithoutPremultiply(const Color& from, const Color& to, const BlendingContext& context)
|
|
{
|
|
// FIXME: ExtendedColor - needs to handle color spaces.
|
|
// We need to preserve the state of the valid flag at the end of the animation
|
|
if (context.progress == 1 && !to.isValid())
|
|
return { };
|
|
|
|
auto fromSRGB = from.toColorTypeLossy<SRGBA<float>>();
|
|
auto toSRGB = to.toColorTypeLossy<SRGBA<float>>();
|
|
|
|
auto blended = makeFromComponentsClamping<SRGBA<float>>(
|
|
WebCore::blend(fromSRGB.red, toSRGB.red, context),
|
|
WebCore::blend(fromSRGB.green, toSRGB.green, context),
|
|
WebCore::blend(fromSRGB.blue, toSRGB.blue, context),
|
|
WebCore::blend(fromSRGB.alpha, toSRGB.alpha, context)
|
|
);
|
|
|
|
return convertColor<SRGBA<uint8_t>>(blended);
|
|
}
|
|
|
|
} // namespace WebCore
|