86 font.setSubpixel(
true);
87 font.setLinearMetrics(
true);
88 font.setBaselineSnap(
false);
95 const std::vector<SkSVGLength>& lengths,
97 std::vector<float> resolved;
98 resolved.reserve(lengths.size());
100 for (
const auto& l : lengths) {
101 resolved.push_back(lctx.
resolve(l, lt));
124 size_t charIndexOffset)
126 , fParent(tctx->fPosResolver)
127 , fCharIndexOffset(charIndexOffset)
132 , fRotate(
txt.getRotate())
134 fTextContext->fPosResolver =
this;
143 fTextContext->fPosResolver = fParent;
149 if (charIndex < fLastPosIndex) {
150 SkASSERT(charIndex >= fCharIndexOffset);
151 const auto localCharIndex = charIndex - fCharIndexOffset;
153 const auto hasAllLocal = localCharIndex < fX.size() &&
154 localCharIndex < fY.size() &&
155 localCharIndex < fDx.size() &&
156 localCharIndex < fDy.size() &&
157 localCharIndex < fRotate.size();
158 if (!hasAllLocal && fParent) {
159 attrs = fParent->resolve(charIndex);
162 if (localCharIndex < fX.size()) {
165 if (localCharIndex < fY.size()) {
168 if (localCharIndex < fDx.size()) {
171 if (localCharIndex < fDy.size()) {
188 if (!fRotate.empty()) {
189 if (localCharIndex < fRotate.size()) {
204 fLastPosIndex = charIndex;
213 if (!fUtf8PosAdjust.empty()) {
214 pos.
offset += fUtf8PosAdjust.back().offset;
219 fUtf8 .push_back_n(utf8_len, utf8_buf);
220 fUtf8PosAdjust.push_back_n(utf8_len,
pos);
224 const char*
utf8 = fShapeBuffer.fUtf8.data();
225 size_t utf8Bytes = fShapeBuffer.fUtf8.size();
227 std::unique_ptr<SkShaper::FontRunIterator> font_runs =
232 if (!fForcePrimitiveShaping) {
234 const uint8_t defaultLTR = 0;
235 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
237 std::unique_ptr<SkShaper::LanguageRunIterator> language =
241 if (bidi &&
script && language) {
252 fShapeBuffer.reset();
271 fShapeBuffer.reset();
277 : fRenderContext(ctx)
279 , fShaper(ctx.makeShaper())
280 , fChunkAlignmentFactor(ComputeAlignmentFactor(ctx.presentationContext())) {
285 fForcePrimitiveShaping =
true;
288 fPathData = std::make_unique<PathData>(ctx, *tpath);
302 return offset.value() * fPathData->length() / 100;
306 fChunkPos.
fX = resolve_offset(tpath->getStartOffset());
331 if (fPrevCharSpace && ch ==
' ') {
342 if (ch ==
'\n' || ch ==
'\t') {
352 const auto font = ResolveFont(ctx);
353 fShapeBuffer.reserve(
txt.size());
355 const char* ch_ptr =
txt.c_str();
356 const char* ch_end = ch_ptr +
txt.size();
358 while (ch_ptr < ch_end) {
361 ? filterWSDefault(ch)
362 : filterWSPreserve(ch);
370 const auto pos = fPosResolver->
resolve(fCurrentCharIndex++);
375 this->shapePendingBuffer(ctx,
font);
387 fShapeBuffer.append(ch, {
395 fPrevCharSpace = (ch ==
' ');
398 this->shapePendingBuffer(ctx,
font);
414 fContours.push_back(std::move(
contour));
418SkMatrix SkSVGTextContext::PathData::getMatrixAt(
float offset)
const {
420 for (
const auto&
contour : fContours) {
421 const auto contour_len =
contour->length();
422 if (
offset < contour_len) {
432 std::numeric_limits<float>::infinity());
437 const PositionAdjustment& pos_adjust)
const {
438 SkPoint pos = fChunkPos + glyph_pos + pos_adjust.
offset + fChunkAdvance * fChunkAlignmentFactor;
448 font.getWidths(&glyph, 1, &glyph_width);
449 auto path_offset =
pos.
fX + glyph_width * .5f;
456 const auto m = fPathData->getMatrixAt(path_offset) *
466 for (
const auto&
run : fRuns) {
469 for (
size_t i = 0;
i <
run.glyphCount; ++
i) {
470 buf.xforms()[
i] = this->computeGlyphXform(
run.glyphs[
i],
473 run.glyhPosAdjust[
i]);
476 fCallback(ctx, blobBuilder.
make(),
run.fillPaint.get(),
run.strokePaint.get());
479 fChunkPos += fChunkAdvance;
480 fChunkAdvance = {0,0};
491 fCurrentFill.
isValid() ? std::make_unique<SkPaint>(*fCurrentFill) :
nullptr,
492 fCurrentStroke.
isValid() ? std::make_unique<SkPaint>(*fCurrentStroke) :
nullptr,
493 std::make_unique<
SkGlyphID[] >(ri.glyphCount),
494 std::make_unique<
SkPoint[] >(ri.glyphCount),
495 std::make_unique<PositionAdjustment[]>(ri.glyphCount),
501 fShapeClusterBuffer.resize(
std::max(fShapeClusterBuffer.size(), ri.glyphCount));
504 fRuns.back().glyphs.get(),
505 fRuns.back().glyphPos.get(),
507 fShapeClusterBuffer.data(),
512void SkSVGTextContext::commitRunBuffer(
const RunInfo& ri) {
513 const auto& current_run = fRuns.back();
516 for (
size_t i = 0;
i < ri.glyphCount; ++
i) {
517 const auto utf8_index = fShapeClusterBuffer[
i];
518 current_run.glyhPosAdjust[
i] = fShapeBuffer.fUtf8PosAdjust[
SkToInt(utf8_index)];
521 fChunkAdvance += ri.fAdvance;
524void SkSVGTextContext::commitLine() {
525 if (!fShapeBuffer.fUtf8PosAdjust.empty()) {
527 fChunkAdvance += fShapeBuffer.fUtf8PosAdjust.back().offset;
549 switch (child->
tag()) {
567 for (
const auto& frag : fChildren) {
569 frag->renderText(ctx, tctx, this->getXmlSpace());
576 static constexpr std::tuple<const char*, SkSVGXmlSpace> gXmlSpaceMap[] = {
581 return this->parseEnumMap(gXmlSpaceMap, xs) && this->parseEOSToken();
593 this->setXmlSpace(SkSVGAttributeParser::parse<SkSVGXmlSpace>(
"xml:space",
name,
value));
619 this->
onShapeText(ctx, &tctx, this->getXmlSpace());
636 it.font().getBounds(it.glyphs(), it.glyphCount(), glyphBounds.
get(),
nullptr);
640 for (uint32_t
i = 0;
i < it.glyphCount(); ++
i) {
641 m.setRSXform(it.xforms()[
i]);
642 bounds.join(
m.mapRect(glyphBounds[
i]));
649 this->
onShapeText(ctx, &tctx, this->getXmlSpace());
669 } get_paths_ctx {
builder, it.xforms()};
671 it.font().getPaths(it.glyphs(), it.glyphCount(), [](
const SkPath*
path,
674 auto* get_paths_ctx =
static_cast<GetPathsCtx*
>(raw_ctx);
675 const auto& glyph_rsx = *get_paths_ctx->xform++;
685 get_paths_ctx->builder.addPath(
path->makeTransform(glyph_matrix));
692 this->
onShapeText(ctx, &tctx, this->getXmlSpace());
711bool SkSVGTextPath::parseAndSetAttribute(
const char*
name,
const char*
value) {
713 this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>(
"xlink:href",
name,
value)) ||
714 this->setStartOffset(SkSVGAttributeParser::parse<SkSVGLength>(
"startOffset",
name,
value));
@ kNone
glyph outlines unchanged
#define SkDegreesToRadians(degrees)
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
constexpr int SkToInt(S x)
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
sk_sp< SkTypeface > legacyMakeTypeface(const char familyName[], SkFontStyle style) const
@ kAntiAlias
may have transparent pixels on glyph edges
static SkMatrix RotateRad(SkScalar rad)
static SkMatrix Translate(SkScalar dx, SkScalar dy)
SkMatrix & setRSXform(const SkRSXform &rsxForm)
static const SkMatrix & I()
SkMatrix & preConcat(const SkMatrix &other)
bool parse(SkSVGIntegerType *v)
const SkString & family() const
const SkSVGLength & size() const
SkScalar resolve(const SkSVGLength &, LengthType) const
virtual bool parseAndSetAttribute(const char *name, const char *value)
SkTLazy< SkPaint > fillPaint() const
BorrowedNode findNodeById(const SkSVGIRI &) const
sk_sp< SkFontMgr > fontMgr() const
const SkSVGPresentationContext & presentationContext() const
std::unique_ptr< SkShaper::ScriptRunIterator > makeScriptRunIterator(const char *utf8, size_t utf8Bytes) const
std::unique_ptr< SkShaper::BiDiRunIterator > makeBidiRunIterator(const char *utf8, size_t utf8Bytes, uint8_t bidiLevel) const
SkCanvas * canvas() const
const SkSVGLengthContext & lengthContext() const
SkTLazy< SkPaint > strokePaint() const
void onShapeText(const SkSVGRenderContext &, SkSVGTextContext *, SkSVGXmlSpace) const override
void appendChild(sk_sp< SkSVGNode >) final
bool parseAndSetAttribute(const char *, const char *) override
void setImplicitRotate(bool imp)
bool isImplicitRotate() const
ScopedPosResolver(const SkSVGTextContainer &, const SkSVGLengthContext &, SkSVGTextContext *, size_t)
PosAttrs resolve(size_t charIndex) const
const ShapedTextCallback & getCallback() const
void flushChunk(const SkSVGRenderContext &ctx)
void shapeFragment(const SkString &, const SkSVGRenderContext &, SkSVGXmlSpace)
std::function< void(const SkSVGRenderContext &, const sk_sp< SkTextBlob > &, const SkPaint *, const SkPaint *)> ShapedTextCallback
SkSVGTextContext(const SkSVGRenderContext &, const ShapedTextCallback &, const SkSVGTextPath *=nullptr)
~SkSVGTextContext() override
void renderText(const SkSVGRenderContext &, SkSVGTextContext *, SkSVGXmlSpace) const
virtual void onShapeText(const SkSVGRenderContext &, SkSVGTextContext *, SkSVGXmlSpace) const =0
static std::unique_ptr< FontRunIterator > MakeFontMgrRunIterator(const char *utf8, size_t utf8Bytes, const SkFont &font, sk_sp< SkFontMgr > fallback)
static std::unique_ptr< LanguageRunIterator > MakeStdLanguageRunIterator(const char *utf8, size_t utf8Bytes)
const RunBuffer & allocRunRSXform(const SkFont &font, int count)
sk_sp< SkTextBlob > make()
static void append(char **dst, size_t *count, const char *src, size_t n)
static float max(float r, float g, float b)
unsigned useCenter Optional< SkMatrix > matrix
Optional< SkRect > bounds
SKSHAPER_API std::unique_ptr< SkShaper > PrimitiveText()
SK_SPI size_t ToUTF8(SkUnichar uni, char utf8[kMaxBytesInUTF8Sequence]=nullptr)
constexpr unsigned kMaxBytesInUTF8Sequence
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
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
static SkRect compute_bounds(const SkPoint *points, int count)
font
Font Metadata and Metrics.
void offset(float dx, float dy)
static constexpr SkRect MakeEmpty()
SkSVGProperty< SkSVGFontSize, true > fFontSize
SkSVGProperty< SkSVGFontFamily, true > fFontFamily
SkSVGProperty< SkSVGFontWeight, true > fFontWeight
SkSVGProperty< SkSVGTextAnchor, true > fTextAnchor
SkSVGProperty< SkSVGFontStyle, true > fFontStyle
SkSVGPresentationAttributes fInherited