// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors // // GlyphRun.h — the reconstruction pipeline's input model. Mirrors the L3 // GlyphRun from §3.2 of the plan: a sequence of glyphs sharing font, size, // color and CTM, each glyph carrying its Unicode mapping and confidence. // // The reconstruction spike (§4.1) takes a vector of these and produces // paragraphs. In production these come from the content-stream interpreter; // in the spike they come from a synthetic generator so the pipeline can be // scored against ground truth without the full L3 stack. #ifndef FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H #define FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H #include #include #include namespace freepdfeditor::spike::b { struct Point { float x; float y; }; // A single glyph as the reconstruction pipeline sees it. `unicode` and // `confidence` are produced by the glyph→Unicode step (§4.1 step 1); the // geometry is in device space (post-CTM) so line detection works in page // coordinates. struct Glyph { std::uint32_t gid = 0; // glyph id in the font std::uint32_t code = 0; // character code in the content stream std::uint32_t unicode = 0; // resolved Unicode codepoint (0 if unknown) float confidence = 0.0f; // [0,1] — see §4.1 step 1 priority ladder Point origin {}; // pen position before this glyph (device space) float advance = 0.0f; // horizontal advance (device space) }; // A run of glyphs sharing typography: font, size, color, text matrix. This is // the unit the content-stream interpreter emits; the reconstruction pipeline // merges and re-splits runs as it builds lines and paragraphs. struct GlyphRun { std::uint64_t font_id = 0; float size = 0.0f; // font size in points float char_spacing = 0.0f; float word_spacing = 0.0f; float rise = 0.0f; // superscript/subscript float rotation = 0.0f; // baseline direction in radians (0 = LTR horizontal) // Glyphs in logical order along the baseline (advance is signed along the // baseline direction; the pipeline handles RTL by negative advance). std::vector glyphs; }; // A detected line: glyphs whose baselines agree and which read in sequence. struct Line { std::vector run_indices; // indices into the input run vector float baseline_y = 0.0f; // in the run's text space (cluster along baseline dir) float x_start = 0.0f; float x_end = 0.0f; float size = 0.0f; // dominant font size on this line std::u32string text; // concatenated Unicode, in reading order std::string marker; // list marker ("•", "1.", etc.) if detected }; // A paragraph: consecutive lines with consistent leading and extent. struct Paragraph { std::vector line_indices; // indices into the line vector float top = 0.0f; float bottom = 0.0f; float left = 0.0f; float right = 0.0f; std::u32string text; // full paragraph text, lines joined bool is_list_item = false; }; // Ground-truth label for one paragraph, used by the scorer. Coordinates are in // the same device space as the glyph origins. struct GroundTruthParagraph { float top = 0.0f; float bottom = 0.0f; float left = 0.0f; float right = 0.0f; std::u32string text; }; } // namespace freepdfeditor::spike::b #endif // FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H