Flutter Engine
The Flutter Engine
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
virtual void onSync ()=0
 
void shrink_to_fit ()
 
void attachDiscardableAdapter (sk_sp< AnimatablePropertyContainer >)
 
- Protected Member Functions inherited from skottie::internal::Animator
 Animator ()=default
 
virtual StateChanged onSeek (float t)=0
 

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)
static float max(float r, float g, float b)
Definition: hsl.cpp:49
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
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 778 of file TextAdapter.cpp.

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

◆ setText()

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

Definition at line 640 of file TextAdapter.cpp.

640 {
641 fText.fCurrentValue = txt;
642 this->onSync();
643}

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