mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-05 16:37:47 +03:00
98 lines
3.3 KiB
Python
98 lines
3.3 KiB
Python
|
# 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/>.
|
||
|
|
||
|
|
||
|
"""
|
||
|
Preferred minimum width and preferred width, also know as shrink-to-fit.
|
||
|
|
||
|
"""
|
||
|
|
||
|
import cairo
|
||
|
|
||
|
from ..formatting_structure import boxes
|
||
|
from ..text import TextFragment
|
||
|
from .inlines import replaced_box_width
|
||
|
|
||
|
|
||
|
def inline_preferred_minimum_width(box):
|
||
|
"""Return the preferred minimum width for an ``InlineBox``.
|
||
|
|
||
|
This is the width by breaking at every line-break opportunity.
|
||
|
|
||
|
*Warning:* only TextBox and InlineReplacedBox children are supported
|
||
|
for now. (No recursive InlineBox childdren.)
|
||
|
|
||
|
"""
|
||
|
widest_line = 0
|
||
|
for child in box.children:
|
||
|
if isinstance(child, boxes.AtomicInlineLevelBox):
|
||
|
# Images are on their own line
|
||
|
current_line = replaced_preferred_width(child)
|
||
|
else:
|
||
|
assert isinstance(child, boxes.TextBox)
|
||
|
current_line = max(text_lines_width(child, width=0))
|
||
|
widest_line = max(widest_line, current_line)
|
||
|
return widest_line
|
||
|
|
||
|
|
||
|
def inline_preferred_width(box):
|
||
|
"""Return the preferred width for an ``InlineBox``.
|
||
|
|
||
|
This is the width by only breaking at forced line breaks.
|
||
|
|
||
|
*Warning:* only TextBox and InlineReplacedBox children are supported
|
||
|
for now. (No recursive InlineBox childdren.)
|
||
|
|
||
|
"""
|
||
|
widest_line = 0
|
||
|
current_line = 0
|
||
|
for child in box.children:
|
||
|
if isinstance(child, boxes.InlineReplacedBox):
|
||
|
# No line break around images
|
||
|
current_line += replaced_preferred_width(child)
|
||
|
else:
|
||
|
assert isinstance(child, boxes.TextBox)
|
||
|
lines = list(text_lines_width(child, width=None))
|
||
|
assert lines
|
||
|
# The first text line goes on the current line
|
||
|
current_line += lines[0]
|
||
|
if len(lines) > 1:
|
||
|
# Forced line break
|
||
|
widest_line = max(widest_line, current_line)
|
||
|
if len(lines) > 2:
|
||
|
widest_line = max(widest_line, max(lines[1:-1]))
|
||
|
current_line = lines[-1]
|
||
|
widest_line = max(widest_line, current_line)
|
||
|
return widest_line
|
||
|
|
||
|
|
||
|
def text_lines_width(box, width):
|
||
|
"""Return the list of line widths for a ``TextBox``."""
|
||
|
# TODO: find the real surface, to have correct hinting
|
||
|
context = cairo.Context(cairo.PDFSurface(None, 1, 1))
|
||
|
fragment = TextFragment(box.text, box.style, context, width=width)
|
||
|
return fragment.line_widths()
|
||
|
|
||
|
|
||
|
def replaced_preferred_width(box):
|
||
|
"""Return the preferred (minimum) width for an ``InlineReplacedBox``."""
|
||
|
# TODO: what about percentage widths?
|
||
|
# TODO: get the actual device size. Or do we really care?
|
||
|
replaced_box_width(box, device_size=None)
|
||
|
return box.width
|