Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/svx/source/svdraw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 31 kB image not shown  

Quelle  svdotextpathdecomposition.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * 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 .
 */


#include <sal/config.h>

#include <o3tl/safeint.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdoutl.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <algorithm>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#include <basegfx/color/bcolor.hxx>
#include <editeng/StripPortionsHelper.hxx>

// primitive decomposition helpers
#include <drawinglayer/attribute/strokeattribute.hxx>
#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <svx/unoapi.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>
#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
#include <utility>

using namespace com::sun::star;

// PathTextPortion helper

namespace
{
    class impPathTextPortion
    {
        basegfx::B2DVector                          maOffset;
        OUString                                    maText;
        sal_Int32                                   mnTextStart;
        sal_Int32                                   mnTextLength;
        sal_Int32                                   mnParagraph;
        SvxFont                                     maFont;
        ::std::vector< double >                     maDblDXArray;   // double DXArray, font size independent -> unit coordinate system
        ::std::vector< sal_Bool >                   maKashidaArray;
        lang::Locale                           maLocale;

        bool                                        mbRTL : 1;

    public:
        explicit impPathTextPortion(const DrawPortionInfo& rInfo)
        :   maOffset(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y()),
            maText(rInfo.maText),
            mnTextStart(rInfo.mnTextStart),
            mnTextLength(rInfo.mnTextLen),
            mnParagraph(rInfo.mnPara),
            maFont(rInfo.mrFont),
            maKashidaArray(rInfo.mpKashidaArray.begin(), rInfo.mpKashidaArray.end()),
            maLocale(rInfo.mpLocale ? *rInfo.mpLocale : lang::Locale()),
            mbRTL(!rInfo.mrFont.IsVertical() && rInfo.IsRTL())
        {
            if(mnTextLength && !rInfo.mpDXArray.empty())
            {
                maDblDXArray.reserve(mnTextLength);

                for(sal_Int32 a=0; a < mnTextLength; a++)
                {
                    maDblDXArray.push_back(rInfo.mpDXArray[a]);
                }
            }
        }

        // for ::std::sort
        bool operator<(const impPathTextPortion& rComp) const
        {
            if(mnParagraph < rComp.mnParagraph)
            {
                return true;
            }

            if(maOffset.getX() < rComp.maOffset.getX())
            {
                return true;
            }

            return (maOffset.getY() < rComp.maOffset.getY());
        }

        const OUString& getText() const { return maText; }
        sal_Int32 getTextStart() const { return mnTextStart; }
        sal_Int32 getTextLength() const { return mnTextLength; }
        sal_Int32 getParagraph() const { return mnParagraph; }
        const SvxFont& getFont() const { return maFont; }
        bool isRTL() const { return mbRTL; }
        const ::std::vector< double >& getDoubleDXArray() const { return maDblDXArray; }
        const ::std::vector< sal_Bool >& getKashidaArray() const { return maKashidaArray; }
        const lang::Locale& getLocale() const { return maLocale; }

        sal_Int32 getPortionIndex(sal_Int32 nIndex, sal_Int32 nLength) const
        {
            if(mbRTL)
            {
                return (mnTextStart + (mnTextLength - (nIndex + nLength)));
            }
            else
            {
                return (mnTextStart + nIndex);
            }
        }

        double getDisplayLength(sal_Int32 nIndex, sal_Int32 nLength) const
        {
            drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
            double fRetval(0.0);

            if(maFont.IsVertical())
            {
                fRetval = aTextLayouter.getTextHeight() * static_cast<double>(nLength);
            }
            else
            {
                fRetval = aTextLayouter.getTextWidth(maText, getPortionIndex(nIndex, nLength), nLength);
            }

            return fRetval;
        }
    };
// end of anonymous namespace


// TextBreakup helper

namespace
{
    class impTextBreakupHandler
    {
        SdrOutliner&                                mrOutliner;
        ::std::vector< impPathTextPortion >         maPathTextPortions;

    public:
        explicit impTextBreakupHandler(SdrOutliner& rOutliner)
        :   mrOutliner(rOutliner)
        {
        }

