#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 clampToComponentBytes<SRGBA>(r, g, b, a);
}
Color blendWithWhite(const Color& color)
{
constexpr int startAlpha = 153; constexpr int endAlpha = 204; 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 (!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) {
int r = blendComponent(existingR, alpha);
int g = blendComponent(existingG, alpha);
int b = blendComponent(existingB, alpha);
result = clampToComponentBytes<SRGBA>(r, g, b, alpha);
if (r >= 0 && g >= 0 && b >= 0)
break;
}
if (color.isSemantic())
return Color(result, Color::Semantic);
return result;
}
Color blend(const Color& from, const Color& to, double progress)
{
if (progress == 1 && !to.isValid())
return { };
auto premultipliedFrom = premultipliedCeiling(from.toSRGBALossy<uint8_t>());
auto premultipliedTo = premultipliedCeiling(to.toSRGBALossy<uint8_t>());
auto premultipliedBlended = clampToComponentBytes<SRGBA>(
WebCore::blend(premultipliedFrom.red, premultipliedTo.red, progress),
WebCore::blend(premultipliedFrom.green, premultipliedTo.green, progress),
WebCore::blend(premultipliedFrom.blue, premultipliedTo.blue, progress),
WebCore::blend(premultipliedFrom.alpha, premultipliedTo.alpha, progress)
);
return unpremultiplied(premultipliedBlended);
}
Color blendWithoutPremultiply(const Color& from, const Color& to, double progress)
{
if (progress == 1 && !to.isValid())
return { };
auto fromSRGB = from.toSRGBALossy<uint8_t>();
auto toSRGB = to.toSRGBALossy<uint8_t>();
return clampToComponentBytes<SRGBA>(
WebCore::blend(fromSRGB.red, toSRGB.red, progress),
WebCore::blend(fromSRGB.green, toSRGB.green, progress),
WebCore::blend(fromSRGB.blue, toSRGB.blue, progress),
WebCore::blend(fromSRGB.alpha, toSRGB.alpha, progress)
);
}
}