Skip to content

feat(ffi): add rofd_document_get_page_size_mm - #11

Merged
lzwind merged 1 commit into
linuxdeepin:mainfrom
YangtseSu:feat/ffi-page-size-query
Oct 19, 2026
Merged

lzwind merged 1 commit into
linuxdeepin:mainfrom
YangtseSu:feat/ffi-page-size-query

Conversation

@YangtseSu

@YangtseSu YangtseSu commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

rofd-core already has a metadata-only page-size query (Document::page_size
— "Reads the physical page box without loading or caching graphical objects"),
but the C ABI only exposes rofd_page_get_size_mm, which needs an opened page
and therefore a full page parse.

Consumers that need every page's physical box pay a full document parse for it.
Papers' backend interface asks a document for the size of every page right
after load (its setup_cache step), so through rofd-ffi that is the
difference between a fast open and parsing all page content up front — for a
several-hundred-page document, most of the open latency.

Change

Adds one entry point:

rofd_status_t rofd_document_get_page_size_mm(const rofd_document_t *document,
                                             size_t page_index,
                                             rofd_rect_t *page_size_mm,
                                             rofd_error_t **error);
  • returns the same value as rofd_page_get_size_mm for the same index;
  • performs no content validation, collects no content warnings, and also
    succeeds for a page whose content cannot be loaded;
  • an index outside [0, page_count) returns ROFD_STATUS_PAGE_OUT_OF_RANGE;
  • ordinary output/error transaction and overlap rules are unchanged;
  • additive only — no struct or record change, so ABI v1 stays v1.

Verification

  • cargo test -p rofd-ffi — three new tests in tests/document.rs:
    • value parity with rofd_page_get_size_mm on the repository fixture;
    • metadata-only behaviour on a generated two-page document whose second page
      references a font resource that does not exist: the size query succeeds while
      rofd_document_get_page fails with ROFD_STATUS_INVALID_DOCUMENT;
    • NULL handle, NULL output, out-of-range index, and a scalar output aliasing
      the error slot are all rejected transactionally, without partial writes.
  • crates/rofd-ffi/tests/run_c_tests.sh — export list (tests/c/expected-symbols.txt
    extended by one line), C/C++ header compile and smoke tests.
  • cargo fmt --all -- --check and
    cargo clippy -p rofd-core -p rofd-render -p rofd-ffi --all-targets -- -D warnings.

Summary by Sourcery

Expose metadata-only page size queries through the FFI so callers can inspect all page dimensions without parsing page content.

New Features:

  • Add a C ABI function for retrieving an individual page's physical size in millimetres directly from document metadata.

Enhancements:

  • Document that page-size queries avoid page-content loading and preserve existing ABI and output/error handling semantics.

Documentation:

  • Document the new metadata-only page-size API in the FFI README and ABI design specification.

Tests:

  • Add coverage for size parity, unreadable page content, invalid arguments, out-of-range pages, output aliasing, and exported C symbols.

Expose rofd-core's metadata-only page-size query through the C ABI, so consumers
that need every page's physical box — a document viewer filling its page-size
cache, for example — do not have to parse and cache each page's content.

The call returns the same value as rofd_page_get_size_mm for the same index. It
performs no content validation, collects no content warnings, and also succeeds
for a page whose content cannot be loaded.

- include/rofd.h: declare the entry point and its output transaction contract
- src/document.rs: implement it over Document::page_size via the shared boundary
- src/lib.rs: re-export the symbol
- tests/document.rs: value parity with the page handle, metadata-only behaviour on
  a page with an unresolvable font resource, and argument/index/alias rejection
- tests/c/expected-symbols.txt: extend the pinned export list
- README.md and the v1 design doc: record the new entry point

Verification:
- cargo fmt --all -- --check
- cargo clippy -p rofd-core -p rofd-render -p rofd-ffi --all-targets -- -D warnings
- cargo test -p rofd-ffi
- crates/rofd-ffi/tests/run_c_tests.sh
@deepin-ci-robot