        const ::std::vector< impPathTextPortion >& decompositionPathTextPrimitive()
        {
            // strip portions to maPathTextPortions
            mrOutliner.StripPortions(
                [this](const DrawPortionInfo& rInfo){ maPathTextPortions.emplace_back(rInfo); },
                std::function<void(const DrawBulletInfo&)>());

            if(!maPathTextPortions.empty())
            {
                // sort portions by paragraph, x and y
                ::std::sort(maPathTextPortions.begin(), maPathTextPortions.end());
            }

            return maPathTextPortions;
        }
    };
// end of anonymous namespace


// TextBreakup one poly and one paragraph helper

namespace
{
    class impPolygonParagraphHandler
    {
        const drawinglayer::attribute::SdrFormTextAttribute         maSdrFormTextAttribute; // FormText parameters
        drawinglayer::primitive2d::Primitive2DContainer&            mrDecomposition;        // destination primitive list
        drawinglayer::primitive2d::Primitive2DContainer&            mrShadowDecomposition;  // destination primitive list for shadow
        uno::Reference<i18n::XBreakIterator>                     mxBreak;                // break iterator

        static double getParagraphTextLength(const ::std::vector< const impPathTextPortion* >&&nbsp;rTextPortions)
        {
            drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
            double fRetval(0.0);

            for(const impPathTextPortion* pCandidate : rTextPortions)
            {
                if(pCandidate && pCandidate->getTextLength())
                {
                    aTextLayouter.setFont(pCandidate->getFont());
                    fRetval += pCandidate->getDisplayLength(0, pCandidate->getTextLength());
                }
            }

            return fRetval;
        }

        sal_Int32 getNextGlyphLen(const impPathTextPortion* pCandidate, sal_Int32 nPosition, const lang::Locale& rFontLocale)
        {
            sal_Int32 nNextGlyphLen(1);

            if(mxBreak.is())
            {
                sal_Int32 nDone(0);
                nNextGlyphLen = mxBreak->nextCharacters(pCandidate->getText(), nPosition,
                    rFontLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone) - nPosition;
            }

            return nNextGlyphLen;
        }

    public:
        impPolygonParagraphHandler(
            drawinglayer::attribute::SdrFormTextAttribute aSdrFormTextAttribute,
            drawinglayer::primitive2d::Primitive2DContainer& rDecomposition,
            drawinglayer::primitive2d::Primitive2DContainer& rShadowDecomposition)
        :   maSdrFormTextAttribute(std::move(aSdrFormTextAttribute)),
            mrDecomposition(rDecomposition),
            mrShadowDecomposition(rShadowDecomposition)
        {
            // prepare BreakIterator
            const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
            mxBreak = i18n::BreakIterator::create(xContext);
        }

        void HandlePair(const basegfx::B2DPolygon& rPolygonCandidate, const ::std::vector< const impPathTextPortion* >& rTextPortions)
        {
            // prepare polygon geometry, take into account as many parameters as possible
            basegfx::B2DPolygon aPolygonCandidate(rPolygonCandidate);
            const double fPolyLength(basegfx::utils::getLength(aPolygonCandidate));
            double fPolyEnd(fPolyLength);
            double fPolyStart(0.0);
            double fAutosizeScaleFactor(1.0);
            bool bAutosizeScale(false);

            if(maSdrFormTextAttribute.getFormTextMirror())
            {
                aPolygonCandidate.flip();
            }

            if(maSdrFormTextAttribute.getFormTextStart()
                && (XFormTextAdjust::Left == maSdrFormTextAttribute.getFormTextAdjust()
                    || XFormTextAdjust::Right == maSdrFormTextAttribute.getFormTextAdjust()))
            {
                if(XFormTextAdjust::Left == maSdrFormTextAttribute.getFormTextAdjust())
                {
                    fPolyStart += maSdrFormTextAttribute.getFormTextStart();

                    if(fPolyStart > fPolyEnd)
                    {
                        fPolyStart = fPolyEnd;
                    }
                }
                else
                {
                    fPolyEnd -= maSdrFormTextAttribute.getFormTextStart();

                    if(fPolyEnd < fPolyStart)
                    {
                        fPolyEnd = fPolyStart;
                    }
                }
            }

            if(XFormTextAdjust::Left != maSdrFormTextAttribute.getFormTextAdjust())
            {
                // calculate total text length of this paragraph, some layout needs to be done
                const double fParagraphTextLength(getParagraphTextLength(rTextPortions));

                // check if text is too long for paragraph. If yes, handle as if left aligned (default),
                // but still take care of XFormTextAdjust::AutoSize in that case
                const bool bTextTooLong(fParagraphTextLength > (fPolyEnd - fPolyStart));

                if(XFormTextAdjust::Right == maSdrFormTextAttribute.getFormTextAdjust())
                {
                    if(!bTextTooLong)
                    {
                        // if right aligned, add difference to polygon start
                        fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength);
                    }
                }
                else if(XFormTextAdjust::Center == maSdrFormTextAttribute.getFormTextAdjust())
                {
                    if(!bTextTooLong)
                    {
                        // if centered, add half of difference to polygon start
                        fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength) / 2.0;
                    }
                }
                else if(XFormTextAdjust::AutoSize == maSdrFormTextAttribute.getFormTextAdjust())
                {
                    // if scale, prepare scale factor between curve length and text length
                    if(0.0 != fParagraphTextLength)
                    {
                        fAutosizeScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength;
                        bAutosizeScale = true;
                    }
                }
            }

