mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-09-11 20:47:56 +03:00
Handle the appearance property
This commit is contained in:
parent
b2e4ea0f4d
commit
ec1424d979
@ -743,3 +743,22 @@ All the ``flex-*``, ``align-*``, ``justify-*`` and ``order`` properties are
|
||||
supported. The ``flex`` and ``flex-flow`` shorthands are supported too.
|
||||
|
||||
.. _CSS Flexible Box Layout Module Level 1: https://www.w3.org/TR/css-flexbox-1/
|
||||
|
||||
CSS Basic User Interface Module Level 3/4
|
||||
+++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The `CSS Basic User Interface Module Level 3/4`_ "enables authors to style user
|
||||
interface related properties and values."
|
||||
|
||||
The ``outline-width``, ``outline-style``, ``outline-color`` properties and the
|
||||
``outline`` shorthand are supported. The ``outline-offset`` property is **not**
|
||||
supported.
|
||||
|
||||
The ``resize``, ``cursor``, ``caret-*`` and ``nav-*`` properties are **not**
|
||||
supported.
|
||||
|
||||
The ``appearance`` property is supported. When set to ``auto``, it displays
|
||||
form fields as PDF form fields (supported for text inputs, check boxes and
|
||||
text areas only).
|
||||
|
||||
The ``accent-color`` property is **not** supported.
|
||||
|
@ -106,7 +106,9 @@ class HTML:
|
||||
result, content_language=None)
|
||||
self.etree_element = self.wrapper_element.etree_element
|
||||
|
||||
def _ua_stylesheets(self):
|
||||
def _ua_stylesheets(self, forms=False):
|
||||
if forms:
|
||||
return [HTML5_UA_STYLESHEET, HTML5_UA_FORM_STYLESHEET]
|
||||
return [HTML5_UA_STYLESHEET]
|
||||
|
||||
def _ua_counter_style(self):
|
||||
@ -117,7 +119,7 @@ class HTML:
|
||||
|
||||
def render(self, stylesheets=None, presentational_hints=False,
|
||||
optimize_size=('fonts',), font_config=None, counter_style=None,
|
||||
image_cache=None):
|
||||
image_cache=None, forms=False):
|
||||
"""Lay out and paginate the document, but do not (yet) export it.
|
||||
|
||||
This returns a :class:`document.Document` object which provides
|
||||
@ -137,12 +139,13 @@ class HTML:
|
||||
:type counter_style: :class:`css.counters.CounterStyle`
|
||||
:param counter_style: A dictionary storing ``@counter-style`` rules.
|
||||
:param dict image_cache: A dictionary used to cache images.
|
||||
:param bool forms: Whether PDF forms have to be included.
|
||||
:returns: A :class:`document.Document` object.
|
||||
|
||||
"""
|
||||
return Document._render(
|
||||
self, stylesheets, presentational_hints,
|
||||
optimize_size, font_config, counter_style, image_cache)
|
||||
self, stylesheets, presentational_hints, optimize_size,
|
||||
font_config, counter_style, image_cache, forms)
|
||||
|
||||
def write_pdf(self, target=None, stylesheets=None, zoom=1,
|
||||
attachments=None, finisher=None, presentational_hints=False,
|
||||
@ -187,7 +190,7 @@ class HTML:
|
||||
:param bytes identifier: A bytestring used as PDF file identifier.
|
||||
:param str variant: A PDF variant name.
|
||||
:param str version: A PDF version number.
|
||||
:param bool version: Whether PDF forms have to be included.
|
||||
:param bool forms: Whether PDF forms have to be included.
|
||||
:param bool custom_metadata: Whether custom HTML metadata should be
|
||||
stored in the generated PDF.
|
||||
:returns:
|
||||
@ -199,10 +202,10 @@ class HTML:
|
||||
return (
|
||||
self.render(
|
||||
stylesheets, presentational_hints, optimize_size, font_config,
|
||||
counter_style, image_cache)
|
||||
counter_style, image_cache, forms)
|
||||
.write_pdf(
|
||||
target, zoom, attachments, finisher, identifier, variant,
|
||||
version, custom_metadata, forms))
|
||||
version, custom_metadata))
|
||||
|
||||
|
||||
class CSS:
|
||||
@ -337,5 +340,6 @@ def _select_source(guess=None, filename=None, url=None, file_obj=None,
|
||||
# Work around circular imports.
|
||||
from .css import preprocess_stylesheet # noqa isort:skip
|
||||
from .html import ( # noqa isort:skip
|
||||
HTML5_UA_COUNTER_STYLE, HTML5_UA_STYLESHEET, HTML5_PH_STYLESHEET)
|
||||
HTML5_UA_COUNTER_STYLE, HTML5_UA_STYLESHEET, HTML5_UA_FORM_STYLESHEET,
|
||||
HTML5_PH_STYLESHEET)
|
||||
from .document import Document, Page # noqa isort:skip
|
||||
|
@ -1096,7 +1096,7 @@ def preprocess_stylesheet(device_media_type, base_url, stylesheet_rules,
|
||||
def get_all_computed_styles(html, user_stylesheets=None,
|
||||
presentational_hints=False, font_config=None,
|
||||
counter_style=None, page_rules=None,
|
||||
target_collector=None):
|
||||
target_collector=None, forms=False):
|
||||
"""Compute all the computed styles of all elements in ``html`` document.
|
||||
|
||||
Do everything from finding author stylesheets to parsing and applying them.
|
||||
@ -1112,7 +1112,7 @@ def get_all_computed_styles(html, user_stylesheets=None,
|
||||
for style in html._ua_counter_style():
|
||||
for key, value in style.items():
|
||||
counter_style[key] = value
|
||||
for sheet in (html._ua_stylesheets() or []):
|
||||
for sheet in (html._ua_stylesheets(forms) or []):
|
||||
sheets.append((sheet, 'user agent', None))
|
||||
if presentational_hints:
|
||||
for sheet in (html._ph_stylesheets() or []):
|
||||
|
5
weasyprint/css/html5_ua_form.css
Normal file
5
weasyprint/css/html5_ua_form.css
Normal file
@ -0,0 +1,5 @@
|
||||
/* Default stylesheet for PDF forms */
|
||||
|
||||
button, input, select, textarea {
|
||||
appearance: auto;
|
||||
}
|
@ -19,15 +19,12 @@ INITIAL_VALUES = {
|
||||
'display': ('inline', 'flow'),
|
||||
'empty_cells': 'show',
|
||||
'float': 'none',
|
||||
'height': 'auto',
|
||||
'left': 'auto',
|
||||
'line_height': 'normal',
|
||||
'margin_top': Dimension(0, 'px'),
|
||||
'margin_right': Dimension(0, 'px'),
|
||||
'margin_bottom': Dimension(0, 'px'),
|
||||
'margin_left': Dimension(0, 'px'),
|
||||
'max_height': Dimension(inf, 'px'), # parsed value for 'none'
|
||||
'max_width': Dimension(inf, 'px'),
|
||||
'padding_top': Dimension(0, 'px'),
|
||||
'padding_right': Dimension(0, 'px'),
|
||||
'padding_bottom': Dimension(0, 'px'),
|
||||
@ -39,7 +36,6 @@ INITIAL_VALUES = {
|
||||
'unicode_bidi': 'normal',
|
||||
'vertical_align': 'baseline',
|
||||
'visibility': 'visible',
|
||||
'width': 'auto',
|
||||
'z_index': 'auto',
|
||||
|
||||
# Backgrounds and Borders 3 (CR): https://www.w3.org/TR/css-backgrounds-3/
|
||||
@ -159,12 +155,20 @@ INITIAL_VALUES = {
|
||||
'transform_origin': (Dimension(50, '%'), Dimension(50, '%')),
|
||||
'transform': (), # computed value for 'none'
|
||||
|
||||
# User Interface 3 (REC): https://www.w3.org/TR/css-ui-3/
|
||||
'box_sizing': 'content-box',
|
||||
# User Interface 3/4 (REC/WD): https://www.w3.org/TR/css-ui-4/
|
||||
'appearance': 'none',
|
||||
'outline_color': 'currentColor', # invert is not supported
|
||||
'outline_style': 'none',
|
||||
'outline_width': 3, # computed value for 'medium'
|
||||
'overflow_wrap': 'normal',
|
||||
|
||||
# Sizing 3 (WD): https://www.w3.org/TR/css-sizing-3/
|
||||
'box_sizing': 'content-box',
|
||||
'height': 'auto',
|
||||
'max_height': Dimension(inf, 'px'), # parsed value for 'none'
|
||||
'max_width': Dimension(inf, 'px'),
|
||||
'min_height': 'auto',
|
||||
'min_width': 'auto',
|
||||
'width': 'auto',
|
||||
|
||||
# Flexible Box Layout Module 1 (CR): https://www.w3.org/TR/css-flexbox-1/
|
||||
'align_content': 'stretch',
|
||||
@ -176,8 +180,6 @@ INITIAL_VALUES = {
|
||||
'flex_shrink': 1,
|
||||
'flex_wrap': 'nowrap',
|
||||
'justify_content': 'flex-start',
|
||||
'min_height': 'auto',
|
||||
'min_width': 'auto',
|
||||
'order': 0,
|
||||
|
||||
# Text Decoration Module 3 (CR): https://www.w3.org/TR/css-text-decor-3/
|
||||
@ -185,11 +187,12 @@ INITIAL_VALUES = {
|
||||
'text_decoration_color': 'currentColor',
|
||||
'text_decoration_style': 'solid',
|
||||
|
||||
# Overflow Module 3 (WD): https://www.w3.org/TR/css-overflow-3/
|
||||
# Overflow Module 3/4 (WD): https://www.w3.org/TR/css-overflow-4/
|
||||
'block_ellipsis': 'none',
|
||||
'continue': 'auto',
|
||||
'max_lines': 'none',
|
||||
'overflow': 'visible',
|
||||
'overflow_wrap': 'normal',
|
||||
'text_overflow': 'clip',
|
||||
|
||||
# Lists Module 3 (WD): https://drafts.csswg.org/css-lists-3/
|
||||
|
@ -1592,3 +1592,12 @@ def transform(tokens):
|
||||
else:
|
||||
return
|
||||
return tuple(transforms)
|
||||
|
||||
|
||||
@property()
|
||||
@single_token
|
||||
def appearance(token):
|
||||
"""``appearance`` property validation."""
|
||||
keyword = get_keyword(token)
|
||||
if keyword in ('none', 'auto'):
|
||||
return keyword
|
||||
|
@ -171,10 +171,9 @@ class Document:
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _build_layout_context(cls, html, stylesheets,
|
||||
presentational_hints=False,
|
||||
optimize_size=('fonts',), font_config=None,
|
||||
counter_style=None, image_cache=None):
|
||||
def _build_layout_context(cls, html, stylesheets, presentational_hints,
|
||||
optimize_size, font_config, counter_style,
|
||||
image_cache, forms):
|
||||
if font_config is None:
|
||||
font_config = FontConfiguration()
|
||||
if counter_style is None:
|
||||
@ -191,7 +190,7 @@ class Document:
|
||||
user_stylesheets.append(css)
|
||||
style_for = get_all_computed_styles(
|
||||
html, user_stylesheets, presentational_hints, font_config,
|
||||
counter_style, page_rules, target_collector)
|
||||
counter_style, page_rules, target_collector, forms)
|
||||
get_image_from_uri = functools.partial(
|
||||
original_get_image_from_uri, cache=image_cache,
|
||||
url_fetcher=html.url_fetcher, optimize_size=optimize_size)
|
||||
@ -202,9 +201,8 @@ class Document:
|
||||
return context
|
||||
|
||||
@classmethod
|
||||
def _render(cls, html, stylesheets, presentational_hints=False,
|
||||
optimize_size=('fonts',), font_config=None, counter_style=None,
|
||||
image_cache=None):
|
||||
def _render(cls, html, stylesheets, presentational_hints, optimize_size,
|
||||
font_config, counter_style, image_cache, forms):
|
||||
if font_config is None:
|
||||
font_config = FontConfiguration()
|
||||
|
||||
@ -213,7 +211,7 @@ class Document:
|
||||
|
||||
context = cls._build_layout_context(
|
||||
html, stylesheets, presentational_hints, optimize_size,
|
||||
font_config, counter_style, image_cache)
|
||||
font_config, counter_style, image_cache, forms)
|
||||
|
||||
root_box = build_formatting_structure(
|
||||
html.etree_element, context.style_for, context.get_image_from_uri,
|
||||
@ -319,7 +317,7 @@ class Document:
|
||||
|
||||
def write_pdf(self, target=None, zoom=1, attachments=None, finisher=None,
|
||||
identifier=None, variant=None, version=None,
|
||||
custom_metadata=False, forms=False):
|
||||
custom_metadata=False):
|
||||
"""Paint the pages in a PDF file, with metadata.
|
||||
|
||||
:type target:
|
||||
@ -342,7 +340,6 @@ class Document:
|
||||
:param bytes identifier: A bytestring used as PDF file identifier.
|
||||
:param str variant: A PDF variant name.
|
||||
:param str version: A PDF version number.
|
||||
:param bool version: Whether PDF forms have to be included.
|
||||
:param bool custom_metadata: A boolean defining whether custom HTML
|
||||
metadata should be stored in the generated PDF.
|
||||
:returns:
|
||||
@ -353,7 +350,7 @@ class Document:
|
||||
"""
|
||||
pdf = generate_pdf(
|
||||
self, target, zoom, attachments, self._optimize_size, identifier,
|
||||
variant, version, custom_metadata, forms)
|
||||
variant, version, custom_metadata)
|
||||
|
||||
if finisher:
|
||||
finisher(self, pdf)
|
||||
|
@ -310,7 +310,7 @@ class Box:
|
||||
def is_input(self):
|
||||
"""Return whether this box is a form input."""
|
||||
# https://html.spec.whatwg.org/multipage/forms.html#category-submit
|
||||
if self.element is not None:
|
||||
if self.style['appearance'] == 'auto' and self.element is not None:
|
||||
if self.element.tag in ('button', 'input', 'select', 'textarea'):
|
||||
return not isinstance(self, (LineBox, TextBox))
|
||||
return False
|
||||
|
@ -219,7 +219,7 @@ def element_to_box(element, style_for, get_image_from_uri, base_url,
|
||||
if not counter_values[name]:
|
||||
counter_values.pop(name)
|
||||
|
||||
box.children = children
|
||||
box.children = children if style['appearance'] == 'none' else []
|
||||
process_whitespace(box)
|
||||
set_content_lists(
|
||||
element, box, style, counter_values, target_collector, counter_style)
|
||||
|
@ -29,9 +29,12 @@ from .urls import get_url_attribute
|
||||
|
||||
HTML5_UA_COUNTER_STYLE = CounterStyle()
|
||||
HTML5_UA = read_text(css, 'html5_ua.css')
|
||||
HTML5_UA_FORM = read_text(css, 'html5_ua_form.css')
|
||||
HTML5_PH = read_text(css, 'html5_ph.css')
|
||||
HTML5_UA_STYLESHEET = CSS(
|
||||
string=HTML5_UA, counter_style=HTML5_UA_COUNTER_STYLE)
|
||||
HTML5_UA_FORM_STYLESHEET = CSS(
|
||||
string=HTML5_UA_FORM, counter_style=HTML5_UA_COUNTER_STYLE)
|
||||
HTML5_PH_STYLESHEET = CSS(string=HTML5_PH)
|
||||
|
||||
# https://html.spec.whatwg.org/multipage/#space-character
|
||||
|
@ -101,7 +101,7 @@ def _use_references(pdf, resources, images):
|
||||
|
||||
|
||||
def generate_pdf(document, target, zoom, attachments, optimize_size,
|
||||
identifier, variant, version, custom_metadata, forms):
|
||||
identifier, variant, version, custom_metadata):
|
||||
# 0.75 = 72 PDF point per inch / 96 CSS pixel per inch
|
||||
scale = zoom * 0.75
|
||||
|
||||
@ -176,10 +176,9 @@ def generate_pdf(document, target, zoom, attachments, optimize_size,
|
||||
add_links(links_and_anchors, matrix, pdf, pdf_page, pdf_names, mark)
|
||||
add_annotations(
|
||||
links_and_anchors[0], matrix, document, pdf, pdf_page, annot_files)
|
||||
if forms:
|
||||
add_inputs(
|
||||
page.inputs, matrix, pdf, pdf_page, resources, stream,
|
||||
document.font_config.font_map)
|
||||
add_inputs(
|
||||
page.inputs, matrix, pdf, pdf_page, resources, stream,
|
||||
document.font_config.font_map)
|
||||
page.paint(stream, scale=scale)
|
||||
|
||||
# Bleed
|
||||
|
Loading…
Reference in New Issue
Block a user