external/pdfium/UnpackedTarball_pdfium.mk |    1 
 external/pdfium/extractpatterns.patch     |  183 ++++++++++++++++++++++++++++++
 include/vcl/filter/PDFiumLibrary.hxx      |    6 
 sd/qa/unit/data/pdf/pattern-fill.pdf      |binary
 sd/qa/unit/data/pdf/pattern-stroke.pdf    |binary
 sd/qa/unit/export-tests.cxx               |   42 ++++++
 svx/source/inc/svdpdf.hxx                 |   12 +
 svx/source/svdraw/svdpdf.cxx              |   91 ++++++++++++--
 vcl/source/pdf/PDFiumLibrary.cxx          |   34 +++++
 9 files changed, 354 insertions(+), 15 deletions(-)

New commits:
commit 0a5a3cb93308973d38a37b6ec983ecd6b57c748e
Author:     Caolán McNamara <[email protected]>
AuthorDate: Thu Oct 16 16:06:38 2025 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Tue Oct 21 08:50:11 2025 +0200

    extract fill/stroke patterns as bitmaps
    
    We can apply fill patterns as tiled bitmap fill.
    
    For strokes/text-color apply center color of pattern as the color to
    use.
    
    Change-Id: I123184d19363c0f0e0a2988108efdb71ff3d34f4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192552
    Reviewed-by: Miklos Vajna <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/external/pdfium/UnpackedTarball_pdfium.mk 
b/external/pdfium/UnpackedTarball_pdfium.mk
index b86756f35743..8da991373c8c 100644
--- a/external/pdfium/UnpackedTarball_pdfium.mk
+++ b/external/pdfium/UnpackedTarball_pdfium.mk
@@ -24,6 +24,7 @@ pdfium_patches += tounicodeinfo.patch.1
 
 # TODO, attempt upstream
 pdfium_patches += ofz451333752.patch
+pdfium_patches += extractpatterns.patch
 
 $(eval $(call gb_UnpackedTarball_UnpackedTarball,pdfium))
 
