1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-09-11 20:47:56 +03:00

Slightly simplify border masks

This commit is contained in:
Guillaume Ayoub 2024-06-08 22:57:15 +02:00
parent a846e0062f
commit 03b8f1acc3
3 changed files with 47 additions and 101 deletions

View File

@ -1,44 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="5"
width="5"
viewBox="0 0 5 5"
version="1.1"
id="svg16"
sodipodi:docname="mask.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="100.40082"
inkscape:cx="1.7679139"
inkscape:cy="2.5597401"
inkscape:window-width="1504"
inkscape:window-height="955"
inkscape:window-x="0"
inkscape:window-y="44"
inkscape:window-maximized="0"
inkscape:current-layer="svg16" />
<defs
id="defs16" />
<path
id="rect2"
d="M 1 0 L 1 1 L 0 1 L 0 2 L 1 2 L 1 3 L 0 3 L 0 4 L 1 4 L 1 5 L 2 5 L 3 5 L 4 5 L 5 5 L 5 4 L 5 3 L 5 2 L 5 1 L 5 0 L 4 0 L 3 0 L 3 1 L 2 1 L 2 0 L 1 0 z M 2 2 L 3 2 L 3 3 L 2 3 L 2 2 z " />
<rect
style="opacity:0.5;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.04315;stroke-miterlimit:3"
id="rect1"
width="1"
height="1"
x="0"
y="2" />
<svg height="5" width="5" xmlns="http://www.w3.org/2000/svg">
<path d="M 1 0 L 1 1 L 0 1 L 0 2 L 1 2 L 1 3 L 0 3 L 0 4 L 1 4 L 1 5 L 2 5 L 3 5 L 4 5 L 5 5 L 5 4 L 5 3 L 5 2 L 5 1 L 5 0 L 4 0 L 3 0 L 3 1 L 2 1 L 2 0 L 1 0 z M 2 2 L 3 2 L 3 3 L 2 3 L 2 2 z " />
<rect fill="black" opacity="0.5" width="1" height="1" x="0" y="2" />
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 340 B

View File

@ -62,6 +62,7 @@ def draw_page(page, stream):
draw_background(
stream, stacking_context.box.background, clip_box=False,
bleed=page.bleed, marks=marks)
set_mask_border(stream, page)
draw_background(stream, page.canvas_background, clip_box=False)
draw_border(stream, page)
draw_stacking_context(stream, stacking_context)
@ -116,7 +117,7 @@ def draw_stacking_context(stream, stacking_context):
if isinstance(box, (boxes.BlockBox, boxes.MarginBox,
boxes.InlineBlockBox, boxes.TableCellBox,
boxes.FlexContainerBox, boxes.ReplacedBox)):
maybe_set_mask_border(box, stream)
set_mask_border(stream, box)
# The canvas background was removed by layout_backgrounds
draw_background(stream, box.background)
draw_border(stream, box)
@ -138,7 +139,7 @@ def draw_stacking_context(stream, stacking_context):
# Point 4
for block in stacking_context.block_level_boxes:
maybe_set_mask_border(block, stream)
set_mask_border(stream, block)
if isinstance(block, boxes.TableBox):
draw_table(stream, block)
@ -444,7 +445,10 @@ def draw_border(stream, box):
# If there's a border image, that takes precedence.
if box.style['border_image_source'][0] != 'none' and box.border_image is not None:
draw_border_image(box, stream)
draw_border_image(
box, stream, box.border_image, box.style['border_image_slice'],
box.style['border_image_repeat'], box.style['border_image_outset'],
box.style['border_image_width'])
return
widths = [getattr(box, f'border_{side}_width') for side in SIDES]
@ -482,8 +486,8 @@ def draw_border(stream, box):
stream, box, style, styled_color(style, color, side))
def draw_border_image_impl(box, stream, image, slice_property,
repeats, outsets, width_property):
def draw_border_image(box, stream, image, border_slice, border_repeat, border_outset,
border_width):
"""Draw ``image`` as a border image for ``box`` on ``stream`` as specified."""
# Shared by border-image-* and mask-border-*
width, height, ratio = image.get_intrinsic_size(
@ -492,8 +496,8 @@ def draw_border_image_impl(box, stream, image, slice_property,
width, height, ratio, specified_width=None, specified_height=None,
default_width=box.border_width(), default_height=box.border_height())
image_slice = slice_property[:4]
should_fill = slice_property[4]
image_slice = border_slice[:4]
should_fill = border_slice[4]
def compute_slice_dimension(dimension, intrinsic):
if isinstance(dimension, (int, float)):
@ -507,7 +511,7 @@ def draw_border_image_impl(box, stream, image, slice_property,
slice_bottom = compute_slice_dimension(image_slice[2], intrinsic_height)
slice_left = compute_slice_dimension(image_slice[3], intrinsic_width)
style_repeat_x, style_repeat_y = repeats
repeat_x, repeat_y = border_repeat
x, y, w, h, tl, tr, br, bl = box.rounded_border_box()
px, py, pw, ph, ptl, ptr, pbr, pbl = box.rounded_padding_box()
@ -523,10 +527,10 @@ def draw_border_image_impl(box, stream, image, slice_property,
assert dimension.unit == 'px'
return dimension.value
outset_top = compute_outset_dimension(outsets[0], border_top)
outset_right = compute_outset_dimension(outsets[1], border_right)
outset_bottom = compute_outset_dimension(outsets[2], border_bottom)
outset_left = compute_outset_dimension(outsets[3], border_left)
outset_top = compute_outset_dimension(border_outset[0], border_top)
outset_right = compute_outset_dimension(border_outset[1], border_right)
outset_bottom = compute_outset_dimension(border_outset[2], border_bottom)
outset_left = compute_outset_dimension(border_outset[3], border_left)
x -= outset_left
y -= outset_top
@ -551,17 +555,16 @@ def draw_border_image_impl(box, stream, image, slice_property,
# for percentage-based border-image-width values includes any expanded
# area due to border-image-outset.
border_top = compute_width_adjustment(
width_property[0], border_top, slice_top, h)
border_width[0], border_top, slice_top, h)
border_right = compute_width_adjustment(
width_property[1], border_right, slice_right, w)
border_width[1], border_right, slice_right, w)
border_bottom = compute_width_adjustment(
width_property[2], border_bottom, slice_bottom, h)
border_width[2], border_bottom, slice_bottom, h)
border_left = compute_width_adjustment(
width_property[3], border_left, slice_left, w)
border_width[3], border_left, slice_left, w)
def draw_border_image_region(x, y, width, height, slice_x, slice_y,
slice_width, slice_height,
repeat_x='stretch', repeat_y='stretch',
def draw_border_image_region(x, y, width, height, slice_x, slice_y, slice_width,
slice_height, repeat_x='stretch', repeat_y='stretch',
scale_x=None, scale_y=None):
if 0 in (intrinsic_width, width, slice_width):
scale_x = 0
@ -652,73 +655,56 @@ def draw_border_image_impl(box, stream, image, slice_property,
draw_border_image_region(
x, y + h - border_bottom, border_left, border_bottom,
0, intrinsic_height - slice_bottom, slice_left, slice_bottom)
if slice_left + slice_right < intrinsic_width:
if x_middle := slice_left + slice_right < intrinsic_width:
# Top middle.
draw_border_image_region(
x + border_left, y, w - border_left - border_right, border_top,
slice_left, 0, intrinsic_width - slice_left - slice_right,
slice_top, repeat_x=style_repeat_x)
slice_top, repeat_x=repeat_x)
# Bottom middle.
draw_border_image_region(
x + border_left, y + h - border_bottom,
w - border_left - border_right, border_bottom,
slice_left, intrinsic_height - slice_bottom,
intrinsic_width - slice_left - slice_right, slice_bottom,
repeat_x=style_repeat_x)
if slice_top + slice_bottom < intrinsic_height:
repeat_x=repeat_x)
if y_middle := slice_top + slice_bottom < intrinsic_height:
# Right middle.
draw_border_image_region(
x + w - border_right, y + border_top,
border_right, h - border_top - border_bottom,
intrinsic_width - slice_right, slice_top,
slice_right, intrinsic_height - slice_top - slice_bottom,
repeat_y=style_repeat_y)
repeat_y=repeat_y)
# Left middle.
draw_border_image_region(
x, y + border_top, border_left, h - border_top - border_bottom,
0, slice_top, slice_left,
intrinsic_height - slice_top - slice_bottom,
repeat_y=style_repeat_y)
if (should_fill and slice_left + slice_right < intrinsic_width
and slice_top + slice_bottom < intrinsic_height):
repeat_y=repeat_y)
if should_fill and x_middle and y_middle:
# Fill middle.
draw_border_image_region(
x + border_left, y + border_top, w - border_left - border_right,
h - border_top - border_bottom, slice_left, slice_top,
intrinsic_width - slice_left - slice_right,
intrinsic_height - slice_top - slice_bottom,
repeat_x=style_repeat_x, repeat_y=style_repeat_y,
repeat_x=repeat_x, repeat_y=repeat_y,
scale_x=scale_left or scale_right, scale_y=scale_top or scale_bottom)
def draw_border_image(box, stream):
"""Draw ``box`` border image on ``stream``."""
# See https://drafts.csswg.org/css-backgrounds-3/#border-images
image = box.border_image
draw_border_image_impl(
box, stream, image, box.style['border_image_slice'],
box.style['border_image_repeat'], box.style['border_image_outset'],
box.style['border_image_width'])
def maybe_set_mask_border(box, stream):
def set_mask_border(stream, box):
"""Set ``box`` mask border as alpha state on ``stream``."""
# See https://drafts.fxtf.org/css-masking/#the-mask-border
if (box.style['mask_border_source'][0] != 'none'
and box.mask_border_image is not None):
x, y, w, h, tl, tr, br, bl = box.rounded_border_box()
matrix = Matrix(e=x, f=y)
matrix @= stream.ctm
mask_stream = stream.set_alpha_state(
x, y, w, h, box.style['mask_border_mode'] != 'luminosity')
image = box.mask_border_image
draw_border_image_impl(
box, mask_stream, image, box.style['mask_border_slice'],
box.style['mask_border_repeat'], box.style['mask_border_outset'],
box.style['mask_border_width'])
if box.style['mask_border_source'][0] == 'none' or box.mask_border_image is None:
return
x, y, w, h, tl, tr, br, bl = box.rounded_border_box()
matrix = Matrix(e=x, f=y)
matrix @= stream.ctm
mask_stream = stream.set_alpha_state(x, y, w, h, box.style['mask_border_mode'])
draw_border_image(
box, mask_stream, box.mask_border_image, box.style['mask_border_slice'],
box.style['mask_border_repeat'], box.style['mask_border_outset'],
box.style['mask_border_width'])
def clip_border_segment(stream, style, width, side, border_box,
@ -1236,7 +1222,7 @@ def draw_inline_level(stream, page, box, offset_x=0, text_overflow='clip',
boxes.InlineBlockBox, boxes.InlineFlexBox, boxes.InlineGridBox))
draw_stacking_context(stream, stacking_context)
else:
maybe_set_mask_border(box, stream)
set_mask_border(stream, box)
draw_background(stream, box.background)
draw_border(stream, box)
if isinstance(box, (boxes.InlineBox, boxes.LineBox)):

View File

@ -112,13 +112,13 @@ class Stream(pydyf.Stream):
self._states[key] = pydyf.Dictionary({'ca': alpha})
super().set_state(key)
def set_alpha_state(self, x, y, width, height, is_alpha_based=False):
def set_alpha_state(self, x, y, width, height, mode='luminosity'):
alpha_stream = self.add_group(x, y, width, height)
alpha_state = pydyf.Dictionary({
'Type': '/ExtGState',
'SMask': pydyf.Dictionary({
'Type': '/Mask',
'S': '/Alpha' if is_alpha_based else '/Luminosity',
'S': f'/{mode.capitalize()}',
'G': alpha_stream,
}),
'ca': 1,