            // handle text portions for this paragraph
            for(auto a = rTextPortions.begin(); a != rTextPortions.end() && fPolyStart < fPolyEnd; ++a)
            {
                const impPathTextPortion* pCandidate = *a;
                basegfx::B2DVector aFontScaling;

                if(pCandidate && pCandidate->getTextLength())
                {
                    const drawinglayer::attribute::FontAttribute aCandidateFontAttribute(
                        drawinglayer::primitive2d::getFontAttributeFromVclFont(
                            aFontScaling,
                            pCandidate->getFont(),
                            pCandidate->isRTL(),
                            false));

                    drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
                    aTextLayouter.setFont(pCandidate->getFont());
                    sal_Int32 nUsedTextLength(0);

                    while(nUsedTextLength < pCandidate->getTextLength() && fPolyStart < fPolyEnd)
                    {
                        sal_Int32 nNextGlyphLen(getNextGlyphLen(pCandidate, pCandidate->getTextStart() + nUsedTextLength, pCandidate->getLocale()));

                        // prepare portion length. Takes RTL sections into account.
                        double fPortionLength(pCandidate->getDisplayLength(nUsedTextLength, nNextGlyphLen));

                        if(bAutosizeScale)
                        {
                            // when autosize scaling, expand portion length
                            fPortionLength *= fAutosizeScaleFactor;
                        }

                        // create transformation
                        basegfx::B2DHomMatrix aNewTransformA, aNewTransformB, aNewShadowTransform;
                        basegfx::B2DPoint aStartPos(basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart, fPolyLength));
                        basegfx::B2DPoint aEndPos(aStartPos);

                        // add font scaling
                        aNewTransformA.scale(aFontScaling.getX(), aFontScaling.getY());

                        // prepare scaling of text primitive
                        if(bAutosizeScale)
                        {
                            // when autosize scaling, expand text primitive scaling to it
                            aNewTransformA.scale(fAutosizeScaleFactor, fAutosizeScaleFactor);
                        }

                        // eventually create shadow primitives from aDecomposition and add to rDecomposition
                        const bool bShadow(XFormTextShadow::NONE != maSdrFormTextAttribute.getFormTextShadow());

                        if(bShadow)
                        {
                            if(XFormTextShadow::Normal == maSdrFormTextAttribute.getFormTextShadow())
                            {
                                aNewShadowTransform.translate(
                                    maSdrFormTextAttribute.getFormTextShdwXVal(),
                                    -maSdrFormTextAttribute.getFormTextShdwYVal());
                            }
                            else // XFormTextShadow::Slant
                            {
                                double fScaleValue(maSdrFormTextAttribute.getFormTextShdwYVal() / 100.0);
                                double fShearValue(-basegfx::deg2rad<10>(maSdrFormTextAttribute.getFormTextShdwXVal()));

                                aNewShadowTransform.scale(1.0, fScaleValue);
                                aNewShadowTransform.shearX(sin(fShearValue));
                                aNewShadowTransform.scale(1.0, cos(fShearValue));
                            }
                        }

                        switch(maSdrFormTextAttribute.getFormTextStyle())
                        {
                            case XFormTextStyle::Rotate :
                            {
                                aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
                                const basegfx::B2DVector aDirection(aEndPos - aStartPos);
                                aNewTransformB.rotate(atan2(aDirection.getY(), aDirection.getX()));
                                aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());

                                break;
                            }
                            case XFormTextStyle::Upright :
                            {
                                aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());

                                break;
                            }
                            case XFormTextStyle::SlantX :
                            {
                                aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
                                const basegfx::B2DVector aDirection(aEndPos - aStartPos);
                                const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
                                const double fSin(sin(fShearValue));
                                const double fCos(cos(fShearValue));

                                aNewTransformB.shearX(-fSin);

                                // Scale may lead to objects without height since fCos == 0.0 is possible.
                                // Renderers need to handle that, it's not a forbidden value and does not
                                // need to be avoided
                                aNewTransformB.scale(1.0, fCos);
                                aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());

                                break;
                            }
                            case XFormTextStyle::SlantY :
                            {
                                aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
                                const basegfx::B2DVector aDirection(aEndPos - aStartPos);
                                const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
                                const double fCos(cos(fShearValue));
                                const double fTan(tan(fShearValue));

                                // shear to 'stand' on the curve
                                aNewTransformB.shearY(fTan);

                                // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
                                // lead to primitives without width which the renderers will handle
                                aNewTransformA.scale(fCos, 1.0);

                                aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());

