LCUI 2.0.0 Beta 开发日志

2019年12月18日  ·  1980 字  ·  阅读

2020-01-19

在浏览器中,vertical-align 的计算值与基线有关,而基线又受到行高和是否有文字的影响,如果有文字则按照文字基线来计算内联块元素的位置,否则将内联块元素的最下边缘作为基线来计算元素位置,以下是测试效果:

Chrome vertical-align

如果给其中一个内联块元素添加文本,布局会变成这样:

Chrome vertical-align

在 LCUI 中,text-align 和 line-height 是 TextView 部件的私有样式属性,不参与布局系统的坐标计算,目前也不打算完全实现浏览器的这种基于基线的布局方式,所以,LCUI 对 vertical-align 的处理很简单,都基于当前行的实际高度来计算。

LCUI vertical-align

2020-01-12

启用 OpenMP 后 CPU 使用率一直在 80% 以上,即使没有重绘区域也是如此,看来需要根据重绘区域面积来自动决定是否使用 OpenMP。

block 和 inline-block 布局已经重写完成,接下来开始重写布局的单元测试。

2020-01-11

简单的布局流程如下:

  • block
    1. 遍历子元素
    2. 计算子元素的位置
    3. 按行分组,计算每一行的最大高度
    4. 累加所有行的高度,作为容器的高度
  • inline-block
    1. 遍历子元素
    2. 计算子元素的位置
    3. 按行分组,计算每一行的最大宽度和高度
    4. 将最大行宽和所有行的高度之和作为容器的宽高

inline-block 和 block 容器的布局类似,可以共用同一布局代码。

布局使用的是部件的 outer box,当 margin 为负数时,outer box 会比 border box 小。

一次遍历没法完成全部部件的坐标计算,那就遍历两次,第一次只按行分组子部件,计算内容区域的宽高,第二次再根据内容宽高来计算子元素的布局。

对于宽高是百分比单位的元素,可在更新样式时计算出准确的值,因为 root 的宽高必定是固定的,那么就能在更新样式后根据父级最大可用尺寸来计算出当前可用尺寸。假设有个 inline-block 显示方式的容器,如果它已指定宽度或最大宽度,则子元素宽度的百分比是相对于这个容器内容宽度,否则相对于最大可用宽度。

absolute 定位的元素脱离布局流,需要在计算完内容区尺寸后更新这些元素布局。

relative 和 absolute 定位的元素,它们的 left、right、top、bottom 属性的变更不需要重新布局,但考虑到现在并没有频繁改动这些属性的需求,所以就不花时间想优化方案了,直接触发重布局。

2020-01-05

在改动部件更新流程后无法通过布局测试,试着追加了几行 LCUIWidget_Update() 调用,可通过测试,看样子现有的布局效率很低,要往复更新好几次才能让布局完全正确。

准备重新调整部件更新方式,将布局任务与样式更新任务分离,在从根到子级更新部件样式时构造一棵树来记录需要更新布局的部件,更新完样式后再递归进这颗树从子级到根更新布局。

2019-12-29

改进后的重绘效果:

paint flashing

2019-12-22

之前提了个重绘区域高亮的改进任务,看到有贡献者提交了 PR 就顺便测试了一下,以 helloworld 程序为例,鼠标悬停在输入框、 hello, world! 上会触发重绘,点击个按钮都会触发全屏重绘,这些重绘是多余的,为此,决定改进部件的更新流程。

首先,集中处理部件属性的差异对比和无效区域的标记,原有的部件属性更新函数只负责更新样式,不再考虑属性变化后的副作用。然后,将属性的更新分为两类:

  • 布局相关:包括宽高、定位、位置、内间距、外间距等属性在更新时会触发重新布局和重绘。
  • 渲染相关:包括背景、边框、阴影、可见性、透明度等属性在变化时只触发重绘,如果布局相关属性已更新,或父级部件不可见,或父级布局已标记内容区域需要刷新,则可跳过这些属性的差异对比。

这样处理后,就不需要 RectList_Add() 处理重复、重叠的脏矩形了。

2019-12-21

在启用 OpenMP 后,可将屏幕划分为 4 个区域来并行渲染,区域高度最小 200 像素。

当前机器的逻辑处理器是 8 个,将并行渲染线程数设置为 8 个后,渲染性能降低,改成 4 个较为合适。

2019-12-18

部件数量多的时候,存在以下问题:

  • 脏矩形处理耗时长
  • 部件样式更新耗时长

以下是性能探查器的检测结果:

Performance

测试程序在每次改完部件样式后会调用 LCUIWidget_RefreshStyle() 刷新全部部件样式,一般情况下应用程序并不需要主动调用这个函数,而是应该调用 Widget_UpdateStyle() 更新当前改动的部件样式。在调整测试程序后,渲染性能会从 30 帧会降到 5 帧,性能检测结果如下:

Performance

由于 LCUIWidget_RefreshStyle() 会标记全屏为无效区域,使后续添加的其它区域都会被忽略掉,所以花费在脏矩形处理上的时间很少。在改成 Widget_UpdateStyle() 调用后,总共会添加 3600 个脏矩形,而脏矩形的处理方式很粗暴,每次添加脏矩形时会遍历一遍脏矩形记录,导致性能非常低。

文章版权归作者所有,未经许可不得转载。

问题反馈

对此文章有疑问?你可以点击 这里 反馈