1 /*
2 * Copyright (c) 2021-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 "core/image/image_source_info.h"
17
18 #include "core/pipeline_ng/pipeline_context.h"
19
20 namespace OHOS::Ace {
21 namespace {
22
23 constexpr uint32_t FILE_SUFFIX_LEN = 4;
24 constexpr uint32_t APNG_FILE_SUFFIX_LEN = 5;
25
CheckSvgExtension(const std::string & src)26 bool CheckSvgExtension(const std::string& src)
27 {
28 if (src.size() <= FILE_SUFFIX_LEN) {
29 return false;
30 }
31 auto srcSuffix = src.substr(src.size() - FILE_SUFFIX_LEN);
32 StringUtils::TransformStrCase(srcSuffix, StringUtils::TEXT_CASE_LOWERCASE);
33 return srcSuffix == ".svg";
34 }
35
36 } // namespace
37
IsSVGSource(const std::string & src,SrcType srcType,InternalResource::ResourceId resourceId)38 bool ImageSourceInfo::IsSVGSource(const std::string& src, SrcType srcType, InternalResource::ResourceId resourceId)
39 {
40 // 4 is the length of ".svg".
41 if (CheckSvgExtension(src)) {
42 return true;
43 } else if (srcType == SrcType::NETWORK) {
44 size_t queryPos = src.find('?');
45 std::string cleanUrl = (queryPos != std::string::npos) ? src.substr(0, queryPos) : src;
46 if (CheckSvgExtension(cleanUrl)) {
47 return true;
48 }
49 }
50 return (src.empty() && resourceId > InternalResource::ResourceId::SVG_START &&
51 resourceId < InternalResource::ResourceId::SVG_END);
52 }
53
IsPngSource(const std::string & src,InternalResource::ResourceId resourceId)54 bool ImageSourceInfo::IsPngSource(const std::string& src, InternalResource::ResourceId resourceId)
55 {
56 // 4 is the length of ".png" or is .apng
57 if (!src.empty()) {
58 std::string head = src.size() > APNG_FILE_SUFFIX_LEN
59 ? src.substr(src.size() - APNG_FILE_SUFFIX_LEN, APNG_FILE_SUFFIX_LEN)
60 : src.size() == 4 ? src.substr(src.size() - FILE_SUFFIX_LEN, FILE_SUFFIX_LEN)
61 : "";
62 std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
63
64 return (head.size() > FILE_SUFFIX_LEN && head.substr(head.size() - FILE_SUFFIX_LEN) == ".png") ||
65 (head.size() > APNG_FILE_SUFFIX_LEN && head.substr(head.size() - APNG_FILE_SUFFIX_LEN) == ".apng");
66 } else if (resourceId < InternalResource::ResourceId::SVG_START) {
67 return true;
68 }
69 return false;
70 }
71
IsValidBase64Head(const std::string & uri,const std::string & pattern)72 bool ImageSourceInfo::IsValidBase64Head(const std::string& uri, const std::string& pattern)
73 {
74 auto iter = uri.find_first_of(',');
75 if (iter == std::string::npos) {
76 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: wrong base64 head format.");
77 return false;
78 }
79 std::string base64Head = uri.substr(0, iter);
80 std::regex regular(pattern);
81 return std::regex_match(base64Head, regular);
82 }
83
IsUriOfDataAbilityEncoded(const std::string & uri,const std::string & pattern)84 bool ImageSourceInfo::IsUriOfDataAbilityEncoded(const std::string& uri, const std::string& pattern)
85 {
86 std::regex regular(pattern);
87 return std::regex_match(uri, regular);
88 }
89
ResolveURIType(const std::string & uri)90 SrcType ImageSourceInfo::ResolveURIType(const std::string& uri)
91 {
92 if (uri.empty()) {
93 return SrcType::UNSUPPORTED;
94 }
95 auto iter = uri.find_first_of(':');
96 if (iter == std::string::npos) {
97 return SrcType::ASSET;
98 }
99 std::string head = uri.substr(0, iter);
100 std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
101 if (head == "http" || head == "https") {
102 return SrcType::NETWORK;
103 } else if (head == "file") {
104 if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*thumbnail.*$")) {
105 return SrcType::DATA_ABILITY_DECODED;
106 } else if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*astc.*$")) {
107 return SrcType::ASTC;
108 } else if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*")) {
109 return SrcType::DATA_ABILITY;
110 }
111 return SrcType::FILE;
112 } else if (head == "internal") {
113 return SrcType::INTERNAL;
114 } else if (head == "data") {
115 static constexpr char BASE64_PATTERN[] =
116 "^data:image/(jpeg|JPEG|jpg|JPG|png|PNG|ico|ICO|gif|GIF|bmp|BMP|webp|WEBP|heic|heif|HEIF"
117 "|sut|astc);base64$";
118 if (IsValidBase64Head(uri, BASE64_PATTERN)) {
119 return SrcType::BASE64;
120 }
121 return SrcType::UNSUPPORTED;
122 } else if (head == "memory") {
123 return SrcType::MEMORY;
124 } else if (head == "resource") {
125 return SrcType::RESOURCE;
126 } else if (head == "dataability" || head == "datashare") {
127 if (IsUriOfDataAbilityEncoded(uri, "^dataability://.*?/media/.*thumbnail.*$") ||
128 IsUriOfDataAbilityEncoded(uri, "^datashare://.*?/media/.*thumbnail.*$")) {
129 return SrcType::DATA_ABILITY_DECODED;
130 }
131 return SrcType::DATA_ABILITY;
132 } else {
133 return SrcType::UNSUPPORTED;
134 }
135 }
136
137 // add constructor method for decompressed hap
ImageSourceInfo(std::string imageSrc,std::string bundleName,std::string moduleName,Dimension width,Dimension height,InternalResource::ResourceId resourceId,const RefPtr<PixelMap> & pixmap)138 ImageSourceInfo::ImageSourceInfo(std::string imageSrc, std::string bundleName, std::string moduleName, Dimension width,
139 Dimension height, InternalResource::ResourceId resourceId, const RefPtr<PixelMap>& pixmap)
140 : src_(std::move(imageSrc)), bundleName_(std::move(bundleName)), moduleName_(std::move(moduleName)),
141 sourceWidth_(width), sourceHeight_(height), resourceId_(resourceId), pixmap_(pixmap),
142 isPng_(IsPngSource(src_, resourceId_)), srcType_(ResolveSrcType())
143 {
144 isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
145 // count how many source set.
146 int32_t count = 0;
147 if (!src_.empty()) {
148 ++count;
149 }
150 if (resourceId_ != InternalResource::ResourceId::NO_ID) {
151 ++count;
152 }
153 if (pixmap != nullptr) {
154 pixmapBuffer_ = pixmap->GetPixels();
155 ++count;
156 }
157 if (count > 1) {
158 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: multi image source set, only one will be load.");
159 }
160
161 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
162 if (pipelineContext) {
163 localColorMode_ = pipelineContext->GetLocalColorMode();
164 }
165
166 GenerateCacheKey();
167 }
168
ImageSourceInfo(const std::shared_ptr<std::string> & imageSrc,std::string bundleName,std::string moduleName,Dimension width,Dimension height,InternalResource::ResourceId resourceId,const RefPtr<PixelMap> & pixmap)169 ImageSourceInfo::ImageSourceInfo(const std::shared_ptr<std::string>& imageSrc, std::string bundleName,
170 std::string moduleName, Dimension width, Dimension height, InternalResource::ResourceId resourceId,
171 const RefPtr<PixelMap>& pixmap)
172 : srcRef_(imageSrc), bundleName_(std::move(bundleName)), moduleName_(std::move(moduleName)), sourceWidth_(width),
173 sourceHeight_(height), resourceId_(resourceId), pixmap_(pixmap), isPng_(IsPngSource(*srcRef_, resourceId_)),
174 srcType_(ResolveSrcType())
175 {
176 // count how many source set.
177 int32_t count = 0;
178 if (srcRef_ && !(*srcRef_).empty()) {
179 isSvg_ = IsSVGSource((*srcRef_), srcType_, resourceId_);
180 ++count;
181 } else {
182 isSvg_ = IsSVGSource("", srcType_, resourceId_);
183 }
184 if (resourceId_ != InternalResource::ResourceId::NO_ID) {
185 ++count;
186 }
187 if (pixmap != nullptr) {
188 pixmapBuffer_ = pixmap->GetPixels();
189 ++count;
190 }
191 if (count > 1) {
192 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: multi image source set, only one will be load.");
193 }
194
195 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
196 if (pipelineContext) {
197 localColorMode_ = pipelineContext->GetLocalColorMode();
198 }
199
200 GenerateCacheKey();
201 }
202
ResolveSrcType() const203 SrcType ImageSourceInfo::ResolveSrcType() const
204 {
205 if (pixmap_) {
206 return SrcType::PIXMAP;
207 }
208 auto& src = GetSrc();
209 if (!src.empty()) {
210 return ResolveURIType(src);
211 }
212 if (resourceId_ != InternalResource::ResourceId::NO_ID) {
213 return SrcType::RESOURCE_ID;
214 }
215 return SrcType::UNSUPPORTED;
216 }
217
GenerateCacheKey()218 void ImageSourceInfo::GenerateCacheKey()
219 {
220 auto name = ToString();
221 name.append(AceApplicationInfo::GetInstance().GetAbilityName())
222 .append(bundleName_)
223 .append(moduleName_)
224 .append(std::to_string(static_cast<int32_t>(resourceId_)))
225 .append(std::to_string(static_cast<int32_t>(SystemProperties::GetColorMode())))
226 .append(std::to_string(static_cast<int32_t>(localColorMode_)));
227 if (srcType_ == SrcType::BASE64) {
228 name.append("SrcType:BASE64");
229 }
230 cacheKey_ = std::to_string(std::hash<std::string> {}(name));
231 }
232
SetFillColor(const Color & color)233 void ImageSourceInfo::SetFillColor(const Color& color)
234 {
235 fillColor_.emplace(color.GetValue());
236 }
237
operator ==(const ImageSourceInfo & info) const238 bool ImageSourceInfo::operator==(const ImageSourceInfo& info) const
239 {
240 if (localColorMode_ != info.localColorMode_) {
241 return false;
242 }
243 // only svg uses fillColor
244 if (isSvg_ && fillColor_ != info.fillColor_) {
245 return false;
246 }
247 return ((!pixmap_ && !info.pixmap_) ||
248 (pixmap_ && info.pixmap_ && pixmapBuffer_ == info.pixmap_->GetPixels())) &&
249 GetSrc() == info.GetSrc() && resourceId_ == info.resourceId_;
250 }
251
operator !=(const ImageSourceInfo & info) const252 bool ImageSourceInfo::operator!=(const ImageSourceInfo& info) const
253 {
254 return !(operator==(info));
255 }
256
SetSrc(const std::string & src,std::optional<Color> fillColor)257 void ImageSourceInfo::SetSrc(const std::string& src, std::optional<Color> fillColor)
258 {
259 srcRef_.reset(new std::string(src));
260 srcType_ = ResolveURIType(src);
261 resourceId_ = InternalResource::ResourceId::NO_ID;
262 isSvg_ = IsSVGSource(src, srcType_, resourceId_);
263 fillColor_ = fillColor;
264 pixmap_ = nullptr;
265 GenerateCacheKey();
266 }
267
GetSrc() const268 const std::string& ImageSourceInfo::GetSrc() const
269 {
270 if (srcRef_) {
271 return *srcRef_;
272 }
273 return src_;
274 }
275
SetResourceId(InternalResource::ResourceId id,std::optional<Color> fillColor)276 void ImageSourceInfo::SetResourceId(InternalResource::ResourceId id, std::optional<Color> fillColor)
277 {
278 resourceId_ = id;
279 srcType_ = SrcType::RESOURCE_ID;
280 src_.clear();
281 isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
282 fillColor_ = fillColor;
283 pixmap_ = nullptr;
284 GenerateCacheKey();
285 }
286
GetResourceId() const287 InternalResource::ResourceId ImageSourceInfo::GetResourceId() const
288 {
289 return resourceId_;
290 }
291
SetPixMap(const RefPtr<PixelMap> & pixmap,std::optional<Color> fillColor)292 void ImageSourceInfo::SetPixMap(const RefPtr<PixelMap>& pixmap, std::optional<Color> fillColor)
293 {
294 resourceId_ = InternalResource::ResourceId::NO_ID;
295 srcType_ = SrcType::PIXMAP;
296 src_.clear();
297 srcRef_.reset();
298 isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
299 fillColor_ = fillColor;
300 pixmap_ = pixmap;
301 }
302
SetBundleName(const std::string & bundleName)303 void ImageSourceInfo::SetBundleName(const std::string& bundleName)
304 {
305 bundleName_ = bundleName;
306 }
307
SetModuleName(const std::string & moduleName)308 void ImageSourceInfo::SetModuleName(const std::string& moduleName)
309 {
310 moduleName_ = moduleName;
311 }
312
IsInternalResource() const313 bool ImageSourceInfo::IsInternalResource() const
314 {
315 return GetSrc().empty() && resourceId_ != InternalResource::ResourceId::NO_ID && !pixmap_;
316 }
317
IsValid() const318 bool ImageSourceInfo::IsValid() const
319 {
320 auto& src = GetSrc();
321 return (src.empty() && resourceId_ != InternalResource::ResourceId::NO_ID) ||
322 (!src.empty() && resourceId_ == InternalResource::ResourceId::NO_ID) || pixmap_;
323 }
324
IsPng() const325 bool ImageSourceInfo::IsPng() const
326 {
327 return isPng_;
328 }
329
IsSvg() const330 bool ImageSourceInfo::IsSvg() const
331 {
332 return isSvg_ && !IsPixmap();
333 }
334
IsPixmap() const335 bool ImageSourceInfo::IsPixmap() const
336 {
337 return pixmap_ != nullptr || SrcType::DATA_ABILITY_DECODED == srcType_ || SrcType::ASTC == srcType_;
338 }
339
GetBundleName() const340 const std::string& ImageSourceInfo::GetBundleName() const
341 {
342 return bundleName_;
343 }
344
GetModuleName() const345 const std::string& ImageSourceInfo::GetModuleName() const
346 {
347 return moduleName_;
348 }
349
GetSrcType() const350 SrcType ImageSourceInfo::GetSrcType() const
351 {
352 return srcType_;
353 }
354
ToString() const355 std::string ImageSourceInfo::ToString() const
356 {
357 auto& src = GetSrc();
358 if (!src.empty()) {
359 return src;
360 }
361 if (resourceId_ != InternalResource::ResourceId::NO_ID) {
362 return std::string("internal resource id: ") + std::to_string(static_cast<int32_t>(resourceId_));
363 }
364 if (pixmap_) {
365 int32_t w = pixmap_->GetWidth();
366 int32_t h = pixmap_->GetHeight();
367 int32_t totalSize = pixmap_->GetByteCount();
368 auto rowStride = pixmap_->GetRowStride();
369 return std::string("pixmapID: ") + pixmap_->GetId() + std::string(" -> modifyID: ") + pixmap_->GetModifyId() +
370 "details: _w" + std::to_string(w) + "_h" + std::to_string(h) + "_rowStride" + std::to_string(rowStride) +
371 "_byteCount" + std::to_string(totalSize);
372 }
373 return std::string("empty source");
374 }
375
SetDimension(Dimension width,Dimension Height)376 void ImageSourceInfo::SetDimension(Dimension width, Dimension Height)
377 {
378 sourceWidth_ = width;
379 sourceHeight_ = Height;
380 }
381
IsSourceDimensionValid() const382 bool ImageSourceInfo::IsSourceDimensionValid() const
383 {
384 return sourceWidth_.IsValid() && sourceHeight_.IsValid();
385 }
386
GetSourceSize() const387 Size ImageSourceInfo::GetSourceSize() const
388 {
389 return Size(sourceWidth_.Value(), sourceHeight_.Value());
390 }
391
Reset()392 void ImageSourceInfo::Reset()
393 {
394 srcRef_.reset();
395 src_.clear();
396 sourceWidth_ = Dimension(-1);
397 sourceHeight_ = Dimension(-1);
398 resourceId_ = InternalResource::ResourceId::NO_ID;
399 isSvg_ = false;
400 fillColor_.reset();
401 pixmap_ = nullptr;
402 cacheKey_.clear();
403 }
404
GetFillColor() const405 const std::optional<Color>& ImageSourceInfo::GetFillColor() const
406 {
407 return fillColor_;
408 }
409
GetPixmap() const410 const RefPtr<PixelMap>& ImageSourceInfo::GetPixmap() const
411 {
412 return pixmap_;
413 }
414
SupportObjCache() const415 bool ImageSourceInfo::SupportObjCache() const
416 {
417 if (IsPixmap()) {
418 return false;
419 }
420 if (!needCache_) {
421 return false;
422 }
423 return !GetSrc().empty() || resourceId_ != InternalResource::ResourceId::NO_ID;
424 }
425
GetKey() const426 std::string ImageSourceInfo::GetKey() const
427 {
428 // only svg sets fillColor
429 if (isSvg_ && fillColor_.has_value()) {
430 return cacheKey_ + fillColor_.value().ColorToString();
431 }
432 return cacheKey_;
433 }
434
435 } // namespace OHOS::Ace
436