[Libreoffice-commits] core.git: external/libepubgen filter/source include/svtools include/vcl svtools/source sw/source vcl/source writerperfect/qa writerperfect/source

Miklos Vajna vmiklos at collabora.co.uk
Tue Jan 23 08:05:28 UTC 2018


 external/libepubgen/libepubgen-epub3.patch.1                |  158 ++++++++++++
 filter/source/graphic/GraphicExportFilter.cxx               |    2 
 include/svtools/DocumentToGraphicRenderer.hxx               |   10 
 include/vcl/pdfextoutdevdata.hxx                            |    2 
 svtools/source/filter/DocumentToGraphicRenderer.cxx         |   26 +
 svtools/source/filter/exportdialog.cxx                      |    2 
 sw/source/uibase/uno/unotxdoc.cxx                           |    5 
 vcl/source/gdi/pdfextoutdevdata.cxx                         |    4 
 writerperfect/qa/unit/EPUBExportTest.cxx                    |    7 
 writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt |    7 
 writerperfect/source/writer/EPUBExportFilter.cxx            |   12 
 writerperfect/source/writer/EPUBExportFilter.hxx            |    4 
 writerperfect/source/writer/exp/xmlimp.cxx                  |   32 +-
 writerperfect/source/writer/exp/xmlimp.hxx                  |   17 -
 14 files changed, 261 insertions(+), 27 deletions(-)

New commits:
commit a54787669b9283efdfdd18b0cbafc3184cdde58f
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Jan 22 15:18:45 2018 +0100

    EPUB export, fixed layout: add chapter names to the navigation document
    
    Extend vcl::PDFExtOutDevData so that it's possible to use it outside the
    PDF export; this way the EPUB export can know which chapters start on
    which page.
    
    This means fixed and reflowable layout has the same table of contents,
    instead of just Page <N> in the fixed layout case.
    
    Change-Id: I935fb23c66ec747431b91e83b0e677d4e5f704b9
    Reviewed-on: https://gerrit.libreoffice.org/48332
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/external/libepubgen/libepubgen-epub3.patch.1 b/external/libepubgen/libepubgen-epub3.patch.1
index 4b7fe5215f05..bcec187b5218 100644
--- a/external/libepubgen/libepubgen-epub3.patch.1
+++ b/external/libepubgen/libepubgen-epub3.patch.1
@@ -197,3 +197,161 @@ index bdf3bf0..cb4efee 100644
 -- 
 2.13.6
 
