1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "svg_decoder.h"
17 
18 #include <sstream>
19 #include <thread>
20 #include "include/core/SkBitmap.h"
21 #include "include/core/SkCanvas.h"
22 #include "include/core/SkImageInfo.h"
23 #include "image_trace.h"
24 #include "image_log.h"
25 #include "image_utils.h"
26 #include "media_errors.h"
27 #include "securec.h"
28 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
29 #include "surface_buffer.h"
30 #endif
31 
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
34 
35 #undef LOG_TAG
36 #define LOG_TAG "SvgDecoder"
37 
38 namespace OHOS {
39 namespace ImagePlugin {
40 using namespace MultimediaPlugin;
41 using namespace Media;
42 namespace {
43 constexpr uint32_t SVG_IMAGE_NUM = 1;
44 constexpr uint32_t SVG_BYTES_PER_PIXEL = 4;
45 constexpr uint32_t SVG_COLOR_ATTR_WIDTH = 6;
46 constexpr uint32_t SVG_COLOR_MASK = 0xFFFFFF;
47 const std::string SVG_FILL_COLOR_ATTR = "fill";
48 const std::string SVG_STROKE_COLOR_ATTR = "stroke";
49 static constexpr uint32_t DEFAULT_RESIZE_PERCENTAGE = 100;
50 static constexpr float FLOAT_HALF = 0.5f;
51 
Float2UInt32(float val)52 static inline uint32_t Float2UInt32(float val)
53 {
54     return static_cast<uint32_t>(val + FLOAT_HALF);
55 }
56 
57 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
AllocShareBufferInner(DecodeContext & context,uint64_t byteCount)58 bool AllocShareBufferInner(DecodeContext &context, uint64_t byteCount)
59 {
60     uint32_t id = context.pixelmapUniqueId_;
61     std::stringstream sstream;
62     sstream << "SVG RawData, uniqueId: " << std::this_thread::get_id() << '_' << std::to_string(getpid()) <<
63         '_' << std::to_string(id);
64     std::string name = sstream.str();
65     int fd = AshmemCreate(name.c_str(), byteCount);
66     if (fd < 0) {
67         IMAGE_LOGE("[AllocShareBuffer] create fail");
68         return false;
69     }
70 
71     int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
72     if (result < 0) {
73         IMAGE_LOGE("[AllocShareBuffer] set fail");
74         ::close(fd);
75         return false;
76     }
77 
78     void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
79     if (ptr == MAP_FAILED) {
80         IMAGE_LOGE("[AllocShareBuffer] map fail");
81         ::close(fd);
82         return false;
83     }
84 
85     context.pixelsBuffer.buffer = ptr;
86     void *fdBuffer = new int32_t();
87     if (fdBuffer == nullptr) {
88         IMAGE_LOGE("[AllocShareBuffer] new fdBuffer fail");
89         ::munmap(ptr, byteCount);
90         ::close(fd);
91         context.pixelsBuffer.buffer = nullptr;
92         return false;
93     }
94 
95     *static_cast<int32_t *>(fdBuffer) = fd;
96     context.pixelsBuffer.context = fdBuffer;
97     context.pixelsBuffer.bufferSize = byteCount;
98     context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
99     context.freeFunc = nullptr;
100 
101     IMAGE_LOGD("[AllocShareBuffer] OUT");
102     return true;
103 }
104 #endif
105 
AllocShareBuffer(DecodeContext & context,uint64_t byteCount)106 bool AllocShareBuffer(DecodeContext &context, uint64_t byteCount)
107 {
108     IMAGE_LOGD("[AllocShareBuffer] IN byteCount=%{public}llu",
109         static_cast<unsigned long long>(byteCount));
110 
111     if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
112         IMAGE_LOGE("[AllocShareBuffer] pixelmap buffer size %{public}llu out of max size",
113             static_cast<unsigned long long>(byteCount));
114         return false;
115     }
116 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
117     return AllocShareBufferInner(context, byteCount);
118 #else
119     IMAGE_LOGE("[AllocShareBuffer] Not support Ashmem!");
120     return false;
121 #endif
122 }
123 
124 // LCOV_EXCL_START
AllocDmaBuffer(DecodeContext & context,uint64_t byteCount,SkSize & svgSize)125 bool AllocDmaBuffer(DecodeContext &context, uint64_t byteCount, SkSize &svgSize)
126 {
127     IMAGE_LOGD("[AllocDmaBuffer] IN byteCount=%{public}llu",
128         static_cast<unsigned long long>(byteCount));
129 
130     if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
131         IMAGE_LOGE("[AllocDmaBuffer] pixelmap buffer size %{public}llu out of max size",
132             static_cast<unsigned long long>(byteCount));
133         return false;
134     }
135 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
136     sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
137     BufferRequestConfig requestConfig = {
138         .width = svgSize.width(),
139         .height = svgSize.height(),
140         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
141         .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
142         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
143         .timeout = 0,
144         .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
145         .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
146     };
147     GSError ret = sb->Alloc(requestConfig);
148     if (ret != GSERROR_OK) {
149         IMAGE_LOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
150         return false;
151     }
152     void* nativeBuffer = sb.GetRefPtr();
153     int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
154     if (err != OHOS::GSERROR_OK) {
155         IMAGE_LOGE("NativeBufferReference failed");
156         return false;
157     }
158 
159     context.pixelsBuffer.buffer = sb->GetVirAddr();
160     context.pixelsBuffer.context = nativeBuffer;
161     context.pixelsBuffer.bufferSize = byteCount;
162     context.allocatorType = AllocatorType::DMA_ALLOC;
163     context.freeFunc = nullptr;
164 
165     IMAGE_LOGD("[AllocDmaBuffer] OUT");
166     return true;
167 #else
168     IMAGE_LOGE("[AllocDmaBuffer] Not support dma!");
169     return false;
170 #endif
171 }
172 
AllocHeapBuffer(DecodeContext & context,uint64_t byteCount)173 bool AllocHeapBuffer(DecodeContext &context, uint64_t byteCount)
174 {
175     IMAGE_LOGD("[AllocHeapBuffer] IN byteCount=%{public}llu",
176         static_cast<unsigned long long>(byteCount));
177 
178     if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
179         IMAGE_LOGE("[AllocHeapBuffer] pixelmap buffer size %{public}llu out of max size",
180             static_cast<unsigned long long>(byteCount));
181         return false;
182     }
183 
184     auto outputBuffer = malloc(byteCount);
185     if (outputBuffer == nullptr) {
186         IMAGE_LOGE("[AllocHeapBuffer] alloc buffer size:[%{public}llu] failed.",
187             static_cast<unsigned long long>(byteCount));
188         return false;
189     }
190 
191     if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
192         IMAGE_LOGE("[AllocHeapBuffer] memset buffer failed.");
193         free(outputBuffer);
194         outputBuffer = nullptr;
195         return false;
196     }
197 
198     context.pixelsBuffer.buffer = outputBuffer;
199     context.pixelsBuffer.bufferSize = byteCount;
200     context.pixelsBuffer.context = nullptr;
201     context.allocatorType = AllocatorType::HEAP_ALLOC;
202     context.freeFunc = nullptr;
203 
204     IMAGE_LOGD("[AllocHeapBuffer] OUT");
205     return true;
206 }
207 // LCOV_EXCL_STOP
208 
MakeImageInfo(const PixelDecodeOptions & opts)209 SkImageInfo MakeImageInfo(const PixelDecodeOptions &opts)
210 {
211     int width = opts.desiredSize.width;
212     int height = opts.desiredSize.height;
213     SkColorType colorType = SkColorType::kRGBA_8888_SkColorType;
214     SkAlphaType alphaType = SkAlphaType::kPremul_SkAlphaType;
215     return SkImageInfo::Make(width, height, colorType, alphaType);
216 }
217 } // namespace
218 
SvgDecoder()219 SvgDecoder::SvgDecoder()
220 {
221     IMAGE_LOGD("[Create] IN");
222 
223     IMAGE_LOGD("[Create] OUT");
224 }
225 
~SvgDecoder()226 SvgDecoder::~SvgDecoder()
227 {
228     IMAGE_LOGD("[Release] IN");
229 
230     Reset();
231 
232     IMAGE_LOGD("[Release] OUT");
233 }
234 
SetSource(InputDataStream & sourceStream)235 void SvgDecoder::SetSource(InputDataStream &sourceStream)
236 {
237     IMAGE_LOGD("[SetSource] IN");
238 
239     Reset();
240 
241     inputStreamPtr_ = &sourceStream;
242     state_ = SvgDecodingState::SOURCE_INITED;
243 
244     IMAGE_LOGD("[SetSource] OUT");
245 }
246 
Reset()247 void SvgDecoder::Reset()
248 {
249     IMAGE_LOGD("[Reset] IN");
250 
251     state_ = SvgDecodingState::UNDECIDED;
252 
253     if (svgDom_) {
254         svgDom_->setContainerSize(svgSize_);
255     }
256 
257     svgDom_ = nullptr;
258     svgStream_ = nullptr;
259     inputStreamPtr_ = nullptr;
260 
261     svgSize_.setEmpty();
262 
263     PixelDecodeOptions opts;
264     opts_ = opts;
265 
266     IMAGE_LOGD("[Reset] OUT");
267 }
268 
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)269 uint32_t SvgDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
270 {
271     if (index >= SVG_IMAGE_NUM) {
272         IMAGE_LOGE("[SetDecodeOptions] decode image index[%{public}u], out of range[%{public}u].",
273             index, SVG_IMAGE_NUM);
274         return Media::ERR_IMAGE_INVALID_PARAMETER;
275     }
276 
277     IMAGE_LOGD("[SetDecodeOptions] IN index=%{public}u, pixelFormat=%{public}d, alphaType=%{public}d, "
278         "colorSpace=%{public}d, size=(%{public}u, %{public}u), state=%{public}d", index,
279         static_cast<int32_t>(opts.desiredPixelFormat), static_cast<int32_t>(opts.desireAlphaType),
280         static_cast<int32_t>(opts.desiredColorSpace), opts.desiredSize.width, opts.desiredSize.height, state_);
281 
282     if (state_ < SvgDecodingState::SOURCE_INITED) {
283         IMAGE_LOGE("[SetDecodeOptions] set decode options failed for state %{public}d.", state_);
284         return Media::ERR_MEDIA_INVALID_OPERATION;
285     }
286 
287     if (state_ >= SvgDecodingState::IMAGE_DECODING) {
288         state_ = SvgDecodingState::SOURCE_INITED;
289     }
290 
291     if (state_ < SvgDecodingState::BASE_INFO_PARSED) {
292         uint32_t ret = DoDecodeHeader();
293         if (ret != Media::SUCCESS) {
294             IMAGE_LOGE("[SetDecodeOptions] decode header error on set decode options, ret:%{public}u.", ret);
295             state_ = SvgDecodingState::BASE_INFO_PARSING;
296             return ret;
297         }
298 
299         state_ = SvgDecodingState::BASE_INFO_PARSED;
300     }
301 
302     // only state SvgDecodingState::BASE_INFO_PARSED can go here.
303     uint32_t ret = DoSetDecodeOptions(index, opts, info);
304     if (ret != Media::SUCCESS) {
305         IMAGE_LOGE("[SetDecodeOptions] do set decode options failed, ret:%{public}u.", ret);
306         state_ = SvgDecodingState::BASE_INFO_PARSING;
307         return ret;
308     }
309 
310     state_ = SvgDecodingState::IMAGE_DECODING;
311 
312     IMAGE_LOGD("[SetDecodeOptions] OUT");
313     return Media::SUCCESS;
314 }
315 
Decode(uint32_t index,DecodeContext & context)316 uint32_t SvgDecoder::Decode(uint32_t index, DecodeContext &context)
317 {
318     ImageTrace imageTrace("SvgDecoder::Decode, index:%u", index);
319     if (index >= SVG_IMAGE_NUM) {
320         IMAGE_LOGE("[Decode] decode image index[%{public}u], out of range[%{public}u].",
321             index, SVG_IMAGE_NUM);
322         return Media::ERR_IMAGE_INVALID_PARAMETER;
323     }
324 
325     IMAGE_LOGD("[Decode] IN index=%{public}u", index);
326 
327     if (state_ < SvgDecodingState::IMAGE_DECODING) {
328         IMAGE_LOGE("[Decode] decode failed for state %{public}d.", state_);
329         return Media::ERR_MEDIA_INVALID_OPERATION;
330     }
331 
332     uint32_t ret = DoDecode(index, context);
333     if (ret == Media::SUCCESS) {
334         IMAGE_LOGD("[Decode] success.");
335         state_ = SvgDecodingState::IMAGE_DECODED;
336     } else {
337         IMAGE_LOGE("[Decode] fail, ret=%{public}u", ret);
338         state_ = SvgDecodingState::IMAGE_ERROR;
339     }
340 
341     IMAGE_LOGD("[Decode] OUT ret=%{public}u", ret);
342     return ret;
343 }
344 
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)345 uint32_t SvgDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
346 {
347     // currently not support increment decode
348     return ERR_IMAGE_DATA_UNSUPPORT;
349 }
350 
351 // need decode all frame to get total number.
GetTopLevelImageNum(uint32_t & num)352 uint32_t SvgDecoder::GetTopLevelImageNum(uint32_t &num)
353 {
354     num = SVG_IMAGE_NUM;
355     return Media::SUCCESS;
356 }
357 
358 // return background size but not specific frame size, cause of frame drawing on background.
GetImageSize(uint32_t index,Size & size)359 uint32_t SvgDecoder::GetImageSize(uint32_t index, Size &size)
360 {
361     if (index >= SVG_IMAGE_NUM) {
362         IMAGE_LOGE("[GetImageSize] decode image index[%{public}u], out of range[%{public}u].",
363             index, SVG_IMAGE_NUM);
364         return Media::ERR_IMAGE_INVALID_PARAMETER;
365     }
366 
367     IMAGE_LOGD("[GetImageSize] IN index=%{public}u", index);
368 
369     if (state_ < SvgDecodingState::SOURCE_INITED) {
370         IMAGE_LOGE("[GetImageSize] get image size failed for state %{public}d.", state_);
371         return ERR_MEDIA_INVALID_OPERATION;
372     }
373 
374     if (state_ >= SvgDecodingState::BASE_INFO_PARSED) {
375         DoGetImageSize(index, size);
376         IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
377         return Media::SUCCESS;
378     }
379 
380     // only state SvgDecodingState::SOURCE_INITED and SvgDecodingState::BASE_INFO_PARSING can go here.
381     uint32_t ret = DoDecodeHeader();
382     if (ret != Media::SUCCESS) {
383         IMAGE_LOGE("[GetImageSize] decode header error on get image size, ret:%{public}u.", ret);
384         state_ = SvgDecodingState::BASE_INFO_PARSING;
385         return ret;
386     }
387 
388     ret = DoGetImageSize(index, size);
389     if (ret != Media::SUCCESS) {
390         IMAGE_LOGE("[GetImageSize] do get image size failed, ret:%{public}u.", ret);
391         state_ = SvgDecodingState::BASE_INFO_PARSING;
392         return ret;
393     }
394 
395     state_ = SvgDecodingState::BASE_INFO_PARSED;
396 
397     IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
398     return Media::SUCCESS;
399 }
400 
AllocBuffer(DecodeContext & context)401 bool SvgDecoder::AllocBuffer(DecodeContext &context)
402 {
403     IMAGE_LOGD("[AllocBuffer] IN");
404 
405     if (svgDom_ == nullptr) {
406         IMAGE_LOGE("[AllocBuffer] DOM is null.");
407         return false;
408     }
409 
410     bool ret = true;
411     if (context.pixelsBuffer.buffer == nullptr) {
412         auto svgSize = svgDom_->containerSize();
413         if (svgSize.isEmpty()) {
414             IMAGE_LOGE("[AllocBuffer] size is empty.");
415             return false;
416         }
417         uint32_t width = Float2UInt32(svgSize.width());
418         uint32_t height = Float2UInt32(svgSize.height());
419         uint64_t byteCount = static_cast<uint64_t>(width) * height * SVG_BYTES_PER_PIXEL;
420         if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
421             ret = AllocShareBuffer(context, byteCount);
422         } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
423             ret = AllocDmaBuffer(context, byteCount, svgSize);
424         } else {
425             ret = AllocHeapBuffer(context, byteCount);
426         }
427     }
428 
429     IMAGE_LOGD("[AllocBuffer] OUT ret=%{public}d", ret);
430     return ret;
431 }
432 
BuildStream()433 bool SvgDecoder::BuildStream()
434 {
435     IMAGE_LOGD("[BuildStream] IN");
436 
437     if (inputStreamPtr_ == nullptr) {
438         IMAGE_LOGE("[BuildStream] Stream is null.");
439         return false;
440     }
441 
442     auto length = inputStreamPtr_->GetStreamSize();
443     if (inputStreamPtr_->GetStreamType() == ImagePlugin::BUFFER_SOURCE_TYPE) {
444         svgStream_ = std::make_unique<SkMemoryStream>(inputStreamPtr_->GetDataPtr(), length);
445     } else {
446         auto data = std::make_unique<uint8_t[]>(length);
447         uint32_t readSize = 0;
448         if (!inputStreamPtr_->Read(length, data.get(), length, readSize)) {
449             IMAGE_LOGE("[BuildStream] read failed.");
450             return false;
451         }
452         svgStream_ = std::make_unique<SkMemoryStream>(data.get(), length, true);
453     }
454 
455     IMAGE_LOGD("[BuildStream] OUT");
456     return true;
457 }
458 
SetSVGColor(SkSVGNode * node,std::string color,std::string colorAttr)459 static void SetSVGColor(SkSVGNode* node, std::string color, std::string colorAttr)
460 {
461     if (node == nullptr) {
462         return;
463     }
464     IMAGE_LOGD("[SetSVGColor] node tag %{public}d %{public}s %{public}s.",
465         node->tag(), color.c_str(), colorAttr.c_str());
466     node->setAttribute(colorAttr.c_str(), color.c_str());
467     for (auto childNode : node->getChild()) {
468         SetSVGColor(childNode.get(), color, colorAttr);
469     }
470 }
471 
SetSVGColor(SkSVGNode * node,uint32_t color,std::string colorAttr)472 static void SetSVGColor(SkSVGNode* node, uint32_t color, std::string colorAttr)
473 {
474     std::stringstream stream;
475     stream.fill('0');
476     stream.width(SVG_COLOR_ATTR_WIDTH);
477     stream << std::hex << (color & SVG_COLOR_MASK);
478     std::string newValue(stream.str());
479     SetSVGColor(node, "#" + newValue, colorAttr);
480 }
481 
BuildDom()482 bool SvgDecoder::BuildDom()
483 {
484     IMAGE_LOGD("[BuildDom] IN");
485 
486     if (svgStream_ == nullptr) {
487         IMAGE_LOGE("[BuildDom] Stream is null.");
488         return false;
489     }
490 
491     svgDom_ = SkSVGDOM::MakeFromStream(*(svgStream_.get()));
492     if (svgDom_ == nullptr) {
493         IMAGE_LOGE("[BuildDom] DOM is null.");
494         return false;
495     }
496 
497     svgSize_ = svgDom_->containerSize();
498     if (svgSize_.isEmpty()) {
499         IMAGE_LOGE("[BuildDom] size is empty.");
500         return false;
501     }
502 
503     auto width = Float2UInt32(svgSize_.width());
504     auto height = Float2UInt32(svgSize_.height());
505 
506     IMAGE_LOGD("[BuildDom] OUT size=(%{public}u, %{public}u)", width, height);
507     return true;
508 }
509 
DoDecodeHeader()510 uint32_t SvgDecoder::DoDecodeHeader()
511 {
512     IMAGE_LOGD("[DoDecodeHeader] IN");
513 
514     if (!BuildStream()) {
515         IMAGE_LOGE("[DoDecodeHeader] Build Stream failed");
516         return Media::ERR_IMAGE_TOO_LARGE;
517     }
518 
519     if (!BuildDom()) {
520         IMAGE_LOGE("[DoDecodeHeader] Build DOM failed");
521         return Media::ERR_IMAGE_DATA_UNSUPPORT;
522     }
523 
524     IMAGE_LOGD("[DoDecodeHeader] OUT");
525     return Media::SUCCESS;
526 }
527 
DoSetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)528 uint32_t SvgDecoder::DoSetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
529 {
530     IMAGE_LOGD("[DoSetDecodeOptions] IN index=%{public}u", index);
531 
532     if (svgDom_ == nullptr) {
533         IMAGE_LOGE("[DoSetDecodeOptions] DOM is null.");
534         return Media::ERROR;
535     }
536 
537     opts_ = opts;
538 
539     auto svgSize = svgDom_->containerSize();
540     if (svgSize.isEmpty()) {
541         IMAGE_LOGE("[DoSetDecodeOptions] size is empty.");
542         return Media::ERROR;
543     }
544 
545     float scaleFitDesired = 1.0;
546     if (opts_.desiredSize.width && opts_.desiredSize.height) {
547         scaleFitDesired = std::min(static_cast<float>(opts_.desiredSize.width) / svgSize.width(),
548             static_cast<float>(opts_.desiredSize.height) / svgSize.height());
549     }
550 
551     if (opts_.plSVGResize.isValidPercentage) {
552         svgDom_->setResizePercentage(opts_.plSVGResize.resizePercentage * scaleFitDesired);
553     } else {
554         svgDom_->setResizePercentage(DEFAULT_RESIZE_PERCENTAGE * scaleFitDesired);
555     }
556 
557     opts_.desiredSize.width = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().width()));
558     opts_.desiredSize.height = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().height()));
559 
560     info.size.width = opts_.desiredSize.width;
561     info.size.height = opts_.desiredSize.height;
562     info.pixelFormat = PixelFormat::RGBA_8888;
563     info.colorSpace = ColorSpace::UNKNOWN;
564     info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
565 
566     IMAGE_LOGD("[DoSetDecodeOptions] OUT pixelFormat=%{public}d, alphaType=%{public}d, "
567         "colorSpace=%{public}d, size=(%{public}u, %{public}u)",
568         static_cast<int32_t>(info.pixelFormat), static_cast<int32_t>(info.alphaType),
569         static_cast<int32_t>(info.colorSpace), info.size.width, info.size.height);
570     return Media::SUCCESS;
571 }
572 
DoGetImageSize(uint32_t index,Size & size)573 uint32_t SvgDecoder::DoGetImageSize(uint32_t index, Size &size)
574 {
575     IMAGE_LOGD("[DoGetImageSize] IN index=%{public}u", index);
576 
577     if (svgDom_ == nullptr) {
578         IMAGE_LOGE("[DoGetImageSize] DOM is null.");
579         return Media::ERROR;
580     }
581 
582     auto svgSize = svgDom_->containerSize();
583     if (svgSize.isEmpty()) {
584         IMAGE_LOGE("[DoGetImageSize] size is empty.");
585         return Media::ERROR;
586     }
587 
588     size.width = static_cast<int32_t>(Float2UInt32(svgSize.width()));
589     size.height = static_cast<int32_t>(Float2UInt32(svgSize.height()));
590 
591     IMAGE_LOGD("[DoGetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
592     return Media::SUCCESS;
593 }
594 
DoDecode(uint32_t index,DecodeContext & context)595 uint32_t SvgDecoder::DoDecode(uint32_t index, DecodeContext &context)
596 {
597     IMAGE_LOGD("[DoDecode] IN index=%{public}u", index);
598 
599     if (svgDom_ == nullptr) {
600         IMAGE_LOGE("[DoDecode] DOM is null.");
601         return Media::ERROR;
602     }
603 
604     if (opts_.plFillColor.isValidColor) {
605         SetSVGColor(svgDom_->getRoot(), opts_.plFillColor.color, SVG_FILL_COLOR_ATTR);
606     }
607 
608     if (opts_.plStrokeColor.isValidColor) {
609         SetSVGColor(svgDom_->getRoot(), opts_.plStrokeColor.color, SVG_STROKE_COLOR_ATTR);
610     }
611 
612     if (!AllocBuffer(context)) {
613         IMAGE_LOGE("[DoDecode] alloc buffer failed.");
614         return Media::ERR_IMAGE_MALLOC_ABNORMAL;
615     }
616 
617     auto imageInfo = MakeImageInfo(opts_);
618     auto rowBytes = static_cast<uint32_t>(opts_.desiredSize.width * SVG_BYTES_PER_PIXEL);
619     auto pixels = context.pixelsBuffer.buffer;
620 
621     SkBitmap bitmap;
622     if (!bitmap.installPixels(imageInfo, pixels, rowBytes)) {
623         IMAGE_LOGE("[DoDecode] bitmap install pixels failed.");
624         return Media::ERROR;
625     }
626 
627     auto canvas = SkCanvas::MakeRasterDirect(imageInfo, bitmap.getPixels(), bitmap.rowBytes());
628     if (canvas == nullptr) {
629         IMAGE_LOGE("[DoDecode] make canvas failed.");
630         return Media::ERROR;
631     }
632     canvas->clear(SK_ColorTRANSPARENT);
633     svgDom_->render(canvas.get());
634 
635     bool result = canvas->readPixels(imageInfo, pixels, rowBytes, 0, 0);
636     if (!result) {
637         IMAGE_LOGE("[DoDecode] read pixels failed.");
638         return Media::ERROR;
639     }
640 
641     IMAGE_LOGD("[DoDecode] OUT");
642     ImageUtils::FlushContextSurfaceBuffer(context);
643     return Media::SUCCESS;
644 }
645 } // namespace ImagePlugin
646 } // namespace OHOS