• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/components_ng/base/frame_node.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20 
21 namespace OHOS::Ace {
22 namespace {
23 
24 constexpr uint32_t FILE_SUFFIX_LEN = 4;
25 constexpr uint32_t APNG_FILE_SUFFIX_LEN = 5;
26 constexpr uint32_t MAX_BASE64_LENGTH = 50; // prevent the Base64 image format from too long.
27 
CheckSvgExtension(const std::string & src)28 bool CheckSvgExtension(const std::string& src)
29 {
30     if (src.size() <= FILE_SUFFIX_LEN) {
31         return false;
32     }
33     auto srcSuffix = src.substr(src.size() - FILE_SUFFIX_LEN);
34     StringUtils::TransformStrCase(srcSuffix, StringUtils::TEXT_CASE_LOWERCASE);
35     return srcSuffix == ".svg";
36 }
37 
38 } // namespace
39 
IsSVGSource(const std::string & src,SrcType srcType,InternalResource::ResourceId resourceId)40 bool ImageSourceInfo::IsSVGSource(const std::string& src, SrcType srcType, InternalResource::ResourceId resourceId)
41 {
42     // 4 is the length of ".svg".
43     if (CheckSvgExtension(src)) {
44         return true;
45     } else if (srcType == SrcType::NETWORK) {
46         size_t queryPos = src.find('?');
47         std::string cleanUrl = (queryPos != std::string::npos) ? src.substr(0, queryPos) : src;
48         if (CheckSvgExtension(cleanUrl)) {
49             return true;
50         }
51     }
52     return (src.empty() && resourceId > InternalResource::ResourceId::SVG_START &&
53             resourceId < InternalResource::ResourceId::SVG_END);
54 }
55 
IsPngSource(const std::string & src,InternalResource::ResourceId resourceId)56 bool ImageSourceInfo::IsPngSource(const std::string& src, InternalResource::ResourceId resourceId)
57 {
58     // 4 is the length of ".png" or is .apng
59     if (!src.empty()) {
60         std::string head = src.size() > APNG_FILE_SUFFIX_LEN
61                                ? src.substr(src.size() - APNG_FILE_SUFFIX_LEN, APNG_FILE_SUFFIX_LEN)
62                            : src.size() == 4 ? src.substr(src.size() - FILE_SUFFIX_LEN, FILE_SUFFIX_LEN)
63                                              : "";
64         std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
65 
66         return (head.size() > FILE_SUFFIX_LEN && head.substr(head.size() - FILE_SUFFIX_LEN) == ".png") ||
67                (head.size() > APNG_FILE_SUFFIX_LEN && head.substr(head.size() - APNG_FILE_SUFFIX_LEN) == ".apng");
68     } else if (resourceId < InternalResource::ResourceId::SVG_START) {
69         return true;
70     }
71     return false;
72 }
73 
IsValidBase64Head(const std::string & uri,const std::string & pattern)74 bool ImageSourceInfo::IsValidBase64Head(const std::string& uri, const std::string& pattern)
75 {
76     auto iter = uri.find_first_of(',');
77     if (iter == std::string::npos) {
78         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: wrong base64 head format.");
79         return false;
80     }
81     std::string base64Head = uri.substr(0, iter);
82     std::regex regular(pattern);
83     return std::regex_match(base64Head, regular);
84 }
85 
IsUriOfDataAbilityEncoded(const std::string & uri,const std::string & pattern)86 bool ImageSourceInfo::IsUriOfDataAbilityEncoded(const std::string& uri, const std::string& pattern)
87 {
88     std::regex regular(pattern);
89     return std::regex_match(uri, regular);
90 }
91 
ResolveURIType(const std::string & uri)92 SrcType ImageSourceInfo::ResolveURIType(const std::string& uri)
93 {
94     if (uri.empty()) {
95         return SrcType::UNSUPPORTED;
96     }
97     auto iter = uri.find_first_of(':');
98     if (iter == std::string::npos) {
99         return SrcType::ASSET;
100     }
101     std::string head = uri.substr(0, iter);
102     std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
103     if (head == "http" || head == "https") {
104         return SrcType::NETWORK;
105     } else if (head == "file") {
106         if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*thumbnail.*$")) {
107             return SrcType::DATA_ABILITY_DECODED;
108         } else if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*astc.*$")) {
109             return SrcType::ASTC;
110         } else if (IsUriOfDataAbilityEncoded(uri, "^file://media/.*")) {
111             return SrcType::DATA_ABILITY;
112         }
113         return SrcType::FILE;
114     } else if (head == "internal") {
115         return SrcType::INTERNAL;
116     } else if (head == "data") {
117         static constexpr char BASE64_PATTERN[] =
118             "^data:image/(jpeg|JPEG|jpg|JPG|png|PNG|ico|ICO|gif|GIF|bmp|BMP|webp|WEBP|heic|heif|HEIF"
119             "|sut|astc);base64$";
120         if (IsValidBase64Head(uri, BASE64_PATTERN)) {
121             return SrcType::BASE64;
122         }
123         return SrcType::UNSUPPORTED;
124     } else if (head == "memory") {
125         return SrcType::MEMORY;
126     } else if (head == "resource") {
127         return SrcType::RESOURCE;
128     } else if (head == "dataability" || head == "datashare") {
129         if (IsUriOfDataAbilityEncoded(uri, "^dataability://.*?/media/.*thumbnail.*$") ||
130             IsUriOfDataAbilityEncoded(uri, "^datashare://.*?/media/.*thumbnail.*$")) {
131             return SrcType::DATA_ABILITY_DECODED;
132         }
133         return SrcType::DATA_ABILITY;
134     } else {
135         return SrcType::UNSUPPORTED;
136     }
137 }
138 
139 // 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)140 ImageSourceInfo::ImageSourceInfo(std::string imageSrc, std::string bundleName, std::string moduleName, Dimension width,
141     Dimension height, InternalResource::ResourceId resourceId, const RefPtr<PixelMap>& pixmap)
142     : src_(std::move(imageSrc)), bundleName_(std::move(bundleName)), moduleName_(std::move(moduleName)),
143       sourceWidth_(width), sourceHeight_(height), resourceId_(resourceId), pixmap_(pixmap),
144       isPng_(IsPngSource(src_, resourceId_)), srcType_(ResolveSrcType())
145 {
146     isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
147     // count how many source set.
148     int32_t count = 0;
149     if (!src_.empty()) {
150         ++count;
151     }
152     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
153         ++count;
154     }
155     if (pixmap != nullptr) {
156         pixmapBuffer_ = pixmap->GetPixels();
157         ++count;
158     }
159     if (count > 1) {
160         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: multi image source set, only one will be load.");
161     }
162 
163     auto pipelineContext = NG::PipelineContext::GetCurrentContext();
164     if (pipelineContext) {
165         localColorMode_ = pipelineContext->GetLocalColorMode();
166     }
167 
168     GenerateCacheKey();
169 }
170 
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)171 ImageSourceInfo::ImageSourceInfo(const std::shared_ptr<std::string>& imageSrc, std::string bundleName,
172     std::string moduleName, Dimension width, Dimension height, InternalResource::ResourceId resourceId,
173     const RefPtr<PixelMap>& pixmap)
174     : srcRef_(imageSrc), bundleName_(std::move(bundleName)), moduleName_(std::move(moduleName)), sourceWidth_(width),
175       sourceHeight_(height), resourceId_(resourceId), pixmap_(pixmap), isPng_(IsPngSource(*srcRef_, resourceId_)),
176       srcType_(ResolveSrcType())
177 {
178     // count how many source set.
179     int32_t count = 0;
180     if (srcRef_ && !(*srcRef_).empty()) {
181         isSvg_ = IsSVGSource((*srcRef_), srcType_, resourceId_);
182         ++count;
183     } else {
184         isSvg_ = IsSVGSource("", srcType_, resourceId_);
185     }
186     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
187         ++count;
188     }
189     if (pixmap != nullptr) {
190         pixmapBuffer_ = pixmap->GetPixels();
191         ++count;
192     }
193     if (count > 1) {
194         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageSourceInfo: multi image source set, only one will be load.");
195     }
196 
197     auto pipelineContext = NG::PipelineContext::GetCurrentContext();
198     if (pipelineContext) {
199         localColorMode_ = pipelineContext->GetLocalColorMode();
200     }
201 
202     GenerateCacheKey();
203 }
204 
ResolveSrcType() const205 SrcType ImageSourceInfo::ResolveSrcType() const
206 {
207     if (pixmap_) {
208         return SrcType::PIXMAP;
209     }
210     auto& src = GetSrc();
211     if (!src.empty()) {
212         return ResolveURIType(src);
213     }
214     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
215         return SrcType::RESOURCE_ID;
216     }
217     return SrcType::UNSUPPORTED;
218 }
219 
GenerateCacheKey()220 void ImageSourceInfo::GenerateCacheKey()
221 {
222     auto name = ToString(false);
223     name.append(AceApplicationInfo::GetInstance().GetAbilityName())
224         .append(bundleName_)
225         .append(moduleName_)
226         .append(std::to_string(static_cast<int32_t>(resourceId_)))
227         .append(std::to_string(static_cast<int32_t>(Container::CurrentColorMode())))
228         .append(std::to_string(static_cast<int32_t>(localColorMode_)));
229     if (srcType_ == SrcType::BASE64) {
230         name.append("SrcType:BASE64");
231     }
232     cacheKey_ = std::to_string(std::hash<std::string> {}(name));
233 }
234 
SetFillColor(const Color & color)235 void ImageSourceInfo::SetFillColor(const Color& color)
236 {
237     fillColor_.emplace(color.GetValue());
238 }
239 
operator ==(const ImageSourceInfo & info) const240 bool ImageSourceInfo::operator==(const ImageSourceInfo& info) const
241 {
242     if (localColorMode_ != info.localColorMode_) {
243         return false;
244     }
245     // only svg uses fillColor
246     if (isSvg_ && fillColor_ != info.fillColor_) {
247         return false;
248     }
249     return ((!pixmap_ && !info.pixmap_) || (pixmap_ && info.pixmap_ && pixmapBuffer_ == info.pixmap_->GetPixels() &&
250                                                pixmap_->GetRawPixelMapPtr() == info.pixmap_->GetRawPixelMapPtr())) &&
251            GetSrc() == info.GetSrc() && resourceId_ == info.resourceId_;
252 }
253 
operator !=(const ImageSourceInfo & info) const254 bool ImageSourceInfo::operator!=(const ImageSourceInfo& info) const
255 {
256     return !(operator==(info));
257 }
258 
SetSrc(const std::string & src,std::optional<Color> fillColor)259 void ImageSourceInfo::SetSrc(const std::string& src, std::optional<Color> fillColor)
260 {
261     srcRef_.reset(new std::string(src));
262     srcType_ = ResolveURIType(src);
263     resourceId_ = InternalResource::ResourceId::NO_ID;
264     isSvg_ = IsSVGSource(src, srcType_, resourceId_);
265     fillColor_ = fillColor;
266     pixmap_ = nullptr;
267     GenerateCacheKey();
268 }
269 
GetSrc() const270 const std::string& ImageSourceInfo::GetSrc() const
271 {
272     if (srcRef_) {
273         return *srcRef_;
274     }
275     return src_;
276 }
277 
SetResourceId(InternalResource::ResourceId id,std::optional<Color> fillColor)278 void ImageSourceInfo::SetResourceId(InternalResource::ResourceId id, std::optional<Color> fillColor)
279 {
280     resourceId_ = id;
281     srcType_ = SrcType::RESOURCE_ID;
282     src_.clear();
283     isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
284     fillColor_ = fillColor;
285     pixmap_ = nullptr;
286     GenerateCacheKey();
287 }
288 
GetResourceId() const289 InternalResource::ResourceId ImageSourceInfo::GetResourceId() const
290 {
291     return resourceId_;
292 }
293 
SetPixMap(const RefPtr<PixelMap> & pixmap,std::optional<Color> fillColor)294 void ImageSourceInfo::SetPixMap(const RefPtr<PixelMap>& pixmap, std::optional<Color> fillColor)
295 {
296     resourceId_ = InternalResource::ResourceId::NO_ID;
297     srcType_ = SrcType::PIXMAP;
298     src_.clear();
299     srcRef_.reset();
300     isSvg_ = IsSVGSource(src_, srcType_, resourceId_);
301     fillColor_ = fillColor;
302     pixmap_ = pixmap;
303 }
304 
SetBundleName(const std::string & bundleName)305 void ImageSourceInfo::SetBundleName(const std::string& bundleName)
306 {
307     bundleName_ = bundleName;
308 }
309 
SetModuleName(const std::string & moduleName)310 void ImageSourceInfo::SetModuleName(const std::string& moduleName)
311 {
312     moduleName_ = moduleName;
313 }
314 
IsInternalResource() const315 bool ImageSourceInfo::IsInternalResource() const
316 {
317     return GetSrc().empty() && resourceId_ != InternalResource::ResourceId::NO_ID && !pixmap_;
318 }
319 
IsValid() const320 bool ImageSourceInfo::IsValid() const
321 {
322     auto& src = GetSrc();
323     return (src.empty() && resourceId_ != InternalResource::ResourceId::NO_ID) ||
324            (!src.empty() && resourceId_ == InternalResource::ResourceId::NO_ID) || pixmap_;
325 }
326 
IsPng() const327 bool ImageSourceInfo::IsPng() const
328 {
329     return isPng_;
330 }
331 
IsSvg() const332 bool ImageSourceInfo::IsSvg() const
333 {
334     return isSvg_ && !IsPixmap();
335 }
336 
IsPixmap() const337 bool ImageSourceInfo::IsPixmap() const
338 {
339     return pixmap_ != nullptr || SrcType::DATA_ABILITY_DECODED == srcType_ || SrcType::ASTC == srcType_;
340 }
341 
GetBundleName() const342 const std::string& ImageSourceInfo::GetBundleName() const
343 {
344     return bundleName_;
345 }
346 
GetModuleName() const347 const std::string& ImageSourceInfo::GetModuleName() const
348 {
349     return moduleName_;
350 }
351 
GetSrcType() const352 SrcType ImageSourceInfo::GetSrcType() const
353 {
354     return srcType_;
355 }
356 
ToString(bool isNeedTruncated) const357 std::string ImageSourceInfo::ToString(bool isNeedTruncated) const
358 {
359     auto& src = GetSrc();
360     if (!src.empty()) {
361         // Check if the src is a base64 image
362         if (srcType_ == SrcType::BASE64 && isNeedTruncated) {
363             // Return the first 50 characters of the base64 image string
364             return src.substr(0, MAX_BASE64_LENGTH) + "...(truncated)";
365         }
366         return src;
367     }
368     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
369         return std::string("internal resource id: ") + std::to_string(static_cast<int32_t>(resourceId_));
370     }
371     if (pixmap_) {
372         int32_t w = pixmap_->GetWidth();
373         int32_t h = pixmap_->GetHeight();
374         int32_t totalSize = pixmap_->GetByteCount();
375         auto rowStride = pixmap_->GetRowStride();
376         return std::string("pixmapID: ") + pixmap_->GetId() + std::string(" -> modifyID: ") + pixmap_->GetModifyId() +
377                "details: _w" + std::to_string(w) + "_h" + std::to_string(h) + "_rowStride" + std::to_string(rowStride) +
378                "_byteCount" + std::to_string(totalSize);
379     }
380     return std::string("empty source");
381 }
382 
SetDimension(Dimension width,Dimension Height)383 void ImageSourceInfo::SetDimension(Dimension width, Dimension Height)
384 {
385     sourceWidth_ = width;
386     sourceHeight_ = Height;
387 }
388 
IsSourceDimensionValid() const389 bool ImageSourceInfo::IsSourceDimensionValid() const
390 {
391     return sourceWidth_.IsValid() && sourceHeight_.IsValid();
392 }
393 
GetSourceSize() const394 Size ImageSourceInfo::GetSourceSize() const
395 {
396     return Size(sourceWidth_.Value(), sourceHeight_.Value());
397 }
398 
Reset()399 void ImageSourceInfo::Reset()
400 {
401     srcRef_.reset();
402     src_.clear();
403     sourceWidth_ = Dimension(-1);
404     sourceHeight_ = Dimension(-1);
405     resourceId_ = InternalResource::ResourceId::NO_ID;
406     isSvg_ = false;
407     fillColor_.reset();
408     pixmap_ = nullptr;
409     cacheKey_.clear();
410 }
411 
GetFillColor() const412 const std::optional<Color>& ImageSourceInfo::GetFillColor() const
413 {
414     return fillColor_;
415 }
416 
GetPixmap() const417 const RefPtr<PixelMap>& ImageSourceInfo::GetPixmap() const
418 {
419     return pixmap_;
420 }
421 
SupportObjCache() const422 bool ImageSourceInfo::SupportObjCache() const
423 {
424     if (IsPixmap()) {
425         return false;
426     }
427     if (!needCache_) {
428         return false;
429     }
430     return !GetSrc().empty() || resourceId_ != InternalResource::ResourceId::NO_ID;
431 }
432 
GetKey() const433 std::string ImageSourceInfo::GetKey() const
434 {
435     // only svg sets fillColor
436     if (isSvg_ && fillColor_.has_value()) {
437         return cacheKey_ + fillColor_.value().ColorToString();
438     }
439     return cacheKey_;
440 }
441 
SetContainerId(int32_t containerId)442 void ImageSourceInfo::SetContainerId(int32_t containerId)
443 {
444     containerId_ = containerId;
445 }
446 
GetContainerId() const447 int32_t ImageSourceInfo::GetContainerId() const
448 {
449     return containerId_;
450 }
451 
GetTaskKey() const452 std::string ImageSourceInfo::GetTaskKey() const
453 {
454     // only svg sets fillColor
455     if (isSvg_ && fillColor_.has_value()) {
456         return cacheKey_ + fillColor_.value().ColorToString() + std::to_string(containerId_);
457     }
458     return cacheKey_ + std::to_string(containerId_);
459 }
460 
CreateImageSourceInfoWithHost(const RefPtr<NG::FrameNode> & host)461 ImageSourceInfo ImageSourceInfo::CreateImageSourceInfoWithHost(const RefPtr<NG::FrameNode>& host)
462 {
463     ImageSourceInfo imageSourceInfo;
464     CHECK_NULL_RETURN(host, imageSourceInfo);
465     auto context = host->GetContext();
466     CHECK_NULL_RETURN(context, imageSourceInfo);
467 
468     std::string bundleName = context->GetBundleName();
469     std::string moduleName = context->GetModuleName();
470     imageSourceInfo.SetBundleName(bundleName);
471     imageSourceInfo.SetModuleName(moduleName);
472 
473     return imageSourceInfo;
474 }
475 } // namespace OHOS::Ace
476