+From c081609849b18113340c39a73b6af432a103a102 Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos at collabora.co.uk>
+Date: Mon, 22 Jan 2018 14:39:19 +0100
+Subject: [PATCH] fixed layout: allow defining chapter names
+
+Fixed layout normally just works with SVG images (one image / page), but
+readable navigation document is still expected, e.g. PDF provides it. So
+add a way to mention what chapters start on a given page.
+---
+ src/lib/EPUBHTMLManager.cpp        | 25 +++++++++++++++++++++++++
+ src/lib/EPUBHTMLManager.h          |  3 +++
+ src/lib/EPUBPath.cpp               | 11 +++++++++++
+ src/lib/EPUBPath.h                 |  4 ++++
+ src/lib/EPUBTextGenerator.cpp      | 15 +++++++++++++++
+ src/test/EPUBTextGeneratorTest.cpp | 37 +++++++++++++++++++++++++++++++++++++
+ 6 files changed, 95 insertions(+)
+
+diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp
+index 5e96d1d..d35bc3f 100644
+--- a/src/lib/EPUBHTMLManager.cpp
++++ b/src/lib/EPUBHTMLManager.cpp
+@@ -93,6 +93,23 @@ void EPUBHTMLManager::writeTocTo(EPUBXMLSink &sink, const EPUBPath &tocPath, int
+   {
+     for (std::vector<EPUBPath>::size_type i = 0; m_paths.size() != i; ++i)
+     {
++      const std::vector<std::string> &chapters = m_paths[i].getChapters();
++      if (!chapters.empty())
++      {
++        for (const auto &chapter : chapters)
++        {
++          sink.openElement("li");
++          librevenge::RVNGPropertyList anchorAttrs;
++          anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str());
++          sink.openElement("a", anchorAttrs);
++          std::ostringstream label;
++          sink.insertCharacters(chapter.c_str());
++          sink.closeElement("a");
++          sink.closeElement("li");
++        }
++        continue;
++      }
++
+       sink.openElement("li");
+       librevenge::RVNGPropertyList anchorAttrs;
+       anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str());
+@@ -140,6 +157,14 @@ void EPUBHTMLManager::insertHeadingText(const std::string &text)
+   m_paths.back().appendTitle(text);
+ }
+ 
++void EPUBHTMLManager::addChapterName(const std::string &text)
++{
++  if (m_paths.empty())
++    return;
++
++  m_paths.back().addChapter(text);
++}
++
+ bool EPUBHTMLManager::hasHeadingText() const
+ {
+   if (m_paths.empty())
+diff --git a/src/lib/EPUBHTMLManager.h b/src/lib/EPUBHTMLManager.h
+index 157896b..d48ddf2 100644
+--- a/src/lib/EPUBHTMLManager.h
++++ b/src/lib/EPUBHTMLManager.h
+@@ -51,6 +51,9 @@ public:
+   /// Appends text to the title of the current heading.
+   void insertHeadingText(const std::string &text);
+ 
++  /// Registers a chapter name for the current page (fixed layout case).
++  void addChapterName(const std::string &text);
++
+   /// If the current heading has a title.
+   bool hasHeadingText() const;
+ 
+diff --git a/src/lib/EPUBPath.cpp b/src/lib/EPUBPath.cpp
+index e1c05ed..be24de5 100644
+--- a/src/lib/EPUBPath.cpp
++++ b/src/lib/EPUBPath.cpp
+@@ -54,6 +54,7 @@ EPUBPath::Relative::Relative(const std::vector<std::string> &components)
+ EPUBPath::EPUBPath(const std::string &path)
+   : m_components()
+   , m_title()
++  , m_chapters()
+ {
+   const std::string trimmed(algorithm::trim_left_copy_if(path, algorithm::is_any_of("/")));
+   algorithm::split(m_components, trimmed, algorithm::is_any_of("/"), algorithm::token_compress_on);
+@@ -116,6 +117,16 @@ void EPUBPath::appendTitle(const std::string &title)
+   m_title += title;
+ }
+ 
++void EPUBPath::addChapter(const std::string &chapter)
++{
++  m_chapters.push_back(chapter);
++}
++
++const std::vector<std::string> &EPUBPath::getChapters() const
++{
++  return m_chapters;
++}
++
+ std::string EPUBPath::getTitle() const
+ {
+   return m_title;
+diff --git a/src/lib/EPUBPath.h b/src/lib/EPUBPath.h
+index 12b8f25..76f2d7b 100644
+--- a/src/lib/EPUBPath.h
++++ b/src/lib/EPUBPath.h
+@@ -51,9 +51,13 @@ public:
+   void appendTitle(const std::string &title);
+   std::string getTitle() const;
+ 
++  /// Adds chapter name (fixed layout).
++  void addChapter(const std::string &chapter);
++  const std::vector<std::string> &getChapters() const;
+ private:
+   std::vector<std::string> m_components;
+   std::string m_title;
++  std::vector<std::string> m_chapters;
+ };
+ 
+ bool operator==(const EPUBPath &left, const EPUBPath &right);
+diff --git a/src/lib/EPUBTextGenerator.cpp b/src/lib/EPUBTextGenerator.cpp
+index 8e88adb..38ddcdf 100644
+--- a/src/lib/EPUBTextGenerator.cpp
++++ b/src/lib/EPUBTextGenerator.cpp
+@@ -270,7 +270,9 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi
+ {
+   const RVNGProperty *const breakBefore = propList["fo:break-before"];
+   if (isPageBreak(breakBefore) && m_impl->getSplitGuard().splitOnPageBreak())
++  {
+     m_impl->startNewHtmlFile();
++  }
+   const RVNGProperty *const breakAfter = propList["fo:break-after"];
+   m_impl->m_breakAfterPara = isPageBreak(breakAfter);
+   if (m_impl->getSplitGuard().splitOnSize())
+@@ -282,6 +284,19 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi
+     m_impl->startNewHtmlFile();
+   m_impl->getSplitGuard().setCurrentHeadingLevel(outlineLevel ? outlineLevel->getInt() : 0);
+ 
++  if (const librevenge::RVNGPropertyListVector *chapterNames = m_impl->m_pageSpanProps.child("librevenge:chapter-names"))
++  {
++    for (unsigned long i = 0; i < chapterNames->count(); i++)
++    {
++      RVNGPropertyList const &chapter=(*chapterNames)[i];
++      const RVNGProperty *const chapterName = chapter["librevenge:name"];
++      if (!chapterName)
++        continue;
++
++      m_impl->getHtmlManager().addChapterName(chapterName->getStr().cstr());
++    }
++  }
++
+   m_impl->getSplitGuard().openLevel();
+ 
+   if (m_impl->m_inHeader || m_impl->m_inFooter)
+-- 
+2.13.6
+
diff --git a/filter/source/graphic/GraphicExportFilter.cxx b/filter/source/graphic/GraphicExportFilter.cxx
index 5990c2d001c7..8d91d4edc605 100644
--- a/filter/source/graphic/GraphicExportFilter.cxx
+++ b/filter/source/graphic/GraphicExportFilter.cxx
@@ -138,7 +138,7 @@ bool GraphicExportFilter::filterRenderDocument() const
     if (mnTargetWidth == 0 || mnTargetHeight == 0)
         aTargetSizePixel = aDocumentSizePixel;
 
-    Graphic aGraphic = aRenderer.renderToGraphic(nCurrentPage, aDocumentSizePixel, aTargetSizePixel, COL_WHITE);
+    Graphic aGraphic = aRenderer.renderToGraphic(nCurrentPage, aDocumentSizePixel, aTargetSizePixel, COL_WHITE, /*bExtOutDevData=*/false);
 
     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
 
diff --git a/include/svtools/DocumentToGraphicRenderer.hxx b/include/svtools/DocumentToGraphicRenderer.hxx
index 5ed6f2ce4434..a7af217597c7 100644
--- a/include/svtools/DocumentToGraphicRenderer.hxx
+++ b/include/svtools/DocumentToGraphicRenderer.hxx
@@ -21,6 +21,8 @@
 #ifndef INCLUDED_SVTOOLS_DOCUMENTTOGRAPHICRENDERER_HXX
 #define INCLUDED_SVTOOLS_DOCUMENTTOGRAPHICRENDERER_HXX
 
+#include <vector>
+
 #include <com/sun/star/frame/XModel.hpp>
 #include <com/sun/star/frame/XController.hpp>
 #include <com/sun/star/view/XRenderable.hpp>
@@ -51,6 +53,7 @@ class SVT_DLLPUBLIC DocumentToGraphicRenderer
     css::uno::Any                                   maSelection;
     bool                                            mbSelectionOnly;
     bool                                            mbIsWriter;
+    std::vector<OUString>                           maChapterNames;
 
     bool hasSelection() const;
 
@@ -66,13 +69,18 @@ public:
     ~DocumentToGraphicRenderer();
 
     sal_Int32 getCurrentPage();
+    /**
+     * Get list of chapter names for a page, current page is set by
+     * renderToGraphic().
+     */
+    const std::vector<OUString>& getChapterNames() const;
 
     Size getDocumentSizeInPixels( sal_Int32 nCurrentPage );
 
     Size getDocumentSizeIn100mm( sal_Int32 nCurrentPage );
 
     Graphic renderToGraphic( sal_Int32 nCurrentPage, Size aDocumentSizePixel,
-                            Size aTargetSizePixel, Color aPageColor);
+                            Size aTargetSizePixel, Color aPageColor, bool bExtOutDevData);
 
     /** Determine whether rxController has a css::view::XSelectionSupplier at
         which either a css::drawing::XShapes or css::drawing::XShape is
diff --git a/include/vcl/pdfextoutdevdata.hxx b/include/vcl/pdfextoutdevdata.hxx
index 377760d7655c..e9a2ad04fb04 100644
--- a/include/vcl/pdfextoutdevdata.hxx
+++ b/include/vcl/pdfextoutdevdata.hxx
@@ -92,6 +92,7 @@ class VCL_DLLPUBLIC PDFExtOutDevData : public ExtOutDevData
     std::unique_ptr<GlobalSyncData> mpGlobalSyncData;
 
     std::vector< PDFExtOutDevBookmarkEntry > maBookmarks;
+    std::vector<OUString> maChapterNames;
 
 public:
 
@@ -143,6 +144,7 @@ public:
     void        SetDocumentLocale( const css::lang::Locale& rLoc );
 
     std::vector< PDFExtOutDevBookmarkEntry >& GetBookmarks() { return maBookmarks;}
+    const std::vector<OUString>& GetChapterNames() { return maChapterNames; }
 
     const Graphic& GetCurrentGraphic() const;
 
diff --git a/svtools/source/filter/DocumentToGraphicRenderer.cxx b/svtools/source/filter/DocumentToGraphicRenderer.cxx
index 74275afa5c79..8d48bca87706 100644
--- a/svtools/source/filter/DocumentToGraphicRenderer.cxx
+++ b/svtools/source/filter/DocumentToGraphicRenderer.cxx
@@ -22,6 +22,7 @@
 #include <vcl/graphicfilter.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/outdev.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
 
 #include <tools/fract.hxx>
 
@@ -154,7 +155,8 @@ Graphic DocumentToGraphicRenderer::renderToGraphic(
     sal_Int32 nCurrentPage,
     Size aDocumentSizePixel,
     Size aTargetSizePixel,
-    Color aPageColor)
+    Color aPageColor,
+    bool bExtOutDevData)
 
 {
     if (!mxModel.is() || !mxController.is() || !mxRenderable.is())
@@ -171,7 +173,7 @@ Graphic DocumentToGraphicRenderer::renderToGraphic(
     double fScaleY = aTargetSizePixel.Height() / static_cast<double>(aDocumentSizePixel.Height());
 
     PropertyValues renderProps;
-    renderProps.realloc( 4 );
+    renderProps.realloc( 6 );
     renderProps[0].Name = "IsPrinter";
     renderProps[0].Value <<= true;
     renderProps[1].Name = "RenderDevice";
@@ -180,10 +182,22 @@ Graphic DocumentToGraphicRenderer::renderToGraphic(
     renderProps[2].Value <<= mxController;
     renderProps[3].Name = "RenderToGraphic";
     renderProps[3].Value <<= true;
+    renderProps[4].Name = "HasPDFExtOutDevData";
+    renderProps[4].Value <<= bExtOutDevData;
+    renderProps[5].Name = "PageRange";
+    renderProps[5].Value <<= OUString::number(nCurrentPage);
 
     GDIMetaFile aMtf;
 
     OutputDevice* pOutputDev = VCLUnoHelper::GetOutputDevice( xDevice );
+
+    vcl::PDFExtOutDevData aPDFExtOutDevData(*pOutputDev);
+    if (bExtOutDevData)
+    {
+        aPDFExtOutDevData.SetIsExportBookmarks(true);
+        pOutputDev->SetExtOutDevData(&aPDFExtOutDevData);
+    }
+
     pOutputDev->SetAntialiasing(pOutputDev->GetAntialiasing() | AntialiasingFlags::EnableB2dDraw);
     MapMode mm = pOutputDev->GetMapMode();
     mm.SetScaleX( Fraction(fScaleX) );
@@ -205,9 +219,17 @@ Graphic DocumentToGraphicRenderer::renderToGraphic(
     aMtf.WindStart();
     aMtf.SetPrefSize( aTargetSizePixel );
 
+    if (bExtOutDevData)
+        maChapterNames = aPDFExtOutDevData.GetChapterNames();
+
     return Graphic(aMtf);
 }
 
+const std::vector<OUString>& DocumentToGraphicRenderer::getChapterNames() const
+{
+    return maChapterNames;
+}
+
 sal_Int32 DocumentToGraphicRenderer::getCurrentPage()
 {
     if (hasSelection())
diff --git a/svtools/source/filter/exportdialog.cxx b/svtools/source/filter/exportdialog.cxx
index a309b748e096..931e4008dd27 100644
--- a/svtools/source/filter/exportdialog.cxx
+++ b/svtools/source/filter/exportdialog.cxx
@@ -434,7 +434,7 @@ void ExportDialog::GetGraphicStream()
                         aDocumentSizePixel );
 
                 Graphic aGraphic( aRenderer.renderToGraphic( nCurrentPage,
-                            aDocumentSizePixel, aTargetSizePixel, COL_WHITE));
+                            aDocumentSizePixel, aTargetSizePixel, COL_WHITE, /*bExtOutDevData=*/false));
                 xGraphic = aGraphic.GetXGraphic();
             }
 
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index c03857e128b6..9d2ccc5cdd11 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -2893,7 +2893,8 @@ void SAL_CALL SwXTextDocument::render(
     if (0 > nRenderer)
         throw IllegalArgumentException();
 
-    const bool bIsPDFExport = !lcl_SeqHasProperty( rxOptions, "IsPrinter" );
+    const bool bHasPDFExtOutDevData = lcl_SeqHasProperty( rxOptions, "HasPDFExtOutDevData" );
+    const bool bIsPDFExport = !lcl_SeqHasProperty( rxOptions, "IsPrinter" ) || bHasPDFExtOutDevData;
     bool bIsSwSrcView = false;
     SfxViewShell *pView = GetRenderView( bIsSwSrcView, rxOptions, bIsPDFExport );
 
@@ -2976,7 +2977,7 @@ void SAL_CALL SwXTextDocument::render(
                     SwPrintData const& rSwPrtOptions =
                         *m_pRenderData->GetSwPrtOptions();
 
-                    if (bIsPDFExport && bFirstPage && pWrtShell)
+                    if (bIsPDFExport && (bFirstPage || bHasPDFExtOutDevData) && pWrtShell)
                     {
                         SwEnhancedPDFExportHelper aHelper( *pWrtShell, *pOut, aPageRange, bIsSkipEmptyPages, false, rSwPrtOptions );
                     }
diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx
index db5b731393c9..d5197a04d41c 100644
--- a/vcl/source/gdi/pdfextoutdevdata.cxx
+++ b/vcl/source/gdi/pdfextoutdevdata.cxx
@@ -684,6 +684,10 @@ void PDFExtOutDevData::SetScreenStream(sal_Int32 nScreenId, const OUString& rURL
 
 sal_Int32 PDFExtOutDevData::CreateOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
 {
+    if (nParent == -1)
+        // Has no parent, it's a chapter / heading 1.
+        maChapterNames.push_back(rText);
+
     mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateOutlineItem );
     mpGlobalSyncData->mParaInts.push_back( nParent );
     mpGlobalSyncData->mParaOUStrings.push_back( rText );
diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx
index 176324b0dff7..47e84ebf1bbc 100644
--- a/writerperfect/qa/unit/EPUBExportTest.cxx
+++ b/writerperfect/qa/unit/EPUBExportTest.cxx
@@ -348,6 +348,13 @@ void EPUBExportTest::testEPUBFixedLayoutImplicitBreak()
     // This was missing, implicit page break (as calculated by the layout) was lost on export.
     CPPUNIT_ASSERT(mxZipFile->hasByName("OEBPS/sections/section0002.xhtml"));
     CPPUNIT_ASSERT(!mxZipFile->hasByName("OEBPS/sections/section0003.xhtml"));
+
+    // Make sure that fixed layout has chapter names in the navigation
+    // document.
+    mpXmlDoc = parseExport("OEBPS/toc.xhtml");
+    // This was 'Page 1' instead.
+    assertXPathContent(mpXmlDoc, "//xhtml:li[1]/xhtml:a", "First chapter");
+    assertXPathContent(mpXmlDoc, "//xhtml:li[2]/xhtml:a", "Second chapter");
 }
 
 void EPUBExportTest::testPageBreakSplit()
diff --git a/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt b/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt
index 6a22acd0821f..40f628b5e646 100644
--- a/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt
+++ b/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt
@@ -44,6 +44,10 @@
       <style:paragraph-properties text:number-lines="false" text:line-number="0"/>
       <style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="swiss"/>
     </style:style>
+    <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text">
+      <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" loext:contextual-spacing="false"/>
+      <style:text-properties fo:font-size="130%" fo:font-weight="bold" style:font-size-asian="130%" style:font-weight-asian="bold" style:font-size-complex="130%" style:font-weight-complex="bold"/>
+    </style:style>
   </office:styles>
   <office:automatic-styles>
     <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
@@ -65,7 +69,10 @@
   </office:master-styles>
   <office:body>
     <office:text text:use-soft-page-breaks="true">
+      <text:h text:style-name="Heading_20_1" text:outline-level="1">First chapter</text:h>
       <text:p text:style-name="P1"><text:span text:style-name="T1">He heard quiet steps behind him. That didn't bode well. Who could be following him this late at night and in this deadbeat part of town? And at this particular moment, just after he pulled off the big time and was making off with the greenbacks. Was there another crook who'd had the same idea, and was now watching him and waiting for a chance to grab the fruit of his labor? Or did the steps behind him mean that one of many law officers in town was on to him and just waiting to pounce and snap those cuffs on his wrists? He nervously looked all around. Suddenly he saw the alley. Like lightning he darted off to the left and disappeared between the two warehouses almost falling over the trash can lying in the middle of the sidewalk. He tried to nervously tap </text:span><text:soft-page-break/><text:span text:style-name="T1">his way along in the inky darkness and suddenly stiffened: it was a dead-end, he would h
 ave to go back the way he had come. The steps got louder and louder, he saw the black outline of a figure coming around the corner. Is this the end of the line?</text:span></text:p>
+      <text:h text:style-name="Heading_20_1" text:outline-level="1">Second chapter</text:h>
+      <text:p text:style-name="Standard">This is the end.</text:p>
     </office:text>
   </office:body>
 </office:document>
diff --git a/writerperfect/source/writer/EPUBExportFilter.cxx b/writerperfect/source/writer/EPUBExportFilter.cxx
index b25118350193..2e4286e1f80b 100644
--- a/writerperfect/source/writer/EPUBExportFilter.cxx
+++ b/writerperfect/source/writer/EPUBExportFilter.cxx
@@ -94,7 +94,7 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe
     if (xSourceModel.is())
         aSourceURL = xSourceModel->getURL();
 
-    std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> aPageMetafiles;
+    std::vector<exp::FixedLayoutPage> aPageMetafiles;
     if (nLayoutMethod == libepubgen::EPUB_LAYOUT_METHOD_FIXED)
         CreateMetafiles(aPageMetafiles);
 
@@ -119,7 +119,7 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe
     return xFilter->filter(rDescriptor);
 }
 
-void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &rPageMetafiles)
+void EPUBExportFilter::CreateMetafiles(std::vector<exp::FixedLayoutPage> &rPageMetafiles)
 {
     DocumentToGraphicRenderer aRenderer(mxSourceDocument, /*bSelectionOnly=*/false);
     uno::Reference<frame::XModel> xModel(mxSourceDocument, uno::UNO_QUERY);
@@ -142,7 +142,7 @@ void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_I
         Size aLogic = aRenderer.getDocumentSizeIn100mm(nPage);
         // Get the CSS pixel size of the page (mm100 -> pixel using 96 DPI, independent from system DPI).
         Size aCss(static_cast<double>(aLogic.getWidth()) / 26.4583, static_cast<double>(aLogic.getHeight()) / 26.4583);
-        Graphic aGraphic = aRenderer.renderToGraphic(nPage, aDocumentSizePixel, aCss, COL_WHITE);
+        Graphic aGraphic = aRenderer.renderToGraphic(nPage, aDocumentSizePixel, aCss, COL_WHITE, /*bExtOutDevData=*/true);
         auto &rGDIMetaFile = const_cast<GDIMetaFile &>(aGraphic.GetGDIMetaFile());
 
         // Set preferred map unit and size on the metafile, so the SVG size
@@ -156,7 +156,11 @@ void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_I
         rGDIMetaFile.Write(aMemoryStream);
         uno::Sequence<sal_Int8> aSequence(static_cast<const sal_Int8 *>(aMemoryStream.GetData()), aMemoryStream.Tell());
 
-        rPageMetafiles.emplace_back(aSequence, aCss);
+        exp::FixedLayoutPage aPage;
+        aPage.aMetafile = aSequence;
+        aPage.aCssPixels = aCss;
+        aPage.aChapterNames = aRenderer.getChapterNames();
+        rPageMetafiles.push_back(aPage);
     }
 }
 
