[skottie] Path support for paragraph text
In addition to single line (point) text, AE also supports path layout for paragraph text. At a high level, the paragraph box top is mapped to the path (following alignment rules), and each glyph is displaced along its path positioning vector, post orientation. The main difference compared to point text, is that the distance on path is based on the fragment position relative to the paragraph left edge. The paragraph box also plays a role in alignment: left/center/right aligns with path start/mid/end. This includes a tangential optimization: instead of validating cached contour data in each PathInfo::getMatrix() call, we only check once at a higher level (onSync) -- to avoid performing a shape vector comparison for each fragment. Change-Id: I2c31ce3b0a525a3cd2d4525abcf88d5fc943bb6e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/457656 Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Ben Wagner <bungeman@google.com> Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
This commit is contained in:
parent
d616f0b949
commit
132d47c90d
@ -67,7 +67,7 @@ struct TextAdapter::PathInfo {
|
||||
fPathPerpendicular = 0,
|
||||
fPathReverse = 0;
|
||||
|
||||
SkM44 getMatrix(float distance, SkTextUtils::Align alignment) {
|
||||
void updateContourData() {
|
||||
const auto reverse = fPathReverse != 0;
|
||||
|
||||
if (fPath != fCurrentPath || reverse != fCurrentReversed) {
|
||||
@ -88,6 +88,18 @@ struct TextAdapter::PathInfo {
|
||||
// AE paths are always single-contour (no moves allowed).
|
||||
SkASSERT(!iter.next());
|
||||
}
|
||||
}
|
||||
|
||||
float pathLength() const {
|
||||
SkASSERT(fPath == fCurrentPath);
|
||||
SkASSERT((fPathReverse != 0) == fCurrentReversed);
|
||||
|
||||
return fCurrentMeasure ? fCurrentMeasure->length() : 0;
|
||||
}
|
||||
|
||||
SkM44 getMatrix(float distance, SkTextUtils::Align alignment) const {
|
||||
SkASSERT(fPath == fCurrentPath);
|
||||
SkASSERT((fPathReverse != 0) == fCurrentReversed);
|
||||
|
||||
if (!fCurrentMeasure) {
|
||||
return SkM44();
|
||||
@ -95,9 +107,6 @@ struct TextAdapter::PathInfo {
|
||||
|
||||
const auto path_len = fCurrentMeasure->length();
|
||||
|
||||
// Alignment adjustment, relative to path len.
|
||||
distance += path_len * align_factor(alignment);
|
||||
|
||||
// First/last margin adjustment also depends on alignment.
|
||||
switch (alignment) {
|
||||
case SkTextUtils::Align::kLeft_Align: distance += fPathFMargin; break;
|
||||
@ -526,6 +535,11 @@ void TextAdapter::onSync() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the path contour measure, if needed.
|
||||
if (fPathInfo) {
|
||||
fPathInfo->updateContourData();
|
||||
}
|
||||
|
||||
// Seed props from the current text value.
|
||||
TextAnimator::ResolvedProps seed_props;
|
||||
seed_props.fill_color = fText->fFillColor;
|
||||
@ -662,10 +676,24 @@ SkM44 TextAdapter::fragmentMatrix(const TextAnimator::ResolvedProps& props,
|
||||
return SkM44::Translate(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
// When using a text path, the horizontal component determines the position on path.
|
||||
const auto path_distance = pos.x;
|
||||
// "Align" the paragraph box left/center/right to path start/mid/end, respectively.
|
||||
const auto align_offset =
|
||||
align_factor(fText->fHAlign)*(fPathInfo->pathLength() - fText->fBox.width());
|
||||
|
||||
// Path positioning is based on the fragment position relative to the paragraph box
|
||||
// upper-left corner:
|
||||
//
|
||||
// - the horizontal component determines the distance on path
|
||||
//
|
||||
// - the vertical component is post-applied after orienting on path
|
||||
//
|
||||
// Note: in point-text mode, the box adjustments have no effect as fBox is {0,0,0,0}.
|
||||
//
|
||||
const auto rel_pos = SkV2{pos.x, pos.y} - SkV2{fText->fBox.fLeft, fText->fBox.fTop};
|
||||
const auto path_distance = rel_pos.x + align_offset;
|
||||
|
||||
return fPathInfo->getMatrix(path_distance, fText->fHAlign)
|
||||
* SkM44::Translate(0, pos.y, pos.z);
|
||||
* SkM44::Translate(0, rel_pos.y, pos.z);
|
||||
}
|
||||
|
||||
void TextAdapter::pushPropsToFragment(const TextAnimator::ResolvedProps& props,
|
||||
|
1
resources/skottie/skottie-textpath-paragraph-01.json
Normal file
1
resources/skottie/skottie-textpath-paragraph-01.json
Normal file
File diff suppressed because one or more lines are too long
1
resources/skottie/skottie-textpath-paragraph-02.json
Normal file
1
resources/skottie/skottie-textpath-paragraph-02.json
Normal file
File diff suppressed because one or more lines are too long
1
resources/skottie/skottie-textpath-paragraph-03.json
Normal file
1
resources/skottie/skottie-textpath-paragraph-03.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user