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