editeng/source/editeng/impedit4.cxx         |   23 +-
 editeng/source/items/svxfont.cxx            |  105 ++++-----
 include/editeng/smallcaps.hxx               |   58 +++++
 include/editeng/svxfont.hxx                 |    2 
 svx/source/svdraw/svdotextdecomposition.cxx |  322 +++++++++++++++++++---------
 5 files changed, 355 insertions(+), 155 deletions(-)

New commits:
commit ffaed5cae29d6bb14faf870cb935ccd3c35d4a3c
Author:     Caolán McNamara <[email protected]>
AuthorDate: Fri Aug 18 17:29:24 2023 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Aug 22 15:29:03 2023 +0200

    tdf#98367 implement rendering of draw/impress small capitals
    
    arising out of Þe old tdf#91932
    
    Change-Id: I953aabc280bc31ef1297dc79d483eb3d28a542f3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155846
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx
index 544d80c7d4a9..08bae76685ed 100644
--- a/editeng/source/items/svxfont.cxx
+++ b/editeng/source/items/svxfont.cxx
@@ -29,6 +29,7 @@
 #include <unotools/charclass.hxx>
 #include <com/sun/star/i18n/KCharacterType.hpp>
 #include <editeng/escapementitem.hxx>
+#include <editeng/smallcaps.hxx>
 #include <sal/log.hxx>
 #include <limits>
 
@@ -220,40 +221,6 @@ OUString SvxFont::CalcCaseMap(const OUString &rTxt) const
     return aTxt;
 }
 
-/*************************************************************************
- *                      class SvxDoCapitals
- * The virtual Method Do si called by SvxFont::DoOnCapitals alternately
- * the uppercase and lowercase parts. The derivate of SvxDoCapitals fills
- * this method with life.
- *************************************************************************/
-
-class SvxDoCapitals
-{
-protected:
-    VclPtr<OutputDevice> pOut;
-    const OUString &rTxt;
-    const sal_Int32 nIdx;
-    const sal_Int32 nLen;
-
-public:
-    SvxDoCapitals( OutputDevice *_pOut, const OUString &_rTxt,
-                   const sal_Int32 _nIdx, const sal_Int32 _nLen )
-        : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen)
-        { }
-
-    virtual ~SvxDoCapitals() {}
-
-    virtual void DoSpace( const bool bDraw );
-    virtual void SetSpace();
-    virtual void Do( const OUString &rTxt,
-                     const sal_Int32 nIdx, const sal_Int32 nLen,
-                     const bool bUpper ) = 0;
-
-    const OUString &GetTxt() const { return rTxt; }
-    sal_Int32 GetIdx() const { return nIdx; }
-    sal_Int32 GetLen() const { return nLen; }
-};
-
 void SvxDoCapitals::DoSpace( const bool /*bDraw*/ ) { }
 
 void SvxDoCapitals::SetSpace() { }
@@ -501,8 +468,13 @@ Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, 
const OUString &rTxt,
     if ( !IsCaseMap() )
         aTxtSize.setWidth( GetTextArray( pOut, rTxt, pDXArray, nIdx, nLen ) );
     else
-        aTxtSize.setWidth( GetTextArray( pOut, CalcCaseMap( rTxt ),
-                           pDXArray, nIdx, nLen ) );
+    {
+        if (IsCapital() && !rTxt.isEmpty())
+            aTxtSize = GetCapitalSize(pOut, rTxt, pDXArray, nIdx, nLen);
+        else
+            aTxtSize.setWidth( GetTextArray( pOut, CalcCaseMap( rTxt ),
+                               pDXArray, nIdx, nLen ) );
+    }
     SAL_INFO( "editeng.quicktextsize", "SvxFont::QuickGetTextSize after 
GetTextArray(): Text length: " << nLen << " Text size: " << aTxtSize.Width() << 
"x" << aTxtSize.Height());
 
     if( IsFixKerning() && ( nLen > 1 ) )