diff --git a/writerperfect/source/writer/EPUBExportFilter.hxx b/writerperfect/source/writer/EPUBExportFilter.hxx
index 188139a32843..ee676d3e1701 100644
--- a/writerperfect/source/writer/EPUBExportFilter.hxx
+++ b/writerperfect/source/writer/EPUBExportFilter.hxx
@@ -19,7 +19,7 @@
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
 
-class Size;
+#include "exp/xmlimp.hxx"
 
 namespace writerperfect
 {
@@ -59,7 +59,7 @@ public:
 
 private:
     /// Create page metafiles in case of fixed layout.
-    void CreateMetafiles(std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &rPageMetafiles);
+    void CreateMetafiles(std::vector<exp::FixedLayoutPage> &rPageMetafiles);
 };
 
 } // namespace writerperfect
diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx
index ef681119d4cf..3ef02f69f008 100644
--- a/writerperfect/source/writer/exp/xmlimp.cxx
+++ b/writerperfect/source/writer/exp/xmlimp.cxx
@@ -238,7 +238,7 @@ public:
     rtl::Reference<XMLImportContext> CreateChildContext(const OUString &rName, const uno::Reference<xml::sax::XAttributeList> &/*xAttribs*/) override;
 
     // Handles metafile for a single page.
-    void HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &rPage, const Size &rSize, bool bFirst);
+    void HandleFixedLayoutPage(const FixedLayoutPage &rPage, bool bFirst);
 };
 
 XMLOfficeDocContext::XMLOfficeDocContext(XMLImport &rImport)
