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