weasyprint 65.1__py3-none-any.whl → 66.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- weasyprint/__init__.py +4 -1
- weasyprint/__main__.py +2 -0
- weasyprint/css/__init__.py +12 -4
- weasyprint/css/computed_values.py +8 -2
- weasyprint/css/html5_ua.css +2 -7
- weasyprint/css/html5_ua_form.css +1 -1
- weasyprint/css/utils.py +1 -1
- weasyprint/document.py +2 -10
- weasyprint/draw/__init__.py +51 -57
- weasyprint/draw/border.py +120 -66
- weasyprint/draw/text.py +1 -2
- weasyprint/formatting_structure/boxes.py +3 -2
- weasyprint/formatting_structure/build.py +32 -42
- weasyprint/images.py +8 -15
- weasyprint/layout/__init__.py +5 -2
- weasyprint/layout/absolute.py +4 -1
- weasyprint/layout/block.py +60 -29
- weasyprint/layout/column.py +1 -0
- weasyprint/layout/flex.py +41 -21
- weasyprint/layout/float.py +8 -1
- weasyprint/layout/grid.py +1 -1
- weasyprint/layout/inline.py +7 -8
- weasyprint/layout/page.py +23 -1
- weasyprint/layout/preferred.py +59 -32
- weasyprint/layout/table.py +8 -4
- weasyprint/pdf/__init__.py +13 -6
- weasyprint/pdf/anchors.py +2 -2
- weasyprint/pdf/pdfua.py +7 -115
- weasyprint/pdf/stream.py +40 -49
- weasyprint/pdf/tags.py +305 -0
- weasyprint/stacking.py +14 -15
- weasyprint/svg/__init__.py +22 -11
- weasyprint/svg/bounding_box.py +4 -2
- weasyprint/svg/defs.py +4 -9
- weasyprint/svg/utils.py +9 -5
- weasyprint/text/fonts.py +1 -1
- weasyprint/text/line_break.py +45 -26
- weasyprint/urls.py +21 -10
- {weasyprint-65.1.dist-info → weasyprint-66.0.dist-info}/METADATA +1 -1
- weasyprint-66.0.dist-info/RECORD +74 -0
- weasyprint/draw/stack.py +0 -13
- weasyprint-65.1.dist-info/RECORD +0 -74
- {weasyprint-65.1.dist-info → weasyprint-66.0.dist-info}/WHEEL +0 -0
- {weasyprint-65.1.dist-info → weasyprint-66.0.dist-info}/entry_points.txt +0 -0
- {weasyprint-65.1.dist-info → weasyprint-66.0.dist-info}/licenses/LICENSE +0 -0
weasyprint/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ import cssselect2
|
|
|
15
15
|
import tinycss2
|
|
16
16
|
import tinyhtml5
|
|
17
17
|
|
|
18
|
-
VERSION = __version__ = '
|
|
18
|
+
VERSION = __version__ = '66.0'
|
|
19
19
|
|
|
20
20
|
#: Default values for command-line and Python API options. See
|
|
21
21
|
#: :func:`__main__.main` to learn more about specific options for
|
|
@@ -39,6 +39,8 @@ VERSION = __version__ = '65.1'
|
|
|
39
39
|
#: A PDF version number.
|
|
40
40
|
#: :param bool pdf_forms:
|
|
41
41
|
#: Whether PDF forms have to be included.
|
|
42
|
+
#: :param bool pdf_tags:
|
|
43
|
+
#: Whether PDF should be tagged for accessibility.
|
|
42
44
|
#: :param bool uncompressed_pdf:
|
|
43
45
|
#: Whether PDF content should be compressed.
|
|
44
46
|
#: :param bool custom_metadata:
|
|
@@ -71,6 +73,7 @@ DEFAULT_OPTIONS = {
|
|
|
71
73
|
'pdf_variant': None,
|
|
72
74
|
'pdf_version': None,
|
|
73
75
|
'pdf_forms': None,
|
|
76
|
+
'pdf_tags': False,
|
|
74
77
|
'uncompressed_pdf': False,
|
|
75
78
|
'custom_metadata': False,
|
|
76
79
|
'presentational_hints': False,
|
weasyprint/__main__.py
CHANGED
|
@@ -89,6 +89,8 @@ PARSER.add_argument(
|
|
|
89
89
|
PARSER.add_argument('--pdf-version', help='PDF version number')
|
|
90
90
|
PARSER.add_argument(
|
|
91
91
|
'--pdf-forms', action='store_true', help='include PDF forms')
|
|
92
|
+
PARSER.add_argument(
|
|
93
|
+
'--pdf-tags', action='store_true', help='tag PDF for accessibility')
|
|
92
94
|
PARSER.add_argument(
|
|
93
95
|
'--uncompressed-pdf', action='store_true',
|
|
94
96
|
help='do not compress PDF content, mainly for debugging purpose')
|
weasyprint/css/__init__.py
CHANGED
|
@@ -573,28 +573,36 @@ def declaration_precedence(origin, importance):
|
|
|
573
573
|
return 5
|
|
574
574
|
|
|
575
575
|
|
|
576
|
-
def resolve_var(computed, token, parent_style):
|
|
576
|
+
def resolve_var(computed, token, parent_style, known_variables=None):
|
|
577
577
|
"""Return token with resolved CSS variables."""
|
|
578
578
|
if not check_var_function(token):
|
|
579
579
|
return
|
|
580
580
|
|
|
581
|
+
if known_variables is None:
|
|
582
|
+
known_variables = set()
|
|
583
|
+
|
|
581
584
|
if token.lower_name != 'var':
|
|
582
585
|
arguments = []
|
|
583
586
|
for i, argument in enumerate(token.arguments):
|
|
584
587
|
if argument.type == 'function':
|
|
585
|
-
arguments.extend(resolve_var(
|
|
588
|
+
arguments.extend(resolve_var(
|
|
589
|
+
computed, argument, parent_style, known_variables))
|
|
586
590
|
else:
|
|
587
591
|
arguments.append(argument)
|
|
588
592
|
token = tinycss2.ast.FunctionBlock(
|
|
589
593
|
token.source_line, token.source_column, token.name, arguments)
|
|
590
|
-
return resolve_var(computed, token, parent_style) or (token,)
|
|
594
|
+
return resolve_var(computed, token, parent_style, known_variables) or (token,)
|
|
591
595
|
|
|
592
596
|
args = parse_function(token)[1]
|
|
593
597
|
variable_name = args.pop(0).value.replace('-', '_') # first arg is name
|
|
598
|
+
if variable_name in known_variables:
|
|
599
|
+
return [] # endless recursion, returned value is nothing
|
|
600
|
+
else:
|
|
601
|
+
known_variables.add(variable_name)
|
|
594
602
|
default = args # next args are default value
|
|
595
603
|
computed_value = []
|
|
596
604
|
for value in (computed[variable_name] or default):
|
|
597
|
-
resolved = resolve_var(computed, value, parent_style)
|
|
605
|
+
resolved = resolve_var(computed, value, parent_style, known_variables)
|
|
598
606
|
computed_value.extend((value,) if resolved is None else resolved)
|
|
599
607
|
return computed_value
|
|
600
608
|
|
|
@@ -282,7 +282,7 @@ def length(style, name, value, font_size=None, pixels_only=False):
|
|
|
282
282
|
elif unit in LENGTHS_TO_PIXELS:
|
|
283
283
|
# Convert absolute lengths to pixels
|
|
284
284
|
result = value.value * LENGTHS_TO_PIXELS[unit]
|
|
285
|
-
elif unit in ('em', 'ex', 'ch', 'rem'):
|
|
285
|
+
elif unit in ('em', 'ex', 'ch', 'rem', 'lh', 'rlh'):
|
|
286
286
|
if font_size is None:
|
|
287
287
|
font_size = style['font_size']
|
|
288
288
|
if unit == 'ex':
|
|
@@ -296,6 +296,12 @@ def length(style, name, value, font_size=None, pixels_only=False):
|
|
|
296
296
|
result = value.value * font_size
|
|
297
297
|
elif unit == 'rem':
|
|
298
298
|
result = value.value * style.root_style['font_size']
|
|
299
|
+
elif unit == 'lh':
|
|
300
|
+
line_height, _ = strut_layout(style)
|
|
301
|
+
result = value.value * line_height
|
|
302
|
+
elif unit == 'rlh':
|
|
303
|
+
line_height, _ = strut_layout(style.root_style)
|
|
304
|
+
result = value.value * line_height
|
|
299
305
|
else:
|
|
300
306
|
# A percentage or 'auto': no conversion needed.
|
|
301
307
|
return value
|
|
@@ -478,7 +484,7 @@ def _content_list(style, values):
|
|
|
478
484
|
if attr is None:
|
|
479
485
|
computed_value = None
|
|
480
486
|
else:
|
|
481
|
-
computed_value = (value[0], (
|
|
487
|
+
computed_value = (value[0], (attr, *value[1][1:]))
|
|
482
488
|
else:
|
|
483
489
|
computed_value = value
|
|
484
490
|
if computed_value is None:
|
weasyprint/css/html5_ua.css
CHANGED
|
@@ -47,11 +47,6 @@ h3 { margin-top: 1em; margin-bottom: 1em }
|
|
|
47
47
|
h4 { margin-top: 1.33em; margin-bottom: 1.33em }
|
|
48
48
|
h5 { margin-top: 1.67em; margin-bottom: 1.67em }
|
|
49
49
|
h6 { margin-top: 2.33em; margin-bottom: 2.33em }
|
|
50
|
-
:is(article, aside, nav, section) h1 { font-size: 1.5em; margin-bottom: .83em; margin-top: .83em }
|
|
51
|
-
:is(article, aside, nav, section) :is(article, aside, nav, section) h1 { font-size: 1.17em; margin-bottom: 1em; margin-top: 1em }
|
|
52
|
-
:is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) h1 { font-size: 1em; margin-bottom: 1.33em; margin-top: 1.33em }
|
|
53
|
-
:is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) h1 { font-size: .83em; margin-bottom: 1.67em; margin-top: 1.67em }
|
|
54
|
-
:is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) :is(article, aside, nav, section) h1 { font-size: .67em; margin-bottom: 2.33em; margin-top: 2.33em }
|
|
55
50
|
|
|
56
51
|
blockquote, figure { margin-left: 40px; margin-right: 40px }
|
|
57
52
|
|
|
@@ -174,9 +169,9 @@ input:is([type=button i], [type=reset i], [type=submit i])[value], button[value]
|
|
|
174
169
|
input[type=submit i]:not([value])::before { content: "Submit" }
|
|
175
170
|
input[type=reset i]:not([value])::before { content: "Reset" }
|
|
176
171
|
input:is([type=checkbox i], [type=radio i]) { height: .7em; vertical-align: -.2em; width: .7em }
|
|
177
|
-
input:is([type=checkbox i], [type=radio i])[checked]::before { background: black; content: ""; height: 100% }
|
|
172
|
+
input:is([type=checkbox i], [type=radio i])[checked]::before { background: black; content: ""; display: block; height: 100% }
|
|
178
173
|
input[type=radio i], input[type=radio][checked]:before { border-radius: 50% }
|
|
179
|
-
input[value]::before { content: attr(value); display: block; overflow: hidden }
|
|
174
|
+
input[value]:not([type=checkbox i], [type=radio i])::before { content: attr(value); display: block; overflow: hidden }
|
|
180
175
|
:is(input, input[value=""], input[type=checkbox i], input[type=radio i]) { content: ""; display: block }
|
|
181
176
|
select { background: lightgrey; border-radius: .25em .25em; position: relative; white-space: normal }
|
|
182
177
|
select[multiple] { height: 3.6em }
|
weasyprint/css/html5_ua_form.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Default stylesheet for PDF forms */
|
|
2
2
|
|
|
3
3
|
button, input, select, textarea { appearance: auto }
|
|
4
|
-
select option, select:not([multiple])::before, input:not([type="submit"])::before {visibility: hidden }
|
|
4
|
+
select option, select:not([multiple])::before, input:not([type="submit"])::before { visibility: hidden }
|
|
5
5
|
textarea { text-indent: 10000% } /* Hide text but don’t change color used by PDF form */
|
weasyprint/css/utils.py
CHANGED
|
@@ -40,7 +40,7 @@ RESOLUTION_TO_DPPX = {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
# Sets of possible length units
|
|
43
|
-
LENGTH_UNITS = set(LENGTHS_TO_PIXELS) | set(['ex', 'em', 'ch', 'rem'])
|
|
43
|
+
LENGTH_UNITS = set(LENGTHS_TO_PIXELS) | set(['ex', 'em', 'ch', 'rem', 'lh', 'rlh'])
|
|
44
44
|
|
|
45
45
|
# Constants about background positions
|
|
46
46
|
ZERO_PERCENT = Dimension(0, '%')
|
weasyprint/document.py
CHANGED
|
@@ -10,7 +10,7 @@ from .anchors import gather_anchors, make_page_bookmark_tree
|
|
|
10
10
|
from .css import get_all_computed_styles
|
|
11
11
|
from .css.counters import CounterStyle
|
|
12
12
|
from .css.targets import TargetCollector
|
|
13
|
-
from .draw import draw_page
|
|
13
|
+
from .draw import draw_page
|
|
14
14
|
from .formatting_structure.build import build_formatting_structure
|
|
15
15
|
from .html import get_html_metadata
|
|
16
16
|
from .images import get_image_from_uri as original_get_image_from_uri
|
|
@@ -82,7 +82,7 @@ class Page:
|
|
|
82
82
|
|
|
83
83
|
def paint(self, stream, scale=1):
|
|
84
84
|
"""Paint the page into the PDF file."""
|
|
85
|
-
with stacked(
|
|
85
|
+
with stream.stacked():
|
|
86
86
|
stream.transform(a=scale, d=scale)
|
|
87
87
|
draw_page(self._page_box, stream)
|
|
88
88
|
|
|
@@ -276,14 +276,6 @@ class Document:
|
|
|
276
276
|
# fonts that may be used when rendering
|
|
277
277
|
self.font_config = font_config
|
|
278
278
|
|
|
279
|
-
def build_element_structure(self, structure, etree_element=None):
|
|
280
|
-
if etree_element is None:
|
|
281
|
-
etree_element = self._html.etree_element
|
|
282
|
-
structure[etree_element] = {'parent': None}
|
|
283
|
-
for child in etree_element:
|
|
284
|
-
structure[child] = {'parent': etree_element}
|
|
285
|
-
self.build_element_structure(structure, child)
|
|
286
|
-
|
|
287
279
|
def copy(self, pages='all'):
|
|
288
280
|
"""Take a subset of the pages.
|
|
289
281
|
|
weasyprint/draw/__init__.py
CHANGED
|
@@ -12,7 +12,6 @@ from ..matrix import Matrix
|
|
|
12
12
|
from ..stacking import StackingContext
|
|
13
13
|
from .border import draw_border, draw_line, draw_outline, rounded_box, set_mask_border
|
|
14
14
|
from .color import styled_color
|
|
15
|
-
from .stack import stacked
|
|
16
15
|
from .text import draw_text
|
|
17
16
|
|
|
18
17
|
|
|
@@ -32,11 +31,9 @@ def draw_page(page, stream):
|
|
|
32
31
|
def draw_stacking_context(stream, stacking_context):
|
|
33
32
|
"""Draw a ``stacking_context`` on ``stream``."""
|
|
34
33
|
# See https://www.w3.org/TR/CSS2/zindex.html.
|
|
35
|
-
with stacked(
|
|
34
|
+
with stream.stacked():
|
|
36
35
|
box = stacking_context.box
|
|
37
36
|
|
|
38
|
-
stream.begin_marked_content(box, mcid=True)
|
|
39
|
-
|
|
40
37
|
# Apply the viewport_overflow to the html box, see #35.
|
|
41
38
|
if box.is_for_root_element and (
|
|
42
39
|
stacking_context.page.style['overflow'] != 'visible'):
|
|
@@ -68,21 +65,20 @@ def draw_stacking_context(stream, stacking_context):
|
|
|
68
65
|
if box.transformation_matrix.determinant:
|
|
69
66
|
stream.transform(*box.transformation_matrix.values)
|
|
70
67
|
else:
|
|
71
|
-
stream.end_marked_content()
|
|
72
68
|
return
|
|
73
69
|
|
|
74
70
|
# Point 1 is done in draw_page.
|
|
75
71
|
|
|
76
72
|
# Point 2.
|
|
77
|
-
if isinstance(box, (boxes.BlockBox, boxes.MarginBox,
|
|
78
|
-
boxes.
|
|
79
|
-
boxes.
|
|
73
|
+
if isinstance(box, (boxes.BlockBox, boxes.MarginBox, boxes.InlineBlockBox,
|
|
74
|
+
boxes.TableCellBox, boxes.FlexContainerBox,
|
|
75
|
+
boxes.GridContainerBox, boxes.ReplacedBox)):
|
|
80
76
|
set_mask_border(stream, box)
|
|
81
|
-
# The canvas background was removed by layout_backgrounds
|
|
77
|
+
# The canvas background was removed by layout_backgrounds.
|
|
82
78
|
draw_background(stream, box.background)
|
|
83
79
|
draw_border(stream, box)
|
|
84
80
|
|
|
85
|
-
with stacked(
|
|
81
|
+
with stream.stacked():
|
|
86
82
|
# Dont clip the page box, see #35.
|
|
87
83
|
clip = (
|
|
88
84
|
box.style['overflow'] != 'visible' and
|
|
@@ -118,17 +114,8 @@ def draw_stacking_context(stream, stacking_context):
|
|
|
118
114
|
draw_inline_level(stream, stacking_context.page, box)
|
|
119
115
|
|
|
120
116
|
# Point 7.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
draw_replacedbox(stream, block)
|
|
124
|
-
elif block.children:
|
|
125
|
-
if block != box:
|
|
126
|
-
stream.begin_marked_content(block, mcid=True)
|
|
127
|
-
if isinstance(block.children[-1], boxes.LineBox):
|
|
128
|
-
for child in block.children:
|
|
129
|
-
draw_inline_level(stream, stacking_context.page, child)
|
|
130
|
-
if block != box:
|
|
131
|
-
stream.end_marked_content()
|
|
117
|
+
draw_block_level(
|
|
118
|
+
stacking_context.page, stream, {box: stacking_context.blocks_and_cells})
|
|
132
119
|
|
|
133
120
|
# Point 8.
|
|
134
121
|
for child_context in stacking_context.zero_z_contexts:
|
|
@@ -144,12 +131,10 @@ def draw_stacking_context(stream, stacking_context):
|
|
|
144
131
|
if box.style['opacity'] < 1:
|
|
145
132
|
group_id = stream.id
|
|
146
133
|
stream = original_stream
|
|
147
|
-
with stacked(
|
|
134
|
+
with stream.stacked():
|
|
148
135
|
stream.set_alpha(box.style['opacity'], stroke=True, fill=True)
|
|
149
136
|
stream.draw_x_object(group_id)
|
|
150
137
|
|
|
151
|
-
stream.end_marked_content()
|
|
152
|
-
|
|
153
138
|
|
|
154
139
|
def draw_background(stream, bg, clip_box=True, bleed=None, marks=()):
|
|
155
140
|
"""Draw the background color and image to a ``pdf.stream.Stream``.
|
|
@@ -161,7 +146,7 @@ def draw_background(stream, bg, clip_box=True, bleed=None, marks=()):
|
|
|
161
146
|
if bg is None:
|
|
162
147
|
return
|
|
163
148
|
|
|
164
|
-
with stacked(
|
|
149
|
+
with stream.stacked():
|
|
165
150
|
if clip_box:
|
|
166
151
|
for box in bg.layers[-1].clipped_boxes:
|
|
167
152
|
rounded_box(stream, box)
|
|
@@ -170,7 +155,7 @@ def draw_background(stream, bg, clip_box=True, bleed=None, marks=()):
|
|
|
170
155
|
|
|
171
156
|
# Draw background color.
|
|
172
157
|
if bg.color.alpha > 0:
|
|
173
|
-
with stacked(
|
|
158
|
+
with stream.artifact(), stream.stacked():
|
|
174
159
|
stream.set_color(bg.color)
|
|
175
160
|
painting_area = bg.layers[-1].painting_area
|
|
176
161
|
stream.rectangle(*painting_area)
|
|
@@ -262,21 +247,21 @@ def draw_background_image(stream, layer, image_rendering):
|
|
|
262
247
|
image_width, image_height = layer.size
|
|
263
248
|
|
|
264
249
|
if repeat_x == 'no-repeat' and repeat_y == 'no-repeat':
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
250
|
+
with stream.artifact():
|
|
251
|
+
# We don't use a pattern when we don't need to because some viewers
|
|
252
|
+
# (e.g., Preview on Mac) introduce unnecessary pixelation when vector
|
|
253
|
+
# images are used in patterns.
|
|
254
|
+
if not layer.unbounded:
|
|
255
|
+
stream.rectangle(
|
|
256
|
+
painting_x, painting_y, painting_width, painting_height)
|
|
257
|
+
stream.clip()
|
|
258
|
+
stream.end()
|
|
259
|
+
# Put the image in a group so that masking outside the image and
|
|
260
|
+
# masking within the image don't conflict.
|
|
261
|
+
group = stream.add_group(*stream.page_rectangle)
|
|
262
|
+
group.transform(e=position_x + positioning_x, f=position_y + positioning_y)
|
|
263
|
+
layer.image.draw(group, image_width, image_height, image_rendering)
|
|
264
|
+
stream.draw_x_object(group.id)
|
|
280
265
|
return
|
|
281
266
|
|
|
282
267
|
if repeat_x == 'no-repeat':
|
|
@@ -322,9 +307,10 @@ def draw_background_image(stream, layer, image_rendering):
|
|
|
322
307
|
0, 0, image_width, image_height, repeat_width, repeat_height, matrix)
|
|
323
308
|
group = pattern.add_group(0, 0, repeat_width, repeat_height)
|
|
324
309
|
|
|
325
|
-
with stacked(
|
|
310
|
+
with stream.artifact(), stream.stacked():
|
|
326
311
|
layer.image.draw(group, image_width, image_height, image_rendering)
|
|
327
|
-
pattern.
|
|
312
|
+
with pattern.artifact():
|
|
313
|
+
pattern.draw_x_object(group.id)
|
|
328
314
|
stream.set_color_space('Pattern')
|
|
329
315
|
stream.set_color_special(pattern.id)
|
|
330
316
|
if layer.unbounded:
|
|
@@ -476,9 +462,9 @@ def draw_collapsed_borders(stream, table):
|
|
|
476
462
|
|
|
477
463
|
for segment in segments:
|
|
478
464
|
_, style, width, color, side, border_box = segment
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
465
|
+
bx, by, bw, bh = border_box
|
|
466
|
+
color = styled_color(style, color, side)
|
|
467
|
+
with stream.artifact(), stream.stacked():
|
|
482
468
|
draw_line(stream, bx, by, bx + bw, by + bh, width, style, color)
|
|
483
469
|
|
|
484
470
|
|
|
@@ -491,10 +477,10 @@ def draw_replacedbox(stream, box):
|
|
|
491
477
|
if draw_width <= 0 or draw_height <= 0:
|
|
492
478
|
return
|
|
493
479
|
|
|
494
|
-
with stacked(
|
|
480
|
+
with stream.stacked():
|
|
495
481
|
stream.set_alpha(1)
|
|
496
482
|
stream.transform(e=draw_x, f=draw_y)
|
|
497
|
-
with stacked(
|
|
483
|
+
with stream.stacked():
|
|
498
484
|
# TODO: Use the real intrinsic size here, not affected by
|
|
499
485
|
# 'image-resolution'?
|
|
500
486
|
box.replacement.draw(
|
|
@@ -513,15 +499,10 @@ def draw_inline_level(stream, page, box, offset_x=0, text_overflow='clip',
|
|
|
513
499
|
draw_background(stream, box.background)
|
|
514
500
|
draw_border(stream, box)
|
|
515
501
|
if isinstance(box, (boxes.InlineBox, boxes.LineBox)):
|
|
516
|
-
link_annotation = None
|
|
517
502
|
if isinstance(box, boxes.LineBox):
|
|
518
503
|
text_overflow = box.text_overflow
|
|
519
504
|
block_ellipsis = box.block_ellipsis
|
|
520
|
-
else:
|
|
521
|
-
link_annotation = box.link_annotation
|
|
522
505
|
ellipsis = 'none'
|
|
523
|
-
if link_annotation:
|
|
524
|
-
stream.begin_marked_content(box, mcid=True, tag='Link')
|
|
525
506
|
for i, child in enumerate(box.children):
|
|
526
507
|
if i == len(box.children) - 1:
|
|
527
508
|
# Last child
|
|
@@ -531,15 +512,28 @@ def draw_inline_level(stream, page, box, offset_x=0, text_overflow='clip',
|
|
|
531
512
|
else:
|
|
532
513
|
child_offset_x = offset_x + child.position_x - box.position_x
|
|
533
514
|
if isinstance(child, boxes.TextBox):
|
|
534
|
-
|
|
515
|
+
with stream.marked(child, 'Span'):
|
|
516
|
+
draw_text(
|
|
517
|
+
stream, child, child_offset_x, text_overflow, ellipsis)
|
|
535
518
|
else:
|
|
536
519
|
draw_inline_level(
|
|
537
520
|
stream, page, child, child_offset_x, text_overflow, ellipsis)
|
|
538
|
-
if link_annotation:
|
|
539
|
-
stream.end_marked_content()
|
|
540
521
|
elif isinstance(box, boxes.InlineReplacedBox):
|
|
541
|
-
|
|
522
|
+
with stream.marked(box, 'Figure'):
|
|
523
|
+
draw_replacedbox(stream, box)
|
|
542
524
|
else:
|
|
543
525
|
assert isinstance(box, boxes.TextBox)
|
|
544
526
|
# Should only happen for list markers.
|
|
545
527
|
draw_text(stream, box, offset_x, text_overflow)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def draw_block_level(page, stream, blocks_and_cells):
|
|
531
|
+
for block, blocks_and_cells in blocks_and_cells.items():
|
|
532
|
+
if isinstance(block, boxes.ReplacedBox):
|
|
533
|
+
with stream.marked(block, 'Figure'):
|
|
534
|
+
draw_replacedbox(stream, block)
|
|
535
|
+
elif block.children:
|
|
536
|
+
if isinstance(block.children[-1], boxes.LineBox):
|
|
537
|
+
for child in block.children:
|
|
538
|
+
draw_inline_level(stream, page, child)
|
|
539
|
+
draw_block_level(page, stream, blocks_and_cells)
|