@@ -266,7 +266,7 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O
         bool bFirst = true;
         for (const auto &rPage : mrImport.GetPageMetafiles())
         {
-            HandleFixedLayoutPage(rPage.first, rPage.second, bFirst);
+            HandleFixedLayoutPage(rPage, bFirst);
             if (bFirst)
                 bFirst = false;
         }
@@ -274,7 +274,7 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O
     return nullptr;
 }
 
-void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &rPage, const Size &rSize, bool bFirst)
+void XMLOfficeDocContext::HandleFixedLayoutPage(const FixedLayoutPage &rPage, bool bFirst)
 {
     uno::Reference<uno::XComponentContext> xCtx = mrImport.GetComponentContext();
     uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(xCtx);
@@ -292,17 +292,31 @@ void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &r
     SvMemoryStream aMemoryStream;
     xSaxWriter->setOutputStream(new utl::OStreamWrapper(aMemoryStream));
 
-    xSVGWriter->write(xSaxWriter, rPage);
+    xSVGWriter->write(xSaxWriter, rPage.aMetafile);
 
-    // Have all the info, invoke libepubgen.
+    // Have all the info, invoke the generator.
     librevenge::RVNGPropertyList aPageProperties;
     // Pixel -> inch.
-    double fWidth = rSize.getWidth();
+    double fWidth = rPage.aCssPixels.getWidth();
     fWidth /= 96;
     aPageProperties.insert("fo:page-width", fWidth);
-    double fHeight = rSize.getHeight();
+    double fHeight = rPage.aCssPixels.getHeight();
     fHeight /= 96;
     aPageProperties.insert("fo:page-height", fHeight);
+
+    if (!rPage.aChapterNames.empty())
+    {
+        // Name of chapters starting on this page.
+        librevenge::RVNGPropertyListVector aChapterNames;
+        for (const auto &rName : rPage.aChapterNames)
+        {
+            librevenge::RVNGPropertyList aChapter;
+            aChapter.insert("librevenge:name", rName.toUtf8().getStr());
+            aChapterNames.append(aChapter);
+        }
+        aPageProperties.insert("librevenge:chapter-names", aChapterNames);
+    }
+
     mrImport.GetGenerator().openPageSpan(aPageProperties);
     librevenge::RVNGPropertyList aParagraphProperties;
     if (!bFirst)
@@ -320,7 +334,7 @@ void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &r
     mrImport.GetGenerator().closePageSpan();
 }
 