Copy link
Copy Markdown

Hi @YangtseSu. Thanks for your PR. 😃

@sourcery-ai

sourcery-ai Bot commented Oct 14, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an additive C ABI entry point that retrieves a page’s physical size from document metadata without loading page content, with shared transactional FFI validation, updated API documentation and symbol coverage, and tests for parity, malformed content, and boundary conditions.

Sequence diagram for metadata-only page size query

sequenceDiagram
    participant C as C Consumer
    participant FFI as rofd_document_get_page_size_mm
    participant Boundary as boundary
    participant Document as Document::page_size

    C->>FFI: rofd_document_get_page_size_mm(document, page_index, page_size_mm, error)
    FFI->>Boundary: validate outputs and transaction rules
    Boundary->>Document: page_size(page_index)
    Document-->>Boundary: physical page box metadata
    Boundary-->>FFI: rofd_rect_t
    FFI-->>C: ROFD_STATUS_OK and page_size_mm
Loading

Flow diagram for metadata-only page size behavior

flowchart TD
    A["Query page size from document"] --> B{"Valid document and outputs?"}
    B -->|No| C["Return error without partial writes"]
    B -->|Yes| D{"page_index in range?"}
    D -->|No| E["Return ROFD_STATUS_PAGE_OUT_OF_RANGE"]
    D -->|Yes| F["Read page area metadata"]
    F --> G["Copy physical box to rofd_rect_t"]
    G --> H["Return ROFD_STATUS_OK"]
    F -.-> I["No page content loading or validation"]
Loading

File-Level Changes

Change Details Files
Expose a document-level metadata-only page-size query through the C ABI.
  • Add the public declaration and Rust FFI implementation for rofd_document_get_page_size_mm.
  • Use Document::page_size to avoid page-content parsing while mapping the result to rofd_rect_t.
  • Reuse the shared boundary validation for transactional outputs, error handling, range checks, and alias rejection.
  • Re-export the symbol and add it to ABI symbol expectations.
crates/rofd-ffi/include/rofd.h
crates/rofd-ffi/src/document.rs
crates/rofd-ffi/src/lib.rs
crates/rofd-ffi/tests/c/expected-symbols.txt
Document the new API contract and ABI surface.
  • Describe metadata-only behavior, parity with page-level sizing, and behavior for unloadable content.
  • Add the function to the ABI v1 design specification.
crates/rofd-ffi/README.md
docs/superpowers/specs/2026-09-06-rofd-c-abi-v1-design.md
Add coverage for value parity, metadata-only behavior, and FFI boundary guarantees.
  • Verify results match rofd_page_get_size_mm on the fixture.
  • Generate a document with an unloadable page resource and verify size lookup succeeds while page opening fails.
  • Verify null handles, null outputs, out-of-range indices, aliased outputs, error statuses, and transactional writes.
crates/rofd-ffi/tests/document.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot

Copy link
Copy Markdown

Hi @YangtseSu. Thanks for your PR.

