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);