12

我正在尝试实现我自己的基于流的小布局引擎。它应该模仿 HTML 布局的行为,但只模仿渲染树,而不是 DOM 部分。渲染树中元素的基类是 Node类。它有:

  • 指向 DOM 中元素的链接(对于那些使用该库构建渲染树的元素)
  • 对它的父级的引用(这是一个ContainerNode实例或无,见后文)
  • 对布局选项的引用
  • X、Y、宽度和高度(在 中计算layout()大小之后,在 中计算compute_size()位置。虽然位置由layout()父级的方法定义,但大小由选项引用定义)。

它的方法是:

  • reflow()调用compute_size()layout()
  • compute_size()用于计算节点的宽度和高度。
  • layout()它旨在定位节点的节点,而不是节点本身。
  • paint()这是由图书馆的用户覆盖的。

该类ContainerNode正在实现子节点的处理。它提供了一个名为 的新方法add_node(),它将传递的节点添加到容器子容器中。该函数还接受默认为 False 的参数force,因为允许容器拒绝传递的节点,但force设置为 True。

这两个类不实现任何布局算法。我的目标是为不同类型的布局创建不同的类(在 CSS 中,主要由display属性定义)。昨晚我对文本布局进行了一些测试,您可以从pastebin.com找到我的代码(需要 pygame)。您可以将其保存到 python 脚本文件并像这样调用它:

python text_test block -c -f "Georgia" -s 15

注意:代码真的很糟糕。我很欣赏对深层误解的评论。

上面提到的代码中的类InlineNodeRow实际上代表了我的想法,即如何实现布局类似于display:inline属性的节点(结合NodeBox)。

问题 1 - 内联文本的边距和填充

回到我在库中的当前方法:文本中的单个单词也将表示为单个节点(就像上面的代码一样)。<span>但我注意到标签中的边距和填充有两件事。

  1. 设置边距时,只考虑水平边距,忽略垂直边距。
  2. 填充溢出父容器并且不会“移动”跨度节点。

请参阅http://jsfiddle.net/CeRkT/1/

我在这里看到了问题:当我想计算 的大小时InlineNodeBox,我向文本节点询问它的大小并将其添加到节点的大小中。但是文本节点的大小包括它的边距和填充,这包括在 HTML 渲染器的定位中。因此下面的代码是不正确的:

def compute_size(self):
    # Propagates the computation to the child-nodes.
    super(InlineNodeBox, self).compute_size()

    self.w = 0
    self.h = 0
    for node in self.nodes:
        self.w += node.w
        if self.h < node.h:
            self.h = node.h

node.w将包括边距和填充。我看到的下一个问题是,为了正确布置文本节点,我想将它们拆分TextNode为每个单词的单个 s,但是边距和填充随后将应用于所有这些节点,而 HTML 中的边距和填充<span>仅对标签。

我认为我目前将每个单词放入单独节点的想法并不理想。浏览器如何构建他们的渲染树,或者你有更好的主意吗?

问题 2 - 单词太长,放到下一行。

该类InlineNodeBox目前只组织一个单行。在上面的代码示例中,我InlineNodeBoxNodeBox前者拒绝接受节点(这意味着它不适合)中创建了一个新的。我不能用我目前的方法做到这一点,因为我不想重新重建渲染树。当一个节点被接受一次,但超过InlineNodeBox下一次回流时,我如何正确地将单词放入下一行(假设我保持InlineNodeBox类只组织单行节点的想法)?


我真的希望这一切都有意义。如果您不理解我的概念,请随时询问。我也非常愿意接受对其他概念、资源链接、文档、出版物等的批评和想法。

4

2 回答 2

1

问题2

您可以像 HTML 渲染器那样渲染多行(例如,检查要添加的新单词是否超过宽度,如果超过则添加新行)。你可以在你的InlineNodeRow, 中做到这一点,如果它们超过最大宽度,也要注意高度并换行。

问题1

如果您确实为文本找出问题 2,那么您可以只为第一行输入偏移量(水平填充)。

虽然<span>没有height考虑,但确实需要line-height,因此您的计算可能是默认高度是字体高度,除非您有可用的line-height选项。

请注意,如果您有两个或多个连续InlineNodeRow的表示跨度,则需要一些智能逻辑来使第二个从第一个结束的地方继续:)

作为旁注,根据我对 Qt 的富文本标签的记忆,具有相同渲染属性的每组单词都被认为是一个节点,它的渲染函数负责计算所有内容。你的方法更细化,我看到的唯一缺点是你不能拆分单词。

高温下,

于 2013-01-14T15:22:26.593 回答
1

可能已经在盒子模型文档中找到了问题 1的解决方案(您可能需要查看有关间隙的文档和溢出的文档以及问题 2的文档)。

"margins of absolutely positioned boxes do not collapse."

您可以查看此 jsfiddle示例。

于 2013-01-18T00:41:09.107 回答