1# Small-System Graphics Framework Integration
2
3The small-system graphics modules run in OpenHarmony as a framework. Therefore, you only need to adapt to and implement APIs at the OpenHarmony HDF layer. The graphics subsystem can run on different platforms. For example, when developing an application on Windows or macOS, you can use Qt Creator for simple page layout, development, and debugging. The graphics framework has been adapted to the Windows and macOS platforms. To integrate the graphics framework into an existing project independently, you need to carry out the following adaptation operations:
4
51. Initialize the graphics engine.
62. Adapt to the display.
73. Adapt to the input device.
84. Initialize the font engine.
95. Interconnect to screen flush.
10
11For details, see [OpenHarmony Small-System Graphics Simulator Adaptation Implementation](https://gitee.com/openharmony/arkui_ui_lite/tree/master/tools/qt/simulator).
12
13### Initializing the Graphics Engine
14Initialize UI tasks, rendering modules, animation modules, and default styles.
15```c++
16// graphic_startup.h
17GraphicStartUp::Init();
18```
19
20### Adapting to the Display
21
22Set the screen size, connect to basic component rendering, obtain the graphics rendering buffer, and refresh the graphics rendering data to the screen for display.
23
24During display layer adaptation, note that the classes to inherit and implement vary according to hardware rendering and software rendering. The **BaseGfxEngine** class in [gfx_engine_manager.h](https://gitee.com/openharmony/arkui_ui_lite/blob/master/interfaces/innerkits/engines/gfx/gfx_engine_manager.h) is a pure virtual implementation. It defines only functions and does not contain any implementation. It can be used as the parent class of hardware rendering. The **SoftEngine** class in [soft_engine.h](https://gitee.com/openharmony/arkui_ui_lite/blob/master/interfaces/innerkits/engines/gfx/soft_engine.h) inherits from **BaseGfxEngine** and implements the functions of **BaseGfxEngine** at the software layer. It can be used as the parent class of software rendering.
25
26The **BaseGfxEngine** class has three types of functions:
27
28Type 1: functions used to obtain the display memory, apply for the buffer, and release the buffer.
29
30Type 2: basic rendering functions, such as line drawing, **Blit**, and **Fill**.
31
32Type 3: display functions, which are called to send the rendered content to the display.
33
34The functions for obtaining the display memory and the display functions must be implemented for different platforms. The second type of function is implemented by software by default in the graphics UI framework, that is, **SoftEngine** of **soft_engine.h**. You can inherit from **SoftEngine** to extend software rendering. If hardware acceleration is required on different platforms, for example, DMA2D, you can inherit from **BaseGfxEngine** of **gfx_engine_manager.h**, implement all pure virtual functions, and carry out scalability adaptation.
35
36The code for interconnecting to the graphics functions is as follows:
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### Adapting to the Input Device
143
144The graphics framework supports touch, key, and rotation devices. Currently, you must inherit from **InputDevice** to implement the **Read** function for all input devices.
145
146For touch devices, inherit from the **PointerInputDevice** class to implement the **Read** function. The x and y coordinates and pressed status need to be returned.
147
148For key input devices, inherit from the **KeyInputDevice** class to implement the **Read** function. The key ID and key status need to be set.
149
150For rotation input devices, inherit from the **RotateInputDevice** class to implement the **Read** function. The rotate value needs to be set.
151
152The code for interconnecting to the **InputDevice** instance is as follows:
153
154```c++
155// Read function in input_device.h
156/**
157 * @brief Reads data from hardware. You should override this to set data. *
158 * @param [out] Indicates device data. *
159 * @returns Returns no more data to read if true.
160 */
161virtual bool Read(DeviceData& data) = 0;
162
163// Inherit from and implement the Read function of the InputDevice base class. The following uses a touch event as an example:
164class TouchInput : public OHOS::PointerInputDevice {
165public:
166    TouchInput() {}
167    virtual TouchInput() {}
168    // Implement the read function.
169    bool Read(OHOS::DeviceData& data) override
170    {
171        // Set the position and state. You should update the value when it is being touched.
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### Initializing the Font Engine
183
184Fonts are classified into dot matrix fonts and vector fonts.
185
186For dot matrix fonts, use the font packaging tool to generate a **font.bin** file. The tool supports packaging of Chinese and English fonts. For details about the supported font sizes and font IDs, see **ui_text_language.h** generated by the tool.
187
188For vector fonts, **DEFAULT_VECTOR_FONT_FILENAME** is registered by default. To use other fonts, call **RegisterFontInfo** to register the required font files. Vector font parsing and layout depend on the third-party open-source software FreeType and ICU. To support complex languages such as Arabic, you must introduce the third-party open-source software HarfBuzz and enable **ENABLE_SHAPING** and **ENABLE_ICU**.
189
190The code of font engine initialization is as follows:
191
192```c++
193// graphic_config.h
194#define DEFAULT_VECTOR_FONT_FILENAME      "SourceHanSansSC-Regular.otf"
195// Vector font switch
196#define ENABLE_VECTOR_FONT                1
197// Dot-matrix font switch
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### Interconnecting to Screen Flush
210
211Periodically call **TaskHandler** based on the screen hardware refresh signal (similar to Vsync).
212
213The code for interconnecting to screen flush is as follows:
214
215```c++
216TaskManager::GetInstance()->TaskHandler();
217```
218
219### Sample Code
220
221The macro definitions related to interconnection are described as follows:
222
223```c++
224// graphic_config.h
225// By default, macro definitions of different levels of devices are defined. For lightweight devices, enable the VERSION_LITE macro.
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// Disable window synthesis. Enabling window synthesis depends on the WMS window synthesis service.
247/**
248 * @brief Multi-window, which is disabled by default on WIN32.
249 */
250#define ENABLE_WINDOW                     0
251
252// Disable the support for images in PNG and JPEG formats. To enable the support, introduce a third-party library.
253#define ENABLE_JPEG_AND_PNG               0
254
255// Hardware acceleration. If hardware acceleration is disabled, CPU soft rendering is used by default. You can disable this feature first and enable it after the page is displayed.
256/**
257 * @brief Graphics rendering hardware acceleration, which is disabled by default on WIN32.
258 */
259#define ENABLE_HARDWARE_ACCELERATION     0
260```
261
262The code snippet is as follows:
263
264```c++
265using namespace OHOS;
266
267int main(int argc, char** argv)
268{
269    // Initialize the graphic engine.
270    GraphicStartUp::Init();
271
272    // Initialize the display and input device.
273    InitHal();
274
275    // Initialize the font engine.
276    InitFontEngine();
277
278    // Run your application code.
279    RunApp();
280
281    // Use while loop to simulate the 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// Below is 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 adapter
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    // Implement the read function.
352    bool Read(OHOS::DeviceData& data) override
353    {
354        // Set the position x, y, and state. You should update the
355        // g_lastX/g_lastY/g_leftButtonDown when it is being touched.
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    // Implement the read function.
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 to add, if required.
380class XXInput : public OHOS::XXInputDevice {
381public:
382    KeyInput();
383    virtual ~KeyInput() {}
384
385    // Implement the read function.
386    bool Read(OHOS::DeviceData& data) override
387    {
388        // Set the device data information.
389    }
390};
391
392static void InitHal()
393{
394    // Set up the GFX engine.
395    BaseGfxEngine::GetInstance()->InitEngine(new SDLMonitorGfxEngine());
396
397    // Set up the touch device.
398    TouchInput* touch = new TouchInput();
399    InputDeviceManager::GetInstance()->Add(touch);
400
401    // Set up the key device if required.
402    KeyInput* key = new KeyInput();
403    InputDeviceManager::GetInstance()->Add(key);
404
405    // Set up xx device if required.
406    XXInput* inputXX = new XXInput();
407    InputDeviceManager::GetInstance()->Add(inputXX);
408}
409```
410