• 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_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