feat: implemented multi page reflow
This commit is contained in:
@@ -28,23 +28,20 @@ struct DocumentMetadata {
|
||||
std::string modificationDate;
|
||||
};
|
||||
|
||||
// Encryption + permission state of a loaded document. Booleans are the EFFECTIVE
|
||||
// permissions for how the doc was opened (an owner-unlocked doc reports all true).
|
||||
// The engine only surfaces these — enforcement happens in the gateway/app layers.
|
||||
struct DocumentPermissions {
|
||||
bool isEncrypted = false;
|
||||
std::string encryption = "None"; // "None", "RC4-40", "RC4-128", "AES-128", "AES-256"
|
||||
int securityRevision = -1; // FPDF_GetSecurityHandlerRevision (-1 if unencrypted)
|
||||
bool ownerUnlocked = false; // encrypted but opened with full (owner) access
|
||||
std::string encryption = "None";
|
||||
int securityRevision = -1;
|
||||
bool ownerUnlocked = false;
|
||||
|
||||
bool canPrint = true;
|
||||
bool canPrintHighRes = true;
|
||||
bool canModify = true;
|
||||
bool canCopy = true; // extract text / graphics
|
||||
bool canAnnotate = true; // add/modify annotations
|
||||
bool canCopy = true;
|
||||
bool canAnnotate = true;
|
||||
bool canFillForms = true;
|
||||
bool canExtractForAccessibility = true;
|
||||
bool canAssemble = true; // insert / rotate / delete pages
|
||||
bool canAssemble = true;
|
||||
};
|
||||
|
||||
struct PageImage {
|
||||
@@ -72,45 +69,40 @@ struct GlyphBounds {
|
||||
double fontSize;
|
||||
};
|
||||
|
||||
// Result of a point hit-test against a page's glyphs (page-point space, top-left
|
||||
// origin — the same space GlyphBounds use).
|
||||
struct HitResult {
|
||||
int glyphIndex = -1; // glyph directly under the point in reading order, -1 if none
|
||||
int caret = 0; // nearest caret position (0..N) for selection anchoring
|
||||
int line = -1; // line band the point resolved to, -1 if the page has no text
|
||||
int glyphIndex = -1;
|
||||
int caret = 0;
|
||||
int line = -1;
|
||||
};
|
||||
|
||||
// A resolved text selection: a half-open glyph range plus its reconstructed text
|
||||
// and per-line union rectangles (for drawing the selection).
|
||||
struct TextSelection {
|
||||
int startGlyph = 0; // inclusive, reading order
|
||||
int endGlyph = 0; // exclusive
|
||||
int startGlyph = 0;
|
||||
int endGlyph = 0;
|
||||
std::string text;
|
||||
std::vector<GlyphBounds> rects; // per-line union rects (text field left empty)
|
||||
std::vector<GlyphBounds> rects;
|
||||
};
|
||||
|
||||
struct FontInfo {
|
||||
std::string fontName;
|
||||
std::string type; // "TrueType", "Type1", "CIDFontType0", "CIDFontType2"
|
||||
std::string type;
|
||||
bool isEmbedded = false;
|
||||
bool isSubset = false;
|
||||
bool isVertical = false;
|
||||
|
||||
// Advanced Introspection & Diagnostics
|
||||
std::string encoding; // "WinAnsiEncoding", "MacRomanEncoding", "Identity-H", "Identity-V", "Symbol", "Custom", "None"
|
||||
bool hasToUnicode = false; // True if font has an active /ToUnicode map
|
||||
std::string cmapName; // e.g. "Identity-H", "Identity-V", "UniJIS-UTF16-H"
|
||||
std::string cidSystemInfo; // e.g. "Adobe-Japan1", "Adobe-GB1", "Adobe-Korea1"
|
||||
std::string subsetTag; // e.g. "ABCDEE" (6-character uppercase tag)
|
||||
std::string sourceType; // "Embedded", "SystemFallback", "Substituted"
|
||||
std::string substitutedFrom; // e.g. "Helvetica" (Original requested font)
|
||||
std::string substitutedTo; // e.g. "Liberation Sans" (Actual fallback font used)
|
||||
std::string normalizedFamily; // e.g. "Arial" (Normalized family grouping name)
|
||||
std::string internalFontId; // Unique stable identifier for internal tracking
|
||||
uint32_t flags = 0; // PDF font descriptor flags
|
||||
double ascent = 0.0; // Font descriptor Ascent metric
|
||||
double descent = 0.0; // Font descriptor Descent metric
|
||||
double capHeight = 0.0; // Font descriptor CapHeight metric
|
||||
std::string encoding;
|
||||
bool hasToUnicode = false;
|
||||
std::string cmapName;
|
||||
std::string cidSystemInfo;
|
||||
std::string subsetTag;
|
||||
std::string sourceType;
|
||||
std::string substitutedFrom;
|
||||
std::string substitutedTo;
|
||||
std::string normalizedFamily;
|
||||
std::string internalFontId;
|
||||
uint32_t flags = 0;
|
||||
double ascent = 0.0;
|
||||
double descent = 0.0;
|
||||
double capHeight = 0.0;
|
||||
};
|
||||
|
||||
struct Glyph {
|
||||
@@ -139,7 +131,8 @@ struct TextRun {
|
||||
std::vector<Glyph> glyphs;
|
||||
std::vector<int> objectIndices;
|
||||
double x = 0.0, y = 0.0, w = 0.0, h = 0.0;
|
||||
std::string fillColor = "#000000"; // hex of the run's fill (or stroke) color, for in-place editing
|
||||
std::string fillColor = "#000000";
|
||||
std::string paraId;
|
||||
};
|
||||
|
||||
struct TextLine {
|
||||
@@ -183,10 +176,8 @@ public:
|
||||
|
||||
[[nodiscard]] std::expected<std::vector<GlyphBounds>, EngineError> orderedGlyphs() const;
|
||||
|
||||
// Nearest glyph/caret to a point.
|
||||
[[nodiscard]] std::expected<HitResult, EngineError> hitGlyph(double x, double y) const;
|
||||
|
||||
// Reading-order selection between two points (e.g. drag anchor → focus).
|
||||
[[nodiscard]] std::expected<TextSelection, EngineError>
|
||||
selectRange(double ax, double ay, double bx, double by) const;
|
||||
|
||||
@@ -197,7 +188,7 @@ public:
|
||||
|
||||
struct AnnotationInfo {
|
||||
std::string id;
|
||||
std::string type; // "highlight", "comment", "ink", "strikeout", "signature", "widget"
|
||||
std::string type;
|
||||
double x = 0.0, y = 0.0, width = 0.0, height = 0.0;
|
||||
std::string color;
|
||||
std::string author;
|
||||
@@ -205,8 +196,7 @@ public:
|
||||
std::string timestamp;
|
||||
int pageIndex = 0;
|
||||
std::vector<std::vector<Point2D>> paths;
|
||||
|
||||
// Form field specific properties
|
||||
|
||||
std::string fieldName;
|
||||
std::string fieldValue;
|
||||
std::string fieldType;
|
||||
@@ -237,11 +227,10 @@ public:
|
||||
[[nodiscard]] virtual DocumentMetadata metadata() const noexcept = 0;
|
||||
[[nodiscard]] virtual DocumentPermissions permissions() const noexcept = 0;
|
||||
|
||||
// A single entry in the document outline (bookmarks), flattened with a depth level.
|
||||
struct OutlineItem {
|
||||
std::string title;
|
||||
int pageIndex = -1; // -1 if the destination page can't be resolved
|
||||
int level = 0; // 0 = top-level
|
||||
int pageIndex = -1;
|
||||
int level = 0;
|
||||
};
|
||||
[[nodiscard]] virtual std::expected<std::vector<OutlineItem>, EngineError> extractOutline() const = 0;
|
||||
|
||||
@@ -259,10 +248,10 @@ public:
|
||||
|
||||
virtual std::expected<void, EngineError> applyEdits(const std::string& editsJson) = 0;
|
||||
|
||||
// Per-character caret layout (JSON, PDF coords) of the most recent reflow_paragraph op, or
|
||||
// empty if none. Lets the WASM live preview align a caret exactly to the rendered glyphs.
|
||||
[[nodiscard]] virtual std::string lastReflowLayout() const { return {}; }
|
||||
|
||||
[[nodiscard]] virtual bool lastReflowOverflowed() const { return false; }
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
|
||||
saveIncremental() const = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user