# 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 .
"""
Specific handling for some HTML elements, especially replaced elements.
Replaced elements (eg. elements) are rendered externally and behave
as an atomic opaque box in CSS. They may or may not have intrinsic dimensions.
"""
from __future__ import division
from .formatting_structure import boxes
from .utils import get_url_attribute
# Maps HTML tag names to function taking an HTML element and returning a Box.
HTML_HANDLERS = {}
def handle_element(document, element, box):
"""Handle HTML elements that need special care.
:returns: a (possibly empty) list of boxes.
"""
if box.element_tag in HTML_HANDLERS:
return HTML_HANDLERS[element.tag](document, element, box)
else:
return [box]
def handler(tag):
"""Return a decorator registering a function handling ``tag`` elements."""
def decorator(function):
"""Decorator registering a function handling ``tag`` elements."""
HTML_HANDLERS[tag] = function
return function
return decorator
def is_block_level(box):
"""Tell wether ``box`` is supposed to be block level.
Return ``True`` if the element is block-level, ``False`` if it is
inline-level, and raise ValueError if it is neither.
"""
display = box.style.display
if display in ('block', 'list-item', 'table'):
return True
elif display in ('inline', 'inline-table', 'inline-block'):
return False
else:
raise ValueError('Unsupported display: ' + display)
def make_replaced_box(element, box, image):
"""Wrap an image in a replaced box.
That box is either block-level or inline-level, depending on what the
element should be.
"""
if is_block_level(box):
type_ = boxes.BlockReplacedBox
else:
type_ = boxes.InlineReplacedBox
return type_(element.tag, element.sourceline, box.style, image)
def make_text_box(element, box, text):
"""Make a text box.
If the element should be block-level, wrap it in a block box.
"""
text_box = boxes.TextBox(element.tag, element.sourceline,
box.style.inherit_from(), text)
if is_block_level(box):
type_ = boxes.BlockBox
else:
type_ = boxes.InlineBox
return type_(element.tag, element.sourceline,
box.style, [text_box])
# TODO: also support images (including SVG) in