diff --git a/external/pdfium/extractpatterns.patch 
b/external/pdfium/extractpatterns.patch
new file mode 100644
index 000000000000..f742c30d949b
--- /dev/null
+++ b/external/pdfium/extractpatterns.patch
@@ -0,0 +1,183 @@
+--- core/fpdfapi/page/cpdf_pattern.h   2025-10-17 15:44:08.393532043 +0100
++++ core/fpdfapi/page/cpdf_pattern.h   2025-10-17 15:44:12.020459390 +0100
+@@ -26,6 +26,7 @@
+   virtual CPDF_ShadingPattern* AsShadingPattern();
+ 
+   const CFX_Matrix& pattern_to_form() const { return m_Pattern2Form; }
++  RetainPtr<CPDF_Object> pattern_obj() const { return m_pPatternObj; }
+ 
+  protected:
+   CPDF_Pattern(CPDF_Document* pDoc,
+@@ -35,7 +36,6 @@
+ 
+   // All the getters that return pointers return non-NULL pointers.
+   CPDF_Document* document() const { return m_pDocument; }
+-  RetainPtr<CPDF_Object> pattern_obj() const { return m_pPatternObj; }
+   const CFX_Matrix& parent_matrix() const { return m_ParentMatrix; }
+ 
+   void SetPatternToFormMatrix();
+--- fpdfsdk/fpdf_edittext.cpp  2025-10-17 15:44:08.410532151 +0100
++++ fpdfsdk/fpdf_edittext.cpp  2025-10-17 15:55:18.804847559 +0100
+@@ -13,6 +13,9 @@
+ #include "core/fpdfapi/font/cpdf_cidfont.h"
+ #include "core/fpdfapi/font/cpdf_font.h"
+ #include "core/fpdfapi/page/cpdf_docpagedata.h"
++#include "core/fpdfapi/page/cpdf_form.h"
++#include "core/fpdfapi/page/cpdf_pathobject.h"
++#include "core/fpdfapi/page/cpdf_tilingpattern.h"
+ #include "core/fpdfapi/page/cpdf_textobject.h"
+ #include "core/fpdfapi/page/cpdf_textstate.h"
+ #include "core/fpdfapi/parser/cpdf_array.h"
+@@ -834,6 +835,108 @@
+   return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak());
+ }
+ 
++FPDF_BITMAP
++FPDFPageObj_GetRenderedPattern(CPDF_Pattern& pattern,
++                               CPDF_Document& doc,
++                               CPDF_PageObject& pageObj,
++                               CPDF_Page* optional_page) {
++  CPDF_TilingPattern* pTilingPattern = pattern.AsTilingPattern();
++  if (!pTilingPattern)
++      return nullptr;
++  const std::unique_ptr<CPDF_Form> pPatternForm = 
pTilingPattern->Load(&pageObj);
++  if (!pPatternForm)
++    return nullptr;
++  RetainPtr<const CPDF_Dictionary> pDict = pattern.pattern_obj()->GetDict();
++  CFX_FloatRect pattern_bbox = pDict->GetRectFor("BBox");
++
++  // `rect` has to use integer values. Round up as needed.
++  const FX_RECT rect = pattern_bbox.GetOuterRect();
++  if (rect.IsEmpty())
++    return nullptr;
++
++  auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
++  if (!result_bitmap->Create(rect.Width(), rect.Height(),
++                             FXDIB_Format::kBgra)) {
++    return nullptr;
++  }
++  CFX_FloatRect cell_bbox = 
pattern.pattern_to_form().TransformRect(pattern_bbox);
++  CFX_FloatRect bitmap_rect(0.0f, 0.0f, rect.Width(), rect.Height());
++  CFX_Matrix mtPattern2Bitmap;
++  mtPattern2Bitmap.MatchRect(bitmap_rect, cell_bbox);
++
++  CFX_DefaultRenderDevice bitmap_device;
++  bitmap_device.AttachWithBackdropAndGroupKnockout(
++      result_bitmap, /*pBackdropBitmap=*/nullptr, /*bGroupKnockout=*/true);
++
++  CPDF_RenderOptions options;
++  if (!pTilingPattern->colored())
++    options.SetColorMode(CPDF_RenderOptions::kAlpha);
++  options.GetOptions().bForceHalftone = true;
++
++  CPDF_RenderContext context(&doc, nullptr, nullptr);
++  context.AppendLayer(pPatternForm.get(), mtPattern2Bitmap);
++  context.Render(&bitmap_device, nullptr, &options, nullptr);
++
++  CHECK(!result_bitmap->IsPremultiplied());
++
++  // Caller takes ownership.
++  return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak());
++}
++
++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
++FPDFPageObj_GetRenderedStrokePattern(FPDF_DOCUMENT document,
++                                     FPDF_PAGE page,
++                                     FPDF_PAGEOBJECT page_object) {
++  CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
++  if (!doc)
++    return nullptr;
++
++  CPDF_Page* optional_page = CPDFPageFromFPDFPage(page);
++  if (optional_page && optional_page->GetDocument() != doc)
++    return nullptr;
++
++  CPDF_PageObject* object = CPDFPageObjectFromFPDFPageObject(page_object);
++  if (!object)
++    return nullptr;
++
++  const CPDF_Color* stroke = object->color_state().GetStrokeColor();
++  if (!stroke || !stroke->IsPattern())
++    return nullptr;
++
++  RetainPtr<CPDF_Pattern> pattern = stroke->GetPattern();
++  if (!pattern)
++    return nullptr;
++
++  return FPDFPageObj_GetRenderedPattern(*pattern, *doc, *object, 
optional_page);
++}
++
++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
++FPDFPageObj_GetRenderedFillPattern(FPDF_DOCUMENT document,
++                                   FPDF_PAGE page,
++                                   FPDF_PAGEOBJECT page_object) {
++  CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
++  if (!doc)
++    return nullptr;
++
++  CPDF_Page* optional_page = CPDFPageFromFPDFPage(page);
++  if (optional_page && optional_page->GetDocument() != doc)
++    return nullptr;
++
++  CPDF_PageObject* object = CPDFPageObjectFromFPDFPageObject(page_object);
++  if (!object)
++    return nullptr;
++
++  const CPDF_Color* fill = object->color_state().GetFillColor();
++  if (!fill || !fill->IsPattern())
++    return nullptr;
++
++  RetainPtr<CPDF_Pattern> pattern = fill->GetPattern();
++  if (!pattern)
++    return nullptr;
++
++  return FPDFPageObj_GetRenderedPattern(*pattern, *doc, *object, 
optional_page);
++}
++
+ FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
+   // Take back ownership from caller and release.
+   RetainPtr<CPDF_Font>().Unleak(CPDFFontFromFPDFFont(font));
+--- public/fpdf_edit.h 2025-10-17 15:44:08.415888612 +0100
++++ public/fpdf_edit.h 2025-10-17 15:44:12.022555158 +0100
+@@ -1417,6 +1417,41 @@
+                               float scale);
+ 
+ // Experimental API.
++// Get a bitmap rasterization of the stroke pattern of |page object|.
++// To render correctly, the caller must provide the |document| associated with
++// |page_object|. If there is a |page| associated with |page_object|, the
++// caller should provide that as well.  The returned bitmap will be owned by
++// the caller, and FPDFBitmap_Destroy() must be called on the returned bitmap
++// when it is no longer needed.
++//
++//   document     - handle to a document associated with |page_object|.
++//   page         - handle to an optional page associated with |page_object|.
++//   page_object - handle to a page object.
++//
++// Returns the bitmap or NULL if the stroke is not a pattern or on failure.
++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
++FPDFPageObj_GetRenderedStrokePattern(FPDF_DOCUMENT document,
++                                     FPDF_PAGE page,
++                                     FPDF_PAGEOBJECT page_object);
++
++// Get a bitmap rasterization of the fill pattern of |page object|.
++// To render correctly, the caller must provide the |document| associated with
++// |page_object|. If there is a |page| associated with |page_object|, the
++// caller should provide that as well.  The returned bitmap will be owned by
++// the caller, and FPDFBitmap_Destroy() must be called on the returned bitmap
++// when it is no longer needed.
++//
++//   document     - handle to a document associated with |page_object|.
++//   page         - handle to an optional page associated with |page_object|.
++//   page_object - handle to a page object.
++//
++// Returns the bitmap or NULL if the fill is not a pattern or on failure.
++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
++FPDFPageObj_GetRenderedFillPattern(FPDF_DOCUMENT document,
++                                   FPDF_PAGE page,
++                                   FPDF_PAGEOBJECT page_object);
++
++// Experimental API.
+ // Get the font of a text object.
+ //
+ // text - the handle to the text object.
diff --git a/include/vcl/filter/PDFiumLibrary.hxx 
b/include/vcl/filter/PDFiumLibrary.hxx
index be1f4866ec7f..4665172068d0 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -165,8 +165,14 @@ public:
     virtual bool getFontProperties(FontWeight& weight) = 0;
     virtual PDFTextRenderMode getTextRenderMode() = 0;
     virtual Color getFillColor() = 0;
