• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "include/core/SkColor.h"
9 #include "include/core/SkOpenTypeSVGDecoder.h"
10 #include "include/core/SkSpan.h"
11 #include "include/core/SkStream.h"
12 #include "include/core/SkTypes.h"
13 #include "include/utils/SkBase64.h"
14 #include "modules/skresources/include/SkResources.h"
15 #include "modules/svg/include/SkSVGDOM.h"
16 #include "modules/svg/include/SkSVGNode.h"
17 #include "modules/svg/include/SkSVGOpenTypeSVGDecoder.h"
18 #include "modules/svg/include/SkSVGRenderContext.h"
19 #include "modules/svg/include/SkSVGSVG.h"
20 #include "modules/svg/include/SkSVGUse.h"
21 #include "src/core/SkEnumerate.h"
22 
23 #include <memory>
24 
25 namespace {
26 class DataResourceProvider final : public skresources::ResourceProvider {
27 public:
Make()28     static sk_sp<skresources::ResourceProvider> Make() {
29         return sk_sp<skresources::ResourceProvider>(new DataResourceProvider());
30     }
31 
loadImageAsset(const char rpath[],const char rname[],const char rid[]) const32     sk_sp<skresources::ImageAsset> loadImageAsset(const char rpath[],
33                                                   const char rname[],
34                                                   const char rid[]) const override {
35         if (auto data = decode_datauri("data:image/", rname)) {
36             return skresources::MultiFrameImageAsset::Make(std::move(data));
37         }
38         return nullptr;
39     }
40 
41 private:
42     DataResourceProvider() = default;
43 
decode_datauri(const char prefix[],const char uri[])44     static sk_sp<SkData> decode_datauri(const char prefix[], const char uri[]) {
45         // We only handle B64 encoded image dataURIs: data:image/<type>;base64,<data>
46         // (https://en.wikipedia.org/wiki/Data_URI_scheme)
47         static constexpr char kDataURIEncodingStr[] = ";base64,";
48 
49         const size_t prefixLen = strlen(prefix);
50         if (strncmp(uri, prefix, prefixLen) != 0) {
51             return nullptr;
52         }
53 
54         const char* encoding = strstr(uri + prefixLen, kDataURIEncodingStr);
55         if (!encoding) {
56             return nullptr;
57         }
58 
59         const char* b64Data = encoding + std::size(kDataURIEncodingStr) - 1;
60         size_t b64DataLen = strlen(b64Data);
61         size_t dataLen;
62         if (SkBase64::Decode(b64Data, b64DataLen, nullptr, &dataLen) != SkBase64::kNoError) {
63             return nullptr;
64         }
65 
66         sk_sp<SkData> data = SkData::MakeUninitialized(dataLen);
67         void* rawData = data->writable_data();
68         if (SkBase64::Decode(b64Data, b64DataLen, rawData, &dataLen) != SkBase64::kNoError) {
69             return nullptr;
70         }
71 
72         return data;
73     }
74 
75     using INHERITED = ResourceProvider;
76 };
77 }  // namespace
78 
SkSVGOpenTypeSVGDecoder(sk_sp<SkSVGDOM> skSvg,size_t approximateSize)79 SkSVGOpenTypeSVGDecoder::SkSVGOpenTypeSVGDecoder(sk_sp<SkSVGDOM> skSvg, size_t approximateSize)
80     : fSkSvg(std::move(skSvg))
81     , fApproximateSize(approximateSize)
82 {}
83 
84 SkSVGOpenTypeSVGDecoder::~SkSVGOpenTypeSVGDecoder() = default;
85 
Make(const uint8_t * svg,size_t svgLength)86 std::unique_ptr<SkOpenTypeSVGDecoder> SkSVGOpenTypeSVGDecoder::Make(const uint8_t* svg,
87                                                                     size_t svgLength) {
88     std::unique_ptr<SkStreamAsset> stream = SkMemoryStream::MakeDirect(svg, svgLength);
89     if (!stream) {
90         return nullptr;
91     }
92     SkSVGDOM::Builder builder;
93     builder.setResourceProvider(DataResourceProvider::Make());
94     sk_sp<SkSVGDOM> skSvg = builder.make(*stream);
95     if (!skSvg) {
96         return nullptr;
97     }
98     return std::unique_ptr<SkOpenTypeSVGDecoder>(
99         new SkSVGOpenTypeSVGDecoder(std::move(skSvg), svgLength));
100 }
101 
approximateSize()102 size_t SkSVGOpenTypeSVGDecoder::approximateSize() {
103     // TODO
104     return fApproximateSize;
105 }
106 
render(SkCanvas & canvas,int upem,SkGlyphID glyphId,SkColor foregroundColor,SkSpan<SkColor> palette)107 bool SkSVGOpenTypeSVGDecoder::render(SkCanvas& canvas, int upem, SkGlyphID glyphId,
108                                      SkColor foregroundColor, SkSpan<SkColor> palette) {
109     SkSize emSize = SkSize::Make(SkScalar(upem), SkScalar(upem));
110     fSkSvg->setContainerSize(emSize);
111 
112     SkSVGPresentationContext pctx;
113     pctx.fInherited.fColor.set(foregroundColor);
114 
115     SkTHashMap<SkString, SkSVGColorType> namedColors;
116     if (palette.size()) {
117         for (auto&& [i, color] : SkMakeEnumerate(palette)) {
118             constexpr const size_t colorStringLen = sizeof("color") - 1;
119             char colorIdString[colorStringLen + kSkStrAppendU32_MaxSize + 1] = "color";
120             *SkStrAppendU32(colorIdString + colorStringLen, i) = 0;
121 
122             namedColors.set(SkString(colorIdString), color);
123         }
124         pctx.fNamedColors = &namedColors;
125     }
126 
127     constexpr const size_t glyphStringLen = sizeof("glyph") - 1;
128     char glyphIdString[glyphStringLen + kSkStrAppendU32_MaxSize + 1] = "glyph";
129     *SkStrAppendU32(glyphIdString + glyphStringLen, glyphId) = 0;
130 
131     fSkSvg->renderNode(&canvas, pctx, glyphIdString);
132     return true;
133 }
134