@@ -544,7 +516,7 @@ Size SvxFont::GetTextSize(const OutputDevice& rOut, const 
OUString &rTxt,
     Size aTxtSize;
     if( IsCapital() && !rTxt.isEmpty() )
     {
-        aTxtSize = GetCapitalSize(&rOut, rTxt, nIdx, nTmp);
+        aTxtSize = GetCapitalSize(&rOut, rTxt, nullptr, nIdx, nTmp);
     }
     else aTxtSize = GetPhysTxtSize(&rOut,rTxt,nIdx,nTmp);
     const_cast<OutputDevice&>(rOut).SetFont(aOldFont);
@@ -703,17 +675,27 @@ namespace {
 class SvxDoGetCapitalSize : public SvxDoCapitals
 {
 protected:
+    VclPtr<OutputDevice> pOut;
     SvxFont*    pFont;
     Size        aTxtSize;
     short       nKern;
+    KernArray*  pDXAry;
 public:
       SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
-                           const OUString &_rTxt, const sal_Int32 _nIdx,
+                           const OUString &_rTxt, KernArray* _pDXAry, const 
sal_Int32 _nIdx,
                            const sal_Int32 _nLen, const short _nKrn )
-            : SvxDoCapitals( const_cast<OutputDevice*>(_pOut), _rTxt, _nIdx, 
_nLen ),
+            : SvxDoCapitals( _rTxt, _nIdx, _nLen ),
+              pOut( const_cast<OutputDevice*>(_pOut) ),
               pFont( _pFnt ),
-              nKern( _nKrn )
-            { }
+              nKern( _nKrn ),
+              pDXAry( _pDXAry )
+    {
+        if (pDXAry)
+        {
+            pDXAry->clear();
+            pDXAry->reserve(_nLen);
+        }
+    }
 
     virtual void Do( const OUString &rTxt, const sal_Int32 nIdx,
                      const sal_Int32 nLen, const bool bUpper ) override;
@@ -727,31 +709,50 @@ void SvxDoGetCapitalSize::Do( const OUString &_rTxt, 
const sal_Int32 _nIdx,
                               const sal_Int32 _nLen, const bool bUpper )
 {
     Size aPartSize;
+    sal_uInt8 nProp(0);
     if ( !bUpper )
     {
-        sal_uInt8 nProp = pFont->GetPropr();
+        nProp = pFont->GetPropr();
         pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
         pFont->SetPhysFont( *pOut );
-        aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
-        aPartSize.setHeight( pOut->GetTextHeight() );
-        aTxtSize.setHeight( aPartSize.Height() );
-        pFont->SetPropr( nProp );
-        pFont->SetPhysFont( *pOut );
+    }
+
+    if (pDXAry)
+    {
+        KernArray aKernArray;
+        aPartSize.setWidth(pOut->GetTextArray(_rTxt, &aKernArray, _nIdx, 
_nLen));
+        assert(pDXAry->get_factor() == aKernArray.get_factor());
+        auto& dest = pDXAry->get_subunit_array();
+        sal_Int32 nStart = dest.empty() ? 0 : dest.back();
+        size_t nSrcLen = aKernArray.size();
+        dest.reserve(dest.size() + nSrcLen);
+        const auto& src = aKernArray.get_subunit_array();
+        for (size_t i = 0; i < nSrcLen; ++i)
+            dest.push_back(src[i] + nStart);
     }
     else
     {
         aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
-        aPartSize.setHeight( pOut->GetTextHeight() );
     }
+
+    aPartSize.setHeight( pOut->GetTextHeight() );
+
+    if ( !bUpper )
+    {
+        aTxtSize.setHeight( aPartSize.Height() );
+        pFont->SetPropr( nProp );
+        pFont->SetPhysFont( *pOut );
+    }
+
     aTxtSize.AdjustWidth(aPartSize.Width() );
     aTxtSize.AdjustWidth( _nLen * tools::Long( nKern ) );
 }
 
-Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt,
+Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt, 
KernArray* pDXAry,
                              const sal_Int32 nIdx, const sal_Int32 nLen) const
 {
     // Start:
-    SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, nIdx, 
nLen, GetFixKerning() );
+    SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, pDXAry, 
nIdx, nLen, GetFixKerning() );
     DoOnCapitals( aDo );
     Size aTxtSize( aDo.GetSize() );
 
