Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Member Functions | Protected Member Functions | List of all members
skottie::internal::TextAdapter Class Referencefinal

#include <TextAdapter.h>

Inheritance diagram for skottie::internal::TextAdapter:
skottie::internal::AnimatablePropertyContainer skottie::internal::Animator SkRefCnt SkRefCntBase

Classes

class  GlyphDecoratorNode
 
struct  PathInfo
 

Public Member Functions

 ~TextAdapter () override
 
const sk_sp< sksg::Group > & node () const
 
const TextValuegetText () const
 
void setText (const TextValue &)
 
- Public Member Functions inherited from skottie::internal::AnimatablePropertyContainer
template<typename T >
bool bind (const AnimationBuilder &, const skjson::ObjectValue *, T *)
 
template<typename T >
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jobject, T &v)
 
bool bindAutoOrientable (const AnimationBuilder &abuilder, const skjson::ObjectValue *jobject, SkV2 *v, float *orientation)
 
bool isStatic () const
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, ScalarValue *v)
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, ShapeValue *v)
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, TextValue *v)
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, Vec2Value *v)
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, VectorValue *v)
 
template<>
bool bind (const AnimationBuilder &abuilder, const skjson::ObjectValue *jprop, ColorValue *v)
 
- Public Member Functions inherited from skottie::internal::Animator
StateChanged seek (float t)
 
- Public Member Functions inherited from SkRefCntBase
 SkRefCntBase ()
 
virtual ~SkRefCntBase ()
 
bool unique () const
 
void ref () const
 
void unref () const
 

Static Public Member Functions

static sk_sp< TextAdapterMake (const skjson::ObjectValue &, const AnimationBuilder *, sk_sp< SkFontMgr >, sk_sp< CustomFont::GlyphCompMapper >, sk_sp< Logger >, sk_sp<::SkShapers::Factory >)
 

Protected Member Functions

void onSync () override
 
- Protected Member Functions inherited from skottie::internal::AnimatablePropertyContainer
void shrink_to_fit ()
 
void attachDiscardableAdapter (sk_sp< AnimatablePropertyContainer >)
 
- Protected Member Functions inherited from skottie::internal::Animator
 Animator ()=default
 

Additional Inherited Members

- Public Types inherited from skottie::internal::Animator
using StateChanged = bool
 

Detailed Description

Definition at line 47 of file TextAdapter.h.

Constructor & Destructor Documentation

◆ ~TextAdapter()

skottie::internal::TextAdapter::~TextAdapter ( )
overridedefault

Member Function Documentation

◆ getText()

const TextValue & skottie::internal::TextAdapter::getText ( ) const
inline

Definition at line 60 of file TextAdapter.h.

60{ return fText.fCurrentValue; }

◆ Make()

sk_sp< TextAdapter > skottie::internal::TextAdapter::Make ( const skjson::ObjectValue jlayer,
const AnimationBuilder abuilder,
sk_sp< SkFontMgr fontmgr,
sk_sp< CustomFont::GlyphCompMapper custom_glyph_mapper,
sk_sp< Logger logger,
sk_sp<::SkShapers::Factory factory 
)
static

Definition at line 297 of file TextAdapter.cpp.

