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