@@ -769,6 +770,7 @@ namespace {
 class SvxDoDrawCapital : public SvxDoCapitals
 {
 protected:
+    VclPtr<OutputDevice> pOut;
     SvxFont *pFont;
     Point aPos;
     Point aSpacePos;
@@ -777,7 +779,8 @@ public:
     SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const OUString 
&_rTxt,
                       const sal_Int32 _nIdx, const sal_Int32 _nLen,
                       const Point &rPos, const short nKrn )
-        : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ),
+        : SvxDoCapitals( _rTxt, _nIdx, _nLen ),
+          pOut( _pOut ),
           pFont( pFnt ),
           aPos( rPos ),
           aSpacePos( rPos ),
diff --git a/include/editeng/smallcaps.hxx b/include/editeng/smallcaps.hxx
new file mode 100644
index 000000000000..8a453b1185f6
--- /dev/null
+++ b/include/editeng/smallcaps.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <editeng/editengdllapi.h>
+
+/*************************************************************************
+ *                      class SvxDoCapitals
+ * The virtual Method Do is called by SvxFont::DoOnCapitals alternately
+ * the uppercase and lowercase parts. The derivate of SvxDoCapitals fills
+ * this method with life.
+ *************************************************************************/
+
+class EDITENG_DLLPUBLIC SvxDoCapitals
+{
+protected:
+    const OUString& rTxt;
+    const sal_Int32 nIdx;
+    const sal_Int32 nLen;
+
+public:
+    SvxDoCapitals(const OUString& _rTxt, const sal_Int32 _nIdx, const 
sal_Int32 _nLen)
+        : rTxt(_rTxt)
+        , nIdx(_nIdx)
+        , nLen(_nLen)
+    {
+    }
+
+    virtual ~SvxDoCapitals() {}
+
+    virtual void DoSpace(const bool bDraw);
+    virtual void SetSpace();
+    virtual void Do(const OUString& rTxt, const sal_Int32 nIdx, const 
sal_Int32 nLen,
+                    const bool bUpper)
+        = 0;
+
+    const OUString& GetTxt() const { return rTxt; }
+    sal_Int32 GetIdx() const { return nIdx; }
+    sal_Int32 GetLen() const { return nLen; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/include/editeng/svxfont.hxx b/include/editeng/svxfont.hxx
index 0968181327e8..9fa7097d04e1 100644
--- a/include/editeng/svxfont.hxx
+++ b/include/editeng/svxfont.hxx
@@ -76,7 +76,7 @@ public:
     void SetPhysFont(OutputDevice& rOut) const;
     vcl::Font ChgPhysFont(OutputDevice& rOut) const;
 
-    Size GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt,
+    Size GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt, 
KernArray* pDXAry,
                           const sal_Int32 nIdx, const sal_Int32 nLen) const;
     void DrawCapital( OutputDevice *pOut, const Point &rPos, const OUString 
&rTxt,
                       const sal_Int32 nIdx, const sal_Int32 nLen ) const;
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx 
b/svx/source/svdraw/svdotextdecomposition.cxx
index 66c97d29b9b1..6a1a54f2321e 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -34,11 +34,13 @@
 #include <svx/xbtmpit.hxx>
 #include <basegfx/vector/b2dvector.hxx>
 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
 #include <basegfx/range/b2drange.hxx>
 #include <editeng/eeitem.hxx>
 #include <editeng/editstat.hxx>
+#include <editeng/smallcaps.hxx>
 #include <tools/helpers.hxx>
 #include <svl/itemset.hxx>
 #include <drawinglayer/animation/animationtiming.hxx>
@@ -66,6 +68,11 @@ using namespace com::sun::star;
 
 namespace
 {
+    rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
buildTextPortionPrimitive(const DrawPortionInfo& rInfo, const OUString& rText,
+                                                                               
          const drawinglayer::attribute::FontAttribute& rFontAttribute,
+                                                                               
          const std::vector<double>& rDXArray,
+                                                                               
          const basegfx::B2DHomMatrix& rNewTransform);
+
     class impTextBreakupHandler
     {
     private:
@@ -94,7 +101,6 @@ namespace
         DECL_LINK(decomposeBlockBulletPrimitive, DrawBulletInfo*, void);
         DECL_LINK(decomposeStretchBulletPrimitive, DrawBulletInfo*, void);
 
-        void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
         static rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, 
const DrawPortionInfo& rInfo);
         void impFlushTextPortionPrimitivesToLinePrimitives();
         void impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara);
@@ -146,6 +152,71 @@ namespace
         }
 
         drawinglayer::primitive2d::Primitive2DContainer 