                                break;
                            }
                            default : break// XFormTextStyle::NONE
                        }

                        // distance from path?
                        if(maSdrFormTextAttribute.getFormTextDistance())
                        {
                            if(aEndPos.equal(aStartPos))
                            {
                                aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
                            }

                            // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
                            const basegfx::B2DVector aPerpendicular(
                                basegfx::getNormalizedPerpendicular(aStartPos - aEndPos) *
                                maSdrFormTextAttribute.getFormTextDistance());
                            aNewTransformB.translate(aPerpendicular.getX(), aPerpendicular.getY());
                        }

                        if(!pCandidate->getText().isEmpty() && nNextGlyphLen)
                        {
                            const sal_Int32 nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen));
                            ::std::vector< double > aNewDXArray;

                            if(nNextGlyphLen > 1 && !pCandidate->getDoubleDXArray().empty())
                            {
                                // copy DXArray for portion
                                aNewDXArray.insert(
                                    aNewDXArray.begin(),
                                    pCandidate->getDoubleDXArray().begin() + nPortionIndex,
                                    pCandidate->getDoubleDXArray().begin() + (nPortionIndex + nNextGlyphLen));

                                if(nPortionIndex > 0)
                                {
                                    // adapt to portion start
                                    double fDXOffset= *(pCandidate->getDoubleDXArray().begin() + (nPortionIndex - 1));
                                    ::std::transform(
                                        aNewDXArray.begin(), aNewDXArray.end(),
                                        aNewDXArray.begin(), [fDXOffset](double x) { return x - fDXOffset; });
                                }

                                if(bAutosizeScale)
                                {
                                    // when autosize scaling, adapt to DXArray, too
                                    ::std::transform(
                                        aNewDXArray.begin(), aNewDXArray.end(),
                                        aNewDXArray.begin(), [fAutosizeScaleFactor](double x) { return x * fAutosizeScaleFactor; });
                                }
                            }

                            if(bShadow)
                            {
                                // shadow primitive creation
                                const Color aShadowColor(maSdrFormTextAttribute.getFormTextShdwColor());
                                const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());

                                mrShadowDecomposition.push_back(
                                    new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
                                        aNewTransformB * aNewShadowTransform * aNewTransformA,
                                        pCandidate->getText(),
                                        nPortionIndex,
                                        nNextGlyphLen,
                                        std::vector(aNewDXArray),
                                        std::vector(pCandidate->getKashidaArray()),
                                        aCandidateFontAttribute,
                                        pCandidate->getLocale(),
                                        aRGBShadowColor) );
                            }

                            {
                                // primitive creation
                                const Color aColor(pCandidate->getFont().GetColor());
                                const basegfx::BColor aRGBColor(aColor.getBColor());

                                mrDecomposition.push_back(
                                    new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
                                        aNewTransformB * aNewTransformA,
                                        pCandidate->getText(),
                                        nPortionIndex,
                                        nNextGlyphLen,
                                        std::move(aNewDXArray),
                                        std::vector(pCandidate->getKashidaArray()),
                                        aCandidateFontAttribute,
                                        pCandidate->getLocale(),
                                        aRGBColor) );
                            }
                        }

                        // consume from portion
                        nUsedTextLength += nNextGlyphLen;

                        // consume from polygon
                        fPolyStart += fPortionLength;
                    }
                }
            }
        }
    };
