include/vcl/pdfwriter.hxx                       |    6 +
 sw/inc/EnhancedPDFExportHelper.hxx              |   14 ++-
 sw/source/core/text/EnhancedPDFExportHelper.cxx |  107 +++++++++++++++++++++++-
 sw/source/core/text/itrpaint.cxx                |    4 
 sw/source/core/text/pormulti.cxx                |   32 ++++++-
 vcl/source/gdi/pdfwriter_impl.cxx               |   38 ++++++++
 6 files changed, 192 insertions(+), 9 deletions(-)

New commits:
commit 949f0d9cf2fe7953691160103139a16473dd3171
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Oct 24 20:05:37 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Oct 25 11:31:01 2023 +0200

    vcl,sw: PDF/UA export: produce Ruby and Warichu SEs
    
    These need to generate multiple elements in
    SwTextPainter::PaintMultiPortion() and it's not altogether obvious.
    
    Change-Id: Ib5fd36c3ea8e15dff93a87bb231c3cc4f78b0089
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158398
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index acc491efdfa9..cd8be2a50581 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -132,6 +132,7 @@ public:
 
         // inline level elements
         Span, Quote, Note, Reference, BibEntry, Code, Link, Annot,
+        Ruby, RB, RT, RP, Warichu, WT, WP,
 
         // illustration elements
         Figure, Formula, Form
@@ -146,6 +147,7 @@ public:
         TextIndent, TextAlign, Width, Height, BlockAlign, InlineAlign,
         LineHeight, BaselineShift, TextDecorationType, ListNumbering,
         RowSpan, ColSpan, Scope, Role,
+        RubyAlign, RubyPosition,
 
         // link destination is an artificial attribute that sets
         // the link annotation ID of a Link element
@@ -186,6 +188,10 @@ public:
         Row, Column, Both,
         // Role
         Rb, Cb, Pb, Tv,
+        // RubyAlign
+        RStart, RCenter, REnd, RJustify, RDistribute,
+        // RubyPosition
+        RBefore, RAfter, RWarichu, RInline,
         // ListNumbering
         Disc, Circle, Square, Decimal, UpperRoman, LowerRoman, UpperAlpha, 
LowerAlpha
     };
diff --git a/sw/inc/EnhancedPDFExportHelper.hxx 
b/sw/inc/EnhancedPDFExportHelper.hxx
index 542138157d2f..be3c45383061 100644
--- a/sw/inc/EnhancedPDFExportHelper.hxx
+++ b/sw/inc/EnhancedPDFExportHelper.hxx
@@ -113,10 +113,15 @@ struct Por_Info
 {
     const SwLinePortion& mrPor;
     const SwTextPainter& mrTextPainter;
-    bool const m_isNumberingLabel;
-
-    Por_Info(const SwLinePortion& rPor, const SwTextPainter& rTextPainer, bool 
const isNumberingLabel)
-        : mrPor(rPor), mrTextPainter(rTextPainer), 
m_isNumberingLabel(isNumberingLabel) {};
+    /** this can be used to generate multiple different SE for the same 
portion:
+      FootnoteNum: 0-> Link 1-> Lbl
+      Double: 0-> Warichu 1-> WP 2-> WT
+      Ruby: 0-> Ruby 1-> RT 2-> RB
+    */
+    int const m_Mode;
+
+    Por_Info(const SwLinePortion& rPor, const SwTextPainter& rTextPainer, int 
const nMode)
+        : mrPor(rPor), mrTextPainter(rTextPainer), m_Mode(nMode) {};
 };
 
 struct lt_TableColumn
@@ -160,6 +165,7 @@ class SwTaggedPDFHelper
     void BeginInlineStructureElements();
     void EndStructureElements();
 
+    void EndCurrentAll();
     void EndCurrentSpan();
     void CreateCurrentSpan(SwTextPaintInfo const& rInf, OUString const& 
rStyleName);
     bool CheckContinueSpan(SwTextPaintInfo const& rInf, std::u16string_view 
rStyleName, SwTextAttr const* pInetFormatAttr);
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx 
b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 999e599b4478..f9702e28b19a 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -71,6 +71,7 @@
 #include <flyfrm.hxx>
 #include <notxtfrm.hxx>
 #include "porfld.hxx"
