Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,105 @@ else()
unset(XPS_DEPS_CFLAGS_OTHER)
endif()

# OFD支持选项(依赖发行版提供的 rofd C ABI 库,见 debian/control 的 librofd-ffi-dev)
option(OFD_SUPPORT "Enable OFD document format support" ON)
set(ROFD_ROOT "" CACHE PATH "Path to the rofd repository checkout or install prefix, overrides the system install")

set(OFD_SUPPORT_RESOLVED ${OFD_SUPPORT})

if (OFD_SUPPORT)
# 默认走系统路径:librofd-ffi-dev 提供 /usr/include/rofd.h 与 lib/<multiarch>/librofd_ffi.so
set(ROFD_ROOT_HINTS "")
if (ROFD_ROOT)
list(APPEND ROFD_ROOT_HINTS ${ROFD_ROOT})
endif()
if (EXISTS "${CMAKE_SOURCE_DIR}/../rofd")
list(APPEND ROFD_ROOT_HINTS "${CMAKE_SOURCE_DIR}/../rofd")
endif()

set(ROFD_LIB_SUFFIXES target/release target/debug lib)
if (CMAKE_LIBRARY_ARCHITECTURE)
list(APPEND ROFD_LIB_SUFFIXES "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()

find_path(ROFD_INCLUDE_DIR rofd.h
HINTS ${ROFD_ROOT_HINTS}
PATH_SUFFIXES crates/rofd-ffi/include include
)
find_library(ROFD_FFI_LIBRARY NAMES rofd_ffi
HINTS ${ROFD_ROOT_HINTS}
PATH_SUFFIXES ${ROFD_LIB_SUFFIXES}
)
pkg_check_modules(OFD_CAIRO QUIET cairo)

if (ROFD_INCLUDE_DIR AND ROFD_FFI_LIBRARY AND OFD_CAIRO_FOUND)
# Require the reader APIs shipped in 0.4.0. Probe declarations and linked
# symbols as well, so mismatched headers and libraries fail at configure.
include(CheckCSourceCompiles)
include(CMakePushCheckState)
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_INCLUDES ${ROFD_INCLUDE_DIR} ${OFD_CAIRO_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${ROFD_FFI_LIBRARY} ${OFD_CAIRO_LIBRARIES})
unset(ROFD_READER_APIS_AVAILABLE CACHE)
check_c_source_compiles([=[
#include <rofd.h>
int main(void) {
rofd_pixel_rect_t viewport;
rofd_metadata_t *metadata = 0;
rofd_warning_list_t *warnings = 0;
rofd_outline_t *outline = 0;
rofd_link_list_t *links = 0;
rofd_outline_node_t node = {0};
rofd_action_t action = {0};
rofd_destination_t destination = {0};
rofd_rect_t region = {0};
size_t count = 0;
int32_t w = 0, h = 0;
rofd_pixel_rect_init(&viewport, sizeof(viewport));
rofd_renderer_get_pixel_canvas_size(0, 0, 0, &w, &h, 0);
rofd_renderer_render_page_region_cairo(0, 0, 0, 0, &viewport, 0, 0);
rofd_document_get_metadata(0, &metadata, 0);
rofd_metadata_get_document_id(metadata);
rofd_metadata_free(metadata);
rofd_document_get_warnings(0, &warnings, 0);
rofd_warning_list_free(warnings);
rofd_document_get_outline(0, &outline, 0);
node.struct_size = sizeof(node);
action.struct_size = sizeof(action);
destination.struct_size = sizeof(destination);
rofd_outline_get_count(outline, &count, 0);
rofd_outline_get_node(outline, 0, &node, 0);
rofd_outline_get_action(outline, 0, 0, &action, 0);
rofd_outline_get_action_destination(outline, 0, 0, &destination, 0);
rofd_outline_free(outline);
rofd_page_get_links(0, &links, 0);
rofd_link_list_get_count(links, &count, 0);
rofd_link_list_get_region_count(links, 0, &count, 0);
rofd_link_list_get_region(links, 0, 0, &region, 0);
rofd_link_list_get_action_count(links, 0, &count, 0);
rofd_link_list_get_action(links, 0, 0, &action, 0);
rofd_link_list_get_action_destination(links, 0, 0, &destination, 0);
rofd_link_list_free(links);
return 0;
}
]=] ROFD_READER_APIS_AVAILABLE)
cmake_pop_check_state()
if (NOT ROFD_READER_APIS_AVAILABLE)
message(FATAL_ERROR "rofd headers/library lack the required region, metadata, warning, outline or page-link APIs. Install matching rofd >= 0.4.0 headers and library, and set ROFD_INCLUDE_DIR/ROFD_FFI_LIBRARY accordingly.")
endif()
message(STATUS ">>> OFD support enabled (rofd_ffi: ${ROFD_FFI_LIBRARY})")
add_compile_definitions(OFD_SUPPORT_ENABLED)
set(OFD_SUPPORT_RESOLVED ON)
else()
message(WARNING ">>> OFD support disabled: install librofd-ffi-dev, or pass -DROFD_ROOT=<rofd checkout>")
set(OFD_SUPPORT_RESOLVED OFF)
endif()
else()
message(STATUS ">>> OFD support disabled by configuration")
endif()

set(OFD_SUPPORT_ENABLED ${OFD_SUPPORT_RESOLVED})

include(GNUInstallDirs)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX /usr)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ deepin-reader is a small, fast and full-featured tool for viewing documents,supp

