• 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 <regex>
19 
20 #include "core/common/container.h"
21 
22 namespace OHOS::Ace {
23 namespace {
24 
25 constexpr uint32_t FILE_SUFFIX_LEN = 4;
26 constexpr uint32_t APNG_FILE_SUFFIX_LEN = 5;
27 
28 } // namespace
29 
IsSVGSource(const std::string & src,InternalResource::ResourceId resourceId)30 bool ImageSourceInfo::IsSVGSource(const std::string& src, InternalResource::ResourceId resourceId)
31 {
32     // 4 is the length of ".svg".
33     return (src.size() > FILE_SUFFIX_LEN && src.substr(src.size() - FILE_SUFFIX_LEN) == ".svg") ||
34            (src.empty() && resourceId > InternalResource::ResourceId::SVG_START &&
35                resourceId < InternalResource::ResourceId::SVG_END);
36 }
37 
IsPngSource(const std::string & src,InternalResource::ResourceId resourceId)38 bool ImageSourceInfo::IsPngSource(const std::string& src, InternalResource::ResourceId resourceId)
39 {
40     // 4 is the length of ".png" or is .apng
41     if (!src.empty()) {
42         std::string head = src.size() > APNG_FILE_SUFFIX_LEN
43                                ? src.substr(src.size() - APNG_FILE_SUFFIX_LEN, APNG_FILE_SUFFIX_LEN)
44                            : src.size() == 4 ? src.substr(src.size() - FILE_SUFFIX_LEN, FILE_SUFFIX_LEN)
45                                              : "";
46         std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
47 
48         return (head.size() > FILE_SUFFIX_LEN && head.substr(head.size() - FILE_SUFFIX_LEN) == ".png") ||
49                (head.size() > APNG_FILE_SUFFIX_LEN && head.substr(head.size() - APNG_FILE_SUFFIX_LEN) == ".apng");
50     } else if (resourceId < InternalResource::ResourceId::SVG_START) {
51         return true;
52     }
53     return false;
54 }
55 
IsValidBase64Head(const std::string & uri,const std::string & pattern)56 bool ImageSourceInfo::IsValidBase64Head(const std::string& uri, const std::string& pattern)
57 {
58     auto iter = uri.find_first_of(',');
59     if (iter == std::string::npos) {
60         LOGE("wrong base64 head format.");
61         return false;
62     }
63     std::string base64Head = uri.substr(0, iter);
64     std::regex regular(pattern);
65     return std::regex_match(base64Head, regular);
66 }
67 
IsUriOfDataAbilityEncoded(const std::string & uri,const std::string & pattern)68 bool ImageSourceInfo::IsUriOfDataAbilityEncoded(const std::string& uri, const std::string& pattern)
69 {
70     std::regex regular(pattern);
71     return std::regex_match(uri, regular);
72 }
73 
ResolveURIType(const std::string & uri)74 SrcType ImageSourceInfo::ResolveURIType(const std::string& uri)
75 {
76     if (uri.empty()) {
77         return SrcType::UNSUPPORTED;
78     }
79     auto iter = uri.find_first_of(':');
80     if (iter == std::string::npos) {
81         return SrcType::ASSET;
82     }
83     std::string head = uri.substr(0, iter);
84     std::transform(head.begin(), head.end(), head.begin(), [](unsigned char c) { return std::tolower(c); });
85     if (head == "http" || head == "https") {
86         return SrcType::NETWORK;
87     } else if (head == "file") {
88         return SrcType::FILE;
89     } else if (head == "internal") {
90         return SrcType::INTERNAL;
91     } else if (head == "data") {
92         static constexpr char BASE64_PATTERN[] =
93             "^data:image/(jpeg|JPEG|jpg|JPG|png|PNG|ico|ICO|gif|GIF|bmp|BMP|webp|WEBP);base64$";
94         if (IsValidBase64Head(uri, BASE64_PATTERN)) {
95             return SrcType::BASE64;
96         }
97         return SrcType::UNSUPPORTED;
98     } else if (head == "memory") {
99         return SrcType::MEMORY;
100     } else if (head == "resource") {
101         return SrcType::RESOURCE;
102     } else if (head == "dataability" || head == "datashare") {
103         if (IsUriOfDataAbilityEncoded(uri, "^dataability://.*?/media/.*/thumbnail/.*$") ||
104             IsUriOfDataAbilityEncoded(uri, "^datashare://.*?/media/.*/thumbnail/.*$")) {
105             return SrcType::DATA_ABILITY_DECODED;
106         }
107         return SrcType::DATA_ABILITY;
108     } else {
109         return SrcType::UNSUPPORTED;
110     }
111 }
112 
ImageSourceInfo(std::string imageSrc,Dimension width,Dimension height,InternalResource::ResourceId resourceId,const RefPtr<PixelMap> & pixmap)113 ImageSourceInfo::ImageSourceInfo(std::string imageSrc, Dimension width, Dimension height,
114     InternalResource::ResourceId resourceId, const RefPtr<PixelMap>& pixmap)
115     : src_(std::move(imageSrc)), sourceWidth_(width), sourceHeight_(height), resourceId_(resourceId), pixmap_(pixmap),
116       isSvg_(IsSVGSource(src_, resourceId_)), isPng_(IsPngSource(src_, resourceId_)), srcType_(ResolveSrcType())
117 {
118     // count how many source set.
119     int32_t count = 0;
120     if (!src_.empty()) {
121         ++count;
122     }
123     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
124         ++count;
125     }
126     if (pixmap != nullptr) {
127         ++count;
128     }
129     if (count > 1) {
130         LOGW("multi image source set, only one will be load.");
131     }
132     GenerateCacheKey();
133 }
134 
ResolveSrcType() const135 SrcType ImageSourceInfo::ResolveSrcType() const
136 {
137     if (pixmap_) {
138         return SrcType::PIXMAP;
139     }
140     if (!src_.empty()) {
141         return ResolveURIType(src_);
142     }
143     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
144         return SrcType::RESOURCE_ID;
145     }
146     return SrcType::UNSUPPORTED;
147 }
148 
GenerateCacheKey()149 void ImageSourceInfo::GenerateCacheKey()
150 {
151     auto name = ToString() + AceApplicationInfo::GetInstance().GetAbilityName();
152     cacheKey_ = std::to_string(std::hash<std::string> {}(name)) + std::to_string(static_cast<int32_t>(resourceId_));
153 }
154 
SetFillColor(const Color & color)155 void ImageSourceInfo::SetFillColor(const Color& color)
156 {
157     fillColor_.emplace(color.GetValue());
158 }
159 
operator ==(const ImageSourceInfo & info) const160 bool ImageSourceInfo::operator==(const ImageSourceInfo& info) const
161 {
162     // only svg uses fillColor
163     if (isSvg_ && fillColor_ != info.fillColor_) {
164         return false;
165     }
166     return ((!pixmap_ && !info.pixmap_) || (pixmap_ && info.pixmap_ && pixmap_ == info.pixmap_)) &&
167            // TODO: Use GetModifyId to distinguish two PixelMap objects after Media provides it
168            src_ == info.src_ && resourceId_ == info.resourceId_;
169 }
170 
operator !=(const ImageSourceInfo & info) const171 bool ImageSourceInfo::operator!=(const ImageSourceInfo& info) const
172 {
173     return !(operator==(info));
174 }
175 
SetSrc(const std::string & src,std::optional<Color> fillColor)176 void ImageSourceInfo::SetSrc(const std::string& src, std::optional<Color> fillColor)
177 {
178     src_ = src;
179     srcType_ = ResolveURIType(src_);
180     resourceId_ = InternalResource::ResourceId::NO_ID;
181     isSvg_ = IsSVGSource(src_, resourceId_);
182     fillColor_ = fillColor;
183     pixmap_ = nullptr;
184     GenerateCacheKey();
185 }
186 
GetSrc() const187 const std::string& ImageSourceInfo::GetSrc() const
188 {
189     return src_;
190 }
191 
SetResourceId(InternalResource::ResourceId id,std::optional<Color> fillColor)192 void ImageSourceInfo::SetResourceId(InternalResource::ResourceId id, std::optional<Color> fillColor)
193 {
194     resourceId_ = id;
195     srcType_ = SrcType::RESOURCE_ID;
196     src_.clear();
197     isSvg_ = IsSVGSource(src_, resourceId_);
198     fillColor_ = fillColor;
199     pixmap_ = nullptr;
200     GenerateCacheKey();
201 }
202 
GetResourceId() const203 InternalResource::ResourceId ImageSourceInfo::GetResourceId() const
204 {
205     return resourceId_;
206 }
207 
SetPixMap(const RefPtr<PixelMap> & pixmap,std::optional<Color> fillColor)208 void ImageSourceInfo::SetPixMap(const RefPtr<PixelMap>& pixmap, std::optional<Color> fillColor)
209 {
210     resourceId_ = InternalResource::ResourceId::NO_ID;
211     srcType_ = SrcType::PIXMAP;
212     src_.clear();
213     isSvg_ = IsSVGSource(src_, resourceId_);
214     fillColor_ = fillColor;
215     pixmap_ = pixmap;
216 }
217 
IsInternalResource() const218 bool ImageSourceInfo::IsInternalResource() const
219 {
220     return src_.empty() && resourceId_ != InternalResource::ResourceId::NO_ID && !pixmap_;
221 }
222 
IsValid() const223 bool ImageSourceInfo::IsValid() const
224 {
225     return (src_.empty() && resourceId_ != InternalResource::ResourceId::NO_ID) ||
226            (!src_.empty() && resourceId_ == InternalResource::ResourceId::NO_ID) || pixmap_;
227 }
228 
IsPng() const229 bool ImageSourceInfo::IsPng() const
230 {
231     return isPng_;
232 }
233 
IsSvg() const234 bool ImageSourceInfo::IsSvg() const
235 {
236     return isSvg_;
237 }
238 
IsPixmap() const239 bool ImageSourceInfo::IsPixmap() const
240 {
241     return pixmap_ != nullptr || SrcType::DATA_ABILITY_DECODED == srcType_;
242 }
243 
GetSrcType() const244 SrcType ImageSourceInfo::GetSrcType() const
245 {
246     return srcType_;
247 }
248 
ToString() const249 std::string ImageSourceInfo::ToString() const
250 {
251     if (!src_.empty()) {
252         return src_;
253     }
254     if (resourceId_ != InternalResource::ResourceId::NO_ID) {
255         return std::string("internal resource id: ") + std::to_string(static_cast<int32_t>(resourceId_));
256     }
257     if (pixmap_) {
258         return std::string("pixmapID: ") + pixmap_->GetId() + std::string(" -> modifyID: ") + pixmap_->GetModifyId();
259     }
260     return std::string("empty source");
261 }
262 
SetDimension(Dimension width,Dimension Height)263 void ImageSourceInfo::SetDimension(Dimension width, Dimension Height)
264 {
265     sourceWidth_ = width;
266     sourceHeight_ = Height;
267 }
268 
IsSourceDimensionValid() const269 bool ImageSourceInfo::IsSourceDimensionValid() const
270 {
271     return sourceWidth_.IsValid() && sourceHeight_.IsValid();
272 }
273 
GetSourceSize() const274 Size ImageSourceInfo::GetSourceSize() const
275 {
276     return Size(sourceWidth_.Value(), sourceHeight_.Value());
277 }
278 
Reset()279 void ImageSourceInfo::Reset()
280 {
281     src_.clear();
282     sourceWidth_ = Dimension(-1);
283     sourceHeight_ = Dimension(-1);
284     resourceId_ = InternalResource::ResourceId::NO_ID;
285     isSvg_ = false;
286     fillColor_.reset();
287     pixmap_ = nullptr;
288     cacheKey_.clear();
289 }
290 
GetFillColor() const291 const std::optional<Color>& ImageSourceInfo::GetFillColor() const
292 {
293     return fillColor_;
294 }
295 
GetPixmap() const296 const RefPtr<PixelMap>& ImageSourceInfo::GetPixmap() const
297 {
298     return pixmap_;
299 }
300 
IsSupportCache() const301 bool ImageSourceInfo::IsSupportCache() const
302 {
303     if (IsPixmap()) {
304         return false;
305     }
306     return !src_.empty() || resourceId_ != InternalResource::ResourceId::NO_ID;
307 }
308 
GetKey() const309 std::string ImageSourceInfo::GetKey() const
310 {
311     // only svg sets fillColor
312     if (isSvg_ && fillColor_.has_value()) {
313         return cacheKey_ + fillColor_.value().ColorToString();
314     }
315     return cacheKey_;
316 }
317 
318 } // namespace OHOS::Ace
319