+#include "pormulti.hxx"
 #include <SwStyleNameMapper.hxx>
 #include "itrpaint.hxx"
 #include <i18nlangtag/languagetag.hxx>
@@ -935,6 +936,51 @@ void SwTaggedPDFHelper::SetAttributes( 
vcl::PDFWriter::StructElement eType )
                 bLanguage = true;
                 break;
 
+            case vcl::PDFWriter::RT:
+                {
+                    SwRubyPortion const*const pRuby(static_cast<SwRubyPortion 
const*>(pPor));
+                    vcl::PDFWriter::StructAttributeValue nAlign = {};
+                    switch (pRuby->GetAdjustment())
+                    {
+                        case text::RubyAdjust_LEFT:
+                            nAlign = vcl::PDFWriter::RStart;
+                            break;
+                        case text::RubyAdjust_CENTER:
+                            nAlign = vcl::PDFWriter::RCenter;
+                            break;
+                        case text::RubyAdjust_RIGHT:
+                            nAlign = vcl::PDFWriter::REnd;
+                            break;
+                        case text::RubyAdjust_BLOCK:
+                            nAlign = vcl::PDFWriter::RJustify;
+                            break;
+                        case text::RubyAdjust_INDENT_BLOCK:
+                            nAlign = vcl::PDFWriter::RDistribute;
+                            break;
+                        default:
+                            assert(false);
+                            break;
+                    }
+                    ::std::optional<vcl::PDFWriter::StructAttributeValue> oPos;
+                    switch (pRuby->GetRubyPosition())
+                    {
+                        case RubyPosition::ABOVE:
+                            oPos = vcl::PDFWriter::RBefore;
+                            break;
+                        case RubyPosition::BELOW:
+                            oPos = vcl::PDFWriter::RAfter;
+                            break;
+                        case RubyPosition::RIGHT:
+                            break; // no such thing???
+                    }
+                    
mpPDFExtOutDevData->SetStructureAttribute(vcl::PDFWriter::RubyAlign, nAlign);
+                    if (oPos)
+                    {
+                        
mpPDFExtOutDevData->SetStructureAttribute(vcl::PDFWriter::RubyPosition, *oPos);
+                    }
+                }
+                break;
+
             default:
                 break;
         }
@@ -1621,6 +1667,18 @@ void SwTaggedPDFHelper::EndStructureElements()
     CheckRestoreTag();
 }
 
+void SwTaggedPDFHelper::EndCurrentAll()
+{
+    if (mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentSpan)
+    {
+        mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentSpan.reset();
+    }
+    if (mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentLink)
+    {
+        mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentLink.reset();
+    }
+}
+
 void SwTaggedPDFHelper::EndCurrentSpan()
 {
     mpPDFExtOutDevData->GetSwPDFState()->m_oCurrentSpan.reset();
@@ -1828,10 +1886,55 @@ void SwTaggedPDFHelper::BeginInlineStructureElements()
             }
             break;
 
+        case PortionType::Multi:
+            {
+                SwMultiPortion const*const pMulti(static_cast<SwMultiPortion 
const*>(pPor));
+                if (pMulti->IsRuby())
+                {
+                    EndCurrentAll();
+                    switch (mpPorInfo->m_Mode)
+                    {
+                        case 0:
+                            nPDFType = vcl::PDFWriter::Ruby;
+                            aPDFType = "Ruby";
+                        break;
+                        case 1:
+                            nPDFType = vcl::PDFWriter::RT;
+                            aPDFType = "RT";
+                        break;
+                        case 2:
+                            nPDFType = vcl::PDFWriter::RB;
+                            aPDFType = "RB";
+                        break;
+                    }
+                }
+                else if (pMulti->IsDouble())
+                {
+                    EndCurrentAll();
+                    switch (mpPorInfo->m_Mode)
+                    {
+                        case 0:
+                            nPDFType = vcl::PDFWriter::Warichu;
+                            aPDFType = "Warichu";
+                        break;
+                        case 1:
+                            nPDFType = vcl::PDFWriter::WP;
+                            aPDFType = "WP";
+                        break;
+                        case 2:
+                            nPDFType = vcl::PDFWriter::WT;
+                            aPDFType = "WT";
+                        break;
+                    }
+                }
+            }
+            break;
+
+
         // for FootnoteNum, is called twice: outer generates Lbl, inner Link
         case PortionType::FootnoteNum:
             assert(!isContinueSpan); // is at start
