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