Flutter Engine
The Flutter Engine
SkStrike.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/core/SkStrike.h"
9
13#include "include/core/SkPath.h"
19#include "src/core/SkGlyph.h"
20#include "src/core/SkMask.h"
26
27#include <cctype>
28#include <new>
29#include <optional>
30#include <utility>
31
32using namespace skglyph;
33
35 const SkFontMetrics* metrics, SkScalerContext* context) {
36 SkFontMetrics answer;
37 if (metrics) {
38 answer = *metrics;
39 } else {
40 context->getFontMetrics(&answer);
41 }
42 return answer;
43}
44
46 const SkStrikeSpec& strikeSpec,
47 std::unique_ptr<SkScalerContext> scaler,
48 const SkFontMetrics* metrics,
49 std::unique_ptr<SkStrikePinner> pinner)
50 : fFontMetrics{use_or_generate_metrics(metrics, scaler.get())}
51 , fRoundingSpec{scaler->isSubpixel(),
52 scaler->computeAxisAlignmentForHText()}
53 , fStrikeSpec{strikeSpec}
54 , fStrikeCache{strikeCache}
55 , fScalerContext{std::move(scaler)}
56 , fPinner{std::move(pinner)} {
57 SkASSERT(fScalerContext != nullptr);
58}
59
61public:
62 Monitor(SkStrike* strike) SK_ACQUIRE(strike->fStrikeLock)
63 : fStrike{strike} {
64 fStrike->lock();
65 }
66
68 fStrike->unlock();
69 }
70
71private:
72 SkStrike* const fStrike;
73};
74
76 fStrikeLock.acquire();
77 fMemoryIncrease = 0;
78}
79
81 const size_t memoryIncrease = fMemoryIncrease;
82 fStrikeLock.release();
83 this->updateMemoryUsage(memoryIncrease);
84}
85
86void
89 SkSpan<SkGlyph> paths,
90 SkSpan<SkGlyph> drawables) {
91 SkASSERT_RELEASE(SkTFitsIn<int>(images.size()) &&
92 SkTFitsIn<int>(paths.size()) &&
93 SkTFitsIn<int>(drawables.size()));
94
95 buffer.writeInt(images.size());
96 for (SkGlyph& glyph : images) {
100 }
101
102 buffer.writeInt(paths.size());
103 for (SkGlyph& glyph : paths) {
107 }
108
109 buffer.writeInt(drawables.size());
110 for (SkGlyph& glyph : drawables) {
114 }
115}
116
118 // Read glyphs with images for the current strike.
119 const int imagesCount = buffer.readInt();
120 if (imagesCount == 0 && !buffer.isValid()) {
121 return false;
122 }
123
124 {
125 Monitor m{this};
126 for (int curImage = 0; curImage < imagesCount; ++curImage) {
127 if (!this->mergeGlyphAndImageFromBuffer(buffer)) {
128 return false;
129 }
130 }
131 }
132
133 // Read glyphs with paths for the current strike.
134 const int pathsCount = buffer.readInt();
135 if (pathsCount == 0 && !buffer.isValid()) {
136 return false;
137 }
138 {
139 Monitor m{this};
140 for (int curPath = 0; curPath < pathsCount; ++curPath) {
141 if (!this->mergeGlyphAndPathFromBuffer(buffer)) {
142 return false;
143 }
144 }
145 }
146
147 // Read glyphs with drawables for the current strike.
148 const int drawablesCount = buffer.readInt();
149 if (drawablesCount == 0 && !buffer.isValid()) {
150 return false;
151 }
152 {
153 Monitor m{this};
154 for (int curDrawable = 0; curDrawable < drawablesCount; ++curDrawable) {
155 if (!this->mergeGlyphAndDrawableFromBuffer(buffer)) {
156 return false;
157 }
158 }
159 }
160
161 return true;
162}
163
165 Monitor m{this};
166 // TODO(herb): remove finding the glyph when setting the metrics and image are separated
167 SkGlyphDigest* digest = fDigestForPackedGlyphID.find(toID);
168 if (digest != nullptr) {
169 SkGlyph* glyph = fGlyphForIndex[digest->index()];
170 if (fromGlyph.setImageHasBeenCalled()) {
172 // Should never set an image on a glyph which already has an image.
173 SkDEBUGFAIL("Re-adding image to existing glyph. This should not happen.");
174 }
175 // TODO: assert that any metrics on fromGlyph are the same.
176 fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph);
177 }
178 return glyph;
179 } else {
180 SkGlyph* glyph = fAlloc.make<SkGlyph>(toID);
181 fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph) + sizeof(SkGlyph);
182 (void)this->addGlyphAndDigest(glyph);
183 return glyph;
184 }
185}
186
187const SkPath* SkStrike::mergePath(SkGlyph* glyph, const SkPath* path, bool hairline) {
188 Monitor m{this};
190 SkDEBUGFAIL("Re-adding path to existing glyph. This should not happen.");
191 }
192 if (glyph->setPath(&fAlloc, path, hairline)) {
193 fMemoryIncrease += glyph->path()->approximateBytesUsed();
194 }
195
196 return glyph->path();
197}
198
200 Monitor m{this};
202 SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
203 }
204 if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
205 fMemoryIncrease += glyph->drawable()->approximateBytesUsed();
206 SkASSERT(fMemoryIncrease > 0);
207 }
208
209 return glyph->drawable();
210}
211
213 SkGlyph* glyph, SkScalar* array, int* count) {
214 SkAutoMutexExclusive lock{fStrikeLock};
215 glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
216}
217
219 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
220 Monitor m{this};
221 return this->internalPrepare(glyphIDs, kMetricsOnly, results);
222}
223
225 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
226 Monitor m{this};
227 return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
228}
229
231 SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
232 const SkGlyph** cursor = results;
233 Monitor m{this};
234 for (auto glyphID : glyphIDs) {
235 SkGlyph* glyph = this->glyph(glyphID);
236 this->prepareForImage(glyph);
237 *cursor++ = glyph;
238 }
239
240 return {results, glyphIDs.size()};
241}
242
244 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
245 const SkGlyph** cursor = results;
246 {
247 Monitor m{this};
248 for (auto glyphID : glyphIDs) {
249 SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
250 this->prepareForDrawable(glyph);
251 *cursor++ = glyph;
252 }
253 }
254
255 return {results, glyphIDs.size()};
256}
257
259 Monitor m{this};
260 for (sktext::IDOrPath& idOrPath : idsOrPaths) {
261 SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrPath.fGlyphID});
262 this->prepareForPath(glyph);
263 new (&idOrPath.fPath) SkPath{*glyph->path()};
264 }
265}
266
268 Monitor m{this};
269 for (sktext::IDOrDrawable& idOrDrawable : idsOrDrawables) {
270 SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrDrawable.fGlyphID});
271 this->prepareForDrawable(glyph);
272 SkASSERT(glyph->drawable() != nullptr);
273 idOrDrawable.fDrawable = glyph->drawable();
274 }
275}
276
277void SkStrike::dump() const {
278 SkAutoMutexExclusive lock{fStrikeLock};
279 const SkTypeface* face = fScalerContext->getTypeface();
280 const SkScalerContextRec& rec = fScalerContext->getRec();
285 face->getFamilyName(&name);
286
287 SkString msg;
288 SkFontStyle style = face->fontStyle();
289 msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
290 face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
291 rec.dump().c_str(), fDigestForPackedGlyphID.count());
292 SkDebugf("%s\n", msg.c_str());
293}
294
296 SkAutoMutexExclusive lock{fStrikeLock};
297 const SkTypeface* face = fScalerContext->getTypeface();
298 const SkScalerContextRec& rec = fScalerContext->getRec();
299
300 SkString fontName;
301 face->getFamilyName(&fontName);
302 // Replace all special characters with '_'.
303 for (size_t index = 0; index < fontName.size(); ++index) {
304 if (!std::isalnum(fontName[index])) {
305 fontName[index] = '_';
306 }
307 }
308
309 SkString dumpName = SkStringPrintf("%s/%s_%u/%p",
310 SkStrikeCache::kGlyphCacheDumpName,
311 fontName.c_str(),
312 rec.fTypefaceID,
313 this);
314
315 dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", fMemoryUsed);
316 dump->dumpNumericValue(dumpName.c_str(),
317 "glyph_count", "objects",
318 fDigestForPackedGlyphID.count());
319 dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
320}
321
323 return fGlyphForIndex[digest.index()];
324}
325
327 SkGlyphDigest digest = this->digestFor(kDirectMask, packedGlyphID);
328 return this->glyph(digest);
329}
330
332 SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(packedGlyphID);
333 if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
334 return *digestPtr;
335 }
336
337 SkGlyph* glyph;
338 if (digestPtr != nullptr) {
339 glyph = fGlyphForIndex[digestPtr->index()];
340 } else {
341 glyph = fAlloc.make<SkGlyph>(fScalerContext->makeGlyph(packedGlyphID, &fAlloc));
342 fMemoryIncrease += sizeof(SkGlyph);
343 digestPtr = this->addGlyphAndDigest(glyph);
344 }
345
346 digestPtr->setActionFor(actionType, glyph, this);
347
348 return *digestPtr;
349}
350
351SkGlyphDigest* SkStrike::addGlyphAndDigest(SkGlyph* glyph) {
352 size_t index = fGlyphForIndex.size();
353 SkGlyphDigest digest = SkGlyphDigest{index, *glyph};
354 SkGlyphDigest* newDigest = fDigestForPackedGlyphID.set(digest);
355 fGlyphForIndex.push_back(glyph);
356 return newDigest;
357}
358
360 if (glyph->setImage(&fAlloc, fScalerContext.get())) {
361 fMemoryIncrease += glyph->imageSize();
362 }
363 return glyph->image() != nullptr;
364}
365
367 if (glyph->setPath(&fAlloc, fScalerContext.get())) {
368 fMemoryIncrease += glyph->path()->approximateBytesUsed();
369 }
370 return glyph->path() !=nullptr;
371}
372
374 if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
375 size_t increase = glyph->drawable()->approximateBytesUsed();
376 SkASSERT(increase > 0);
377 fMemoryIncrease += increase;
378 }
379 return glyph->drawable() != nullptr;
380}
381
382SkGlyph* SkStrike::mergeGlyphFromBuffer(SkReadBuffer& buffer) {
383 SkASSERT(buffer.isValid());
384 std::optional<SkGlyph> prototypeGlyph = SkGlyph::MakeFromBuffer(buffer);
385 if (!buffer.validate(prototypeGlyph.has_value())) {
386 return nullptr;
387 }
388
389 // Check if this glyph has already been seen.
390 SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(prototypeGlyph->getPackedID());
391 if (digestPtr != nullptr) {
392 return fGlyphForIndex[digestPtr->index()];
393 }
394
395 // This is the first time. Allocate a new glyph.
396 SkGlyph* glyph = fAlloc.make<SkGlyph>(prototypeGlyph.value());
397 fMemoryIncrease += sizeof(SkGlyph);
398 this->addGlyphAndDigest(glyph);
399 return glyph;
400}
401
402bool SkStrike::mergeGlyphAndImageFromBuffer(SkReadBuffer& buffer) {
403 SkASSERT(buffer.isValid());
404 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
405 if (!buffer.validate(glyph != nullptr)) {
406 return false;
407 }
408 fMemoryIncrease += glyph->addImageFromBuffer(buffer, &fAlloc);
409 return buffer.isValid();
410}
411
412bool SkStrike::mergeGlyphAndPathFromBuffer(SkReadBuffer& buffer) {
413 SkASSERT(buffer.isValid());
414 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
415 if (!buffer.validate(glyph != nullptr)) {
416 return false;
417 }
418 fMemoryIncrease += glyph->addPathFromBuffer(buffer, &fAlloc);
419 return buffer.isValid();
420}
421
422bool SkStrike::mergeGlyphAndDrawableFromBuffer(SkReadBuffer& buffer) {
423 SkASSERT(buffer.isValid());
424 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
425 if (!buffer.validate(glyph != nullptr)) {
426 return false;
427 }
428 fMemoryIncrease += glyph->addDrawableFromBuffer(buffer, &fAlloc);
429 return buffer.isValid();
430}
431
432SkSpan<const SkGlyph*> SkStrike::internalPrepare(
433 SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
434 const SkGlyph** cursor = results;
435 for (auto glyphID : glyphIDs) {
436 SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
437 if (pathDetail == kMetricsAndPath) {
438 this->prepareForPath(glyph);
439 }
440 *cursor++ = glyph;
441 }
442
443 return {results, glyphIDs.size()};
444}
445
446void SkStrike::updateMemoryUsage(size_t increase) {
447 if (increase > 0) {
448 // fRemoved and the cache's total memory are managed under the cache's lock. This allows
449 // them to be accessed under LRU operation.
450 SkAutoMutexExclusive lock{fStrikeCache->fLock};
451 fMemoryUsed += increase;
452 if (!fRemoved) {
453 fStrikeCache->fTotalMemoryUsed += increase;
454 }
455 }
456}
int count
Definition: FontMgrTest.cpp:50
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkScalarInvert(x)
Definition: SkScalar.h:73
static SkFontMetrics use_or_generate_metrics(const SkFontMetrics *metrics, SkScalerContext *context)
Definition: SkStrike.cpp:34
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
#define SK_SCOPED_CAPABILITY
#define SK_RELEASE_CAPABILITY(...)
#define SK_ACQUIRE(...)
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
size_t approximateBytesUsed()
Definition: SkDrawable.cpp:75
Slant slant() const
Definition: SkFontStyle.h:64
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
void setActionFor(skglyph::ActionType, SkGlyph *, sktext::StrikeForGPU *)
Definition: SkGlyph.cpp:634
int index() const
Definition: SkGlyph.h:338
skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const
Definition: SkGlyph.h:343
bool setPathHasBeenCalled() const
Definition: SkGlyph.h:486
size_t addPathFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:389
void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, SkScalar *array, int *count, SkArenaAlloc *alloc)
Definition: SkGlyph.cpp:547
void flattenMetrics(SkWriteBuffer &) const
Definition: SkGlyph.cpp:336
bool setDrawableHasBeenCalled() const
Definition: SkGlyph.h:495
size_t imageSize() const
Definition: SkGlyph.cpp:241
bool setImageHasBeenCalled() const
Definition: SkGlyph.h:459
size_t setMetricsAndImage(SkArenaAlloc *alloc, const SkGlyph &from)
Definition: SkGlyph.cpp:207
const SkPath * path() const
Definition: SkGlyph.cpp:284
SkMask::Format maskFormat() const
Definition: SkGlyph.h:500
bool setDrawable(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:310
bool setPath(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:266
void flattenPath(SkWriteBuffer &) const
Definition: SkGlyph.cpp:378
bool setImage(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:185
void flattenDrawable(SkWriteBuffer &) const
Definition: SkGlyph.cpp:414
size_t addImageFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:358
size_t addDrawableFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:425
void flattenImage(SkWriteBuffer &) const
Definition: SkGlyph.cpp:349
SkDrawable * drawable() const
Definition: SkGlyph.cpp:327
const void * image() const
Definition: SkGlyph.h:465
static std::optional< SkGlyph > MakeFromBuffer(SkReadBuffer &)
Definition: SkGlyph.cpp:95
Definition: SkPath.h:59
size_t approximateBytesUsed() const
Definition: SkPath.cpp:572
void getFontMetrics(SkFontMetrics *)
constexpr size_t size() const
Definition: SkSpan_impl.h:95
static void FlattenGlyphsByType(SkWriteBuffer &buffer, SkSpan< SkGlyph > images, SkSpan< SkGlyph > paths, SkSpan< SkGlyph > drawables)
Definition: SkStrike.cpp:87
void dump() const SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:277
const SkDrawable * mergeDrawable(SkGlyph *glyph, sk_sp< SkDrawable > drawable) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:199
void glyphIDsToDrawables(SkSpan< sktext::IDOrDrawable > idsOrDrawables) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:267
void dumpMemoryStatistics(SkTraceMemoryDump *dump) const SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:295
void unlock() override SK_RELEASE_CAPABILITY(fStrikeLock)
Definition: SkStrike.cpp:80
bool mergeFromBuffer(SkReadBuffer &buffer) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:117
~Monitor() SK_RELEASE_CAPABILITY()
Definition: SkStrike.cpp:67
SkSpan< const SkGlyph * > metrics(SkSpan< const SkGlyphID > glyphIDs, const SkGlyph *results[]) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:218
const SkPath * mergePath(SkGlyph *glyph, const SkPath *path, bool hairline) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:187
bool prepareForPath(SkGlyph *) override SK_REQUIRES(fStrikeLock)
Definition: SkStrike.cpp:366
void lock() override SK_ACQUIRE(fStrikeLock)
Definition: SkStrike.cpp:75
SkStrike(SkStrikeCache *strikeCache, const SkStrikeSpec &strikeSpec, std::unique_ptr< SkScalerContext > scaler, const SkFontMetrics *metrics, std::unique_ptr< SkStrikePinner > pinner)
Definition: SkStrike.cpp:45
SkSpan< const SkGlyph * > preparePaths(SkSpan< const SkGlyphID > glyphIDs, const SkGlyph *results[]) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:224
void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, SkGlyph *, SkScalar *array, int *count) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:212
void glyphIDsToPaths(SkSpan< sktext::IDOrPath > idsOrPaths) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:258
SkGlyph * mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph &fromGlyph) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:164
bool prepareForDrawable(SkGlyph *) override SK_REQUIRES(fStrikeLock)
Definition: SkStrike.cpp:373
Monitor(SkStrike *strike) SK_ACQUIRE(strike -> fStrikeLock) :fStrike
Definition: SkStrike.cpp:62
SkGlyph * glyph(SkGlyphDigest) SK_REQUIRES(fStrikeLock)
Definition: SkStrike.cpp:322
SkSpan< const SkGlyph * > prepareDrawables(SkSpan< const SkGlyphID > glyphIDs, const SkGlyph *results[]) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:243
bool prepareForImage(SkGlyph *glyph) override SK_REQUIRES(fStrikeLock)
Definition: SkStrike.cpp:359
SkSpan< const SkGlyph * > prepareImages(SkSpan< const SkPackedGlyphID > glyphIDs, const SkGlyph *results[]) SK_EXCLUDES(fStrikeLock)
Definition: SkStrike.cpp:230
SkGlyphDigest digestFor(skglyph::ActionType, SkPackedGlyphID) override SK_REQUIRES(fStrikeLock)
Definition: SkStrike.cpp:331
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
size_t size() const
Definition: SkString.h:131
const char * c_str() const
Definition: SkString.h:133
SkTypefaceID uniqueID() const
Definition: SkTypeface.h:101
void getFamilyName(SkString *name) const
Definition: SkTypeface.cpp:459
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
float SkScalar
Definition: extension.cpp:12
std::array< MockImage, 3 > images
Definition: mock_vulkan.cc:41
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
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
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
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
Definition: switches.h:126
const myers::Point & get(const myers::Segment &)
ActionType
Definition: SkGlyph.h:312
@ kDirectMask
Definition: SkGlyph.h:313
Definition: ref_ptr.h:256
const Scalar scale
static bool IsValidFormat(uint8_t format)
Definition: SkMask.h:46
void getSingleMatrix(SkMatrix *) const
SkTypefaceID fTypefaceID
SkString dump() const