Flutter Engine
The Flutter Engine
Classes | Public Types | Public Member Functions | List of all members
SkSVGTextContext Class Referencefinal

#include <SkSVGTextPriv.h>

Inheritance diagram for SkSVGTextContext:
SkShaper::RunHandler

Classes

class  PosAttrs
 
class  ScopedPosResolver
 

Public Types

using ShapedTextCallback = std::function< void(const SkSVGRenderContext &, const sk_sp< SkTextBlob > &, const SkPaint *, const SkPaint *)>
 

Public Member Functions

 SkSVGTextContext (const SkSVGRenderContext &, const ShapedTextCallback &, const SkSVGTextPath *=nullptr)
 
 ~SkSVGTextContext () override
 
void shapeFragment (const SkString &, const SkSVGRenderContext &, SkSVGXmlSpace)
 
void flushChunk (const SkSVGRenderContext &ctx)
 
const ShapedTextCallbackgetCallback () const
 

Detailed Description

Definition at line 34 of file SkSVGTextPriv.h.

Member Typedef Documentation

◆ ShapedTextCallback

Definition at line 36 of file SkSVGTextPriv.h.

Constructor & Destructor Documentation

◆ SkSVGTextContext()

SkSVGTextContext::SkSVGTextContext ( const SkSVGRenderContext ctx,
const ShapedTextCallback cb,
const SkSVGTextPath tpath = nullptr 
)

Definition at line 274 of file SkSVGText.cpp.

277 : fRenderContext(ctx)
278 , fCallback(cb)
279 , fShaper(ctx.makeShaper())
280 , fChunkAlignmentFactor(ComputeAlignmentFactor(ctx.presentationContext())) {
281 // If the shaper callback returns null, fallback to the primitive shaper and
282 // signal that we should not use the other callbacks in shapePendingBuffer
283 if (!fShaper) {
285 fForcePrimitiveShaping = true;
286 }
287 if (tpath) {
288 fPathData = std::make_unique<PathData>(ctx, *tpath);
289
290 // https://www.w3.org/TR/SVG11/text.html#TextPathElementStartOffsetAttribute
291 auto resolve_offset = [this](const SkSVGLength& offset) {
293 // "If a <length> other than a percentage is given, then the ‘startOffset’
294 // represents a distance along the path measured in the current user coordinate
295 // system."
296 return fRenderContext.lengthContext()
298 }
299
300 // "If a percentage is given, then the ‘startOffset’ represents a percentage distance
301 // along the entire path."
302 return offset.value() * fPathData->length() / 100;
303 };
304
305 // startOffset acts as an initial absolute position
306 fChunkPos.fX = resolve_offset(tpath->getStartOffset());
307 }
308}
SkScalar resolve(const SkSVGLength &, LengthType) const
const SkSVGPresentationContext & presentationContext() const
const SkSVGLengthContext & lengthContext() const
std::unique_ptr< SkShaper > makeShaper() const
SKSHAPER_API std::unique_ptr< SkShaper > PrimitiveText()
SeparatedVector2 offset
float fX
x-axis value
Definition: SkPoint_impl.h:164

◆ ~SkSVGTextContext()

SkSVGTextContext::~SkSVGTextContext ( )
override

Definition at line 310 of file SkSVGText.cpp.

310 {
311 this->flushChunk(fRenderContext);
312}
void flushChunk(const SkSVGRenderContext &ctx)
Definition: SkSVGText.cpp:463

Member Function Documentation

◆ flushChunk()

void SkSVGTextContext::flushChunk ( const SkSVGRenderContext ctx)

Definition at line 463 of file SkSVGText.cpp.

463 {
464 SkTextBlobBuilder blobBuilder;
465
466 for (const auto& run : fRuns) {
467 const auto& buf = blobBuilder.allocRunRSXform(run.font, SkToInt(run.glyphCount));
468 std::copy(run.glyphs.get(), run.glyphs.get() + run.glyphCount, buf.glyphs);
469 for (size_t i = 0; i < run.glyphCount; ++i) {
470 buf.xforms()[i] = this->computeGlyphXform(run.glyphs[i],
471 run.font,
472 run.glyphPos[i],
473 run.glyhPosAdjust[i]);
474 }
475
476 fCallback(ctx, blobBuilder.make(), run.fillPaint.get(), run.strokePaint.get());
477 }
478
479 fChunkPos += fChunkAdvance;
480 fChunkAdvance = {0,0};
481 fChunkAlignmentFactor = ComputeAlignmentFactor(ctx.presentationContext());
482
483 fRuns.clear();
484}
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
constexpr int SkToInt(S x)
Definition: SkTo.h:29
const RunBuffer & allocRunRSXform(const SkFont &font, int count)
Definition: SkTextBlob.cpp:560
sk_sp< SkTextBlob > make()
Definition: SkTextBlob.cpp:617
Definition: run.py:1

