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 // 1. find in cache file path.
397 auto skData = ImageLoader::LoadDataFromCachedFile(uri);
398 if (skData) {
399 return skData;
400 }
401
402 // 2. if not found. download it.
403 std::vector<uint8_t> imageData;
404 if (!DownloadManager::GetInstance().Download(uri, imageData) || imageData.empty()) {
405 LOGE("Download network image %{private}s failed!", uri.c_str());
406 return nullptr;
407 }
408 sk_sp<SkData> data = SkData::MakeWithCopy(imageData.data(), imageData.size());
409 // 3. write it into file cache.
410 BackgroundTaskExecutor::GetInstance().PostTask(
411 [uri, imgData = std::move(imageData)]() { ImageCache::WriteCacheFile(uri, imgData.data(), imgData.size()); },
412 BgTaskPriority::LOW);
413 return data;
414 }
415
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)416 sk_sp<SkData> InternalImageLoader::LoadImageData(
417 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
418 {
419 size_t imageSize = 0;
420 const uint8_t* internalData =
421 InternalResource::GetInstance().GetResource(imageSourceInfo.GetResourceId(), imageSize);
422 if (internalData == nullptr) {
423 LOGE("data null, the resource id may be wrong.");
424 return nullptr;
425 }
426 return SkData::MakeWithCopy(internalData, imageSize);
427 }
428
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)429 sk_sp<SkData> Base64ImageLoader::LoadImageData(
430 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
431 {
432 std::string_view base64Code = GetBase64ImageCode(imageSourceInfo.GetSrc());
433 if (base64Code.size() == 0) {
434 return nullptr;
435 }
436
437 #ifdef NG_BUILD
438 size_t outputLen;
439 SkBase64::Error error = SkBase64::Decode(base64Code.data(), base64Code.size(), nullptr, &outputLen);
440 if (error != SkBase64::Error::kNoError) {
441 LOGE("error base64 image code!");
442 return nullptr;
443 }
444
445 sk_sp<SkData> resData = SkData::MakeUninitialized(outputLen);
446 void* output = resData->writable_data();
447 error = SkBase64::Decode(base64Code.data(), base64Code.size(), output, &outputLen);
448 if (error != SkBase64::Error::kNoError) {
449 LOGE("error base64 image code!");
450 return nullptr;
451 }
452 return resData;
453 #else
454 SkBase64 base64Decoder;
455 SkBase64::Error error = base64Decoder.decode(base64Code.data(), base64Code.size());
456 if (error != SkBase64::kNoError) {
457 LOGE("error base64 image code!");
458 return nullptr;
459 }
460 auto base64Data = base64Decoder.getData();
461 const uint8_t* imageData = reinterpret_cast<uint8_t*>(base64Data);
462 auto resData = SkData::MakeWithCopy(imageData, base64Decoder.getDataSize());
463 // in SkBase64, the fData is not deleted after decoded.
464 if (base64Data != nullptr) {
465 delete[] base64Data;
466 base64Data = nullptr;
467 }
468 return resData;
469 #endif
470 }
471
GetBase64ImageCode(const std::string & uri)472 std::string_view Base64ImageLoader::GetBase64ImageCode(const std::string& uri)
473 {
474 auto iter = uri.find_first_of(',');
475 if (iter == std::string::npos || iter == uri.size() - 1) {
476 LOGE("wrong code format!");
477 return std::string_view();
478 }
479 // iter + 1 to skip the ","
480 std::string_view code(uri.c_str() + (iter + 1));
481 return code;
482 }
483
GetResourceId(const std::string & uri,uint32_t & resId) const484 bool ResourceImageLoader::GetResourceId(const std::string& uri, uint32_t& resId) const
485 {
486 std::smatch matches;
487 if (std::regex_match(uri, matches, MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
488 resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
489 return true;
490 }
491
492 std::smatch appMatches;
493 if (std::regex_match(uri, appMatches, MEDIA_APP_RES_ID_REGEX) && appMatches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
494 resId = static_cast<uint32_t>(std::stoul(appMatches[1].str()));
495 return true;
496 }
497
498 return false;
499 }
500
GetResourceId(const std::string & uri,std::string & path) const501 bool ResourceImageLoader::GetResourceId(const std::string& uri, std::string& path) const
502 {
503 std::smatch matches;
504 if (std::regex_match(uri, matches, MEDIA_APP_RES_PATH_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
505 path = matches[1].str();
506 return true;
507 }
508
509 return false;
510 }
511
GetResourceName(const std::string & uri,std::string & resName) const512 bool ResourceImageLoader::GetResourceName(const std::string& uri, std::string& resName) const
513 {
514 std::smatch matches;
515 if (std::regex_match(uri, matches, MEDIA_RES_NAME_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
516 resName = matches[1].str();
517 return true;
518 }
519
520 return false;
521 }
522
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)523 sk_sp<SkData> ResourceImageLoader::LoadImageData(
524 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
525 {
526 auto uri = imageSourceInfo.GetSrc();
527 auto pipelineContext = context.Upgrade();
528 CHECK_NULL_RETURN(pipelineContext, nullptr);
529 auto themeManager = pipelineContext->GetThemeManager();
530 CHECK_NULL_RETURN(themeManager, nullptr);
531 auto themeConstants = themeManager->GetThemeConstants();
532 CHECK_NULL_RETURN(themeConstants, nullptr);
533
534 std::unique_ptr<uint8_t[]> data;
535 size_t dataLen = 0;
536 std::string rawFile;
537 if (GetResourceId(uri, rawFile)) {
538 // must fit raw file firstly, as file name may contains number
539 if (!themeConstants->GetRawFileData(rawFile, dataLen, data)) {
540 LOGE("get image data by name failed, uri:%{private}s, rawFile:%{public}s", uri.c_str(), rawFile.c_str());
541 return nullptr;
542 }
543 return SkData::MakeWithCopy(data.get(), dataLen);
544 }
545 uint32_t resId = 0;
546 if (GetResourceId(uri, resId)) {
547 if (!themeConstants->GetMediaData(resId, dataLen, data)) {
548 LOGE("get image data by id failed, uri:%{private}s, id:%{public}u", uri.c_str(), resId);
549 return nullptr;
550 }
551 return SkData::MakeWithCopy(data.get(), dataLen);
552 }
553 std::string resName;
554 if (GetResourceName(uri, resName)) {
555 if (!themeConstants->GetMediaData(resName, dataLen, data)) {
556 LOGE("get image data by name failed, uri:%{private}s, resName:%{public}s", uri.c_str(), resName.c_str());
557 return nullptr;
558 }
559 return SkData::MakeWithCopy(data.get(), dataLen);
560 }
561 LOGE("load image data failed, as uri is invalid:%{private}s", uri.c_str());
562 return nullptr;
563 }
564
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)565 sk_sp<SkData> DecodedDataProviderImageLoader::LoadImageData(
566 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
567 {
568 return nullptr;
569 }
570
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)571 RefPtr<NG::ImageData> DecodedDataProviderImageLoader::LoadDecodedImageData(
572 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
573 {
574 #if !defined(PIXEL_MAP_SUPPORTED)
575 return nullptr;
576 #else
577 auto orientation = GetThumbnailOrientation(src);
578
579 // query thumbnail from cache
580 auto pipeline = pipelineWk.Upgrade();
581 CHECK_NULL_RETURN(pipeline, nullptr);
582 auto cache = pipeline->GetImageCache();
583 CHECK_NULL_RETURN(cache, nullptr);
584 auto data = DynamicCast<PixmapCachedData>(cache->GetCacheImageData(src.GetKey() + orientation));
585 if (data) {
586 LOGD("thumbnail cache found %{public}s, orientation = %{public}s", src.GetSrc().c_str(), orientation.c_str());
587 return MakeRefPtr<NG::ImageData>(data->pixmap_);
588 }
589
590 auto dataProvider = pipeline->GetDataProviderManager();
591 CHECK_NULL_RETURN(dataProvider, nullptr);
592
593 void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
594 auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
595 CHECK_NULL_RETURN(pixmap, nullptr);
596 if (cache) {
597 cache->CacheImageData(src.GetKey() + orientation, MakeRefPtr<PixmapCachedData>(pixmap));
598 }
599 return MakeRefPtr<NG::ImageData>(pixmap);
600 #endif
601 }
602
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)603 sk_sp<SkData> PixelMapImageLoader::LoadImageData(
604 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
605 {
606 return nullptr;
607 }
608
LoadDecodedImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)609 RefPtr<NG::ImageData> PixelMapImageLoader::LoadDecodedImageData(
610 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
611 {
612 #if !defined(PIXEL_MAP_SUPPORTED)
613 return nullptr;
614 #else
615 if (!imageSourceInfo.GetPixmap()) {
616 LOGW("no pixel map in imageSourceInfo, imageSourceInfo: %{public}s", imageSourceInfo.ToString().c_str());
617 return nullptr;
618 }
619 return MakeRefPtr<NG::ImageData>(imageSourceInfo.GetPixmap());
620 #endif
621 }
622
LoadImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)623 sk_sp<SkData> SharedMemoryImageLoader::LoadImageData(
624 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
625 {
626 CHECK_RUN_ON(BG);
627 auto pipeline = pipelineWk.Upgrade();
628 CHECK_NULL_RETURN(pipeline, nullptr);
629 auto manager = pipeline->GetSharedImageManager();
630 CHECK_NULL_RETURN(manager, nullptr);
631 auto id = RemovePathHead(src.GetSrc());
632 bool found = manager->FindImageInSharedImageMap(id, AceType::WeakClaim(this));
633 // image data not ready yet, wait for data
634 if (!found) {
635 manager->RegisterLoader(id, AceType::WeakClaim(this));
636 // wait for SharedImageManager to notify
637 std::unique_lock<std::mutex> lock(mtx_);
638 auto status = cv_.wait_for(lock, TIMEOUT_DURATION);
639 if (status == std::cv_status::timeout) {
640 return nullptr;
641 }
642 }
643
644 auto skData = SkData::MakeWithCopy(data_.data(), data_.size());
645 return skData;
646 }
647
UpdateData(const std::string & uri,const std::vector<uint8_t> & memData)648 void SharedMemoryImageLoader::UpdateData(const std::string& uri, const std::vector<uint8_t>& memData)
649 {
650 LOGI("SharedMemory image data is ready %{public}s", uri.c_str());
651 {
652 std::scoped_lock<std::mutex> lock(mtx_);
653 data_ = memData;
654 }
655
656 cv_.notify_one();
657 }
658
659 } // namespace OHOS::Ace
660