extractPrimitive2DSequence();
+
+        void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
+    };
+
+    class DoCapitalsDrawPortionInfo : public SvxDoCapitals
+    {
+    private:
+        impTextBreakupHandler& m_rHandler;
+        const DrawPortionInfo& m_rInfo;
+        SvxFont m_aFont;
+    public:
+        DoCapitalsDrawPortionInfo(impTextBreakupHandler& rHandler, const 
DrawPortionInfo& rInfo)
+            : SvxDoCapitals(rInfo.maText, rInfo.mnTextStart, rInfo.mnTextLen)
+            , m_rHandler(rHandler)
+            , m_rInfo(rInfo)
+            , m_aFont(rInfo.mrFont)
+        {
+            assert(!m_rInfo.mpDXArray.empty());
+
+            /* turn all these off as they are handled outside subportions for 
the whole portion */
+            m_aFont.SetTransparent(false);
+            m_aFont.SetUnderline(LINESTYLE_NONE);
+            m_aFont.SetOverline(LINESTYLE_NONE);
+            m_aFont.SetStrikeout(STRIKEOUT_NONE);
+
+            m_aFont.SetCaseMap(SvxCaseMap::NotMapped); /* otherwise this would 
call itself */
+        }
+        virtual void Do( const OUString &rSpanTxt, const sal_Int32 nSpanIdx,
+                         const sal_Int32 nSpanLen, const bool bUpper ) override
+        {
+            sal_uInt8 nProp(0);
+            if (!bUpper)
+            {
+                nProp = m_aFont.GetPropr();
+                m_aFont.SetProprRel(SMALL_CAPS_PERCENTAGE);
+            }
+
+            sal_Int32 nStartOffset = nSpanIdx - nIdx;
+            sal_Int32 nStartX = nStartOffset ? m_rInfo.mpDXArray[nStartOffset 
- 1] : 0;
+
+            Point aStartPos(m_rInfo.mrStartPos.X() + nStartX, 
m_rInfo.mrStartPos.Y());
+
+            std::vector<sal_Int32> aDXArray;
+            aDXArray.reserve(nSpanLen);
+            for (sal_Int32 i = 0; i < nSpanLen; ++i)
+                aDXArray.push_back(m_rInfo.mpDXArray[nStartOffset + i] - 
nStartX);
+
+            auto aKashidaArray = !m_rInfo.mpKashidaArray.empty() ?
+                o3tl::span<const sal_Bool>(m_rInfo.mpKashidaArray.data() + 
nStartOffset, nSpanLen) :
+                o3tl::span<const sal_Bool>();
+
+            DrawPortionInfo aInfo(aStartPos, rSpanTxt,
+                                  nSpanIdx, nSpanLen,
+                                  m_aFont, m_rInfo.mnPara,
+                                  aDXArray, aKashidaArray,
+                                  nullptr, /* no spelling in subportion, 
handled outside */
+                                  nullptr, /* no field in subportion, handled 
outside */
+                                  m_rInfo.mpLocale, m_rInfo.maOverlineColor, 
m_rInfo.maTextLineColor,
+                                  m_rInfo.mnBiDiLevel, false, 0, false, false, 
false);
+
+            m_rHandler.impCreateTextPortionPrimitive(aInfo);
+
+            if (!bUpper)
+                m_aFont.SetPropr(nProp);
+        }
     };
 
     void impTextBreakupHandler::impCreateTextPortionPrimitive(const 
DrawPortionInfo& rInfo)
@@ -153,7 +224,6 @@ namespace
         if(rInfo.maText.isEmpty() || !rInfo.mnTextLen)
             return;
 
