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