HTML就像布局一样

时间:2013-01-10 18:06:35

标签: python layout reflow

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

  • 指向DOM中元素的链接(用于构建具有该库的渲染树的元素)
  • 对它的父级的引用(这是ContainerNode实例或无,请参阅后面的内容)
  • 对布局选项的引用
  • X,Y,宽度和高度(在layout()中计算大小后,位置在compute_size()中计算。而位置由layout()方法定义父级,大小由选项引用定义,例如)。

它的方法是:

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

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

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

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

注意:代码非常糟糕。我很欣赏有关深层次误解的评论。

上面提到的代码中的类InlineNodeRow实际上代表了我如何实现类似于display:inline属性的节点(与NodeBox结合使用)的想法。< / p>

问题1 - 保证金&amp;填充内联文本

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

  1. 设置保证金时,仅考虑水平保证金,忽略垂直保证金。
  2. 填充符溢出父容器,不会“移动”span节点。
  3. 请参阅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课目前只会组织一行。在上面的代码示例中,当前者拒绝接受节点(这意味着它不适合)时,我在InlineNodeBox内创建了一个新的NodeBox。我不能用我当前的方法,因为我不想再重建渲染树。当一个节点被接受一次但超过下一次重排时的InlineNodeBox时,如何正确设置将该单词放入下一行(假设我保持InlineNodeBox类的想法仅组织一个单行节点)?


    我真的希望这一切都有道理。如果您不理解我的概念,请随时询问。我也对其他概念,资源链接,文档,出版物等方面的批评和想法持开放态度。

2 个答案:

答案 0 :(得分:1)

问题2

您可以像HTML渲染器那样执行此操作并渲染多行(例如,检查要添加的新单词是否超出宽度,如果有,则添加新行)。您可以在InlineNodeRow中执行此操作,也可以通过处理高度并在超过最大宽度时包装单词。

问题1

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

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

请注意,如果你有两个或更多连续的line-height代表跨度,你需要一些智能逻辑来使第二个继续从第一个结束的地方开始:)

作为旁注,根据我记得的Qt rich text label,每组具有相同渲染属性的单词被认为是一个节点,其渲染功能负责计算所有的东西。你的方法更精细,我所看到的唯一的缺点是你不能分割单词。

HTH,

答案 1 :(得分:1)

可能已找到box model documentation问题1 的解决方案(您可能需要查看documentation about clearancethe one for overflow以及问题2 )。

"margins of absolutely positioned boxes do not collapse."

您可以查看this jsfiddle作为示例。