302 {
303 // General text node format:
304 // "t": {
305 // "a": [], // animators (see TextAnimator)
306 // "d": {
307 // "k": [
308 // {
309 // "s": {
310 // "f": "Roboto-Regular",
311 // "fc": [
312 // 0.42,
313 // 0.15,
314 // 0.15
315 // ],
316 // "j": 1,
317 // "lh": 60,
318 // "ls": 0,
319 // "s": 50,
320 // "t": "text align right",
321 // "tr": 0
322 // },
323 // "t": 0
324 // }
325 // ],
326 // "sid": "optionalSlotID"
327 // },
328 // "m": { // more options
329 // "g": 1, // Anchor Point Grouping
330 // "a": {...} // Grouping Alignment
331 // },
332 // "p": { // path options
333 // "a": 0, // force alignment
334 // "f": {}, // first margin
335 // "l": {}, // last margin
336 // "m": 1, // mask index
337 // "p": 1, // perpendicular
338 // "r": 0 // reverse path
339 // }
340
341 // },
342
343 const skjson::ObjectValue* jt = jlayer["t"];
344 const skjson::ObjectValue* jd = jt ? static_cast<const skjson::ObjectValue*>((*jt)["d"])
345 : nullptr;
346 if (!jd) {
347 abuilder->log(Logger::Level::kError, &jlayer, "Invalid text layer.");
348 return nullptr;
349 }
350
351 // "More options"
352 const skjson::ObjectValue* jm = (*jt)["m"];
353 static constexpr AnchorPointGrouping gGroupingMap[] = {
354 AnchorPointGrouping::kCharacter, // 'g': 1
355 AnchorPointGrouping::kWord, // 'g': 2
356 AnchorPointGrouping::kLine, // 'g': 3
357 AnchorPointGrouping::kAll, // 'g': 4
358 };
359 const auto apg = jm
360 ? SkTPin<int>(ParseDefault<int>((*jm)["g"], 1), 1, std::size(gGroupingMap))
361 : 1;
362
363 auto adapter = sk_sp<TextAdapter>(new TextAdapter(std::move(fontmgr),
364 std::move(custom_glyph_mapper),
365 std::move(logger),
366 std::move(factory),
367 gGroupingMap[SkToSizeT(apg - 1)]));
368
369 adapter->bind(*abuilder, jd, adapter->fText.fCurrentValue);
370 if (jm) {
371 adapter->bind(*abuilder, (*jm)["a"], adapter->fGroupingAlignment);
372 }
373
374 // Animators
375 if (const skjson::ArrayValue* janimators = (*jt)["a"]) {
376 adapter->fAnimators.reserve(janimators->size());
377
378 for (const skjson::ObjectValue* janimator : *janimators) {
379 if (auto animator = TextAnimator::Make(janimator, abuilder, adapter.get())) {
380 adapter->fHasBlurAnimator |= animator->hasBlur();
381 adapter->fRequiresAnchorPoint |= animator->requiresAnchorPoint();
382 adapter->fRequiresLineAdjustments |= animator->requiresLineAdjustments();
383
384 adapter->fAnimators.push_back(std::move(animator));
385 }
386 }
387 }
388
389 // Optional text path
390 const auto attach_path = [&](const skjson::ObjectValue* jpath) -> std::unique_ptr<PathInfo> {
391 if (!jpath) {
392 return nullptr;
393 }
394
395 // the actual path is identified as an index in the layer mask stack
396 const auto mask_index =
397 ParseDefault<size_t>((*jpath)["m"], std::numeric_limits<size_t>::max());
398 const skjson::ArrayValue* jmasks = jlayer["masksProperties"];
399 if (!jmasks || mask_index >= jmasks->size()) {
400 return nullptr;
401 }
402
403 const skjson::ObjectValue* mask = (*jmasks)[mask_index];
404 if (!mask) {
405 return nullptr;
406 }
407
408 auto pinfo = std::make_unique<PathInfo>();
409 adapter->bind(*abuilder, (*mask)["pt"], &pinfo->fPath);
410 adapter->bind(*abuilder, (*jpath)["f"], &pinfo->fPathFMargin);
411 adapter->bind(*abuilder, (*jpath)["l"], &pinfo->fPathLMargin);
412 adapter->bind(*abuilder, (*jpath)["p"], &pinfo->fPathPerpendicular);
413 adapter->bind(*abuilder, (*jpath)["r"], &pinfo->fPathReverse);
414
415 // TODO: force align support
416
417 // Historically, these used to be exported as static properties.
418 // Attempt parsing both ways, for backward compat.
419 skottie::Parse((*jpath)["p"], &pinfo->fPathPerpendicular);
420 skottie::Parse((*jpath)["r"], &pinfo->fPathReverse);
421
422 // Path positioning requires anchor point info.
423 adapter->fRequiresAnchorPoint = true;
424
425 return pinfo;
426 };
427
428 adapter->fPathInfo = attach_path((*jt)["p"]);
429 abuilder->dispatchTextProperty(adapter, jd);
430
431 return adapter;
432}
constexpr size_t SkToSizeT(S x)
Definition SkTo.h:31
size_t size() const
Definition SkJSON.h:262
static sk_sp< TextAnimator > Make(const skjson::ObjectValue *, const AnimationBuilder *, AnimatablePropertyContainer *acontainer)
bool Parse(const skjson::Value &, T *)

◆ node()

const sk_sp< sksg::Group > & skottie::internal::TextAdapter::node ( ) const
inline

Definition at line 58 of file TextAdapter.h.

58{ return fRoot; }

◆ onSync()

void skottie::internal::TextAdapter::onSync ( )
overrideprotectedvirtual

Implements skottie::internal::AnimatablePropertyContainer.

Definition at line 774 of file TextAdapter.cpp.

