From 42a328a9bfb6165ef27a4f6deca8e17501ca84d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 21:49:46 +0000 Subject: [PATCH 1/4] Initial plan From 93632f5227064a937b94789db7e24cec56ce2b12 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 21:59:13 +0000 Subject: [PATCH 2/4] refactor backend interface composition with edit method accessors --- doc/project-doc/contributors/architecture.md | 4 +- .../components/backend-integration.md | 4 +- .../contributors/components/backend.md | 4 +- .../backend/docraft_rendering_backend.h | 28 +- .../backend/pdf/docraft_haru_backend.h | 91 +++--- .../backend/pdf/docraft_haru_backend.cc | 180 +++++++++++- .../src/docraft/docraft_document_context.cc | 22 +- .../backend/docraft_haru_backend_test.cc | 16 ++ .../utils/docraft_mock_rendering_backend.h | 262 +++++++++++++++--- 9 files changed, 511 insertions(+), 100 deletions(-) diff --git a/doc/project-doc/contributors/architecture.md b/doc/project-doc/contributors/architecture.md index cb86d7d..392d021 100644 --- a/doc/project-doc/contributors/architecture.md +++ b/doc/project-doc/contributors/architecture.md @@ -146,7 +146,7 @@ Metadata lifecycle: - Node model remains backend-agnostic. - Rendering is split into renderer + painters for separation of concerns. - Layout uses chain-of-responsibility handlers to keep node-specific rules isolated. -- Context caches sub-backend interfaces (`text_backend()`, `shape_backend()`, etc.) to reduce repeated casts. +- Context caches sub-backend interfaces (`text_backend()`, `shape_backend()`, etc.) using backend composition getters (`*_edit_methods()`). - `DocraftDocument::render()` is the main orchestration point and intentionally centralizes pipeline sequencing. ## 5. Extension points @@ -158,7 +158,7 @@ Primary extension points for contributors: - Add a new backend primitive: - extend interfaces + implement in backend + consume in painters. - Add a new backend implementation: - - implement `IDocraftRenderingBackend` (and required inherited contracts). + - implement `IDocraftRenderingBackend` and expose composed interface objects through `*_edit_methods()` getters. - Add new templating capability: - extend `DocraftTemplateEngine::template_node` + helper methods. diff --git a/doc/project-doc/contributors/components/backend-integration.md b/doc/project-doc/contributors/components/backend-integration.md index 72ffd06..c16b5e7 100644 --- a/doc/project-doc/contributors/components/backend-integration.md +++ b/doc/project-doc/contributors/components/backend-integration.md @@ -17,7 +17,7 @@ Important implication: ## 2. Interface contract you must implement -A backend must implement `IDocraftRenderingBackend`, which aggregates: +A backend must implement `IDocraftRenderingBackend`, which exposes composed edit-method objects for: - text primitives, - line/shape primitives, @@ -27,7 +27,7 @@ A backend must implement `IDocraftRenderingBackend`, which aggregates: - metadata application, - font registration and font selection hooks. -In practice you implement one concrete class inheriting `IDocraftRenderingBackend`. +In practice you implement one concrete class inheriting `IDocraftRenderingBackend` and return small composed objects from the `*_edit_methods()` getters. ## 3. External integration (recommended path) diff --git a/doc/project-doc/contributors/components/backend.md b/doc/project-doc/contributors/components/backend.md index 13bf9a7..7166bc0 100644 --- a/doc/project-doc/contributors/components/backend.md +++ b/doc/project-doc/contributors/components/backend.md @@ -4,7 +4,7 @@ The backend layer is the portability boundary for output targets. ## 1. Contract hierarchy -`IDocraftRenderingBackend` aggregates these contracts: +`IDocraftRenderingBackend` composes these contracts through getter methods: - `IDocraftTextRenderingBackend` - `IDocraftShapeRenderingBackend` @@ -18,7 +18,7 @@ Plus lifecycle methods: - font registration/selection helpers - metadata application -This design lets renderers/painters consume only the primitives they need. +This design lets renderers/painters consume only the primitives they need while avoiding deep interface-inheritance chains. ## 2. Concrete implementation: Haru backend diff --git a/docraft/include/docraft/backend/docraft_rendering_backend.h b/docraft/include/docraft/backend/docraft_rendering_backend.h index 87ae6e4..4ea32ca 100644 --- a/docraft/include/docraft/backend/docraft_rendering_backend.h +++ b/docraft/include/docraft/backend/docraft_rendering_backend.h @@ -17,6 +17,7 @@ #pragma once #include "docraft/docraft_lib.h" +#include #include #include "docraft/backend/docraft_image_rendering_backend.h" @@ -32,15 +33,32 @@ namespace docraft::backend { /** * @brief Aggregated rendering backend interface. */ - class DOCRAFT_LIB IDocraftRenderingBackend : public IDocraftTextRenderingBackend, - public IDocraftShapeRenderingBackend, - public IDocraftImageRenderingBackend, - public IDocraftPageRenderingBackend { + class DOCRAFT_LIB IDocraftRenderingBackend { public: /** * @brief Virtual destructor. */ - ~IDocraftRenderingBackend() override = default; + virtual ~IDocraftRenderingBackend() = default; + /** + * @brief Returns line editing methods supported by this backend. + */ + [[nodiscard]] virtual const std::shared_ptr& line_edit_methods() const = 0; + /** + * @brief Returns shape editing methods supported by this backend. + */ + [[nodiscard]] virtual const std::shared_ptr& shape_edit_methods() const = 0; + /** + * @brief Returns text editing methods supported by this backend. + */ + [[nodiscard]] virtual const std::shared_ptr& text_edit_methods() const = 0; + /** + * @brief Returns image editing methods supported by this backend. + */ + [[nodiscard]] virtual const std::shared_ptr& image_edit_methods() const = 0; + /** + * @brief Returns page editing/getter methods supported by this backend. + */ + [[nodiscard]] virtual const std::shared_ptr& page_edit_methods() const = 0; /** * @brief Saves the document to a file path. * @param path Output file path. diff --git a/docraft/include/docraft/backend/pdf/docraft_haru_backend.h b/docraft/include/docraft/backend/pdf/docraft_haru_backend.h index 5dcd9a3..9d6d18e 100644 --- a/docraft/include/docraft/backend/pdf/docraft_haru_backend.h +++ b/docraft/include/docraft/backend/pdf/docraft_haru_backend.h @@ -31,6 +31,12 @@ namespace docraft::backend::pdf { */ class DOCRAFT_LIB DocraftHaruBackend : public docraft::backend::IDocraftRenderingBackend { public: + class LineEditMethods; + class ShapeEditMethods; + class TextEditMethods; + class ImageEditMethods; + class PageEditMethods; + /** * @brief Creates a Haru PDF backend with a new document and page. */ @@ -43,19 +49,19 @@ namespace docraft::backend::pdf { /** * @brief Begins a text object. */ - void begin_text() const override; + void begin_text() const; /** * @brief Ends a text object. */ - void end_text() const override; + void end_text() const; /** * @brief Draws text at the given coordinates. */ - void draw_text(const std::string& text, float x, float y) const override; + void draw_text(const std::string& text, float x, float y) const; /** * @brief Sets text fill color. */ - void set_text_color(float r, float g, float b) const override; + void set_text_color(float r, float g, float b) const; /** * @brief Draws text with a custom transformation matrix. */ @@ -66,71 +72,71 @@ namespace docraft::backend::pdf { float skew_y, float scale_y, float translate_x, - float translate_y) const override; + float translate_y) const; /** * @brief Measures text width using current font settings. */ - float measure_text_width(const std::string& text) const override; + float measure_text_width(const std::string& text) const; #pragma endregion #pragma region line rendering /** * @brief Sets stroke color for lines and shapes. */ - void set_stroke_color(float r, float g, float b) const override; + void set_stroke_color(float r, float g, float b) const; /** * @brief Sets line width in points. */ - void set_line_width(float thickness) const override; + void set_line_width(float thickness) const; /** * @brief Draws a line between two points. */ - void draw_line(float x1, float y1, float x2, float y2) const override; + void draw_line(float x1, float y1, float x2, float y2) const; #pragma endregion #pragma region shape rendering /** * @brief Saves the current graphics state. */ - void save_state() const override; + void save_state() const; /** * @brief Restores the previous graphics state. */ - void restore_state() const override; + void restore_state() const; /** * @brief Sets fill color for shapes. */ - void set_fill_color(float r, float g, float b) const override; + void set_fill_color(float r, float g, float b) const; /** * @brief Sets fill alpha for shapes. */ - void set_fill_alpha(float alpha) const override; + void set_fill_alpha(float alpha) const; /** * @brief Sets stroke alpha for shapes. */ - void set_stroke_alpha(float alpha) const override; + void set_stroke_alpha(float alpha) const; /** * @brief Adds a rectangle path. */ - void draw_rectangle(float x, float y, float width, float height) const override; + void draw_rectangle(float x, float y, float width, float height) const; /** * @brief Adds a circle path. */ - void draw_circle(float center_x, float center_y, float radius) const override; + void draw_circle(float center_x, float center_y, float radius) const; /** * @brief Adds a polygon path. */ - void draw_polygon(const std::vector &points) const override; + void draw_polygon(const std::vector &points) const; /** * @brief Fills the current path. */ - void fill() const override; + void fill() const; /** * @brief Strokes the current path. */ - void stroke() const override; + void stroke() const; /** * @brief Fills and strokes the current path. */ - void fill_stroke() const override; + void fill_stroke() const; #pragma endregion #pragma region image rendering /** @@ -141,7 +147,7 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; /** * @brief Draws a PNG image from memory. */ @@ -151,7 +157,7 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; /** * @brief Draws a JPEG image from file. */ @@ -160,7 +166,7 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; /** * @brief Draws a JPEG image from memory. */ @@ -170,7 +176,7 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; /** * @brief Draws a raw RGB image from file. */ @@ -181,7 +187,7 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; /** * @brief Draws a raw RGB image from memory. */ @@ -192,10 +198,16 @@ namespace docraft::backend::pdf { float x, float y, float width, - float height) const override; + float height) const; #pragma endregion #pragma region backend lifecycle + [[nodiscard]] const std::shared_ptr& line_edit_methods() const override; + [[nodiscard]] const std::shared_ptr& shape_edit_methods() const override; + [[nodiscard]] const std::shared_ptr& text_edit_methods() const override; + [[nodiscard]] const std::shared_ptr& image_edit_methods() const override; + [[nodiscard]] const std::shared_ptr& page_edit_methods() const override; + void save_to_file(const std::string& path) const override; [[nodiscard]] std::string file_extension() const override; /** @@ -219,52 +231,52 @@ namespace docraft::backend::pdf { /** * @brief Returns the current page width in points. */ - float page_width() const override; + float page_width() const; /** * @brief Returns the current page height in points. */ - float page_height() const override; + float page_height() const; /** * @brief Adds a new page to the document and makes it the current page. */ - void add_new_page() override; + void add_new_page(); /** * @brief Moves the cursor to the next page if it exists. * @throws std::runtime_error if already at the last page. */ - void move_to_next_page() override; + void move_to_next_page(); /** * @brief Navigates to a specific page (0-based index). * @param page_number Destination page index. * @throws std::runtime_error if the page number is out of range. */ - void go_to_page(std::size_t page_number) override; + void go_to_page(std::size_t page_number); /** * @brief Navigates to the first page. */ - void go_to_first_page() override; + void go_to_first_page(); /** * @brief Navigates to the previous page. * @throws std::runtime_error if already at the first page. */ - void go_to_previous_page() override; + void go_to_previous_page(); /** * @brief Navigates to the last page. */ - void go_to_last_page() override; + void go_to_last_page(); /** * @brief Sets the page size and orientation. */ void set_page_format(model::DocraftPageSize size, - model::DocraftPageOrientation orientation) override; + model::DocraftPageOrientation orientation); /** * @brief Returns the current page number (1-based index). */ - std::size_t current_page_number() const override; + std::size_t current_page_number() const; /** * @brief Returns the total number of pages in the document. */ - std::size_t total_page_count() const override; + std::size_t total_page_count() const; #pragma endregion private: /** @@ -290,5 +302,10 @@ namespace docraft::backend::pdf { size_t current_page_number_ = 0; mutable float fill_alpha_ = 1.0F; mutable float stroke_alpha_ = 1.0F; + std::shared_ptr line_edit_methods_; + std::shared_ptr shape_edit_methods_; + std::shared_ptr text_edit_methods_; + std::shared_ptr image_edit_methods_; + std::shared_ptr page_edit_methods_; }; } // docraft diff --git a/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc b/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc index c845717..e565d5e 100644 --- a/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc +++ b/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc @@ -240,6 +240,159 @@ namespace docraft::backend::pdf { } } // namespace + class DocraftHaruBackend::LineEditMethods final : public IDocraftLineRenderingBackend { + public: + explicit LineEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { backend_.draw_line(x1, y1, x2, y2); } + + private: + DocraftHaruBackend& backend_; + }; + + class DocraftHaruBackend::ShapeEditMethods final : public IDocraftShapeRenderingBackend { + public: + explicit ShapeEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + + void save_state() const override { backend_.save_state(); } + void restore_state() const override { backend_.restore_state(); } + void set_fill_color(float r, float g, float b) const override { backend_.set_fill_color(r, g, b); } + void set_fill_alpha(float alpha) const override { backend_.set_fill_alpha(alpha); } + void set_stroke_alpha(float alpha) const override { backend_.set_stroke_alpha(alpha); } + void draw_rectangle(float x, float y, float width, float height) const override { + backend_.draw_rectangle(x, y, width, height); + } + void draw_circle(float center_x, float center_y, float radius) const override { + backend_.draw_circle(center_x, center_y, radius); + } + void draw_polygon(const std::vector &points) const override { + backend_.draw_polygon(points); + } + void fill() const override { backend_.fill(); } + void stroke() const override { backend_.stroke(); } + void fill_stroke() const override { backend_.fill_stroke(); } + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { backend_.draw_line(x1, y1, x2, y2); } + + private: + DocraftHaruBackend& backend_; + }; + + class DocraftHaruBackend::TextEditMethods final : public IDocraftTextRenderingBackend { + public: + explicit TextEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + + void begin_text() const override { backend_.begin_text(); } + void end_text() const override { backend_.end_text(); } + void draw_text(const std::string& text, float x, float y) const override { backend_.draw_text(text, x, y); } + void set_text_color(float r, float g, float b) const override { backend_.set_text_color(r, g, b); } + void draw_text_matrix( + const std::string& text, + float scale_x, + float skew_x, + float skew_y, + float scale_y, + float translate_x, + float translate_y) const override { + backend_.draw_text_matrix(text, scale_x, skew_x, skew_y, scale_y, translate_x, translate_y); + } + float measure_text_width(const std::string& text) const override { return backend_.measure_text_width(text); } + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { backend_.draw_line(x1, y1, x2, y2); } + + private: + DocraftHaruBackend& backend_; + }; + + class DocraftHaruBackend::ImageEditMethods final : public IDocraftImageRenderingBackend { + public: + explicit ImageEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + + void draw_png_image( + const std::string& path, + float x, + float y, + float width, + float height) const override { + backend_.draw_png_image(path, x, y, width, height); + } + void draw_png_image_from_memory( + const unsigned char* data, + std::size_t size, + float x, + float y, + float width, + float height) const override { + backend_.draw_png_image_from_memory(data, size, x, y, width, height); + } + void draw_jpeg_image( + const std::string& path, + float x, + float y, + float width, + float height) const override { + backend_.draw_jpeg_image(path, x, y, width, height); + } + void draw_jpeg_image_from_memory( + const unsigned char* data, + std::size_t size, + float x, + float y, + float width, + float height) const override { + backend_.draw_jpeg_image_from_memory(data, size, x, y, width, height); + } + void draw_raw_rgb_image( + const std::string& path, + int pixel_width, + int pixel_height, + float x, + float y, + float width, + float height) const override { + backend_.draw_raw_rgb_image(path, pixel_width, pixel_height, x, y, width, height); + } + void draw_raw_rgb_image_from_memory( + const unsigned char* data, + int pixel_width, + int pixel_height, + float x, + float y, + float width, + float height) const override { + backend_.draw_raw_rgb_image_from_memory(data, pixel_width, pixel_height, x, y, width, height); + } + + private: + DocraftHaruBackend& backend_; + }; + + class DocraftHaruBackend::PageEditMethods final : public IDocraftPageRenderingBackend { + public: + explicit PageEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + + float page_width() const override { return backend_.page_width(); } + float page_height() const override { return backend_.page_height(); } + void add_new_page() override { backend_.add_new_page(); } + void move_to_next_page() override { backend_.move_to_next_page(); } + void go_to_page(std::size_t page_number) override { backend_.go_to_page(page_number); } + void go_to_first_page() override { backend_.go_to_first_page(); } + void go_to_previous_page() override { backend_.go_to_previous_page(); } + void go_to_last_page() override { backend_.go_to_last_page(); } + void set_page_format(model::DocraftPageSize size, model::DocraftPageOrientation orientation) override { + backend_.set_page_format(size, orientation); + } + std::size_t current_page_number() const override { return backend_.current_page_number(); } + std::size_t total_page_count() const override { return backend_.total_page_count(); } + + private: + DocraftHaruBackend& backend_; + }; + void DocraftHaruBackend::create_new_page() { HPDF_Page new_page = HPDF_AddPage(pdf_); if (!new_page) { @@ -249,7 +402,12 @@ namespace docraft::backend::pdf { pages_.push_back(new_page); current_page_number_ = pages_.size() - 1; // Move to the newly created page } - DocraftHaruBackend::DocraftHaruBackend() { + DocraftHaruBackend::DocraftHaruBackend() + : line_edit_methods_(std::make_shared(*this)), + shape_edit_methods_(std::make_shared(*this)), + text_edit_methods_(std::make_shared(*this)), + image_edit_methods_(std::make_shared(*this)), + page_edit_methods_(std::make_shared(*this)) { pdf_ = HPDF_New(error_handler, NULL); if (!pdf_) { throw std::runtime_error("Failed to initialize Haru PDF document"); @@ -484,6 +642,26 @@ namespace docraft::backend::pdf { HPDF_SaveToFile(pdf_, path.c_str()); } + const std::shared_ptr& DocraftHaruBackend::line_edit_methods() const { + return line_edit_methods_; + } + + const std::shared_ptr& DocraftHaruBackend::shape_edit_methods() const { + return shape_edit_methods_; + } + + const std::shared_ptr& DocraftHaruBackend::text_edit_methods() const { + return text_edit_methods_; + } + + const std::shared_ptr& DocraftHaruBackend::image_edit_methods() const { + return image_edit_methods_; + } + + const std::shared_ptr& DocraftHaruBackend::page_edit_methods() const { + return page_edit_methods_; + } + std::string DocraftHaruBackend::file_extension() const { return ".pdf"; } diff --git a/docraft/src/docraft/docraft_document_context.cc b/docraft/src/docraft/docraft_document_context.cc index 38bdf2d..06bcccc 100644 --- a/docraft/src/docraft/docraft_document_context.cc +++ b/docraft/src/docraft/docraft_document_context.cc @@ -20,8 +20,8 @@ namespace docraft { DocraftDocumentContext::DocraftDocumentContext() { backend_ = std::make_shared(); - page_height_ = backend_->page_height(); - page_width_ = backend_->page_width(); + page_height_ = backend_->page_edit_methods()->page_height(); + page_width_ = backend_->page_edit_methods()->page_width(); current_rect_width_ = page_width_; } @@ -29,8 +29,8 @@ namespace docraft { DocraftDocumentContext::DocraftDocumentContext( const std::shared_ptr &backend) : backend_( backend) { - page_height_ = backend_->page_height(); - page_width_ = backend_->page_width(); + page_height_ = backend_->page_edit_methods()->page_height(); + page_width_ = backend_->page_edit_methods()->page_width(); current_rect_width_ = page_width_; } @@ -62,8 +62,8 @@ namespace docraft { void DocraftDocumentContext::set_backend(const std::shared_ptr &backend) { backend_ = backend ? backend : std::make_shared(); - page_height_ = backend_->page_height(); - page_width_ = backend_->page_width(); + page_height_ = backend_->page_edit_methods()->page_height(); + page_width_ = backend_->page_edit_methods()->page_width(); current_rect_width_ = page_width_; line_backend_.reset(); shape_backend_.reset(); @@ -131,35 +131,35 @@ namespace docraft { const std::shared_ptr &DocraftDocumentContext::line_backend() const { if (!line_backend_) { - line_backend_ = std::dynamic_pointer_cast(backend_); + line_backend_ = backend_->line_edit_methods(); } return line_backend_; } const std::shared_ptr &DocraftDocumentContext::shape_backend() const { if (!shape_backend_) { - shape_backend_ = std::dynamic_pointer_cast(backend_); + shape_backend_ = backend_->shape_edit_methods(); } return shape_backend_; } const std::shared_ptr &DocraftDocumentContext::text_backend() const { if (!text_backend_) { - text_backend_ = std::dynamic_pointer_cast(backend_); + text_backend_ = backend_->text_edit_methods(); } return text_backend_; } const std::shared_ptr &DocraftDocumentContext::image_backend() const { if (!image_backend_) { - image_backend_ = std::dynamic_pointer_cast(backend_); + image_backend_ = backend_->image_edit_methods(); } return image_backend_; } const std::shared_ptr &DocraftDocumentContext::page_backend() const { if (!page_backend_) { - page_backend_ = std::dynamic_pointer_cast(backend_); + page_backend_ = backend_->page_edit_methods(); } return page_backend_; } diff --git a/docraft/test/docraft/backend/docraft_haru_backend_test.cc b/docraft/test/docraft/backend/docraft_haru_backend_test.cc index 2202b24..2c5a78a 100644 --- a/docraft/test/docraft/backend/docraft_haru_backend_test.cc +++ b/docraft/test/docraft/backend/docraft_haru_backend_test.cc @@ -30,6 +30,22 @@ TEST_F(DocraftHaruBackendTest, StartsWithSinglePageAndValidDimensions) { EXPECT_GT(backend().page_width(), 0.0F); EXPECT_GT(backend().page_height(), 0.0F); } + +TEST_F(DocraftHaruBackendTest, ExposesComposedEditMethods) { + auto& rendering_backend = static_cast(backend()); + + ASSERT_TRUE(rendering_backend.page_edit_methods()); + ASSERT_TRUE(rendering_backend.text_edit_methods()); + ASSERT_TRUE(rendering_backend.shape_edit_methods()); + ASSERT_TRUE(rendering_backend.image_edit_methods()); + ASSERT_TRUE(rendering_backend.line_edit_methods()); + + ASSERT_TRUE(rendering_backend.can_use_font("Helvetica", nullptr)); + rendering_backend.set_font("Helvetica", 12.0F, nullptr); + EXPECT_EQ(rendering_backend.page_edit_methods()->total_page_count(), 1U); + EXPECT_GT(rendering_backend.text_edit_methods()->measure_text_width("hello"), 0.0F); +} + TEST_F(DocraftHaruBackendTest, MoveToNextPage) { backend().add_new_page(); EXPECT_EQ(backend().total_page_count(), 2U); diff --git a/docraft/test/docraft/utils/docraft_mock_rendering_backend.h b/docraft/test/docraft/utils/docraft_mock_rendering_backend.h index 53d7ca9..13a7d3f 100644 --- a/docraft/test/docraft/utils/docraft_mock_rendering_backend.h +++ b/docraft/test/docraft/utils/docraft_mock_rendering_backend.h @@ -9,6 +9,157 @@ namespace docraft::test::utils { class MockRenderingBackend : public backend::IDocraftRenderingBackend { public: + class LineEditMethods final : public backend::IDocraftLineRenderingBackend { + public: + explicit LineEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { + backend_.draw_line(x1, y1, x2, y2); + } + + private: + MockRenderingBackend& backend_; + }; + + class ShapeEditMethods final : public backend::IDocraftShapeRenderingBackend { + public: + explicit ShapeEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + + void save_state() const override { backend_.save_state(); } + void restore_state() const override { backend_.restore_state(); } + void set_fill_color(float r, float g, float b) const override { backend_.set_fill_color(r, g, b); } + void set_fill_alpha(float alpha) const override { backend_.set_fill_alpha(alpha); } + void set_stroke_alpha(float alpha) const override { backend_.set_stroke_alpha(alpha); } + void draw_rectangle(float x, float y, float width, float height) const override { + backend_.draw_rectangle(x, y, width, height); + } + void draw_circle(float center_x, float center_y, float radius) const override { + backend_.draw_circle(center_x, center_y, radius); + } + void draw_polygon(const std::vector &points) const override { + backend_.draw_polygon(points); + } + void fill() const override { backend_.fill(); } + void stroke() const override { backend_.stroke(); } + void fill_stroke() const override { backend_.fill_stroke(); } + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { + backend_.draw_line(x1, y1, x2, y2); + } + + private: + MockRenderingBackend& backend_; + }; + + class TextEditMethods final : public backend::IDocraftTextRenderingBackend { + public: + explicit TextEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + + void begin_text() const override { backend_.begin_text(); } + void end_text() const override { backend_.end_text(); } + void draw_text(const std::string &text, float x, float y) const override { + backend_.draw_text(text, x, y); + } + void set_text_color(float r, float g, float b) const override { backend_.set_text_color(r, g, b); } + void draw_text_matrix( + const std::string &text, + float scale_x, + float skew_x, + float skew_y, + float scale_y, + float translate_x, + float translate_y) const override { + backend_.draw_text_matrix(text, scale_x, skew_x, skew_y, scale_y, translate_x, translate_y); + } + float measure_text_width(const std::string &text) const override { return backend_.measure_text_width(text); } + void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } + void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } + void draw_line(float x1, float y1, float x2, float y2) const override { + backend_.draw_line(x1, y1, x2, y2); + } + + private: + MockRenderingBackend& backend_; + }; + + class ImageEditMethods final : public backend::IDocraftImageRenderingBackend { + public: + explicit ImageEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + + void draw_png_image(const std::string &path, float x, float y, float width, float height) const override { + backend_.draw_png_image(path, x, y, width, height); + } + void draw_png_image_from_memory( + const unsigned char *data, + std::size_t size, + float x, + float y, + float width, + float height) const override { + backend_.draw_png_image_from_memory(data, size, x, y, width, height); + } + void draw_jpeg_image(const std::string &path, float x, float y, float width, float height) const override { + backend_.draw_jpeg_image(path, x, y, width, height); + } + void draw_jpeg_image_from_memory( + const unsigned char *data, + std::size_t size, + float x, + float y, + float width, + float height) const override { + backend_.draw_jpeg_image_from_memory(data, size, x, y, width, height); + } + void draw_raw_rgb_image( + const std::string &path, + int pixel_width, + int pixel_height, + float x, + float y, + float width, + float height) const override { + backend_.draw_raw_rgb_image(path, pixel_width, pixel_height, x, y, width, height); + } + void draw_raw_rgb_image_from_memory( + const unsigned char *data, + int pixel_width, + int pixel_height, + float x, + float y, + float width, + float height) const override { + backend_.draw_raw_rgb_image_from_memory(data, pixel_width, pixel_height, x, y, width, height); + } + + private: + MockRenderingBackend& backend_; + }; + + class PageEditMethods final : public backend::IDocraftPageRenderingBackend { + public: + explicit PageEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + + float page_width() const override { return backend_.page_width(); } + float page_height() const override { return backend_.page_height(); } + void add_new_page() override { backend_.add_new_page(); } + void move_to_next_page() override { backend_.move_to_next_page(); } + void go_to_page(std::size_t page_number) override { backend_.go_to_page(page_number); } + void go_to_first_page() override { backend_.go_to_first_page(); } + void go_to_previous_page() override { backend_.go_to_previous_page(); } + void go_to_last_page() override { backend_.go_to_last_page(); } + void set_page_format(model::DocraftPageSize size, model::DocraftPageOrientation orientation) override { + backend_.set_page_format(size, orientation); + } + std::size_t current_page_number() const override { return backend_.current_page_number(); } + std::size_t total_page_count() const override { return backend_.total_page_count(); } + + private: + MockRenderingBackend& backend_; + }; + struct Config { float page_width = 100.0F; float page_height = 100.0F; @@ -20,42 +171,68 @@ namespace docraft::test::utils { MockRenderingBackend() : MockRenderingBackend(Config{}) {} - explicit MockRenderingBackend(Config config) : config_(std::move(config)) { + explicit MockRenderingBackend(Config config) + : config_(std::move(config)), + line_edit_methods_(std::make_shared(*this)), + shape_edit_methods_(std::make_shared(*this)), + text_edit_methods_(std::make_shared(*this)), + image_edit_methods_(std::make_shared(*this)), + page_edit_methods_(std::make_shared(*this)) { pages_ = config_.initial_pages > 0 ? config_.initial_pages : 1; current_page_ = 0; } - void begin_text() const override {} - void end_text() const override {} - void draw_text(const std::string &, float, float) const override {} - void set_text_color(float, float, float) const override {} - void draw_text_matrix(const std::string &, float, float, float, float, float, float) const override {} - float measure_text_width(const std::string &text) const override { + void begin_text() const {} + void end_text() const {} + void draw_text(const std::string &, float, float) const {} + void set_text_color(float, float, float) const {} + void draw_text_matrix(const std::string &, float, float, float, float, float, float) const {} + float measure_text_width(const std::string &text) const { return static_cast(text.size()) * config_.text_width_factor; } - void set_stroke_color(float, float, float) const override {} - void set_line_width(float) const override {} - void draw_line(float, float, float, float) const override { ++line_count; } - - void save_state() const override {} - void restore_state() const override {} - void set_fill_color(float, float, float) const override {} - void set_fill_alpha(float) const override {} - void set_stroke_alpha(float) const override {} - void draw_rectangle(float, float, float, float) const override {} - void draw_circle(float, float, float) const override {} - void draw_polygon(const std::vector &) const override {} - void fill() const override {} - void stroke() const override {} - void fill_stroke() const override {} - - void draw_png_image(const std::string &, float, float, float, float) const override {} - void draw_png_image_from_memory(const unsigned char *, std::size_t, float, float, float, float) const override {} - void draw_jpeg_image(const std::string &, float, float, float, float) const override {} - void draw_jpeg_image_from_memory(const unsigned char *, std::size_t, float, float, float, float) const override {} - void draw_raw_rgb_image(const std::string &, int, int, float, float, float, float) const override {} - void draw_raw_rgb_image_from_memory(const unsigned char *, int, int, float, float, float, float) const override {} + void set_stroke_color(float, float, float) const {} + void set_line_width(float) const {} + void draw_line(float, float, float, float) const { ++line_count; } + + void save_state() const {} + void restore_state() const {} + void set_fill_color(float, float, float) const {} + void set_fill_alpha(float) const {} + void set_stroke_alpha(float) const {} + void draw_rectangle(float, float, float, float) const {} + void draw_circle(float, float, float) const {} + void draw_polygon(const std::vector &) const {} + void fill() const {} + void stroke() const {} + void fill_stroke() const {} + + void draw_png_image(const std::string &, float, float, float, float) const {} + void draw_png_image_from_memory(const unsigned char *, std::size_t, float, float, float, float) const {} + void draw_jpeg_image(const std::string &, float, float, float, float) const {} + void draw_jpeg_image_from_memory(const unsigned char *, std::size_t, float, float, float, float) const {} + void draw_raw_rgb_image(const std::string &, int, int, float, float, float, float) const {} + void draw_raw_rgb_image_from_memory(const unsigned char *, int, int, float, float, float, float) const {} + + [[nodiscard]] const std::shared_ptr& line_edit_methods() const override { + return line_edit_methods_; + } + + [[nodiscard]] const std::shared_ptr& shape_edit_methods() const override { + return shape_edit_methods_; + } + + [[nodiscard]] const std::shared_ptr& text_edit_methods() const override { + return text_edit_methods_; + } + + [[nodiscard]] const std::shared_ptr& image_edit_methods() const override { + return image_edit_methods_; + } + + [[nodiscard]] const std::shared_ptr& page_edit_methods() const override { + return page_edit_methods_; + } void save_to_file(const std::string &path) const override { last_saved_path_ = path; } [[nodiscard]] std::string file_extension() const override { return config_.extension; } @@ -64,53 +241,53 @@ namespace docraft::test::utils { void set_font(const std::string &, float, const char *) const override {} void set_document_metadata(const DocraftDocumentMetadata &) override {} - float page_width() const override { return config_.page_width; } - float page_height() const override { return config_.page_height; } + float page_width() const { return config_.page_width; } + float page_height() const { return config_.page_height; } - void add_new_page() override { + void add_new_page() { ++pages_; current_page_ = pages_ - 1; } - void move_to_next_page() override { + void move_to_next_page() { if (current_page_ + 1 >= pages_) { throw std::runtime_error("Already at the last page"); } ++current_page_; } - void go_to_page(std::size_t page_number) override { + void go_to_page(std::size_t page_number) { if (page_number >= pages_) { throw std::runtime_error("Invalid page number"); } current_page_ = page_number; } - void go_to_first_page() override { + void go_to_first_page() { if (pages_ == 0) { throw std::runtime_error("No pages"); } current_page_ = 0; } - void go_to_previous_page() override { + void go_to_previous_page() { if (current_page_ == 0) { throw std::runtime_error("Already at first page"); } --current_page_; } - void go_to_last_page() override { + void go_to_last_page() { if (pages_ == 0) { throw std::runtime_error("No pages"); } current_page_ = pages_ - 1; } - void set_page_format(model::DocraftPageSize, model::DocraftPageOrientation) override {} + void set_page_format(model::DocraftPageSize, model::DocraftPageOrientation) {} - std::size_t current_page_number() const override { return current_page_ + 1; } - std::size_t total_page_count() const override { return pages_; } + std::size_t current_page_number() const { return current_page_ + 1; } + std::size_t total_page_count() const { return pages_; } void set_current_page(std::size_t one_based_page_number) { current_page_ = one_based_page_number > 0 ? one_based_page_number - 1 : 0; @@ -127,5 +304,10 @@ namespace docraft::test::utils { std::size_t pages_ = 1; std::size_t current_page_ = 0; mutable std::string last_saved_path_; + std::shared_ptr line_edit_methods_; + std::shared_ptr shape_edit_methods_; + std::shared_ptr text_edit_methods_; + std::shared_ptr image_edit_methods_; + std::shared_ptr page_edit_methods_; }; } // namespace docraft::test::utils From 798858371b35fad7135269946457417f2809fe69 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 05:54:13 +0000 Subject: [PATCH 3/4] Rename edit API methods and Haru edit helper classes --- .../backend/docraft_rendering_backend.h | 10 ++-- .../backend/pdf/docraft_haru_backend.h | 30 +++++----- .../backend/pdf/docraft_haru_backend.cc | 50 ++++++++-------- .../src/docraft/docraft_document_context.cc | 22 +++---- .../backend/docraft_haru_backend_test.cc | 14 ++--- .../utils/docraft_mock_rendering_backend.h | 60 +++++++++---------- 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/docraft/include/docraft/backend/docraft_rendering_backend.h b/docraft/include/docraft/backend/docraft_rendering_backend.h index 4ea32ca..a1f3e12 100644 --- a/docraft/include/docraft/backend/docraft_rendering_backend.h +++ b/docraft/include/docraft/backend/docraft_rendering_backend.h @@ -42,23 +42,23 @@ namespace docraft::backend { /** * @brief Returns line editing methods supported by this backend. */ - [[nodiscard]] virtual const std::shared_ptr& line_edit_methods() const = 0; + [[nodiscard]] virtual const std::shared_ptr& edit_line() const = 0; /** * @brief Returns shape editing methods supported by this backend. */ - [[nodiscard]] virtual const std::shared_ptr& shape_edit_methods() const = 0; + [[nodiscard]] virtual const std::shared_ptr& edit_shape() const = 0; /** * @brief Returns text editing methods supported by this backend. */ - [[nodiscard]] virtual const std::shared_ptr& text_edit_methods() const = 0; + [[nodiscard]] virtual const std::shared_ptr& edit_text() const = 0; /** * @brief Returns image editing methods supported by this backend. */ - [[nodiscard]] virtual const std::shared_ptr& image_edit_methods() const = 0; + [[nodiscard]] virtual const std::shared_ptr& edit_image() const = 0; /** * @brief Returns page editing/getter methods supported by this backend. */ - [[nodiscard]] virtual const std::shared_ptr& page_edit_methods() const = 0; + [[nodiscard]] virtual const std::shared_ptr& edit_page() const = 0; /** * @brief Saves the document to a file path. * @param path Output file path. diff --git a/docraft/include/docraft/backend/pdf/docraft_haru_backend.h b/docraft/include/docraft/backend/pdf/docraft_haru_backend.h index 9d6d18e..1859d06 100644 --- a/docraft/include/docraft/backend/pdf/docraft_haru_backend.h +++ b/docraft/include/docraft/backend/pdf/docraft_haru_backend.h @@ -31,11 +31,11 @@ namespace docraft::backend::pdf { */ class DOCRAFT_LIB DocraftHaruBackend : public docraft::backend::IDocraftRenderingBackend { public: - class LineEditMethods; - class ShapeEditMethods; - class TextEditMethods; - class ImageEditMethods; - class PageEditMethods; + class LineHaruBackend; + class ShapeHaruBackend; + class TextHaruBackend; + class ImageHaruBackend; + class PageHaruBackend; /** * @brief Creates a Haru PDF backend with a new document and page. @@ -202,11 +202,11 @@ namespace docraft::backend::pdf { #pragma endregion #pragma region backend lifecycle - [[nodiscard]] const std::shared_ptr& line_edit_methods() const override; - [[nodiscard]] const std::shared_ptr& shape_edit_methods() const override; - [[nodiscard]] const std::shared_ptr& text_edit_methods() const override; - [[nodiscard]] const std::shared_ptr& image_edit_methods() const override; - [[nodiscard]] const std::shared_ptr& page_edit_methods() const override; + [[nodiscard]] const std::shared_ptr& edit_line() const override; + [[nodiscard]] const std::shared_ptr& edit_shape() const override; + [[nodiscard]] const std::shared_ptr& edit_text() const override; + [[nodiscard]] const std::shared_ptr& edit_image() const override; + [[nodiscard]] const std::shared_ptr& edit_page() const override; void save_to_file(const std::string& path) const override; [[nodiscard]] std::string file_extension() const override; @@ -302,10 +302,10 @@ namespace docraft::backend::pdf { size_t current_page_number_ = 0; mutable float fill_alpha_ = 1.0F; mutable float stroke_alpha_ = 1.0F; - std::shared_ptr line_edit_methods_; - std::shared_ptr shape_edit_methods_; - std::shared_ptr text_edit_methods_; - std::shared_ptr image_edit_methods_; - std::shared_ptr page_edit_methods_; + std::shared_ptr edit_line_; + std::shared_ptr edit_shape_; + std::shared_ptr edit_text_; + std::shared_ptr edit_image_; + std::shared_ptr edit_page_; }; } // docraft diff --git a/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc b/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc index e565d5e..f595868 100644 --- a/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc +++ b/docraft/src/docraft/backend/pdf/docraft_haru_backend.cc @@ -240,9 +240,9 @@ namespace docraft::backend::pdf { } } // namespace - class DocraftHaruBackend::LineEditMethods final : public IDocraftLineRenderingBackend { + class DocraftHaruBackend::LineHaruBackend final : public IDocraftLineRenderingBackend { public: - explicit LineEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + explicit LineHaruBackend(DocraftHaruBackend& backend) : backend_(backend) {} void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } @@ -252,9 +252,9 @@ namespace docraft::backend::pdf { DocraftHaruBackend& backend_; }; - class DocraftHaruBackend::ShapeEditMethods final : public IDocraftShapeRenderingBackend { + class DocraftHaruBackend::ShapeHaruBackend final : public IDocraftShapeRenderingBackend { public: - explicit ShapeEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + explicit ShapeHaruBackend(DocraftHaruBackend& backend) : backend_(backend) {} void save_state() const override { backend_.save_state(); } void restore_state() const override { backend_.restore_state(); } @@ -281,9 +281,9 @@ namespace docraft::backend::pdf { DocraftHaruBackend& backend_; }; - class DocraftHaruBackend::TextEditMethods final : public IDocraftTextRenderingBackend { + class DocraftHaruBackend::TextHaruBackend final : public IDocraftTextRenderingBackend { public: - explicit TextEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + explicit TextHaruBackend(DocraftHaruBackend& backend) : backend_(backend) {} void begin_text() const override { backend_.begin_text(); } void end_text() const override { backend_.end_text(); } @@ -308,9 +308,9 @@ namespace docraft::backend::pdf { DocraftHaruBackend& backend_; }; - class DocraftHaruBackend::ImageEditMethods final : public IDocraftImageRenderingBackend { + class DocraftHaruBackend::ImageHaruBackend final : public IDocraftImageRenderingBackend { public: - explicit ImageEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + explicit ImageHaruBackend(DocraftHaruBackend& backend) : backend_(backend) {} void draw_png_image( const std::string& path, @@ -371,9 +371,9 @@ namespace docraft::backend::pdf { DocraftHaruBackend& backend_; }; - class DocraftHaruBackend::PageEditMethods final : public IDocraftPageRenderingBackend { + class DocraftHaruBackend::PageHaruBackend final : public IDocraftPageRenderingBackend { public: - explicit PageEditMethods(DocraftHaruBackend& backend) : backend_(backend) {} + explicit PageHaruBackend(DocraftHaruBackend& backend) : backend_(backend) {} float page_width() const override { return backend_.page_width(); } float page_height() const override { return backend_.page_height(); } @@ -403,11 +403,11 @@ namespace docraft::backend::pdf { current_page_number_ = pages_.size() - 1; // Move to the newly created page } DocraftHaruBackend::DocraftHaruBackend() - : line_edit_methods_(std::make_shared(*this)), - shape_edit_methods_(std::make_shared(*this)), - text_edit_methods_(std::make_shared(*this)), - image_edit_methods_(std::make_shared(*this)), - page_edit_methods_(std::make_shared(*this)) { + : edit_line_(std::make_shared(*this)), + edit_shape_(std::make_shared(*this)), + edit_text_(std::make_shared(*this)), + edit_image_(std::make_shared(*this)), + edit_page_(std::make_shared(*this)) { pdf_ = HPDF_New(error_handler, NULL); if (!pdf_) { throw std::runtime_error("Failed to initialize Haru PDF document"); @@ -642,24 +642,24 @@ namespace docraft::backend::pdf { HPDF_SaveToFile(pdf_, path.c_str()); } - const std::shared_ptr& DocraftHaruBackend::line_edit_methods() const { - return line_edit_methods_; + const std::shared_ptr& DocraftHaruBackend::edit_line() const { + return edit_line_; } - const std::shared_ptr& DocraftHaruBackend::shape_edit_methods() const { - return shape_edit_methods_; + const std::shared_ptr& DocraftHaruBackend::edit_shape() const { + return edit_shape_; } - const std::shared_ptr& DocraftHaruBackend::text_edit_methods() const { - return text_edit_methods_; + const std::shared_ptr& DocraftHaruBackend::edit_text() const { + return edit_text_; } - const std::shared_ptr& DocraftHaruBackend::image_edit_methods() const { - return image_edit_methods_; + const std::shared_ptr& DocraftHaruBackend::edit_image() const { + return edit_image_; } - const std::shared_ptr& DocraftHaruBackend::page_edit_methods() const { - return page_edit_methods_; + const std::shared_ptr& DocraftHaruBackend::edit_page() const { + return edit_page_; } std::string DocraftHaruBackend::file_extension() const { diff --git a/docraft/src/docraft/docraft_document_context.cc b/docraft/src/docraft/docraft_document_context.cc index 06bcccc..aade41a 100644 --- a/docraft/src/docraft/docraft_document_context.cc +++ b/docraft/src/docraft/docraft_document_context.cc @@ -20,8 +20,8 @@ namespace docraft { DocraftDocumentContext::DocraftDocumentContext() { backend_ = std::make_shared(); - page_height_ = backend_->page_edit_methods()->page_height(); - page_width_ = backend_->page_edit_methods()->page_width(); + page_height_ = backend_->edit_page()->page_height(); + page_width_ = backend_->edit_page()->page_width(); current_rect_width_ = page_width_; } @@ -29,8 +29,8 @@ namespace docraft { DocraftDocumentContext::DocraftDocumentContext( const std::shared_ptr &backend) : backend_( backend) { - page_height_ = backend_->page_edit_methods()->page_height(); - page_width_ = backend_->page_edit_methods()->page_width(); + page_height_ = backend_->edit_page()->page_height(); + page_width_ = backend_->edit_page()->page_width(); current_rect_width_ = page_width_; } @@ -62,8 +62,8 @@ namespace docraft { void DocraftDocumentContext::set_backend(const std::shared_ptr &backend) { backend_ = backend ? backend : std::make_shared(); - page_height_ = backend_->page_edit_methods()->page_height(); - page_width_ = backend_->page_edit_methods()->page_width(); + page_height_ = backend_->edit_page()->page_height(); + page_width_ = backend_->edit_page()->page_width(); current_rect_width_ = page_width_; line_backend_.reset(); shape_backend_.reset(); @@ -131,35 +131,35 @@ namespace docraft { const std::shared_ptr &DocraftDocumentContext::line_backend() const { if (!line_backend_) { - line_backend_ = backend_->line_edit_methods(); + line_backend_ = backend_->edit_line(); } return line_backend_; } const std::shared_ptr &DocraftDocumentContext::shape_backend() const { if (!shape_backend_) { - shape_backend_ = backend_->shape_edit_methods(); + shape_backend_ = backend_->edit_shape(); } return shape_backend_; } const std::shared_ptr &DocraftDocumentContext::text_backend() const { if (!text_backend_) { - text_backend_ = backend_->text_edit_methods(); + text_backend_ = backend_->edit_text(); } return text_backend_; } const std::shared_ptr &DocraftDocumentContext::image_backend() const { if (!image_backend_) { - image_backend_ = backend_->image_edit_methods(); + image_backend_ = backend_->edit_image(); } return image_backend_; } const std::shared_ptr &DocraftDocumentContext::page_backend() const { if (!page_backend_) { - page_backend_ = backend_->page_edit_methods(); + page_backend_ = backend_->edit_page(); } return page_backend_; } diff --git a/docraft/test/docraft/backend/docraft_haru_backend_test.cc b/docraft/test/docraft/backend/docraft_haru_backend_test.cc index 2c5a78a..0cf4d03 100644 --- a/docraft/test/docraft/backend/docraft_haru_backend_test.cc +++ b/docraft/test/docraft/backend/docraft_haru_backend_test.cc @@ -34,16 +34,16 @@ TEST_F(DocraftHaruBackendTest, StartsWithSinglePageAndValidDimensions) { TEST_F(DocraftHaruBackendTest, ExposesComposedEditMethods) { auto& rendering_backend = static_cast(backend()); - ASSERT_TRUE(rendering_backend.page_edit_methods()); - ASSERT_TRUE(rendering_backend.text_edit_methods()); - ASSERT_TRUE(rendering_backend.shape_edit_methods()); - ASSERT_TRUE(rendering_backend.image_edit_methods()); - ASSERT_TRUE(rendering_backend.line_edit_methods()); + ASSERT_TRUE(rendering_backend.edit_page()); + ASSERT_TRUE(rendering_backend.edit_text()); + ASSERT_TRUE(rendering_backend.edit_shape()); + ASSERT_TRUE(rendering_backend.edit_image()); + ASSERT_TRUE(rendering_backend.edit_line()); ASSERT_TRUE(rendering_backend.can_use_font("Helvetica", nullptr)); rendering_backend.set_font("Helvetica", 12.0F, nullptr); - EXPECT_EQ(rendering_backend.page_edit_methods()->total_page_count(), 1U); - EXPECT_GT(rendering_backend.text_edit_methods()->measure_text_width("hello"), 0.0F); + EXPECT_EQ(rendering_backend.edit_page()->total_page_count(), 1U); + EXPECT_GT(rendering_backend.edit_text()->measure_text_width("hello"), 0.0F); } TEST_F(DocraftHaruBackendTest, MoveToNextPage) { diff --git a/docraft/test/docraft/utils/docraft_mock_rendering_backend.h b/docraft/test/docraft/utils/docraft_mock_rendering_backend.h index 13a7d3f..bb8c65d 100644 --- a/docraft/test/docraft/utils/docraft_mock_rendering_backend.h +++ b/docraft/test/docraft/utils/docraft_mock_rendering_backend.h @@ -9,9 +9,9 @@ namespace docraft::test::utils { class MockRenderingBackend : public backend::IDocraftRenderingBackend { public: - class LineEditMethods final : public backend::IDocraftLineRenderingBackend { + class LineHaruBackend final : public backend::IDocraftLineRenderingBackend { public: - explicit LineEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + explicit LineHaruBackend(MockRenderingBackend& backend) : backend_(backend) {} void set_stroke_color(float r, float g, float b) const override { backend_.set_stroke_color(r, g, b); } void set_line_width(float thickness) const override { backend_.set_line_width(thickness); } @@ -23,9 +23,9 @@ namespace docraft::test::utils { MockRenderingBackend& backend_; }; - class ShapeEditMethods final : public backend::IDocraftShapeRenderingBackend { + class ShapeHaruBackend final : public backend::IDocraftShapeRenderingBackend { public: - explicit ShapeEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + explicit ShapeHaruBackend(MockRenderingBackend& backend) : backend_(backend) {} void save_state() const override { backend_.save_state(); } void restore_state() const override { backend_.restore_state(); } @@ -54,9 +54,9 @@ namespace docraft::test::utils { MockRenderingBackend& backend_; }; - class TextEditMethods final : public backend::IDocraftTextRenderingBackend { + class TextHaruBackend final : public backend::IDocraftTextRenderingBackend { public: - explicit TextEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + explicit TextHaruBackend(MockRenderingBackend& backend) : backend_(backend) {} void begin_text() const override { backend_.begin_text(); } void end_text() const override { backend_.end_text(); } @@ -85,9 +85,9 @@ namespace docraft::test::utils { MockRenderingBackend& backend_; }; - class ImageEditMethods final : public backend::IDocraftImageRenderingBackend { + class ImageHaruBackend final : public backend::IDocraftImageRenderingBackend { public: - explicit ImageEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + explicit ImageHaruBackend(MockRenderingBackend& backend) : backend_(backend) {} void draw_png_image(const std::string &path, float x, float y, float width, float height) const override { backend_.draw_png_image(path, x, y, width, height); @@ -138,9 +138,9 @@ namespace docraft::test::utils { MockRenderingBackend& backend_; }; - class PageEditMethods final : public backend::IDocraftPageRenderingBackend { + class PageHaruBackend final : public backend::IDocraftPageRenderingBackend { public: - explicit PageEditMethods(MockRenderingBackend& backend) : backend_(backend) {} + explicit PageHaruBackend(MockRenderingBackend& backend) : backend_(backend) {} float page_width() const override { return backend_.page_width(); } float page_height() const override { return backend_.page_height(); } @@ -173,11 +173,11 @@ namespace docraft::test::utils { explicit MockRenderingBackend(Config config) : config_(std::move(config)), - line_edit_methods_(std::make_shared(*this)), - shape_edit_methods_(std::make_shared(*this)), - text_edit_methods_(std::make_shared(*this)), - image_edit_methods_(std::make_shared(*this)), - page_edit_methods_(std::make_shared(*this)) { + edit_line_(std::make_shared(*this)), + edit_shape_(std::make_shared(*this)), + edit_text_(std::make_shared(*this)), + edit_image_(std::make_shared(*this)), + edit_page_(std::make_shared(*this)) { pages_ = config_.initial_pages > 0 ? config_.initial_pages : 1; current_page_ = 0; } @@ -214,24 +214,24 @@ namespace docraft::test::utils { void draw_raw_rgb_image(const std::string &, int, int, float, float, float, float) const {} void draw_raw_rgb_image_from_memory(const unsigned char *, int, int, float, float, float, float) const {} - [[nodiscard]] const std::shared_ptr& line_edit_methods() const override { - return line_edit_methods_; + [[nodiscard]] const std::shared_ptr& edit_line() const override { + return edit_line_; } - [[nodiscard]] const std::shared_ptr& shape_edit_methods() const override { - return shape_edit_methods_; + [[nodiscard]] const std::shared_ptr& edit_shape() const override { + return edit_shape_; } - [[nodiscard]] const std::shared_ptr& text_edit_methods() const override { - return text_edit_methods_; + [[nodiscard]] const std::shared_ptr& edit_text() const override { + return edit_text_; } - [[nodiscard]] const std::shared_ptr& image_edit_methods() const override { - return image_edit_methods_; + [[nodiscard]] const std::shared_ptr& edit_image() const override { + return edit_image_; } - [[nodiscard]] const std::shared_ptr& page_edit_methods() const override { - return page_edit_methods_; + [[nodiscard]] const std::shared_ptr& edit_page() const override { + return edit_page_; } void save_to_file(const std::string &path) const override { last_saved_path_ = path; } @@ -304,10 +304,10 @@ namespace docraft::test::utils { std::size_t pages_ = 1; std::size_t current_page_ = 0; mutable std::string last_saved_path_; - std::shared_ptr line_edit_methods_; - std::shared_ptr shape_edit_methods_; - std::shared_ptr text_edit_methods_; - std::shared_ptr image_edit_methods_; - std::shared_ptr page_edit_methods_; + std::shared_ptr edit_line_; + std::shared_ptr edit_shape_; + std::shared_ptr edit_text_; + std::shared_ptr edit_image_; + std::shared_ptr edit_page_; }; } // namespace docraft::test::utils From 3ff222e9ebf96128b3d9cf57d20dec4b6dbb3846 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 05:57:42 +0000 Subject: [PATCH 4/4] Align contributor docs with edit_* backend naming --- doc/project-doc/contributors/architecture.md | 4 ++-- .../contributors/components/backend-integration.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/project-doc/contributors/architecture.md b/doc/project-doc/contributors/architecture.md index 392d021..68c0d98 100644 --- a/doc/project-doc/contributors/architecture.md +++ b/doc/project-doc/contributors/architecture.md @@ -146,7 +146,7 @@ Metadata lifecycle: - Node model remains backend-agnostic. - Rendering is split into renderer + painters for separation of concerns. - Layout uses chain-of-responsibility handlers to keep node-specific rules isolated. -- Context caches sub-backend interfaces (`text_backend()`, `shape_backend()`, etc.) using backend composition getters (`*_edit_methods()`). +- Context caches sub-backend interfaces (`text_backend()`, `shape_backend()`, etc.) using backend composition getters (`edit_*()`). - `DocraftDocument::render()` is the main orchestration point and intentionally centralizes pipeline sequencing. ## 5. Extension points @@ -158,7 +158,7 @@ Primary extension points for contributors: - Add a new backend primitive: - extend interfaces + implement in backend + consume in painters. - Add a new backend implementation: - - implement `IDocraftRenderingBackend` and expose composed interface objects through `*_edit_methods()` getters. + - implement `IDocraftRenderingBackend` and expose composed interface objects through `edit_*()` getters. - Add new templating capability: - extend `DocraftTemplateEngine::template_node` + helper methods. diff --git a/doc/project-doc/contributors/components/backend-integration.md b/doc/project-doc/contributors/components/backend-integration.md index c16b5e7..05130de 100644 --- a/doc/project-doc/contributors/components/backend-integration.md +++ b/doc/project-doc/contributors/components/backend-integration.md @@ -27,7 +27,7 @@ A backend must implement `IDocraftRenderingBackend`, which exposes composed edit - metadata application, - font registration and font selection hooks. -In practice you implement one concrete class inheriting `IDocraftRenderingBackend` and return small composed objects from the `*_edit_methods()` getters. +In practice you implement one concrete class inheriting `IDocraftRenderingBackend` and return small composed objects from the `edit_*()` getters. ## 3. External integration (recommended path)