76 auto named_color = [](
SkColor c) ->
const char* {
77 switch (c & 0xffffff) {
78 case 0x000000:
return "black";
79 case 0x000080:
return "navy";
80 case 0x0000ff:
return "blue";
81 case 0x008000:
return "green";
82 case 0x008080:
return "teal";
83 case 0x00ff00:
return "lime";
84 case 0x00ffff:
return "aqua";
85 case 0x800000:
return "maroon";
86 case 0x800080:
return "purple";
87 case 0x808000:
return "olive";
88 case 0x808080:
return "gray";
89 case 0xc0c0c0:
return "silver";
90 case 0xff0000:
return "red";
91 case 0xff00ff:
return "fuchsia";
92 case 0xffff00:
return "yellow";
93 case 0xffffff:
return "white";
100 if (
const auto* nc = named_color(
color)) {
111 uint8_t rl = r & 0xf;
113 uint8_t
gl = g & 0xf;
115 uint8_t bl =
b & 0xf;
116 if ((rh == rl) && (gh ==
gl) && (bh == bl)) {
128static const char* cap_map[] = {
141static const char* join_map[] = {
150 return join_map[
join];
172 tstr.
printf(
"matrix(%g %g %g %g %g %g)",
184 : fPaintServer(svg_color(
paint.getColor())) {}
204 for (
int i = 0;
i < 2;
i++) {
220 Rec* rec = reinterpret_cast<Rec*>(ctx);
223 total.postTranslate(rec->fPos->fX + rec->fOffset.fX,
224 rec->fPos->fY + rec->fOffset.fY);
225 rec->fPath->addPath(*path, total);
244 , fColorFilterCount(0) {}
265 uint32_t fGradientCount;
267 uint32_t fImageCount;
268 uint32_t fPatternCount;
269 uint32_t fColorFilterCount;
284 , fResourceBucket(nullptr) {
293 : fWriter(svgdev->fWriter.
get())
294 , fResourceBucket(bucket) {
297 Resources res = this->addResources(mc,
paint);
301 this->addPaint(
paint, res);
338 void addShaderResources(
const SkPaint&
paint, Resources* resources);
340 Resources* resources);
341 void addColorFilterResources(
const SkColorFilter& cf, Resources* resources);
343 Resources* resources);
345 void addPatternDef(
const SkBitmap& bm);
347 void addPaint(
const SkPaint&
paint,
const Resources& resources);
357void SkSVGDevice::AutoElement::addPaint(
const SkPaint&
paint,
const Resources& resources) {
362 if (
paint.getPathEffect() !=
nullptr) {
363 SkDebugf(
"Unsupported path effect in addPaint.");
367 static constexpr char kDefaultFill[] =
"black";
368 if (!resources.fPaintServer.equals(kDefaultFill)) {
379 if (!resources.fColorFilter.isEmpty()) {
380 this->
addAttribute(
"filter", resources.fColorFilter.c_str());
390 this->
addAttribute(
"vector-effect",
"non-scaling-stroke");
394 if (
const char* cap = svg_cap(
paint.getStrokeCap())) {
398 if (
const char*
join = svg_join(
paint.getStrokeJoin())) {
415Resources SkSVGDevice::AutoElement::addResources(
const MxCp& mc,
const SkPaint&
paint) {
416 Resources resources(
paint);
418 if (
paint.getShader()) {
419 AutoElement
defs(
"defs", fWriter);
421 this->addShaderResources(
paint, &resources);
428 this->addColorFilterResources(*cf, &resources);
435void SkSVGDevice::AutoElement::addGradientShaderResources(
const SkShader* shader,
437 Resources* resources) {
440 auto colorShader =
static_cast<const SkColorShader*
>(shader);
441 resources->fPaintServer = svg_color(colorShader->color());
455 grInfo.
fColors = grColors.get();
465 resources->fPaintServer =
466 SkStringPrintf(
"url(#%s)", addLinearGradientDef(grInfo, shader, localMatrix).c_str());
469void SkSVGDevice::AutoElement::addColorFilterResources(
const SkColorFilter& cf,
470 Resources* resources) {
471 SkString colorfilterID = fResourceBucket->addColorFilter();
473 AutoElement filterElement(
"filter", fWriter);
474 filterElement.addAttribute(
"id", colorfilterID);
475 filterElement.addAttribute(
"x",
"0%");
476 filterElement.addAttribute(
"y",
"0%");
477 filterElement.addAttribute(
"width",
"100%");
478 filterElement.addAttribute(
"height",
"100%");
488 AutoElement floodElement(
"feFlood", fWriter);
489 floodElement.addAttribute(
"flood-color", svg_color(filterColor));
490 floodElement.addAttribute(
"flood-opacity", svg_opacity(filterColor));
491 floodElement.addAttribute(
"result",
"flood");
496 AutoElement compositeElement(
"feComposite", fWriter);
497 compositeElement.addAttribute(
"in",
"flood");
498 compositeElement.addAttribute(
"operator",
"in");
501 resources->fColorFilter.printf(
"url(#%s)", colorfilterID.
c_str());
505 static constexpr uint8_t pngSig[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
506 return length >=
sizeof(pngSig) && !memcmp(bytes, pngSig,
sizeof(pngSig));
510 static constexpr uint8_t jpegSig[] = {0xFF, 0xD8, 0xFF};
511 return length >=
sizeof(jpegSig) && !memcmp(bytes, jpegSig,
sizeof(jpegSig));
518 static constexpr char jpgDataPrefix[] =
"data:image/jpeg;base64,";
519 static constexpr char pngDataPrefix[] =
"data:image/png;base64,";
523 const char* selectedPrefix = pngDataPrefix;
524 size_t selectedPrefixLength =
sizeof(pngDataPrefix);
529 selectedPrefix = jpgDataPrefix;
530 selectedPrefixLength =
sizeof(jpgDataPrefix);
552 memcpy(
dest, selectedPrefix, selectedPrefixLength);
558void SkSVGDevice::AutoElement::addImageShaderResources(
const SkShader* shader,
const SkPaint&
paint,
559 Resources* resources) {
573 for (
int i = 0;
i < 2;
i++) {
574 int imageDimension =
i == 0 ? imageSize.
width() : imageSize.
height();
581 patternDims[
i] =
"100%";
585 SkString patternID = fResourceBucket->addPattern();
587 AutoElement pattern(
"pattern", fWriter);
588 pattern.addAttribute(
"id", patternID);
589 pattern.addAttribute(
"patternUnits",
"userSpaceOnUse");
590 pattern.addAttribute(
"patternContentUnits",
"userSpaceOnUse");
591 pattern.addAttribute(
"width", patternDims[0]);
592 pattern.addAttribute(
"height", patternDims[1]);
593 pattern.addAttribute(
"x", 0);
594 pattern.addAttribute(
"y", 0);
597 SkString imageID = fResourceBucket->addImage();
598 AutoElement imageTag(
"image", fWriter);
599 imageTag.addAttribute(
"id", imageID);
600 imageTag.addAttribute(
"x", 0);
601 imageTag.addAttribute(
"y", 0);
602 imageTag.addAttribute(
"width",
image->
width());
604 imageTag.addAttribute(
"xlink:href",
static_cast<const char*
>(dataUri->
data()));
607 resources->fPaintServer.printf(
"url(#%s)", patternID.
c_str());
610void SkSVGDevice::AutoElement::addShaderResources(
const SkPaint&
paint, Resources* resources) {
616 shaderType == SkShaderBase::ShaderType::kGradientBase) {
617 this->addGradientShaderResources(shader,
paint, resources);
619 this->addImageShaderResources(shader,
paint, resources);
628 SkString id = fResourceBucket->addLinearGradient();
631 AutoElement gradient(
"linearGradient", fWriter);
633 gradient.addAttribute(
"id",
id);
634 gradient.addAttribute(
"gradientUnits",
"userSpaceOnUse");
635 gradient.addAttribute(
"x1",
info.fPoint[0].x());
636 gradient.addAttribute(
"y1",
info.fPoint[0].y());
637 gradient.addAttribute(
"x2",
info.fPoint[1].x());
638 gradient.addAttribute(
"y2",
info.fPoint[1].y());
641 this->addAttribute(
"gradientTransform", svg_transform(localMatrix));
645 for (
int i = 0;
i <
info.fColorCount; ++
i) {
650 AutoElement stop(
"stop", fWriter);
651 stop.addAttribute(
"offset",
info.fColorOffsets[
i]);
652 stop.addAttribute(
"stop-color", colorStr.c_str());
655 stop.addAttribute(
"stop-opacity", svg_opacity(
color));
667 this->addAttribute(
"x",
rect.x());
670 this->addAttribute(
"y",
rect.y());
673 this->addAttribute(
"width",
rect.width());
674 this->addAttribute(
"height",
rect.height());
683 this->addAttribute(
"font-size",
font.getSize());
692 this->addAttribute(
"font-style",
"italic");
694 this->addAttribute(
"font-style",
"oblique");
696 int weightIndex = (
SkTPin(style.
weight(), 100, 900) - 50) / 100;
697 if (weightIndex != 3) {
698 static constexpr const char* weights[] = {
699 "100",
"200",
"300",
"normal",
"400",
"500",
"600",
"bold",
"800",
"900"
701 this->addAttribute(
"font-weight", weights[weightIndex]);
703 int stretchIndex = style.
width() - 1;
704 if (stretchIndex != 4) {
705 static constexpr const char* stretches[] = {
706 "ultra-condensed",
"extra-condensed",
"condensed",
"semi-condensed",
708 "semi-expanded",
"expanded",
"extra-expanded",
"ultra-expanded"
710 this->addAttribute(
"font-stretch", stretches[stretchIndex]);
715 if (familyNameIter) {
716 while (familyNameIter->next(&familyString)) {
725 this->addAttribute(
"font-family", familyName);
730 std::unique_ptr<SkXMLWriter> writer,
736SkSVGDevice::SkSVGDevice(
const SkISize&
size, std::unique_ptr<SkXMLWriter> writer, uint32_t
flags)
740 , fWriter(
std::move(writer))
741 , fResourceBucket(new ResourceBucket)
746 fWriter->writeHeader();
749 fRootElement = std::make_unique<AutoElement>(
"svg", fWriter);
751 fRootElement->addAttribute(
"xmlns",
"http://www.w3.org/2000/svg");
752 fRootElement->addAttribute(
"xmlns:xlink",
"http://www.w3.org/1999/xlink");
753 fRootElement->addAttribute(
"width",
size.
width());
754 fRootElement->addAttribute(
"height",
size.
height());
757SkSVGDevice::~SkSVGDevice() {
759 while (!fClipStack.
empty()) {
770void SkSVGDevice::syncClipStack(
const SkClipStack& cs) {
777 while ((elem = iter.next()) && (rec_idx < fClipStack.
size())) {
785 while (fClipStack.
size() > rec_idx) {
792 AutoElement clip_path(
"clipPath", fWriter);
793 clip_path.addAttribute(
"id",
cid);
797 switch (
e->getDeviceSpaceType()) {
800 AutoElement
rect(
"rect", fWriter);
803 AutoElement
rect(
"rect", fWriter);
804 rect.addRectAttributes(
e->getDeviceSpaceRect());
808 const auto& rr =
e->getDeviceSpaceRRect();
809 const auto radii = rr.getSimpleRadii();
811 AutoElement
rrect(
"rect", fWriter);
812 rrect.addRectAttributes(rr.rect());
813 rrect.addAttribute(
"rx", radii.x());
814 rrect.addAttribute(
"ry", radii.y());
817 const auto&
p =
e->getDeviceSpacePath();
818 AutoElement
path(
"path", fWriter);
819 path.addPathAttributes(
p, this->pathEncoding());
821 path.addAttribute(
"clip-rule",
"evenodd");
834 const auto cid = define_clip(elem);
836 auto clip_grp = std::make_unique<AutoElement>(
"g", fWriter);
862 if (transformedRect.
isEmpty()) {
868 a.addAttribute(
"xlink:href", url.
c_str());
888 for (
size_t i = 0;
i <
count;
i += 2) {
890 path.lineTo(pts[
i+1]);
904 if (
paint.getPathEffect()) {
909 std::unique_ptr<AutoElement>
svg;
910 if (RequiresViewportReset(
paint)) {
911 svg = std::make_unique<AutoElement>(
"svg",
this, fResourceBucket.get(),
MxCp(
this),
paint);
912 svg->addRectAttributes(r);
918 rect.addAttribute(
"x", 0);
919 rect.addAttribute(
"y", 0);
920 rect.addAttribute(
"width",
"100%");
921 rect.addAttribute(
"height",
"100%");
923 rect.addRectAttributes(r);
928 if (
paint.getPathEffect()) {
941 if (
paint.getPathEffect()) {
951 if (
path.isInverseFillType()) {
952 SkDebugf(
"Inverse path fill type not yet implemented.");
961 if (path_paint->getPathEffect()) {
962 if (!pathIsMutable) {
963 pathPtr = &pathStorage;
972 path_paint.
writable()->setStrokeWidth(0);
975 path_paint.
writable()->setPathEffect(
nullptr);
979 AutoElement elem(
"path",
this, fResourceBucket.get(),
MxCp(
this), *path_paint);
1003 SkString svgImageData(
"data:image/png;base64,");
1004 svgImageData.append(b64Data.get(), b64Size);
1006 SkString imageID = fResourceBucket->addImage();
1008 AutoElement
defs(
"defs", fWriter);
1010 AutoElement
image(
"image", fWriter);
1011 image.addAttribute(
"id", imageID);
1014 image.addAttribute(
"xlink:href", svgImageData);
1019 AutoElement imageUse(
"use",
this, fResourceBucket.get(), mc,
paint);
1029 if (!
as_IB(
image)->getROPixels(
nullptr, &bm)) {
1043 drawBitmapCommon(
MxCp(&adjustedMatrix,
cs), bm,
paint);
1050 auto runSize = glyphRun.
runSize();
1053 runSize, unichars.
get());
1055 for (
size_t i = 0;
i < runSize; ++
i) {
1056 this->appendUnichar(unichars[
i], positions[
i]);
1062 const SkString&
posY()
const {
return fHasConstY ? fConstYStr : fPosYStr; }
1066 bool discardPos =
false;
1074 if (fLastCharWasWhitespace) {
1113 position += fOrigin;
1114 fPosXStr.
appendf(
"%.8g, ", position.
fX);
1115 fPosYStr.
appendf(
"%.8g, ", position.
fY);
1118 fConstYStr = fPosYStr;
1119 fConstY = position.
fY;
1131 bool fLastCharWasWhitespace =
true,
1135void SkSVGDevice::onDrawGlyphRunList(
SkCanvas* canvas,
1139 const auto draw_as_path =
1145 for (
auto& glyphRun : glyphRunList) {
1146 AddPath(glyphRun, glyphRunList.origin(), &
path);
1155 for (
auto& glyphRun : glyphRunList) {
1156 AutoElement elem(
"text",
this, fResourceBucket.get(), MxCp(
this),
paint);
1157 elem.addTextAttributes(glyphRun.
font());
1160 elem.addAttribute(
"x",
builder.posX());
1161 elem.addAttribute(
"y",
builder.posY());
static const int strokeWidth
static constexpr SkColor kColor
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SkColorGetR(color)
#define SkColorGetG(color)
constexpr SkAlpha SK_AlphaOPAQUE
#define SkColorGetA(color)
#define SkColorGetB(color)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkImage_Base * as_IB(SkImage *image)
static bool is_png(const void *bytes, size_t length)
sk_sp< SkData > AsDataUri(SkImage *image)
static sk_sp< SkData > encode(const SkBitmap &src)
static bool is_jpeg(const void *bytes, size_t length)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
SkShaderBase * as_SB(SkShader *shader)
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
constexpr int SkToInt(S x)
SVGTextBuilder(SkPoint origin, const sktext::GlyphRun &glyphRun)
const SkString & text() const
const SkString & posX() const
const SkString & posY() const
static const char * Link_Named_Dest_Key()
static const char * URL_Key()
@ kLines_PointMode
draw each pair of points as a line segment
@ kPolygon_PointMode
draw the array of points as a open polygon
@ kPoints_PointMode
draw each point separately
@ kPath
This element does not have geometry, but applies a shader to the clip.
@ kEmpty
This element makes the clip empty (regardless of previous elements).
@ kRect
This element combines a device space round-rect with the current clip.
@ kRRect
This element combines a device space path with the current clip.
uint32_t getGenID() const
void clipRect(const SkRect &, const SkMatrix &matrix, SkClipOp, bool doAA)
SkRect bounds(const SkIRect &deviceBounds) const
bool asAColorMode(SkColor *color, SkBlendMode *mode) const
static sk_sp< SkData > MakeUninitialized(size_t length)
const void * data() const
const SkMatrix & localToDevice() const
SkIRect getGlobalBounds() const
sk_sp< SkData > detachAsData()
static void GlyphsToUnichars(const SkFont &, const uint16_t glyphs[], int count, SkUnichar[])
void getPaths(const SkGlyphID glyphIDs[], int count, void(*glyphPathProc)(const SkPath *pathOrNull, const SkMatrix &mx, void *ctx), void *ctx) const
virtual bool isTextureBacked() const =0
sk_sp< SkData > refEncodedData() const
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
SkScalar getSkewY() const
SkScalar getTranslateY() const
SkScalar getSkewX() const
SkScalar getScaleX() const
SkScalar getScaleY() const
SkScalar getTranslateX() const
@ kPerspective_Mask
perspective SkMatrix
@ kTranslate_Mask
translation SkMatrix
@ kScale_Mask
scale SkMatrix
SkScalar getStrokeMiter() const
static constexpr int kCapCount
@ kStroke_Style
set to stroke geometry
@ kFill_Style
set to fill geometry
@ kStrokeAndFill_Style
sets to stroke and fill geometry
static constexpr int kJoinCount
@ kMiter_Join
extends to miter limit
static SkString ToSVGString(const SkPath &, PathEncoding=PathEncoding::Absolute)
static SkPath RRect(const SkRRect &, SkPathDirection dir=SkPathDirection::kCW)
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
SkPathFillType getFillType() const
static SkPath Oval(const SkRect &, SkPathDirection=SkPathDirection::kCW)
@ kRelativePathEncoding_Flag
@ kConvertTextToPaths_Flag
void addTextAttributes(const SkFont &)
void addAttribute(const char name[], int32_t val)
AutoElement(const char name[], SkSVGDevice *svgdev, ResourceBucket *bucket, const MxCp &mc, const SkPaint &paint)
void addAttribute(const char name[], const SkString &val)
void addAttribute(const char name[], const char val[])
void addText(const SkString &text)
AutoElement(const char name[], SkXMLWriter *writer)
void addPathAttributes(const SkPath &, SkParsePath::PathEncoding)
void addRectAttributes(const SkRect &)
void addAttribute(const char name[], SkScalar val)
AutoElement(const char name[], const std::unique_ptr< SkXMLWriter > &writer)
SkString addColorFilter()
SkString addLinearGradient()
void drawOval(const SkRect &oval, const SkPaint &paint) override
void drawPath(const SkPath &path, const SkPaint &paint, bool pathIsMutable=false) override
void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint &paint) override
void drawPaint(const SkPaint &paint) override
static sk_sp< SkDevice > Make(const SkISize &size, std::unique_ptr< SkXMLWriter >, uint32_t flags)
void drawVertices(const SkVertices *, sk_sp< SkBlender >, const SkPaint &, bool) override
void drawAnnotation(const SkRect &rect, const char key[], SkData *value) override
void drawRRect(const SkRRect &rr, const SkPaint &paint) override
void drawImageRect(const SkImage *image, const SkRect *src, const SkRect &dst, const SkSamplingOptions &, const SkPaint &paint, SkCanvas::SrcRectConstraint constraint) override
void drawMesh(const SkMesh &, sk_sp< SkBlender >, const SkPaint &) override
void drawRect(const SkRect &r, const SkPaint &paint) override
virtual GradientType asGradient(GradientInfo *info=nullptr, SkMatrix *localMatrix=nullptr) const
virtual ShaderType type() const =0
SkImage * isAImage(SkMatrix *localMatrix, SkTileMode xy[2]) const
void appendUnichar(SkUnichar uni)
void printf(const char format[],...) SK_PRINTF_LIKE(2
void append(const char text[])
void appendScalar(SkScalar value)
const char * c_str() const
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
LocalizedStrings * createFamilyNameIterator() const
SkFontStyle fontStyle() const
void addText(const char text[], size_t length)
void addScalarAttribute(const char name[], SkScalar value)
void addS32Attribute(const char name[], int32_t value)
void addAttribute(const char name[], const char value[])
void startElement(const char elem[])
bool contains(const T &item) const
const SkFont & font() const
SkSpan< const SkGlyphID > glyphsIDs() const
SkSpan< const SkPoint > positions() const
FlutterSemanticsFlag flags
static constexpr skcms_TransferFunction kLinear
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
sk_sp< const SkImage > image
sk_sp< SkBlender > blender SkRect rect
SkSamplingOptions sampling
static bool isWhitespace(int x)
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 mode
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
font
Font Metadata and Metrics.
const myers::Point & get(const myers::Segment &)
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
static SkString join(const CommandLineFlags::StringArray &)
static size_t EncodedSize(size_t srcDataLength)
static size_t Encode(const void *src, size_t length, void *dst, const char *encode=nullptr)
constexpr int32_t height() const
constexpr int32_t width() const
constexpr int32_t width() const
constexpr int32_t height() const
static SkRect Make(const SkISize &size)
constexpr float centerX() const
constexpr float height() const
constexpr float centerY() const
constexpr float width() const
static constexpr SkRect MakeWH(float w, float h)
const SkClipStack * fClipStack
MxCp(SkSVGDevice *device)
MxCp(const SkMatrix *mx, const SkClipStack *cs)
SkColor * fColors
The colors in the gradient.
int fColorCount
In-out parameter, specifies passed size.
SkScalar * fColorOffsets
The unit offset for color transitions.