In debian, use below command to install compile dependencies:

`sudo apt install debhelper (>= 11),pkg-config,libspectre-dev, libdjvulibre-dev, qt5-qmake, qt5-default,libtiff-dev, libkf5archive-dev, libdtkwidget-dev,qttools5-dev-tools,qtbase5-private-dev,libjpeg-dev,libicu-dev,libpng-dev,zlib1g-dev`
`sudo apt install debhelper (>= 11),pkg-config,libspectre-dev, libdjvulibre-dev, qt5-qmake, qt5-default,libtiff-dev, libkf5archive-dev, libdtkwidget-dev,qttools5-dev-tools,qtbase5-private-dev,libjpeg-dev,libicu-dev,libpng-dev,zlib1g-dev,librofd-ffi-dev`

## Install

Expand Down
2 changes: 1 addition & 1 deletion README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ deepin-reader是一款小型、快速、功能齐全的工具,用于查看文

In debian, use below command to install compile dependencies:

`sudo apt install debhelper (>= 11),pkg-config,libspectre-dev, libdjvulibre-dev, qt5-qmake, qt5-default,libtiff-dev, libkf5archive-dev, libdtkwidget-dev,qttools5-dev-tools,qtbase5-private-dev,libjpeg-dev,libicu-dev,libpng-dev,zlib1g-dev`
`sudo apt install debhelper (>= 11),pkg-config,libspectre-dev, libdjvulibre-dev, qt5-qmake, qt5-default,libtiff-dev, libkf5archive-dev, libdtkwidget-dev,qttools5-dev-tools,qtbase5-private-dev,libjpeg-dev,libicu-dev,libpng-dev,zlib1g-dev,librofd-ffi-dev`

## 安装

Expand Down
14 changes: 14 additions & 0 deletions assets/mimetype/ofd.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<!-- OFD 文档格式 (GB/T 33190-2016 电子文件存储与交换格式 版式文档) -->
<mime-type type="application/ofd">
<comment>OFD document</comment>
<comment xml:lang="zh_CN">OFD 版式文档</comment>
<comment xml:lang="en">OFD Document</comment>
<acronym>OFD</acronym>
<expanded-acronym>Open Fixed-layout Document</expanded-acronym>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.ofd"/>
</mime-type>
</mime-info>
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Build-Depends:
libdtk6core-dev [!mipsel !mips64el] | libdtkcore-dev,
libgxps-dev,
libcairo2-dev,
librofd-ffi-dev (>= 0.4.0),
libglib2.0-dev,
libdjvulibre-dev,
libtiff-dev,
Expand Down
106 changes: 106 additions & 0 deletions docs/superpowers/plans/2026-09-10-ofd-semantic-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# OFD Semantic Text Integration Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Make OFD documents participate in the reader's existing text extraction, search, selection, and copy workflows using the current `rofd` semantic C ABI.