-            if (!mpPorInfo->m_isNumberingLabel)
+            if (mpPorInfo->m_Mode == 0)
             {   // tdf#152218 link both directions
                 nPDFType = vcl::PDFWriter::Link;
                 aPDFType = aLinkString;
@@ -1842,7 +1945,7 @@ void SwTaggedPDFHelper::BeginInlineStructureElements()
         case PortionType::Bullet:
         case PortionType::GrfNum:
             assert(!isContinueSpan); // is at start
-            if (mpPorInfo->m_isNumberingLabel)
+            if (mpPorInfo->m_Mode == 1)
             {   // only works for multiple lines via wrapper from PaintSwFrame
                 nPDFType = vcl::PDFWriter::LILabel;
                 aPDFType = aListLabelString;
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index 6d07ef7dc468..31bd418e94e2 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -415,13 +415,13 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, 
SwSaveClip &rClip,
             && !roTaggedLabel) // note: CalcPaintOfst may skip some portions
         {
             assert(isPDFTaggingEnabled);
-            Por_Info aPorInfo(*pPor, *this, true); // open Lbl
+            Por_Info aPorInfo(*pPor, *this, 1); // open Lbl
             roTaggedLabel.emplace(nullptr, nullptr, &aPorInfo, *pOut);
         }
 
         {
             // #i16816# tagged pdf support
-            Por_Info aPorInfo(*pPor, *this, false);
+            Por_Info aPorInfo(*pPor, *this, 0);
             SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, 
*pOut );
 
             if( pPor->IsMultiPortion() )
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 7a2e8c44c653..07453a4b1fcb 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -31,6 +31,7 @@
 #include <charfmt.hxx>
 #include <layfrm.hxx>
 #include <SwPortionHandler.hxx>
+#include <EnhancedPDFExportHelper.hxx>
 #include "pormulti.hxx"
 #include "inftxt.hxx"
 #include "itrpaint.hxx"
@@ -1601,6 +1602,10 @@ void SwTextPainter::PaintMultiPortion( const SwRect 
&rPaint,
 
     if( rMulti.HasBrackets() )
     {
+        // WP is mandatory
+        Por_Info const por(rMulti, *this, 1);
+        SwTaggedPDFHelper const tag(nullptr, nullptr, &por, 
*GetInfo().GetOut());
+
         TextFrameIndex const nTmpOldIdx = GetInfo().GetIdx();
         
GetInfo().SetIdx(static_cast<SwDoubleLinePortion&>(rMulti).GetBrackets()->nStart);
         SeekAndChg( GetInfo() );
@@ -1659,8 +1664,18 @@ void SwTextPainter::PaintMultiPortion( const SwRect 
&rPaint,
     OSL_ENSURE( nullptr == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
             " Only BiDi portions are allowed to use the common underlining 
font" );
 
-    if ( rMulti.IsRuby() )
+    ::std::optional<SwTaggedPDFHelper> oTag;
+    if (rMulti.IsDouble())
+    {
+        Por_Info const por(rMulti, *this, 2);
+        oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut());
+    }
+    else if (rMulti.IsRuby())
+    {
+        Por_Info const por(rMulti, *this, bRubyTop ? 1 : 2);
+        oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut());
         GetInfo().SetRuby( rMulti.OnTop() );
+    }
 
     do
     {
@@ -1822,9 +1837,20 @@ void SwTextPainter::PaintMultiPortion( const SwRect 
&rPaint,
                 // We switch to the baseline of the next inner line
                 nOfst += rMulti.GetRoot().Height();
             }
+            if (rMulti.IsRuby())
+            {
+                oTag.reset();
+                Por_Info const por(rMulti, *this, bRubyTop ? 2 : 1);
+                oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut());
+            }
         }
     } while( pPor );
 
+    if (rMulti.IsDouble())
+    {
+        oTag.reset();
+    }
+
     if ( bRubyInGrid )
         GetInfo().SetSnapToGrid( bOldGridModeAllowed );
 
@@ -1840,6 +1866,10 @@ void SwTextPainter::PaintMultiPortion( const SwRect 
&rPaint,
 
     if( rMulti.HasBrackets() )
     {
+        // WP is mandatory
+        Por_Info const por(rMulti, *this, 1);
+        SwTaggedPDFHelper const tag(nullptr, nullptr, &por, 
*GetInfo().GetOut());
+
         TextFrameIndex const nTmpOldIdx = GetInfo().GetIdx();
         
GetInfo().SetIdx(static_cast<SwDoubleLinePortion&>(rMulti).GetBrackets()->nStart);
         SeekAndChg( GetInfo() );
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 677212e15d1a..751c931ff945 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1880,6 +1880,8 @@ const char* PDFWriterImpl::getAttributeTag( 
PDFWriter::StructAttribute eAttr )
         { PDFWriter::ColSpan,           "ColSpan" },
         { PDFWriter::Scope,             "Scope" },
         { PDFWriter::Role,              "Role" },
+        { PDFWriter::RubyAlign,         "RubyAlign" },
+        { PDFWriter::RubyPosition,      "RubyPosition" },
         { PDFWriter::Type,              "Type" },
         { PDFWriter::Subtype,           "Subtype" },
         { PDFWriter::LinkAnnotation,    "LinkAnnotation" }
@@ -1928,6 +1930,15 @@ const char* PDFWriterImpl::getAttributeValueTag( 
PDFWriter::StructAttributeValue
         { PDFWriter::Cb,         "cb" },
         { PDFWriter::Pb,         "pb" },
         { PDFWriter::Tv,         "tv" },
+        { PDFWriter::RStart,     "Start" },
+        { PDFWriter::RCenter,    "Center" },
+        { PDFWriter::REnd,       "End" },
+        { PDFWriter::RJustify,   "Justify" },
+        { PDFWriter::RDistribute,"Distribute" },
+        { PDFWriter::RBefore,    "Before" },
+        { PDFWriter::RAfter,     "After" },
+        { PDFWriter::RWarichu,   "Warichu" },
+        { PDFWriter::RInline,    "Inline" },
         { PDFWriter::Disc,       "Disc" },
         { PDFWriter::Circle,     "Circle" },
         { PDFWriter::Square,     "Square" },
@@ -10687,6 +10698,13 @@ const char* PDFWriterImpl::getStructureTag( 
PDFWriter::StructElement eType )
         { PDFWriter::Code,        "Code" },
         { PDFWriter::Link,        "Link" },
         { PDFWriter::Annot,       "Annot" },
+        { PDFWriter::Ruby,        "Ruby" },
+        { PDFWriter::RB,          "RB" },
+        { PDFWriter::RT,          "RT" },
+        { PDFWriter::RP,          "RP" },
+        { PDFWriter::Warichu,     "Warichu" },
+        { PDFWriter::WT,          "WT" },
+        { PDFWriter::WP,          "WP" },
         { PDFWriter::Figure,      "Figure" },
         { PDFWriter::Formula,     "Formula"},
         { PDFWriter::Form,        "Form" }
@@ -11370,6 +11388,26 @@ bool PDFWriterImpl::setStructureAttribute( enum 
PDFWriter::StructAttribute eAttr
                     }
                 }
                 break;
+            case PDFWriter::RubyAlign:
+                if (eVal == PDFWriter::RStart || eVal == PDFWriter::RCenter || 
eVal == PDFWriter::REnd || eVal == PDFWriter::RJustify || eVal == 
PDFWriter::RDistribute)
+                {
+                    if (eType == PDFWriter::RT
+                        && PDFWriter::PDFVersion::PDF_1_5 <= 
m_aContext.Version)
+                    {
+                        bInsert = true;
+                    }
+                }
+                break;
+            case PDFWriter::RubyPosition:
+                if (eVal == PDFWriter::RBefore || eVal == PDFWriter::RAfter || 
eVal == PDFWriter::RWarichu || eVal == PDFWriter::RInline)
+                {
+                    if (eType == PDFWriter::RT
+                        && PDFWriter::PDFVersion::PDF_1_5 <= 
m_aContext.Version)
+                    {
+                        bInsert = true;
+                    }
+                }
+                break;
             case PDFWriter::ListNumbering:
                 if( eVal == PDFWriter::NONE         ||
                     eVal == PDFWriter::Disc         ||

Reply via email to