• 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 <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 
AllocDmaBuffer(DecodeContext & context,uint64_t byteCount,SkSize & svgSize)124 bool AllocDmaBuffer(DecodeContext &context, uint64_t byteCount, SkSize &svgSize)
125 {
126     IMAGE_LOGD("[AllocDmaBuffer] IN byteCount=%{public}llu",
127         static_cast<unsigned long long>(byteCount));
128 
129     if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
130         IMAGE_LOGE("[AllocDmaBuffer] pixelmap buffer size %{public}llu out of max size",
131             static_cast<unsigned long long>(byteCount));
132         return false;
133     }
134 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
135     sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
136     BufferRequestConfig requestConfig = {
137         .width = svgSize.width(),
138         .height = svgSize.height(),
139         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
140         .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
141         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
142         .timeout = 0,
143         .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
144         .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
145     };
146     GSError ret = sb->Alloc(requestConfig);
147     if (ret != GSERROR_OK) {
148         IMAGE_LOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
149         return false;
150     }
151     void* nativeBuffer = sb.GetRefPtr();
152     int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
153     if (err != OHOS::GSERROR_OK) {
154         IMAGE_LOGE("NativeBufferReference failed");
155         return false;
156     }
157 
158     context.pixelsBuffer.buffer = sb->GetVirAddr();
159     context.pixelsBuffer.context = nativeBuffer;
160     context.pixelsBuffer.bufferSize = byteCount;
161     context.allocatorType = AllocatorType::DMA_ALLOC;
162     context.freeFunc = nullptr;
163 
164     IMAGE_LOGD("[AllocDmaBuffer] OUT");
165     return true;
166 #else
167     IMAGE_LOGE("[AllocDmaBuffer] Not support dma!");
168     return false;
169 #endif
170 }
171 
AllocHeapBuffer(DecodeContext & context,uint64_t byteCount)172 bool AllocHeapBuffer(DecodeContext &context, uint64_t byteCount)
173 {
174     IMAGE_LOGD("[AllocHeapBuffer] IN byteCount=%{public}llu",
175         static_cast<unsigned long long>(byteCount));
176 
177     if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
178         IMAGE_LOGE("[AllocHeapBuffer] pixelmap buffer size %{public}llu out of max size",
179             static_cast<unsigned long long>(byteCount));
180         return false;
181     }
182 
183     auto outputBuffer = malloc(byteCount);
184     if (outputBuffer == nullptr) {
185         IMAGE_LOGE("[AllocHeapBuffer] alloc buffer size:[%{public}llu] failed.",
186             static_cast<unsigned long long>(byteCount));
187         return false;
188     }
189 
190     if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
191         IMAGE_LOGE("[AllocHeapBuffer] memset buffer failed.");
192         free(outputBuffer);
193         outputBuffer = nullptr;
194         return false;
195     }
196 
197     context.pixelsBuffer.buffer = outputBuffer;
198     context.pixelsBuffer.bufferSize = byteCount;
199     context.pixelsBuffer.context = nullptr;
200     context.allocatorType = AllocatorType::HEAP_ALLOC;
201     context.freeFunc = nullptr;
202 
203     IMAGE_LOGD("[AllocHeapBuffer] OUT");
204     return true;
205 }
206 
MakeImageInfo(const PixelDecodeOptions & opts)207 SkImageInfo MakeImageInfo(const PixelDecodeOptions &opts)
208 {
209     int width = opts.desiredSize.width;
210     int height = opts.desiredSize.height;
211     SkColorType colorType = SkColorType::kRGBA_8888_SkColorType;
212     SkAlphaType alphaType = SkAlphaType::kPremul_SkAlphaType;
213     return SkImageInfo::Make(width, height, colorType, alphaType);
214 }
215 } // namespace
216 
SvgDecoder()217 SvgDecoder::SvgDecoder()
218 {
219     IMAGE_LOGD("[Create] IN");
220 
221     IMAGE_LOGD("[Create] OUT");
222 }
223 
~SvgDecoder()224 SvgDecoder::~SvgDecoder()
225 {
226     IMAGE_LOGD("[Release] IN");
227 
228     Reset();
229 
230     IMAGE_LOGD("[Release] OUT");
231 }
232 
SetSource(InputDataStream & sourceStream)233 void SvgDecoder::SetSource(InputDataStream &sourceStream)
234 {
235     IMAGE_LOGD("[SetSource] IN");
236 
237     Reset();
238 
239     inputStreamPtr_ = &sourceStream;
240     state_ = SvgDecodingState::SOURCE_INITED;
241 
242     IMAGE_LOGD("[SetSource] OUT");
243 }
244 
Reset()245 void SvgDecoder::Reset()
246 {
247     IMAGE_LOGD("[Reset] IN");
248 
249     state_ = SvgDecodingState::UNDECIDED;
250 
251     if (svgDom_) {
252         svgDom_->setContainerSize(svgSize_);
253     }
254 
255     svgDom_ = nullptr;
256     svgStream_ = nullptr;
257     inputStreamPtr_ = nullptr;
258 
259     svgSize_.setEmpty();
260 
261     PixelDecodeOptions opts;
262     opts_ = opts;
263 
264     IMAGE_LOGD("[Reset] OUT");
265 }
266 
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)267 uint32_t SvgDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
268 {
269     if (index >= SVG_IMAGE_NUM) {
270         IMAGE_LOGE("[SetDecodeOptions] decode image index[%{public}u], out of range[%{public}u].",
271             index, SVG_IMAGE_NUM);
272         return Media::ERR_IMAGE_INVALID_PARAMETER;
273     }
274 
275     IMAGE_LOGD("[SetDecodeOptions] IN index=%{public}u, pixelFormat=%{public}d, alphaType=%{public}d, "
276         "colorSpace=%{public}d, size=(%{public}u, %{public}u), state=%{public}d", index,
277         static_cast<int32_t>(opts.desiredPixelFormat), static_cast<int32_t>(opts.desireAlphaType),
278         static_cast<int32_t>(opts.desiredColorSpace), opts.desiredSize.width, opts.desiredSize.height, state_);
279 
280     if (state_ < SvgDecodingState::SOURCE_INITED) {
281         IMAGE_LOGE("[SetDecodeOptions] set decode options failed for state %{public}d.", state_);
282         return Media::ERR_MEDIA_INVALID_OPERATION;
283     }
284 
285     if (state_ >= SvgDecodingState::IMAGE_DECODING) {
286         state_ = SvgDecodingState::SOURCE_INITED;
287     }
288 
289     if (state_ < SvgDecodingState::BASE_INFO_PARSED) {
290         uint32_t ret = DoDecodeHeader();
291         if (ret != Media::SUCCESS) {
292             IMAGE_LOGE("[SetDecodeOptions] decode header error on set decode options, ret:%{public}u.", ret);
293             state_ = SvgDecodingState::BASE_INFO_PARSING;
294             return ret;
295         }
296 
297         state_ = SvgDecodingState::BASE_INFO_PARSED;
298     }
299 
300     // only state SvgDecodingState::BASE_INFO_PARSED can go here.
301     uint32_t ret = DoSetDecodeOptions(index, opts, info);
302     if (ret != Media::SUCCESS) {
303         IMAGE_LOGE("[SetDecodeOptions] do set decode options failed, ret:%{public}u.", ret);
304         state_ = SvgDecodingState::BASE_INFO_PARSING;
305         return ret;
306     }
307 
308     state_ = SvgDecodingState::IMAGE_DECODING;
309 
310     IMAGE_LOGD("[SetDecodeOptions] OUT");
311     return Media::SUCCESS;
312 }
313 
Decode(uint32_t index,DecodeContext & context)314 uint32_t SvgDecoder::Decode(uint32_t index, DecodeContext &context)
315 {
316     ImageTrace imageTrace("SvgDecoder::Decode, index:%u", index);
317     if (index >= SVG_IMAGE_NUM) {
318         IMAGE_LOGE("[Decode] decode image index[%{public}u], out of range[%{public}u].",
319             index, SVG_IMAGE_NUM);
320         return Media::ERR_IMAGE_INVALID_PARAMETER;
321     }
322 
323     IMAGE_LOGD("[Decode] IN index=%{public}u", index);
324 
325     if (state_ < SvgDecodingState::IMAGE_DECODING) {
326         IMAGE_LOGE("[Decode] decode failed for state %{public}d.", state_);
327         return Media::ERR_MEDIA_INVALID_OPERATION;
328     }
329 
330     uint32_t ret = DoDecode(index, context);
331     if (ret == Media::SUCCESS) {
332         IMAGE_LOGD("[Decode] success.");
333         state_ = SvgDecodingState::IMAGE_DECODED;
334     } else {
335         IMAGE_LOGE("[Decode] fail, ret=%{public}u", ret);
336         state_ = SvgDecodingState::IMAGE_ERROR;
337     }
338 
339     IMAGE_LOGD("[Decode] OUT ret=%{public}u", ret);
340     return ret;
341 }
342 
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)343 uint32_t SvgDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
344 {
345     // currently not support increment decode
346     return ERR_IMAGE_DATA_UNSUPPORT;
347 }
348 
349 // need decode all frame to get total number.
GetTopLevelImageNum(uint32_t & num)350 uint32_t SvgDecoder::GetTopLevelImageNum(uint32_t &num)
351 {
352     num = SVG_IMAGE_NUM;
353     return Media::SUCCESS;
354 }
355 
356 // return background size but not specific frame size, cause of frame drawing on background.
GetImageSize(uint32_t index,Size & size)357 uint32_t SvgDecoder::GetImageSize(uint32_t index, Size &size)
358 {
359     if (index >= SVG_IMAGE_NUM) {
360         IMAGE_LOGE("[GetImageSize] decode image index[%{public}u], out of range[%{public}u].",
361             index, SVG_IMAGE_NUM);
362         return Media::ERR_IMAGE_INVALID_PARAMETER;
363     }
364 
365     IMAGE_LOGD("[GetImageSize] IN index=%{public}u", index);
366 
367     if (state_ < SvgDecodingState::SOURCE_INITED) {
368         IMAGE_LOGE("[GetImageSize] get image size failed for state %{public}d.", state_);
369         return ERR_MEDIA_INVALID_OPERATION;
370     }
371 
372     if (state_ >= SvgDecodingState::BASE_INFO_PARSED) {
373         DoGetImageSize(index, size);
374         IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
375         return Media::SUCCESS;
376     }
377 
378     // only state SvgDecodingState::SOURCE_INITED and SvgDecodingState::BASE_INFO_PARSING can go here.
379     uint32_t ret = DoDecodeHeader();
380     if (ret != Media::SUCCESS) {
381         IMAGE_LOGE("[GetImageSize] decode header error on get image size, ret:%{public}u.", ret);
382         state_ = SvgDecodingState::BASE_INFO_PARSING;
383         return ret;
384     }
385 
386     ret = DoGetImageSize(index, size);
387     if (ret != Media::SUCCESS) {
388         IMAGE_LOGE("[GetImageSize] do get image size failed, ret:%{public}u.", ret);
389         state_ = SvgDecodingState::BASE_INFO_PARSING;
390         return ret;
391     }
392 
393     state_ = SvgDecodingState::BASE_INFO_PARSED;
394 
395     IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
396     return Media::SUCCESS;
397 }
398 
AllocBuffer(DecodeContext & context)399 bool SvgDecoder::AllocBuffer(DecodeContext &context)
400 {
401     IMAGE_LOGD("[AllocBuffer] IN");
402 
403     if (svgDom_ == nullptr) {
404         IMAGE_LOGE("[AllocBuffer] DOM is null.");
405         return false;
406     }
407 
408     bool ret = true;
409     if (context.pixelsBuffer.buffer == nullptr) {
410         auto svgSize = svgDom_->containerSize();
411         if (svgSize.isEmpty()) {
412             IMAGE_LOGE("[AllocBuffer] size is empty.");
413             return false;
414         }
415         uint32_t width = Float2UInt32(svgSize.width());
416         uint32_t height = Float2UInt32(svgSize.height());
417         uint64_t byteCount = static_cast<uint64_t>(width) * height * SVG_BYTES_PER_PIXEL;
418         if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
419             ret = AllocShareBuffer(context, byteCount);
420         } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
421             ret = AllocDmaBuffer(context, byteCount, svgSize);
422         } else {
423             ret = AllocHeapBuffer(context, byteCount);
424         }
425     }
426 
427     IMAGE_LOGD("[AllocBuffer] OUT ret=%{public}d", ret);
428     return ret;
429 }
430 
BuildStream()431 bool SvgDecoder::BuildStream()
432 {
433     IMAGE_LOGD("[BuildStream] IN");
434 
435     if (inputStreamPtr_ == nullptr) {
436         IMAGE_LOGE("[BuildStream] Stream is null.");
437         return false;
438     }
439 
440     auto length = inputStreamPtr_->GetStreamSize();
441     if (inputStreamPtr_->GetStreamType() == ImagePlugin::BUFFER_SOURCE_TYPE) {
442         svgStream_ = std::make_unique<SkMemoryStream>(inputStreamPtr_->GetDataPtr(), length);
443     } else {
444         auto data = std::make_unique<uint8_t[]>(length);
445         uint32_t readSize = 0;
446         if (!inputStreamPtr_->Read(length, data.get(), length, readSize)) {
447             IMAGE_LOGE("[BuildStream] read failed.");
448             return false;
449         }
450         svgStream_ = std::make_unique<SkMemoryStream>(data.get(), length, true);
451     }
452 
453     IMAGE_LOGD("[BuildStream] OUT");
454     return true;
455 }
456 
SetSVGColor(SkSVGNode * node,std::string color,std::string colorAttr)457 static void SetSVGColor(SkSVGNode* node, std::string color, std::string colorAttr)
458 {
459     if (node == nullptr) {
460         return;
461     }
462     IMAGE_LOGD("[SetSVGColor] node tag %{public}d %{public}s %{public}s.",
463         node->tag(), color.c_str(), colorAttr.c_str());
464     node->setAttribute(colorAttr.c_str(), color.c_str());
465     for (auto childNode : node->getChild()) {
466         SetSVGColor(childNode.get(), color, colorAttr);
467     }
468 }
469 
SetSVGColor(SkSVGNode * node,uint32_t color,std::string colorAttr)470 static void SetSVGColor(SkSVGNode* node, uint32_t color, std::string colorAttr)
471 {
472     std::stringstream stream;
473     stream.fill('0');
474     stream.width(SVG_COLOR_ATTR_WIDTH);
475     stream << std::hex << (color & SVG_COLOR_MASK);
476     std::string newValue(stream.str());
477     SetSVGColor(node, "#" + newValue, colorAttr);
478 }
479 
BuildDom()480 bool SvgDecoder::BuildDom()
481 {
482     IMAGE_LOGD("[BuildDom] IN");
483 
484     if (svgStream_ == nullptr) {
485         IMAGE_LOGE("[BuildDom] Stream is null.");
486         return false;
487     }
488 
489     svgDom_ = SkSVGDOM::MakeFromStream(*(svgStream_.get()));
490     if (svgDom_ == nullptr) {
491         IMAGE_LOGE("[BuildDom] DOM is null.");
492         return false;
493     }
494 
495     svgSize_ = svgDom_->containerSize();
496     if (svgSize_.isEmpty()) {
497         IMAGE_LOGE("[BuildDom] size is empty.");
498         return false;
499     }
500 
501     auto width = Float2UInt32(svgSize_.width());
502     auto height = Float2UInt32(svgSize_.height());
503 
504     IMAGE_LOGD("[BuildDom] OUT size=(%{public}u, %{public}u)", width, height);
505     return true;
506 }
507 
DoDecodeHeader()508 uint32_t SvgDecoder::DoDecodeHeader()
509 {
510     IMAGE_LOGD("[DoDecodeHeader] IN");
511 
512     if (!BuildStream()) {
513         IMAGE_LOGE("[DoDecodeHeader] Build Stream failed");
514         return Media::ERR_IMAGE_TOO_LARGE;
515     }
516 
517     if (!BuildDom()) {
518         IMAGE_LOGE("[DoDecodeHeader] Build DOM failed");
519         return Media::ERR_IMAGE_DATA_UNSUPPORT;
520     }
521 
522     IMAGE_LOGD("[DoDecodeHeader] OUT");
523     return Media::SUCCESS;
524 }
525 
IsSrcRectContainsDistRect(const OHOS::Media::Rect & srcRect,const OHOS::Media::Rect & distRect)526 bool IsSrcRectContainsDistRect(const OHOS::Media::Rect &srcRect, const OHOS::Media::Rect &distRect)
527 {
528     if (srcRect.left < 0 || srcRect.top < 0 || srcRect.width <= 0 || srcRect.height <= 0) {
529         return false;
530     }
531     if (distRect.left < 0 || distRect.top < 0 || distRect.width <= 0 || distRect.height <= 0) {
532         return false;
533     }
534     return srcRect.left <= distRect.left && srcRect.top <= distRect.top &&
535         (srcRect.left + srcRect.width) >= (distRect.left + distRect.width) &&
536         (srcRect.top + srcRect.height) >= (distRect.top + distRect.height);
537 }
538 
CheckCropRectValid(const PixelDecodeOptions & opts,const SkSize & svgSize)539 bool CheckCropRectValid(const PixelDecodeOptions &opts, const SkSize &svgSize)
540 {
541     OHOS::Media::Rect srcRect = {0, 0, 0, 0};
542     if (opts.cropAndScaleStrategy == CropAndScaleStrategy::DEFAULT) {
543         return true;
544     }
545     srcRect.width = svgSize.width();
546     srcRect.height = svgSize.height();
547     if (opts.cropAndScaleStrategy == CropAndScaleStrategy::SCALE_FIRST &&
548         (opts.desiredSize.width != 0 || opts.desiredSize.height != 0)) {
549         srcRect.width = opts.desiredSize.width;
550         srcRect.height = opts.desiredSize.height;
551     }
552     return IsSrcRectContainsDistRect(srcRect, opts.CropRect);
553 }
554 
DoSetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)555 uint32_t SvgDecoder::DoSetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
556 {
557     IMAGE_LOGD("[DoSetDecodeOptions] IN index=%{public}u", index);
558 
559     if (svgDom_ == nullptr) {
560         IMAGE_LOGE("[DoSetDecodeOptions] DOM is null.");
561         return Media::ERROR;
562     }
563 
564     opts_ = opts;
565 
566     auto svgSize = svgDom_->containerSize();
567     if (svgSize.isEmpty()) {
568         IMAGE_LOGE("[DoSetDecodeOptions] size is empty.");
569         return Media::ERROR;
570     }
571     if (!CheckCropRectValid(opts_, svgSize)) {
572         IMAGE_LOGI("crop rect is invalid.");
573         return ERR_MEDIA_INVALID_OPERATION;
574     }
575 
576     float scaleFitDesired = 1.0;
577     if (opts_.desiredSize.width && opts_.desiredSize.height &&
578         opts.cropAndScaleStrategy == CropAndScaleStrategy::DEFAULT) {
579         scaleFitDesired = std::min(static_cast<float>(opts_.desiredSize.width) / svgSize.width(),
580             static_cast<float>(opts_.desiredSize.height) / svgSize.height());
581     }
582 
583     if (opts_.plSVGResize.isValidPercentage) {
584         svgDom_->setResizePercentage(opts_.plSVGResize.resizePercentage * scaleFitDesired);
585     } else {
586         svgDom_->setResizePercentage(DEFAULT_RESIZE_PERCENTAGE * scaleFitDesired);
587     }
588 
589     opts_.desiredSize.width = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().width()));
590     opts_.desiredSize.height = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().height()));
591 
592     info.size.width = opts_.desiredSize.width;
593     info.size.height = opts_.desiredSize.height;
594     info.pixelFormat = PixelFormat::RGBA_8888;
595     info.colorSpace = ColorSpace::UNKNOWN;
596     info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
597 
598     IMAGE_LOGD("[DoSetDecodeOptions] OUT pixelFormat=%{public}d, alphaType=%{public}d, "
599         "colorSpace=%{public}d, size=(%{public}u, %{public}u)",
600         static_cast<int32_t>(info.pixelFormat), static_cast<int32_t>(info.alphaType),
601         static_cast<int32_t>(info.colorSpace), info.size.width, info.size.height);
602     return Media::SUCCESS;
603 }
604 
DoGetImageSize(uint32_t index,Size & size)605 uint32_t SvgDecoder::DoGetImageSize(uint32_t index, Size &size)
606 {
607     IMAGE_LOGD("[DoGetImageSize] IN index=%{public}u", index);
608 
609     if (svgDom_ == nullptr) {
610         IMAGE_LOGE("[DoGetImageSize] DOM is null.");
611         return Media::ERROR;
612     }
613 
614     auto svgSize = svgDom_->containerSize();
615     if (svgSize.isEmpty()) {
616         IMAGE_LOGE("[DoGetImageSize] size is empty.");
617         return Media::ERROR;
618     }
619 
620     size.width = static_cast<int32_t>(Float2UInt32(svgSize.width()));
621     size.height = static_cast<int32_t>(Float2UInt32(svgSize.height()));
622 
623     IMAGE_LOGD("[DoGetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
624     return Media::SUCCESS;
625 }
626 
DoDecode(uint32_t index,DecodeContext & context)627 uint32_t SvgDecoder::DoDecode(uint32_t index, DecodeContext &context)
628 {
629     IMAGE_LOGD("[DoDecode] IN index=%{public}u", index);
630 
631     if (svgDom_ == nullptr) {
632         IMAGE_LOGE("[DoDecode] DOM is null.");
633         return Media::ERROR;
634     }
635 
636     if (opts_.plFillColor.isValidColor) {
637         SetSVGColor(svgDom_->getRoot(), opts_.plFillColor.color, SVG_FILL_COLOR_ATTR);
638     }
639 
640     if (opts_.plStrokeColor.isValidColor) {
641         SetSVGColor(svgDom_->getRoot(), opts_.plStrokeColor.color, SVG_STROKE_COLOR_ATTR);
642     }
643 
644     if (!AllocBuffer(context)) {
645         IMAGE_LOGE("[DoDecode] alloc buffer failed.");
646         return Media::ERR_IMAGE_MALLOC_ABNORMAL;
647     }
648 
649     auto imageInfo = MakeImageInfo(opts_);
650     auto rowBytes = static_cast<uint32_t>(opts_.desiredSize.width * SVG_BYTES_PER_PIXEL);
651     auto pixels = context.pixelsBuffer.buffer;
652 
653     SkBitmap bitmap;
654     if (!bitmap.installPixels(imageInfo, pixels, rowBytes)) {
655         IMAGE_LOGE("[DoDecode] bitmap install pixels failed.");
656         return Media::ERROR;
657     }
658 
659     auto canvas = SkCanvas::MakeRasterDirect(imageInfo, bitmap.getPixels(), bitmap.rowBytes());
660     if (canvas == nullptr) {
661         IMAGE_LOGE("[DoDecode] make canvas failed.");
662         return Media::ERROR;
663     }
664     canvas->clear(SK_ColorTRANSPARENT);
665     svgDom_->render(canvas.get());
666 
667     bool result = canvas->readPixels(imageInfo, pixels, rowBytes, 0, 0);
668     if (!result) {
669         IMAGE_LOGE("[DoDecode] read pixels failed.");
670         return Media::ERROR;
671     }
672 
673     IMAGE_LOGD("[DoDecode] OUT");
674     ImageUtils::FlushContextSurfaceBuffer(context);
675     return Media::SUCCESS;
676 }
677 } // namespace ImagePlugin
678 } // namespace OHOS