From 51c41786d594c1cff1daa99256733f856a5e68c6 Mon Sep 17 00:00:00 2001 From: poire-z Date: Tue, 26 Apr 2022 14:45:44 +0200 Subject: [PATCH] PageMap: allow building synthetic pages numbers Add a method (available to frontends) to build a synthetic page map, with a new page number every N chars. This could allow a frontend to show stable page numbers, that do not change with the rendering. --- crengine/include/lvtinydom.h | 18 +++++++++-- crengine/src/epubfmt.cpp | 7 +++-- crengine/src/lvtinydom.cpp | 58 +++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/crengine/include/lvtinydom.h b/crengine/include/lvtinydom.h index 68f206eb8..3c8799e4f 100644 --- a/crengine/include/lvtinydom.h +++ b/crengine/include/lvtinydom.h @@ -2306,10 +2306,13 @@ class LVPageMapItem /// PageMapItems container class LVPageMap { - friend class LVDocView; + friend class ldomDocument; private: ldomDocument * _doc; int _valid_for_visible_page_numbers; + int _chars_per_synthetic_page; // non-0 means this pagemap has synthetic pages + bool _is_document_provided; + bool _has_document_provided; lString32 _source; LVPtrVector _children; void addPage( LVPageMapItem * item ) { @@ -2341,12 +2344,21 @@ class LVPageMap _valid_for_visible_page_numbers = visible_page_numbers; } void invalidatePageInfo() { _valid_for_visible_page_numbers = 0; } + // Whether this page map comes from the document itself + void setIsDocumentProvided( bool is_document_provided ) { + _is_document_provided = is_document_provided; + if ( _is_document_provided ) // If this was called once with true, the document provides some pagemap + _has_document_provided = true; + } + bool isDocumentProvided() const { return _is_document_provided; } + bool hasDocumentProvided() const { return _has_document_provided; } + int isSynthetic() const { return _chars_per_synthetic_page; } // Page source (info about the book paper version the page labels reference) void setSource( lString32 source ) { _source = source; } lString32 getSource() const { return _source; } // root node constructor LVPageMap( ldomDocument * doc ) - : _doc(doc), _valid_for_visible_page_numbers(0) { } + : _doc(doc), _valid_for_visible_page_numbers(0), _chars_per_synthetic_page(0), _is_document_provided(false), _has_document_provided(false) { } ~LVPageMap() { clear(); } }; @@ -2513,6 +2525,8 @@ class ldomDocument : public lxmlDocBase /// returns pointer to PageMapItems container LVPageMap * getPageMap() { return &m_pagemap; } + /// generate synthetic page map + void buildSyntheticPageMap( int chars_per_synthetic_page ); #if BUILD_LITE!=1 bool isTocFromCacheValid() { return _toc_from_cache_valid; } diff --git a/crengine/src/epubfmt.cpp b/crengine/src/epubfmt.cpp index cc6fd5063..a9e7a8bea 100644 --- a/crengine/src/epubfmt.cpp +++ b/crengine/src/epubfmt.cpp @@ -1551,8 +1551,11 @@ bool ImportEpubDocument( LVStreamRef stream, ldomDocument * m_doc, LVDocViewCall } } - if ( m_doc->getPageMap()->getChildCount() > 0 && !pageMapSource.empty() ) - m_doc->getPageMap()->setSource(pageMapSource); + if ( m_doc->getPageMap()->getChildCount() > 0 ) { + m_doc->getPageMap()->setIsDocumentProvided(true); + if ( !pageMapSource.empty() ) + m_doc->getPageMap()->setSource(pageMapSource); + } writer.OnTagClose(U"", U"body"); writer.OnStop(); diff --git a/crengine/src/lvtinydom.cpp b/crengine/src/lvtinydom.cpp index 8f329e3ef..6dcb630b1 100644 --- a/crengine/src/lvtinydom.cpp +++ b/crengine/src/lvtinydom.cpp @@ -88,7 +88,7 @@ extern const int gDOMVersionCurrent = DOM_VERSION_CURRENT; /// change in case of incompatible changes in swap/cache file format to avoid using incompatible swap file // increment to force complete reload/reparsing of old file -#define CACHE_FILE_FORMAT_VERSION "3.05.67k" +#define CACHE_FILE_FORMAT_VERSION "3.05.68k" /// increment following value to force re-formatting of old book after load #define FORMATTING_VERSION_ID 0x002D @@ -19966,6 +19966,48 @@ void ldomDocument::buildAlternativeToc() _toc_from_cache_valid = false; // to force update of page numbers } +void ldomDocument::buildSyntheticPageMap( int chars_per_synthetic_page ) +{ + m_pagemap._is_document_provided = false; + if ( m_pagemap._chars_per_synthetic_page == chars_per_synthetic_page ) { + return; // already done + } + m_pagemap.clear(); + if ( chars_per_synthetic_page <= 0 ) { + m_pagemap._chars_per_synthetic_page = 0; + return; + } + printf("CRE: building synthetic page map (%d)\n", chars_per_synthetic_page); + m_pagemap._chars_per_synthetic_page = chars_per_synthetic_page; + ldomXPointerEx xp = ldomXPointerEx( getRootNode(), 0 ); + int page_num = 0; + int count = 0; // chars needed until new page + // We loop thru all text nodes, whether visible or not (as visiblity can be changed + // with styles, and we want this to be stable) + while ( xp.nextText() ) { + // But skip text from elements which would by default be hidden (