1 /*
2 * Copyright (c) 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 "drawable_descriptor.h"
17
18 #include <cstddef>
19 #include <memory>
20 #include <string>
21
22 #include "base/utils/string_utils.h"
23
24 #ifdef NEW_SKIA
25 #include "include/core/SkSamplingOptions.h"
26 #endif
27 #include "cJSON.h"
28 #ifndef PREVIEW
29 #include "image_source.h"
30 #endif
31 #include "include/core/SkImage.h"
32 #include "include/core/SkRect.h"
33
34 // 区分此函数是在Windows环境调用还是Linux/mac环境调用
35 #ifdef PREVIEW
36 #ifdef WINDOWS_PLATFORM
37 #include <windows.h>
38 #include <direct.h>
39 #elif defined(MAC_PLATFORM)
40 #include <mach-o/dyld.h>
41 #else
42 #include <unistd.h>
43 #endif
44 #endif
45
46 namespace OHOS::Ace::Napi {
47 namespace {
48 #ifndef PREVIEW
49 const char DRAWABLEDESCRIPTOR_JSON_KEY_BACKGROUND[] = "background";
50 const char DRAWABLEDESCRIPTOR_JSON_KEY_FOREGROUND[] = "foreground";
51 #endif
52 constexpr float SIDE = 192.0;
53
54 // define for get resource path in preview scenes
55 const static char PREVIEW_LOAD_RESOURCE_ID[] = "ohos_drawable_descriptor_path";
56 #ifdef PREVIEW
57 #ifdef WINDOWS_PLATFORM
58 constexpr static char PREVIEW_LOAD_RESOURCE_PATH[] = "\\resources\\entry\\resources.index";
59 #else
60 constexpr static char PREVIEW_LOAD_RESOURCE_PATH[] = "/resources/entry/resources.index";
61 #endif
62
63 #ifdef LINUX_PLATFORM
64 const static size_t MAX_PATH_LEN = 255;
65 #endif
66 #endif
67 } // namespace
68
GetPixelMapFromBuffer()69 bool DrawableDescriptor::GetPixelMapFromBuffer()
70 {
71 Media::SourceOptions opts;
72 uint32_t errorCode = 0;
73 std::unique_ptr<Media::ImageSource> imageSource =
74 Media::ImageSource::CreateImageSource(mediaData_.get(), len_, opts, errorCode);
75 if (errorCode != 0) {
76 HILOG_ERROR("CreateImageSource from buffer failed");
77 return false;
78 }
79 mediaData_.reset();
80 Media::DecodeOptions decodeOpts;
81 decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
82 if (imageSource) {
83 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
84 pixelMap_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
85 }
86 if (errorCode != 0 || !pixelMap_) {
87 HILOG_ERROR("Get PixelMap from buffer failed");
88 return false;
89 }
90 return true;
91 }
92
GetPixelMap()93 std::shared_ptr<Media::PixelMap> DrawableDescriptor::GetPixelMap()
94 {
95 if (pixelMap_.has_value()) {
96 return pixelMap_.value();
97 }
98 if (GetPixelMapFromBuffer()) {
99 return pixelMap_.value();
100 }
101 HILOG_ERROR("Failed to GetPixelMap!");
102 return nullptr;
103 }
104
CreateImageSource(const char * item,uint32_t & errorCode)105 std::unique_ptr<Media::ImageSource> LayeredDrawableDescriptor::CreateImageSource(const char* item, uint32_t& errorCode)
106 {
107 std::string itemStr = item;
108 std::string idStr = itemStr.substr(itemStr.find(':') + 1);
109 if (!StringUtils::IsNumber(idStr)) {
110 return nullptr;
111 }
112
113 size_t len = 0;
114 std::unique_ptr<uint8_t[]> data;
115 auto state = resourceMgr_->GetMediaDataById(static_cast<uint32_t>(std::stoul(idStr)), len, data);
116 if (state != Global::Resource::SUCCESS) {
117 HILOG_ERROR("GetMediaDataById failed");
118 return nullptr;
119 }
120
121 Media::SourceOptions opts;
122 return Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
123 }
124
GetPixelMapFromJsonBuf(bool isBackground)125 bool LayeredDrawableDescriptor::GetPixelMapFromJsonBuf(bool isBackground)
126 {
127 #ifndef PREVIEW
128 cJSON* roots = cJSON_ParseWithLength(reinterpret_cast<const char*>(jsonBuf_.get()), len_);
129
130 if (roots == nullptr) {
131 return false;
132 }
133
134 uint32_t errorCode = 0;
135 cJSON* item = nullptr;
136 if (isBackground) {
137 item = cJSON_GetObjectItem(roots->child, DRAWABLEDESCRIPTOR_JSON_KEY_BACKGROUND);
138 } else {
139 item = cJSON_GetObjectItem(roots->child, DRAWABLEDESCRIPTOR_JSON_KEY_FOREGROUND);
140 }
141 if (item == nullptr) {
142 cJSON_Delete(roots);
143 HILOG_ERROR("GetObjectItem from json buffer failed");
144 return false;
145 }
146
147 if (cJSON_IsString(item)) {
148 std::unique_ptr<Media::ImageSource> imageSource =
149 LayeredDrawableDescriptor::CreateImageSource(item->valuestring, errorCode);
150 if (errorCode != 0) {
151 cJSON_Delete(roots);
152 HILOG_ERROR("CreateImageSource from json buffer failed");
153 return false;
154 }
155 Media::DecodeOptions decodeOpts;
156 decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
157 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
158 if (errorCode != 0) {
159 cJSON_Delete(roots);
160 HILOG_ERROR("Get PixelMap from json buffer failed");
161 return false;
162 }
163
164 if (isBackground) {
165 background_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
166 } else {
167 foreground_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
168 }
169 } else {
170 cJSON_Delete(roots);
171 HILOG_ERROR("Get background from json buffer failed");
172 return false;
173 }
174 cJSON_Delete(roots);
175 return true;
176 #else
177 return false;
178 #endif
179 }
180
GetDefaultMask()181 bool LayeredDrawableDescriptor::GetDefaultMask()
182 {
183 const std::string name = "ohos_icon_mask";
184 size_t len = 0;
185 std::unique_ptr<uint8_t[]> data;
186 resourceMgr_->GetMediaDataByName(name.c_str(), len, data);
187 Media::SourceOptions opts;
188 uint32_t errorCode = 0;
189 std::unique_ptr<Media::ImageSource> imageSource =
190 Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
191 Media::DecodeOptions decodeOpts;
192 decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
193 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
194 mask_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
195 if (errorCode != 0 || !mask_) {
196 HILOG_ERROR("Get mask failed");
197 return false;
198 }
199 return true;
200 }
201
GetMaskByName(const std::string & name)202 bool LayeredDrawableDescriptor::GetMaskByName(const std::string& name)
203 {
204 size_t len = 0;
205 std::unique_ptr<uint8_t[]> data;
206 resourceMgr_->GetMediaDataByName(name.c_str(), len, data);
207 Media::SourceOptions opts;
208 uint32_t errorCode = 0;
209 std::unique_ptr<Media::ImageSource> imageSource =
210 Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
211 Media::DecodeOptions decodeOpts;
212 decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
213 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
214 mask_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
215 if (errorCode != 0 || !mask_) {
216 HILOG_ERROR("Get mask failed");
217 return false;
218 }
219 return true;
220 }
221
GetForeground()222 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetForeground()
223 {
224 if (foreground_.has_value()) {
225 return std::make_unique<DrawableDescriptor>(foreground_.value());
226 }
227
228 if (GetPixelMapFromJsonBuf(false)) {
229 return std::make_unique<DrawableDescriptor>(foreground_.value());
230 }
231
232 HILOG_ERROR("GetForeground failed");
233 return nullptr;
234 }
235
GetBackground()236 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetBackground()
237 {
238 if (background_.has_value()) {
239 return std::make_unique<DrawableDescriptor>(background_.value());
240 }
241
242 if (GetPixelMapFromJsonBuf(true)) {
243 return std::make_unique<DrawableDescriptor>(background_.value());
244 }
245 HILOG_ERROR("GetForeground failed");
246 return nullptr;
247 }
248
GetMask()249 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetMask()
250 {
251 if (mask_.has_value()) {
252 return std::make_unique<DrawableDescriptor>(mask_.value());
253 }
254
255 if (GetDefaultMask()) {
256 return std::make_unique<DrawableDescriptor>(mask_.value());
257 }
258
259 HILOG_ERROR("GetMask failed");
260 return nullptr;
261 }
262
DrawOntoCanvas(const std::shared_ptr<SkBitmap> & bitMap,float width,float height,SkCanvas & canvas,const SkPaint & paint)263 void LayeredDrawableDescriptor::DrawOntoCanvas(
264 const std::shared_ptr<SkBitmap>& bitMap, float width, float height, SkCanvas& canvas, const SkPaint& paint)
265 {
266 auto x = static_cast<float>((bitMap->width() - static_cast<float>(width)) / 2);
267 auto y = static_cast<float>((bitMap->height() - static_cast<float>(height)) / 2);
268 auto rect1 = SkRect::MakeXYWH(x, y, static_cast<float>(width), static_cast<float>(width));
269 auto rect2 = SkRect::MakeWH(static_cast<float>(width), static_cast<float>(width));
270 #ifndef NEW_SKIA
271 canvas.drawImageRect(SkImage::MakeFromBitmap(*bitMap), rect1, rect2, &paint);
272 #else
273 canvas.drawImageRect(
274 SkImage::MakeFromBitmap(*bitMap), rect1, rect2, SkSamplingOptions(), &paint, SkCanvas::kFast_SrcRectConstraint);
275 #endif
276 }
277
CreatePixelMap()278 bool LayeredDrawableDescriptor::CreatePixelMap()
279 {
280 std::shared_ptr<SkBitmap> foreground;
281 if (foreground_.has_value()) {
282 foreground = ImageConverter::PixelMapToBitmap(foreground_.value());
283 } else if (GetPixelMapFromJsonBuf(false)) {
284 foreground = ImageConverter::PixelMapToBitmap(foreground_.value());
285 } else {
286 HILOG_INFO("Get pixelMap of foreground failed.");
287 return false;
288 }
289
290 std::shared_ptr<SkBitmap> background;
291 if (background_.has_value()) {
292 background = ImageConverter::PixelMapToBitmap(background_.value());
293 } else if (GetPixelMapFromJsonBuf(true)) {
294 background = ImageConverter::PixelMapToBitmap(background_.value());
295 } else {
296 HILOG_ERROR("Get pixelMap of background failed.");
297 return false;
298 }
299
300 std::shared_ptr<SkBitmap> mask;
301 if (mask_.has_value()) {
302 mask = ImageConverter::PixelMapToBitmap(mask_.value());
303 } else if (GetDefaultMask()) {
304 mask = ImageConverter::PixelMapToBitmap(mask_.value());
305 } else {
306 HILOG_ERROR("Get pixelMap of mask failed.");
307 return false;
308 }
309
310 SkPaint paint;
311 paint.setAntiAlias(true);
312 auto colorType = ImageConverter::PixelFormatToSkColorType(background_.value()->GetPixelFormat());
313 auto alphaType = ImageConverter::AlphaTypeToSkAlphaType(background_.value()->GetAlphaType());
314 auto imageInfo = SkImageInfo::Make(SIDE, SIDE, colorType, alphaType);
315 SkBitmap tempCache;
316 tempCache.allocPixels(imageInfo);
317 SkCanvas bitmapCanvas(tempCache);
318
319 paint.setBlendMode(SkBlendMode::kSrc);
320 DrawOntoCanvas(background, SIDE, SIDE, bitmapCanvas, paint);
321 paint.setBlendMode(SkBlendMode::kDstATop);
322 DrawOntoCanvas(mask, SIDE, SIDE, bitmapCanvas, paint);
323 paint.setBlendMode(SkBlendMode::kSrcATop);
324 DrawOntoCanvas(foreground, SIDE, SIDE, bitmapCanvas, paint);
325 bitmapCanvas.readPixels(tempCache, 0, 0);
326
327 // convert bitmap back to pixelMap
328 Media::InitializationOptions opts;
329 opts.alphaType = background_.value()->GetAlphaType();
330 opts.pixelFormat = Media::PixelFormat::BGRA_8888;
331 layeredPixelMap_ = ImageConverter::BitmapToPixelMap(std::make_shared<SkBitmap>(tempCache), opts);
332 return true;
333 }
334
GetPixelMap()335 std::shared_ptr<Media::PixelMap> LayeredDrawableDescriptor::GetPixelMap()
336 {
337 if (layeredPixelMap_.has_value()) {
338 return layeredPixelMap_.value();
339 }
340
341 if (CreatePixelMap()) {
342 return layeredPixelMap_.value();
343 }
344
345 HILOG_ERROR("Failed to GetPixelMap!");
346 return nullptr;
347 }
348
GetStaticMaskClipPath()349 std::string LayeredDrawableDescriptor::GetStaticMaskClipPath()
350 {
351 std::string data;
352 std::shared_ptr<Global::Resource::ResourceManager> resMgr(Global::Resource::CreateResourceManager());
353
354 #ifdef PREVIEW
355 std::string pathTmp = "";
356 #ifdef WINDOWS_PLATFORM
357 char pathBuf [MAX_PATH];
358 _getcwd(pathBuf, MAX_PATH);
359 pathTmp = pathBuf;
360 #elif defined(MAC_PLATFORM)
361 uint32_t size = 0;
362 _NSGetExecutablePath(nullptr, &size);
363
364 char pathBuf [size + 1];
365 if (_NSGetExecutablePath(pathBuf, &size) != 0) {
366 pathBuf[0] = '\0';
367 HILOG_ERROR("Failed, buffer too small!");
368 }
369 pathBuf[size] = '\0';
370
371 std::string previewFullPath = pathBuf;
372 size_t lastPathIdx = previewFullPath.find_last_of("\\/");
373 pathTmp = (lastPathIdx != std::string::npos) ? previewFullPath.substr(0, lastPathIdx) : "";
374 #else
375 char pathBuf [MAX_PATH_LEN];
376 readlink("/proc/self/exe", pathBuf, MAX_PATH_LEN);
377 pathTmp = pathBuf;
378 #endif
379 size_t lastPathSepLoc = pathTmp.find_last_of("\\/");
380 std::string path = (lastPathSepLoc != std::string::npos) ? pathTmp.substr(0, lastPathSepLoc) : "";
381 path += PREVIEW_LOAD_RESOURCE_PATH;
382 resMgr->AddResource(path.c_str());
383 #endif
384 resMgr->GetStringByName(PREVIEW_LOAD_RESOURCE_ID, data);
385 return data;
386 }
387 } // namespace OHOS::Ace::Napi
388