• 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 
24 #include "third_party/skia/include/codec/SkCodec.h"
25 #include "third_party/skia/include/utils/SkBase64.h"
26 
27 #include "base/image/image_source.h"
28 #include "base/log/ace_trace.h"
29 #include "base/network/download_manager.h"
30 #include "base/resource/ace_res_config.h"
31 #include "base/resource/asset_manager.h"
32 #include "base/thread/background_task_executor.h"
33 #include "base/utils/string_utils.h"
34 #include "base/utils/utils.h"
35 #include "core/common/ace_application_info.h"
36 #include "core/common/container.h"
37 #include "core/common/thread_checker.h"
38 #include "core/components/common/layout/constants.h"
39 #include "core/components_ng/image_provider/image_data.h"
40 #include "core/image/flutter_image_cache.h" // TODO: add adapter layer and use FlutterImageCache there
41 #include "core/image/image_cache.h"
42 #include "core/pipeline/pipeline_context.h"
43 
44 namespace OHOS::Ace {
45 namespace {
46 
47 constexpr size_t FILE_HEAD_LENGTH = 7;           // 7 is the size of "file://"
48 constexpr size_t MEMORY_HEAD_LENGTH = 9;         // 9 is the size of "memory://"
49 constexpr size_t INTERNAL_FILE_HEAD_LENGTH = 15; // 15 is the size of "internal://app/"
50 // regex for "resource://colormode/xxx.type", colormode can be "light" or "dark", xxx represents system resource id,
51 // type can be "jpg", "png", "svg" and so on.
52 const std::regex MEDIA_RES_ID_REGEX(R"(^resource://\w+/([0-9]+)\.\w+$)", std::regex::icase);
53 const std::regex MEDIA_APP_RES_PATH_REGEX(R"(^resource://RAWFILE/(.*)$)");
54 const std::regex MEDIA_APP_RES_ID_REGEX(R"(^resource://.*/([0-9]+)\.\w+$)", std::regex::icase);
55 const std::regex MEDIA_RES_NAME_REGEX(R"(^resource://.*/(\w+)\.\w+$)", std::regex::icase);
56 constexpr uint32_t MEDIA_RESOURCE_MATCH_SIZE = 2;
57 
58 const std::chrono::duration<int, std::milli> TIMEOUT_DURATION(10000);
59 
60 #ifdef WINDOWS_PLATFORM
realpath(const char * path,char * resolved_path)61 char* realpath(const char* path, char* resolved_path)
62 {
63     if (strcpy_s(resolved_path, PATH_MAX, path) != 0) {
64         return nullptr;
65     }
66     return resolved_path;
67 }
68 #endif
69 
70 #ifdef PIXEL_MAP_SUPPORTED
71 // return orientation of pixmap for cache key
GetThumbnailOrientation(const ImageSourceInfo & src)72 std::string GetThumbnailOrientation(const ImageSourceInfo& src)
73 {
74     // disabling orientation check
75     return "Undefined";
76     auto pipeline = PipelineContext::GetCurrentContext();
77     CHECK_NULL_RETURN(pipeline, "");
78     auto dataProvider = pipeline->GetDataProviderManager();
79     CHECK_NULL_RETURN(dataProvider, "");
80 
81     // get file fd
82     // concat to get file path ("datashare://media/xx")
83     auto path = src.GetSrc();
84     auto pos = path.find("/thumbnail");
85     path = path.substr(0, pos);
86     int32_t fd = dataProvider->GetDataProviderFile(path, "r");
87     CHECK_NULL_RETURN(fd >= 0, "");
88 
89     // check image orientation
90     auto imageSrc = ImageSource::Create(fd);
91     CHECK_NULL_RETURN(imageSrc, "");
92     std::string orientation = imageSrc->GetProperty("Orientation");
93     LOGD("image %{public}s has orientation = %{public}s", path.c_str(), orientation.c_str());
94     return orientation;
95 }
96 #endif
97 } // namespace
98 
RemovePathHead(const std::string & uri)99 std::string ImageLoader::RemovePathHead(const std::string& uri)
100 {
101     auto iter = uri.find_first_of(':');
102     if (iter == std::string::npos) {
103         LOGW("No scheme, not a File or Memory path");
104         return std::string();
105     }
106     std::string head = uri.substr(0, iter);
107     if ((head == "file" && uri.size() > FILE_HEAD_LENGTH) || (head == "memory" && uri.size() > MEMORY_HEAD_LENGTH) ||
108         (head == "internal" && uri.size() > INTERNAL_FILE_HEAD_LENGTH)) {
109         // the file uri format is like "file:///data/data...",
110         // the memory uri format is like "memory://imagename.png" for example,
111         // iter + 3 to get the absolutely file path substring : "/data/data..." or the image name: "imagename.png"
112         return uri.substr(iter + 3);
113     }
114     LOGE("Wrong scheme, not a File!");
115     return std::string();
116 }
117 
CreateImageLoader(const ImageSourceInfo & imageSourceInfo)118 RefPtr<ImageLoader> ImageLoader::CreateImageLoader(const ImageSourceInfo& imageSourceInfo)
119 {
120     SrcType srcType = imageSourceInfo.GetSrcType();
121     switch (srcType) {
122         case SrcType::INTERNAL:
123         case SrcType::FILE: {
124             return MakeRefPtr<FileImageLoader>();
125         }
126         case SrcType::NETWORK: {
127             return MakeRefPtr<NetworkImageLoader>();
128         }
129         case SrcType::ASSET: {
130             return MakeRefPtr<AssetImageLoader>();
131         }
132         case SrcType::BASE64: {
133             return MakeRefPtr<Base64ImageLoader>();
134         }
135         case SrcType::RESOURCE: {
136             return MakeRefPtr<ResourceImageLoader>();
137         }
138         case SrcType::DATA_ABILITY: {
139             return MakeRefPtr<DataProviderImageLoader>();
140         }
141         case SrcType::DATA_ABILITY_DECODED: {
142             return MakeRefPtr<DecodedDataProviderImageLoader>();
143         }
144         case SrcType::MEMORY: {
145             if (Container::IsCurrentUseNewPipeline()) {
146                 return MakeRefPtr<SharedMemoryImageLoader>();
147             }
148             LOGE("Image source type: shared memory. image data is not come from image loader.");
149             return nullptr;
150         }
151         case SrcType::RESOURCE_ID: {
152             return MakeRefPtr<InternalImageLoader>();
153         }
154         case SrcType::PIXMAP: {
155             return MakeRefPtr<PixelMapImageLoader>();
156         }
157         default: {
158             LOGE("Image source type not supported!  srcType: %{public}d, sourceInfo: %{public}s", srcType,
159                 imageSourceInfo.ToString().c_str());
160             return nullptr;
161         }
162     }
163 }
164 
LoadDataFromCachedFile(const std::string & uri)165 sk_sp<SkData> ImageLoader::LoadDataFromCachedFile(const std::string& uri)
166 {
167     std::string cacheFilePath = ImageCache::GetImageCacheFilePath(uri);
168     if (cacheFilePath.length() > PATH_MAX) {
169         LOGE("cache file path is too long, cacheFilePath: %{private}s", cacheFilePath.c_str());
170         return nullptr;
171     }
172     bool cacheFileFound = ImageCache::GetFromCacheFile(cacheFilePath);
173     if (!cacheFileFound) {
174         return nullptr;
175     }
176     char realPath[PATH_MAX] = { 0x00 };
177     if (realpath(cacheFilePath.c_str(), realPath) == nullptr) {
178         LOGE("realpath fail! cacheFilePath: %{private}s, fail reason: %{public}s", cacheFilePath.c_str(),
179             strerror(errno));
180         return nullptr;
181     }
182     std::unique_ptr<FILE, decltype(&fclose)> file(fopen(realPath, "rb"), fclose);
183     if (file) {
184         return SkData::MakeFromFILE(file.get());
185     }
186     return nullptr;
187 }
188 
QueryImageDataFromImageCache(const ImageSourceInfo & sourceInfo)189 sk_sp<SkData> ImageLoader::QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo)
190 {
191     auto pipelineCtx = PipelineContext::GetCurrentContext();
192     CHECK_NULL_RETURN(pipelineCtx, nullptr);
193     auto imageCache = pipelineCtx->GetImageCache();
194     CHECK_NULL_RETURN(imageCache, nullptr);
195     auto cacheData = imageCache->GetCacheImageData(sourceInfo.GetSrc());
196     CHECK_NULL_RETURN_NOLOG(cacheData, nullptr);
197     // TODO: add adapter layer and use [SkiaCachedImageData] there
198     auto skiaCachedImageData = AceType::DynamicCast<SkiaCachedImageData>(cacheData);
199     CHECK_NULL_RETURN(skiaCachedImageData, nullptr);
200     return skiaCachedImageData->imageData;
201 }
202 
CacheImageDataToImageCache(const std::string & key,const RefPtr<CachedImageData> & imageData)203 void ImageLoader::CacheImageDataToImageCache(const std::string& key, const RefPtr<CachedImageData>& imageData)
204 {
205     auto pipelineCtx = PipelineContext::GetCurrentContext();
206     CHECK_NULL_VOID(pipelineCtx);
207     auto imageCache = pipelineCtx->GetImageCache();
208     CHECK_NULL_VOID(imageCache);
209     imageCache->CacheImageData(key, imageData);
210 }
211 
LoadImageDataFromFileCache(const std::string & key,const std::string & suffix)212 RefPtr<NG::ImageData> ImageLoader::LoadImageDataFromFileCache(const std::string& key, const std::string& suffix)
213 {
214     ACE_FUNCTION_TRACE();
215     auto pipelineCtx = PipelineContext::GetCurrentContext();
216     CHECK_NULL_RETURN(pipelineCtx, nullptr);
217     auto imageCache = pipelineCtx->GetImageCache();
218     CHECK_NULL_RETURN(imageCache, nullptr);
219     std::string filePath = ImageCache::GetImageCacheFilePath(key) + suffix;
220     auto data = imageCache->GetDataFromCacheFile(filePath);
221     CHECK_NULL_RETURN_NOLOG(data, nullptr);
222     // add adapter layer to replace [SkiaCachedImageData]
223     auto skdata = AceType::DynamicCast<SkiaCachedImageData>(data)->imageData;
224     CHECK_NULL_RETURN(skdata, nullptr);
225     return NG::ImageData::MakeFromDataWrapper(reinterpret_cast<void*>(&skdata));
226 }
227 
228 // NG ImageLoader entrance
GetImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)229 RefPtr<NG::ImageData> ImageLoader::GetImageData(
230     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
231 {
232     if (imageSourceInfo.IsPixmap()) {
233         return LoadDecodedImageData(imageSourceInfo, context);
234     }
235     sk_sp<SkData> skData;
236     do {
237         skData = ImageLoader::QueryImageDataFromImageCache(imageSourceInfo);
238         if (skData) {
239             break;
240         }
241         skData = LoadImageData(imageSourceInfo, context);
242         CHECK_NULL_RETURN(skData, nullptr);
243         // TODO: add adapter layer and use [SkiaCachedImageData] there
244         ImageLoader::CacheImageDataToImageCache(
245             imageSourceInfo.GetSrc(), AceType::MakeRefPtr<SkiaCachedImageData>(skData));
246     } while (0);
247     return NG::ImageData::MakeFromDataWrapper(reinterpret_cast<void*>(&skData));
248 }
249 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> &)250 sk_sp<SkData> FileImageLoader::LoadImageData(
251     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& /* context */)
252 {
253     ACE_SCOPED_TRACE("LoadImageData %s", imageSourceInfo.ToString().c_str());
254     const auto& src = imageSourceInfo.GetSrc();
255     std::string filePath = RemovePathHead(src);
256     if (imageSourceInfo.GetSrcType() == SrcType::INTERNAL) {
257         // the internal source uri format is like "internal://app/imagename.png", the absolute path of which is like
258         // "/data/data/{bundleName}/files/imagename.png"
259         auto bundleName = AceApplicationInfo::GetInstance().GetPackageName();
260         if (bundleName.empty()) {
261             LOGE("bundleName is empty, LoadImageData for internal source fail!");
262             return nullptr;
263         }
264         if (!StringUtils::StartWith(filePath, "app/")) { // "app/" is infix of internal path
265             LOGE("internal path format is wrong. path is %{private}s", src.c_str());
266             return nullptr;
267         }
268         filePath = std::string("/data/data/") // head of absolute path
269                        .append(bundleName)
270                        .append("/files/")           // infix of absolute path
271                        .append(filePath.substr(4)); // 4 is the length of "app/" from "internal://app/"
272     }
273     if (filePath.length() > PATH_MAX) {
274         LOGE("src path is too long");
275         return nullptr;
276     }
277     char realPath[PATH_MAX] = { 0x00 };
278     if (realpath(filePath.c_str(), realPath) == nullptr) {
279         LOGE("realpath fail! filePath: %{private}s, fail reason: %{public}s src:%{public}s", filePath.c_str(),
280             strerror(errno), src.c_str());
281         return nullptr;
282     }
283     auto result = SkData::MakeFromFileName(realPath);
284 #ifdef PREVIEW
285     // on Windows previewer, SkData::MakeFromFile keeps the file open during SkData's lifetime
286     // return a copy to release the file handle
287     CHECK_NULL_RETURN(result, nullptr);
288     return SkData::MakeWithCopy(result->data(), result->size());
289 #else
290     return result;
291 #endif
292 }
293 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)294 sk_sp<SkData> DataProviderImageLoader::LoadImageData(
295     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
296 {
297     const auto& src = imageSourceInfo.GetSrc();
298     auto skData = ImageLoader::LoadDataFromCachedFile(src);
299     if (skData) {
300         return skData;
301     }
302     auto pipeline = context.Upgrade();
303     if (!pipeline) {
304         LOGE("the pipeline context is null");
305         return nullptr;
306     }
307     auto dataProvider = pipeline->GetDataProviderManager();
308     if (!dataProvider) {
309         LOGE("the data provider is null");
310         return nullptr;
311     }
312     auto dataRes = dataProvider->GetDataProviderResFromUri(src);
313     if (!dataRes || dataRes->GetData().size() == 0) {
314         LOGE("fail to get data res is from data provider");
315         return nullptr;
316     }
317     auto imageData = dataRes->GetData();
318     sk_sp<SkData> data = SkData::MakeWithCopy(imageData.data(), imageData.size());
319     BackgroundTaskExecutor::GetInstance().PostTask(
320         [src, imgData = std::move(imageData)]() { ImageCache::WriteCacheFile(src, imgData.data(), imgData.size()); },
321         BgTaskPriority::LOW);
322     return data;
323 }
324 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)325 sk_sp<SkData> AssetImageLoader::LoadImageData(
326     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
327 {
328     ACE_FUNCTION_TRACE();
329     const auto& src = imageSourceInfo.GetSrc();
330     if (src.empty()) {
331         LOGE("image src is empty");
332         return nullptr;
333     }
334 
335     std::string assetSrc(src);
336     if (assetSrc[0] == '/') {
337         assetSrc = assetSrc.substr(1); // get the asset src without '/'.
338     } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
339         assetSrc = assetSrc.substr(2); // get the asset src without './'.
340     }
341     auto pipelineContext = context.Upgrade();
342     if (!pipelineContext) {
343         LOGE("invalid pipeline context");
344         return nullptr;
345     }
346     auto assetManager = pipelineContext->GetAssetManager();
347     if (!assetManager) {
348         LOGE("No asset manager!");
349         return nullptr;
350     }
351     auto assetData = assetManager->GetAsset(assetSrc);
352     if (!assetData) {
353         LOGE("No asset data!");
354         return nullptr;
355     }
356     const uint8_t* data = assetData->GetData();
357     const size_t dataSize = assetData->GetSize();
358     return SkData::MakeWithCopy(data, dataSize);
359 }
360 
LoadJsonData(const std::string & src,const WeakPtr<PipelineBase> context)361 std::string AssetImageLoader::LoadJsonData(const std::string& src, const WeakPtr<PipelineBase> context)
362 {
363     if (src.empty()) {
364         LOGE("image src is empty");
365         return "";
366     }
367 
368     std::string assetSrc(src);
369     if (assetSrc[0] == '/') {
370         assetSrc = assetSrc.substr(1); // get the asset src without '/'.
371     } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
372         assetSrc = assetSrc.substr(2); // get the asset src without './'.
373     }
374     auto pipelineContext = context.Upgrade();
375     if (!pipelineContext) {
376         LOGE("invalid pipeline context");
377         return "";
378     }
379     auto assetManager = pipelineContext->GetAssetManager();
380     if (!assetManager) {
381         LOGE("No asset manager!");
382         return "";
383     }
384     auto assetData = assetManager->GetAsset(assetSrc);
385     if (!assetData || !assetData->GetData()) {
386         LOGE("No asset data!");
387         return "";
388     }
389     return std::string((char*)assetData->GetData(), assetData->GetSize());
390 }
391 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)392 sk_sp<SkData> NetworkImageLoader::LoadImageData(
393     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
394 {
395     auto uri = imageSourceInfo.GetSrc();
396     auto pipelineContext = context.Upgrade();
397     if (!pipelineContext || pipelineContext->IsJsCard()) {
398         LOGW("network image in JS card is forbidden.");
399         return nullptr;
400     }
401     // 1. find in cache file path.
402     auto skData = ImageLoader::LoadDataFromCachedFile(uri);
403     if (skData) {
404         return skData;
405     }
406 
407     // 2. if not found. download it.
408     std::vector<uint8_t> imageData;
409     if (!DownloadManager::GetInstance().Download(uri, imageData) || imageData.empty()) {
410         LOGE("Download network image %{private}s failed!", uri.c_str());
411         return nullptr;
412     }
413     sk_sp<SkData> data = SkData::MakeWithCopy(imageData.data(), imageData.size());
414     // 3. write it into file cache.
415     BackgroundTaskExecutor::GetInstance().PostTask(
416         [uri, imgData = std::move(imageData)]() { ImageCache::WriteCacheFile(uri, imgData.data(), imgData.size()); },
417         BgTaskPriority::LOW);
418     return data;
419 }
420 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)421 sk_sp<SkData> InternalImageLoader::LoadImageData(
422     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
423 {
424     size_t imageSize = 0;
425     const uint8_t* internalData =
426         InternalResource::GetInstance().GetResource(imageSourceInfo.GetResourceId(), imageSize);
427     if (internalData == nullptr) {
428         LOGE("data null, the resource id may be wrong.");
429         return nullptr;
430     }
431     return SkData::MakeWithCopy(internalData, imageSize);
432 }
433 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)434 sk_sp<SkData> Base64ImageLoader::LoadImageData(
435     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
436 {
437     std::string_view base64Code = GetBase64ImageCode(imageSourceInfo.GetSrc());
438     if (base64Code.size() == 0) {
439         return nullptr;
440     }
441 
442 #ifdef NG_BUILD
443     size_t outputLen;
444     SkBase64::Error error = SkBase64::Decode(base64Code.data(), base64Code.size(), nullptr, &outputLen);
445     if (error != SkBase64::Error::kNoError) {
446         LOGE("error base64 image code!");
447         return nullptr;
448     }
449 
450     sk_sp<SkData> resData = SkData::MakeUninitialized(outputLen);
451     void* output = resData->writable_data();
452     error = SkBase64::Decode(base64Code.data(), base64Code.size(), output, &outputLen);
453     if (error != SkBase64::Error::kNoError) {
454         LOGE("error base64 image code!");
455         return nullptr;
456     }
457     return resData;
458 #else
459     SkBase64 base64Decoder;
460     SkBase64::Error error = base64Decoder.decode(base64Code.data(), base64Code.size());
461     if (error != SkBase64::kNoError) {
462         LOGE("error base64 image code!");
463         return nullptr;
464     }
465     auto base64Data = base64Decoder.getData();
466     const uint8_t* imageData = reinterpret_cast<uint8_t*>(base64Data);
467     auto resData = SkData::MakeWithCopy(imageData, base64Decoder.getDataSize());
468     // in SkBase64, the fData is not deleted after decoded.
469     if (base64Data != nullptr) {
470         delete[] base64Data;
471         base64Data = nullptr;
472     }
473     return resData;
474 #endif
475 }
476 
GetBase64ImageCode(const std::string & uri)477 std::string_view Base64ImageLoader::GetBase64ImageCode(const std::string& uri)
478 {
479     auto iter = uri.find_first_of(',');
480     if (iter == std::string::npos || iter == uri.size() - 1) {
481         LOGE("wrong code format!");
482         return std::string_view();
483     }
484     // iter + 1 to skip the ","
485     std::string_view code(uri.c_str() + (iter + 1));
486     return code;
487 }
488 
GetResourceId(const std::string & uri,uint32_t & resId) const489 bool ResourceImageLoader::GetResourceId(const std::string& uri, uint32_t& resId) const
490 {
491     std::smatch matches;
492     if (std::regex_match(uri, matches, MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
493         resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
494         return true;
495     }
496 
497     std::smatch appMatches;
498     if (std::regex_match(uri, appMatches, MEDIA_APP_RES_ID_REGEX) && appMatches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
499         resId = static_cast<uint32_t>(std::stoul(appMatches[1].str()));
500         return true;
501     }
502 
503     return false;
504 }
505 
GetResourceId(const std::string & uri,std::string & path) const506 bool ResourceImageLoader::GetResourceId(const std::string& uri, std::string& path) const
507 {
508     std::smatch matches;
509     if (std::regex_match(uri, matches, MEDIA_APP_RES_PATH_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
510         path = matches[1].str();
511         return true;
512     }
513 
514     return false;
515 }
516 
GetResourceName(const std::string & uri,std::string & resName) const517 bool ResourceImageLoader::GetResourceName(const std::string& uri, std::string& resName) const
518 {
519     std::smatch matches;
520     if (std::regex_match(uri, matches, MEDIA_RES_NAME_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
521         resName = matches[1].str();
522         return true;
523     }
524 
525     return false;
526 }
527 
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)528 sk_sp<SkData> ResourceImageLoader::LoadImageData(
529     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
530 {
531     auto uri = imageSourceInfo.GetSrc();
532     auto pipelineContext = context.Upgrade();
533     CHECK_NULL_RETURN(pipelineContext, nullptr);
534     auto themeManager = pipelineContext->GetThemeManager();
535     CHECK_NULL_RETURN(themeManager, nullptr);
536     auto themeConstants = themeManager->GetThemeConstants();
537     CHECK_NULL_RETURN(themeConstants, nullptr);
538 
539     std::unique_ptr<uint8_t[]> data;
540     size_t dataLen = 0;
541     std::string rawFile;
542     if (GetResourceId(uri, rawFile)) {
543         // must fit raw file firstly, as file name may contains number
544         if (!themeConstants->GetRawFileData(rawFile, dataLen, data)) {
545             LOGE("get image data by name failed, uri:%{private}s, rawFile:%{public}s", uri.c_str(), rawFile.c_str());
546             return nullptr;
547         }
548         return SkData::MakeWithCopy(data.get(), dataLen);
549     }
550     uint32_t resId = 0;
551     if (GetResourceId(uri, resId)) {
552         if (!themeConstants->GetMediaData(resId, dataLen, data)) {
553             LOGE("get image data by id failed, uri:%{private}s, id:%{public}u", uri.c_str(), resId);
554             return nullptr;
555         }
556         return SkData::MakeWithCopy(data.get(), dataLen);
557     }
558     std::string resName;
559     if (GetResourceName(uri, resName)) {
560         if (!themeConstants->GetMediaData(resName, dataLen, data)) {
561             LOGE("get image data by name failed, uri:%{private}s, resName:%{public}s", uri.c_str(), resName.c_str());
562             return nullptr;
563         }
564         return SkData::MakeWithCopy(data.get(), dataLen);
565     }
566     LOGE("load image data failed, as uri is invalid:%{private}s", uri.c_str());
567     return nullptr;
568 }
569 
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)570 sk_sp<SkData> DecodedDataProviderImageLoader::LoadImageData(
571     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
572 {
573     return nullptr;
574 }
575 
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)576 RefPtr<NG::ImageData> DecodedDataProviderImageLoader::LoadDecodedImageData(
577     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
578 {
579 #if !defined(PIXEL_MAP_SUPPORTED)
580     return nullptr;
581 #else
582     auto orientation = GetThumbnailOrientation(src);
583 
584     // query thumbnail from cache
585     auto pipeline = pipelineWk.Upgrade();
586     CHECK_NULL_RETURN(pipeline, nullptr);
587     auto cache = pipeline->GetImageCache();
588     CHECK_NULL_RETURN(cache, nullptr);
589     auto data = DynamicCast<PixmapCachedData>(cache->GetCacheImageData(src.GetKey() + orientation));
590     if (data) {
591         LOGD("thumbnail cache found %{public}s, orientation = %{public}s", src.GetSrc().c_str(), orientation.c_str());
592         return MakeRefPtr<NG::ImageData>(data->pixmap_);
593     }
594 
595     auto dataProvider = pipeline->GetDataProviderManager();
596     CHECK_NULL_RETURN(dataProvider, nullptr);
597 
598     void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
599     auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
600     CHECK_NULL_RETURN(pixmap, nullptr);
601     if (cache) {
602         cache->CacheImageData(src.GetKey() + orientation, MakeRefPtr<PixmapCachedData>(pixmap));
603     }
604     return MakeRefPtr<NG::ImageData>(pixmap);
605 #endif
606 }
607 
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)608 sk_sp<SkData> PixelMapImageLoader::LoadImageData(
609     const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
610 {
611     return nullptr;
612 }
613 
LoadDecodedImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)614 RefPtr<NG::ImageData> PixelMapImageLoader::LoadDecodedImageData(
615     const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
616 {
617 #if !defined(PIXEL_MAP_SUPPORTED)
618     return nullptr;
619 #else
620     if (!imageSourceInfo.GetPixmap()) {
621         LOGW("no pixel map in imageSourceInfo, imageSourceInfo: %{public}s", imageSourceInfo.ToString().c_str());
622         return nullptr;
623     }
624     return MakeRefPtr<NG::ImageData>(imageSourceInfo.GetPixmap());
625 #endif
626 }
627 
LoadImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)628 sk_sp<SkData> SharedMemoryImageLoader::LoadImageData(
629     const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
630 {
631     CHECK_RUN_ON(BG);
632     auto pipeline = pipelineWk.Upgrade();
633     CHECK_NULL_RETURN(pipeline, nullptr);
634     auto manager = pipeline->GetSharedImageManager();
635     CHECK_NULL_RETURN(manager, nullptr);
636     auto id = RemovePathHead(src.GetSrc());
637     bool found = manager->FindImageInSharedImageMap(id, AceType::WeakClaim(this));
638     // image data not ready yet, wait for data
639     if (!found) {
640         manager->RegisterLoader(id, AceType::WeakClaim(this));
641         // wait for SharedImageManager to notify
642         std::unique_lock<std::mutex> lock(mtx_);
643         auto status = cv_.wait_for(lock, TIMEOUT_DURATION);
644         if (status == std::cv_status::timeout) {
645             return nullptr;
646         }
647     }
648 
649     auto skData = SkData::MakeWithCopy(data_.data(), data_.size());
650     return skData;
651 }
652 
UpdateData(const std::string & uri,const std::vector<uint8_t> & memData)653 void SharedMemoryImageLoader::UpdateData(const std::string& uri, const std::vector<uint8_t>& memData)
654 {
655     LOGI("SharedMemory image data is ready %{public}s", uri.c_str());
656     {
657         std::scoped_lock<std::mutex> lock(mtx_);
658         data_ = memData;
659     }
660 
661     cv_.notify_one();
662 }
663 
664 } // namespace OHOS::Ace
665