develop
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
589b6d41ee
|
fix(renderer): scene 2 text after independent review: a proof that never cuts, a bounded shrink search, named refusals
The proof of `maxLength` - The proof never cuts. With `overflow: truncate` the proof was given a cut block, which counts as fitting, so a bound element whose box held ten characters validated clean with `maxLength: 40` and every long value was cut at print. The proof now runs with cutting off. When it fails, an element that did not ask for cutting is refused as before; one that did still validates, since cutting is what its author chose, with the warning FIT_NOT_PROVEN at every validation carrying `measured.provenCharacters`, the longest length proven to fit whole (found by halving: fewer characters never fit worse), against `limit.characters`. No new code: FIT_NOT_PROVEN already means that the fit of a bound value is not proven. - A bound element with `maxLength` is judged for legibility, when validated, at the size the proof shrank to (the floor when it fails and the element cuts), not at its stated size. The shrink search - The size chosen is still exactly the one a search of every quarter-point step gives, but that search is no longer made. A count that errs only toward yes says whether a size could hold the text: lines filled at any character, each held to a width no real line can be under, and a block to its lines' ascent, pitches and descent. It never refuses a size that fits and, once it allows a size, allows every smaller one, so the largest size it allows is found by halving and only the steps from there are laid out. When one line at the floor is higher than the box nothing is searched, and a cut tries no line count the box is too low for. - 1024 characters at 600 dpi from 1000 pt to 1 pt took 180 to 250 ms a fit and now takes under 1 ms: at most 21 555 characters visited where the search of every size visits 15.6 million. - A text is fitted once: what `check` composed is what `paint` draws. - The text of one scene may take 64 million steps (a character visited while fitting is one, a character to be drawn 16, a glyph the scene draws for the first time at a size 4096, since the runtime rasterises it once). The element that passes it, and every text after it, is SCENE_INVALID at the element with `textWorkSteps`, as the painted-area limit is. The count is integer arithmetic: the same on every machine, and the same validated or rendered. A thousand of the worst elements validate in well under a second. Ink outside the measure - TEXT_INK_OUTSIDE_MEASURE was an IllegalStateException thrown while painting, which failed the whole render after part of the text was on the label. The dots of a text are now gathered first and reach the label only when none strayed; otherwise the one element is refused as TEXT_DOES_NOT_FIT with `glyphsOutsideMeasure` and `dotsOutsideMeasure`. A literal is held to the glyph bounds when the scene is validated. - The bound is tested at 1, 2, 300 and 1000 pt as well as from 5 to 72 pt, for every character of every face at the three resolutions; nothing strays. Schema and vocabulary - `fit` declares `maxLines`, `shrinkTo` and `overflow` under `properties` with `additionalProperties: false`. The three names are in the renderer's and the host bridge's pointer vocabularies, and a wrong member is reported at the member (`/elements/3/fit/maxLines`, or in the override that states `fit`). - A bound number is printed as the schema says: plain decimal digits, no exponent, no fraction that is only zeros (`1.0E10` prints `10000000000`, `2.50` prints `2.5`). A number that is not finite is VALUE_MISSING. Tests - The widest-advance check covers every character a face draws, inked or not (a no-break space advances the pen), so a font update cannot break the proof unseen. - Property: `fit` equals the search of every size, block for block, over 3600 generated texts, boxes, sizes, floors and line counts. - The goldens are unchanged. A README beside them records the JDK builds and the FreeType each ships. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
f5acf93e3d
|
feat(renderer): scene 2 text: bundled faces, measurement before drawing, stated fit rules (P2)
A version 2 `text` element is now drawn. It replaces the placeholder that parsed and placed a text and refused it as RENDERER_TOO_OLD. What a scene can say - `font` names one of the five bundled faces (or comes from `defaults`); any other name is FONT_UNKNOWN. There is no printer font and no installed font. - `size` is the em as a physical length (1 pt to 1000 pt), not rounded to dots. - `value` or `valuePath`; `align`/`valign` place the block in the box and each line in the block; `lineHeight`, `rotation`, `reverse`, `threshold`. - `fit`: one line by default, shrunk in quarter-point steps to 70% of the size (not below 5 pt), then refused. Opt in to more lines (`maxLines`) and to cutting with an ellipsis (`overflow: truncate`). - `maxLength`: validation proves the longest value fits, so a length refusal happens when a scene is published; printing refuses a longer value first. How it is measured and drawn - Measurement is integer arithmetic on the face's own numbers (thousandths of the em, read once at a reference size), so it is the same on every machine. Every character sits at a whole-dot pen position and is drawn there by the Java rasteriser that version 1 raster text uses, then reduced to ink at the threshold. A line's box is its advance widened to its ink plus two dots a side; a render whose ink would leave it fails instead of clipping. - At each size a line is broken between words while that fits and at any character when it does not, which is also what makes a length provable. - One glyph for each character, left to right: no kerning, ligatures, mark placement or bidirectional text. A character that cannot be drawn that way is FONT_MISSING_GLYPH with a count. Diagnostics (ids and numbers only; no value ever enters one) TEXT_DOES_NOT_FIT, VALUE_MISSING, VALUE_TOO_LONG, FONT_UNKNOWN, FONT_MISSING_GLYPH, RESERVED_FONT_NAME; TEXT_TRUNCATED, TEXT_SMALL_FOR_DPI, TEXT_LIGHT_FACE, FIT_NOT_PROVEN; TEXT_SHRUNK, TEXT_WRAPPED. Core seams added: `ElementSource.inherit` gives an element the scene's `defaults` for the properties its type reads, and `ElementSource.refuse` raises a coded refusal at a property (FONT_UNKNOWN at the place that names the face, in the element, the defaults or an override). Tests: goldens for the five faces and for fit, rotation and reverse at 203, 300 and 600 dpi, generated in the CI image (Linux, Temurin 21.0.9) and the same bytes on Windows (21.0.12) and on Linux Temurin 21.0.13; every character of every face drawn inside its measured line; seeded property tests of fit (never shrunk when it fits, the largest size that fits, never below the floor, never more lines than allowed, cut only when asked and always with the mark, a proven length never refused); licence, provenance and hash of every face; the version 2 mutation campaign extended to text. The version 1 corpus is untouched. 100% line coverage of the scene 2 packages. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
58051e7b99
|
fix(renderer): scene 2 core: the findings of the independent review
1. A length too long for any stock is a named refusal. Length.parse narrowed the micrometres to an int before it applied the 2 m limit, so "84600in" or "99999in" threw ArithmeticException: the opaque RENDER_FAILED, and an error instead of a REFUSED answer when collecting. The limit is now compared in long before narrowing, so it is SCENE_INVALID at the pointer of the length. 2. The printable area holds a box of its own size at every resolution. It was floor(far edge) less ceil(near margin), which can be one dot smaller than a box of the stated printable width: 100 mm stock with 3 mm margins and a 94 mm box fitted at 203 and 600 dpi and was refused at 300. It is now floor((W - L - R) x dpi) by floor((H - T - B) x dpi), the rounding of a box size, starting at ceil(L x dpi), ceil(T x dpi), moved back one dot where it would otherwise pass the page edge. New golden case `margins` with fractional-dot margins; the three existing goldens at 600 dpi are regenerated (the area grew by one dot each way; 203 and 300 unchanged). 3. The version 2 mutation campaign accepts only a Refusal (the package's own invariants are IllegalArgumentExceptions too) and renders about one input in four, reading the label back and comparing with validation. It found nothing at 20000 or 100000 iterations for either seed. 4. A refused answer carries no label bytes: with COLLECT and an error the answer had base64 of a label with elements missing. Scene2.render answers no label for a refused scene and the answer has no document fields. This changes the wire contract of section B.1 of the design, which records it. 5. One scene may paint sixteen times its printable area, an overlap counted each time, counted before any ink and in validation too. The element that would pass it is SCENE_INVALID with measured.paintedPercent against limit.paintedPercent 1600. 1000 fills of a 64 million dot canvas were 8 GB of byte writes; the worst scene is now 128 MB. 6. The README states what changed in the version 1 answer envelope in 0.2.0 (diagnostics on every answer; SCENE_INVALID with detail where unreadable JSON and a missing or unknown schema were RENDER_FAILED) and what the bridge must handle. The version 1 ZPL bytes are unchanged. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
ad6b0ffa88
|
feat(renderer): scene 2 core: layout in physical units, one canvas, diagnostics (P1)
A source with schema qqq-zpl-scene/2 is a label layout in millimetres, inches, points, percentages and dots that renders at 203, 300 or 600 dpi. The worker routes by the schema alone: version 1 takes exactly the path it always took (the compatibility corpus is unchanged and green), version 2 takes the new package com.kingsrook.qbits.renderer.scene2, and anything else is refused by name. - Length: parse, whole micrometres, dots by the rule of each use (position nearest, box size down, thickness nearest and at least one, module up, font size not rounded). - Layout: nine-point anchors, offsets inward from the anchored edge, omitted sizes, content alignment, groups four deep, percentages of the container. Coordinates start at the top left of the printable area. - Canvas and ZplEmitter: the whole label on one 1-bit canvas, emitted as trimmed ^GFA bands that pass the unchanged ZplOutputPolicy. - Diagnostics: every refusal is one diagnostic with a code, the element id, the box and named integers; SCENE_INVALID carries a JSON pointer. A diagnostic names only an id the scene declares and points only through schema names, indexes and declared ids. - box and group elements; overrides by resolution, checked for all three resolutions; samples accepted and ignored. Text, barcodes and images are parsed and placed and then refused as RENDERER_TOO_OLD by placeholder factories in their own sub-packages. - Renderer 0.2.0: optional targetDpi and "diagnostics": "COLLECT" on the request, diagnostics on the answer, detail on a version 2 error, the REFUSED outcome, and INSPECT_ASSET and UPGRADE_SCENE routed and refused as UNSUPPORTED_OPERATION. A version 1 scene with a target other than its stock's dpi is refused as TARGET_REQUIRES_SCENE_2. Tests: every length and rounding rule; all nine anchors; seeded property tests (mirrored anchors, boxes never leave the printable area, the bitmap rebuilt from the emitted fields equals the canvas); goldens at three resolutions as pictures and as ZPL, the ZPL also checked against the host gate in bridges/renderer; every refusal asserted as the whole diagnostic; a mutation campaign over the version 2 parser. The new package is at 100% line coverage. Also, from the review of the foundations: the mutation campaigns accept only declared refusals (a NullPointerException in a parser is now a finding), git no longer treats the stored corpus as text, and both compatibility tests pin the digest of the corpus manifest. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
ee782b7d6e |
chore: preserve unfinished document generation source and status
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Failing after 7s
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / ci-result (push) Failing after 5s
QRun-IO/ci-policy: native / native-result (push) Successful in 6s
Checkpoint implementation at user-requested stop; document known failures and incomplete release qualification. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: GPT-6 Codex <noreply@openai.com> |