**Architecture:** Keep semantic adaptation inside `OfdPage`. Convert between physical-page millimetres and reader logical pixels at the boundary, use owned result handles per query, and expose character layout through the existing `Word` list.

**Tech Stack:** C++17, Qt Core/Gui, GoogleTest, `rofd` stable C ABI

---

### Task 1: Fixture-backed semantic behavior

**Files:**
- Modify: `tests/document/ut_ofdmodel.cpp`

- [ ] **Step 1: Add failing tests**

Add tests that load `normal.ofd`, require non-empty full-page text, extract text
from the first returned word rectangle, verify case-sensitive and whole-word
search filtering, and require non-empty `words()` entries with valid geometry.

- [ ] **Step 2: Run the focused tests and verify RED**

Run:

```bash
QT_QPA_PLATFORM=offscreen build-semantic/tests/test-deepin-reader \
--gtest_filter='TestOfdModel.semantic*'
```

Expected: the text, search, and words assertions fail because `OfdPage` still
returns empty values.

### Task 2: Coordinate-safe semantic adapter

**Files:**
- Modify: `reader/document/OfdModel.h`
- Modify: `reader/document/OfdModel.cpp`
- Test: `tests/document/ut_ofdmodel.cpp`

- [ ] **Step 1: Store physical page geometry and declare `words()`**

Add `QList<Word> words() override`, store the page's complete `rofd_rect_t`, and
declare private `toMillimetres` and `toPixels` rectangle helpers.

- [ ] **Step 2: Implement owned-string extraction**

Use `rofd_page_get_text` for a null rectangle and
`rofd_page_get_text_for_area` otherwise. Convert the borrowed UTF-8 bytes with
an explicit length before freeing `rofd_string_t`.

- [ ] **Step 3: Implement semantic search**

Initialize `rofd_find_options_t`, set `ROFD_FIND_CASE_SENSITIVE` and
`ROFD_FIND_WHOLE_WORDS` as requested, enumerate matches, convert each match
rectangle, and append `PageSection{PageLine{QString(), rect}}`.

- [ ] **Step 4: Implement selectable character layout**

Acquire canonical text and a layout snapshot, skip synthesized separators and
zero-area geometry, validate every UTF-8 span, and append one `Word` per scalar
using the converted rectangle.

- [ ] **Step 5: Run focused tests and verify GREEN**

Run the semantic test filter and expect every new test to pass.

### Task 3: Build contract and regression verification

**Files:**
- Modify only if required by configure checks: `CMakeLists.txt`
- Modify: `debian/control` only after the semantic package version is known

- [ ] **Step 1: Configure against local current `rofd main`**

Build `rofd-ffi` into an isolated `/tmp` target, then configure a fresh reader
build using `-DROFD_ROOT=/home/hualet/projects/hualet/rofd` and the matching
library directory.

- [ ] **Step 2: Build the reader and tests**

Run the normal CMake build for `test-deepin-reader` and `deepin-reader`.

- [ ] **Step 3: Run all OFD model tests**

Run:

```bash
QT_QPA_PLATFORM=offscreen build-semantic/tests/test-deepin-reader \
--gtest_filter='TestOfdModel.*'
```

Expected: all OFD model tests pass.

- [ ] **Step 4: Run the complete document-model test subset**

Run the repository's document model test filters and report any unrelated
pre-existing failures separately.

- [ ] **Step 5: Inspect the final diff**

Confirm only the OFD adapter, OFD tests, and approved build-contract changes are
present. Leave implementation changes uncommitted until the user requests a
commit.
Loading
Loading