From fbe10255d793bc39974007eb9add8ef65c9f6af6 Mon Sep 17 00:00:00 2001 From: Jinny You Date: Thu, 3 Apr 2025 14:42:07 +0900 Subject: [PATCH] lottie/text: added range selector flags Duplicated text document properties (fill color, stroke color, and stroke width) to the text range. If these properties are not defined in the range selector, ThorVG incorrectly overrides them with default values. The correct behavior is to preserve the original values. The added flags address this issue. Co-Authored-By: Hermet Park --- src/loaders/lottie/tvgLottieBuilder.cpp | 18 +++------------- src/loaders/lottie/tvgLottieModel.h | 28 +++++++++++++++++++++++++ src/loaders/lottie/tvgLottieParser.cpp | 21 +++++++++++++++---- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index b1ec0a78..30f61757 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -1082,25 +1082,13 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo) opacity = (uint8_t)(opacity - f * (opacity - range->style.opacity(frameNo, tween, exps))); shape->opacity(opacity); - auto rangeColor = range->style.fillColor(frameNo, tween, exps); //TODO: use flag to check whether it was really set - if (tvg::equal(f, 1.0f)) color = rangeColor; - else { - color.rgb[0] = tvg::lerp(color.rgb[0], rangeColor.rgb[0], f); - color.rgb[1] = tvg::lerp(color.rgb[1], rangeColor.rgb[1], f); - color.rgb[2] = tvg::lerp(color.rgb[2], rangeColor.rgb[2], f); - } + range->color(frameNo, color, strokeColor, f, tween, exps); + fillOpacity = (uint8_t)(fillOpacity - f * (fillOpacity - range->style.fillOpacity(frameNo, tween, exps))); shape->fill(color.rgb[0], color.rgb[1], color.rgb[2], fillOpacity); - shape->strokeWidth(f * range->style.strokeWidth(frameNo, tween, exps) / scale); + if (range->style.flags.strokeWidth) shape->strokeWidth(f * range->style.strokeWidth(frameNo, tween, exps) / scale); if (shape->strokeWidth() > 0.0f) { - auto rangeColor = range->style.strokeColor(frameNo, tween, exps); //TODO: use flag to check whether it was really set - if (tvg::equal(f, 1.0f)) strokeColor = rangeColor; - else { - strokeColor.rgb[0] = tvg::lerp(strokeColor.rgb[0], rangeColor.rgb[0], f); - strokeColor.rgb[1] = tvg::lerp(strokeColor.rgb[1], rangeColor.rgb[1], f); - strokeColor.rgb[2] = tvg::lerp(strokeColor.rgb[2], rangeColor.rgb[2], f); - } strokeOpacity = (uint8_t)(strokeOpacity - f * (strokeOpacity - range->style.strokeOpacity(frameNo, tween, exps))); shape->strokeFill(strokeColor.rgb[0], strokeColor.rgb[1], strokeColor.rgb[2], strokeOpacity); shape->order(doc.stroke.below); diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index d925916d..4cedd8bd 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -258,6 +258,13 @@ struct LottieTextRange enum Shape : uint8_t { Square = 1, RampUp, RampDown, Triangle, Round, Smooth }; enum Unit : uint8_t { Percent = 1, Index }; + LottieTextRange() + { + style.flags.fillColor = 0; + style.flags.strokeColor = 0; + style.flags.strokeWidth = 0; + } + ~LottieTextRange() { tvg::free(interpolator); @@ -275,6 +282,11 @@ struct LottieTextRange LottieOpacity fillOpacity = 255; LottieOpacity strokeOpacity = 255; LottieOpacity opacity = 255; + struct { + bool fillColor : 1; + bool strokeColor : 1; + bool strokeWidth : 1; + } flags; } style; LottieFloat offset = 0.0f; @@ -292,6 +304,22 @@ struct LottieTextRange bool expressible = false; float factor(float frameNo, float totalLen, float idx); + + void color(float frameNo, RGB24& fillColor, RGB24& strokeColor, float factor, Tween& tween, LottieExpressions* exps) + { + if (style.flags.fillColor) { + auto color = style.fillColor(frameNo, tween, exps); + fillColor.rgb[0] = tvg::lerp(fillColor.rgb[0], color.rgb[0], factor); + fillColor.rgb[1] = tvg::lerp(fillColor.rgb[1], color.rgb[1], factor); + fillColor.rgb[2] = tvg::lerp(fillColor.rgb[2], color.rgb[2], factor); + } + if (style.flags.strokeColor) { + auto color = style.strokeColor(frameNo, tween, exps); + strokeColor.rgb[0] = tvg::lerp(strokeColor.rgb[0], color.rgb[0], factor); + strokeColor.rgb[1] = tvg::lerp(strokeColor.rgb[1], color.rgb[1], factor); + strokeColor.rgb[2] = tvg::lerp(strokeColor.rgb[2], color.rgb[2], factor); + } + } }; diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 9ff2fab6..174349a1 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -1132,7 +1132,8 @@ void LottieParser::parseTextRange(LottieText* text) enterObject(); while (auto key = nextObjectKey()) { if (KEY_AS("t")) selector->expressible = (bool) getInt(); - else if (KEY_AS("xe")) { + else if (KEY_AS("xe")) + { parseProperty(selector->maxEase); selector->interpolator = tvg::malloc(sizeof(LottieInterpolator)); } @@ -1153,10 +1154,22 @@ void LottieParser::parseTextRange(LottieText* text) while (auto key = nextObjectKey()) { if (KEY_AS("t")) parseProperty(selector->style.letterSpacing); else if (KEY_AS("ls")) parseProperty(selector->style.lineSpacing); - else if (KEY_AS("fc")) parseProperty(selector->style.fillColor); + else if (KEY_AS("fc")) + { + parseProperty(selector->style.fillColor); + selector->style.flags.fillColor = true; + } else if (KEY_AS("fo")) parseProperty(selector->style.fillOpacity); - else if (KEY_AS("sw")) parseProperty(selector->style.strokeWidth); - else if (KEY_AS("sc")) parseProperty(selector->style.strokeColor); + else if (KEY_AS("sw")) + { + parseProperty(selector->style.strokeWidth); + selector->style.flags.strokeWidth = true; + } + else if (KEY_AS("sc")) + { + parseProperty(selector->style.strokeColor); + selector->style.flags.strokeColor = true; + } else if (KEY_AS("so")) parseProperty(selector->style.strokeOpacity); else if (KEY_AS("o")) parseProperty(selector->style.opacity); else if (KEY_AS("p")) parseProperty(selector->style.position);