-XMLImport::XMLImport(const uno::Reference<uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor, const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &rPageMetafiles)
+XMLImport::XMLImport(const uno::Reference<uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor, const std::vector<FixedLayoutPage> &rPageMetafiles)
     : mrGenerator(rGenerator),
       mxContext(xContext),
       mrPageMetafiles(rPageMetafiles)
@@ -421,7 +435,7 @@ PopupState XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGProper
     return PopupState::Consumed;
 }
 
-const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &XMLImport::GetPageMetafiles() const
+const std::vector<FixedLayoutPage> &XMLImport::GetPageMetafiles() const
 {
     return mrPageMetafiles;
 }
diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx
index 246eb45dbd16..1953c7196772 100644
--- a/writerperfect/source/writer/exp/xmlimp.hxx
+++ b/writerperfect/source/writer/exp/xmlimp.hxx
@@ -23,8 +23,7 @@
 
 #include <cppuhelper/implbase.hxx>
 #include <rtl/ref.hxx>
-
-class Size;
+#include <tools/gen.hxx>
 
 namespace writerperfect
 {
@@ -33,6 +32,14 @@ namespace exp
 
 class XMLImportContext;
 
+/// Contains info about a fixed-layout page.
+struct FixedLayoutPage
+{
+    css::uno::Sequence<sal_Int8> aMetafile;
+    Size aCssPixels;
+    std::vector<OUString> aChapterNames;
+};
+
 /// States describing the result of a link -> popup conversion.
 enum class PopupState
 {
@@ -74,10 +81,10 @@ class XMLImport : public cppu::WeakImplHelper
     const css::uno::Reference<css::uno::XComponentContext> &mxContext;
     css::uno::Reference<css::uri::XUriReferenceFactory> mxUriReferenceFactory;
     OUString maMediaDir;
-    const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &mrPageMetafiles;
+    const std::vector<FixedLayoutPage> &mrPageMetafiles;
 
 public:
-    XMLImport(const css::uno::Reference<css::uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const css::uno::Sequence<css::beans::PropertyValue> &rDescriptor, const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &rPageMetafiles);
+    XMLImport(const css::uno::Reference<css::uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const css::uno::Sequence<css::beans::PropertyValue> &rDescriptor, const std::vector<FixedLayoutPage> &rPageMetafiles);
 
     rtl::Reference<XMLImportContext> CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs);
 
@@ -99,7 +106,7 @@ public:
     const librevenge::RVNGPropertyListVector &GetCoverImages();
     const librevenge::RVNGPropertyList &GetMetaData();
     PopupState FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList &rPropList);
-    const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &GetPageMetafiles() const;
+    const std::vector<FixedLayoutPage> &GetPageMetafiles() const;
     const css::uno::Reference<css::uno::XComponentContext> &GetComponentContext() const;
 
     // XDocumentHandler


More information about the Libreoffice-commits mailing list