1# 小型系统图形框架集成指导
2
3当前,小型系统图形模块以子系统的形式在 OpenHarmony 中运行。开发者只需适配实现OpenHarmony HDF 层 API 即可。由于使用场景不同,图形子系统也支持在不同平台集成运行。例如,在 Windows/Mac 上开发应用程序时,可以使用 QT Creator 进行简单的页面布局、开发和调试。此时,图形子系统已经适配到了 Windows/Mac 平台上运行。如果想要将图形子系统独立集成到现有项目中,则需要进行一些简单的适配工作,并分为以下几个主要部分:
4
51. 引擎初始化
62. 显示设备适配
73. 输入设备适配
84. 字体初始化
95. 屏幕刷新对接
10
11具体步骤如下,步骤最后有参考示例代码,具体可参照 [OpenHarmony 小型系统图形 Simulator 适配实现](https://gitee.com/openharmony/arkui_ui_lite/tree/master/tools/qt/simulator)12
13### 图形引擎初始化
14主要包括初始化 UI 任务、渲染模块、动画模块、默认样式等
15```c++
16// graphic_startup.h
17GraphicStartUp::Init();
18```
19
20### 显示设备适配
21
22主要包括设置屏幕大小,对接基础图元绘制,获取图形绘制的 buffer,把图形绘制的数据刷到屏幕上显示等。
23
24显示层适配根据硬件绘制和软件绘制不同,需继承实现不同的类。其中 [gfx_engine_manager.h](https://gitee.com/openharmony/arkui_ui_lite/blob/master/interfaces/innerkits/engines/gfx/gfx_engine_manager.h) 中的 BaseGfxEngine 类为纯虚实现,只定义了接口,不含任何实现,适合作为自行实现的硬件绘制的父类;[soft_engine.h](https://gitee.com/openharmony/arkui_ui_lite/blob/master/interfaces/innerkits/engines/gfx/soft_engine.h) 中的 SoftEngine 继承自 BaseGfxEngine,对 BaseGfxEngine 的接口进行了软件层实现,适合作为软件绘制的父类。
25
26BaseGfxEngine 类中有3类接口:
27
28第一类:获取显存、申请缓存、释放缓存;
29
30第二类:绘制类基础接口,例如:画线、Blit、Fill 等;
31
32第三类:送显接口,调用该接口完成把绘制内容送显。
33
34其中获取显存和送显接口为移植不同平台必须实现的,第二类接口,图形 UI 框架有默认软件实现,具体在 soft_engine.h 的 SoftEngine 中,软件绘制可继承 SoftEngine 进行功能拓展;不同平台如有硬件加速,例如 DMA2D,可继承 gfx_engine_manager.h 的 BaseGfxEngine,对其纯虚方法进行全部实现后,进行扩展性适配。
35
36图形对接接口代码如下:
37```c++
38// gfx_engine_manager.h
39virtual void DrawArc(BufferInfo& dst,
40                        ArcInfo& arcInfo,
41                        const Rect& mask,
42                        const Style& style,
43                        OpacityType opacity,
44                        uint8_t cap) = 0;
45
46virtual void DrawLine(BufferInfo& dst,
47                        const Point& start,
48                        const Point& end,
49                        const Rect& mask,
50                        int16_t width,
51                        ColorType color,
52                        OpacityType opacity) = 0;
53
54virtual void DrawLetter(BufferInfo& gfxDstBuffer,
55                        const uint8_t* fontMap,
56                        const Rect& fontRect,
57                        const Rect& subRect,
58                        const uint8_t fontWeight,
59                        const ColorType& color,
60                        const OpacityType opa) = 0;
61
62virtual void DrawCubicBezier(BufferInfo& dst,
63                                const Point& start,
64                                const Point& control1,
65                                const Point& control2,
66                                const Point& end,
67                                const Rect& mask,
68                                int16_t width,
69                                ColorType color,
70                                OpacityType opacity) = 0;
71
72virtual void
73    DrawRect(BufferInfo& dst, const Rect& rect, const Rect& dirtyRect, const Style& style, OpacityType opacity) = 0;
74
75virtual void DrawTransform(BufferInfo& dst,
76                            const Rect& mask,
77                            const Point& position,
78                            ColorType color,
79                            OpacityType opacity,
80                            const TransformMap& transMap,
81                            const TransformDataInfo& dataInfo) = 0;
82
83// x/y: center of a circle
84virtual void ClipCircle(const ImageInfo* info, float x, float y, float radius) = 0;
85
86virtual void Blit(BufferInfo& dst,
87                    const Point& dstPos,
88                    const BufferInfo& src,
89                    const Rect& subRect,
90                    const BlendOption& blendOption) = 0;
91
92virtual void Fill(BufferInfo& dst, const Rect& fillArea, const ColorType color, const OpacityType opacity) = 0;
93
94virtual void DrawPath(BufferInfo& dst,
95                        void* param,
96                        const Paint& paint,
97                        const Rect& rect,
98                        const Rect& invalidatedArea,
99                        const Style& style) = 0;
100
101virtual void FillPath(BufferInfo& dst,
102                        void* param,
103                        const Paint& paint,
104                        const Rect& rect,
105                        const Rect& invalidatedArea,
106                        const Style& style) = 0;
107
108virtual uint8_t* AllocBuffer(uint32_t size, uint32_t usage) = 0;
109
110virtual void FreeBuffer(uint8_t* buffer, uint32_t usage) = 0;
111
112virtual BufferInfo* GetFBBufferInfo()
113{
114    return nullptr;
115}
116
117virtual void AdjustLineStride(BufferInfo& info) {}
118
119virtual void Flush(const Rect& flushRect) {}
120
121virtual uint16_t GetScreenWidth()
122{
123    return screenWidth_;
124}
125
126virtual uint16_t GetScreenHeight()
127{
128    return screenHeight_;
129}
130
131virtual void SetScreenShape(ScreenShape screenShape)
132{
133    screenShape_ = screenShape;
134}
135
136virtual ScreenShape GetScreenShape()
137{
138    return screenShape_;
139}
140```
141
142### 输入设备适配
143
144图形框架支持触摸、按键和旋转设备。当前所有输入设备都需要继承 InputDevice 实现 Read 接口。
145
146触摸输入继承 PointerInputDevice 类实现 Read 接口,需要返回 x/y 坐标和按压状态;
147
148按键输入继承 KeyInputDevice 类实现 Read 接口,需要设置 keyId 和按键状态;
149
150旋转输入继承 RotateInputDevice 类实现 Read 接口,需要设置 rotate 值。
151
152InputDevice 设备对接实例代码如下:
153
154```c++
155// input_device.h Read 接口
156/**
157 * @brief Read data from hardware.User should override this to set data *
158 * @param [out] input device data. *
159 * @returns no more data to read if true.
160 */
161virtual bool Read(DeviceData& data) = 0;
162
163// 继承实现 InputDevice 基类的 Read 接口,以触摸事件对接为例,示例代码如下:
164class TouchInput : public OHOS::PointerInputDevice {
165public:
166    TouchInput() {}
167    virtual TouchInput() {}
168    // implements read fouction
169    bool Read(OHOS::DeviceData& data) override
170    {
171        // set position and state, you should update the value when touch
172        data.point.x = g_lastX;
173        data.point.y = g_lastY;
174        data.state = g_leftButtonDown ? STATE_PRESS : STATE_RELEASE;
175        return false;
176    }
177};
178```
179
180
181
182### 字体初始化
183
184字体分为点阵字体和矢量字体。
185
186点阵字体:需要使用字体打包工具生成对应字体 font.bin 文件,工具支持打包中英文字体,详细支持字号和 fontId 可以在工具生成的 ui_text_language.h 中查看。
187
188矢量字体:默认注册了 DEFAULT_VECTOR_FONT_FILENAME,假如想使用其他字体,可以调用 RegisterFontInfo 注册其他字体文件。矢量字体解析和布局需要依赖三方开源软件 freetype 和 icu,假如想支持阿拉伯语等复杂语言需要依赖三软件 harfbuzz,同时打开 ENABLE_SHAPING 和 ENABLE_ICU。
189
190字体初始化接口代码如下:
191
192```c++
193// graphic_config.h
194#define DEFAULT_VECTOR_FONT_FILENAME      "SourceHanSansSC-Regular.otf"
195// 矢量字体开关
196#define ENABLE_VECTOR_FONT                1
197// 点阵字体开关
198#define ENABLE_BITMAP_FONT                0
199#define ENABLE_ICU                        0
200#define ENABLE_SHAPING                    0
201
202// ui_font.h
203uint8_t RegisterFontInfo(const char* ttfName, uint8_t shaping = 0)
204
205// graphic_startup.h
206static void InitFontEngine(uintptr_t psramAddr, uint32_t psramLen, const char* dPath, const char* ttfName);
207```
208
209### 屏幕刷新对接
210
211根据屏幕硬件刷新信号(类似 Vsync 信号),周期性回调 TaskHandler
212
213屏幕刷新对接接口代码如下:
214
215```c++
216TaskManager::GetInstance()->TaskHandler();
217```
218
219### 图形适配示例代码
220
221对接相关宏定义说明如下:
222
223```c++
224// graphic_config.h
225// 默认定义了不同级别设备宏定义,轻设备请启动 VERSION_LITE 宏
226/**
227 * Defines three graphics library versions: lightweight, standard, and extended versions.
228 * The three versions have different requirements on the memory and hardware.
229 * The standard version is enabled by default.
230 *
231 * The macros of the versions are defined as follows:
232 * Name                | Version Description
233 * ------------------- | ----------
234 * VERSION_LITE        | Lightweight version
235 * VERSION_STANDARD    | Standard version
236 * VERSION_EXTENDED    | Extended version
237 */
238#ifdef _LITEOS
239#define VERSION_LITE
240#elif defined _WIN32 || defined __APPLE__
241#define VERSION_LITE
242#else
243#define VERSION_STANDARD
244#endif
245
246// 关闭窗口合成,打开需要依赖 wms 窗口合成服务
247/**
248 * @brief Multi-window, which is disabled by default on WIN32.
249 */
250#define ENABLE_WINDOW                     0
251
252// 关闭 png、jpeg 格式图片支持,打开需要引入三方库
253#define ENABLE_JPEG_AND_PNG               0
254
255// 硬件加速,关闭默认走CPU软绘制,可以先关闭,界面显示后再打开适配硬件能力
256/**
257 * @brief Graphics rendering hardware acceleration, which is disabled by default on WIN32.
258 */
259#define ENABLE_HARDWARE_ACCELERATION     0
260```
261
262对接示例代码如下:
263
264```c++
265using namespace OHOS;
266
267int main(int argc, char** argv)
268{
269    // init graphic
270    GraphicStartUp::Init();
271
272    // init display/input device
273    InitHal();
274
275    // init font engine
276    InitFontEngine();
277
278    // run your app code
279    RunApp();
280
281    // use while loop to simulate hardware flush callback
282    // you should call *TaskHandler* in screen flush signal callback(like Vsync).
283    while (1) {
284        TaskManager::GetInstance()->TaskHandler();
285        Sleep(DEFAULT_TASK_PERIOD);
286    }
287    return 0;
288}
289
290// assuming below are the memory pool
291static uint8_t g_fontPsramBaseAddr[MIN_FONT_PSRAM_LENGTH];
292#if ENABLE_SHAPING
293static uint8_t g_shapePsramBaseAddr[MIN_SHAPING_PSRAM_LENGTH];
294#else
295static uint8_t* g_shapePsramBaseAddr = nullptr;
296#endif
297
298static void InitFontEngine()
299
300{
301#if ENABLE_VECTOR_FONT
302    GraphicStartUp::InitFontEngine(reinterpret_cast<uintptr_t>(g_fontMemBaseAddr), MIN_FONT_PSRAM_LENGTH, VECTOR_FONT_DIR, DEFAULT_VECTOR_FONT_FILENAME);
303#else
304    BitmapFontInit();
305    std::string dPath(_pgmptr);
306    size_t len = dPath.size();
307    size_t pos = dPath.find_last_of('\\');
308    dPath.replace((pos + 1), (len - pos), "..\\..\\simulator\\font\\font.bin");
309    GraphicStartUp::InitFontEngine(reinterpret_cast<uintptr_t>(g_fontMemBaseAddr), MIN_FONT_PSRAM_LENGTH, dPath.c_str(), nullptr);
310#endif
311
312#if ENABLE_ICU
313    GraphicStartUp::InitLineBreakEngine(reinterpret_cast<uintptr_t>(g_icuMemBaseAddr), SHAPING_WORD_DICT_LENGTH,
314 VECTOR_FONT_DIR, DEFAULT_LINE_BREAK_RULE_FILENAME);
315#endif
316}
317
318// display adaptor
319class SDLMonitorGfxEngine : public BaseGfxEngine {
320public:
321    BufferInfo* GetFBBufferInfo() override
322    {
323        static BufferInfo* bufferInfo = nullptr;
324        if (bufferInfo == nullptr) {
325            bufferInfo = new BufferInfo;
326            bufferInfo->rect = {0, 0, HORIZONTAL_RESOLUTION - 1, VERTICAL_RESOLUTION - 1};
327            bufferInfo->mode = ARGB8888;
328            bufferInfo->color = 0x44;
329            bufferInfo->virAddr = GetFramBuff();
330            bufferInfo->phyAddr = bufferInfo->virAddr;
331            // 4: bpp
332            bufferInfo->stride = HORIZONTAL_RESOLUTION * 4;
333            bufferInfo->width = HORIZONTAL_RESOLUTION;
334            bufferInfo->height = VERTICAL_RESOLUTION;
335        }
336
337        return bufferInfo;
338    }
339
340    void Flush() override
341    {
342        MonitorRenderFinish();
343    }
344};
345
346class TouchInput : public OHOS::PointerInputDevice {
347public:
348    TouchInput() {}
349    virtual TouchInput() {}
350
351    // implements read function
352    bool Read(OHOS::DeviceData& data) override
353    {
354        // set position x,y and state, you should update the
355        // g_lastX/g_lastY/g_leftButtonDown when touch
356        data.point.x = g_lastX;
357        data.point.y = g_lastY;
358        data.state = g_leftButtonDown ? STATE_PRESS : STATE_RELEASE;
359
360        return false;
361    }
362};
363
364class KeyInput : public OHOS::KeyInputDevice {
365public:
366    KeyInput();
367    virtual ~KeyInput() {}
368
369    // implements read fouction
370    bool Read(OHOS::DeviceData& data) override
371    {
372        data.keyId = g_lastKeyId;
373        data.state = g_lastState;
374        g_lastState = INVALID_KEY_STATE;
375        return false;
376    }
377};
378
379// other device if you need to add
380class XXInput : public OHOS::XXInputDevice {
381public:
382    KeyInput();
383    virtual ~KeyInput() {}
384
385    // implements read fouction
386    bool Read(OHOS::DeviceData& data) override
387    {
388        // set device data info
389    }
390};
391
392static void InitHal()
393{
394    // Setup gfxengine
395    BaseGfxEngine::GetInstance()->InitEngine(new SDLMonitorGfxEngine());
396
397    // Setup touch device
398    TouchInput* touch = new TouchInput();
399    InputDeviceManager::GetInstance()->Add(touch);
400
401    // Setup key device if you need
402    KeyInput* key = new KeyInput();
403    InputDeviceManager::GetInstance()->Add(key);
404
405    // Setup xx device if you need
406    XXInput* inputXX = new XXInput();
407    InputDeviceManager::GetInstance()->Add(inputXX);
408}
409```
410