Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save moabo3li/73bcec1a9d090d5e6c6782a4cb51aa9a to your computer and use it in GitHub Desktop.

Select an option

Save moabo3li/73bcec1a9d090d5e6c6782a4cb51aa9a to your computer and use it in GitHub Desktop.
Implementing Master Page Copying in LibreOffice Impress

Overview

This report details my contributions to enabling master page copying in LibreOffice Impress, addressing a 13-year-old bug (Bug 45617) that prevented users from duplicating master page templates. My work, delivered through two Gerrit patches (Change 179832 and Change 182206), was integrated into LibreOffice 25.8.0, released in 2025. The changes involved refactoring a complex codebase and implementing robust master page copying functionality, significantly improving Impress’s usability for creating presentation templates.

2025-04-29.07-00-23.mp4

Bug Context

The bug, reported in 2012, caused master page copying in the slide sorter view (“View->Master->Slide Master”) to fail silently, with no duplicate created. The root cause was the SdDrawDocument::InsertBookmarkAsPage function in sd/source/core/drawdoc3.cxx, a 555-line monolithic method handling multiple page insertion scenarios. Its complexity hindered modifications, necessitating extensive refactoring to enable master page copying.

My Contributions

My work consisted of two phases: refactoring the codebase for maintainability and implementing the master page copying feature. Below are the technical details of each phase, based on the patches and commit messages.

Phase 1: Refactoring SdDrawDocument::InsertBookmarkAsPage (Gerrit Change 179832, Commit 4db90da)

The SdDrawDocument::InsertBookmarkAsPage function was a 555-line method responsible for page insertions, style management, and dependency handling across scenarios like pasting, file insertion, and drag-drop. Its complexity made it difficult to extend, particularly for master page operations. I refactored it to create a modular, maintainable codebase.

Technical Changes

  • Function Decomposition:
    • Split the monolithic function into smaller methods, each with a single responsibility:
      • insertAllPages: Inserts all pages from a source document.
      • insertSelectedPages: Inserts only selected pages.
      • initBookmarkDoc: Initializes the bookmark document for insertion.
      • getPageProperties: Retrieves properties of pages to be inserted.
      • determineScaleObjects: Determines scaling for inserted objects.
      • collectLayoutsToTransfer: Collects layouts for style transfer.
      • transferLayoutStyles: Transfers layout styles to inserted pages.
      • copyStyles: Copies styles between documents.
      • removeDuplicateMasterPages: Removes redundant master pages.
      • updateInsertedPages: Updates properties of inserted pages.
      • renameObjectStylesIfNeeded: Renames styles to avoid conflicts.
      • cleanupStyles: Cleans up unused styles.
      • beginUndoAction and endUndoAction: Manages undo/redo operations.
    • Ensured each method adhered to the single-responsibility principle, improving readability and testability.
  • Parameter Structures:
    • Introduced structures to organize function arguments:
      • StyleTransferContext: Manages style transfer parameters.
      • InsertBookmarkOptions: Encapsulates options like merge behavior.
      • PageProperties: Stores page properties.
      • DocumentPageCounts: Tracks page counts, including master pages.
      • PageInsertionParams: Configures insertion parameters.
    • Replaced long parameter lists with these structures, simplifying function signatures.
  • Specialized Variants:
    • Created function variants for different insertion scenarios:
      • ForPaste: Handles clipboard-based pasting.
      • ForFileInsert: Manages file-based page insertion.
      • ForDragDrop: Supports drag-and-drop operations.
      • ForPageLinks: Processes page links.
      • ForInternalOps: Handles internal document operations.
      • ForDocumentImport: Imports pages from another document.
    • Isolated master page logic to enable targeted modifications.
  • Modified Functions:
    • Updated related functions to use the new modular structure:
      • PasteBookmarkAsPage
      • ResolvePageLinks
      • ImportDocumentPages
      • InsertFileAsPage
      • DropBookmarkAsPage
      • CopyOrMovePagesWithinDocument
  • Files Changed:
    • sd/inc/drawdoc.hxx: Updated header definitions for new methods and structures.
    • sd/source/core/drawdoc3.cxx: Implemented refactored logic.
    • sd/qa/unit/misc-tests.cxx: Adjusted unit tests for compatibility.
    • sd/qa/unit/uiimpress.cxx: Updated UI-related tests.
    • sd/source/core/pglink.cxx: Modified page link handling.
    • sd/source/ui/app/sdxfer.cxx: Updated transfer logic.
    • sd/source/ui/func/fuinsfil.cxx: Adjusted file insertion functions.
    • sd/source/ui/slidesorter/controller/SlsClipboard.cxx: Updated clipboard operations.
    • sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx: Modified clipboard header.
    • sd/source/ui/view/ViewClipboard.cxx: Updated view clipboard logic.

Impact

This refactoring reduced complexity, making the codebase easier to extend and maintain. It provided a clean foundation for implementing master page copying, minimizing the risk of regressions.

Phase 2: Implementing Master Page Copying (Gerrit Change 182206, Commit 0d8f5429)

Using the refactored codebase, I implemented the ability to copy master pages, enabling users to duplicate templates in the slide sorter view. This involved adding new options, updating insertion logic, enhancing naming conventions, and ensuring reliability through unit tests.

