Skip to content

Commit

Permalink
docs: add rfcs
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-soft committed Jun 3, 2023
1 parent 53ec550 commit 4a0c470
Show file tree
Hide file tree
Showing 22 changed files with 1,930 additions and 96 deletions.
56 changes: 56 additions & 0 deletions docs/rfcs/0000-template.zh-cn.md
@@ -0,0 +1,56 @@
- 开始日期:(填写今天的日期,YYYY-MM-DD)
- 目标主要版本:(2.x / 3.x)
- 参考问题:(填写现有的相关问题,如果有的话)
- 实现 PR:(留空)

# 概括

功能的简要说明。

# 基本示例

如果提案涉及新的或更改的 API,请包括一个基本代码示例。
如果不适用,请忽略此部分。

# 动机

我们为什么要这样做呢? 它支持哪些用例? 什么是预期
结果?

请重点解释动机,以便如果不接受此 RFC,
这种动机可用于制定替代解决方案。 换句话说,
枚举你试图解决的约束而不耦合它们
与您想到的解决方案密切相关。

# 详细设计

这是 RFC 的大部分内容。 为某人详细解释设计
熟悉 LCUI 才能理解,对于熟悉的人来说
实施实施。 这应该进入细节和极端情况,
并包括如何使用该功能的示例。 任何新术语都应该
在这里定义。

# 缺点

我们为什么**这样做? 请考虑:

- 实施成本,包括代码大小和复杂性
- 提议的特性是否可以在用户空间实现
- 对教人 LCUI 的影响
- 将此功能与其他现有和计划中的功能集成
- 迁移现有 LCUI 应用程序的成本(这是一个重大变化吗?)

选择任何路径都需要权衡。 尝试在此处识别它们。

# 备选方案

还考虑了哪些其他设计? 不这样做有什么影响?

# 采用策略

如果我们实施这个提案,现有的 LCUI 开发人员将如何采用它? 是...
这是一个破坏性的改动? 我们可以写一个 codemod 吗? 我们能否为它所取代的原始 API 提供一个运行时适配库? 这将如何影响 LCUI 生态系统中的其他项目?

# 未解决的问题

可选,但建议用于初稿。 设计的哪些部分仍然存在
3 changes: 3 additions & 0 deletions docs/rfcs/README.md
@@ -0,0 +1,3 @@
# LCUI RFCs

[中文](README.zh-cn.md)/**English**
96 changes: 96 additions & 0 deletions docs/rfcs/README.zh-cn.md
@@ -0,0 +1,96 @@
# LCUI RFCs

**中文**/[English](README.md)

许多改动,包括错误修复和文档改进,都可以通过正常的 GitHub/Gitee 拉取请求工作流程实施和审查。

虽然有些改动是“实质性的”,但我们要求这些改动经过一些设计过程,并在 LCUI 核心团队中达成共识。

“RFC”(征求意见)流程旨在为新功能进入项目提供一致且受控的路径。

## RFC 生命周期

- 待处理:当 RFC 作为 PR 提交时。
- 已生效:当 RFC PR 已合并、且正在实施时。
- 已落地:当 RFC 提议的更改在实际版本中发布时。
- 已拒绝:当一个 RFC PR 在没有被合并的情况下被关闭。

[活跃的征求意见列表](https://gitee.com/lc-soft/LCUI/pulls?search=%E5%BE%81%E6%B1%82%E6%84%8F%E8%A7%81)

## 贡献者协议 (CLA)

为了接受你的拉取请求,我们需要你提交贡献者协议。如果你是第一次提交拉取请求,请告诉我们你已完成 贡献者协议签署。

[点击此处签署你的贡献者协议](https://gitee.com/organizations/lc-ui/cla/lcui-cla)

## 何时遵循此流程

如果你打算对 LCUI 或其文档进行“实质性”改动,则应考虑使用此过程。

构成“实质性”变化的内容是根据社区规范不断演变的,但可能包括以下内容:

- 基于新 API 接口实现的新功能
- 删除已作为发布渠道的一部分提供的功能
- 引入新的惯用用法或约定,即使它们不包括对 LCUI 本身的代码更改

一些更改不需要征求意见:

- 改写、重组或重构
- 添加或删除警告
- 添加的内容只会被其他 LCUI 实现者注意到,而对 LCUI 用户是不可见的

## 为什么你需要这样做

为了提升稳定性,更多地考虑我们所做的每一项更改对最终用户可能造成的影响,另一方面,也需要防止新 API 变得更复杂。

在 LCUI 的 2.x 版本之前,所有改动都没有文档,其中有些改动并没有经过认真思考和设计,在后期维护时,它们会阻碍我们理解相关需求和设计意图。对于用户而言,我们希望公开 LCUI 已实施的和待实施的改动,以征求更好的改进意见,让新增的改动内容更稳定可靠,而不是像以前那样随便增加了一些没有文档的功能,然后又随便删掉,又或是推倒重写。

此外,在对 LCUI 进行更改时,RFC 流程可以引导你完成我们的思考过程,这样我们就可以在讨论为什么或为什么不应该进行这些更改时达成共识。

## 在提交前收集反馈

在深入研究 RFC 所需的 API 设计细节级别之前,获得对你的概念的反馈通常很有帮助。你可以在此仓库上提出问题以展开讨论,目标是最终制定具有特定实现设计的 RFC 拉取请求。

## 流程是什么

简而言之,要将主要功能添加到 LCUI,首先必须将 RFC 作为 markdown 文件合并到此代码库中。届时 RFC 的状态是“已确认”并且可能以最终包含到 LCUI 中为目标来实现。

1. 基于此代码库中的模板 (`0000-template.zh-cn.md`) ,在新的 Markdown 文件中撰写你的提案。
- 注意细节:RFC 没有提供令人信服的动机,没有展示对设计影响的理解,或者对缺点或替代方案不诚实,往往不会被接受。
1.[讨论板块](https://github.com/lc-soft/LCUI/discussions)中打开一个新主题帖,并确保将类别设置为“RFC Discussions”。
- 在讨论主题帖中建立共识并整合反馈。 获得广泛支持的 RFC 比那些没有收到任何评论的 RFC 更有可能取得进展。
1. 如果提案收到社区成员的极大兴趣和普遍积极的反馈,你可以准备一个 拉取请求:
- Fork 此仓库。
- 创建你的提案并命名为 `active-rfcs/0000-my-feature.md` (其中的 "my-feature" 对提案的描述,而编号无需指定)。
- 提交拉取请求。确保它链接到讨论帖。
1. 最终,核心团队将确定是否纳入 LCUI 中的候选 RFC。
- RFC 可根据核心团队和社区的反馈进行修改。重大修改可能会触发新的最终评论期。
- RFC 在公众讨论已经解决并且评论总结了拒绝的理由之后可能会被拒绝。然后,核心团队的一名成员应该关闭 RFC 的相关拉取请求。
- RFC 可能会在其最终评论期结束时被接受。 核心团队成员将合并 RFC 的相关拉取请求,此时 RFC 将变为“已生效”状态。

## 有关活动 RFC 的详细信息

一旦 RFC 生效,作者就可以实现它并将该功能作为拉取请求提交到 LCUI 存储库。 变为“生效”意味着核心团队已经原则上同意并愿意合并它,并不意味着该功能最终会被合并。

此外,给定的 RFC 已被接受并处于“生效”状态这一事实并不意味着分配给其实现的优先级是什么,也不意味着当前是否有人正在处理它。

后续的 PR 可对生效的 RFC 进行修改。我们努力以反映功能最终设计的方式编写每个 RFC;但是这个过程的性质意味着我们不能期望每个合并的 RFC 都能实际反映下一个主要版本发布时的最终结果;因此,我们尝试按计划使每个 RFC 文档与语言功能保持同步,并通过对文档的后续拉取请求来跟踪此类更改。

## 实现 RFC

RFC 的作者没有义务实施它。 当然,欢迎 RFC 作者(像任何其他开发人员一样)在 RFC 被接受后发布实现以供审查。

一个生效的 RFC 应该有指向实现 PR 的链接(如果有的话)。 对实际实现的反馈应该在实现 PR 而不是原来的 RFC PR 中进行。

如果你对“活跃”RFC 的实现感兴趣,但无法确定其他人是否已经在处理它,请随时提问(例如,通过对相关问题发表评论)。

## 审查 RFC

核心团队的成员将尝试定期审查一些已打开的 RFC 拉取请求。 如果核心团队成员认为 RFC PR 已准备好接受进入生效状态,他们可以使用 GitHub/Gitee 的审查功能批准 PR,以表示他们批准了 RFC。

## 参考

LCUI 的 RFC 流程及文档内容参考自:

- https://github.com/reactjs/rfcs
- https://github.com/vuejs/rfcs
154 changes: 154 additions & 0 deletions docs/rfcs/active-refs/0000-lib-css-computed-style.md
@@ -0,0 +1,154 @@
- 开始日期:2023-04-08
- 目标主要版本:3.x
- 参考问题:无
- 实现 PR:[#287](https://github.com/lc-soft/LCUI/pull/287)

# 概括

重新设计 CSS 样式计算流程和相关数据存储方式,将 UI 库中的部分样式计算逻辑移入 CSS 库中实现。

# 基本示例

以下是 UI 部件的计算流程示例:

```c
css_computed_style_t *s = &w->specified_style;
css_style_decl_t *style;

css_computed_style_destroy(s);
if (w->custom_style) {
style = css_style_decl_create();
css_style_decl_merge(style, w->custom_style);
css_style_decl_merge(style, w->matched_style);
css_cascade_style(style, s);
css_style_decl_destroy(style);
} else {
css_cascade_style(w->matched_style, s);
}
w->computed_style = *s;
ui_widget_compute_style(w);
```
先清空之前的计算结果,然后层叠(Cascade)已匹配样式和自定义样式,最后对层叠结果进行计算,得出已计算样式。
2.x 版本中的 `LCUI_Widget` 结构体成员 `style` 和 `computed_style` 已统一改用 `css_computed_style_t` 类型,并重命名为 `specified_style` 和 `computed_style`。
# 动机
UI 库中包含了部分 CSS 计算逻辑,例如:width、height、flex-grow 等属性的应用值计算,这有违单一责任原则,应该将 CSS 属性计算移动到 CSS 库内,以让 CSS 库的功能更完备。
另一个方面,UI 部件的 `computed_style` 和 `style` 成员的内存占用比较大:`computed_style` 占用 336 字节,`style` 成员占用 8 字节,其中每个 CSS 属性值占用 16 字节,共有 68 个属性值,也就是共占用 336 + 8 + 16 * 68 = 1432 字节,需要优化。
# 详细设计
参考 [LibCSS](http://www.netsurf-browser.org/projects/libcss/) 的设计,更改样式计算流程为:
1. 层叠已匹配的样式和自定义样式,计算每个属性的指定值,得出指定样式(`specified_style`)。
1. 计算每个属性的实际值,得出已计算样式(`computed_style`)。
内存优化方面,调整已计算样式的数据结构,以比特位为最小粒度为 CSS 属性值分配存储空间,例如:
```c
typedef struct css_computed_style_t {
struct css_type_bits_t {
uint8_t display : 5;
uint8_t box_sizing : 2;
uint8_t visibility : 4;
uint8_t vertical_align : 4;
uint8_t pointer_events : 2;
uint8_t position : 3;
...
} type_bits;
struct css_unit_bits_t {
css_unit_t left : 4;
css_unit_t right : 4;
css_unit_t top : 4;
css_unit_t bottom : 4;
css_unit_t width : 4;
css_unit_t height : 4;
...
} unit_bits;
css_numeric_value_t z_index;
css_numeric_value_t opacity;
css_numeric_value_t left;
css_numeric_value_t right;
css_numeric_value_t top;
css_numeric_value_t bottom;
...
}
```

以目前的 CSS 属性数量,`css_computed_style_t` 占用 288 字节,相比修改前减少了 `1432 - 288 * 2 = 856` 字节。

为方便使用属性值,可为部分 CSS 属性提供 `css_computed_` 开头的辅助函数,例如:

```c
LIBCSS_PUBLIC uint8_t css_computed_display(const css_computed_style_t *s);

LIBCSS_PUBLIC uint8_t css_computed_width(const css_computed_style_t *s,
css_numeric_value_t *value,
css_unit_t *unit);

LIBCSS_PUBLIC uint8_t css_computed_height(const css_computed_style_t *s,
css_numeric_value_t *value,
css_unit_t *unit);
```
用法如下:
```c
css_number_value_t value;
css_unit_t unit;
switch (css_computed_width(&style, &value, &unit)) {
case CSS_WIDTH_AUTO:
// ...
break;
case CSS_WIDTH_SET:
if (unit == CSS_UNIT_PERCENT) {
// ...
}
break;
default:
break;
}
```

还可以添加一些常用的 CSS 值操作相关的工具函数宏,例如:

```c
#define IS_CSS_LENGTH(S, PROP_KEY) (S)->type_bits.PROP_KEY == CSS_LENGTH_SET

#define IS_CSS_FIXED_LENGTH(S, PROP_KEY) \
((S)->type_bits.PROP_KEY == CSS_LENGTH_SET && \
(S)->unit_bits.PROP_KEY == CSS_UNIT_PX)
```

# 缺点

每次样式计算都是计算全部属性的值,影响性能。

# 备选方案

改用 libcss 库。不建议采用此方案,因为 libcss 的用法与 LCUI 现有的 CSS 库的用法相差较大。

# 采用策略

这是个破坏性改动,包含数据结构和函数的改动,涉及 UI 库和 CSS 库。

数据结构的改动主要是 `LCUI_Widget`

```diff
- LCUI_StyleList custom_style;
- LCUI_CachedStyleSheet inherited_style;
- LCUI_WidgetStyle computed_style;
+ css_style_decl_t *custom_style;
+ const css_style_decl_t *matched_style;
+ css_computed_style_t specified_style;
+ css_computed_style_t computed_style;
```

UI 库内涉及样式读写的代码都需要重构,包括布局计算、绘制、鼠标事件等。

0 comments on commit 4a0c470

Please sign in to comment.