I'm waiting for a linuxdeepin member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="crates/rofd-ffi/src/document.rs" line_range="160" />
<code_context>
+        boundary(error, ScalarOutput::required(page_size_mm), || {
+            let size = document_ref(document)?
+                .inner
+                .page_size(page_index)
+                .map_err(FfiError::from)?;
+            Ok(rofd_rect_t {
</code_context>
<issue_to_address>
**Page sizes fail on unreadable content**

When the page has a readable physical box but its XML is malformed, malformed within its content subtree, or exceeds the configured XML depth limit, `Document::page_size` parses or deserializes the page XML before extracting its area, so malformed content or a depth-limit violation returns an invalid-document error instead of the documented content-independent size result.

Read the page's physical box without parsing or deserializing its XML.

Also at `crates/rofd-ffi/README.md:94-99`, `crates/rofd-ffi/include/rofd.h:343-349`, `crates/rofd-ffi/src/document.rs:137-140`.
</issue_to_address>

### Comment 2
<location path="crates/rofd-ffi/src/document.rs" line_range="160" />
<code_context>
+        boundary(error, ScalarOutput::required(page_size_mm), || {
+            let size = document_ref(document)?
+                .inner
+                .page_size(page_index)
+                .map_err(FfiError::from)?;
+            Ok(rofd_rect_t {
</code_context>
<issue_to_address>
**Malformed page sizes disagree**

When a page's physical box has a nonpositive width or height, `Document::page_size` rejects nonpositive dimensions, while `Document::page` stores the parsed rectangle and `Page::size` returns it unchanged; this call therefore returns `ROFD_STATUS_INVALID_DOCUMENT` where `rofd_page_get_size_mm` returns a rectangle, breaking the documented parity.

Make both page-size APIs apply the same validity rules, or document and test the malformed-page exception to the parity guarantee.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

boundary(error, ScalarOutput::required(page_size_mm), || {
let size = document_ref(document)?
.inner
.page_size(page_index)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Page sizes fail on unreadable content

When the page has a readable physical box but its XML is malformed, malformed within its content subtree, or exceeds the configured XML depth limit, Document::page_size parses or deserializes the page XML before extracting its area, so malformed content or a depth-limit violation returns an invalid-document error instead of the documented content-independent size result.

Read the page's physical box without parsing or deserializing its XML.

Also at crates/rofd-ffi/README.md:94-99, crates/rofd-ffi/include/rofd.h:343-349, crates/rofd-ffi/src/document.rs:137-140.

Prompt for AI agents
In `crates/rofd-ffi/src/document.rs` at line 160:

**Page sizes fail on unreadable content**

When the page has a readable physical box but its XML is malformed, malformed within its content subtree, or exceeds the configured XML depth limit, `Document::page_size` parses or deserializes the page XML before extracting its area, so malformed content or a depth-limit violation returns an invalid-document error instead of the documented content-independent size result.

Read the page's physical box without parsing or deserializing its XML.

Also at `crates/rofd-ffi/README.md:94-99`, `crates/rofd-ffi/include/rofd.h:343-349`, `crates/rofd-ffi/src/document.rs:137-140`.

boundary(error, ScalarOutput::required(page_size_mm), || {
let size = document_ref(document)?
.inner
.page_size(page_index)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Malformed page sizes disagree

When a page's physical box has a nonpositive width or height, Document::page_size rejects nonpositive dimensions, while Document::page stores the parsed rectangle and Page::size returns it unchanged; this call therefore returns ROFD_STATUS_INVALID_DOCUMENT where rofd_page_get_size_mm returns a rectangle, breaking the documented parity.

Make both page-size APIs apply the same validity rules, or document and test the malformed-page exception to the parity guarantee.

Prompt for AI agents
In `crates/rofd-ffi/src/document.rs` at line 160:

**Malformed page sizes disagree**

When a page's physical box has a nonpositive width or height, `Document::page_size` rejects nonpositive dimensions, while `Document::page` stores the parsed rectangle and `Page::size` returns it unchanged; this call therefore returns `ROFD_STATUS_INVALID_DOCUMENT` where `rofd_page_get_size_mm` returns a rectangle, breaking the documented parity.

Make both page-size APIs apply the same validity rules, or document and test the malformed-page exception to the parity guarantee.

archlinux-github pushed a commit to archlinux/aur that referenced this pull request Oct 14, 2026
Carry the metadata-only page-size query (rofd_document_get_page_size_mm) from
upstream pull request linuxdeepin/rofd#11, so consumers that need every page's
physical box do not have to parse all page content.

- source: add rofd-ffi-page-size.patch (sha256 pinned), applied in prepare()
- drop the patch source and that line once a rofd release contains the function
@YangtseSu

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, YangtseSu

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@lzwind
lzwind merged commit 16eaa8d into linuxdeepin:main Oct 19, 2026
12 of 13 checks passed
@YangtseSu
YangtseSu deleted the feat/ffi-page-size-query branch October 19, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants