1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-05 00:21:15 +03:00
WeasyPrint/weasyprint/tests/test_draw.py
Simon Sapin 97f3eee889 Refactor text handling
* Kill the TextFragment class. Use a set of functions instead.
* Pass around an `enable_hinting` boolean rather than a dummy surface
2012-06-21 17:22:01 +02:00

1920 lines
67 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding: utf8
"""
weasyprint.tests.test_draw
--------------------------
Test the final, drawn results and compare PNG images pixel per pixel.
:copyright: Copyright 2011-2012 Simon Sapin and contributors, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import division, unicode_literals
import contextlib
import os.path
import tempfile
import shutil
import itertools
from io import BytesIO
import pystacia
from ..compat import xrange
from ..urls import ensure_url
from .testing_utils import (
resource_filename, TestPNGDocument, FONTS, assert_no_logs, capture_logs)
# Short variable names are OK here
# pylint: disable=C0103
_ = b'\xff\xff\xff\xff' # white
r = b'\xff\x00\x00\xff' # red
B = b'\x00\x00\xff\xff' # blue
BYTES_PER_PIXELS = 4
PIXEL_FORMAT = 'rgba(%i, %i, %i, %i)'
def format_pixel(pixels, width, x, y): # pragma: no cover
"""Return the pixel color as ``#RRGGBB``."""
start = (y * width + x) * BYTES_PER_PIXELS
end = start + BYTES_PER_PIXELS
pixel_bytes = pixels[start:end]
# Py2/3 compat:
pixel_ints = tuple(ord(byte) for byte in pixel_bytes.decode('latin1'))
return PIXEL_FORMAT % pixel_ints
def assert_pixels(name, expected_width, expected_height, expected_lines,
html, nb_pages=1):
"""Helper testing the size of the image and the pixels values."""
assert len(expected_lines) == expected_height
assert len(expected_lines[0]) == expected_width * BYTES_PER_PIXELS
expected_raw = b''.join(expected_lines)
_doc, lines = html_to_pixels(name, expected_width, expected_height,
html, nb_pages=nb_pages)
assert_pixels_equal(name, expected_width, expected_height, lines,
expected_raw)
def assert_same_rendering(expected_width, expected_height, documents):
"""
Render HTML documents to PNG and check that they render the same,
pixel-per-pixel.
Each document is passed as a (name, html_source) tuple.
"""
lines_list = []
for name, html in documents:
_doc, lines = html_to_pixels(
name, expected_width, expected_height, html)
lines_list.append((name, lines))
_name, reference = lines_list[0]
for name, lines in lines_list[1:]:
assert_pixels_equal(name, expected_width, expected_height,
reference, lines)
def assert_different_renderings(expected_width, expected_height, documents):
"""
Render HTML documents to PNG and check that no two documents render
the same.
Each document is passed as a (name, html_source) tuple.
"""
lines_list = []
for name, html in documents:
_doc, lines = html_to_pixels(
name, expected_width, expected_height, html)
lines_list.append((name, lines))
for i, (name_1, lines_1) in enumerate(lines_list):
for name_2, lines_2 in lines_list[i + 1:]:
if lines_1 == lines_2: # pragma: no cover
# Same as "assert lines_1 != lines_2" but the output of
# the assert hook would be gigantic and useless.
assert False, '%s and %s are the same' % (name_1, name_2)
def write_png(basename, lines, width, height): # pragma: no cover
"""Take a pixel matrix and write a PNG file."""
directory = os.path.join(os.path.dirname(__file__), 'test_results')
if not os.path.isdir(directory):
os.mkdir(directory)
filename = os.path.join(directory, basename + '.png')
with contextlib.closing(pystacia.read_raw(
lines, 'rgba', width, height, depth=8)) as image:
image.write(filename)
def html_to_pixels(name, expected_width, expected_height, html, nb_pages=1):
"""
Render an HTML document to PNG, checks its size and return pixel data.
Also return the document to aid debugging.
"""
document = TestPNGDocument(html,
# Dummy filename, but in the right directory.
base_url=resource_filename('<test>'))
lines = document_to_pixels(document, name, expected_width,
expected_height, nb_pages=nb_pages)
return document, lines
def document_to_pixels(document, name, expected_width, expected_height,
nb_pages=1):
"""
Render an HTML document to PNG, checks its size and return pixel data.
"""
file_like = BytesIO()
document.write_to(file_like)
assert len(document.pages) == nb_pages
with contextlib.closing(pystacia.read_blob(file_like.getvalue())) as image:
assert image.size == (expected_width, expected_height)
raw = image.get_raw('rgba')['raw']
assert len(raw) == expected_width * expected_height * BYTES_PER_PIXELS
return raw
def assert_pixels_equal(name, width, height, lines, expected_lines):
"""
Take 2 matrices of height by width pixels and assert that they
are the same.
"""
if lines != expected_lines: # pragma: no cover
write_png(name + '.expected', expected_lines, width, height)
write_png(name, lines, width, height)
for y in xrange(height):
for x in xrange(width):
pixel = format_pixel(lines, width, x, y)
expected_pixel = format_pixel(expected_lines, width, x, y)
assert pixel == expected_pixel , (
'Pixel (%i, %i) in %s: expected %s, got %s' % (
x, y, name, expected_pixel, pixel))
@assert_no_logs
def test_canvas_background():
"""Test the background applied on ``<html>`` and/or ``<body>`` tags."""
assert_pixels('all_blue', 10, 10, (10 * [10 * B]), '''
<style>
@page { -weasy-size: 10px }
/* bodys background propagates to the whole canvas */
body { margin: 2px; background: #00f; height: 5px }
</style>
<body>
''')
assert_pixels('blocks', 10, 10, [
r+r+r+r+r+r+r+r+r+r,
r+r+r+r+r+r+r+r+r+r,
r+r+B+B+B+B+B+B+r+r,
r+r+B+B+B+B+B+B+r+r,
r+r+B+B+B+B+B+B+r+r,
r+r+B+B+B+B+B+B+r+r,
r+r+B+B+B+B+B+B+r+r,
r+r+r+r+r+r+r+r+r+r,
r+r+r+r+r+r+r+r+r+r,
r+r+r+r+r+r+r+r+r+r,
], '''
<style>
@page { -weasy-size: 10px }
/* htmls background propagates to the whole canvas */
html { padding: 1px; background: #f00 }
/* html has a background, so bodys does not propagate */
body { margin: 1px; background: #00f; height: 5px }
</style>
<body>
''')
@assert_no_logs
def test_background_image():
"""Test background images."""
# pattern.png looks like this:
# r+B+B+B,
# B+B+B+B,
# B+B+B+B,
# B+B+B+B,
for name, css, pixels in [
('repeat', '', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+r+B+B+B+r+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+r+B+B+B+r+B+B+B+r+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+r+B+B+B+r+B+B+B+r+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('repeat_x', 'repeat-x', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+r+B+B+B+r+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('repeat_y', 'repeat-y', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('left_top', 'no-repeat 0 0%', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('center_top', 'no-repeat 50% 0px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('right_top', 'no-repeat 6px top', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+r+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('left_center', 'no-repeat left center', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('center_left', 'no-repeat center left', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('center_center', 'no-repeat 3px 3px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('right_center', 'no-repeat 100% 50%', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+r+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('left_bottom', 'no-repeat 0% bottom', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('center_bottom', 'no-repeat center 6px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('bottom_center', 'no-repeat bottom center', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('right_bottom', 'no-repeat 6px 100%', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+r+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('repeat_x_1px_2px', 'repeat-x 1px 2px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+B+r+B+B+B+r+B+B+B+r+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+B+B+B+B+B+B+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('repeat_y_2px_1px', 'repeat-y 2px 1px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+r+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+r+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+r+B+B+B+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('fixed', 'no-repeat fixed', [
# The image is actually here:
#######
_+_+_+_+_+_+_+_+_+_+_+_+_+_, #
_+_+_+_+_+_+_+_+_+_+_+_+_+_, #
_+_+B+B+_+_+_+_+_+_+_+_+_+_, #
_+_+B+B+_+_+_+_+_+_+_+_+_+_, #
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('fixed_right', 'no-repeat fixed right 3px', [
#######
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+r+B+_+_, #
_+_+_+_+_+_+_+_+_+_+B+B+_+_, #
_+_+_+_+_+_+_+_+_+_+B+B+_+_, #
_+_+_+_+_+_+_+_+_+_+B+B+_+_, #
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
('fixed_center_center', 'no-repeat fixed 50% center', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
]),
]:
assert_pixels('background_' + name, 14, 16, pixels, '''
<style>
@page { -weasy-size: 14px 16px }
html { background: #fff }
body { margin: 2px; height: 10px;
background: url(pattern.png) %s }
p { background: none }
</style>
<body>
<p>&nbsp;
''' % (css,))
@assert_no_logs
def test_background_origin():
"""Test the background-origin property."""
def test_value(value, pixels, css=None):
assert_pixels('background_origin_' + value, 12, 12, pixels, '''
<style>
@page { -weasy-size: 12px }
html { background: #fff }
body { margin: 1px; padding: 1px; height: 6px;
border: 1px solid transparent;
background: url(pattern.png) bottom right no-repeat;
background-origin: %s }
</style>
<body>
''' % (css or value,))
test_value('border-box', [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+r+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_,
])
test_value('padding-box', [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+r+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
])
test_value('content-box', [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B+B+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_,
_+_+_+_+_+B+B+B+B+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
])
test_value('border-box_clip', [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+r+B+_+_+_,
_+_+_+_+_+_+_+B+B+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], css='border-box; background-clip: content-box')
@assert_no_logs
def test_background_clip():
"""Test the background-clip property."""
def test_value(value, pixels):
assert_pixels('background_clip_' + value, 8, 8, pixels, '''
<style>
@page { -weasy-size: 8px }
html { background: #fff }
body { margin: 1px; padding: 1px; height: 2px;
border: 1px solid transparent;
background: #00f; background-clip : %s }
</style>
<body>
''' % (value,))
test_value('border-box', [
_+_+_+_+_+_+_+_,
_+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_,
])
test_value('padding-box', [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
])
test_value('content-box', [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+B+B+_+_+_,
_+_+_+B+B+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
])
@assert_no_logs
def test_background_size():
"""Test the background-size property."""
assert_pixels('background_size', 12, 12, [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+r+r+B+B+B+B+B+B+_,
_+_+_+r+r+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 12px }
html { background: #fff }
body { margin: 1px; height: 10px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) bottom right no-repeat;
background-size: 8px }
</style>
<body>
''')
assert_pixels('background_size_auto', 12, 12, [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+r+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 12px }
html { background: #fff }
body { margin: 1px; height: 10px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) bottom right no-repeat;
background-size: auto }
</style>
<body>
''')
assert_pixels('background_size_contain', 14, 10, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 14px 10px }
html { background: #fff }
body { margin: 1px; height: 8px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) no-repeat;
background-size: contain }
</style>
<body>
''')
assert_pixels('background_size_mixed', 14, 10, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 14px 10px }
html { background: #fff }
body { margin: 1px; height: 8px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) no-repeat;
background-size: auto 8px;
clip: auto; /* no-op to cover more validation */ }
</style>
<body>
''')
assert_pixels('background_size_double', 14, 10, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 14px 10px }
html { background: #fff }
body { margin: 1px; height: 8px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) no-repeat;
background-size: 8px 4px;
clip: auto; /* no-op to cover more validation */ }
</style>
<body>
''')
assert_pixels('background_size_cover', 14, 10, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+r+r+r+B+B+B+B+B+B+B+B+B+_,
_+r+r+r+B+B+B+B+B+B+B+B+B+_,
_+r+r+r+B+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 14px 10px }
html { background: #fff }
body { margin: 1px; height: 8px;
/* Use nearest neighbor algorithm for image resizing: */
-weasy-image-rendering: optimizeSpeed;
background: url(pattern.png) no-repeat;
background-size: cover }
</style>
<body>
''')
@assert_no_logs
def test_list_style_image():
"""Test images as list markers."""
for position, pixels in [
('outside', [
# ++++++++++++++ ++++ <li> horizontal margins: 7px 2px
# ###### <li> width: 12 - 7 - 2 = 3px
# -- list marker margin: 0.5em = 2px
# ******** list marker image is 4px wide
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_,
_+_+B+B+B+B+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
]),
('inside', [
# ++++++++++++++ ++++ <li> horizontal margins: 7px 2px
# ###### <li> width: 12 - 7 - 2 = 3px
# ******** list marker image is 4px wide: overflow
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+r+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
])
]:
assert_pixels('list_style_image_' + position, 12, 10, pixels, '''
<style>
@page { -weasy-size: 12px 10px }
body { margin: 0; background: white; font-family: %s }
ul { margin: 2px 2px 0 7px; list-style: url(pattern.png) %s;
font-size: 2px }
</style>
<ul><li></li></ul>
''' % (FONTS, position))
assert_pixels('list_style_none', 10, 10, [
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 10px }
body { margin: 0; background: white; font-family: %s }
ul { margin: 0 0 0 5px; list-style: none; font-size: 2px; }
</style>
<ul><li>
''' % (FONTS,))
@assert_no_logs
def test_images():
"""Test images sizes, positions and pixels."""
centered_image = [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
]
# JPG is lossy...
b = b'\x00\x00\xfe\xff'
blue_image = [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+b+b+b+b+_+_,
_+_+b+b+b+b+_+_,
_+_+b+b+b+b+_+_,
_+_+b+b+b+b+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
]
no_image = [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
]
for filename, image in [
('pattern.svg', centered_image),
('pattern.png', centered_image),
('pattern.palette.png', centered_image),
('pattern.gif', centered_image),
('blue.jpg', blue_image)]:
assert_pixels('inline_image_' + filename, 8, 8, image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px 0 0 2px; background: #fff; font-size: 0 }
</style>
<div><img src="%s"></div>
''' % filename)
assert_pixels('block_image', 8, 8, centered_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 0; background: #fff; font-size: 0 }
img { display: block; margin: 2px auto 0 }
</style>
<div><img src="pattern.png"></div>
''')
with capture_logs() as logs:
assert_pixels('image_not_found', 8, 8, no_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 0; background: #fff; font-size: 0 }
img { display: block; margin: 2px auto 0 }
</style>
<div><img src="inexistent1.png" alt=""></div>
''')
assert len(logs) == 1
assert 'WARNING: Error for image' in logs[0]
assert 'inexistent1.png' in logs[0]
assert_pixels('image_no_src', 8, 8, no_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 0; background: #fff; font-size: 0 }
img { display: block; margin: 2px auto 0 }
</style>
<div><img alt=""></div>
''')
with capture_logs() as logs:
assert_same_rendering(200, 30, [
(name, '''
<style>
@page { -weasy-size: 200px 30px }
body { margin: 0; background: #fff; font-size: 0 }
</style>
<div>%s</div>
''' % html)
for name, html in [
('image_alt_text_reference', 'Hello, world!'),
('image_alt_text_not_found',
'<img src="inexistent2.png" alt="Hello, world!">'),
('image_alt_text_no_src',
'<img alt="Hello, world!">'),
('image_svg_no_intrinsic_size',
'''<img src="data:image/svg+xml,<svg></svg>"
alt="Hello, world!">'''),
]
])
assert len(logs) == 2
assert 'WARNING: Error for image' in logs[0]
assert 'inexistent2.png' in logs[0]
assert 'WARNING: Error for image at data:image/svg+xml' in logs[1]
assert 'intrinsic size' in logs[1]
assert_pixels('image_0x1', 8, 8, no_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px; background: #fff; font-size: 0 }
</style>
<div><img src="pattern.png" alt="not shown"
style="width: 0; height: 1px"></div>
''')
assert_pixels('image_1x0', 8, 8, no_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px; background: #fff; font-size: 0 }
</style>
<div><img src="pattern.png" alt="not shown"
style="width: 1px; height: 0"></div>
''')
assert_pixels('image_0x0', 8, 8, no_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px; background: #fff; font-size: 0 }
</style>
<div><img src="pattern.png" alt="not shown"
style="width: 0; height: 0"></div>
''')
page_break = [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
]
assert_pixels('image_page_break', 8, 3 * 8, page_break, '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff }
body { font-size: 0 }
</style>
<div><img src="pattern.png"></div>
<div style="page-break-before: right"><img src="pattern.png"></div>
''', nb_pages=3)
# Regression test: padding used to be ignored on images
assert_pixels('image_with_padding', 8, 8, centered_image, '''
<style>
@page { -weasy-size: 8px; background: #fff }
body { font-size: 0 }
</style>
<div style="line-height: 1px">
<img src=pattern.png style="padding: 2px 0 0 2px">
</div>
''')
# Regression test: this used to cause an exception
assert_pixels('image_in_inline_block', 8, 8, centered_image, '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px 0 0 2px; background: #fff; font-size: 0 }
</style>
<div style="display: inline-block">
<p><img src=pattern.png></p>
</div>
''')
@assert_no_logs
def test_visibility():
source = '''
<style>
@page { -weasy-size: 12px 7px }
body { background: #fff; font: 1px/1 serif }
img { margin: 1px 0 0 1px; }
%(extra_css)s
</style>
<div>
<img src="pattern.png">
<span><img src="pattern.png"></span>
</div>
'''
assert_pixels('visibility_reference', 12, 7, [
_+_+_+_+_+_+_+_+_+_+_+_,
_+r+B+B+B+_+r+B+B+B+_+_,
_+B+B+B+B+_+B+B+B+B+_+_,
_+B+B+B+B+_+B+B+B+B+_+_,
_+B+B+B+B+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': ''})
assert_pixels('visibility_hidden', 12, 7, [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': 'div { visibility: hidden }'})
assert_pixels('visibility_mixed', 12, 7, [
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+r+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': '''div { visibility: hidden }
span { visibility: visible } '''})
@assert_no_logs
def test_tables():
source = '''
<style>
@page { -weasy-size: 28px }
html { background: #fff; }
table { margin: 1px; padding: 1px; border-spacing: 1px;
border: 1px solid transparent }
td { width: 2px; height: 2px; padding: 1px;
border: 1px solid transparent }
%(extra_css)s
</style>
<table>
<colgroup>
<col>
<col>
</colgroup>
<col>
<thead>
<tr>
<td></td>
<td rowspan=2></td>
<td></td>
</tr>
<tr>
<td colspan=2></td>
<td></td>
</tr>
</thead>
<tr>
<td></td>
<td></td>
</tr>
</table>
'''
r = b'\xff\x7f\x7f\xff' # rgba(255, 0, 0, 0.5) above #fff
R = b'\xff\x3f\x3f\xff' # r above r above #fff
assert_pixels('table_borders', 28, 28, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+_+_+_+_+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+r+_+_+_+_+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+r+r+r+r+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+_+_+r+_+_+_+_+R+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+_+_+r+_+_+_+_+R+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+_+_+r+_+_+_+_+R+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+_+_+_+_+_+_+r+_+_+_+_+R+_+r+_+_+_+_+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+_+_+_+_+r+_+r+_+_+_+_+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': '''
table { border-color: #00f; table-layout: fixed }
td { border-color: rgba(255, 0, 0, 0.5) }
'''})
assert_pixels('table_td_backgrounds', 28, 28, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+R+R+R+R+R+R+_+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+_+r+r+r+r+r+r+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': '''
table { border-color: #00f; table-layout: fixed }
td { background: rgba(255, 0, 0, 0.5) }
'''})
g = b'\x7f\xff\x7f\xff' # rgba(0, 255, 0, 0.5) above #fff
G = b'\x7f\xbf\x3f\xff' # g above r above #fff
# Not the same as r above g above #fff
assert_pixels('table_column_backgrounds', 28, 28, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+r+G+G+G+G+G+G+_+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': '''
table { border-color: #00f; table-layout: fixed }
colgroup { background: rgba(255, 0, 0, 0.5) }
col { background: rgba(0, 255, 0, 0.5) }
'''})
assert_pixels('table_row_backgrounds', 28, 28, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+r+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+G+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+g+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+B+_,
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], source % {'extra_css': '''
table { border-color: #00f; table-layout: fixed }
thead { background: rgba(255, 0, 0, 0.5) }
tr { background: rgba(0, 255, 0, 0.5) }
'''})
@assert_no_logs
def test_before_after():
assert_same_rendering(300, 30, [
('pseudo_before', '''
<style>
@page { -weasy-size: 300px 30px }
body { margin: 0; background: #fff }
a[href]:before { content: '[' '' attr(href) '] ' }
</style>
<p><a href="some url">some content</p>
'''),
('pseudo_before_reference', '''
<style>
@page { -weasy-size: 300px 30px }
body { margin: 0; background: #fff }
</style>
<p><a href="another url">[some url] some content</p>
''')
])
assert_same_rendering(500, 30, [
('pseudo_quotes', '''
<style>
@page { -weasy-size: 500px 30px }
body { margin: 0; background: #fff; quotes: '«' '»' '' '' }
q:before { content: open-quote ' '}
q:after { content: ' ' close-quote }
</style>
<p><q>Lorem ipsum <q>dolor</q> sit amet</q></p>
'''),
('pseudo_quotes_reference', '''
<style>
@page { -weasy-size: 500px 30px }
body { margin: 0; background: #fff }
</style>
<p>« Lorem ipsum “ dolor ” sit amet »</p>
''')
])
assert_same_rendering(100, 30, [
('pseudo_url', '''
<style>
@page { -weasy-size: 100px 30px }
body { margin: 0; background: #fff; }
p:before { content: 'a' url(pattern.png) 'b'}
</style>
<p>c</p>
'''),
('pseudo_url_reference', '''
<style>
@page { -weasy-size: 100px 30px }
body { margin: 0; background: #fff }
</style>
<p>a<img src="pattern.png" alt="Missing image">bc</p>
''')
])
@assert_no_logs
def test_borders():
"""Test the rendering of borders"""
source = '''
<style>
@page { -weasy-size: 140px 110px }
html { background: #fff }
body { margin: 10px; width: 100px; height: 70px;
border: 10px %(border_style)s blue }
</style>
<body>
'''
# Do not test the exact rendering of earch border style but at least
# check that they do not do the same.
assert_different_renderings(140, 110, [
('border_' + border_style, source % {'border_style': border_style})
for border_style in [
'none', 'solid', 'dashed', 'dotted', 'double',
'inset', 'outset', 'groove', 'ridge',
]
])
width = 140
height = 110
margin = 10
border = 10
solid_pixels = [[_] * width for y in xrange(height)]
for x in xrange(margin, width - margin):
for y in itertools.chain(
range(margin, margin + border),
range(height - margin - border, height - margin)):
solid_pixels[y][x] = B
for y in xrange(margin, height - margin):
for x in itertools.chain(
range(margin, margin + border),
range(width - margin - border, width - margin)):
solid_pixels[y][x] = B
solid_pixels = [b''.join(line) for line in solid_pixels]
assert_pixels(
'border_solid', 140, 110, solid_pixels,
source % {'border_style': 'solid'}
)
@assert_no_logs
def test_margin_boxes():
"""Test the rendering of margin boxes"""
_ = b'\xff\xff\xff\xff' # white
R = b'\xff\x00\x00\xff' # red
G = b'\x00\xff\x00\xff' # green
B = b'\x00\x00\xff\xff' # blue
g = b'\x00\x80\x00\xff' # half green
b = b'\x00\x00\x80\xff' # half blue
assert_pixels('margin_boxes', 15, 15, [
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+G+G+G+_+_+_+_+_+_+B+B+B+B+_,
_+G+G+G+_+_+_+_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+R+R+R+R+_+_+_+_+_+_,
_+_+_+_+_+R+R+R+R+_+_+_+_+_+_,
_+_+_+_+_+R+R+R+R+_+_+_+_+_+_,
_+_+_+_+_+R+R+R+R+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+b+b+b+_+_+_+_+_+_+g+g+g+g+_,
_+b+b+b+_+_+_+_+_+_+g+g+g+g+_,
_+b+b+b+_+_+_+_+_+_+g+g+g+g+_,
_+b+b+b+_+_+_+_+_+_+g+g+g+g+_,
_+b+b+b+_+_+_+_+_+_+g+g+g+g+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
], '''
<style>
html { height: 100% }
body { background: #f00; height: 100% }
@page {
-weasy-size: 15px;
margin: 4px 6px 7px 5px;
background: white;
@top-left-corner {
margin: 1px;
content: " ";
background: #0f0;
}
@top-right-corner {
margin: 1px;
content: " ";
background: #00f;
}
@bottom-right-corner {
margin: 1px;
content: " ";
background: #008000;
}
@bottom-left-corner {
margin: 1px;
content: " ";
background: #000080;
}
}
</style>
<body>
''')
@assert_no_logs
def test_unicode():
"""Test non-ASCII filenames (URLs)"""
text = 'I løvë Unicode'
style = '''
@page {
-weasy-size: 200px 50px;
}
p { color: blue }
'''
_doc, expected_lines = html_to_pixels('unicode_reference', 200, 50, '''
<style>{0}</style>
<p><img src="pattern.png"> {1}</p>
'''.format(style, text))
temp = tempfile.mkdtemp(prefix=text + '-')
try:
stylesheet = os.path.join(temp, 'style.css')
image = os.path.join(temp, 'pattern.png')
html = os.path.join(temp, 'doc.html')
with open(stylesheet, 'wb') as fd:
fd.write(style.encode('utf8'))
with open(resource_filename('pattern.png'), 'rb') as fd:
image_content = fd.read()
with open(image, 'wb') as fd:
fd.write(image_content)
with open(html, 'wb') as fd:
html_content = '''
<link rel=stylesheet href="{0}">
<p><img src="{1}"> {2}</p>
'''.format(
ensure_url(stylesheet), ensure_url(image), text
)
fd.write(html_content.encode('utf8'))
# TODO: change this back to actually read from a file
document = TestPNGDocument(html_content)
lines = document_to_pixels(document, 'unicode', 200, 50)
assert_pixels_equal('unicode', 200, 50, lines, expected_lines)
finally:
shutil.rmtree(temp)
@assert_no_logs
def test_overflow():
"""Test the overflow property."""
# See test_images
assert_pixels('inline_image_overflow', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px }
body { margin: 2px 0 0 2px; background: #fff; font-size:0 }
div { height: 2px; overflow: hidden }
</style>
<div><img src="pattern.png"></div>
''')
# <body> is only 1px high, but its overflow is propageted to the viewport
# ie. the padding edge of the page box.
assert_pixels('inline_image_viewport_overflow', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; background: #fff;
margin: 2px;
padding-bottom: 2px;
border-bottom: 1px transparent solid; }
body { height: 1px; overflow: hidden; font-size:0 }
</style>
<div><img src="pattern.png"></div>
''')
@assert_no_logs
def test_clip():
"""Test the clip property."""
num = [0]
def clip(css, pixels):
num[0] += 1
name = 'background_repeat_clipped_%s' % num[0]
assert_pixels(name, 14, 16, pixels, '''
<style>
@page { -weasy-size: 14px 16px; background: #fff }
div { margin: 1px; height: 10px;
border: 1px green solid;
background: url(pattern.png);
clip: rect(%s); }
</style>
<div>
''' % (css,))
print('test_draw.test_clip() is known to fail with cairo 1.10, '
'try with 1.12.')
g = b'\x00\x80\x00\xff' # green
clip('5px, 5px, 9px, auto', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+r+B+B+B+r+B+g+_,
_+_+_+_+_+_+B+B+B+B+B+B+g+_,
_+_+_+_+_+_+B+B+B+B+B+B+g+_,
_+_+_+_+_+_+B+B+B+B+B+B+g+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
])
clip('5px, 5px, auto, 10px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+r+B+B+B+r+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+r+B+B+B+r+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+g+g+g+g+g+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
])
clip('5px, auto, 9px, 10px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+g+r+B+B+B+r+B+B+B+r+_+_+_,
_+g+B+B+B+B+B+B+B+B+B+_+_+_,
_+g+B+B+B+B+B+B+B+B+B+_+_+_,
_+g+B+B+B+B+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
])
clip('auto, 5px, 9px, 10px', [
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+g+g+g+g+g+_+_+_,
_+_+_+_+_+_+r+B+B+B+r+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+r+B+B+B+r+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+B+B+B+B+B+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_+_+_+_+_,
])
@assert_no_logs
def test_opacity():
"""Test the opacity property."""
template = '''
<style>
@page { -weasy-size: 200px 60px }
body { margin: 0; background: #fff }
</style>
%s
'''
assert_same_rendering(200, 60, [
('opacity_0_reference', template % '''
<div>Hello, world!</div>
<div style="opacity: 0">Lorem ipsum</div>
'''),
('opacity_0', template % '''
<div>Hello, world!</div>
'''),
])
assert_same_rendering(200, 60, [
('opacity_color_reference', template % '''
<div style="color: rgb(102, 102, 102)">Hello, world!</div>
'''),
('opacity_color', template % '''
<div style="color: black; opacity: 0.6">Hello, world!</div>
'''),
])
assert_same_rendering(200, 60, [
('opacity_multiplied_reference', template % '''
<div style="color: transparent;
background: rgb(102, 102, 102)">Hello, world!</div>
'''),
('opacity_multiplied', template % '''
<div style="color: transparent;
background: black; opacity: 0.6">Hello, world!</div>
'''),
('opacity_multiplied_2', template % '''
<div style="opacity: 0.666666">
<div style="color: transparent;
background: black; opacity: 0.9">Hello, world!</div>
'''), # 0.9 * 0.666666 == 0.6
])
@assert_no_logs
def test_2d_transform():
"""Test 2D transformations."""
assert_pixels('image_rotate90', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+B+B+B+r+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: rotate(90deg); font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_reflection', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+B+B+B+r+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: matrix(-1, 0, 0, 1, 0, 0); font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_translate', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+r+B+B+B+_,
_+_+_+B+B+B+B+_,
_+_+_+B+B+B+B+_,
_+_+_+B+B+B+B+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: translate(1px, 2px); font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_translate_percentage', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+r+B+B+B+_,
_+_+_+B+B+B+B+_,
_+_+_+B+B+B+B+_,
_+_+_+B+B+B+B+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: translate(25%, 0); font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_translateX', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+r+B+B,
_+_+_+_+_+B+B+B,
_+_+_+_+_+B+B+B,
_+_+_+_+_+B+B+B,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: translateX(0.25em); font-size: 12px }
div div { font-size: 0 }
</style>
<div><div><img src="pattern.png"></div></div>
''')
assert_pixels('image_translateY', 8, 8, [
_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+B+B+B+B+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 8px; margin: 2px; background: #fff; }
div { -weasy-transform: translateY(-1px); font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_scale', 10, 10, [
_+_+_+_+_+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_,
_+r+r+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 10px; margin: 2px; background: #fff; }
div { -weasy-transform: scale(2, 2);
-weasy-transform-origin: 1px 1px;
-weasy-image-rendering: optimizeSpeed;
font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_scale12', 10, 10, [
_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_,
_+_+r+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 10px; margin: 2px; background: #fff; }
div { -weasy-transform: scale(1, 2);
-weasy-transform-origin: 1px 1px;
-weasy-image-rendering: optimizeSpeed;
font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_scaleY', 10, 10, [
_+_+_+_+_+_+_+_+_+_,
_+_+r+B+B+B+_+_+_+_,
_+_+r+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+B+B+B+B+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 10px; margin: 2px; background: #fff; }
div { -weasy-transform: scaleY(2);
-weasy-transform-origin: 1px 1px;
-weasy-image-rendering: optimizeSpeed;
font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')
assert_pixels('image_scaleX', 10, 10, [
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+r+r+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+B+B+B+B+B+B+B+B+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
_+_+_+_+_+_+_+_+_+_,
], '''
<style>
@page { -weasy-size: 10px; margin: 2px; background: #fff; }
div { -weasy-transform: scaleX(2);
-weasy-transform-origin: 1px 1px;
-weasy-image-rendering: optimizeSpeed;
font-size: 0 }
</style>
<div><img src="pattern.png"></div>
''')