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