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