• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }