diff options
author | László Németh <nemeth@numbertext.org> | 2024-11-05 12:40:40 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2024-11-06 17:46:59 +0100 |
commit | 3056c75db5b2a8a945621349fea9ee1183872989 (patch) | |
tree | 55fa447665353f3f520791d317a5dc6a8871dc7e /vcl/source | |
parent | 315180b2a3977aadb0de3ff6d20774e87eaf9ffd (diff) |
tdf#95239 sw: fix wrong order of PDF ToC, if headings put in text frames
PDF outlines (called also as PDF bookmarks or ToC) contained headings in
the wrong order if they were placed in a text frame:
Heading 2 (frame) ... 2
Heading 3 (frame) ... 2
Heading 1 ........... 1
Now PDF export didn't list text frame headings only at the start of the
ToC, but in their correct position and hierarchy, based on the page
and vertical position of the headings:
Heading 1 ................ 1
Heading 2 (frame) ...... 2
Heading 3 (frame) ... 2
This is useful for the recently implemented inline headings, where
e.g. APA Style Heading 4 and Heading 5 are there in text frames
anchored as characters, see tdf#48459.
Extend PDFium test environment for bookmarks, and add tdf#131728 DOCX
and an APA Style .fodt unit tests.
Note: if the higher headings are only in text frames, but not the
lower ones, only the order corrected, but not the full hierarchy, yet.
This is a follow-up to commit d87cf67f8f3346a1e380383917a3a4552fd9248e
"tdf#131728 sw inline heading: fix missing/broken DOCX export",
commit a1dcbd1d1ce6071d48bb5df26d7839aeb21b75a8
"tdf#48459 sw inline heading: add Inline Heading frame style" and
commit 49765a9e7be41d4908729ff7d838755276b244cb
"tdf#48459 tdf#131728 sw inline heading: new frame style: fix DOCX
export".
Change-Id: I87dffb9244d8aea553c98bf16c70955bb9b732d3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176050
Reviewed-by: László Németh <nemeth@numbertext.org>
Tested-by: Jenkins
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/pdf/PDFiumLibrary.cxx | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index dd7abd5defd5..f48d02595453 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -26,6 +26,7 @@ #include <tools/stream.hxx> #include <tools/UnitConversion.hxx> #include <o3tl/string_view.hxx> +#include <rtl/ustrbuf.hxx> #include <vcl/BitmapWriteAccess.hxx> #include <vcl/bitmapex.hxx> @@ -484,6 +485,7 @@ public: std::unique_ptr<PDFiumPage> openPage(int nIndex) override; std::unique_ptr<PDFiumSignature> getSignature(int nIndex) override; std::vector<unsigned int> getTrailerEnds() override; + OUString getBookmarks() override; }; class PDFiumImpl : public PDFium @@ -746,6 +748,56 @@ std::vector<unsigned int> PDFiumDocumentImpl::getTrailerEnds() return aTrailerEnds; } +static void lcl_getBookmarks(int nLevel, OUStringBuffer& rBuf, FPDF_DOCUMENT pDoc, + FPDF_BOOKMARK pBookmark) +{ + // no first child or too much levels + if (!pBookmark || nLevel > 10) + return; + + OUString aString; + int nBytes = FPDFBookmark_GetTitle(pBookmark, nullptr, 0); + assert(nBytes % 2 == 0); + nBytes /= 2; + + std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nBytes]); + + int nActualBytes = FPDFBookmark_GetTitle(pBookmark, pText.get(), nBytes * 2); + assert(nActualBytes % 2 == 0); + nActualBytes /= 2; + if (nActualBytes > 1) + { +#if defined OSL_BIGENDIAN + // The data returned by FPDFTextObj_GetText is documented to always be UTF-16LE: + for (int i = 0; i != nActualBytes; ++i) + { + pText[i] = OSL_SWAPWORD(pText[i]); + } +#endif + // insert nLevel spaces before the title + rBuf.append(OUString(" ").subView(0, nLevel)); + aString = OUString(pText.get()); + } + + rBuf.append(aString); + rBuf.append("\n"); + + // get children + lcl_getBookmarks(nLevel + 1, rBuf, pDoc, FPDFBookmark_GetFirstChild(pDoc, pBookmark)); + + // get siblings + while (nullptr != (pBookmark = FPDFBookmark_GetNextSibling(pDoc, pBookmark))) + lcl_getBookmarks(nLevel, rBuf, pDoc, pBookmark); +} + +OUString PDFiumDocumentImpl::getBookmarks() +{ + OUStringBuffer aBuf; + FPDF_BOOKMARK pBookmark = FPDFBookmark_GetFirstChild(mpPdfDocument, nullptr); + lcl_getBookmarks(0, aBuf, mpPdfDocument, pBookmark); + return aBuf.makeStringAndClear(); +} + basegfx::B2DSize PDFiumDocumentImpl::getPageSize(int nIndex) { basegfx::B2DSize aSize; |