mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
lottie/text: Support text range selector (Phase 1)
This patch provides initial support for the text range selector. Full support will be added gradually in subsequent steps. This is the first step. Text range selector with following properties: 1. Text Range Selector (Units) 2. Text Style - Fill Color - Fill Opacity - Stroke Color - Stroke Width - Stroke Opacity - Opacity - Rotation - Position - Scale
This commit is contained in:
parent
318c76119a
commit
b24e876a67
3 changed files with 121 additions and 6 deletions
|
@ -1057,12 +1057,13 @@ static void _updateText(LottieLayer* layer, float frameNo)
|
|||
if (!p || !text->font) return;
|
||||
|
||||
auto scale = doc.size * 0.01f;
|
||||
float spacing = text->spacing(frameNo) / scale;
|
||||
Point cursor = {0.0f, 0.0f};
|
||||
auto scene = Scene::gen();
|
||||
int line = 0;
|
||||
|
||||
//text string
|
||||
int idx = 0;
|
||||
auto totalChars = strlen(p);
|
||||
while (true) {
|
||||
//TODO: remove nested scenes.
|
||||
//end of text, new line of the cursor position
|
||||
|
@ -1114,19 +1115,60 @@ static void _updateText(LottieLayer* layer, float frameNo)
|
|||
shape->stroke(doc.stroke.color.rgb[0], doc.stroke.color.rgb[1], doc.stroke.color.rgb[2]);
|
||||
}
|
||||
|
||||
//text range process
|
||||
for (auto s = text->ranges.begin(); s < text->ranges.end(); ++s) {
|
||||
float divisor = (*s)->rangeUnit == LottieTextRange::Unit::Percent ? (100.0f / totalChars) : 1;
|
||||
auto offset = (*s)->offset(frameNo) / divisor;
|
||||
auto start = round((*s)->start(frameNo) / divisor) + offset;
|
||||
auto end = round((*s)->end(frameNo) / divisor) + offset;
|
||||
|
||||
if (start > end) std::swap(start, end);
|
||||
|
||||
if (idx < start || idx >= end) continue;
|
||||
auto matrix = PP(shape.get())->transform();
|
||||
|
||||
shape->opacity((*s)->style.opacity(frameNo));
|
||||
|
||||
auto color = (*s)->style.fillColor(frameNo);
|
||||
shape->fill(color.rgb[0], color.rgb[1], color.rgb[2], (*s)->style.fillOpacity(frameNo));
|
||||
|
||||
mathRotate(matrix, (*s)->style.rotation(frameNo));
|
||||
|
||||
auto glyphScale = (*s)->style.scale(frameNo) * 0.01f;
|
||||
mathScale(matrix, glyphScale.x, glyphScale.y);
|
||||
|
||||
auto position = (*s)->style.position(frameNo);
|
||||
mathTranslate(matrix, position.x, position.y);
|
||||
|
||||
shape->transform(*matrix);
|
||||
|
||||
if (doc.stroke.render) {
|
||||
auto strokeColor = (*s)->style.strokeColor(frameNo);
|
||||
|
||||
shape->stroke((*s)->style.strokeWidth(frameNo) / scale);
|
||||
shape->stroke(strokeColor.rgb[0], strokeColor.rgb[1], strokeColor.rgb[2], (*s)->style.strokeOpacity(frameNo));
|
||||
}
|
||||
|
||||
cursor.x += (*s)->style.letterSpacing(frameNo);
|
||||
}
|
||||
|
||||
scene->push(std::move(shape));
|
||||
|
||||
p += glyph->len;
|
||||
idx += glyph->len;
|
||||
|
||||
//advance the cursor position horizontally
|
||||
cursor.x += glyph->width + spacing + doc.tracking;
|
||||
cursor.x += glyph->width + doc.tracking;
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) ++p;
|
||||
if (!found) {
|
||||
++p;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,43 @@ struct LottieGlyph
|
|||
};
|
||||
|
||||
|
||||
struct LottieTextStyle
|
||||
{
|
||||
LottieColor fillColor = RGB24{255, 255, 255};
|
||||
LottieColor strokeColor = RGB24{255, 255, 255};
|
||||
LottiePosition position = Point{0, 0};
|
||||
LottiePoint scale = Point{100, 100};
|
||||
LottieFloat letterSpacing = 0.0f;
|
||||
LottieFloat strokeWidth = 0.0f;
|
||||
LottieFloat rotation = 0.0f;
|
||||
LottieOpacity fillOpacity = 255;
|
||||
LottieOpacity strokeOpacity = 255;
|
||||
LottieOpacity opacity = 255;
|
||||
};
|
||||
|
||||
|
||||
struct LottieTextRange
|
||||
{
|
||||
enum Based : uint8_t { Chars = 1, CharsExcludingSpaces, Words, Lines };
|
||||
enum Shape : uint8_t { Square = 1, RampUp, RampDown, Triangle, Round, Smooth };
|
||||
enum Unit : uint8_t { Percent = 1, Index };
|
||||
|
||||
LottieTextStyle style;
|
||||
LottieFloat offset = 0.0f;
|
||||
LottieFloat maxEase = 0.0f;
|
||||
LottieFloat minEase = 0.0f;
|
||||
LottieFloat maxAmount = 0.0f;
|
||||
LottieFloat smoothness = 0.0f;
|
||||
LottieFloat start = 0.0f;
|
||||
LottieFloat end = 0.0f;
|
||||
Based based = Chars;
|
||||
Shape shape = Square;
|
||||
Unit rangeUnit = Percent;
|
||||
bool expressible = false;
|
||||
bool randomize = false;
|
||||
};
|
||||
|
||||
|
||||
struct LottieFont
|
||||
{
|
||||
enum Origin : uint8_t { Local = 0, CssURL, ScriptURL, FontURL, Embedded };
|
||||
|
@ -195,7 +232,12 @@ struct LottieText : LottieObject
|
|||
|
||||
LottieTextDoc doc;
|
||||
LottieFont* font;
|
||||
LottieFloat spacing = 0.0f; //letter spacing
|
||||
Array<LottieTextRange*> ranges;
|
||||
|
||||
~LottieText()
|
||||
{
|
||||
for (auto r = ranges.begin(); r < ranges.end(); ++r) delete(*r);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1120,15 +1120,46 @@ void LottieParser::parseTextRange(LottieText* text)
|
|||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
||||
auto selector = new LottieTextRange;
|
||||
|
||||
while (auto key = nextObjectKey()) {
|
||||
if (KEY_AS("a")) { //text style
|
||||
if (KEY_AS("s")) { // text range selector
|
||||
enterObject();
|
||||
while (auto key = nextObjectKey()) {
|
||||
if (KEY_AS("t")) parseProperty<LottieProperty::Type::Float>(text->spacing);
|
||||
if (KEY_AS("t")) selector->expressible = (bool) getInt();
|
||||
else if (KEY_AS("xe")) parseProperty<LottieProperty::Type::Float>(selector->maxEase);
|
||||
else if (KEY_AS("ne")) parseProperty<LottieProperty::Type::Float>(selector->minEase);
|
||||
else if (KEY_AS("a")) parseProperty<LottieProperty::Type::Float>(selector->maxAmount);
|
||||
else if (KEY_AS("b")) selector->based = (LottieTextRange::Based) getInt();
|
||||
else if (KEY_AS("rn")) selector->randomize = (bool) getInt();
|
||||
else if (KEY_AS("sh")) selector->shape = (LottieTextRange::Shape) getInt();
|
||||
else if (KEY_AS("o")) parseProperty<LottieProperty::Type::Float>(selector->offset);
|
||||
else if (KEY_AS("r")) selector->rangeUnit = (LottieTextRange::Unit) getInt();
|
||||
else if (KEY_AS("sm")) parseProperty<LottieProperty::Type::Float>(selector->smoothness);
|
||||
else if (KEY_AS("s")) parseProperty<LottieProperty::Type::Float>(selector->start);
|
||||
else if (KEY_AS("e")) parseProperty<LottieProperty::Type::Float>(selector->end);
|
||||
else skip(key);
|
||||
}
|
||||
} else if (KEY_AS("a")) { // text style
|
||||
enterObject();
|
||||
while (auto key = nextObjectKey()) {
|
||||
if (KEY_AS("t")) parseProperty<LottieProperty::Type::Float>(selector->style.letterSpacing);
|
||||
else if (KEY_AS("fc")) parseProperty<LottieProperty::Type::Color>(selector->style.fillColor);
|
||||
else if (KEY_AS("fo")) parseProperty<LottieProperty::Type::Color>(selector->style.fillOpacity);
|
||||
else if (KEY_AS("sw")) parseProperty<LottieProperty::Type::Float>(selector->style.strokeWidth);
|
||||
else if (KEY_AS("sc")) parseProperty<LottieProperty::Type::Color>(selector->style.strokeColor);
|
||||
else if (KEY_AS("so")) parseProperty<LottieProperty::Type::Opacity>(selector->style.strokeOpacity);
|
||||
else if (KEY_AS("o")) parseProperty<LottieProperty::Type::Opacity>(selector->style.opacity);
|
||||
else if (KEY_AS("p")) parseProperty<LottieProperty::Type::Position>(selector->style.position);
|
||||
else if (KEY_AS("s")) parseProperty<LottieProperty::Type::Position>(selector->style.scale);
|
||||
else if (KEY_AS("r")) parseProperty<LottieProperty::Type::Float>(selector->style.rotation);
|
||||
else skip(key);
|
||||
}
|
||||
} else skip(key);
|
||||
}
|
||||
|
||||
text->ranges.push(selector);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue