• 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/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