• 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_loader.h"
17 
18 #include <condition_variable>
19 #include <mutex>
20 #include <ratio>
21 #include <regex>
22 #include <string_view>
23 #include <unistd.h>
24 
25 #include "include/utils/SkBase64.h"
26 
27 #include "base/memory/ace_type.h"
28 #include "base/utils/system_properties.h"
29 #include "core/common/resource/resource_manager.h"
30 #include "core/common/resource/resource_object.h"
31 #include "core/common/resource/resource_wrapper.h"
32 #include "core/components/theme/theme_utils.h"
33 
34 #ifdef USE_ROSEN_DRAWING
35 #include "drawing/engine_adapter/skia_adapter/skia_data.h"
36 #endif
37 
38 #include "base/image/file_uri_helper.h"
39 #include "base/image/image_source.h"
40 #include "base/log/ace_trace.h"
41 #include "base/network/download_manager.h"
42 #include "base/resource/ace_res_config.h"
43 #include "base/resource/asset_manager.h"
44 #include "base/thread/background_task_executor.h"
45 #include "base/utils/string_utils.h"
46 #include "base/utils/utils.h"
47 #include "core/common/ace_application_info.h"
48 #include "core/common/container.h"
49 #include "core/common/thread_checker.h"
50 #include "core/components/common/layout/constants.h"
51 #include "core/components_ng/image_provider/image_data.h"
52 #ifdef USE_ROSEN_DRAWING
53 #include "core/components_ng/image_provider/adapter/rosen/drawing_image_data.h"
54 #endif
55 #include "core/image/image_cache.h"
56 #include "core/image/image_file_cache.h"
57 #include "core/pipeline/pipeline_context.h"
58 
59 namespace OHOS::Ace {
60 namespace {
61 
62 constexpr size_t FILE_HEAD_LENGTH = 7;           // 7 is the size of "file://"
63 constexpr size_t MEMORY_HEAD_LENGTH = 9;         // 9 is the size of "memory://"
64 constexpr size_t INTERNAL_FILE_HEAD_LENGTH = 15; // 15 is the size of "internal://app/"
65 // regex for "resource://colormode/xxx.type", colormode can be "light" or "dark", xxx represents system resource id,
66 // type can be "jpg", "png", "svg" and so on.
67 const std::regex MEDIA_RES_ID_REGEX(R"(^resource://\w+/([0-9]+)\.\w+$)", std::regex::icase);
68 const std::regex MEDIA_APP_RES_PATH_REGEX(R"(^resource://RAWFILE/(.*)$)");
69 const std::regex MEDIA_APP_RES_ID_REGEX(R"(^resource://.*/([0-9]+)\.\w+$)", std::regex::icase);
70 const std::regex MEDIA_RES_NAME_REGEX(R"(^resource://.*/(\w+)\.\w+$)", std::regex::icase);
71 constexpr uint32_t MEDIA_RESOURCE_MATCH_SIZE = 2;
72 
73 const std::chrono::duration<int, std::milli> TIMEOUT_DURATION(10000);
74 
75 #ifdef WINDOWS_PLATFORM
realpath(const char * path,char * resolved_path)76 char* realpath(const char* path, char* resolved_path)
77 {
78     if (strcpy_s(resolved_path, PATH_MAX, path) != 0) {
79         return nullptr;
80     }
81     return resolved_path;
82 }
83 #endif
84 } // namespace
85 
RemovePathHead(const std::string & uri)86 std::string ImageLoader::RemovePathHead(const std::string& uri)
87 {
88     auto iter = uri.find_first_of(':');
89     if (iter == std::string::npos) {
90         TAG_LOGW(AceLogTag::ACE_IMAGE, "No scheme, not a File or Memory path");
91         return std::string();
92     }
93     std::string head = uri.substr(0, iter);
94     if ((head == "file" && uri.size() > FILE_HEAD_LENGTH) || (head == "memory" && uri.size() > MEMORY_HEAD_LENGTH) ||
95         (head == "internal" && uri.size() > INTERNAL_FILE_HEAD_LENGTH)) {
96         // the file uri format is like "file:///data/data...",
97         // the memory uri format is like "memory://imagename.png" for example,
98         // iter + 3 to get the absolutely file path substring : "/data/data..." or the image name: "imagename.png"
99         return uri.substr(iter + 3);
100     }
101     TAG_LOGW(AceLogTag::ACE_IMAGE, "Wrong scheme, not a File!");
102     return std::string();
103 }
104 
CreateImageLoader(const ImageSourceInfo & imageSourceInfo)105 RefPtr<ImageLoader> ImageLoader::CreateImageLoader(const ImageSourceInfo& imageSourceInfo)
106 {
107     SrcType srcType = imageSourceInfo.GetSrcType();
108     switch (srcType) {
109         case SrcType::INTERNAL:
110         case SrcType::FILE: {
111             return MakeRefPtr<FileImageLoader>();
112         }
113         case SrcType::NETWORK: {
114             return MakeRefPtr<NetworkImageLoader>();
115         }
116         case SrcType::ASSET: {
117             return MakeRefPtr<AssetImageLoader>();
118         }
119         case SrcType::BASE64: {
120             return MakeRefPtr<Base64ImageLoader>();
121         }
122         case SrcType::RESOURCE: {
123             return MakeRefPtr<ResourceImageLoader>();
124         }
125         case SrcType::DATA_ABILITY: {
126             return MakeRefPtr<DataProviderImageLoader>();
127         }
128         case SrcType::DATA_ABILITY_DECODED: {
129             return MakeRefPtr<DecodedDataProviderImageLoader>();
130         }
131         case SrcType::MEMORY: {
132             if (Container::IsCurrentUseNewPipeline()) {
133                 return MakeRefPtr<SharedMemoryImageLoader>();
134             }
135             TAG_LOGW(
136                 AceLogTag::ACE_IMAGE, "Image source type: shared memory. image data is not come from image loader.");
137             return nullptr;
138         }
139         case SrcType::RESOURCE_ID: {
140             return MakeRefPtr<InternalImageLoader>();
141         }
142         case SrcType::PIXMAP: {
143             return MakeRefPtr<PixelMapImageLoader>();
144         }
145         case SrcType::ASTC: {
146             return MakeRefPtr<AstcImageLoader>();
147         }
148         default: {
149             TAG_LOGW(AceLogTag::ACE_IMAGE,
150                 "Image source type not supported!  srcType: %{public}d, sourceInfo: %{public}s", srcType,
151                 imageSourceInfo.ToString().c_str());
152             return nullptr;
153         }
154     }
155 }
156 
157 #ifndef USE_ROSEN_DRAWING
LoadDataFromCachedFile(const std::string & uri)158 sk_sp<SkData> ImageLoader::LoadDataFromCachedFile(const std::string& uri)
159 #else
160 std::shared_ptr<RSData> ImageLoader::LoadDataFromCachedFile(const std::string& uri)
161 #endif
162 {
163     std::string cacheFilePath = ImageFileCache::GetInstance().GetImageCacheFilePath(uri);
164     if (cacheFilePath.length() > PATH_MAX) {
165         TAG_LOGW(
166             AceLogTag::ACE_IMAGE, "cache file path is too long, cacheFilePath: %{private}s", cacheFilePath.c_str());
167         return nullptr;
168     }
169     cacheFilePath = ImageFileCache::GetInstance().GetCacheFilePath(uri);
170     if (cacheFilePath == "") {
171         return nullptr;
172     }
173     char realPath[PATH_MAX] = { 0x00 };
174     if (realpath(cacheFilePath.c_str(), realPath) == nullptr) {
175         TAG_LOGW(AceLogTag::ACE_IMAGE, "realpath fail! cacheFilePath: %{private}s, fail reason: %{public}s",
176             cacheFilePath.c_str(), strerror(errno));
177         return nullptr;
178     }
179     std::unique_ptr<FILE, decltype(&fclose)> file(fopen(realPath, "rb"), fclose);
180     if (file) {
181 #ifndef USE_ROSEN_DRAWING
182         return SkData::MakeFromFILE(file.get());
183 #else
184         auto skData = SkData::MakeFromFILE(file.get());
185         CHECK_NULL_RETURN(skData, nullptr);
186         auto rsData = std::make_shared<RSData>();
187         rsData->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(skData);
188         return rsData;
189 #endif
190     }
191     return nullptr;
192 }
193 
194 #ifndef USE_ROSEN_DRAWING
QueryImageDataFromImageCache(const ImageSourceInfo & sourceInfo)195 sk_sp<SkData> ImageLoader::QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo)
196 #else
197 std::shared_ptr<RSData> ImageLoader::QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo)
198 #endif
199 {
200     auto pipelineCtx = PipelineContext::GetCurrentContext();
201     CHECK_NULL_RETURN(pipelineCtx, nullptr);
202     auto imageCache = pipelineCtx->GetImageCache();
203     CHECK_NULL_RETURN(imageCache, nullptr);
204     auto cacheData = imageCache->GetCacheImageData(sourceInfo.GetKey());
205     CHECK_NULL_RETURN(cacheData, nullptr);
206 #ifndef USE_ROSEN_DRAWING
207     const auto* skData = reinterpret_cast<const sk_sp<SkData>*>(cacheData->GetDataWrapper());
208     return *skData;
209 #else
210     auto rosenCachedImageData = AceType::DynamicCast<NG::DrawingImageData>(cacheData);
211     CHECK_NULL_RETURN(rosenCachedImageData, nullptr);
212     return rosenCachedImageData->GetRSData();
213 #endif
214 }
215 
CacheImageData(const std::string & key,const RefPtr<NG::ImageData> & imageData)216 void ImageLoader::CacheImageData(const std::string& key, const RefPtr<NG::ImageData>& imageData)
217 {
218     auto pipelineCtx = PipelineContext::GetCurrentContext();
219     CHECK_NULL_VOID(pipelineCtx);
220     auto imageCache = pipelineCtx->GetImageCache();
221     CHECK_NULL_VOID(imageCache);
222     imageCache->CacheImageData(key, imageData);
223 }
224 
LoadImageDataFromFileCache(const std::string & key,const std::string & suffix)225 RefPtr<NG::ImageData> ImageLoader::LoadImageDataFromFileCache(const std::string& key, const std::string& suffix)
226 {
227     ACE_FUNCTION_TRACE();
228     return ImageFileCache::GetInstance().GetDataFromCacheFile(key, suffix);
229 }
230 
231 // NG ImageLoader entrance
GetImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & context)232 RefPtr<NG::ImageData> ImageLoader::GetImageData(const ImageSourceInfo& src, const WeakPtr<PipelineBase>& context)
233 {
234     ACE_FUNCTION_TRACE();
235     bool queryCache = !src.GetIsConfigurationChange();
236     if (src.IsPixmap()) {
237         return LoadDecodedImageData(src, context);
238     }
239 #ifndef USE_ROSEN_DRAWING
240     if (queryCache) {
241         auto cachedData = ImageLoader::QueryImageDataFromImageCache(src);
242         if (cachedData) {
243             return NG::ImageData::MakeFromDataWrapper(&cachedData);
244         }
245     }
246     auto skData = LoadImageData(src, context);
247     CHECK_NULL_RETURN(skData, nullptr);
248     auto data = NG::ImageData::MakeFromDataWrapper(&skData);
249     ImageLoader::CacheImageData(src.GetKey(), data);
250     return data;
251 #else
252     std::shared_ptr<RSData> rsData = nullptr;
253     do {
254         if (queryCache) {
255             rsData = ImageLoader::QueryImageDataFromImageCache(src);
256             if (rsData) {
257                 break;
258             }
259         }
260         rsData = LoadImageData(src, context);
261         CHECK_NULL_RETURN(rsData, nullptr);
262         ImageLoader::CacheImageData(src.GetKey(), AceType::MakeRefPtr<NG::DrawingImageData>(rsData));
263     } while (0);
264     return AceType::MakeRefPtr<NG::DrawingImageData>(rsData);
265 #endif
266 }
267 
268 // NG ImageLoader entrance
DownloadImage(DownloadCallback && downloadCallback,const std::string & src,bool sync)269 bool NetworkImageLoader::DownloadImage(DownloadCallback&& downloadCallback, const std::string& src, bool sync)
270 {
271     return sync ? DownloadManager::GetInstance()->DownloadSync(std::move(downloadCallback), src, Container::CurrentId())
272                 : DownloadManager::GetInstance()->DownloadAsync(
273                       std::move(downloadCallback), src, Container::CurrentId());
274 }
275 
276 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> &)277 sk_sp<SkData> FileImageLoader::LoadImageData(
278     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& /* context */)
279 #else
280 std::shared_ptr<RSData> FileImageLoader::LoadImageData(
281     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& /* context */)
282 #endif
283 {
284     ACE_SCOPED_TRACE("LoadImageData %s", imageSourceInfo.ToString().c_str());
285     const auto& src = imageSourceInfo.GetSrc();
286     std::string filePath = RemovePathHead(src);
287     if (imageSourceInfo.GetSrcType() == SrcType::INTERNAL) {
288         // the internal source uri format is like "internal://app/imagename.png", the absolute path of which is like
289         // "/data/data/{bundleName}/files/imagename.png"
290         auto bundleName = AceApplicationInfo::GetInstance().GetPackageName();
291         if (bundleName.empty()) {
292             TAG_LOGW(AceLogTag::ACE_IMAGE, "bundleName is empty, LoadImageData for internal source fail!");
293             return nullptr;
294         }
295         if (!StringUtils::StartWith(filePath, "app/")) { // "app/" is infix of internal path
296             TAG_LOGW(AceLogTag::ACE_IMAGE, "internal path format is wrong. path is %{private}s", src.c_str());
297             return nullptr;
298         }
299         filePath = std::string("/data/data/") // head of absolute path
300                        .append(bundleName)
301                        .append("/files/")           // infix of absolute path
302                        .append(filePath.substr(4)); // 4 is the length of "app/" from "internal://app/"
303     } else if (imageSourceInfo.GetSrcType() == SrcType::FILE) {
304         filePath = FileUriHelper::GetRealPath(src);
305     }
306     if (filePath.length() > PATH_MAX) {
307         TAG_LOGW(AceLogTag::ACE_IMAGE, "src path is too long");
308         return nullptr;
309     }
310     char realPath[PATH_MAX] = { 0x00 };
311     if (realpath(filePath.c_str(), realPath) == nullptr) {
312         TAG_LOGW(AceLogTag::ACE_IMAGE, "realpath fail! filePath: %{public}s, fail reason: %{public}s src:%{public}s",
313             filePath.c_str(), strerror(errno), src.c_str());
314         return nullptr;
315     }
316     auto result = SkData::MakeFromFileName(realPath);
317     if (!result) {
318         TAG_LOGW(AceLogTag::ACE_IMAGE,
319             "read data failed, filePath: %{public}s, src: %{public}s, fail reason: "
320             "%{public}s",
321             filePath.c_str(), src.c_str(), strerror(errno));
322     }
323 #ifndef USE_ROSEN_DRAWING
324 #ifdef PREVIEW
325     // on Windows previewer, SkData::MakeFromFile keeps the file open during SkData's lifetime
326     // return a copy to release the file handle
327     CHECK_NULL_RETURN(result, nullptr);
328     return SkData::MakeWithCopy(result->data(), result->size());
329 #else
330     return result;
331 #endif
332 #else
333     CHECK_NULL_RETURN(result, nullptr);
334     auto rsData = std::make_shared<RSData>();
335 #ifdef PREVIEW
336     // on Windows previewer, SkData::MakeFromFile keeps the file open during Drawing::Data's lifetime
337     // return a copy to release the file handle
338     return rsData->BuildWithCopy(result->data(), result->size()) ? rsData : nullptr;
339 #else
340     rsData->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(result);
341     return rsData;
342 #endif
343 #endif
344 }
345 
346 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)347 sk_sp<SkData> DataProviderImageLoader::LoadImageData(
348     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
349 #else
350 std::shared_ptr<RSData> DataProviderImageLoader::LoadImageData(
351     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
352 #endif
353 {
354     const auto& src = imageSourceInfo.GetSrc();
355     auto drawingData = ImageLoader::LoadDataFromCachedFile(src);
356     if (drawingData) {
357         return drawingData;
358     }
359     auto pipeline = context.Upgrade();
360     CHECK_NULL_RETURN(pipeline, nullptr);
361     auto dataProvider = pipeline->GetDataProviderManager();
362     CHECK_NULL_RETURN(dataProvider, nullptr);
363     auto res = dataProvider->GetDataProviderResFromUri(src);
364     CHECK_NULL_RETURN(res, nullptr);
365 #ifndef USE_ROSEN_DRAWING
366     auto data = SkData::MakeFromMalloc(res->GetData().release(), res->GetSize());
367 #else
368     // function is ok, just pointer cast from SKData to RSData
369     auto skData = SkData::MakeFromMalloc(res->GetData().release(), res->GetSize());
370     CHECK_NULL_RETURN(skData, nullptr);
371     auto data = std::make_shared<RSData>();
372     data->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(skData);
373 #endif
374     return data;
375 }
376 
377 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)378 sk_sp<SkData> AssetImageLoader::LoadImageData(
379     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
380 #else
381 std::shared_ptr<RSData> AssetImageLoader::LoadImageData(
382     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
383 #endif
384 {
385     ACE_FUNCTION_TRACE();
386     const auto& src = imageSourceInfo.GetSrc();
387     if (src.empty()) {
388         TAG_LOGW(AceLogTag::ACE_IMAGE, "image src is empty");
389         return nullptr;
390     }
391 
392     std::string assetSrc(src);
393     if (assetSrc[0] == '/') {
394         assetSrc = assetSrc.substr(1); // get the asset src without '/'.
395     } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
396         assetSrc = assetSrc.substr(2); // get the asset src without './'.
397     }
398     auto pipelineContext = context.Upgrade();
399     if (!pipelineContext) {
400         TAG_LOGW(AceLogTag::ACE_IMAGE, "invalid pipeline context");
401         return nullptr;
402     }
403     auto assetManager = pipelineContext->GetAssetManager();
404     if (!assetManager) {
405         TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset manager!");
406         return nullptr;
407     }
408     auto assetData = assetManager->GetAsset(assetSrc);
409     if (!assetData) {
410         TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset data!");
411         return nullptr;
412     }
413     const uint8_t* data = assetData->GetData();
414     const size_t dataSize = assetData->GetSize();
415 #ifndef USE_ROSEN_DRAWING
416     return SkData::MakeWithCopy(data, dataSize);
417 #else
418     auto drawingData = std::make_shared<RSData>();
419     drawingData->BuildWithCopy(data, dataSize);
420     return drawingData;
421 #endif
422 }
423 
LoadJsonData(const std::string & src,const WeakPtr<PipelineBase> context)424 std::string AssetImageLoader::LoadJsonData(const std::string& src, const WeakPtr<PipelineBase> context)
425 {
426     if (src.empty()) {
427         TAG_LOGW(AceLogTag::ACE_IMAGE, "image src is empty");
428         return "";
429     }
430 
431     std::string assetSrc(src);
432     if (assetSrc[0] == '/') {
433         assetSrc = assetSrc.substr(1); // get the asset src without '/'.
434     } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
435         assetSrc = assetSrc.substr(2); // get the asset src without './'.
436     }
437     auto pipelineContext = context.Upgrade();
438     if (!pipelineContext) {
439         return "";
440     }
441     auto assetManager = pipelineContext->GetAssetManager();
442     if (!assetManager) {
443         TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset manager!");
444         return "";
445     }
446     auto assetData = assetManager->GetAsset(assetSrc);
447     if (!assetData || !assetData->GetData()) {
448         TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset data!");
449         return "";
450     }
451     return std::string((char*)assetData->GetData(), assetData->GetSize());
452 }
453 
454 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)455 sk_sp<SkData> NetworkImageLoader::LoadImageData(
456     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
457 #else
458 std::shared_ptr<RSData> NetworkImageLoader::LoadImageData(
459     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
460 #endif
461 {
462     auto uri = imageSourceInfo.GetSrc();
463     auto pipelineContext = context.Upgrade();
464     if (!pipelineContext || pipelineContext->IsJsCard()) {
465         TAG_LOGW(AceLogTag::ACE_IMAGE, "network image in JS card is forbidden.");
466         return nullptr;
467     }
468     // 1. find in cache file path.
469 #ifndef USE_ROSEN_DRAWING
470     auto skData = ImageLoader::LoadDataFromCachedFile(uri);
471     if (skData) {
472         return skData;
473     }
474 #else
475     auto drawingData = ImageLoader::LoadDataFromCachedFile(uri);
476     if (drawingData) {
477         return drawingData;
478     }
479 #endif
480 
481     // 2. if not found. download it.
482     if (SystemProperties::GetDebugEnabled()) {
483         TAG_LOGI(AceLogTag::ACE_IMAGE, "Download network image, uri=%{public}s", uri.c_str());
484     }
485     std::vector<uint8_t> imageData;
486     if (!DownloadManager::GetInstance()->Download(uri, imageData) || imageData.empty()) {
487         TAG_LOGW(AceLogTag::ACE_IMAGE, "Download network image %{private}s failed!", uri.c_str());
488         return nullptr;
489     }
490 #ifndef USE_ROSEN_DRAWING
491     sk_sp<SkData> data = SkData::MakeWithCopy(imageData.data(), imageData.size());
492 #else
493     auto data = std::make_shared<RSData>();
494     data->BuildWithCopy(imageData.data(), imageData.size());
495 #endif
496     // 3. write it into file cache.
497     WriteCacheToFile(uri, imageData);
498     return data;
499 }
500 
501 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)502 sk_sp<SkData> InternalImageLoader::LoadImageData(
503     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
504 #else
505 std::shared_ptr<RSData> InternalImageLoader::LoadImageData(
506     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
507 #endif
508 {
509     size_t imageSize = 0;
510     const uint8_t* internalData =
511         InternalResource::GetInstance().GetResource(imageSourceInfo.GetResourceId(), imageSize);
512     if (internalData == nullptr) {
513         TAG_LOGW(AceLogTag::ACE_IMAGE, "data null, the resource id may be wrong.");
514         return nullptr;
515     }
516 #ifndef USE_ROSEN_DRAWING
517     return SkData::MakeWithCopy(internalData, imageSize);
518 #else
519     auto drawingData = std::make_shared<RSData>();
520     drawingData->BuildWithCopy(internalData, imageSize);
521     return drawingData;
522 #endif
523 }
524 
525 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)526 sk_sp<SkData> Base64ImageLoader::LoadImageData(
527     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
528 #else
529 std::shared_ptr<RSData> Base64ImageLoader::LoadImageData(
530     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
531 #endif
532 {
533     std::string_view base64Code = GetBase64ImageCode(imageSourceInfo.GetSrc());
534     if (base64Code.size() == 0) {
535         return nullptr;
536     }
537 
538     size_t outputLen;
539     SkBase64::Error error = SkBase64::Decode(base64Code.data(), base64Code.size(), nullptr, &outputLen);
540     if (error != SkBase64::Error::kNoError) {
541         TAG_LOGW(AceLogTag::ACE_IMAGE, "error base64 image code!");
542         return nullptr;
543     }
544 
545 #ifndef USE_ROSEN_DRAWING
546     sk_sp<SkData> resData = SkData::MakeUninitialized(outputLen);
547     void* output = resData->writable_data();
548 #else
549     auto resData = std::make_shared<RSData>();
550     resData->BuildUninitialized(outputLen);
551     void* output = resData->WritableData();
552 #endif
553     error = SkBase64::Decode(base64Code.data(), base64Code.size(), output, &outputLen);
554     if (error != SkBase64::Error::kNoError) {
555         TAG_LOGW(AceLogTag::ACE_IMAGE, "error base64 image code!");
556         return nullptr;
557     }
558     return resData;
559 }
560 
GetBase64ImageCode(const std::string & uri)561 std::string_view Base64ImageLoader::GetBase64ImageCode(const std::string& uri)
562 {
563     auto iter = uri.find_first_of(',');
564     if (iter == std::string::npos || iter == uri.size() - 1) {
565         TAG_LOGW(AceLogTag::ACE_IMAGE, "wrong code format!");
566         return std::string_view();
567     }
568     // iter + 1 to skip the ","
569     std::string_view code(uri.c_str() + (iter + 1));
570     return code;
571 }
572 
GetResourceId(const std::string & uri,uint32_t & resId) const573 bool ResourceImageLoader::GetResourceId(const std::string& uri, uint32_t& resId) const
574 {
575     std::smatch matches;
576     if (std::regex_match(uri, matches, MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
577         resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
578         return true;
579     }
580 
581     std::smatch appMatches;
582     if (std::regex_match(uri, appMatches, MEDIA_APP_RES_ID_REGEX) && appMatches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
583         resId = static_cast<uint32_t>(std::stoul(appMatches[1].str()));
584         return true;
585     }
586 
587     return false;
588 }
589 
GetResourceId(const std::string & uri,std::string & path) const590 bool ResourceImageLoader::GetResourceId(const std::string& uri, std::string& path) const
591 {
592     std::smatch matches;
593     if (std::regex_match(uri, matches, MEDIA_APP_RES_PATH_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
594         path = matches[1].str();
595         return true;
596     }
597 
598     return false;
599 }
600 
GetResourceName(const std::string & uri,std::string & resName) const601 bool ResourceImageLoader::GetResourceName(const std::string& uri, std::string& resName) const
602 {
603     std::smatch matches;
604     if (std::regex_match(uri, matches, MEDIA_RES_NAME_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
605         resName = matches[1].str();
606         return true;
607     }
608 
609     return false;
610 }
611 
612 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)613 sk_sp<SkData> ResourceImageLoader::LoadImageData(
614     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
615 #else
616 std::shared_ptr<RSData> ResourceImageLoader::LoadImageData(
617     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
618 #endif
619 {
620     auto uri = imageSourceInfo.GetSrc();
621     auto bundleName = imageSourceInfo.GetBundleName();
622     auto moudleName = imageSourceInfo.GetModuleName();
623 
624     auto resourceObject = AceType::MakeRefPtr<ResourceObject>(bundleName, moudleName);
625     RefPtr<ResourceAdapter> resourceAdapter = nullptr;
626     RefPtr<ThemeConstants> themeConstants = nullptr;
627     if (SystemProperties::GetResourceDecoupling()) {
628         resourceAdapter = ResourceManager::GetInstance().GetOrCreateResourceAdapter(resourceObject);
629         CHECK_NULL_RETURN(resourceAdapter, nullptr);
630     } else {
631         auto themeManager = PipelineBase::CurrentThemeManager();
632         CHECK_NULL_RETURN(themeManager, nullptr);
633         themeConstants = themeManager->GetThemeConstants();
634         CHECK_NULL_RETURN(themeConstants, nullptr);
635     }
636     auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
637 
638     std::unique_ptr<uint8_t[]> data;
639     size_t dataLen = 0;
640     std::string rawFile;
641     if (!imageSourceInfo.GetIsUriPureNumber() && GetResourceId(uri, rawFile)) {
642         // must fit raw file firstly, as file name may contains number
643         if (!resourceWrapper->GetRawFileData(rawFile, dataLen, data, bundleName, moudleName)) {
644             TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by name failed, uri:%{private}s, rawFile:%{public}s",
645                 uri.c_str(), rawFile.c_str());
646             return nullptr;
647         }
648 #ifndef USE_ROSEN_DRAWING
649         return SkData::MakeWithCopy(data.get(), dataLen);
650 #else
651         auto drawingData = std::make_shared<RSData>();
652         drawingData->BuildWithCopy(data.get(), dataLen);
653         return drawingData;
654 #endif
655     }
656     uint32_t resId = 0;
657     if (!imageSourceInfo.GetIsUriPureNumber() && GetResourceId(uri, resId)) {
658         if (!resourceWrapper->GetMediaData(resId, dataLen, data, bundleName, moudleName)) {
659             TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by id failed, uri:%{private}s, id:%{public}u", uri.c_str(),
660                 resId);
661             return nullptr;
662         }
663 #ifndef USE_ROSEN_DRAWING
664         return SkData::MakeWithCopy(data.get(), dataLen);
665 #else
666         auto drawingData = std::make_shared<RSData>();
667         drawingData->BuildWithCopy(data.get(), dataLen);
668         return drawingData;
669 #endif
670     }
671     std::string resName;
672     if (GetResourceName(uri, resName)) {
673         if (!resourceWrapper->GetMediaData(resName, dataLen, data, bundleName, moudleName)) {
674             TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by name failed, uri:%{private}s, resName:%{public}s",
675                 uri.c_str(), resName.c_str());
676             return nullptr;
677         }
678 #ifndef USE_ROSEN_DRAWING
679         return SkData::MakeWithCopy(data.get(), dataLen);
680 #else
681         auto drawingData = std::make_shared<RSData>();
682         drawingData->BuildWithCopy(data.get(), dataLen);
683         return drawingData;
684 #endif
685     }
686     TAG_LOGW(AceLogTag::ACE_IMAGE, "load image data failed, as uri is invalid:%{private}s", uri.c_str());
687     return nullptr;
688 }
689 
690 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)691 sk_sp<SkData> DecodedDataProviderImageLoader::LoadImageData(
692     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
693 #else
694 std::shared_ptr<RSData> DecodedDataProviderImageLoader::LoadImageData(
695     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
696 #endif
697 {
698     return nullptr;
699 }
700 
701 // return orientation of pixmap for cache key
GetThumbnailOrientation(const ImageSourceInfo & src)702 std::string DecodedDataProviderImageLoader::GetThumbnailOrientation(const ImageSourceInfo& src)
703 {
704     auto pipeline = PipelineContext::GetCurrentContext();
705     CHECK_NULL_RETURN(pipeline, "");
706     auto dataProvider = pipeline->GetDataProviderManager();
707     CHECK_NULL_RETURN(dataProvider, "");
708 
709     // get file fd
710     // concat to get file path ("datashare://media/xx")
711     auto path = src.GetSrc();
712     auto pos = path.find("/thumbnail");
713     path = path.substr(0, pos);
714     int32_t fd = dataProvider->GetDataProviderFile(path, "r");
715     CHECK_NULL_RETURN(fd >= 0, "");
716 
717     // check image orientation
718     auto imageSrc = ImageSource::Create(fd);
719     CHECK_NULL_RETURN(imageSrc, "");
720     std::string orientation = imageSrc->GetProperty("Orientation");
721     return orientation;
722 }
723 
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)724 RefPtr<NG::ImageData> DecodedDataProviderImageLoader::LoadDecodedImageData(
725     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
726 {
727 #if !defined(PIXEL_MAP_SUPPORTED)
728     return nullptr;
729 #else
730     ACE_FUNCTION_TRACE();
731     auto pipeline = pipelineWk.Upgrade();
732     CHECK_NULL_RETURN(pipeline, nullptr);
733     auto dataProvider = pipeline->GetDataProviderManager();
734     CHECK_NULL_RETURN(dataProvider, nullptr);
735 
736     void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
737     auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
738     CHECK_NULL_RETURN(pixmap, nullptr);
739     TAG_LOGI(AceLogTag::ACE_IMAGE,
740         "src=%{public}s, pixmap from Media width*height=%{public}d*%{public}d, ByteCount=%{public}d",
741         src.ToString().c_str(), pixmap->GetWidth(), pixmap->GetHeight(), pixmap->GetByteCount());
742     if (SystemProperties::GetDebugPixelMapSaveEnabled()) {
743         pixmap->SavePixelMapToFile("_fromMedia_");
744     }
745 
746     auto cache = pipeline->GetImageCache();
747     if (cache) {
748         cache->CacheImageData(src.GetKey(), MakeRefPtr<NG::PixmapData>(pixmap));
749     }
750     return MakeRefPtr<NG::PixmapData>(pixmap);
751 #endif
752 }
753 
754 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)755 sk_sp<SkData> PixelMapImageLoader::LoadImageData(
756     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
757 #else
758 std::shared_ptr<RSData> PixelMapImageLoader::LoadImageData(
759     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
760 #endif
761 {
762     return nullptr;
763 }
764 
LoadDecodedImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)765 RefPtr<NG::ImageData> PixelMapImageLoader::LoadDecodedImageData(
766     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
767 {
768 #if !defined(PIXEL_MAP_SUPPORTED)
769     return nullptr;
770 #else
771     if (!imageSourceInfo.GetPixmap()) {
772         TAG_LOGW(AceLogTag::ACE_IMAGE, "no pixel map in imageSourceInfo, imageSourceInfo: %{public}s",
773             imageSourceInfo.ToString().c_str());
774         return nullptr;
775     }
776     if (SystemProperties::GetDebugEnabled()) {
777         TAG_LOGI(AceLogTag::ACE_IMAGE, "src is pixmap %{public}s", imageSourceInfo.ToString().c_str());
778     }
779     return MakeRefPtr<NG::PixmapData>(imageSourceInfo.GetPixmap());
780 #endif
781 }
782 
783 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)784 sk_sp<SkData> SharedMemoryImageLoader::LoadImageData(
785     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
786 #else
787 std::shared_ptr<RSData> SharedMemoryImageLoader::LoadImageData(
788     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
789 #endif
790 {
791     CHECK_RUN_ON(BACKGROUND);
792     auto pipeline = pipelineWk.Upgrade();
793     CHECK_NULL_RETURN(pipeline, nullptr);
794     auto manager = pipeline->GetOrCreateSharedImageManager();
795     auto id = RemovePathHead(src.GetSrc());
796     bool found = manager->FindImageInSharedImageMap(id, AceType::WeakClaim(this));
797     // image data not ready yet, wait for data
798     if (!found) {
799         manager->RegisterLoader(id, AceType::WeakClaim(this));
800         // wait for SharedImageManager to notify
801         std::unique_lock<std::mutex> lock(mtx_);
802         auto status = cv_.wait_for(lock, TIMEOUT_DURATION);
803         if (status == std::cv_status::timeout) {
804             TAG_LOGW(AceLogTag::ACE_IMAGE, "load SharedMemoryImage timeout! %{public}s", src.ToString().c_str());
805             return nullptr;
806         }
807     }
808 
809     std::unique_lock<std::mutex> lock(mtx_);
810 #ifndef USE_ROSEN_DRAWING
811     auto skData = SkData::MakeWithCopy(data_.data(), data_.size());
812     return skData;
813 #else
814     auto drawingData = std::make_shared<RSData>();
815     drawingData->BuildWithCopy(data_.data(), data_.size());
816     return drawingData;
817 #endif
818 }
819 
UpdateData(const std::string & uri,const std::vector<uint8_t> & memData)820 void SharedMemoryImageLoader::UpdateData(const std::string& uri, const std::vector<uint8_t>& memData)
821 {
822     TAG_LOGI(AceLogTag::ACE_IMAGE, "SharedMemory image data is ready %{public}s", uri.c_str());
823     {
824         std::scoped_lock<std::mutex> lock(mtx_);
825         data_ = memData;
826     }
827 
828     cv_.notify_one();
829 }
830 
831 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)832 sk_sp<SkData> AstcImageLoader::LoadImageData(
833     const ImageSourceInfo& /* ImageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
834 #else
835 std::shared_ptr<RSData> AstcImageLoader::LoadImageData(
836     const ImageSourceInfo& /* ImageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
837 #endif
838 {
839     return nullptr;
840 }
841 
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWK)842 RefPtr<NG::ImageData> AstcImageLoader::LoadDecodedImageData(
843     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWK)
844 {
845 #if !defined(PIXEL_MAP_SUPPORTED)
846     return nullptr;
847 #else
848     auto pipeline = pipelineWK.Upgrade();
849     CHECK_NULL_RETURN(pipeline, nullptr);
850     auto dataProvider = pipeline->GetDataProviderManager();
851     CHECK_NULL_RETURN(dataProvider, nullptr);
852 
853     void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
854     auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
855     CHECK_NULL_RETURN(pixmap, nullptr);
856 
857     auto cache = pipeline->GetImageCache();
858     if (cache) {
859         cache->CacheImageData(src.GetKey(), MakeRefPtr<NG::PixmapData>(pixmap));
860     }
861     return MakeRefPtr<NG::PixmapData>(pixmap);
862 #endif
863 }
864 
GetThumbnailOrientation(const ImageSourceInfo & src)865 std::string AstcImageLoader::GetThumbnailOrientation(const ImageSourceInfo& src)
866 {
867     auto pipeline = PipelineContext::GetCurrentContext();
868     CHECK_NULL_RETURN(pipeline, "");
869     auto dataProvider = pipeline->GetDataProviderManager();
870     CHECK_NULL_RETURN(dataProvider, "");
871 
872     auto path = src.GetSrc();
873     auto pos = path.find("/astc");
874     path = path.substr(0, pos);
875     int32_t fd = dataProvider->GetDataProviderFile(path, "r");
876     CHECK_NULL_RETURN(fd >= 0, "");
877 
878     auto imageSrc = ImageSource::Create(fd);
879     CHECK_NULL_RETURN(imageSrc, "");
880     std::string orientation = imageSrc->GetProperty("Orientation");
881     return orientation;
882 }
883 
WriteCacheToFile(const std::string & uri,const std::vector<uint8_t> & imageData)884 void ImageLoader::WriteCacheToFile(const std::string& uri, const std::vector<uint8_t>& imageData)
885 {
886     BackgroundTaskExecutor::GetInstance().PostTask(
887         [uri, data = std::move(imageData)]() {
888             ImageFileCache::GetInstance().WriteCacheFile(uri, data.data(), data.size());
889         },
890         BgTaskPriority::LOW);
891 }
892 
WriteCacheToFile(const std::string & uri,const std::string & imageData)893 void ImageLoader::WriteCacheToFile(const std::string& uri, const std::string& imageData)
894 {
895     BackgroundTaskExecutor::GetInstance().PostTask(
896         [uri, data = std::move(imageData)]() {
897             ImageFileCache::GetInstance().WriteCacheFile(uri, data.data(), data.size());
898         },
899         BgTaskPriority::LOW);
900 }
901 } // namespace OHOS::Ace
902