21#include <initializer_list>
36 , fScaledRotations{scaledRotations}
40 : fSource{that.fSource}
42 , fClusters{that.fClusters}
51 : fGlyphRuns{glyphRunList}
52 , fOriginalTextBlob{blob}
62 , fOriginalTextBlob{
nullptr}
67uint64_t GlyphRunList::uniqueID()
const {
68 return fOriginalTextBlob !=
nullptr ? fOriginalTextBlob->uniqueID()
72bool GlyphRunList::anyRunsLCD()
const {
73 for (
const auto& r : fGlyphRuns) {
81void GlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID,
82 SkTextBlob::PurgeDelegate pd)
const {
83 SkASSERT(fOriginalTextBlob !=
nullptr);
85 fOriginalTextBlob->notifyAddedToCache(cacheID, pd);
90 for (
auto&
run : *
this) {
92 if (
run.scaledRotations().empty()) {
93 if (
run.text().empty()) {
99 auto clusters =
run.clusters();
100 memcpy(
buffer.clusters, clusters.data(), clusters.size_bytes());
102 auto positions =
run.positions();
103 memcpy(
buffer.points(), positions.data(), positions.size_bytes());
108 run.scaledRotations())) {
112 auto glyphIDs =
run.glyphsIDs();
113 memcpy(
buffer.glyphs, glyphIDs.data(), glyphIDs.size_bytes());
136 if (scaledRotations.
empty()) {
138 auto scaleAndTranslateRect =
149 bounds.join(scaleAndTranslateRect(r,
pos));
156 for (
auto [
pos, scaleRotate, glyph] :
SkMakeZip(positions, scaledRotations,
glyphs)) {
157 if (!glyph->rect().isEmpty()) {
160 xform.
preScale(strikeToSourceScale, strikeToSourceScale);
169 if (scaledRotations.
empty()) {
181 for (
auto [
pos, scaleRotate] :
SkMakeZip(positions, scaledRotations)) {
200 auto glyphs = storage.glyphs(glyphIDs);
203 SkPoint endOfLastGlyph = origin;
204 for (
auto glyph :
glyphs) {
205 *positionCursor++ = endOfLastGlyph;
206 endOfLastGlyph += glyph->advanceVector();
213 const void* bytes,
size_t byteLength,
SkPoint origin,
215 auto glyphIDs = textToGlyphIDs(
font, bytes, byteLength, encoding);
217 this->prepareBuffers(glyphIDs.size(), 0);
218 if (!glyphIDs.empty()) {
220 this->makeGlyphRun(
font,
226 auto run = fGlyphRunListStorage.front();
230 return this->setGlyphRunList(
nullptr,
bounds, origin);
236 this->initialize(blob);
238 SkPoint* positionCursor = fPositions;
239 SkVector* scaledRotationsCursor = fScaledRotations;
241 size_t runSize = it.glyphCount();
252 switch (it.positioning()) {
255 positionCursor += positions.
size();
259 positions =
SkSpan(positionCursor, runSize);
266 positions =
SkSpan(it.points(), runSize);
270 positions =
SkSpan(positionCursor, runSize);
271 scaledRotations =
SkSpan(scaledRotationsCursor, runSize);
273 *positionCursor++ = {xform.fTx, xform.fTy};
274 *scaledRotationsCursor++ = {xform.fSCos, xform.fSSin};
280 const uint32_t* clusters = it.clusters();
290 return this->setGlyphRunList(&blob, blob.
bounds(), origin);
298 auto scaledRotations =
SkSpan(fScaledRotations.get(),
count);
300 auto [scos, ssin, tx, ty] = xform;
304 return {positions, scaledRotations};
307void GlyphRunBuilder::initialize(
const SkTextBlob& blob) {
308 int positionCount = 0;
309 int rsxFormCount = 0;
312 positionCount += it.glyphCount();
315 rsxFormCount += it.glyphCount();
319 prepareBuffers(positionCount, rsxFormCount);
322void GlyphRunBuilder::prepareBuffers(
int positionCount,
int RSXFormCount) {
323 if (positionCount > fMaxTotalRunSize) {
324 fMaxTotalRunSize = positionCount;
325 fPositions.
reset(fMaxTotalRunSize);
328 if (RSXFormCount > fMaxScaledRotations) {
329 fMaxScaledRotations = RSXFormCount;
330 fScaledRotations.reset(RSXFormCount);
333 fGlyphRunListStorage.clear();
339 int count =
font.countText(bytes, byteLength, encoding);
341 fScratchGlyphIDs.resize(
count);
342 font.textToGlyphs(bytes, byteLength, encoding, fScratchGlyphIDs.data(),
count);
343 return SkSpan(fScratchGlyphIDs);
352void GlyphRunBuilder::makeGlyphRun(
361 if (!glyphIDs.
empty()) {
362 fGlyphRunListStorage.emplace_back(
372const GlyphRunList& sktext::GlyphRunBuilder::setGlyphRunList(
374 fGlyphRunList.emplace(blob,
bounds, origin,
SkSpan(fGlyphRunListStorage),
this);
375 return fGlyphRunList.value();
@ kGlyphID
uses two byte words to represent glyph indices
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr int SkCount(const Container &c)
static constexpr uint32_t SK_InvalidUniqueID
constexpr auto SkMakeZip(Ts &&... ts)
static bool IsFinite(const SkFont &font)
static SkRect GetFontBounds(const SkFont &)
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
SkMatrix & setRSXform(const SkRSXform &rsxForm)
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
constexpr T * data() const
constexpr bool empty() const
constexpr size_t size() const
static SkStrikeSpec MakeWithNoDevice(const SkFont &font, const SkPaint *paint=nullptr)
static std::tuple< SkStrikeSpec, SkScalar > MakeCanonicalized(const SkFont &font, const SkPaint *paint=nullptr)
@ kHorizontal_Positioning
const SkRect & bounds() const
T * reset(size_t count=0)
std::tuple< SkSpan< const SkPoint >, SkSpan< const SkVector > > convertRSXForm(SkSpan< const SkRSXform > xforms)
const GlyphRunList & blobToGlyphRunList(const SkTextBlob &blob, SkPoint origin)
GlyphRunList(const SkTextBlob *blob, SkRect bounds, SkPoint origin, SkSpan< const GlyphRun > glyphRunList, GlyphRunBuilder *builder)
GlyphRun(const SkFont &font, SkSpan< const SkPoint > positions, SkSpan< const SkGlyphID > glyphIDs, SkSpan< const char > text, SkSpan< const uint32_t > clusters, SkSpan< const SkVector > scaledRotations)
Optional< SkRect > bounds
PODArray< SkRSXform > xforms
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
font
Font Metadata and Metrics.
static SkRect glyphrun_source_bounds(const SkFont &font, const SkPaint &paint, SkZip< const SkGlyphID, const SkPoint > source, SkSpan< const SkVector > scaledRotations)
static SkSpan< const SkPoint > draw_text_positions(const SkFont &font, SkSpan< const SkGlyphID > glyphIDs, SkPoint origin, SkPoint *buffer)
static constexpr SkPoint Make(float x, float y)
constexpr float y() const
constexpr float x() const
static constexpr SkRect MakeEmpty()
constexpr float left() const
constexpr float top() const
constexpr float right() const
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
constexpr float bottom() const