Clay,开源地址:https://github.com/nicbarker/clayhttps://github.com/nicbarker/clay
这是一个 C 语言开发的高性能 2D 开源布局引擎。
主要特点:
-
微秒级布局性能。
-
Flex-box的布局模型,支持复杂、响应式布局,类似于react的嵌套声明性语法。
-
支持容器内文本换行、scrolling容器,宽高等比例缩放等。
-
单个clay.h头文件,零依赖(甚至不包括C标准库)。
-
Wasm支持:可编译成15kb未压缩的.wasm文件。
-
基于静态内存池的方式使用内存,没有 malloc 和 free,总内存开销低(8192个布局元素约占3.5MB内存)。
-
渲染引擎无关:输出一个排序后的渲染原语列表,这些渲染原语可以轻松地在任何渲染引擎中合成,甚至可以编译成HTML。
yoga没有scrolling容器,也不处理文本换行,也不会为开发者输出渲染原语列表。
如下是一段 CLay 的示例代码:
#include <iostream>
#define CLAY_IMPLEMENTATION
#include "clay.h"
Clay_LayoutConfig layoutElement = Clay_LayoutConfig {
.padding = {5}
};
int main(void) {
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = Clay_Arena {
.label = CLAY_STRING("Clay Memory Arena"),
.capacity = totalMemorySize,
.memory = (char *)malloc(totalMemorySize)
};
Clay_Initialize(clayMemory, Clay_Dimensions {1024,768});
Clay_BeginLayout();
CLAY(
CLAY_RECTANGLE({ .color = {255,255,255,0} }),
CLAY_LAYOUT(layoutElement)
) {}
Clay_EndLayout();
return 0;
}
更详细的使用方法请读者看项目ReadMe。
以下是我自己对这个开源库的一些观点:
容器内文本换行这个特性,是需要开发者把“文本测量”的方法指针交给CLay 的,如下代码所示:
Clay_SetMeasureTextFunction((*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config))
这个方法的参数就是文本测量的函数指针,该函数可用于测量字符串的宽度、高度。Clay 在布局期间使用此方法确定 CLAY_TEXT 元素的大小。Clay_TextElementConfig对象包含字体字号等信息。
然而有些渲染引擎根本就不需要Clay多此一举,比如 Direct2D 和 DirectWrite 绘制大段文本,如下代码所示:
#include <d2d1.h>
#include <dwrite.h>
ComPtr<IDWriteTextLayout> pTextLayout;
m_pWriteFactory->CreateTextLayout(
text.c_str(), //文本内容
(UINT32)text.length(), //字符长度
pTextFormat.Get(), //文本格式
rect.right - rect.left, //最大宽度
rect.bottom - rect.top, //最大高度
&pTextLayout
);
m_pRenderTarget->DrawTextLayout(
D2D1_POINT_2F{ rect.left, rect.top },
pTextLayout.Get(),
m_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black)),
D2D1_DRAW_TEXT_OPTIONS_CLIP
);
如你所见,Direct2D 渲染引擎根本就不需要布局引擎做这个事,它自己就能做。
而且,很多渲染引擎的文本测量方法都是根据字体来的,如下代码所示(Skia渲染引擎):
std::wstring text{ L"你好,世界!" };
auto length = text.size() * sizeof(wchar_t);
SkRect measureRect;
font.measureText(text.c_str(),
length,
SkTextEncoding::kUTF16,
&measureRect);
当大段文本中包含不同字体,不同字号时,我不确定Clay是否能很好的计算文本的尺寸。
另外,Clay用一大堆宏来公开API,这看上去也非常之别扭。
其他方面,待我进一步研究之后,再给大家分享。
补充:
这两天 Clay 发布了新版本,用于包装文本和缓存文本度量的内部算法已经全部重写,从而使布局计算的性能提高了大约2-4倍。因此,相当复杂的布局工作也会在100微秒内完成。