-        OUString caseMappedText = rInfo.mrFont.CalcCaseMap( rInfo.maText );
         basegfx::B2DVector aFontScaling;
         drawinglayer::attribute::FontAttribute aFontAttribute(
             drawinglayer::primitive2d::getFontAttributeFromVclFont(
@@ -222,16 +292,153 @@ namespace
         // the text transformation), scale it to unit coordinates
         ::std::vector< double > aDXArray;
 
-        if(!rInfo.mpDXArray.empty() && rInfo.mnTextLen)
+        if (!rInfo.mpDXArray.empty())
         {
             aDXArray.reserve(rInfo.mnTextLen);
-
             for(sal_Int32 a=0; a < rInfo.mnTextLen; a++)
             {
                 aDXArray.push_back(static_cast<double>(rInfo.mpDXArray[a]));
             }
         }
 
+        OUString caseMappedText = rInfo.mrFont.CalcCaseMap(rInfo.maText);
+        rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
pNewPrimitive(buildTextPortionPrimitive(rInfo, caseMappedText,
+                                                                               
                            aFontAttribute,
+                                                                               
                            aDXArray, aNewTransform));
+
+        bool bSmallCaps = rInfo.mrFont.IsCapital();
+        if (bSmallCaps && rInfo.mpDXArray.empty())
+        {
+            SAL_WARN("svx", "SmallCaps requested with DXArray, abandoning");
+            bSmallCaps = false;
+        }
+        if (bSmallCaps)
+        {
+            // rerun with each sub-portion
+            DoCapitalsDrawPortionInfo aDoDrawPortionInfo(*this, rInfo);
+            rInfo.mrFont.DoOnCapitals(aDoDrawPortionInfo);
+
+            // transfer collected primitives from maTextPortionPrimitives to a 
new container
+            drawinglayer::primitive2d::Primitive2DContainer aContainer;
+            aContainer.swap(maTextPortionPrimitives);
+
+            // Take any decoration for the whole formatted portion and keep it 
to get continous over/under/strike-through
+            if (pNewPrimitive->getPrimitive2DID() == 
PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
+            {
+                const 
drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D* pTCPP =
+                    static_cast<const 
drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D*>(pNewPrimitive.get());
+
+                pTCPP->CreateDecorationGeometryContent(
+                    aContainer,
+                    pTCPP->getTextTransform(),
+                    caseMappedText,
+                    rInfo.mnTextStart,
+                    rInfo.mnTextLen,
+                    aDXArray);
+            }
+
+            pNewPrimitive = new 
drawinglayer::primitive2d::GroupPrimitive2D(std::move(aContainer));
+        }
+
+        const Color aFontColor(rInfo.mrFont.GetColor());
+        if (aFontColor.IsTransparent())
+        {
+            // Handle semi-transparent text for both the decorated and simple 
case here.
+            pNewPrimitive = new 
drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+                drawinglayer::primitive2d::Primitive2DContainer{ pNewPrimitive 
},
+                (255 - aFontColor.GetAlpha()) / 255.0);
+        }
+
+        if(rInfo.mbEndOfBullet)
+        {
+            // embed in TextHierarchyBulletPrimitive2D
+            drawinglayer::primitive2d::Primitive2DReference 
aNewReference(pNewPrimitive);
+            drawinglayer::primitive2d::Primitive2DContainer aNewSequence { 
aNewReference } ;
+            pNewPrimitive = new 
drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(std::move(aNewSequence));
+        }
+
+        if(rInfo.mpFieldData)
+        {
+            pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive.get(), rInfo);
+        }
+
+        maTextPortionPrimitives.push_back(pNewPrimitive);
+
+        // support for WrongSpellVector. Create WrongSpellPrimitives as needed
+        if(!rInfo.mpWrongSpellVector || aDXArray.empty())
+            return;
+
+        const sal_Int32 nSize(rInfo.mpWrongSpellVector->size());
+        const sal_Int32 nDXCount(aDXArray.size());
+        const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
+
+        for(sal_Int32 a(0); a < nSize; a++)
+        {
+            const EEngineData::WrongSpellClass& rCandidate = 
(*rInfo.mpWrongSpellVector)[a];
+
+            if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= 
rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
+            {
+                const sal_Int32 nStart(rCandidate.nStart - rInfo.mnTextStart);
+                const sal_Int32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
+                double fStart(0.0);
+                double fEnd(0.0);
+
+                if(nStart > 0 && nStart - 1 < nDXCount)
+                {
+                    fStart = aDXArray[nStart - 1];
+                }
+
+                if(nEnd > 0 && nEnd - 1 < nDXCount)
+                {
+                    fEnd = aDXArray[nEnd - 1];
+                }
+
+                if(!basegfx::fTools::equal(fStart, fEnd))
+                {
+                    if(rInfo.IsRTL())
+                    {
+                        // #i98523#
+                        // When the portion is RTL, mirror the redlining using 
the
+                        // full portion width
+                        const double fTextWidth(aDXArray[aDXArray.size() - 1]);
+
+                        fStart = fTextWidth - fStart;
+                        fEnd = fTextWidth - fEnd;
+
+                        // tdf#151968
+                        // if start < end, OutputDevice::DrawWaveLine() will
+                        // think it is a rotated line, so we swap fStart and
+                        // fEnd to avoid this.
+                        std::swap(fStart, fEnd);
+                    }
+
+                    // need to take FontScaling out of values; it's already 
part of
+                    // aNewTransform and would be double applied
+                    const double fFontScaleX(aFontScaling.getX() * 
fPropFontFactor);
+
+                    if(!basegfx::fTools::equal(fFontScaleX, 1.0)
+                        && !basegfx::fTools::equalZero(fFontScaleX))
+                    {
+                        fStart /= fFontScaleX;
+                        fEnd /= fFontScaleX;
+                    }
+
+                    maTextPortionPrimitives.push_back(new 
drawinglayer::primitive2d::WrongSpellPrimitive2D(
+                        aNewTransform,
+                        fStart,
+                        fEnd,
+                        aSpellColor));
+                }
+            }
+        }
+    }
+
+    rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
buildTextPortionPrimitive(
+            const DrawPortionInfo& rInfo, const OUString& rText,
+            const drawinglayer::attribute::FontAttribute& rFontAttribute,
+            const std::vector<double>& rDXArray,
+            const basegfx::B2DHomMatrix& rNewTransform)
+    {
         ::std::vector< sal_Bool > aKashidaArray;
 
         if(!rInfo.mpKashidaArray.empty() && rInfo.mnTextLen)
@@ -321,13 +528,13 @@ namespace
             pNewPrimitive = new 
drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
 
                 // attributes for TextSimplePortionPrimitive2D
-                aNewTransform,
-                caseMappedText,
+                rNewTransform,
+                rText,
                 rInfo.mnTextStart,
                 rInfo.mnTextLen,
-                std::vector(aDXArray),
+                std::vector(rDXArray),
                 std::vector(aKashidaArray),
-                aFontAttribute,
+                rFontAttribute,
                 rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
                 aBFontColor,
                 aTextFillColor,
@@ -350,13 +557,13 @@ namespace
         {
             // TextSimplePortionPrimitive2D is enough
             pNewPrimitive = new 
drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
-                aNewTransform,
-                caseMappedText,
+                rNewTransform,
+                rText,
                 rInfo.mnTextStart,
                 rInfo.mnTextLen,
-                std::vector(aDXArray),
+                std::vector(rDXArray),
                 std::vector(aKashidaArray),
-                std::move(aFontAttribute),
+                rFontAttribute,
                 rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
                 aBFontColor,
                 rInfo.mbFilled,
@@ -364,96 +571,7 @@ namespace
                 aTextFillColor);
         }
 
