Skip to content

Commit

Permalink
Merge pull request #2000 from VagnerNico/vn/add-support-to-combo-boxes
Browse files Browse the repository at this point in the history
Added support for Select fields as combo boxes
  • Loading branch information
liZe authored Dec 6, 2023
2 parents 62a79a7 + 2a7ced5 commit e9b06d1
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 20 deletions.
4 changes: 2 additions & 2 deletions docs/api_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
13 changes: 11 additions & 2 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,21 @@ def test_partial_pdf_custom_metadata():
(b'<input value="">', [b'/Tx', b'/V ()']),
(b'<input type="checkbox">', [b'/Btn']),
(b'<textarea></textarea>', [b'/Tx', b'/V ()']),
(b'<select><option value="a">A</option></select>', [b'/Ch', b'/Opt']),
(b'<select>'
b'<option value="a">A</option>'
b'<option value="b" selected>B</option>'
b'</select>', [b'/Ch', b'/Opt', b'/V (b)']),
(b'<select multiple>'
b'<option value="a">A</option>'
b'<option value="b" selected>B</option>'
b'<option value="c" selected>C</option>'
b'</select>', [b'/Ch', b'/Opt', b'[(b) (c)]']),
))
def test_pdf_inputs(html, fields):
stdout = _run('--pdf-forms --uncompressed-pdf - -', html)
assert b'AcroForm' in stdout
for field in fields:
assert field in stdout
assert all(field in stdout for field in fields)
stdout = _run('--uncompressed-pdf - -', html)
assert b'AcroForm' not in stdout

Expand Down
16 changes: 11 additions & 5 deletions weasyprint/css/html5_ua.css
Original file line number Diff line number Diff line change
Expand Up @@ -363,23 +363,29 @@ input[value=""]::before {
select {
background: lightgrey;
border-radius: 0.25em 0.25em;
padding-right: 1.5em;
position: relative;
white-space: normal;
}
select::before {
select[multiple] {
height: 3.6em;
}
select:not([multiple])::before {
content: "˅";
position: absolute;
right: 0;
text-align: center;
width: 1.5em;
}
option {
display: none;
select option {
padding-right: 1.5em;
white-space: nowrap;
}
select:not([multiple]) option {
display: none;
}
select[multiple] option,
select:not(:has(option[selected])) option:first-of-type,
option[selected]:not(option[selected] ~ option[selected]) {
select option[selected]:not(option[selected] ~ option[selected]) {
display: block;
overflow: hidden;
}
Expand Down
53 changes: 42 additions & 11 deletions weasyprint/pdf/anchors.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def add_inputs(inputs, matrix, pdf, page, resources, stream, font_map,
'Subtype': '/Widget',
'Rect': pydyf.Array(rectangle),
'FT': '/Btn',
'F': 2 ** (3 - 1), # Print flag
'F': 1 << (3 - 1), # Print flag
'P': page.reference,
'T': pydyf.String(input_name),
'V': '/Yes' if checked else '/Off',
Expand All @@ -160,6 +160,43 @@ 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':
# Select fields
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)
options = []
selected_values = []
for option in element:
value = pydyf.String(option.attrib.get('value', ''))
text = pydyf.String(option.text)
options.append(pydyf.Array([value, text]))
if 'selected' in option.attrib:
selected_values.append(value)

field = pydyf.Dictionary({
'DA': pydyf.String(b' '.join(field_stream.stream)),
'F': 1 << (3 - 1), # Print flag
'FT': '/Ch',
'Opt': pydyf.Array(options),
'P': page.reference,
'Rect': pydyf.Array(rectangle),
'Subtype': '/Widget',
'T': pydyf.String(input_name),
'Type': '/Annot',
})
if 'multiple' in element.attrib:
field['Ff'] = 1 << (22 - 1)
field['V'] = pydyf.Array(selected_values)
else:
field['Ff'] = 1 << (18 - 1)
field['V'] = (
selected_values[-1] if selected_values
else pydyf.String(''))
else:
# Text, password, textarea, files, and unknown
font_description = get_font_description(style)
Expand All @@ -177,24 +214,18 @@ def add_inputs(inputs, matrix, pdf, page, resources, stream, font_map,
'Subtype': '/Widget',
'Rect': pydyf.Array(rectangle),
'FT': '/Tx',
'F': 2 ** (3 - 1), # Print flag
'F': 1 << (3 - 1), # Print flag
'P': page.reference,
'T': pydyf.String(input_name),
# Previously if the input had no value or the value was an
# empty string, the V key was filled with a pydyf.String(None)
# object. This caused the PDF input/textarea to be filled with
# the string "None". Now if the input has no value or the
# value is an empty string, the V key is filled with a
# pydyf.String('') object.
'V': pydyf.String(value or ''),
'DA': pydyf.String(b' '.join(field_stream.stream)),
})
if element.tag == 'textarea':
field['Ff'] = 2 ** (13 - 1)
field['Ff'] = 1 << (13 - 1)
elif input_type == 'password':
field['Ff'] = 2 ** (14 - 1)
field['Ff'] = 1 << (14 - 1)
elif input_type == 'file':
field['Ff'] = 2 ** (21 - 1)
field['Ff'] = 1 << (21 - 1)

pdf.add_object(field)
page['Annots'].append(field.reference)
Expand Down

0 comments on commit e9b06d1

Please sign in to comment.