diff --git a/docs/api_reference.rst b/docs/api_reference.rst
index 1e11c758e..377c21566 100644
--- a/docs/api_reference.rst
+++ b/docs/api_reference.rst
@@ -765,7 +765,7 @@ 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).
+form fields as PDF form fields (supported for text inputs, check boxes, text
+areas, and select only).
The ``accent-color`` property is **not** supported.
diff --git a/tests/test_api.py b/tests/test_api.py
index 640400462..0ca986c80 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -482,15 +482,23 @@ def test_partial_pdf_custom_metadata():
assert b'value' in stdout
-@pytest.mark.parametrize('html, field', (
- (b'', b'/Tx'),
- (b'', b'/Btn'),
- (b'', b'/Tx'),
+@pytest.mark.parametrize('html, fields', (
+ (b'', [b'/Tx']),
+ (b'', [b'/Btn']),
+ (b'', [b'/Tx']),
+ (b'', [b'/Ch', b'/Opt']),
+ # The selected values will be (b) and (c) in the PDF.
+ (b''
+ , [b'/Ch', b'/Opt', b'[(b) (c)]']),
))
-def test_pdf_inputs(html, field):
+def test_pdf_inputs(html, fields):
stdout = _run('--pdf-forms --uncompressed-pdf - -', html)
assert b'AcroForm' in stdout
- assert field in stdout
+ assert all(field in stdout for field in fields)
stdout = _run('--uncompressed-pdf - -', html)
assert b'AcroForm' not in stdout
diff --git a/weasyprint/layout/block.py b/weasyprint/layout/block.py
index 2e1dc9958..fb39301f4 100644
--- a/weasyprint/layout/block.py
+++ b/weasyprint/layout/block.py
@@ -833,6 +833,18 @@ def block_container_layout(context, box, bottom_space, skip_stack,
if next_page['page'] is None:
next_page['page'] = new_box.page_values()[1]
+ if (
+ box.element and
+ box.element.tag == 'select' and
+ box.element.attrib.get('multiple') is not None and
+ not box.element.attrib.get('height') and
+ not box.element.attrib.get('max-height')
+ ):
+ # Overriding the height when the select has the multiple attribute
+ # and no height attribute
+ options_number = len([child for child in box.element])
+ new_box.height = min(box.height * 4, box.height * options_number)
+
return (
new_box, resume_at, next_page, adjoining_margins, collapsing_through,
max_lines)
diff --git a/weasyprint/pdf/anchors.py b/weasyprint/pdf/anchors.py
index 269ed7b87..8105c200c 100644
--- a/weasyprint/pdf/anchors.py
+++ b/weasyprint/pdf/anchors.py
@@ -160,6 +160,75 @@ def add_inputs(inputs, matrix, pdf, page, resources, stream, font_map,
'AS': '/Yes' if checked else '/Off',
'DA': pydyf.String(b' '.join(field_stream.stream)),
})
+ elif element.tag == "select":
+ # Text, password, textarea, files, and unknown
+ font_description = get_font_description(style)
+ font = pango.pango_font_map_load_font(
+ font_map, context, font_description)
+ font = stream.add_font(font)
+ font.used_in_forms = True
+
+ field_stream.set_font_size(font.hash, font_size)
+ multiple = element.attrib.get("multiple") is not None
+ options = []
+ selected_values = []
+ for option in element:
+ options.append(
+ pydyf.Array(
+ [f'({option.attrib.get("value")})', f'({option.text})']
+ )
+ )
+ if option.attrib.get("selected") is not None:
+ selected_values.append(
+ pydyf.String(option.attrib.get("value"))
+ )
+
+ if multiple:
+ field = pydyf.Dictionary({
+ 'DA': pydyf.String(b' '.join(field_stream.stream)),
+ 'F': 2 ** (3 - 1), # Print flag
+ 'FT': '/Ch',
+ 'Ff': 2097152,
+ 'I': pydyf.Array([3]),
+ 'M': "(D:20231104123906+00'00')",
+ 'MK': pydyf.Dictionary({
+ 'BC': pydyf.Array([
+ 0.627451, 0.627451, 0.643137
+ ]),
+ 'R': 0,
+ }),
+ 'Opt': pydyf.Array(options),
+ 'P': page.reference,
+ 'Rect': pydyf.Array(rectangle),
+ 'Subtype': '/Widget',
+ 'T': pydyf.String(input_name),
+ 'Type': '/Annot',
+ 'V': pydyf.Array(selected_values)
+ if len(selected_values) > 1
+ else pydyf.String(element.attrib.get('value', '')),
+ })
+ else:
+ field = pydyf.Dictionary({
+ 'DA': pydyf.String(b' '.join(field_stream.stream)),
+ 'F': 2 ** (3 - 1), # Print flag
+ 'FT': '/Ch',
+ 'Ff': 131072,
+ 'I': pydyf.Array([0]),
+ 'M': "(D:20231103110832+00'00')",
+ 'MK': pydyf.Dictionary({
+ 'BC': pydyf.Array([
+ 0.627451, 0.627451, 0.643137
+ ]),
+ 'R': 0,
+ }),
+ 'Opt': pydyf.Array(options),
+ 'P': page.reference,
+ 'Rect': pydyf.Array(rectangle),
+ 'Subtype': '/Widget',
+ 'T': pydyf.String(input_name),
+ 'Type': '/Annot',
+ 'V': pydyf.String(element.attrib.get('value', '')),
+ })
else:
# Text, password, textarea, files, and unknown
font_description = get_font_description(style)