Flutter Engine
The Flutter Engine
SkSVGOpenTypeSVGDecoder.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google Inc.
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
13#include "include/core/SkSpan.h"
23#include "src/base/SkBase64.h"
25
26#include <memory>
27
28using namespace skia_private;
29
30namespace {
31class DataResourceProvider final : public skresources::ResourceProvider {
32public:
34 return sk_sp<skresources::ResourceProvider>(new DataResourceProvider());
35 }
36
38 const char rname[],
39 const char rid[]) const override {
40 if (auto data = decode_datauri("data:image/", rname)) {
41 std::unique_ptr<SkCodec> codec = nullptr;
42 if (SkPngDecoder::IsPng(data->bytes(), data->size())) {
43 codec = SkPngDecoder::Decode(data, nullptr);
44 } else if (SkJpegDecoder::IsJpeg(data->bytes(), data->size())) {
45 codec = SkJpegDecoder::Decode(data, nullptr);
46 } else {
47 // The spec says only JPEG or PNG should be used to encode the embedded data.
48 // https://learn.microsoft.com/en-us/typography/opentype/spec/svg#svg-capability-requirements-and-restrictions
49 SkDEBUGFAIL("Unsupported codec");
50 return nullptr;
51 }
52 if (!codec) {
53 return nullptr;
54 }
55 return skresources::MultiFrameImageAsset::Make(std::move(codec));
56 }
57 return nullptr;
58 }
59
60private:
61 DataResourceProvider() = default;
62
63 static sk_sp<SkData> decode_datauri(const char prefix[], const char uri[]) {
64 // We only handle B64 encoded image dataURIs: data:image/<type>;base64,<data>
65 // (https://en.wikipedia.org/wiki/Data_URI_scheme)
66 static constexpr char kDataURIEncodingStr[] = ";base64,";
67
68 const size_t prefixLen = strlen(prefix);
69 if (strncmp(uri, prefix, prefixLen) != 0) {
70 return nullptr;
71 }
72
73 const char* encoding = strstr(uri + prefixLen, kDataURIEncodingStr);
74 if (!encoding) {
75 return nullptr;
76 }
77
78 const char* b64Data = encoding + std::size(kDataURIEncodingStr) - 1;
79 size_t b64DataLen = strlen(b64Data);
80 size_t dataLen;
81 if (SkBase64::Decode(b64Data, b64DataLen, nullptr, &dataLen) != SkBase64::kNoError) {
82 return nullptr;
83 }
84
86 void* rawData = data->writable_data();
87 if (SkBase64::Decode(b64Data, b64DataLen, rawData, &dataLen) != SkBase64::kNoError) {
88 return nullptr;
89 }
90
91 return data;
92 }
93
95};
96} // namespace
97
98SkSVGOpenTypeSVGDecoder::SkSVGOpenTypeSVGDecoder(sk_sp<SkSVGDOM> skSvg, size_t approximateSize)
99 : fSkSvg(std::move(skSvg))
100 , fApproximateSize(approximateSize)
101{}
102
104
105std::unique_ptr<SkOpenTypeSVGDecoder> SkSVGOpenTypeSVGDecoder::Make(const uint8_t* svg,
106 size_t svgLength) {
107 std::unique_ptr<SkStreamAsset> stream = SkMemoryStream::MakeDirect(svg, svgLength);
108 if (!stream) {
109 return nullptr;
110 }
112 builder.setResourceProvider(DataResourceProvider::Make());
113 // We shouldn't need to set this builder's font manager or shaping utils because hopefully
114 // the SVG we are decoding doesn't itself have <text> tags.
115 sk_sp<SkSVGDOM> skSvg = builder.make(*stream);
116 if (!skSvg) {
117 return nullptr;
118 }
119 return std::unique_ptr<SkOpenTypeSVGDecoder>(
120 new SkSVGOpenTypeSVGDecoder(std::move(skSvg), svgLength));
121}
122
124 // TODO
125 return fApproximateSize;
126}
127
128bool SkSVGOpenTypeSVGDecoder::render(SkCanvas& canvas, int upem, SkGlyphID glyphId,
129 SkColor foregroundColor, SkSpan<SkColor> palette) {
130 SkSize emSize = SkSize::Make(SkScalar(upem), SkScalar(upem));
131 fSkSvg->setContainerSize(emSize);
132
134 pctx.fInherited.fColor.set(foregroundColor);
135
137 if (!palette.empty()) {
138 for (auto&& [i, color] : SkMakeEnumerate(palette)) {
139 constexpr const size_t colorStringLen = sizeof("color") - 1;
140 char colorIdString[colorStringLen + kSkStrAppendU32_MaxSize + 1] = "color";
141 *SkStrAppendU32(colorIdString + colorStringLen, i) = 0;
142
143 namedColors.set(SkString(colorIdString), color);
144 }
145 pctx.fNamedColors = &namedColors;
146 }
147
148 constexpr const size_t glyphStringLen = sizeof("glyph") - 1;
149 char glyphIdString[glyphStringLen + kSkStrAppendU32_MaxSize + 1] = "glyph";
150 *SkStrAppendU32(glyphIdString + glyphStringLen, glyphId) = 0;
151
152 fSkSvg->renderNode(&canvas, pctx, glyphIdString);
153 return true;
154}
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkEnumerate< Iter > SkMakeEnumerate(C &c)
Definition: SkEnumerate.h:102
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
static constexpr int kSkStrAppendU32_MaxSize
Definition: SkString.h:84
char * SkStrAppendU32(char buffer[], uint32_t)
Definition: SkString.cpp:100
uint16_t SkGlyphID
Definition: SkTypes.h:179
skresources::ResourceProvider ResourceProvider
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
static std::unique_ptr< SkMemoryStream > MakeDirect(const void *data, size_t length)
Definition: SkStream.cpp:310
void renderNode(SkCanvas *, SkSVGPresentationContext &, const char *id) const
Definition: SkSVGDOM.cpp:476
void setContainerSize(const SkSize &)
Definition: SkSVGDOM.cpp:497
~SkSVGOpenTypeSVGDecoder() override
static std::unique_ptr< SkOpenTypeSVGDecoder > Make(const uint8_t *svg, size_t svgLength)
bool render(SkCanvas &, int upem, SkGlyphID glyphId, SkColor foregroundColor, SkSpan< SkColor > palette) override
void set(SkSVGPropertyState state)
Definition: SkSVGTypes.h:70
constexpr bool empty() const
Definition: SkSpan_impl.h:96
V * set(K key, V val)
Definition: SkTHash.h:487
static sk_sp< MultiFrameImageAsset > Make(sk_sp< SkData >, ImageDecodeStrategy=ImageDecodeStrategy::kLazyDecode)
virtual sk_sp< ImageAsset > loadImageAsset(const char[], const char[], const char[]) const
Definition: SkResources.h:165
DlColor color
float SkScalar
Definition: extension.cpp:12
SK_API bool IsJpeg(const void *, size_t)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
SK_API bool IsPng(const void *, size_t)
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
Definition: switches.h:259
static sk_sp< SkData > decode_datauri(const char prefix[], const char uri[])
Definition: ref_ptr.h:256
static Error Decode(const void *src, size_t srcLength, void *dst, size_t *dstLength)
Definition: SkBase64.cpp:37
@ kNoError
Definition: SkBase64.h:16
SkSVGProperty< SkSVGColorType, true > fColor
SkSVGPresentationAttributes fInherited
const skia_private::THashMap< SkString, SkSVGColorType > * fNamedColors
Definition: SkSize.h:52
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
const char * svg
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63