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_xcomponent.h"
21
OnSurfaceCreatedCB(OH_NativeXComponent * component,void * window)22 static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
23 {
24 SAMPLE_LOGI("OnSurfaceCreatedCB");
25 if ((component == nullptr) || (window == nullptr)) {
26 SAMPLE_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 SAMPLE_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id");
33 return;
34 }
35 std::string id(idStr);
36 auto render = SampleXComponent::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 SAMPLE_LOGI("xComponent width = %{public}lu, 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 SAMPLE_LOGI("OnSurfaceDestroyedCB");
53 if ((component == nullptr) || (window == nullptr)) {
54 SAMPLE_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 SAMPLE_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
61 return;
62 }
63 std::string id(idStr);
64 SampleXComponent::Release(id);
65 }
66
TestCallback(OH_NativeXComponent * component,uint64_t timestamp,uint64_t targetTimestamp)67 static void TestCallback(OH_NativeXComponent *component, uint64_t timestamp, uint64_t targetTimestamp)
68 {
69 SAMPLE_LOGI("test callback timestamp = %{public}llu, targetTimestamp = %{public}llu", timestamp, targetTimestamp);
70 if (component == nullptr) {
71 SAMPLE_LOGE("TestCallback: component is null");
72 return;
73 }
74
75 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
76 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
77 if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
78 SAMPLE_LOGE("TestCallback: Unable to get XComponent id");
79 return;
80 }
81
82 std::string id(idStr);
83 auto render = SampleXComponent::GetInstance(id);
84 OHNativeWindow *nativeWindow = render->GetNativeWindow();
85 uint64_t width;
86 uint64_t height;
87
88 int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height);
89 if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
90 render->Prepare();
91 render->Create();
92 if (id == "xcomponentId_30") {
93 // 30Hz绘制时,每帧移动的距离为16像素
94 render->ConstructPath(16, 16, render->defaultOffsetY);
95 }
96 if (id == "xcomponentId_120") {
97 // 120Hz绘制时,每帧移动的距离为4像素
98 render->ConstructPath(4, 4, render->defaultOffsetY);
99 }
100 render->SetPenAndBrush();
101 render->DrawPath();
102 render->DisPlay();
103 render->Destroy();
104 }
105 }
106
107 static std::unordered_map<std::string, SampleXComponent *> g_instance;
108
SetWidth(uint64_t width)109 void SampleXComponent::SetWidth(uint64_t width)
110 {
111 width_ = width;
112 }
113
SetHeight(uint64_t height)114 void SampleXComponent::SetHeight(uint64_t height)
115 {
116 height_ = height;
117 }
118
SetNativeWindow(OHNativeWindow * nativeWindow)119 void SampleXComponent::SetNativeWindow(OHNativeWindow *nativeWindow)
120 {
121 nativeWindow_ = nativeWindow;
122 }
123
GetNativeWindow()124 OHNativeWindow *SampleXComponent::GetNativeWindow()
125 {
126 return nativeWindow_;
127 }
128
Prepare()129 void SampleXComponent::Prepare()
130 {
131 if (nativeWindow_ == nullptr) {
132 SAMPLE_LOGE("nativeWindow_ is nullptr");
133 return;
134 }
135 // 这里的nativeWindow是从上一步骤中的回调函数中获得的
136 // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
137 int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
138 SAMPLE_LOGI("request buffer ret = %{public}d", ret);
139 // 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
140 bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
141 // 使用系统mmap接口拿到bufferHandle的内存虚拟地址
142 mappedAddr_ = static_cast<uint32_t *>(
143 mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
144 if (mappedAddr_ == MAP_FAILED) {
145 SAMPLE_LOGE("mmap failed");
146 }
147 }
148
DisPlay()149 void SampleXComponent::DisPlay()
150 {
151 // 画完后获取像素地址,地址指向的内存包含画布画的像素数据
152 void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
153 uint32_t *value = static_cast<uint32_t *>(bitmapAddr);
154
155 uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_); // 使用mmap获取到的地址来访问内存
156 if (pixel == nullptr) {
157 SAMPLE_LOGE("pixel is null");
158 return;
159 }
160 if (value == nullptr) {
161 SAMPLE_LOGE("value is null");
162 return;
163 }
164 for (uint32_t x = 0; x < width_; x++) {
165 for (uint32_t y = 0; y < height_; y++) {
166 *pixel++ = *value++;
167 }
168 }
169 // 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
170 Region region {nullptr, 0};
171 // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
172 OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
173 // 内存使用完记得去掉内存映射
174 int result = munmap(mappedAddr_, bufferHandle_->size);
175 if (result == -1) {
176 SAMPLE_LOGE("munmap failed!");
177 }
178 }
179
Create()180 void SampleXComponent::Create()
181 {
182 uint32_t width = static_cast<uint32_t>(bufferHandle_->stride / 4);
183 // 创建一个bitmap对象
184 cBitmap_ = OH_Drawing_BitmapCreate();
185 // 定义bitmap的像素格式
186 OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
187 // 构造对应格式的bitmap
188 OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat);
189
190 // 创建一个canvas对象
191 cCanvas_ = OH_Drawing_CanvasCreate();
192 // 将画布与bitmap绑定,画布画的内容会输出到绑定的bitmap内存中
193 OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
194 // 使用白色清除画布内容
195 OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
196 }
197
ConstructPath(int x,int y,int offsetY)198 void SampleXComponent::ConstructPath(int x, int y, int offsetY)
199 {
200 // 初始的矩形A点纵坐标为100.0
201 aY = 100.0 + offsetY;
202 // 初始的矩形C点纵坐标为200.0
203 cY = 200.0 + offsetY;
204
205 if (desc) {
206 aX -= x * 1.0;
207 bX -= x * 1.0;
208 } else {
209 aX += x * 1.0;
210 bX += x * 1.0;
211 }
212
213 if (bX >= width_) {
214 desc = true;
215 }
216
217 if (aX <= 0) {
218 desc = false;
219 }
220
221 float bY = aY;
222 float cX = bX;
223 float dX = aX;
224 float dY = cY;
225
226 // 创建一个path对象,然后使用接口连接成一个矩形形状
227 cPath_ = OH_Drawing_PathCreate();
228 // 指定path的起始位置
229 OH_Drawing_PathMoveTo(cPath_, aX, aY);
230 // 用直线连接到目标点
231 OH_Drawing_PathLineTo(cPath_, bX, bY);
232 OH_Drawing_PathLineTo(cPath_, cX, cY);
233 OH_Drawing_PathLineTo(cPath_, dX, dY);
234
235 // 闭合形状,path绘制完毕
236 OH_Drawing_PathClose(cPath_);
237 }
238
SetPenAndBrush()239 void SampleXComponent::SetPenAndBrush()
240 {
241 constexpr float penWidth = 10.0f; // pen width 10
242 // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制
243 cPen_ = OH_Drawing_PenCreate();
244 OH_Drawing_PenSetAntiAlias(cPen_, true);
245 OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
246 OH_Drawing_PenSetWidth(cPen_, penWidth);
247 OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
248 // 将Pen画笔设置到canvas中
249 OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
250
251 // 创建一个画刷Brush对象,Brush对象用于形状的填充
252 cBrush_ = OH_Drawing_BrushCreate();
253 OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
254
255 // 将Brush画刷设置到canvas中
256 OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
257 }
258
DrawPath()259 void SampleXComponent::DrawPath()
260 {
261 // 在画布上画path的形状,矩形的边框样式为pen设置,颜色填充为Brush设置
262 OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
263 }
264
NapiRegister(napi_env env,napi_callback_info info)265 napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info)
266 {
267 SAMPLE_LOGI("NapiRegister");
268 if ((env == nullptr) || (info == nullptr)) {
269 SAMPLE_LOGE("NapiRegister: env or info is null");
270 return nullptr;
271 }
272
273 napi_value thisArg;
274 if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
275 SAMPLE_LOGE("NapiRegister: napi_get_cb_info fail");
276 return nullptr;
277 }
278
279 napi_value exportInstance;
280 if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
281 SAMPLE_LOGE("NapiRegister: napi_get_named_property fail");
282 return nullptr;
283 }
284
285 OH_NativeXComponent *nativeXComponent = nullptr;
286 if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
287 SAMPLE_LOGE("NapiRegister: napi_unwrap fail");
288 return nullptr;
289 }
290
291 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
292 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
293 if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
294 SAMPLE_LOGE("NapiRegister: Unable to get XComponent id");
295 return nullptr;
296 }
297 SAMPLE_LOGI("RegisterID = %{public}s", idStr);
298 std::string id(idStr);
299 SampleXComponent *render = SampleXComponent().GetInstance(id);
300 if (render != nullptr) {
301 if (id == "xcomponentId_30") {
302 // 第一个按照期望30HZ的帧率来移动
303 OH_NativeXComponent_ExpectedRateRange range = {30, 120, 30};
304 OH_NativeXComponent_SetExpectedFrameRateRange(nativeXComponent, &range);
305 }
306
307 if (id == "xcomponentId_120") {
308 // 第一个按照期望120HZ的帧率来移动
309 OH_NativeXComponent_ExpectedRateRange range = {30, 120, 120};
310 OH_NativeXComponent_SetExpectedFrameRateRange(nativeXComponent, &range);
311 }
312 render->RegisterOnFrameCallback(nativeXComponent);
313 }
314 return nullptr;
315 }
316
NapiUnregister(napi_env env,napi_callback_info info)317 napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info)
318 {
319 SAMPLE_LOGI("NapiUnregister");
320 if ((env == nullptr) || (info == nullptr)) {
321 SAMPLE_LOGE("NapiUnregister: env or info is null");
322 return nullptr;
323 }
324
325 napi_value thisArg;
326 if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
327 SAMPLE_LOGE("NapiUnregister: napi_get_cb_info fail");
328 return nullptr;
329 }
330
331 napi_value exportInstance;
332 if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
333 SAMPLE_LOGE("NapiUnregister: napi_get_named_property fail");
334 return nullptr;
335 }
336
337 OH_NativeXComponent *nativeXComponent = nullptr;
338 if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
339 SAMPLE_LOGE("NapiUnregister: napi_unwrap fail");
340 return nullptr;
341 }
342
343 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
344 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
345 if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
346 SAMPLE_LOGE("NapiUnregister: Unable to get XComponent id");
347 return nullptr;
348 }
349 SAMPLE_LOGI("ID = %{public}s", idStr);
350 std::string id(idStr);
351 SampleXComponent *render = SampleXComponent().GetInstance(id);
352 if (render != nullptr) {
353 OH_NativeXComponent_UnregisterOnFrameCallback(nativeXComponent);
354 SAMPLE_LOGI("NapiUnregister executed");
355 } else {
356 SAMPLE_LOGE("render is nullptr");
357 }
358 return nullptr;
359 }
360
~SampleXComponent()361 SampleXComponent::~SampleXComponent()
362 {
363 // 销毁创建的对象
364 OH_Drawing_BrushDestroy(cBrush_);
365 cBrush_ = nullptr;
366 OH_Drawing_PenDestroy(cPen_);
367 cPen_ = nullptr;
368 OH_Drawing_PathDestroy(cPath_);
369 cPath_ = nullptr;
370 // 销毁canvas对象
371 OH_Drawing_CanvasDestroy(cCanvas_);
372 cCanvas_ = nullptr;
373 // 销毁bitmap对象
374 OH_Drawing_BitmapDestroy(cBitmap_);
375 cBitmap_ = nullptr;
376
377 buffer_ = nullptr;
378 bufferHandle_ = nullptr;
379 nativeWindow_ = nullptr;
380 mappedAddr_ = nullptr;
381 }
382
Destroy()383 void SampleXComponent::Destroy()
384 {
385 // 销毁创建的对象
386 OH_Drawing_BrushDestroy(cBrush_);
387 cBrush_ = nullptr;
388 OH_Drawing_PenDestroy(cPen_);
389 cPen_ = nullptr;
390 OH_Drawing_PathDestroy(cPath_);
391 cPath_ = nullptr;
392 // 销毁canvas对象
393 OH_Drawing_CanvasDestroy(cCanvas_);
394 cCanvas_ = nullptr;
395 // 销毁bitmap对象
396 OH_Drawing_BitmapDestroy(cBitmap_);
397 cBitmap_ = nullptr;
398 }
399
Release(std::string & id)400 void SampleXComponent::Release(std::string &id)
401 {
402 SampleXComponent *render = SampleXComponent::GetInstance(id);
403 if (render != nullptr) {
404 delete render;
405 render = nullptr;
406 g_instance.erase(g_instance.find(id));
407 }
408 }
409
Export(napi_env env,napi_value exports)410 void SampleXComponent::Export(napi_env env, napi_value exports)
411 {
412 if ((env == nullptr) || (exports == nullptr)) {
413 SAMPLE_LOGE("Export: env or exports is null");
414 return;
415 }
416 napi_property_descriptor desc[] = {
417 {"register", nullptr, SampleXComponent::NapiRegister, nullptr, nullptr, nullptr, napi_default, nullptr},
418 {"unregister", nullptr, SampleXComponent::NapiUnregister, nullptr, nullptr, nullptr, napi_default, nullptr}};
419 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
420 if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
421 SAMPLE_LOGE("Export: napi_define_properties failed");
422 }
423 }
424
RegisterCallback(OH_NativeXComponent * nativeXComponent)425 void SampleXComponent::RegisterCallback(OH_NativeXComponent *nativeXComponent)
426 {
427 SAMPLE_LOGI("register callback");
428 renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
429 renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
430 // Callback must be initialized
431 renderCallback_.DispatchTouchEvent = nullptr;
432 renderCallback_.OnSurfaceChanged = nullptr;
433 OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
434 }
435
RegisterOnFrameCallback(OH_NativeXComponent * nativeXComponent)436 void SampleXComponent::RegisterOnFrameCallback(OH_NativeXComponent *nativeXComponent)
437 {
438 SAMPLE_LOGI("register onFrameCallback");
439 OH_NativeXComponent_RegisterOnFrameCallback(nativeXComponent, TestCallback);
440 }
441
GetInstance(std::string & id)442 SampleXComponent *SampleXComponent::GetInstance(std::string &id)
443 {
444 if (g_instance.find(id) == g_instance.end()) {
445 SampleXComponent *render = new SampleXComponent(id);
446 g_instance[id] = render;
447 return render;
448 } else {
449 return g_instance[id];
450 }
451 }