+    virtual std::unique_ptr<PDFiumBitmap> 
getRenderedFillPattern(PDFiumDocument& rDoc,
+                                                                 PDFiumPage& 
rPage)
+        = 0;
     virtual Color getStrokeColor() = 0;
     virtual double getStrokeWidth() = 0;
+    virtual std::unique_ptr<PDFiumBitmap> 
getRenderedStrokePattern(PDFiumDocument& rDoc,
+                                                                   PDFiumPage& 
rPage)
+        = 0;
     // Path
     virtual int getPathSegmentCount() = 0;
     virtual std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) = 0;
diff --git a/sd/qa/unit/data/pdf/pattern-fill.pdf 
b/sd/qa/unit/data/pdf/pattern-fill.pdf
new file mode 100644
index 000000000000..d5c4f0acebf9
Binary files /dev/null and b/sd/qa/unit/data/pdf/pattern-fill.pdf differ
diff --git a/sd/qa/unit/data/pdf/pattern-stroke.pdf 
b/sd/qa/unit/data/pdf/pattern-stroke.pdf
new file mode 100644
index 000000000000..ce26b39e295c
Binary files /dev/null and b/sd/qa/unit/data/pdf/pattern-stroke.pdf differ
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index 753b6e0e365f..13b97f0bf33b 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -1223,6 +1223,48 @@ CPPUNIT_TEST_FIXTURE(SdExportTest, 
testExplodedPdfEmbeddedFonts)
                          "and @loext:font-style='normal']/office:binary-data");
 }
 
+CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfPatternStroke)
+{
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+    if (!pPdfium)
+        return;
+    UsePdfium aGuard;
+
+    loadFromFile(u"pdf/pattern-stroke.pdf");
+
+    
setFilterOptions("{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}");
+    save(u"OpenDocument Drawing Flat XML"_ustr);
+
+    xmlDocUniquePtr pXmlDoc = parseExportedFile();
+
+    // ensure the stroke color is this redish color, and not gray which is 
what it
+    // defaults to if the stroke pattern isn't taken into account.
+    assertXPath(pXmlDoc, 
"/office:document/office:automatic-styles/style:style[@style:name='gr1']/"
+                         
"style:graphic-properties[@svg:stroke-color='#ed1b2d']");
+}
+
+CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfPatternFill)
+{
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+    if (!pPdfium)
+        return;
+    UsePdfium aGuard;
+
+    loadFromFile(u"pdf/pattern-fill.pdf");
+
+    
setFilterOptions("{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}");
+    save(u"OpenDocument Drawing Flat XML"_ustr);
+
+    xmlDocUniquePtr pXmlDoc = parseExportedFile();
+
+    // ensure the stroke color is this redish color, and not gray which is 
what it
+    // defaults to if the stroke pattern isn't taken into account.
+    assertXPath(pXmlDoc, 
"/office:document/office:automatic-styles/style:style[@style:name='gr1']/"
+                         "style:graphic-properties[@style:repeat='repeat' and "
+                         "@draw:fill-image-width='1.27cm' and 
@draw:fill-image-height='1.27cm' and "
+                         "@draw:fill-image-name='Bitmap_20_1']");
+}
+
 CPPUNIT_TEST_FIXTURE(SdExportTest, testEmbeddedText)
 {
     createSdDrawDoc("objectwithtext.fodg");
diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx
index fbea79b404fb..73d43ebee2fb 100644
--- a/svx/source/inc/svdpdf.hxx
+++ b/svx/source/inc/svdpdf.hxx
@@ -109,6 +109,8 @@ class ImpSdrPdfImport final
     sal_Int32 mnLineWidth;
     static constexpr css::drawing::LineCap gaLineCap = 
css::drawing::LineCap_BUTT;
     XDash maDash;
+    std::optional<Color> moFillColor;
+    std::optional<BitmapEx> moFillPattern;
 
     bool mbMov;
     bool mbSize;
@@ -147,17 +149,25 @@ class ImpSdrPdfImport final
     void checkClip();
     bool isClip() const;
 
+    Color getStrokeColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
+                         std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage);
+    Color getFillColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
+                       std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage);
+
     void ImportPdfObject(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
+                         std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage,
                          std::unique_ptr<vcl::pdf::PDFiumTextPage> const& 
pTextPage,
                          int nPageObjectIndex);
     void ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
