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 <bits/alltypes.h>
17 #include <native_drawing/drawing_font_collection.h>
18 #include <native_drawing/drawing_text_typography.h>
19 #include "common/log_common.h"
20 #include "sample_bitmap.h"
21 #include "plugin/plugin_manager.h"
22
OnSurfaceCreatedCB(OH_NativeXComponent * component,void * window)23 static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
24 {
25 DRAWING_LOGI("OnSurfaceCreatedCB");
26 if ((component == nullptr) || (window == nullptr)) {
27 DRAWING_LOGE("OnSurfaceCreatedCB: component or window is null");
28 return;
29 }
30 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
31 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
32 if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
33 DRAWING_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id");
34 return;
35 }
36 std::string id(idStr);
37 auto render = SampleBitMap::GetInstance(id);
38 OHNativeWindow *nativeWindow = static_cast<OHNativeWindow *>(window);
39 render->SetNativeWindow(nativeWindow);
40
41 uint64_t width;
42 uint64_t height;
43 int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
44 if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
45 render->SetHeight(height);
46 render->SetWidth(width);
47 DRAWING_LOGI("xComponent width = %{public}llu, height = %{public}llu", width, height);
48 }
49 }
50
OnSurfaceDestroyedCB(OH_NativeXComponent * component,void * window)51 static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
52 {
53 DRAWING_LOGI("OnSurfaceDestroyedCB");
54 if ((component == nullptr) || (window == nullptr)) {
55 DRAWING_LOGE("OnSurfaceDestroyedCB: component or window is null");
56 return;
57 }
58 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
59 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
60 if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
61 DRAWING_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
62 return;
63 }
64 std::string id(idStr);
65 SampleBitMap::Release(id);
66 }
67
68 static std::unordered_map<std::string, SampleBitMap *> g_instance;
69
SetWidth(uint64_t width)70 void SampleBitMap::SetWidth(uint64_t width)
71 {
72 width_ = width;
73 }
74
SetHeight(uint64_t height)75 void SampleBitMap::SetHeight(uint64_t height)
76 {
77 height_ = height;
78 }
79
SetNativeWindow(OHNativeWindow * nativeWindow)80 void SampleBitMap::SetNativeWindow(OHNativeWindow *nativeWindow)
81 {
82 nativeWindow_ = nativeWindow;
83 }
84
Prepare()85 void SampleBitMap::Prepare()
86 {
87 if (nativeWindow_ == nullptr) {
88 DRAWING_LOGE("nativeWindow_ is nullptr");
89 return;
90 }
91 // 这里的nativeWindow是从上一步骤中的回调函数中获得的
92 // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
93 int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
94 DRAWING_LOGI("request buffer ret = %{public}d", ret);
95 // 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
96 bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
97 // 使用系统mmap接口拿到bufferHandle的内存虚拟地址
98 mappedAddr_ = static_cast<uint32_t *>(
99 mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
100 if (mappedAddr_ == MAP_FAILED) {
101 DRAWING_LOGE("mmap failed");
102 }
103 }
104
DisPlay()105 void SampleBitMap::DisPlay()
106 {
107 // 画完后获取像素地址,地址指向的内存包含画布画的像素数据
108 void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
109 uint32_t *value = static_cast<uint32_t *>(bitmapAddr);
110
111 uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_); // 使用mmap获取到的地址来访问内存
112 if (pixel == nullptr) {
113 DRAWING_LOGE("pixel is null");
114 return;
115 }
116 if (value == nullptr) {
117 DRAWING_LOGE("value is null");
118 return;
119 }
120 uint32_t width = static_cast<uint32_t>(bufferHandle_->stride / 4);
121 for (uint32_t x = 0; x < width; x++) {
122 for (uint32_t y = 0; y < height_; y++) {
123 *pixel++ = *value++;
124 }
125 }
126 // 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
127 Region region {nullptr, 0};
128 // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
129 OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
130 // 内存使用完记得去掉内存映射
131 int result = munmap(mappedAddr_, bufferHandle_->size);
132 if (result == -1) {
133 DRAWING_LOGE("munmap failed!");
134 }
135 }
136
Create()137 void SampleBitMap::Create()
138 {
139 uint32_t width = static_cast<uint32_t>(bufferHandle_->stride / 4);
140 // 创建一个bitmap对象
141 cBitmap_ = OH_Drawing_BitmapCreate();
142 // 定义bitmap的像素格式
143 OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
144 // 构造对应格式的bitmap
145 OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat);
146
147 // 创建一个canvas对象
148 cCanvas_ = OH_Drawing_CanvasCreate();
149 // 将画布与bitmap绑定,画布画的内容会输出到绑定的bitmap内存中
150 OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
151 // 使用白色清除画布内容
152 OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
153 }
154
ConstructPath()155 void SampleBitMap::ConstructPath()
156 {
157 int len = height_ / 4;
158 float aX = width_ / 2;
159 float aY = height_ / 4;
160 float dX = aX - len * std::sin(18.0f);
161 float dY = aY + len * std::cos(18.0f);
162 float cX = aX + len * std::sin(18.0f);
163 float cY = dY;
164 float bX = aX + (len / 2.0);
165 float bY = aY + std::sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0));
166 float eX = aX - (len / 2.0);
167 float eY = bY;
168 // 创建一个path对象,然后使用接口连接成一个五角星形状
169 cPath_ = OH_Drawing_PathCreate();
170 // 指定path的起始位置
171 OH_Drawing_PathMoveTo(cPath_, aX, aY);
172 // 用直线连接到目标点
173 OH_Drawing_PathLineTo(cPath_, bX, bY);
174 OH_Drawing_PathLineTo(cPath_, cX, cY);
175 OH_Drawing_PathLineTo(cPath_, dX, dY);
176 OH_Drawing_PathLineTo(cPath_, eX, eY);
177 // 闭合形状,path绘制完毕
178 OH_Drawing_PathClose(cPath_);
179 }
180
SetPenAndBrush()181 void SampleBitMap::SetPenAndBrush()
182 {
183 constexpr float penWidth = 10.0f; // pen width 10
184 // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制
185 cPen_ = OH_Drawing_PenCreate();
186 OH_Drawing_PenSetAntiAlias(cPen_, true);
187 OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
188 OH_Drawing_PenSetWidth(cPen_, penWidth);
189 OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
190 // 将Pen画笔设置到canvas中
191 OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
192
193 // 创建一个画刷Brush对象,Brush对象用于形状的填充
194 cBrush_ = OH_Drawing_BrushCreate();
195 OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
196
197 // 将Brush画刷设置到canvas中
198 OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
199 }
200
DrawPath()201 void SampleBitMap::DrawPath()
202 {
203 // 在画布上画path的形状,五角星的边框样式为pen设置,颜色填充为Brush设置
204 OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
205 }
206
DrawText()207 void SampleBitMap::DrawText()
208 {
209 // 选择从左到右/左对齐等排版属性
210 OH_Drawing_TypographyStyle *typoStyle = OH_Drawing_CreateTypographyStyle();
211 OH_Drawing_SetTypographyTextDirection(typoStyle, TEXT_DIRECTION_LTR);
212 OH_Drawing_SetTypographyTextAlign(typoStyle, TEXT_ALIGN_JUSTIFY);
213
214 // TEXT_ALIGN_JUSTIFY
215 // 设置文字颜色,例如黑色
216 OH_Drawing_TextStyle *txtStyle = OH_Drawing_CreateTextStyle();
217 OH_Drawing_SetTextStyleColor(txtStyle, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
218 // 设置文字大小、字重等属性
219 double fontSize = width_ / 15;
220 OH_Drawing_SetTextStyleFontSize(txtStyle, fontSize);
221 OH_Drawing_SetTextStyleFontWeight(txtStyle, FONT_WEIGHT_400);
222 OH_Drawing_SetTextStyleBaseLine(txtStyle, TEXT_BASELINE_ALPHABETIC);
223 OH_Drawing_SetTextStyleFontHeight(txtStyle, 1);
224 // 设置字体类型等
225 const char *fontFamilies[] = {"Roboto"};
226 OH_Drawing_SetTextStyleFontFamilies(txtStyle, 1, fontFamilies);
227 OH_Drawing_SetTextStyleFontStyle(txtStyle, FONT_STYLE_NORMAL);
228 OH_Drawing_SetTextStyleLocale(txtStyle, "en");
229 OH_Drawing_TypographyCreate *handler =
230 OH_Drawing_CreateTypographyHandler(typoStyle, OH_Drawing_CreateFontCollection());
231 OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle);
232 // 设置文字内容
233 const char *text = "Hello World Drawing\n";
234 OH_Drawing_TypographyHandlerAddText(handler, text);
235 OH_Drawing_TypographyHandlerPopTextStyle(handler);
236 OH_Drawing_Typography *typography = OH_Drawing_CreateTypography(handler);
237 // 设置页面最大宽度
238 double maxWidth = width_;
239 OH_Drawing_TypographyLayout(typography, maxWidth);
240 // 设置文本在画布上绘制的起始位置
241 double position[2] = {width_ / 5.0, height_ / 2.0};
242 // 将文本绘制到画布上
243 OH_Drawing_TypographyPaint(typography, cCanvas_, position[0], position[1]);
244 }
245
NapiDrawPattern(napi_env env,napi_callback_info info)246 napi_value SampleBitMap::NapiDrawPattern(napi_env env, napi_callback_info info)
247 {
248 DRAWING_LOGI("NapiDrawPattern");
249 if ((env == nullptr) || (info == nullptr)) {
250 DRAWING_LOGE("NapiDrawPattern: env or info is null");
251 return nullptr;
252 }
253
254 napi_value thisArg;
255 if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
256 DRAWING_LOGE("NapiDrawPattern: napi_get_cb_info fail");
257 return nullptr;
258 }
259
260 napi_value exportInstance;
261 if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
262 DRAWING_LOGE("NapiDrawPattern: napi_get_named_property fail");
263 return nullptr;
264 }
265
266 OH_NativeXComponent *nativeXComponent = nullptr;
267 if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
268 DRAWING_LOGE("NapiDrawPattern: napi_unwrap fail");
269 return nullptr;
270 }
271
272 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
273 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
274 if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
275 DRAWING_LOGE("NapiDrawPattern: Unable to get XComponent id");
276 return nullptr;
277 }
278 DRAWING_LOGI("ID = %{public}s", idStr);
279 std::string id(idStr);
280 SampleBitMap *render = SampleBitMap().GetInstance(id);
281 if (render != nullptr) {
282 render->Prepare();
283 render->Create();
284 render->ConstructPath();
285 render->SetPenAndBrush();
286 render->DrawPath();
287 render->DisPlay();
288 render->Destroy();
289 DRAWING_LOGI("DrawPath executed");
290 } else {
291 DRAWING_LOGE("render is nullptr");
292 }
293 return nullptr;
294 }
295
NapiDrawText(napi_env env,napi_callback_info info)296 napi_value SampleBitMap::NapiDrawText(napi_env env, napi_callback_info info)
297 {
298 DRAWING_LOGI("NapiDrawText");
299 if ((env == nullptr) || (info == nullptr)) {
300 DRAWING_LOGE("NapiDrawPattern: env or info is null");
301 return nullptr;
302 }
303
304 napi_value thisArg;
305 if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
306 DRAWING_LOGE("NapiDrawPattern: napi_get_cb_info fail");
307 return nullptr;
308 }
309
310 napi_value exportInstance;
311 if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
312 DRAWING_LOGE("NapiDrawPattern: napi_get_named_property fail");
313 return nullptr;
314 }
315
316 OH_NativeXComponent *nativeXComponent = nullptr;
317 if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
318 DRAWING_LOGE("NapiDrawPattern: napi_unwrap fail");
319 return nullptr;
320 }
321
322 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
323 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
324 if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
325 DRAWING_LOGE("NapiDrawPattern: Unable to get XComponent id");
326 return nullptr;
327 }
328 DRAWING_LOGI("ID = %{public}s", idStr);
329 std::string id(idStr);
330 SampleBitMap *render = SampleBitMap().GetInstance(id);
331 if (render != nullptr) {
332 render->Prepare();
333 render->Create();
334 render->DrawText();
335 render->DisPlay();
336 render->Destroy();
337 DRAWING_LOGI("DrawText executed");
338 } else {
339 DRAWING_LOGE("render is nullptr");
340 }
341 return nullptr;
342 }
343
~SampleBitMap()344 SampleBitMap::~SampleBitMap()
345 {
346 // 销毁创建的对象
347 OH_Drawing_BrushDestroy(cBrush_);
348 cBrush_ = nullptr;
349 OH_Drawing_PenDestroy(cPen_);
350 cPen_ = nullptr;
351 OH_Drawing_PathDestroy(cPath_);
352 cPath_ = nullptr;
353 // 销毁canvas对象
354 OH_Drawing_CanvasDestroy(cCanvas_);
355 cCanvas_ = nullptr;
356 // 销毁bitmap对象
357 OH_Drawing_BitmapDestroy(cBitmap_);
358 cBitmap_ = nullptr;
359
360 buffer_ = nullptr;
361 bufferHandle_ = nullptr;
362 nativeWindow_ = nullptr;
363 mappedAddr_ = nullptr;
364 }
365
Destroy()366 void SampleBitMap::Destroy()
367 {
368 // 销毁创建的对象
369 OH_Drawing_BrushDestroy(cBrush_);
370 cBrush_ = nullptr;
371 OH_Drawing_PenDestroy(cPen_);
372 cPen_ = nullptr;
373 OH_Drawing_PathDestroy(cPath_);
374 cPath_ = nullptr;
375 // 销毁canvas对象
376 OH_Drawing_CanvasDestroy(cCanvas_);
377 cCanvas_ = nullptr;
378 // 销毁bitmap对象
379 OH_Drawing_BitmapDestroy(cBitmap_);
380 }
381
Release(std::string & id)382 void SampleBitMap::Release(std::string &id)
383 {
384 PluginManager::GetInstance()->ReleaseRender(id);
385 SampleBitMap *render = SampleBitMap::GetInstance(id);
386 if (render != nullptr) {
387 delete render;
388 render = nullptr;
389 g_instance.erase(g_instance.find(id));
390 }
391 }
392
Export(napi_env env,napi_value exports)393 void SampleBitMap::Export(napi_env env, napi_value exports)
394 {
395 if ((env == nullptr) || (exports == nullptr)) {
396 DRAWING_LOGE("Export: env or exports is null");
397 return;
398 }
399 napi_property_descriptor desc[] = {
400 {"drawPattern", nullptr, SampleBitMap::NapiDrawPattern, nullptr, nullptr, nullptr, napi_default, nullptr},
401 {"drawText", nullptr, SampleBitMap::NapiDrawText, nullptr, nullptr, nullptr, napi_default, nullptr}};
402 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
403 if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
404 DRAWING_LOGE("Export: napi_define_properties failed");
405 }
406 }
407
RegisterCallback(OH_NativeXComponent * nativeXComponent)408 void SampleBitMap::RegisterCallback(OH_NativeXComponent *nativeXComponent)
409 {
410 DRAWING_LOGI("register callback");
411 renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
412 renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
413 // Callback must be initialized
414 renderCallback_.DispatchTouchEvent = nullptr;
415 renderCallback_.OnSurfaceChanged = nullptr;
416 OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
417 }
418
GetInstance(std::string & id)419 SampleBitMap *SampleBitMap::GetInstance(std::string &id)
420 {
421 if (g_instance.find(id) == g_instance.end()) {
422 SampleBitMap *render = new SampleBitMap(id);
423 g_instance[id] = render;
424 return render;
425 } else {
426 return g_instance[id];
427 }
428 }
429