-        if (aFontColor.IsTransparent())
-        {
-            // Handle semi-transparent text for both the decorated and simple 
case here.
-            pNewPrimitive = new 
drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
-                drawinglayer::primitive2d::Primitive2DContainer{ pNewPrimitive 
},
-                (255 - aFontColor.GetAlpha()) / 255.0);
-        }
-
-        if(rInfo.mbEndOfBullet)
-        {
-            // embed in TextHierarchyBulletPrimitive2D
-            drawinglayer::primitive2d::Primitive2DReference 
aNewReference(pNewPrimitive);
-            drawinglayer::primitive2d::Primitive2DContainer aNewSequence { 
aNewReference } ;
-            pNewPrimitive = new 
drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(std::move(aNewSequence));
-        }
-
-        if(rInfo.mpFieldData)
-        {
-            pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive.get(), rInfo);
-        }
-
-        maTextPortionPrimitives.push_back(pNewPrimitive);
-
-        // support for WrongSpellVector. Create WrongSpellPrimitives as needed
-        if(!rInfo.mpWrongSpellVector || aDXArray.empty())
-            return;
-
-        const sal_Int32 nSize(rInfo.mpWrongSpellVector->size());
-        const sal_Int32 nDXCount(aDXArray.size());
-        const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
-
-        for(sal_Int32 a(0); a < nSize; a++)
-        {
-            const EEngineData::WrongSpellClass& rCandidate = 
(*rInfo.mpWrongSpellVector)[a];
-
-            if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= 
rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
-            {
-                const sal_Int32 nStart(rCandidate.nStart - rInfo.mnTextStart);
-                const sal_Int32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
-                double fStart(0.0);
-                double fEnd(0.0);
-
-                if(nStart > 0 && nStart - 1 < nDXCount)
-                {
-                    fStart = aDXArray[nStart - 1];
-                }
-
-                if(nEnd > 0 && nEnd - 1 < nDXCount)
-                {
-                    fEnd = aDXArray[nEnd - 1];
-                }
-
-                if(!basegfx::fTools::equal(fStart, fEnd))
-                {
-                    if(rInfo.IsRTL())
-                    {
-                        // #i98523#
-                        // When the portion is RTL, mirror the redlining using 
the
-                        // full portion width
-                        const double fTextWidth(aDXArray[aDXArray.size() - 1]);
-
-                        fStart = fTextWidth - fStart;
-                        fEnd = fTextWidth - fEnd;
-
-                        // tdf#151968
-                        // if start < end, OutputDevice::DrawWaveLine() will
-                        // think it is a rotated line, so we swap fStart and
-                        // fEnd to avoid this.
-                        std::swap(fStart, fEnd);
-                    }
-
-                    // need to take FontScaling out of values; it's already 
part of
-                    // aNewTransform and would be double applied
-                    const double fFontScaleX(aFontScaling.getX() * 
fPropFontFactor);
-
-                    if(!basegfx::fTools::equal(fFontScaleX, 1.0)
-                        && !basegfx::fTools::equalZero(fFontScaleX))
-                    {
-                        fStart /= fFontScaleX;
-                        fEnd /= fFontScaleX;
-                    }
-
-                    maTextPortionPrimitives.push_back(new 
drawinglayer::primitive2d::WrongSpellPrimitive2D(
-                        aNewTransform,
-                        fStart,
-                        fEnd,
-                        aSpellColor));
-                }
-            }
-        }
+        return pNewPrimitive;
     }
 
     rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D*
 pPrimitive, const DrawPortionInfo& rInfo)
