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