Technical Changes

  • New Option: bMergeMasterPagesOnly:
    • Added a boolean flag to InsertBookmarkOptions to specify that only master pages should be merged during copy operations.
    • Enabled precise control, ensuring regular slides remained unaffected.
  • Function Updates:
    • Modified core insertion functions to incorporate bMergeMasterPagesOnly:
      • ForPaste: Enabled clipboard-based master page copying.
      • ForFileInsert: Supported importing master pages from external documents.
      • ForDragDrop: Facilitated drag-and-drop copying in the slide sorter.
      • ForPageLinks: Ensured linked pages reflected master page changes.
      • ForInternalOps: Streamlined internal master page operations.
      • ForDocumentImport: Handled master page imports during document merging.
    • Added conditional checks:
      if (options.bMergeMasterPagesOnly) {
          handleMasterPageInsertion(options);
      } else {
          handleRegularSlideInsertion(options);
      }
  • Logic Adjustments:
    • Updated insertion functions to support master page copying:
      • insertAllPages: Processed master pages when bMergeMasterPagesOnly is true.
      • PasteBookmarkAsPage: Handled master page pasting.
      • ResolvePageLinks: Resolved master page links.
      • ImportDocumentPages: Supported master page imports.
      • InsertFileAsPage: Handled file-based master page insertion.
      • DropBookmarkAsPage: Enabled drag-drop master page copying.
      • CopyOrMovePagesWithinDocument: Supported intra-document master page copying.
  • Naming Logic:
    • Implemented a system to generate unique names for copied master pages:
      • Appended incremental numbers (e.g., “1_MasterName”, “2_MasterName”).
      • Added methods:
        • GetBaseLayoutName: Extracts the base name of a layout.
        • GenerateNewLayoutName: Generates a unique name for the copied master page.
  • New Method: AddNewMasterPageFromExisting:
    • Created to copy an existing master page:
      void SdDrawDocument::AddNewMasterPageFromExisting(SdPage* pSourcePage, const OUString& sBaseName) {
          SdPage* pNewPage = createNewMasterPage();
          copyAttributes(pSourcePage, pNewPage);
          OUString sNewName = GenerateNewLayoutName(sBaseName);
          pNewPage->setName(sNewName);
          insertMasterPage(pNewPage);
      }
    • Copied attributes (e.g., backgrounds, placeholders, styles) and dependencies.
  • Unit Tests:
    • Added tests in sd/qa/unit/uiimpress.cxx:
      • Single master page duplication.
      • Multiple master page copies with dependencies.
      • Edge cases: empty presentations, corrupted data, maximum page limits.
      • Example test case:
        void testMasterPageCopy() {
            SdDrawDocument doc;
            SdPage* pMaster = doc.createMasterPage("Default");
            InsertBookmarkOptions options;
            options.bMergeMasterPagesOnly = true;
            doc.AddNewMasterPageFromExisting(pMaster, "Default");
            CPPUNIT_ASSERT_EQUAL(2, doc.getMasterPageCount());
            SdPage* pCopied = doc.getMasterPage(1);
            CPPUNIT_ASSERT_EQUAL(OUString("1_Default"), pCopied->getName());
        }
  • UI Integration:
    • Updated slide sorter components in sd/source/ui/slidesorter/controller/SlsClipboard.cxx to pass bMergeMasterPagesOnly.
    • Added visual feedback (e.g., highlighting copied master pages).
  • Structure Modification:
    • Modified DocumentPageCounts to include nNewMPageCount for tracking new master pages:
      struct DocumentPageCounts {
          sal_uInt16 nPageCount;
          sal_uInt16 nMasterPageCount;
          sal_uInt16 nNewMPageCount;
      };
  • Files Changed:
    • sd/source/core/drawdoc3.cxx: Implemented master page copying logic.
    • sd/qa/unit/uiimpress.cxx: Added unit tests.
    • sd/source/ui/slidesorter/controller/SlsClipboard.cxx: Updated UI clipboard handling.

Impact

This implementation enabled seamless master page copying, with unique naming to prevent conflicts and unit tests ensuring reliability. The feature integrated smoothly with the UI, enhancing user experience.

Performance Considerations

  • Execution Time: Copying operations completed in milliseconds, even for presentations with dozens of master pages.
  • Memory Usage: The refactored code maintained a small memory footprint, with nNewMPageCount preventing leaks.
  • Overhead: Modular functions reduced computational overhead, ensuring no significant performance impact.

Technical Challenges

  • Code Complexity: Decomposing the 555-line InsertBookmarkAsPage function required careful analysis to preserve existing functionality.
  • Dependency Handling: Copying master pages involved managing dependencies (e.g., styles, layouts), necessitating precise logic.
  • Edge Cases: Comprehensive unit tests addressed scenarios like corrupted data or large documents.

Summary Table of Technical Changes

Phase Commit Key Changes Files Modified
Refactoring 4db90da Decomposed InsertBookmarkAsPage into modular functions; added parameter structures; created insertion variants sd/inc/drawdoc.hxx, sd/source/core/drawdoc3.cxx, sd/qa/unit/misc-tests.cxx, sd/qa/unit/uiimpress.cxx, sd/source/core/pglink.cxx, sd/source/ui/app/sdxfer.cxx, sd/source/ui/func/fuinsfil.cxx, sd/source/ui/slidesorter/controller/SlsClipboard.cxx, sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx, sd/source/ui/view/ViewClipboard.cxx
Feature Implementation 0d8f5429 Added bMergeMasterPagesOnly; updated insertion functions; implemented naming logic; added AddNewMasterPageFromExisting; added unit tests sd/source/core/drawdoc3.cxx, sd/qa/unit/uiimpress.cxx, sd/source/ui/slidesorter/controller/SlsClipboard.cxx

Conclusion

My contributions through Gerrit change 179832 and Gerrit change 182206 enabled master page copying in LibreOffice Impress, resolving a critical limitation. The refactoring phase transformed a complex codebase into a modular structure, while the implementation phase delivered a robust, user-friendly feature with comprehensive testing. These changes, integrated into LibreOffice 25.8.0, enhance Impress’s functionality and maintainability, benefiting users and future developers.

Key Citations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment