77
88#include " SkottieAdapter.h"
99
10+ #include " SkFont.h"
1011#include " SkMatrix.h"
1112#include " SkPath.h"
1213#include " SkRRect.h"
1920#include " SkSGText.h"
2021#include " SkSGTransform.h"
2122#include " SkSGTrimEffect.h"
23+ #include " SkTextBlob.h"
24+ #include " SkTextUtils.h"
2225#include " SkTo.h"
26+ #include " SkUTF.h"
2327#include " SkottieValue.h"
2428
2529#include < cmath>
@@ -179,7 +183,7 @@ void TrimEffectAdapter::apply() {
179183
180184TextAdapter::TextAdapter (sk_sp<sksg::Group> root)
181185 : fRoot (std::move(root))
182- , fTextNode (sksg::Text ::Make(nullptr , SkString() ))
186+ , fTextNode (sksg::TextBlob ::Make())
183187 , fFillColor (sksg::Color::Make(SK_ColorTRANSPARENT))
184188 , fStrokeColor (sksg::Color::Make(SK_ColorTRANSPARENT))
185189 , fFillNode (sksg::Draw::Make(fTextNode , fFillColor ))
@@ -198,21 +202,80 @@ TextAdapter::TextAdapter(sk_sp<sksg::Group> root)
198202 //
199203 // * where the text node is shared
200204
201- fTextNode ->setFlags (fTextNode ->getFlags () |
202- SkPaint::kAntiAlias_Flag |
203- SkPaint::kSubpixelText_Flag );
204- fTextNode ->setHinting (SkPaint::kNo_Hinting );
205-
205+ fFillColor ->setAntiAlias (true );
206+ fStrokeColor ->setAntiAlias (true );
206207 fStrokeColor ->setStyle (SkPaint::kStroke_Style );
207208}
208209
209- void TextAdapter::apply () {
210- // Push text props to the scene graph.
211- fTextNode ->setTypeface (fText .fTypeface );
212- fTextNode ->setText (fText .fText );
213- fTextNode ->setSize (fText .fTextSize );
214- fTextNode ->setAlign (fText .fAlign );
210+ sk_sp<SkTextBlob> TextAdapter::makeBlob () const {
211+ // TODO: convert to SkFont (missing getFontSpacing, measureText).
212+ SkPaint font;
213+ font.setTypeface (fText .fTypeface );
214+ font.setTextSize (fText .fTextSize );
215+ font.setHinting (SkPaint::kNo_Hinting );
216+ font.setSubpixelText (true );
217+ font.setAntiAlias (true );
218+ font.setTextEncoding (SkPaint::kUTF8_TextEncoding );
219+
220+ const auto align_fract = [](SkTextUtils::Align align) {
221+ switch (align) {
222+ case SkTextUtils::kLeft_Align : return 0 .0f ;
223+ case SkTextUtils::kCenter_Align : return -0 .5f ;
224+ case SkTextUtils::kRight_Align : return -1 .0f ;
225+ }
226+ return 0 .0f ; // go home, msvc...
227+ }(fText .fAlign );
228+
229+ const auto line_spacing = font.getFontSpacing ();
230+ const auto blob_font = SkFont::LEGACY_ExtractFromPaint (font);
231+ float y_off = 0 ;
232+ SkSTArray<256 , SkGlyphID, true > line_glyph_buffer;
233+ SkTextBlobBuilder builder;
234+
235+ const auto & push_line = [&](const char * start, const char * end) {
236+ if (end > start) {
237+ const auto len = SkToSizeT (end - start);
238+ line_glyph_buffer.reset (font.textToGlyphs (start, len, nullptr ));
239+ SkAssertResult (font.textToGlyphs (start, len, line_glyph_buffer.data ())
240+ == line_glyph_buffer.count ());
241+
242+ const auto x_off = align_fract != 0
243+ ? align_fract * font.measureText (start, len)
244+ : 0 ;
245+ const auto & buf = builder.allocRun (blob_font, line_glyph_buffer.count (), x_off, y_off);
246+ if (!buf.glyphs ) {
247+ return ;
248+ }
249+
250+ memcpy (buf.glyphs , line_glyph_buffer.data (),
251+ SkToSizeT (line_glyph_buffer.count ()) * sizeof (SkGlyphID));
252+
253+ y_off += line_spacing;
254+ }
255+ };
256+
257+ const auto & is_line_break = [](SkUnichar uch) {
258+ // TODO: other explicit breaks?
259+ return uch == ' \r ' ;
260+ };
215261
262+ const char * ptr = fText .fText .c_str ();
263+ const char * line_start = ptr;
264+ const char * end = ptr + fText .fText .size ();
265+
266+ while (ptr < end) {
267+ if (is_line_break (SkUTF::NextUTF8 (&ptr, end))) {
268+ push_line (line_start, ptr - 1 );
269+ line_start = ptr;
270+ }
271+ }
272+ push_line (line_start, ptr);
273+
274+ return builder.make ();
275+ }
276+
277+ void TextAdapter::apply () {
278+ fTextNode ->setBlob (this ->makeBlob ());
216279 fFillColor ->setColor (fText .fFillColor );
217280 fStrokeColor ->setColor (fText .fStrokeColor );
218281 fStrokeColor ->setStrokeWidth (fText .fStrokeWidth );
0 commit comments