From 284298445b900bbba09beb4673e9d055584e1f81 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 5 Oct 2021 01:17:30 +0200 Subject: [PATCH] sw_engine: border cases for gradients According to the svg standard, in a case when 'x1==x2 and y1==y2' for a linear gradient or when 'r==0' for a radial gradient, the area should be painted as a single color - the last gradient stop color. --- meson.build | 6 +++++ src/lib/sw_engine/tvgSwRenderer.cpp | 35 +++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 2cd27e90..9b8f8a14 100644 --- a/meson.build +++ b/meson.build @@ -6,9 +6,15 @@ project('thorvg', config_h = configuration_data() +if host_machine.system() != 'windows' add_project_arguments('-DEXAMPLE_DIR="@0@/src/examples/images"'.format(meson.current_source_dir()), '-DTEST_DIR="@0@/test/images"'.format(meson.current_source_dir()), language : 'cpp') +else +add_project_arguments('-DEXAMPLE_DIR="@0@\src\examples\images"'.format(meson.current_source_dir()), + '-DTEST_DIR="@0@\test\images"'.format(meson.current_source_dir()), + language : 'cpp') +endif config_h.set_quoted('THORVG_VERSION_STRING', meson.project_version()) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8d5caadf..32f28ee8 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ #include +#include #include "tvgSwCommon.h" #include "tvgTaskScheduler.h" #include "tvgSwRenderer.h" @@ -224,6 +225,18 @@ static void _termEngine() } +bool _monochromaticGradient(const Fill* fill) +{ + float x1, x2, y1, y2, r; + + if ((fill->id() == TVG_CLASS_ID_LINEAR && static_cast(fill)->linear(&x1, &y1, &x2, &y2) == Result::Success && + fabsf(x1 - x2) < FLT_EPSILON && fabsf(y1 - y2) < FLT_EPSILON) || + (fill->id() == TVG_CLASS_ID_RADIAL && static_cast(fill)->radial(nullptr, nullptr, &r) == Result::Success && + r < FLT_EPSILON)) return true; + + return false; +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -364,7 +377,16 @@ bool SwRenderer::renderShape(RenderData data) uint8_t r, g, b, a; if (auto fill = task->sdata->fill()) { - rasterGradientShape(surface, &task->shape, fill->id()); + if (_monochromaticGradient(fill)) { + const Fill::ColorStop* stop; + auto cnt = fill->colorStops(&stop); + if (cnt > 0 && stop) { + a = static_cast((opacity * static_cast(stop[cnt - 1].a)) / 255); + if (a > 0) rasterSolidShape(surface, &task->shape, stop[cnt - 1].r, stop[cnt - 1].g, stop[cnt - 1].b, a); + } + } else { + rasterGradientShape(surface, &task->shape, fill->id()); + } } else { task->sdata->fillColor(&r, &g, &b, &a); a = static_cast((opacity * (uint32_t) a) / 255); @@ -372,7 +394,16 @@ bool SwRenderer::renderShape(RenderData data) } if (auto strokeFill = task->sdata->strokeFill()) { - rasterGradientStroke(surface, &task->shape, strokeFill->id()); + if (_monochromaticGradient(strokeFill)) { + const Fill::ColorStop* stop; + auto cnt = strokeFill->colorStops(&stop); + if (cnt > 0 && stop) { + a = static_cast((opacity * static_cast(stop[cnt - 1].a)) / 255); + if (a > 0) rasterStroke(surface, &task->shape, stop[cnt - 1].r, stop[cnt - 1].g, stop[cnt - 1].b, a); + } + } else { + rasterGradientStroke(surface, &task->shape, strokeFill->id()); + } } else { if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) { a = static_cast((opacity * (uint32_t) a) / 255);