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