◆ getCallback()

const ShapedTextCallback & SkSVGTextContext::getCallback ( ) const
inline

Definition at line 120 of file SkSVGTextPriv.h.

120{ return fCallback; }

◆ shapeFragment()

void SkSVGTextContext::shapeFragment ( const SkString txt,
const SkSVGRenderContext ctx,
SkSVGXmlSpace  xs 
)

Definition at line 314 of file SkSVGText.cpp.

315 {
316 // https://www.w3.org/TR/SVG11/text.html#WhiteSpace
317 // https://www.w3.org/TR/2008/REC-xml-20081126/#NT-S
318 auto filterWSDefault = [this](SkUnichar ch) -> SkUnichar {
319 // Remove all newline chars.
320 if (ch == '\n') {
321 return -1;
322 }
323
324 // Convert tab chars to space.
325 if (ch == '\t') {
326 ch = ' ';
327 }
328
329 // Consolidate contiguous space chars and strip leading spaces (fPrevCharSpace
330 // starts off as true).
331 if (fPrevCharSpace && ch == ' ') {
332 return -1;
333 }
334
335 // TODO: Strip trailing WS? Doing this across chunks would require another buffering
336 // layer. In general, trailing WS should have no rendering side effects. Skipping
337 // for now.
338 return ch;
339 };
340 auto filterWSPreserve = [](SkUnichar ch) -> SkUnichar {
341 // Convert newline and tab chars to space.
342 if (ch == '\n' || ch == '\t') {
343 ch = ' ';
344 }
345 return ch;
346 };
347
348 // Stash paints for access from SkShaper callbacks.
349 fCurrentFill = ctx.fillPaint();
350 fCurrentStroke = ctx.strokePaint();
351
352 const auto font = ResolveFont(ctx);
353 fShapeBuffer.reserve(txt.size());
354
355 const char* ch_ptr = txt.c_str();
356 const char* ch_end = ch_ptr + txt.size();
357
358 while (ch_ptr < ch_end) {
359 auto ch = SkUTF::NextUTF8(&ch_ptr, ch_end);
360 ch = (xs == SkSVGXmlSpace::kDefault)
361 ? filterWSDefault(ch)
362 : filterWSPreserve(ch);
363
364 if (ch < 0) {
365 // invalid utf or char filtered out
366 continue;
367 }
368
369 SkASSERT(fPosResolver);
370 const auto pos = fPosResolver->resolve(fCurrentCharIndex++);
371
372 // Absolute position adjustments define a new chunk.
373 // (https://www.w3.org/TR/SVG11/text.html#TextLayoutIntroduction)
374 if (pos.has(PosAttrs::kX) || pos.has(PosAttrs::kY)) {
375 this->shapePendingBuffer(ctx, font);
376 this->flushChunk(ctx);
377
378 // New chunk position.
379 if (pos.has(PosAttrs::kX)) {
380 fChunkPos.fX = pos[PosAttrs::kX];
381 }
382 if (pos.has(PosAttrs::kY)) {
383 fChunkPos.fY = pos[PosAttrs::kY];
384 }
385 }
386
387 fShapeBuffer.append(ch, {
388 {
391 },
393 });
394
395 fPrevCharSpace = (ch == ' ');
396 }
397
398 this->shapePendingBuffer(ctx, font);
399
400 // Note: at this point we have shaped and buffered RunRecs for the current fragment.
401 // The active text chunk continues until an explicit or implicit flush.
402}
SkPoint pos
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkDegreesToRadians(degrees)
Definition: SkScalar.h:77
int32_t SkUnichar
Definition: SkTypes.h:175
SkTLazy< SkPaint > fillPaint() const
SkTLazy< SkPaint > strokePaint() const
PosAttrs resolve(size_t charIndex) const
Definition: SkSVGText.cpp:146
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition: SkUTF.cpp:118
font
Font Metadata and Metrics.
float fY
y-axis value
Definition: SkPoint_impl.h:165

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