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