+                    std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage,
                     std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
                     int nPageObjectIndex);
     void ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
                      int nPageObjectIndex);
     void ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
-                    int nPageObjectIndex);
+                    std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, int 
nPageObjectIndex);
     void ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& 
pPageObject,
+                    std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage,
                     std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
                     int nPageObjectIndex);
     void InsertTextObject(const Point& rPos, const Size& rSize, const 
OUString& rStr,
diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx
index 629f770c1d3a..4d1bf340573e 100644
--- a/svx/source/svdraw/svdpdf.cxx
+++ b/svx/source/svdraw/svdpdf.cxx
@@ -32,6 +32,7 @@
 #include <editeng/udlnitem.hxx>
 #include <editeng/crossedoutitem.hxx>
 #include <editeng/shdditem.hxx>
+#include <svx/xflbmsxy.hxx>
 #include <svx/xlnclit.hxx>
 #include <svx/xlncapit.hxx>
 #include <svx/xlnwtit.hxx>
@@ -128,7 +129,6 @@ ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, 
SdrLayerID nLay, const tools:
     mpVD->SetMapMode(MapMode(MapUnit::Map100thMM));
     mpVD->EnableOutput(false);
     mpVD->SetLineColor();
-    mpVD->SetFillColor();
 
     // Get TextBounds relative to baseline
     vcl::Font aFnt = mpVD->GetFont();
@@ -379,7 +379,7 @@ void ImpSdrPdfImport::DoObjects(SvdProgressInfo* 
pProgrInfo, sal_uInt32* pAction
     for (int nPageObjectIndex = 0; nPageObjectIndex < nPageObjectCount; 
++nPageObjectIndex)
     {
         auto pPageObject = pPdfPage->getObject(nPageObjectIndex);
-        ImportPdfObject(pPageObject, pTextPage, nPageObjectIndex);
+        ImportPdfObject(pPageObject, pPdfPage, pTextPage, nPageObjectIndex);
         if (pProgrInfo && pActionsToReport)
         {
             (*pActionsToReport)++;
@@ -552,10 +552,29 @@ void ImpSdrPdfImport::SetAttributes(SdrObject* pObj, bool 
bForceTextAttr)
 
     if (bFill)
     {
-        if (mpVD->IsFillColor())
+        bool doFill
+            = mpVD->GetDrawMode() != DrawModeFlags::NoFill && (moFillColor || 
moFillPattern);
+        if (doFill && moFillColor)
+            doFill = !moFillColor->IsTransparent();
+        if (doFill)
         {
-            mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
-            mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor()));
+            if (moFillColor)
+            {
+                mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
+                mpFillAttr->Put(XFillColorItem(OUString(), *moFillColor));
+            }
+            else
+            {
+                assert(moFillPattern && "pattern should exist");
+                mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+                mpFillAttr->Put(XFillBitmapItem(OUString(), 
Graphic(*moFillPattern)));
+                mpFillAttr->Put(XFillBmpStretchItem(false));
+                mpFillAttr->Put(XFillBmpTileItem(true));
+                mpFillAttr->Put(
+                    
XFillBmpSizeXItem(convertPointToMm100(moFillPattern->GetSizePixel().Width())));
+                mpFillAttr->Put(
+                    
XFillBmpSizeYItem(convertPointToMm100(moFillPattern->GetSizePixel().Height())));
+            }
         }
         else
         {
@@ -874,6 +893,7 @@ void ImpSdrPdfImport::checkClip()
 bool ImpSdrPdfImport::isClip() const { return !maClip.getB2DRange().isEmpty(); 
}
 void ImpSdrPdfImport::ImportPdfObject(
     std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+    std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage,
     std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int 
nPageObjectIndex)
 {
     if (!pPageObject)
@@ -883,10 +903,10 @@ void ImpSdrPdfImport::ImportPdfObject(
     switch (ePageObjectType)
     {
         case vcl::pdf::PDFPageObjectType::Text:
-            ImportText(pPageObject, pTextPage, nPageObjectIndex);
+            ImportText(pPageObject, pPage, pTextPage, nPageObjectIndex);
             break;
         case vcl::pdf::PDFPageObjectType::Path:
-            ImportPath(pPageObject, nPageObjectIndex);
+            ImportPath(pPageObject, pPage, nPageObjectIndex);
             break;
         case vcl::pdf::PDFPageObjectType::Image:
             ImportImage(pPageObject, nPageObjectIndex);
@@ -895,7 +915,7 @@ void ImpSdrPdfImport::ImportPdfObject(
             SAL_WARN("sd.filter", "Got page object SHADING: " << 
nPageObjectIndex);
             break;
         case vcl::pdf::PDFPageObjectType::Form:
-            ImportForm(pPageObject, pTextPage, nPageObjectIndex);
+            ImportForm(pPageObject, pPage, pTextPage, nPageObjectIndex);
             break;
         default:
             SAL_WARN("sd.filter", "Unknown PDF page object #" << 
nPageObjectIndex << " of type: "
@@ -905,6 +925,7 @@ void ImpSdrPdfImport::ImportPdfObject(
 }
 
 void ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> 
const& pPageObject,
+                                 std::unique_ptr<vcl::pdf::PDFiumPage> const& 
pPage,
                                  std::unique_ptr<vcl::pdf::PDFiumTextPage> 
const& pTextPage,
                                  int /*nPageObjectIndex*/)
 {
@@ -918,7 +939,7 @@ void 
ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> con
     {
         auto pFormObject = pPageObject->getFormObject(nIndex);
 
-        ImportPdfObject(pFormObject, pTextPage, -1);
+        ImportPdfObject(pFormObject, pPage, pTextPage, -1);
     }
 
     // Restore the old one.
@@ -1754,7 +1775,39 @@ EmbeddedFontInfo 
ImpSdrPdfImport::convertToOTF(SubSetInfo& rSubSetInfo, const OU
 
 #endif
 
+// There isn't, as far as I know, a way to stroke with a pattern at the moment,
+// so extract some sensible color if this is a stroke pattern
+Color ImpSdrPdfImport::getStrokeColor(
+    std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+    std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage)
+{
+    if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap
+        = pPageObject->getRenderedStrokePattern(*mpPdfDocument, *pPage))
+    {
+        BitmapEx aBitmap(bitmap->createBitmapFromBuffer());
+        return aBitmap.GetPixelColor(aBitmap.GetSizePixel().Width() / 2,
+                                     aBitmap.GetSizePixel().Height() / 2);
+    }
+    return pPageObject->getStrokeColor();
+}
+
+// Typically for a fill pattern you want to use some pattern fill equivalent
+// but if that's not possible then this fallback can be useful
+Color 
ImpSdrPdfImport::getFillColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> 
const& pPageObject,
+                                    std::unique_ptr<vcl::pdf::PDFiumPage> 
const& pPage)
+{
+    if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap
+        = pPageObject->getRenderedFillPattern(*mpPdfDocument, *pPage))
+    {
+        BitmapEx aBitmap(bitmap->createBitmapFromBuffer());
+        return aBitmap.GetPixelColor(aBitmap.GetSizePixel().Width() / 2,
+                                     aBitmap.GetSizePixel().Height() / 2);
+    }
+    return pPageObject->getFillColor();
+}
+
 void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> 
const& pPageObject,
+                                 std::unique_ptr<vcl::pdf::PDFiumPage> const& 
pPage,
                                  std::unique_ptr<vcl::pdf::PDFiumTextPage> 
const& pTextPage,
                                  int /*nPageObjectIndex*/)
 {
@@ -1844,7 +1897,8 @@ void 
ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> con
     }
     if (bUse)
     {
-        Color aColor = bFill ? pPageObject->getFillColor() : 
pPageObject->getStrokeColor();
+        Color aColor
+            = bFill ? getFillColor(pPageObject, pPage) : 
getStrokeColor(pPageObject, pPage);
         if (aColor != COL_TRANSPARENT)
             aTextColor = aColor.GetRGBColor();
     }
@@ -1979,6 +2033,7 @@ void 
ImpSdrPdfImport::ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> co
 }
 
 void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> 
const& pPageObject,
+                                 std::unique_ptr<vcl::pdf::PDFiumPage> const& 
pPage,
                                  int /*nPageObjectIndex*/)
 {
     auto aPathMatrix = pPageObject->getMatrix();
@@ -2074,12 +2129,20 @@ void 
ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> con
             mpVD->SetDrawMode(DrawModeFlags::NoFill);
     }
 
-    mpVD->SetFillColor(pPageObject->getFillColor());
-
-    if (bStroke)
+    if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap
+        = pPageObject->getRenderedFillPattern(*mpPdfDocument, *pPage))
     {
-        mpVD->SetLineColor(pPageObject->getStrokeColor());
+        moFillPattern = bitmap->createBitmapFromBuffer();
+        moFillColor.reset();
     }
+    else
+    {
+        moFillColor = pPageObject->getFillColor();
+        moFillPattern.reset();
+    }
+
+    if (bStroke)
+        mpVD->SetLineColor(getStrokeColor(pPageObject, pPage));
     else
         mpVD->SetLineColor(COL_TRANSPARENT);
 
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index 1307cf12795c..cb2ff7f377a5 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -426,8 +426,12 @@ public:
     bool getFontProperties(FontWeight& weight) override;
     PDFTextRenderMode getTextRenderMode() override;
     Color getFillColor() override;
+    std::unique_ptr<PDFiumBitmap> getRenderedFillPattern(PDFiumDocument& rDoc,
+                                                         PDFiumPage& rPage) 
override;
     Color getStrokeColor() override;
     double getStrokeWidth() override;
+    std::unique_ptr<PDFiumBitmap> getRenderedStrokePattern(PDFiumDocument& 
rDoc,
+                                                           PDFiumPage& rPage) 
override;
     // Path
     int getPathSegmentCount() override;
     std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) override;
@@ -1362,6 +1366,36 @@ std::unique_ptr<PDFiumBitmap> 
PDFiumPageObjectImpl::getImageBitmap()
     return pPDFiumBitmap;
 }
 
+std::unique_ptr<PDFiumBitmap> 
PDFiumPageObjectImpl::getRenderedStrokePattern(PDFiumDocument& rDoc,
+                                                                             
PDFiumPage& rPage)
+{
+    auto& rDocImpl = static_cast<PDFiumDocumentImpl&>(rDoc);
+    auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage);
+    std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
+    FPDF_BITMAP pBitmap = FPDFPageObj_GetRenderedStrokePattern(
+        rDocImpl.getPointer(), rPageImpl.getPointer(), mpPageObject);
+    if (pBitmap)
+    {
+        pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap);
+    }
+    return pPDFiumBitmap;
+}
+
+std::unique_ptr<PDFiumBitmap> 
PDFiumPageObjectImpl::getRenderedFillPattern(PDFiumDocument& rDoc,
+                                                                           
PDFiumPage& rPage)
+{
+    auto& rDocImpl = static_cast<PDFiumDocumentImpl&>(rDoc);
+    auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage);
+    std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
+    FPDF_BITMAP pBitmap = 
FPDFPageObj_GetRenderedFillPattern(rDocImpl.getPointer(),
+                                                             
rPageImpl.getPointer(), mpPageObject);
+    if (pBitmap)
+    {
+        pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap);
+    }
+    return pPDFiumBitmap;
+}
+
 bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& rFillMode, bool& rStroke)
 {
     auto nFillMode = static_cast<int>(rFillMode);

Reply via email to