fix(functional): form field labels no longer overprint the field above (S15)
FormFieldText treats its origin as the control's top-left - size and in_object both measure down from it - but drew the label by calling Text.render at that origin, and Text anchors on the baseline. The label's glyphs therefore landed above the origin, outside the box the control claims, on top of whatever was there. In a stacked form that is the preceding field's input box, which is what example_10_forms.png showed: every label but the first crowding the box above it. The label is now offset down by its ascent, so it occupies the space the control accounts for. Height derives from the label's ink height rather than the nominal font size, which had also eaten into the 5px gap between label and box. LABEL_GAP names that gap and field_area_offset gives the distance from the origin to the top of the input box; render, handle_click and the height calculation now share it instead of each recomputing font_size + 5. Also recorded under S12: the broken process pool is not merely wasted work. It forks from a process that already has threads, and tests/layout/test_ereader_image_rendering.py hangs at interpreter exit roughly one run in four - every test passes, then the process never returns.
This commit is contained in:
@@ -29,6 +29,7 @@ It is independent of every other spec here.
|
||||
| [S12](#s12--background-rendering) | Background rendering | 4 |
|
||||
| [S13](#s13--word-spacing-and-alignment) | Word spacing and alignment | 0 |
|
||||
| [S14](#s14--vertical-centring-in-buttons-and-fields) | Vertical centring in buttons and fields | 0 |
|
||||
| [S15](#s15--form-field-label-geometry) | Form field label geometry | 0 |
|
||||
|
||||
## Design invariants
|
||||
|
||||
@@ -1016,6 +1017,20 @@ a full page laid out in the worker — then the result is thrown away by
|
||||
4-core Pi with 512MB this is actively harmful: four interpreter copies plus four
|
||||
copies of the book, to populate a cache that never populates.
|
||||
|
||||
It is also not inert. The pool is started from `PageBuffer.initialize` inside a
|
||||
process that already has threads, and CPython warns about exactly this:
|
||||
|
||||
```
|
||||
DeprecationWarning: This process (pid=...) is multi-threaded,
|
||||
use of fork() may lead to deadlocks in the child.
|
||||
```
|
||||
|
||||
`tests/layout/test_ereader_image_rendering.py` intermittently hangs at
|
||||
interpreter exit as a result — every test reports PASSED, then the process never
|
||||
returns. Observed roughly one run in four. A reader that hangs on shutdown once
|
||||
in four launches would be a shipped bug; the test suite is just where it shows
|
||||
up first. This raises S12 from "wasted work" to "actively harmful".
|
||||
|
||||
Four further defects in the same file, which matter only if the decision is to
|
||||
keep it:
|
||||
|
||||
@@ -1211,6 +1226,45 @@ the demo to write straight to `docs/images/` so it cannot drift again.
|
||||
|
||||
---
|
||||
|
||||
## S15 — Form field label geometry
|
||||
|
||||
### Problem
|
||||
|
||||
`FormFieldText` treats its origin as the control's top-left: `size` and
|
||||
`in_object` both measure down from it. But it drew the label by calling
|
||||
`Text.render` at that origin, and Text anchors on the **baseline**, so the
|
||||
label's glyphs landed *above* the origin — outside the box the control claims,
|
||||
on top of whatever was there. In a stacked form that is the previous field's
|
||||
input box, which is what
|
||||
`docs/images/example_10_forms.png` showed: every label but the first crowding
|
||||
and touching the box above it.
|
||||
|
||||
The height was also computed as `font_size + 5 + field_height`, understating the
|
||||
label by the difference between nominal size and ink height, which left the gap
|
||||
between label and box smaller than the intended 5px.
|
||||
|
||||
### Design
|
||||
|
||||
- The origin is documented as the top-left of the whole control.
|
||||
- Rendering offsets the label down by its ascent, so the glyphs occupy
|
||||
`[origin.y, origin.y + ascent + descent]`.
|
||||
- `LABEL_GAP` names the 5px gap, and `field_area_offset` gives the distance from
|
||||
the origin to the top of the input box. `render`, `handle_click` and the height
|
||||
calculation all derive from it, instead of each recomputing `font_size + 5`.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- No label ink is drawn above the control's origin.
|
||||
- All ink lies within `[origin.y, origin.y + size[1]]`.
|
||||
- Consecutive fields laid out by `form_layouter` do not overlap.
|
||||
- A click in the input area focuses the field; a click on the label does not.
|
||||
|
||||
### Files
|
||||
|
||||
`pyWebLayout/concrete/functional.py`
|
||||
|
||||
---
|
||||
|
||||
## Test plan
|
||||
|
||||
Findings were reproduced with four probe scripts; each becomes a regression test
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user