774 {
775 if (!fText->fHasFill && !fText->fHasStroke) {
776 return;
777 }
778
779 if (fText.hasChanged()) {
780 this->reshape();
781 }
782
783 if (fFragments.empty()) {
784 return;
785 }
786
787 // Update the path contour measure, if needed.
788 if (fPathInfo) {
789 fPathInfo->updateContourData();
790 }
791
792 // Seed props from the current text value.
793 TextAnimator::ResolvedProps seed_props;
794 seed_props.fill_color = fText->fFillColor;
795 seed_props.stroke_color = fText->fStrokeColor;
796 seed_props.stroke_width = fText->fStrokeWidth;
797
799 buf.resize(fFragments.size(), { seed_props, 0 });
800
801 // Apply all animators to the modulator buffer.
802 for (const auto& animator : fAnimators) {
803 animator->modulateProps(fMaps, buf);
804 }
805
806 const TextAnimator::DomainMap* grouping_domain = nullptr;
807 switch (fAnchorPointGrouping) {
808 // for word/line grouping, we rely on domain map info
809 case AnchorPointGrouping::kWord: grouping_domain = &fMaps.fWordsMap; break;
810 case AnchorPointGrouping::kLine: grouping_domain = &fMaps.fLinesMap; break;
811 // remaining grouping modes (character/all) do not need (or have) domain map data
812 default: break;
813 }
814
815 size_t grouping_span_index = 0;
816 SkV2 current_line_offset = { 0, 0 }; // cumulative line spacing
817
818 auto compute_linewide_props = [this](const TextAnimator::ModulatorBuffer& buf,
819 const TextAnimator::DomainSpan& line_span) {
820 SkV2 total_spacing = {0,0};
821 float total_tracking = 0;
822
823 // Only compute these when needed.
824 if (fRequiresLineAdjustments && line_span.fCount) {
825 for (size_t i = line_span.fOffset; i < line_span.fOffset + line_span.fCount; ++i) {
826 const auto& props = buf[i].props;
827 total_spacing += props.line_spacing;
828 total_tracking += props.tracking;
829 }
830
831 // The first glyph does not contribute |before| tracking, and the last one does not
832 // contribute |after| tracking.
833 total_tracking -= 0.5f * (buf[line_span.fOffset].props.tracking +
834 buf[line_span.fOffset + line_span.fCount - 1].props.tracking);
835 }
836
837 return std::make_tuple(total_spacing, total_tracking);
838 };
839
840 // Finally, push all props to their corresponding fragment.
841 for (const auto& line_span : fMaps.fLinesMap) {
842 const auto [line_spacing, line_tracking] = compute_linewide_props(buf, line_span);
843 const auto align_offset = -line_tracking * align_factor(fText->fHAlign);
844
845 // line spacing of the first line is ignored (nothing to "space" against)
846 if (&line_span != &fMaps.fLinesMap.front() && line_span.fCount) {
847 // For each line, the actual spacing is an average of individual fragment spacing
848 // (to preserve the "line").
849 current_line_offset += line_spacing / line_span.fCount;
850 }
851
852 float tracking_acc = 0;
853 for (size_t i = line_span.fOffset; i < line_span.fOffset + line_span.fCount; ++i) {
854 // Track the grouping domain span in parallel.
855 if (grouping_domain && i >= (*grouping_domain)[grouping_span_index].fOffset +
856 (*grouping_domain)[grouping_span_index].fCount) {
857 grouping_span_index += 1;
858 SkASSERT(i < (*grouping_domain)[grouping_span_index].fOffset +
859 (*grouping_domain)[grouping_span_index].fCount);
860 }
861
862 const auto& props = buf[i].props;
863 const auto& frag = fFragments[i];
864
865 // AE tracking is defined per glyph, based on two components: |before| and |after|.
866 // BodyMovin only exports "balanced" tracking values, where before = after = tracking/2.
867 //
868 // Tracking is applied as a local glyph offset, and contributes to the line width for
869 // alignment purposes.
870 //
871 // No |before| tracking for the first glyph, nor |after| tracking for the last one.
872 const auto track_before = i > line_span.fOffset
873 ? props.tracking * 0.5f : 0.0f,
874 track_after = i < line_span.fOffset + line_span.fCount - 1
875 ? props.tracking * 0.5f : 0.0f;
876
877 const auto frag_offset = current_line_offset +
878 SkV2{align_offset + tracking_acc + track_before, 0};
879
880 tracking_acc += track_before + track_after;
881
882 this->pushPropsToFragment(props, frag, frag_offset, fGroupingAlignment * .01f, // %
883 grouping_domain ? &(*grouping_domain)[grouping_span_index]
884 : nullptr);
885 }
886 }
887}
#define SkASSERT(cond)
Definition SkAssert.h:116
std::vector< DomainSpan > DomainMap
std::vector< AnimatedPropsModulator > ModulatorBuffer
Definition SkM44.h:19

◆ setText()

void skottie::internal::TextAdapter::setText ( const TextValue txt)

Definition at line 636 of file TextAdapter.cpp.

636 {
637 fText.fCurrentValue = txt;
638 this->onSync();
639}

The documentation for this class was generated from the following files: