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