1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-05 08:27:22 +03:00
WeasyPrint/weasy/formatting_structure/boxes.py

258 lines
7.5 KiB
Python
Raw Normal View History

2011-05-17 13:29:00 +04:00
# coding: utf8
# WeasyPrint converts web documents (HTML, CSS, ...) to PDF.
# Copyright (C) 2011 Simon Sapin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This module defines the classes for all types of boxes in the CSS formatting
structure / box model.
http://www.w3.org/TR/CSS21/visuren.html
Names are the same as in CSS 2.1 with the exception of TextBox. In WeasyPrint,
any text is in a TextBox. What CSS calls anonymous inline boxes are text boxes
but not all text boxes are anonymous inline boxes.
http://www.w3.org/TR/CSS21/visuren.html#anonymous
Abstract classes, should not be instanciated:
* Box
* BlockLevelBox
* InlineLevelBox
* BlockContainerBox
* AnonymousBox
* ReplacedBox
Concrete classes:
* BlockBox
* AnonymousBlockBox
* InlineBox
* InlineBlockBox
* BlockLevelReplacedBox
* InlineLevelReplacedBox
* TextBox
* LineBox
Apart from LineBox, all concrete box classes have one of the following "outside"
behavior:
* Block-level (inherits from BlockLevelBox)
* Inline-level (inherits from InlineLevelBox)
and one of the following "inside" behavior:
* Block container (inherits from BlockContainerBox)
* Inline content (is or inherits from InlineBox)
* Replaced content (inherits from ReplacedBox)
See respective docstrings for details.
"""
2011-05-17 13:29:00 +04:00
from .. import css
2011-05-17 13:29:00 +04:00
2011-05-19 17:31:34 +04:00
class Box(object):
2011-05-23 16:31:14 +04:00
"""
Abstract base class for all boxes.
"""
2011-05-19 17:31:34 +04:00
def __init__(self, element):
# Should never be None
self.element = element
# No parent yet. Will be set when this box is added to another boxs
# children. Only the root box should stay without a parent.
self.parent = None
self.children = []
2011-05-23 15:59:47 +04:00
self._init_style()
2011-06-29 16:04:42 +04:00
2011-05-23 15:59:47 +04:00
def _init_style(self):
2011-05-19 17:31:34 +04:00
# Computed values
2011-05-23 15:59:47 +04:00
# Copying might not be needed, but lets be careful with mutable
# objects.
self.style = self.element.style.copy()
2011-06-29 16:04:42 +04:00
def add_child(self, child, index=None):
2011-05-19 17:31:34 +04:00
"""
Add the new child to this boxs children list and set this box as the
childs parent.
"""
child.parent = self
if index == None:
self.children.append(child)
else:
self.children.insert(index, child)
2011-06-29 16:04:42 +04:00
def descendants(self):
"""A flat generator for a box, its children and descendants."""
yield self
for child in self.children or []:
for grand_child in child.descendants():
yield grand_child
def ancestors(self):
"""Yield parent and recursively yield parent's parents."""
parent = self
while parent.parent:
parent = parent.parent
yield parent
@property
def index(self):
"""Index of the box in its parent's children."""
if self.parent:
return self.parent.children.index(self)
2011-05-19 17:31:34 +04:00
class BlockLevelBox(Box):
2011-05-23 16:31:14 +04:00
"""
A box that participates in an block formatting context.
An element with a 'display' value of 'block', 'liste-item' or 'table'
generates a block-level box.
"""
class BlockContainerBox(Box):
"""
A box that either contains only block-level boxes or establishes an inline
formatting context and thus contains only line boxes.
A non-replaced element with a 'display' value of 'block', 'list-item',
'inline-block' or 'table-cell' generates a block container box.
"""
class BlockBox(BlockContainerBox, BlockLevelBox):
"""
A block-level box that is also a block container.
2011-06-29 16:04:42 +04:00
A non-replaced element with a 'display' value of 'block', 'list-item'
generates a block box.
2011-05-23 16:31:14 +04:00
"""
2011-05-19 17:31:34 +04:00
2011-05-23 15:59:47 +04:00
class AnonymousBox(Box):
2011-05-23 16:31:14 +04:00
"""
A box that is not directly generated by an element. Inherits style instead
of copying them.
2011-05-23 16:31:14 +04:00
"""
2011-05-23 15:59:47 +04:00
def _init_style(self):
pseudo = css.PseudoElement(self.element, 'anonymous_box')
# New PseudoElement has an empty .applicable_properties list:
# no cascaded value, only inherited and initial values.
# TODO: Maybe pre-compute initial values and remove the compute_values
# step here.
css.assign_properties(pseudo)
self.style = pseudo.style
class AnonymousBlockBox(AnonymousBox, BlockBox):
2011-05-23 16:31:14 +04:00
"""
Wraps inline-level boxes where block-level boxes are needed.
2011-06-29 16:04:42 +04:00
Block containers (eventually) contain either only block-level boxes or only
inline-level boxes. When they initially contain both, consecutive
2011-06-29 16:04:42 +04:00
inline-level boxes are wrapped in an anonymous block box by
``boxes.inline_in_block()``.
2011-05-23 16:31:14 +04:00
"""
2011-05-23 15:59:47 +04:00
class LineBox(AnonymousBox):
2011-05-23 16:31:14 +04:00
"""
Eventually a line in an inline formatting context. Can only contain
inline-level boxes.
2011-06-29 16:04:42 +04:00
2011-05-23 16:31:14 +04:00
In early stages of building the box tree a single line box contains many
consecutive inline boxes and will be split later when wrapping lines.
"""
2011-05-19 17:31:34 +04:00
class InlineLevelBox(Box):
2011-05-23 16:31:14 +04:00
"""
A box that participates in an inline formatting context.
2011-06-29 16:04:42 +04:00
An inline-level box that is not an inline box (see below) is said to be
"atomic". Such boxes are inline-blocks, replaced elements and inline tables.
An element with a 'display' value of 'inline', 'inline-table', or
'inline-block' generates an inline-level box.
2011-05-23 16:31:14 +04:00
"""
2011-05-19 17:31:34 +04:00
class InlineBox(InlineLevelBox):
2011-05-23 16:31:14 +04:00
"""
A box who participates in an inline formatting context and whose content
also participates in that inline formatting context.
2011-06-29 16:04:42 +04:00
A non-replaced element with a 'display' value of 'inline' generates an
inline box.
"""
class TextBox(AnonymousBox, InlineBox):
"""
A box that contains only text and has no box children.
2011-06-29 16:04:42 +04:00
Any text in the document ends up in a text box. What CSS calls "anonymous
inline boxes" are also text boxes.
2011-05-23 16:31:14 +04:00
"""
2011-05-19 17:31:34 +04:00
def __init__(self, element, text):
super(TextBox, self).__init__(element)
self.children = None
self.text = text
class InlineBlockBox(InlineLevelBox, BlockContainerBox):
"""
A box that is both inline-level and a block container: it behaves as
inline on the outside and as a block on the inside.
A non-replaced element with a 'display' value of 'inline-block' generates an
inline-block box.
"""
class ReplacedBox(Box):
"""
A box that is replaced, ie. its content is rendered externally and is opaque
from CSSs point of view. Example: <img> elements are replaced.
"""
2011-05-25 17:54:46 +04:00
def __init__(self, element, replacement):
super(ReplacedBox, self).__init__(element)
self.replacement = replacement
class BlockLevelReplacedBox(ReplacedBox, BlockLevelBox):
"""
A box that is both replaced and block-level.
A replaced element with a 'display' value of 'block', 'liste-item' or
'table' generates a block-level replaced box.
"""
class InlineLevelReplacedBox(ReplacedBox, InlineLevelBox):
"""
A box that is both replaced and inline-level.
A replaced element with a 'display' value of 'inline', 'inline-table', or
'inline-block' generates an inline-level replaced box.
"""