* M9: redraw named-layer signature status layers - /N drawing one Form that holds n1 and n3: n1, n3 and n4 redrawn for the state - copies made once per original and state; originals never edited - Lucide icons; captions in Helvetica, embedded Inter, or craft-fonts outlines Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: draw signature states in the display copy, exports and print - marks follow the bytes shown; a changed verdict redraws after a metadata edit - background opens pick up the trust and captions current at commit Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: status captions in the interface language - the three captions in all 22 catalogues - Signatures panel colours from sign::status_rgb Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: signature badge in the widget's corner - a quarter of the shorter side, 48pt cap; outline only under 32pt - dropped for a drawn valid state; bottom-right where the appearance draws one - sign_list reports verdict_shown; parity and roadmap Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep Arabic signature captions in logical order Pass raw RTL catalogue text to the signature appearance shaper so UAX #9 is applied exactly once. This keeps the rendered word order and exported /ActualText consistent. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: read /ActualText over painted paths and pictures - A replacement that marks no glyph reads where it paints, cut to what is visible and along the way it is drawn. - A span the page content leaves open ends before the annotations. - OCR and scan field detection still count such a page as having no text of its own. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M8: redaction strips /ActualText around paint it clips - A path or shading written again under a clip counts as changed, so a partly redacted word drawn as outlines leaves no name in the file. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: recognise only layer forms that draw n1 and n3 - Settle on the one form holding both first, then read its content once per call. - Skip an /N that is its own layer form; copies keep the layer's /OC. - A verdict counts as drawn when any visible widget shows it. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep the signature badge and redraw wherever a state changes - The badge stays for every state; its mark sits bottom-right as the widget lies on the page. - An edit that changes a verdict redraws every page; captions apply before startup files open. - Print, the CLI's render and the repair log follow the display copy. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: restore the attribution usage the rebase dropped - Usage lines for the three icons, Inter and the craft-fonts input; ATTRIBUTION.md rebuilt from them. - Roadmap and localization notes for this round. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: pin signature field names on a nested form Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: bound the signature field walk - kids share their parent's name and type instead of each copying them - a widget stays listed under every field that claims it, as one shared copy - a field written in place in a shared /Kids array is walked once - caps of 20,000 fields, 100,000 entries and 4096-byte names; no states drawn past them Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep a document signed when the field walk stops early - list_cached adds a signed row of unknown validity for the fields the walk didn't read - Save As and actions then append, and Optimize, Sanitize and full rewrites are refused, as for any signed file Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M8: removing hidden content no longer strips the names of shadings - With no regions to clip, a shading is left alone instead of wrapped and marked clipped - clean_replacements skips scopes already marked, so deep nesting stays linear Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: read a picture's /ActualText over the whole picture - draw_image's transform maps pixels, not a unit square, so the text sat on one pixel in the corner; the test now draws a 2x2 picture - Painted grows in place instead of being copied through an Option Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: cap the bytes of names the signature field walk keeps - A kid's name repeats its parent's, so one long name over 20,000 kids came to 80 MB; the walk now stops at 4 MiB of names and counts the rest as unread - Cover the widget written into a shared /Kids array and the field cap among kids, which no test caught - sig_fields is private again, and the cap docs say what happens past each cap Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: skip status-layer work that changes nothing; fix tests that could not fail - show_status_layers and has_status_layers return before reading the form when nothing is signed, so an unsigned form no longer walks every field on each edit - revalidate and draw_captions leave documents with no drawn state alone, and no longer copy the signature list to update it - Scan form detection reads the page's text once; comment and badge tips share one hover rule - Tests: drop a table row that repeated another, stop taking an expectation from the code under test, stop comparing an Arc with itself, give bare asserts messages Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: test the signature field name cap at the engine boundary - A 4,096-byte name is read and blocks a full rewrite; at 4,097 bytes the list holds the unread-fields row and a full rewrite is still refused Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: test signature states beside fields the viewer draws - One display copy holds both a field's drawn appearance and the signature's state. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: draw Thai and Devanagari status captions in their own script - script_of names Thai and Devanagari, so a craft-fonts face meant for either draws the caption as outlines; without one it stays English. - Localization, parity and the craft-fonts usage line list the new scripts. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: paint left out by an exclusion mixes its /ActualText replacement - A replacement placed by outlines or pictures, some of them excluded, fails filtered extraction as one with excluded glyphs does. - Glyphs still place a replacement that has them. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: a long-named field that can't hold a signature leaves the walk whole - A leaf of another type passed over for its name is no signature field and has none below it, so an unsigned form stays unsigned. - A signature field, or any field with kids, still counts as unread. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: status captions use document faces only - Each script takes the face PdfCraft writes it into documents with, so Chinese stays English although the pinned craft-fonts' interface-only Chinese face is meant for Hani. - The craft-fonts usage line names Devanagari: the pinned revision has a face for it, and Hindi captions are drawn in it. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: refuse a new signature field the field walk can't read back - Signing adds a field only when the walk reads the whole form with it: past a cap the signature would be listed as unread fields, and its name could repeat an unread field's. - A field the walk already reads is signed as before. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: refuse a new signature field with a blank name - The walk lists no field without a name, so signing now also requires the walk to list the new field: one named only with spaces or NULs would be a signature nothing shows. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: an unnamed signed field or an unreadable form counts as unread - A signed field with no usable /T, or an /AcroForm or /Fields of the wrong type, cuts the field walk short: the document keeps its unread-fields row and stays signed. - Signing refuses a blank new field name before it adds the field, so the refusal still says why. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: no display copy when no signature state is drawn - display_bytes_for makes a copy only when it added an appearance or drew a state, as the app does. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the verdict mark stays on the page - A widget past the crop box takes its mark in the part on the page, or none when too little of it is there. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: typed values stay drawn while a signature redraws every page - A form edit that changes a signature's state puts its values back in unbaked after the pages are invalidated. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the action, Save As and shading tests check their effects - The signed action and Save As tests reopen the output for the title and the comment; the shading test checks its clip. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: values typed earlier stay drawn while a signature redraws every page - A form edit that changes a signature's state keeps every value still waiting on its page, not only its own. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: comment and content edits keep typed values drawn too - An edit to one page's comments or content that changes a signature's state moves no page, so the values still waiting on their pages stay pending, as after a form edit. - The pending-value test runs a field deletion and a comment after a fill, under a certification that allows the fill; its messages say what it checks. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the language-change test skips without catalogs - Like the other language tests, it returns early when the build has no craft-i18n catalogs. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: signed fields behind kids without a name count - A kid with no /T but kids of its own is walked as a field node, so a signed field under it is listed by its full name. - An unnamed kid claiming a signature its field doesn't have cuts the walk short, so the document stays signed and keeps its unread-fields row. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> --------- Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>
pdfcraft-fonts
Layer L2. Font helpers for the appearance streams PdfCraft generates (comments, form fields).
Today it holds what generated appearances need without a font program:
helvetica_width: the exact standard-14 advance widths, viaStd14::Helvetica. It was an estimate by character class until the generated tables landed; those tables are Adobe-authored non-visual technical data, the itemAGENTS.md§1.1 permits, carried instd14_metrics.rswithadobe_data = trueinATTRIBUTION.toml. No font program or typeface from any vendor is bundled — widths and encodings only. Reach forStd14directly for any other face.wrap: greedy line breaking with that measure (paragraphs on newlines, long words split).win_ansi: Unicode → WinAnsiEncoding bytes (?for characters it can't represent), andliteralto write bytes as a PDF literal string. Nothing writes that?silently. Callers checkfirst_undrawable(orUnicodeCMap::first_unencodable, for a character beyond U+FFFF in UCS-2), then either refuse withundrawable_message(one wording that names the character and what can be written instead) where the?would be permanent page content, or, for a form value or a comment's text, which is stored as typed, draw the?and mark the annotation withset_undrawn_mark(UNDRAWN_MARK, read back byundrawn_mark) so the edit is reported and flattening refuses.script_missingnames what the typed-signature script font and its Inter fallback both lack.
It also holds the fonts of the optional craft-fonts
build input. build.rs embeds them as CRAFT_FONTS when the build sets
CRAFT_FONTS_DIR=<checkout> (and fails if it can't while CRAFT_FONTS_REQUIRED=1, as releases
set). Without that variable CRAFT_FONTS is empty and everything below copes:
ui_japanese_fonts: theJpanfaces for the interface, BIZ UDPGothic first.ui_chinese_fonts: theHansfaces for the interface, in manifest order (without one, Chinese characters the Japanese faces lack show the replacement glyph).ui_cjk_fonts(prefer_hans): both in fallback order for the UI language (Chinese group first in Chinese mode, so one line never mixes faces with different vertical metrics).ui_arabic_fonts: theArabfaces for Arabic-script interface text (file names, document titles), in manifest order.ui_telugu_fonts: theTelufaces for Telugu interface text (the Telugu catalog, file names, document titles), in manifest order.ui_hebrew_fonts/document_hebrew_font(bold): theHebrfaces (Noto Sans Hebrew) for Hebrew interface text, and the face whose outlines become the Type 3 fallback for Hebrew text written by Edit text (Bold when asked for and present, else Regular).Nonewithout a craft-fonts input that has one; the editor then reports a clear error.shape_hebrew/hebrew_has: the RegularHebrface shaped with harfrust for Hebrew Add Text content, one cluster per letter with its points and cantillation marks (positioned by the face), drawn by the same Type 3 writer as Arabic and Thai.GlyphError::NoFontwithout the face.document_japanese_font/japanese_glyph: the face (Shippori Mincho, then BIZ UDMincho) whose outlines become the Type 3 fallback font for Japanese text written into PDFs. Without it,japanese_glyphreturnsGlyphError::NoFontand the editor reports a clear error.document_japanese_font_for_style/japanese_glyph_from: select and draw a real Japanese fallback face for edited text. Sans sources prefer BIZ UDPGothic Regular/Bold; serif sources keep Mincho. Type 3 paths and advances both come from that selected face. Missing weights fall back to a real Regular face, never synthetic bold; no italic face is supplied. The defaultdocument_japanese_font/japanese_glyphAPIs still use regular document Mincho.document_arabic_font/shape_arabic/arabic_glyph: the firstArabface, shaped with harfrust (joining forms, ligatures, mark positions) into clusters for Arabic text written into PDFs; the editor draws each cluster as one Type 3 glyph with a ToUnicode entry and per-line ActualText for logical copy/search order. Without the face they returnGlyphError::NoFontand the editor reports a clear error.document_japanese_fonts_for_style: everyJpanface in that order of preference, so the editor can use the first one that has all of the replacement's glyphs (the faces differ in coverage, e.g. of Cyrillic).ui_thai_fonts/document_thai_font/shape_thai: theThaifaces for the interface and shaped Thai Add Text content. Harfrust positions stacked vowel/tone marks and decomposes Sara Am; cluster ToUnicode entries preserve the original text. The shared Type 3 writer embeds outlines, so reopening does not depend on installed fonts.craft_glyph(face, ch)andface_has(bytes, ch): bounded outlines and glyph coverage for any bundled face.SHIPPORI_MINCHO: Shippori Mincho's bytes, orNone.TextPlan::for_words: how the OCR output writes text beyond WinAnsi — per word the first face (document face first) whose glyphs cover it, planned once per page into Type 3 fonts (codes, advances,?stand-ins) thatpdfcraft-editregisters and thepdfcraft-ocrlayers draw with; characters no face has are counted (missing) so the output reports them.
Generated Japanese Type 3 fonts record the fallback face's family and style in an indirect
FontDescriptor. pdf::Metrics::base_font uses its FontName when the Type 3 dictionary has
no BaseFont, so text inspection and edit-tool results identify the fallback after save/reopen.
The descriptor does not change glyph programs or replace the Type 3 FontBBox metrics when
Ascent/Descent are omitted (PDF Reference 1.7, tables 5.9 and 5.19). The small web input has
only Gothic Regular, so it cannot preserve bold. No new font assets or changes to that input are
needed.
wasm32 builds embed only BIZ UDPGothic Regular and any Arab, Telu, Hebr or Thai face, to keep the web build small: the web build
currently has no Chinese face, so Chinese there still shows the replacement glyph.
Font files are never
committed here (AGENTS.md §1.4).
The full font subsystem (parsing, shaping, subsetting and embedding) arrives with M2.2/M7.
Document font inputs use embedding: bounded static TrueType/OpenType-CFF validation,
exact program preservation, Unicode/CID/GID mapping and full-face subset completion.
shaping uses the same program with harfrust and UAX #9; source UI fallback fonts are
never exported. See existing-text editing.