From f3beeb3ab097e59493e6f8d2539a1b9f23e9cea5 Mon Sep 17 00:00:00 2001
From: Hparty <420024556@qq.com>
Date: Tue, 31 Dec 2024 15:05:51 +0800
Subject: [PATCH] Place color premultiplication in RenderContext to ensure that
intermediate process colors are non-premultiplied.
---
resources/apitest/mask_invert_picture_image.svg | 2 +-
resources/apitest/mask_picture_image.svg | 2 +-
src/core/Canvas.cpp | 6 +++---
src/core/FillStyle.h | 2 +-
src/gpu/RenderContext.cpp | 13 +++++++------
test/baseline/version.json | 4 ++--
test/src/SVGExportTest.cpp | 8 ++++----
7 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/resources/apitest/mask_invert_picture_image.svg b/resources/apitest/mask_invert_picture_image.svg
index 6badc53d..0d2248ff 100644
--- a/resources/apitest/mask_invert_picture_image.svg
+++ b/resources/apitest/mask_invert_picture_image.svg
@@ -6,7 +6,7 @@
-
+
diff --git a/resources/apitest/mask_picture_image.svg b/resources/apitest/mask_picture_image.svg
index 5021aeed..d0825d7f 100644
--- a/resources/apitest/mask_picture_image.svg
+++ b/resources/apitest/mask_picture_image.svg
@@ -6,7 +6,7 @@
-
+
diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp
index f9359c55..f99bf4b9 100644
--- a/src/core/Canvas.cpp
+++ b/src/core/Canvas.cpp
@@ -54,10 +54,10 @@ static FillStyle CreateFillStyle(const Paint& paint) {
Color color = {};
if (shader && shader->asColor(&color)) {
color.alpha *= paint.getAlpha();
- style.color = color.premultiply();
+ style.color = color;
shader = nullptr;
} else {
- style.color = paint.getColor().premultiply();
+ style.color = paint.getColor();
}
style.shader = shader;
style.antiAlias = paint.isAntiAlias();
@@ -504,7 +504,7 @@ void Canvas::drawAtlas(std::shared_ptr atlas, const Matrix matrix[], cons
state.matrix.preTranslate(-rect.x(), -rect.y());
auto glyphStyle = style;
if (colors) {
- glyphStyle.color = colors[i].premultiply();
+ glyphStyle.color = colors[i];
}
if (rect == atlasRect) {
drawContext->drawImage(atlas, sampling, state, glyphStyle);
diff --git a/src/core/FillStyle.h b/src/core/FillStyle.h
index 49a73d41..6c4aba88 100644
--- a/src/core/FillStyle.h
+++ b/src/core/FillStyle.h
@@ -33,7 +33,7 @@ class FillStyle {
bool antiAlias = true;
/**
- * The input color, premultiplied, as four floating point values.
+ * The input color, unpremultiplied, as four floating point values.
*/
Color color = Color::White();
diff --git a/src/gpu/RenderContext.cpp b/src/gpu/RenderContext.cpp
index ae99f2a7..87f54df7 100644
--- a/src/gpu/RenderContext.cpp
+++ b/src/gpu/RenderContext.cpp
@@ -99,7 +99,7 @@ void RenderContext::drawRect(const Rect& rect, const MCState& state, const FillS
if (localBounds.isEmpty()) {
return;
}
- auto drawOp = RectDrawOp::Make(style.color, localBounds, state.matrix);
+ auto drawOp = RectDrawOp::Make(style.color.premultiply(), localBounds, state.matrix);
addDrawOp(std::move(drawOp), localBounds, state, style);
}
@@ -111,7 +111,7 @@ bool RenderContext::drawAsClear(const Rect& rect, const MCState& state, const Fi
if (!HasColorOnly(style) || !style.isOpaque() || !state.matrix.rectStaysRect()) {
return false;
}
- auto color = style.color;
+ auto color = style.color.premultiply();
auto bounds = rect;
state.matrix.mapRect(&bounds);
auto [clipRect, useScissor] = getClipRect(state.clip, &bounds);
@@ -136,7 +136,7 @@ void RenderContext::drawRRect(const RRect& rRect, const MCState& state, const Fi
if (localBounds.isEmpty()) {
return;
}
- auto drawOp = RRectDrawOp::Make(style.color, rRect, state.matrix);
+ auto drawOp = RRectDrawOp::Make(style.color.premultiply(), rRect, state.matrix);
addDrawOp(std::move(drawOp), localBounds, state, style);
}
@@ -153,7 +153,8 @@ void RenderContext::drawShape(std::shared_ptr shape, const MCState& state
return;
}
auto clipBounds = getClipBounds(state.clip);
- auto drawOp = ShapeDrawOp::Make(style.color, std::move(shape), state.matrix, clipBounds);
+ auto drawOp =
+ ShapeDrawOp::Make(style.color.premultiply(), std::move(shape), state.matrix, clipBounds);
addDrawOp(std::move(drawOp), localBounds, state, style);
}
@@ -184,7 +185,7 @@ void RenderContext::drawImageRect(std::shared_ptr image, const Rect& rect
if (processor == nullptr) {
return;
}
- auto drawOp = RectDrawOp::Make(style.color, localBounds, state.matrix, uvMatrix);
+ auto drawOp = RectDrawOp::Make(style.color.premultiply(), localBounds, state.matrix, uvMatrix);
drawOp->addColorFP(std::move(processor));
addDrawOp(std::move(drawOp), localBounds, state, style);
}
@@ -224,7 +225,7 @@ void RenderContext::drawGlyphRunList(std::shared_ptr glyphRunList,
if (processor == nullptr) {
return;
}
- auto drawOp = RectDrawOp::Make(style.color, localBounds, state.matrix);
+ auto drawOp = RectDrawOp::Make(style.color.premultiply(), localBounds, state.matrix);
drawOp->addCoverageFP(std::move(processor));
addDrawOp(std::move(drawOp), localBounds, state, style);
}
diff --git a/test/baseline/version.json b/test/baseline/version.json
index 7ceef311..b8556594 100644
--- a/test/baseline/version.json
+++ b/test/baseline/version.json
@@ -20,7 +20,7 @@
"Path_addArc_reversed7": "4802e56",
"Path_addArc_reversed8": "4802e56",
"Path_complex": "e031f25",
- "Picture": "b062b9a",
+ "Picture": "002c391",
"PictureImage": "c28a93c",
"PictureImage_Path": "2212c4e",
"PictureImage_Text": "b062b9a",
@@ -99,7 +99,7 @@
"DropShadowStyle-stroke-behindLayer": "002c391",
"DropShadowStyle-stroke-blur": "002c391",
"DropShadowStyle-stroke-blur-behindLayer": "002c391",
- "DropShadowStyle2": "19dcc4d",
+ "DropShadowStyle2": "7a9c80a",
"InnerShadowStyle": "19dcc4d",
"Layer_hitTestPoint": "50c58e6",
"Layer_hitTestPointNested": "b062b9a",
diff --git a/test/src/SVGExportTest.cpp b/test/src/SVGExportTest.cpp
index 31135de4..82092759 100644
--- a/test/src/SVGExportTest.cpp
+++ b/test/src/SVGExportTest.cpp
@@ -105,13 +105,13 @@ TGFX_TEST(SVGExportTest, OpacityColor) {
std::string compareString =
"";
+ "fill=\"#00F\" fill-opacity=\"0.5\" cx=\"100\" cy=\"100\" r=\"100\"/>";
ContextScope scope;
auto* context = scope.getContext();
ASSERT_TRUE(context != nullptr);
- tgfx::Paint paint;
+ Paint paint;
paint.setColor(Color::Blue());
paint.setAlpha(0.5f);
@@ -131,7 +131,7 @@ TGFX_TEST(SVGExportTest, OpacityColorFile) {
std::string compareString =
"";
+ "fill=\"#00F\" fill-opacity=\"0.5\" cx=\"100\" cy=\"100\" r=\"100\"/>";
ContextScope scope;
auto* context = scope.getContext();
@@ -156,7 +156,7 @@ TGFX_TEST(SVGExportTest, OpacityColorFile) {
auto readStream = Stream::MakeFromFile(path);
EXPECT_TRUE(readStream != nullptr);
- EXPECT_EQ(readStream->size(), 222U);
+ EXPECT_EQ(readStream->size(), 219U);
Buffer buffer(readStream->size());
readStream->read(buffer.data(), buffer.size());
EXPECT_EQ(std::string((char*)buffer.data(), buffer.size()), compareString);