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