// end of anonymous namespace


// primitive decomposition helpers

namespace
{
    void impAddPolygonStrokePrimitives(
        const basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
        const basegfx::B2DHomMatrix& rTransform,
        const drawinglayer::attribute::LineAttribute& rLineAttribute,
        const drawinglayer::attribute::StrokeAttribute& rStrokeAttribute,
        drawinglayer::primitive2d::Primitive2DContainer& rTarget)
    {
        for(const auto& rB2DPolyPolygon : rB2DPolyPolyVector)
        {
            // prepare PolyPolygons
            basegfx::B2DPolyPolygon aB2DPolyPolygon = rB2DPolyPolygon;
            aB2DPolyPolygon.transform(rTransform);

            for(auto const& rPolygon : std::as_const(aB2DPolyPolygon))
            {
                // create one primitive per polygon
                rTarget.push_back(
                    new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
                        rPolygon, rLineAttribute, rStrokeAttribute) );
            }
        }
    }

    drawinglayer::primitive2d::Primitive2DContainer impAddPathTextOutlines(
        const drawinglayer::primitive2d::Primitive2DContainer& rSource,
        const drawinglayer::attribute::SdrFormTextOutlineAttribute& rOutlineAttribute)
    {
        drawinglayer::primitive2d::Primitive2DContainer aNewPrimitives;

        for(const drawinglayer::primitive2d::Primitive2DReference& a : rSource)
        {
            const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pTextCandidate = dynamic_castconst drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(a.get());

            if(pTextCandidate)
            {
                basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
                basegfx::B2DHomMatrix aPolygonTransform;

                // get text outlines and their object transformation
                pTextCandidate->getTextOutlinesAndTransformation(aB2DPolyPolyVector, aPolygonTransform);

                if(!aB2DPolyPolyVector.empty())
                {
                    // create stroke primitives
                    drawinglayer::primitive2d::Primitive2DContainer aStrokePrimitives;
                    impAddPolygonStrokePrimitives(
                        aB2DPolyPolyVector,
                        aPolygonTransform,
                        rOutlineAttribute.getLineAttribute(),
                        rOutlineAttribute.getStrokeAttribute(),
                        aStrokePrimitives);

                    if(!aStrokePrimitives.empty())
                    {
                        if(rOutlineAttribute.getTransparence())
                        {
                            // create UnifiedTransparencePrimitive2D
                            aNewPrimitives.push_back(
                                new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
                                    std::move(aStrokePrimitives),
                                    static_cast<double>(rOutlineAttribute.getTransparence()) / 100.0) );
                        }
                        else
                        {
                            // add polygons to rDecomposition as polygonStrokePrimitives
                            aNewPrimitives.append( std::move(aStrokePrimitives) );
                        }
                    }
                }
            }
        }

        return aNewPrimitives;
    }
// end of anonymous namespace


// primitive decomposition

