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