commit 97469c2cac442fc3231694e35a8cd7a0f8d16af4
Author:     Caolán McNamara <[email protected]>
AuthorDate: Mon Aug 21 21:42:19 2023 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Aug 22 15:28:53 2023 +0200

    Related: tdf#98367 export editeng EE_CHAR_CASEMAP the same as writer does
    
    so can cut and paste from impress/draw to writer, import already works
    
    Change-Id: Ifc35687b1f77f6519d14a71820bb635ff25a159f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155906
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/editeng/source/editeng/impedit4.cxx 
b/editeng/source/editeng/impedit4.cxx
index 34d26b1a899a..995d713c304b 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -19,8 +19,9 @@
 
 
 #include <svl/srchitem.hxx>
-#include <editeng/lspcitem.hxx>
 #include <editeng/adjustitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/lspcitem.hxx>
 #include <editeng/tstpitem.hxx>
 
 #include "eertfpar.hxx"
@@ -965,6 +966,26 @@ void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& 
rItem, SvStream& rOutput,
             rOutput.WriteNumberAsString(nUpDown);
         }
         break;
+        case EE_CHAR_CASEMAP:
+        {
+            const SvxCaseMapItem& rCaseMap = static_cast<const 
SvxCaseMapItem&>(rItem);
+            switch (rCaseMap.GetValue())
+            {
+                case SvxCaseMap::SmallCaps:
+                    rOutput.WriteOString(OOO_STRING_SVTOOLS_RTF_SCAPS);
+                    break;
+                case SvxCaseMap::Uppercase:
+                    rOutput.WriteOString(OOO_STRING_SVTOOLS_RTF_CAPS);
+                    break;
+                default: // Something that rtf does not support
+                    rOutput.WriteOString(OOO_STRING_SVTOOLS_RTF_SCAPS);
+                    rOutput.WriteNumberAsString(0);
+                    rOutput.WriteOString(OOO_STRING_SVTOOLS_RTF_CAPS);
+                    rOutput.WriteNumberAsString(0);
+                    break;
+            }
+        }
+        break;
     }
 }
 

Reply via email to