void SdrTextObj::impDecomposePathTextPrimitive(
    drawinglayer::primitive2d::Primitive2DContainer& rTarget,
    const drawinglayer::primitive2d::SdrPathTextPrimitive2D& rSdrPathTextPrimitive,
    const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
{
    drawinglayer::primitive2d::Primitive2DContainer aRetvalA;
    drawinglayer::primitive2d::Primitive2DContainer aRetvalB;

    // prepare outliner
    SdrOutliner& rOutliner = ImpGetDrawOutliner();
    rOutliner.SetUpdateLayout(true);
    rOutliner.Clear();
    rOutliner.SetPaperSize(Size(LONG_MAX,LONG_MAX));
    rOutliner.SetText(rSdrPathTextPrimitive.getOutlinerParaObject());

    // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
    rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));

    // now break up to text portions
    impTextBreakupHandler aConverter(rOutliner);
    const ::std::vector< impPathTextPortion > rPathTextPortions = aConverter.decompositionPathTextPrimitive();

    if(!rPathTextPortions.empty())
    {
        // get FormText and polygon values
        const drawinglayer::attribute::SdrFormTextAttribute& rFormTextAttribute = rSdrPathTextPrimitive.getSdrFormTextAttribute();
        const basegfx::B2DPolyPolygon& rPathPolyPolygon(rSdrPathTextPrimitive.getPathPolyPolygon());

        // get loop count
        sal_uInt32 nLoopCount(rPathPolyPolygon.count());

        if(o3tl::make_unsigned(rOutliner.GetParagraphCount()) < nLoopCount)
        {
            nLoopCount = rOutliner.GetParagraphCount();
        }

        if(nLoopCount)
        {
            // prepare common decomposition stuff
            drawinglayer::primitive2d::Primitive2DContainer aRegularDecomposition;
            drawinglayer::primitive2d::Primitive2DContainer aShadowDecomposition;
            impPolygonParagraphHandler aPolygonParagraphHandler(
                rFormTextAttribute,
                aRegularDecomposition,
                aShadowDecomposition);
            sal_uInt32 a;

            for(a = 0; a < nLoopCount; a++)
            {
                // filter text portions for this paragraph
                ::std::vector< const impPathTextPortion* > aParagraphTextPortions;

                for(const auto & rCandidate : rPathTextPortions)
                {
                    if(static_cast<sal_uInt32>(rCandidate.getParagraph()) == a)
                    {
                        aParagraphTextPortions.push_back(&rCandidate);
                    }
                }

                // handle data pair polygon/ParagraphTextPortions
                if(!aParagraphTextPortions.empty())
                {
                    aPolygonParagraphHandler.HandlePair(rPathPolyPolygon.getB2DPolygon(a), aParagraphTextPortions);
                }
            }

            const sal_uInt32 nShadowCount(aShadowDecomposition.size());
            const sal_uInt32 nRegularCount(aRegularDecomposition.size());

            if(nShadowCount)
            {
                // add shadow primitives to decomposition

                // if necessary, add shadow outlines
                if(rFormTextAttribute.getFormTextOutline()
                    && !rFormTextAttribute.getShadowOutline().isDefault())
                {
                    aRetvalA = aShadowDecomposition;
                    const drawinglayer::primitive2d::Primitive2DContainer aOutlines(
                        impAddPathTextOutlines(
                            aShadowDecomposition,
                            rFormTextAttribute.getShadowOutline()));

                    aRetvalA.append(aOutlines);
                }
                else
                    aRetvalA = std::move(aShadowDecomposition);
            }

            if(nRegularCount)
            {
                // add normal primitives to decomposition

                // if necessary, add outlines
                if(rFormTextAttribute.getFormTextOutline()
                    && !rFormTextAttribute.getOutline().isDefault())
                {
                    aRetvalB = aRegularDecomposition;
                    const drawinglayer::primitive2d::Primitive2DContainer aOutlines(
                        impAddPathTextOutlines(
                            aRegularDecomposition,
                            rFormTextAttribute.getOutline()));

                    aRetvalB.append(aOutlines);
                }
                else
                    aRetvalB = std::move(aRegularDecomposition);
            }
        }
    }

    // clean up outliner
    rOutliner.Clear();
    rOutliner.setVisualizedPage(nullptr);

    // concatenate all results
    rTarget.append(std::move(aRetvalA));
    rTarget.append(std::move(aRetvalB));
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.