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

Quelle  editdoc.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 <editdoc.hxx>

#include <editeng/tstpitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/flditem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/kernitem.hxx>
#include <editeng/wrlmitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/cmapitem.hxx>
#include <editeng/contouritem.hxx>
#include <editeng/escapementitem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/autokernitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/emphasismarkitem.hxx>
#include <editeng/charscaleitem.hxx>
#include <editeng/charreliefitem.hxx>
#include <editeng/editids.hrc>
#include <editeng/editdata.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lspcitem.hxx>
#if ENABLE_YRS
#include <editeng/frmdiritem.hxx>
#include <editeng/hngpnctitem.hxx>
#include <editeng/forbiddenruleitem.hxx>
#include <editeng/scriptspaceitem.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/justifyitem.hxx>
#include <editeng/numdef.hxx>
#include <svl/itemiter.hxx>
#endif

#include <editeng/eerdll.hxx>
#include <eerdll2.hxx>
#include "impedit.hxx"

#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>

#include <svl/grabbagitem.hxx>
#include <svl/voiditem.hxx>
#include <tools/debug.hxx>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <libxml/xmlwriter.h>

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <limits>
#include <memory>
#include <set>
#include <string_view>
#include <utility>

using namespace ::com::sun::star;


sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, SvtScriptType nScriptType )
{
    sal_uInt16 nId = nItemId;

    if ( ( nScriptType == SvtScriptType::ASIAN ) ||
         ( nScriptType == SvtScriptType::COMPLEX ) )
    {
        switch ( nItemId )
        {
            case EE_CHAR_LANGUAGE:
                nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
            break;
            case EE_CHAR_FONTINFO:
                nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
            break;
            case EE_CHAR_FONTHEIGHT:
                nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
            break;
            case EE_CHAR_WEIGHT:
                nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
            break;
            case EE_CHAR_ITALIC:
                nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
            break;
        }
    }

    return nId;
}

bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
{
    bool bValid = true;

    switch ( nItemId )
    {
        case EE_CHAR_LANGUAGE:
            bValid = nScriptType == i18n::ScriptType::LATIN;
        break;
        case EE_CHAR_LANGUAGE_CJK:
            bValid = nScriptType == i18n::ScriptType::ASIAN;
        break;
        case EE_CHAR_LANGUAGE_CTL:
            bValid = nScriptType == i18n::ScriptType::COMPLEX;
        break;
        case EE_CHAR_FONTINFO:
            bValid = nScriptType == i18n::ScriptType::LATIN;
        break;
        case EE_CHAR_FONTINFO_CJK:
            bValid = nScriptType == i18n::ScriptType::ASIAN;
        break;
        case EE_CHAR_FONTINFO_CTL:
            bValid = nScriptType == i18n::ScriptType::COMPLEX;
        break;
        case EE_CHAR_FONTHEIGHT:
            bValid = nScriptType == i18n::ScriptType::LATIN;
        break;
        case EE_CHAR_FONTHEIGHT_CJK:
            bValid = nScriptType == i18n::ScriptType::ASIAN;
        break;
        case EE_CHAR_FONTHEIGHT_CTL:
            bValid = nScriptType == i18n::ScriptType::COMPLEX;
        break;
        case EE_CHAR_WEIGHT:
            bValid = nScriptType == i18n::ScriptType::LATIN;
        break;
        case EE_CHAR_WEIGHT_CJK:
            bValid = nScriptType == i18n::ScriptType::ASIAN;
        break;
        case EE_CHAR_WEIGHT_CTL:
            bValid = nScriptType == i18n::ScriptType::COMPLEX;
        break;
        case EE_CHAR_ITALIC:
            bValid = nScriptType == i18n::ScriptType::LATIN;
        break;
        case EE_CHAR_ITALIC_CJK:
            bValid = nScriptType == i18n::ScriptType::ASIAN;
        break;
        case EE_CHAR_ITALIC_CTL:
            bValid = nScriptType == i18n::ScriptType::COMPLEX;
        break;
    }

    return bValid;
}

EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_Int32 nS, sal_Int32 nE )
{
    // Create a new attribute in the pool
    switch( rAttr.Which() )
    {
        case EE_CHAR_LANGUAGE:
        case EE_CHAR_LANGUAGE_CJK:
        case EE_CHAR_LANGUAGE_CTL:
        {
            return new EditCharAttribLanguage(rPool, rAttr, nS, nE);
        }
        break;
        case EE_CHAR_COLOR:
        {
            return new EditCharAttribColor(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_FONTINFO:
        case EE_CHAR_FONTINFO_CJK:
        case EE_CHAR_FONTINFO_CTL:
        {
            return new EditCharAttribFont(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_FONTHEIGHT:
        case EE_CHAR_FONTHEIGHT_CJK:
        case EE_CHAR_FONTHEIGHT_CTL:
        {
            return new EditCharAttribFontHeight(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_FONTWIDTH:
        {
            return new EditCharAttribFontWidth(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_WEIGHT:
        case EE_CHAR_WEIGHT_CJK:
        case EE_CHAR_WEIGHT_CTL:
        {
            return new EditCharAttribWeight(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_UNDERLINE:
        {
            return new EditCharAttribUnderline(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_OVERLINE:
        {
            return new EditCharAttribOverline(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_EMPHASISMARK:
        {
            return new EditCharAttribEmphasisMark(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_RELIEF:
        {
            return new EditCharAttribRelief(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_STRIKEOUT:
        {
            return new EditCharAttribStrikeout(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_ITALIC:
        case EE_CHAR_ITALIC_CJK:
        case EE_CHAR_ITALIC_CTL:
        {
            return new EditCharAttribItalic(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_OUTLINE:
        {
            return new EditCharAttribOutline(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_SHADOW:
        {
            return new EditCharAttribShadow(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_ESCAPEMENT:
        {
            return new EditCharAttribEscapement(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_PAIRKERNING:
        {
            return new EditCharAttribPairKerning(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_KERNING:
        {
            return new EditCharAttribKerning(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_WLM:
        {
            return new EditCharAttribWordLineMode(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_XMLATTRIBS:
        {
            return new EditCharAttrib(rPool, rAttr, nS, nE);  // Attribute is only for holding XML information...
        }
        break;
        case EE_CHAR_CASEMAP:
        {
            return new EditCharAttribCaseMap(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_GRABBAG:
        {
            return new EditCharAttribGrabBag(rPool, rAttr, nS, nE );
        }
        break;
        case EE_FEATURE_TAB:
        {
            return new EditCharAttribTab(rPool, rAttr, nS );
        }
        break;
        case EE_FEATURE_LINEBR:
        {
            return new EditCharAttribLineBreak(rPool, rAttr, nS );
        }
        break;
        case EE_FEATURE_FIELD:
        {
            return new EditCharAttribField(rPool, rAttr, nS );
        }
        break;
        case EE_CHAR_BKGCOLOR:
        {
            return new EditCharAttribBackgroundColor(rPool, rAttr, nS, nE );
        }
        break;
        case EE_CHAR_RUBY:
        {
            return new EditCharAttribRuby(rPool, rAttr, nS, nE);
        }
        break;
        case EE_CHAR_SCRIPT_HINT:
        {
            return new EditCharAttribScriptHint(rPool, rAttr, nS, nE);
        }
        break;
        default:
        break;
    }

    OSL_FAIL( "Invalid Attribute!" );
    return nullptr;
}

void ParaPortion::MarkInvalid(sal_Int32 nStart, sal_Int32 nDiff)
{
    if (!mbInvalid)
    {
//      mnInvalidPosEnd = nStart;    // ??? => CreateLines
        mnInvalidPosStart = nDiff >= 0 ? nStart : nStart + nDiff;
        mnInvalidDiff = nDiff;
    }
    else
    {
        // Simple tap in succession
        if (nDiff > 0 && mnInvalidDiff > 0 && (mnInvalidPosStart + mnInvalidDiff) == nStart)
        {
            mnInvalidDiff = mnInvalidDiff + nDiff;
        }
        // Simple delete in succession
        else if (nDiff < 0 && mnInvalidDiff < 0 && mnInvalidPosStart == nStart)
        {
            mnInvalidPosStart = mnInvalidPosStart + nDiff;
            mnInvalidDiff = mnInvalidDiff + nDiff;
        }
        else
        {
//          mnInvalidPosEnd = pNode->Len();
            DBG_ASSERT(nDiff >= 0 || (nStart + nDiff) >= 0, "MarkInvalid: Diff out of Range");
            mnInvalidPosStart = std::min(mnInvalidPosStart, nDiff < 0 ? nStart + nDiff : nDiff);
            mnInvalidDiff = 0;
            mbSimple = false;
        }
    }
    mbInvalid = true;
    maScriptInfos.clear();
    maWritingDirectionInfos.clear();
}

void ParaPortion::MarkSelectionInvalid(sal_Int32 nStart)
{
    if ( !mbInvalid )
    {
        mnInvalidPosStart = nStart;
    }
    else
    {
        mnInvalidPosStart = std::min(mnInvalidPosStart, nStart);
    }
    mnInvalidDiff = 0;
    mbInvalid = true;
    mbSimple = false;
    maScriptInfos.clear();
    maWritingDirectionInfos.clear();
}

sal_Int32 ParaPortion::GetLineNumber( sal_Int32 nIndex ) const
{
    const sal_Int32 nCount = maLineList.Count();
    assert(nCount > 0 && "Empty ParaPortion in GetLine!");
    if (nCount == 0)
        return 0;
    DBG_ASSERT(mbVisible, "Why GetLine() on an invisible paragraph?");

    for ( sal_Int32 nLine = 0; nLine < nCount; nLine++ )
    {
        if (maLineList[nLine].IsIn(nIndex))
            return nLine;
    }

    // Then it should be at the end of the last line!
    DBG_ASSERT(nIndex == maLineList[nCount - 1].GetEnd(), "Index dead wrong!");
    return nCount - 1;
}

void ParaPortion::CorrectValuesBehindLastFormattedLine( sal_Int32 nLastFormattedLine )
{
    sal_Int32 nLines = maLineList.Count();
    DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Empty Portion?" );
    if ( nLastFormattedLine < ( nLines - 1 ) )
    {
        const EditLine& rLastFormatted = maLineList[ nLastFormattedLine ];
        const EditLine& rUnformatted = maLineList[ nLastFormattedLine+1 ];
        sal_Int32 nPortionDiff = rUnformatted.GetStartPortion() - rLastFormatted.GetEndPortion();
        sal_Int32 nTextDiff = rUnformatted.GetStart() - rLastFormatted.GetEnd();
        nTextDiff++;    // LastFormatted->GetEnd() was included => 1 deducted too much!

        // The first unformatted must begin exactly one Portion behind the last
        // of the formatted:
        // If the modified line was split into one portion, can
        // nLastEnd > nNextStart!
        int nPDiff = -( nPortionDiff-1 );
        int nTDiff = -( nTextDiff-1 );
        if ( nPDiff || nTDiff )
        {
            for ( sal_Int32 nL = nLastFormattedLine+1; nL < nLines; nL++ )
            {
                EditLine& rLine = maLineList[ nL ];

                rLine.GetStartPortion() = rLine.GetStartPortion() + nPDiff;
                rLine.GetEndPortion() = rLine.GetEndPortion() + nPDiff;

                rLine.GetStart() = rLine.GetStart() + nTDiff;
                rLine.GetEnd() = rLine.GetEnd() + nTDiff;

                rLine.SetValid();
            }
        }
    }
    DBG_ASSERT(maLineList[maLineList.Count() - 1].GetEnd() == mpNode->Len(), "CorrectLines: The end is not right!");
}

// Shared reverse lookup acceleration pieces ...

namespace {

template<typename Array, typename Val>
sal_Int32 FastGetPos(const Array& rArray, const Val* p, sal_Int32& rLastPos)
{
    sal_Int32 nArrayLen = rArray.size();

    // Through certain filter code-paths we do a lot of appends, which in
    // turn call GetPos - creating some N^2 nightmares. If we have a
    // non-trivially large list, do a few checks from the end first.
    if (rLastPos > 16 && nArrayLen > 16)
    {
        sal_Int32 nEnd;
        if (rLastPos > nArrayLen - 2)
            nEnd = nArrayLen;
        else
            nEnd = rLastPos + 2;

        for (sal_Int32 nIdx = rLastPos - 2; nIdx < nEnd; ++nIdx)
        {
            if (rArray.at(nIdx).get() == p)
            {
                rLastPos = nIdx;
                return nIdx;
            }
        }
    }
    // The world's lamest linear search from svarray...
    for (sal_Int32 nIdx = 0; nIdx < nArrayLen; ++nIdx)
        if (rArray.at(nIdx).get() == p)
        {
            rLastPos = nIdx;
            return rLastPos;
        }

    // XXX "not found" condition for sal_Int32 indexes
    return EE_PARA_MAX;
}

}

sal_Int32 ParaPortionList::GetPos(const ParaPortion* p) const
{
    return FastGetPos(maPortions, p, nLastCache);
}

std::unique_ptr<ParaPortion> ParaPortionList::Release(sal_Int32 nPos)
{
    if (nPos < 0 || maPortions.size() <= o3tl::make_unsigned(nPos))
    {
        SAL_WARN( "editeng""ParaPortionList::Release - out of bounds pos " << nPos);
        return nullptr;
    }
    std::unique_ptr<ParaPortion> p = std::move(maPortions[nPos]);
    maPortions.erase(maPortions.begin()+nPos);
    return p;
}

void ParaPortionList::Remove(sal_Int32 nPos)
{
    if (nPos < 0 || maPortions.size() <= o3tl::make_unsigned(nPos))
    {
        SAL_WARN( "editeng""ParaPortionList::Remove - out of bounds pos " << nPos);
        return;
    }
    maPortions.erase(maPortions.begin()+nPos);
}

void ParaPortionList::Insert(sal_Int32 nPos, std::unique_ptr<ParaPortion> p)
{
    if (nPos < 0 || maPortions.size() < o3tl::make_unsigned(nPos))
    {
        SAL_WARN( "editeng""ParaPortionList::Insert - out of bounds pos " << nPos);
        return;
    }
    maPortions.insert(maPortions.begin()+nPos, std::move(p));
}

void ParaPortionList::Append(std::unique_ptr<ParaPortion> p)
{
    maPortions.push_back(std::move(p));
}

sal_Int32 ParaPortionList::Count() const
{
    size_t nSize = maPortions.size();
    if (nSize > SAL_MAX_INT32)
    {
        SAL_WARN( "editeng""ParaPortionList::Count - overflow " << nSize);
        return SAL_MAX_INT32;
    }
    return nSize;
}

void ParaPortionList::Reset()
{
    maPortions.clear();
}

tools::Long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
{
    tools::Long nHeight = 0;
    for (const auto & rPortion : maPortions)
    {
        const ParaPortion* pTmpPortion = rPortion.get();
        if ( pTmpPortion == pPPortion )
            return nHeight;
        nHeight += pTmpPortion->GetHeight();
    }
    OSL_FAIL( "GetYOffset: Portion not found" );
    return nHeight;
}

sal_Int32 ParaPortionList::FindParagraph(tools::Long nYOffset) const
{
    tools::Long nY = 0;
    for (size_t i = 0, n = maPortions.size(); i < n; ++i)
    {
        nY += maPortions[i]->GetHeight(); // should also be correct even in bVisible!
        if ( nY > nYOffset )
            return i <= SAL_MAX_INT32 ? static_cast<sal_Int32>(i) : SAL_MAX_INT32;
    }
    return EE_PARA_MAX;
}

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
void
ParaPortionList::DbgCheck(ParaPortionList const& rParas, EditDoc const& rDoc)
{
    assert(rParas.Count() == rDoc.Count());
    for (sal_Int32 i = 0; i < rParas.Count(); ++i)
    {
        assert(rParas.SafeGetObject(i) != nullptr);
        assert(rParas.SafeGetObject(i)->GetNode() != nullptr);
        assert(rParas.SafeGetObject(i)->GetNode() == rDoc.GetObject(i));
    }
}
#endif

ContentAttribsInfo::ContentAttribsInfo( SfxItemSet aParaAttribs ) :
        aPrevParaAttribs(std::move( aParaAttribs))
{
}

void ContentAttribsInfo::AppendCharAttrib(EditCharAttrib* pNew)
{
    aPrevCharAttribs.push_back(std::unique_ptr<EditCharAttrib>(pNew));
}

void ConvertItem( std::unique_ptr<SfxPoolItem>& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit )
{
    DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" );

    switch ( rPoolItem->Which() )
    {
        case EE_PARA_LRSPACE:
        {
            assert(dynamic_cast<const SvxLRSpaceItem *>(rPoolItem.get()) != nullptr);
            SvxLRSpaceItem& rItem = static_cast<SvxLRSpaceItem&>(*rPoolItem);
            if (rItem.GetTextFirstLineOffset().m_nUnit == css::util::MeasureUnit::TWIP)
            {
                rItem.SetTextFirstLineOffset(
                    SvxIndentValue::twips(sal::static_int_cast<short>(OutputDevice::LogicToLogic(
                        rItem.ResolveTextFirstLineOffset({}), eSourceUnit, eDestUnit))));
            }
            rItem.SetTextLeft(SvxIndentValue::twips(
                OutputDevice::LogicToLogic(rItem.ResolveTextLeft({}), eSourceUnit, eDestUnit)));
            if (rItem.GetRight().m_nUnit == css::util::MeasureUnit::TWIP)
            {
                rItem.SetRight(SvxIndentValue::twips(
                    OutputDevice::LogicToLogic(rItem.ResolveRight({}), eSourceUnit, eDestUnit)));
            }
        }
        break;
        case EE_PARA_ULSPACE:
        {
            assert(dynamic_cast<const SvxULSpaceItem *>(rPoolItem.get()) != nullptr);
            SvxULSpaceItem& rItem = static_cast<SvxULSpaceItem&>(*rPoolItem);
            rItem.SetUpper( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) );
            rItem.SetLower( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) );
        }
        break;
        case EE_PARA_SBL:
        {
            assert(dynamic_cast<const SvxLineSpacingItem *>(rPoolItem.get()) != nullptr);
            SvxLineSpacingItem& rItem = static_cast<SvxLineSpacingItem&>(*rPoolItem);
            // SetLineHeight changes also eLineSpace!
            if ( rItem.GetLineSpaceRule() == SvxLineSpaceRule::Min )
                rItem.SetLineHeight( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) );
        }
        break;
        case EE_PARA_TABS:
        {
            assert(dynamic_cast<const SvxTabStopItem *>(rPoolItem.get()) != nullptr);
            SvxTabStopItem& rItem = static_cast<SvxTabStopItem&>(*rPoolItem);
            SvxTabStopItem* pNewItem(new SvxTabStopItem(EE_PARA_TABS));

            if (sal_Int32 nDefTabDistance = rItem.GetDefaultDistance())
            {
                pNewItem->SetDefaultDistance(
                    OutputDevice::LogicToLogic(nDefTabDistance, eSourceUnit, eDestUnit));
            }

            for ( sal_uInt16 i = 0; i < rItem.Count(); i++ )
            {
                const SvxTabStop& rTab = rItem[i];
                SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() );
                pNewItem->Insert( aNewStop );
            }
            rPoolItem.reset(pNewItem);
        }
        break;
        case EE_CHAR_FONTHEIGHT:
        case EE_CHAR_FONTHEIGHT_CJK:
        case EE_CHAR_FONTHEIGHT_CTL:
        {
            assert(dynamic_cast<const SvxFontHeightItem *>(rPoolItem.get()) != nullptr);
            SvxFontHeightItem& rItem = static_cast<SvxFontHeightItem&>(*rPoolItem);
            rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) );
        }
        break;
    }
}

void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit )
{
    const SfxItemPool* pSourcePool = rSource.GetPool();
    const SfxItemPool* pDestPool = rDest.GetPool();

    for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
    {
        // If possible go through SlotID ...

        sal_uInt16 nSourceWhich = nWhich;
        sal_uInt16 nSlot = pDestPool->GetTrueSlotId( nWhich );
        if ( nSlot )
        {
            sal_uInt16 nW = pSourcePool->GetTrueWhichIDFromSlotID( nSlot );
            if ( nW )
                nSourceWhich = nW;
        }

        if ( rSource.GetItemState( nSourceWhich, false ) == SfxItemState::SET )
        {
            MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : pSourcePool->GetMetric( nSourceWhich );
            MapUnit eDestUnit = pDestUnit ? *pDestUnit : pDestPool->GetMetric( nWhich );
            if ( eSourceUnit != eDestUnit )
            {
                std::unique_ptr<SfxPoolItem> pItem(rSource.Get( nSourceWhich ).Clone());
                ConvertItem( pItem, eSourceUnit, eDestUnit );
                pItem->SetWhich(nWhich);
                rDest.Put( std::move(pItem) );
            }
            else
            {
                rDest.Put( rSource.Get( nSourceWhich ).CloneSetWhich(nWhich) );
            }
        }
    }
}

bool EditPaM::DbgIsBuggy( EditDoc const & rDoc ) const
{
    return !pNode ||
           rDoc.GetPos( pNode ) >= rDoc.Count() ||
           nIndex > pNode->Len();
}

bool EditSelection::DbgIsBuggy( EditDoc const & rDoc ) const
{
    return aStartPaM.DbgIsBuggy( rDoc ) || aEndPaM.DbgIsBuggy( rDoc );
}

void EditSelection::Adjust( const EditDoc& rNodes )
{
    DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in Adjust(1)" );
    DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in Adjust(2)" );

    const ContentNode* pStartNode = aStartPaM.GetNode();
    const ContentNode* pEndNode = aEndPaM.GetNode();

    sal_Int32 nStartNode = rNodes.GetPos( pStartNode );
    sal_Int32 nEndNode = rNodes.GetPos( pEndNode );

    DBG_ASSERT( nStartNode != SAL_MAX_INT32, "Node out of range in Adjust(1)" );
    DBG_ASSERT( nEndNode != SAL_MAX_INT32, "Node out of range in Adjust(2)" );

    const bool bSwap = ( nStartNode > nEndNode ) ||
                       ( ( nStartNode == nEndNode ) &&
                         ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) );

    if ( bSwap )
    {
        EditPaM aTmpPaM( aStartPaM );
        aStartPaM = aEndPaM;
        aEndPaM = aTmpPaM;
    }
}

#if ENABLE_YRS
#include <editeng/yrstransactionsupplier.hxx>
#include <editeng/yrs.hxx>

namespace {

struct YrsReplayGuard
{
    IYrsTransactionSupplier *const m_pYrsSupplier;
    IYrsTransactionSupplier::Mode m_Mode;

    explicit YrsReplayGuard(IYrsTransactionSupplier *const pYrsSupplier)
        : m_pYrsSupplier(pYrsSupplier)
    {
        if (m_pYrsSupplier)
        {
            m_Mode = m_pYrsSupplier->SetMode(IYrsTransactionSupplier::Mode::Replay);
        }
    }
    ~YrsReplayGuard()
    {
        if (m_pYrsSupplier)
        {
            m_pYrsSupplier->SetMode(m_Mode);
        }
    }
};

struct YrsWrite
{
    YTransaction *const pTxn;
    Branch *const pProps;
    Branch *const pText;
};

constexpr char CH_PARA = 0x0d;

YrsWrite GetYrsWrite(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rId, YTransaction *const pInTxn = nullptr)
{
    if (!pYrsSupplier)
    {
        return { nullptr, nullptr, nullptr };
    }
    YDoc *const pDoc{pYrsSupplier->GetYDoc()};
    YTransaction *const pTxn{pInTxn ? pInTxn : pYrsSupplier->GetWriteTransaction()};
    // write is disabled when receiving edits from peers
    if (!pTxn)
    {
        return { nullptr, nullptr, nullptr };
    }
    assert(pDoc);
    Branch *const pComments{pYrsSupplier->GetCommentMap()};
    ::std::unique_ptr<YOutput, YOutputDeleter> const pComment{ymap_get(pComments, pTxn, rId.getStr())};
    yvalidate(pComment->tag == Y_ARRAY);
    yvalidate(pComment->len == 1);
    Branch *const pCommentArray{pComment->value.y_type};
    ::std::unique_ptr<YOutput, YOutputDeleter> const pProps{yarray_get(pCommentArray, pTxn, 1)};
    yvalidate(pProps->tag == Y_MAP);
    yvalidate(pProps->len == 1);
    ::std::unique_ptr<YOutput, YOutputDeleter> const pText{yarray_get(pCommentArray, pTxn, 2)};
    yvalidate(pText->tag == Y_TEXT);
    yvalidate(pText->len == 1);
    return { pTxn, pProps->value.y_type, pText->value.y_type };
}

void YrsSetVertical(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rCommentId, bool const isVertical)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    YInput const input{yinput_bool(isVertical ? Y_TRUE : Y_FALSE)};
    ymap_insert(yw.pProps, yw.pTxn, "is-vertical", &input);
}

void YrsSetRotation(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rCommentId, TextRotation const nRotation)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    YInput const input{yinput_long(static_cast<int64_t>(nRotation))};
    ymap_insert(yw.pProps, yw.pTxn, "rotation", &input);
}

void YrsSetDefTab(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rCommentId, sal_uInt16 const nDefTab)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    YInput const input{yinput_long(static_cast<int64_t>(nDefTab))};
    ymap_insert(yw.pProps, yw.pTxn, "def-tab", &input);
}

void YrsInsertAttribImplImpl(YrsWrite const& yw, SfxPoolItem const& rItm,
    uint32_t const nStart, uint32_t const nLen)
{
    ::std::vector<YInput> tabStops;
    ::std::vector<::std::vector<YInput>> tabStopValues;
    ::std::vector<OString> tempStrings;
    ::std::vector<YInput> itemArray;
    ::std::vector<char const*> itemNames;
    YInput attr;
    char const* attrName;
    switch (rItm.Which())
    {
        case EE_CHAR_COLOR:
        case EE_CHAR_BKGCOLOR:
        {
            sal_uInt32 const nColor{static_cast<SvxColorItem const&>(rItm).getColor()};
            attr = yinput_long(nColor);
            attrName = rItm.Which() == EE_CHAR_COLOR ? "EE_CHAR_COLOR" : "EE_CHAR_BKGCOLOR";
            break;
        }
        case EE_CHAR_FONTINFO:
        case EE_CHAR_FONTINFO_CJK:
        case EE_CHAR_FONTINFO_CTL:
        {
            SvxFontItem const& rItem{static_cast<SvxFontItem const&>(rItm)};
            tempStrings.reserve(2); // prevent realloc
            tempStrings.emplace_back(OUStringToOString(rItem.GetFamilyName(), RTL_TEXTENCODING_UTF8));
            itemArray.emplace_back(yinput_string(tempStrings.back().getStr()));
            itemNames.emplace_back("familyname");
            tempStrings.emplace_back(OUStringToOString(rItem.GetStyleName(), RTL_TEXTENCODING_UTF8));
            itemArray.emplace_back(yinput_string(tempStrings.back().getStr()));
            itemNames.emplace_back("style");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetFamily())));
            itemNames.emplace_back("family");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetPitch())));
            itemNames.emplace_back("pitch");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetCharSet())));
            itemNames.emplace_back("charset");
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = rItm.Which() == EE_CHAR_FONTINFO
                ? "EE_CHAR_FONTINFO"
                : rItm.Which() == EE_CHAR_FONTINFO_CJK ? "EE_CHAR_FONTINFO_CJK" : "EE_CHAR_FONTINFO_CTL";
            break;
        }
        case EE_CHAR_FONTHEIGHT:
        case EE_CHAR_FONTHEIGHT_CJK:
        case EE_CHAR_FONTHEIGHT_CTL:
        {
            SvxFontHeightItem const& rItem{static_cast<SvxFontHeightItem const&>(rItm)};
            itemNames.emplace_back("height");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetHeight())));
            itemNames.emplace_back("prop");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetProp())));
            itemNames.emplace_back("propunit");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetPropUnit())));
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = rItm.Which() == EE_CHAR_FONTHEIGHT
                ? "EE_CHAR_FONTHEIGHT"
                : rItm.Which() == EE_CHAR_FONTHEIGHT_CJK ? "EE_CHAR_FONTHEIGHT_CJK" : "EE_CHAR_FONTHEIGHT_CTL";
            break;
        }
        case EE_CHAR_FONTWIDTH:
        {
            SvxCharScaleWidthItem const& rItem{static_cast<SvxCharScaleWidthItem const&>(rItm)};
            attr = yinput_long(rItem.GetValue());
            attrName = "EE_CHAR_FONTWIDTH";
            break;
        }
        case EE_CHAR_WEIGHT:
        case EE_CHAR_WEIGHT_CJK:
        case EE_CHAR_WEIGHT_CTL:
        {
            SvxWeightItem const& rItem{static_cast<SvxWeightItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetWeight()));
            attrName = rItm.Which() == EE_CHAR_WEIGHT
                ? "EE_CHAR_WEIGHT"
                : rItm.Which() == EE_CHAR_WEIGHT_CJK ? "EE_CHAR_WEIGHT_CJK" : "EE_CHAR_WEIGHT_CTL";
            break;
        }
        case EE_CHAR_UNDERLINE:
        case EE_CHAR_OVERLINE:
        {
            SvxTextLineItem const& rItem{static_cast<SvxTextLineItem const&>(rItm)};
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetLineStyle())));
            itemNames.emplace_back("style");
            itemArray.emplace_back(yinput_long(uint64_t(sal_uInt32(rItem.GetColor()))));
            itemNames.emplace_back("color");
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = rItm.Which() == EE_CHAR_UNDERLINE ? "EE_CHAR_UNDERLINE" : "EE_CHAR_OVERLINE";
            break;
        }
        case EE_CHAR_STRIKEOUT:
        {
            SvxCrossedOutItem const& rItem{static_cast<SvxCrossedOutItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetStrikeout()));
            attrName = "EE_CHAR_STRIKEOUT";
            break;
        }
        case EE_CHAR_ITALIC:
        case EE_CHAR_ITALIC_CJK:
        case EE_CHAR_ITALIC_CTL:
        {
            SvxPostureItem const& rItem{static_cast<SvxPostureItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetPosture()));
            attrName = rItm.Which() == EE_CHAR_ITALIC
                ? "EE_CHAR_ITALIC"
                : rItm.Which() == EE_CHAR_ITALIC_CJK ? "EE_CHAR_ITALIC_CJK" : "EE_CHAR_ITALIC_CTL";
            break;
        }
        case EE_CHAR_OUTLINE:
        {
            SvxContourItem const& rItem{static_cast<SvxContourItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_CHAR_OUTLINE";
            break;
        }
        case EE_CHAR_SHADOW:
        {
            SvxShadowedItem const& rItem{static_cast<SvxShadowedItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_CHAR_SHADOW";
            break;
        }
        case EE_CHAR_ESCAPEMENT:
        {
            SvxEscapementItem const& rItem{static_cast<SvxEscapementItem const&>(rItm)};
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetEsc())));
            itemNames.emplace_back("esc");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetProportionalHeight())));
            itemNames.emplace_back("prop");
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = "EE_CHAR_ESCAPEMENT";
            break;
        }
        case EE_CHAR_PAIRKERNING:
        {
            SvxAutoKernItem const& rItem{static_cast<SvxAutoKernItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_CHAR_PAIRKERNING";
            break;
        }
        case EE_CHAR_KERNING:
        {
            SvxKerningItem const& rItem{static_cast<SvxKerningItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_CHAR_KERNING";
            break;
        }
        case EE_CHAR_WLM:
        {
            SvxWordLineModeItem const& rItem{static_cast<SvxWordLineModeItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_CHAR_WLM";
            break;
        }
        case EE_CHAR_LANGUAGE:
        case EE_CHAR_LANGUAGE_CJK:
        case EE_CHAR_LANGUAGE_CTL:
        {
            SvxLanguageItem const& rItem{static_cast<SvxLanguageItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue().get()));
            attrName = rItm.Which() == EE_CHAR_LANGUAGE
                ? "EE_CHAR_LANGUAGE"
                : rItm.Which() == EE_CHAR_LANGUAGE_CJK ? "EE_CHAR_LANGUAGE_CJK" : "EE_CHAR_LANGUAGE_CTL";
            break;
        }
        case EE_CHAR_EMPHASISMARK:
        {
            SvxEmphasisMarkItem const& rItem{static_cast<SvxEmphasisMarkItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_CHAR_EMPHASISMARK";
            break;
        }
        case EE_CHAR_RELIEF:
        {
            SvxCharReliefItem const& rItem{static_cast<SvxCharReliefItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_CHAR_RELIEF";
            break;
        }
        case EE_CHAR_CASEMAP:
        {
            SvxCaseMapItem const& rItem{static_cast<SvxCaseMapItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_CHAR_CASEMAP";
            break;
        }
        case EE_PARA_WRITINGDIR:
        {
            SvxFrameDirectionItem const& rItem{static_cast<SvxFrameDirectionItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_PARA_WRITINGDIR";
            break;
        }
        case EE_PARA_HANGINGPUNCTUATION:
        {
            SvxHangingPunctuationItem const& rItem{static_cast<SvxHangingPunctuationItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_PARA_HANGINGPUNCTUATION";
            break;
        }
        case EE_PARA_FORBIDDENRULES:
        {
            SvxForbiddenRuleItem const& rItem{static_cast<SvxForbiddenRuleItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_PARA_FORBIDDENRULES";
            break;
        }
        case EE_PARA_ASIANCJKSPACING:
        {
            SvxScriptSpaceItem const& rItem{static_cast<SvxScriptSpaceItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = "EE_PARA_ASIANCJKSPACING";
            break;
        }
//TODO complex, but apparently no way to set this in comment? inline constexpr TypedWhichId<SvxNumBulletItem>          EE_PARA_NUMBULLET          (EE_PARA_START+5);
        case EE_PARA_HYPHENATE:
        case EE_PARA_HYPHENATE_NO_CAPS:
        case EE_PARA_HYPHENATE_NO_LAST_WORD:
        case EE_PARA_BULLETSTATE:
        {
            SfxBoolItem const& rItem{static_cast<SfxBoolItem const&>(rItm)};
            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
            attrName = rItm.Which() == EE_PARA_HYPHENATE
                ? "EE_PARA_HYPHENATE"
                : rItm.Which() == EE_PARA_HYPHENATE_NO_CAPS
                    ? "EE_PARA_HYPHENATE_NO_CAPS"
                    : rItm.Which() == EE_PARA_HYPHENATE_NO_LAST_WORD
                        ? "EE_PARA_HYPHENATE_NO_LAST_WORD"
                        : "EE_PARA_BULLETSTATE";
            break;
        }
//TODO no way to set this in comment? inline constexpr TypedWhichId<SvxLRSpaceItem>            EE_PARA_OUTLLRSPACE        (EE_PARA_START+10);
        case EE_PARA_OUTLLEVEL:
        {
            SfxInt16Item const& rItem{static_cast<SfxInt16Item const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_PARA_OUTLLEVEL";
            break;
        }
//TODO complex, but apparently no way to set this in comment? inline constexpr TypedWhichId<SvxBulletItem>             EE_PARA_BULLET             (EE_PARA_START+12);
        case EE_PARA_LRSPACE:
        {
            SvxLRSpaceItem const& rItem{static_cast<SvxLRSpaceItem const&>(rItm)};
            itemArray.emplace_back(yinput_float(rItem.GetTextFirstLineOffset().m_dValue));
            itemNames.emplace_back("first-line-offset");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetTextFirstLineOffset().m_nUnit)));
            itemNames.emplace_back("first-line-offset-unit");
            itemArray.emplace_back(yinput_float(rItem.GetLeft().m_dValue));
            itemNames.emplace_back("left-margin");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetLeft().m_nUnit)));
            itemNames.emplace_back("left-margin-unit");
            itemArray.emplace_back(yinput_float(rItem.GetRight().m_dValue));
            itemNames.emplace_back("right-margin");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetRight().m_nUnit)));
            itemNames.emplace_back("right-margin-unit");
            itemArray.emplace_back(yinput_bool(rItem.IsAutoFirst() ? Y_TRUE : Y_FALSE));
            itemNames.emplace_back("auto-first");
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = "EE_PARA_LRSPACE";
            break;
        }
        case EE_PARA_ULSPACE:
        {
            SvxULSpaceItem const& rItem{static_cast<SvxULSpaceItem const&>(rItm)};
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetUpper())));
            itemNames.emplace_back("upper-margin");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetLower())));
            itemNames.emplace_back("lower-margin");
            // TODO what does EE support here?
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = "EE_PARA_ULSPACE";
            break;
        }
        case EE_PARA_SBL:
        {
            SvxLineSpacingItem const& rItem{static_cast<SvxLineSpacingItem const&>(rItm)};
            switch (rItem.GetLineSpaceRule())
            {
                case SvxLineSpaceRule::Auto:
                    break;
                case SvxLineSpaceRule::Fix:
                    itemArray.emplace_back(yinput_long(uint64_t(rItem.GetLineHeight())));
                    itemNames.emplace_back("line-space-fix");
                    break;
                case SvxLineSpaceRule::Min:
                    itemArray.emplace_back(yinput_long(uint64_t(rItem.GetLineHeight())));
                    itemNames.emplace_back("line-space-min");
                    break;
            }
            switch (rItem.GetInterLineSpaceRule())
            {
                case SvxInterLineSpaceRule::Off:
                    break;
                case SvxInterLineSpaceRule::Prop:
                    itemArray.emplace_back(yinput_long(uint64_t(rItem.GetPropLineSpace())));
                    itemNames.emplace_back("inter-line-space-prop");
                    break;
                case SvxInterLineSpaceRule::Fix:
                    itemArray.emplace_back(yinput_long(uint64_t(rItem.GetInterLineSpace())));
                    itemNames.emplace_back("inter-line-space-fix");
                    break;
            }
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = "EE_PARA_SBL";
            break;
        }
        case EE_PARA_JUST:
        {
            SvxAdjustItem const& rItem{static_cast<SvxAdjustItem const&>(rItm)};
            switch (rItem.GetAdjust())
            {
                case SvxAdjust::Left:
                case SvxAdjust::Right:
                case SvxAdjust::Center:
                    attr = yinput_long(uint64_t(rItem.GetAdjust()));
                    break;
                case SvxAdjust::Block:
                    switch (rItem.GetLastBlock())
                    {
                        case SvxAdjust::Left:
                            attr = yinput_long(uint64_t(SvxAdjust::Block));
                            break;
                        case SvxAdjust::Center:
                            attr = yinput_long(uint64_t(5));
                            break;
                        case SvxAdjust::Block:
                            attr = yinput_long(uint64_t(rItem.GetOneWord() == SvxAdjust::Block ? 7 : 6));
                            break;
                        default:
                            assert(false);
                    }
                    break;
                default:
                    assert(false);
            }
            attrName = "EE_PARA_JUST";
            break;
        }
        case EE_PARA_TABS:
        {
            SvxTabStopItem const& rItem{static_cast<SvxTabStopItem const&>(rItm)};
            itemNames.emplace_back("default-distance");
            itemArray.emplace_back(yinput_long(uint64_t(rItem.GetDefaultDistance())));
            tabStopValues.reserve(rItem.Count()); // prevent realloc
            for (decltype(rItem.Count()) i{0}; i < rItem.Count(); ++i)
            {
                SvxTabStop const& rTab{rItem.At(i)};
                char const*const names[]{"pos""adjustment""decimal""fill"};
                tabStopValues.emplace_back();
                tabStopValues.back().emplace_back(yinput_long(uint64_t(rTab.GetTabPos())));
                tabStopValues.back().emplace_back(yinput_long(uint64_t(rTab.GetAdjustment())));
                tabStopValues.back().emplace_back(yinput_long(uint64_t(rTab.GetDecimal())));
                tabStopValues.back().emplace_back(yinput_long(uint64_t(rTab.GetFill())));
                tabStops.emplace_back(yinput_json_map(const_cast<char**>(names), tabStopValues.back().data(), 4));
            }
            itemNames.emplace_back("tab-stops");
            itemArray.emplace_back(yinput_json_array(tabStops.data(), tabStops.size()));
            attr = yinput_json_map(const_cast<char**>(itemNames.data()), itemArray.data(), itemArray.size());
            attrName = "EE_PARA_TABS";
            break;
        }
        case EE_PARA_JUST_METHOD:
        {
            SvxJustifyMethodItem const& rItem{static_cast<SvxJustifyMethodItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_PARA_JUST_METHOD";
            break;
        }
        case EE_PARA_VER_JUST:
        {
            SvxVerJustifyItem const& rItem{static_cast<SvxVerJustifyItem const&>(rItm)};
            attr = yinput_long(uint64_t(rItem.GetValue()));
            attrName = "EE_PARA_VER_JUST";
            break;
        }
        // these aren't editable?
//constexpr TypedWhichId<SvXMLAttrContainerItem> EE_CHAR_XMLATTRIBS     (EE_CHAR_START+27);
//constexpr TypedWhichId<SfxGrabBagItem>         EE_CHAR_GRABBAG        (EE_CHAR_START+30);

        default:
            assert(false);
    }
    assert(itemNames.size() == itemArray.size());
    YInput const attrs{yinput_json_map(const_cast<char**>(&attrName), &attr, 1)};
    ytext_format(yw.pText, yw.pTxn, nStart, nLen, &attrs);
}

void YrsInsertAttribImpl(YrsWrite const& yw, uint32_t const offset, EditCharAttrib const*const pAttr)
{
    auto const start{offset + pAttr->GetStart()};
    auto const len{pAttr->GetEnd() - pAttr->GetStart()};
    YrsInsertAttribImplImpl(yw, *pAttr->GetItem(), start, len);
}

void YrsInsertFeature(IYrsTransactionSupplier *const pYrsSupplier, OString constrCommentId,
    EditDoc const& rDoc, uint32_t const index, EditCharAttrib const*const pAttr)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += pAttr->GetStart();
    char const feature[]{ CH_FEATURE, '\0' };
    switch (pAttr->Which())
    {
        case EE_FEATURE_TAB:
        case EE_FEATURE_LINEBR:
        {
            YInput const type{yinput_string(pAttr->Which() == EE_FEATURE_TAB ? "tab" : "line")};
            YInput attrArray[]{ type };
            char const*const attrNames[]{ "feature" };
            YInput const attrs{yinput_json_map(const_cast<char**>(attrNames), attrArray, 1)};
            ytext_insert(yw.pText, yw.pTxn, i, feature, &attrs);
            break;
        }
        case EE_FEATURE_FIELD:
        {
            SvxURLField const*const pURLField{dynamic_cast<SvxURLField const*>(dynamic_cast<SvxFieldItem const*>(pAttr->GetItem())->GetField())};
            assert(pURLField);
            YInput const type{yinput_string("url")};
            // ??? somehow this comes out as Y_JSON_NUM at the other end?
            YInput const format{yinput_long(static_cast<int64_t>(pURLField->GetFormat()))};
            OString const urlStr{OUStringToOString(pURLField->GetURL(), RTL_TEXTENCODING_UTF8)};
            YInput const url{yinput_string(urlStr.getStr())};
            OString const reprStr{OUStringToOString(pURLField->GetRepresentation(), RTL_TEXTENCODING_UTF8)};
            YInput const representation{yinput_string(reprStr.getStr())};
            OString const targetStr{OUStringToOString(pURLField->GetTargetFrame(), RTL_TEXTENCODING_UTF8)};
            YInput const targetframe{yinput_string(targetStr.getStr())};
            YInput attrArray[]{ type, format, url, representation, targetframe };
            char const*const attrNames[]{ "feature""url-format""url-url""url-representation""url-targetframe" };
            // don't use yinput_ymap for this!
            YInput const attrs{yinput_json_map(const_cast<char**>(attrNames), attrArray, 5)};
            ytext_insert(yw.pText, yw.pTxn, i, feature, &attrs);

            break;
        }
        default// EE_FEATURE_NOTCONV appears unused?
            assert(false);
    }
}

void YrsAddPara(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rCommentId, EditDoc const& rDoc, uint32_t const index)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    SAL_INFO("editeng.yrs""YRS YrsAddPara");
    // need to encode into 1 YText
    char const para[]{ CH_PARA, '\0' };
    uint32_t i{0};
    // UTF-16 index should be equal to EditDoc one
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    ContentAttribs const& rParaAttribs{rDoc.GetObject(index)->GetContentAttribs()};
    auto const pStyle{rParaAttribs.GetStyleSheet()};
    if (pStyle)
    {
        OString const styleName{OUStringToOString(pStyle->GetName(), RTL_TEXTENCODING_UTF8)};
        YInput const style{yinput_string(styleName.getStr())};
        YInput attrArray[]{ style };
        char const*const attrNames[]{ "para-style" };
        YInput const attrs{yinput_json_map(const_cast<char**>(attrNames), attrArray, 1)};
        ytext_insert(yw.pText, yw.pTxn, i, para, &attrs);
    }
    else
    {
        ytext_insert(yw.pText, yw.pTxn, i, para, nullptr);
    }
    for (SfxItemIter it{rParaAttribs.GetItems()}; !it.IsAtEnd(); it.NextItem())
    {
        YrsInsertAttribImplImpl(yw, *it.GetCurItem(), i, 1);
    }
}

void YrsRemovePara(IYrsTransactionSupplier *const pYrsSupplier,
    OString const& rCommentId, EditDoc const& rDoc, uint32_t const index)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    if (index != 0)
    {
        for (auto paras{index}; paras != 0; --paras)
        {
            i += rDoc.GetObject(paras-1)->Len() + 1;
        }
    }
    uint32_t const len(rDoc.GetObject(index)->Len() + 1);
    ytext_remove_range(yw.pText, yw.pTxn, i, len);
}

void YrsClear(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    auto const len{ytext_len(yw.pText, yw.pTxn)};
    ytext_remove_range(yw.pText, yw.pTxn, 0, len);
}

void YrsInsertParaBreak(IYrsTransactionSupplier *const pYrsSupplier, OString const&&nbsp;rCommentId,
    EditDoc const& rDoc, uint32_t const index, uint32_t const content)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    // need to encode into 1 YText
    char const para[]{ CH_PARA, '\0' };
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += content;
    ContentAttribs const& rParaAttribs{rDoc.GetObject(index)->GetContentAttribs()};
    OString const styleName{OUStringToOString(rParaAttribs.GetStyleSheet()->GetName(), RTL_TEXTENCODING_UTF8)};
    YInput const style{yinput_string(styleName.getStr())};
    YInput attrArray[]{ style };
    char const*const attrNames[]{ "para-style" };
    YInput const attrs{yinput_json_map(const_cast<char**>(attrNames), attrArray, 1)};
    ytext_insert(yw.pText, yw.pTxn, i, para, &attrs);
    for (SfxItemIter it{rParaAttribs.GetItems()}; !it.IsAtEnd(); it.NextItem())
    {
        YrsInsertAttribImplImpl(yw, *it.GetCurItem(), i, 1);
    }
}

void YrsInsertText(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, uint32_t const content, ::std::u16string_view const rText)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += content;
    OString const text{::rtl::OUStringToOString(rText, RTL_TEXTENCODING_UTF8)};
    ytext_insert(yw.pText, yw.pTxn, i, text.getStr(), nullptr);
}

void YrsConnectPara(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, uint32_t const pos)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += pos;
    ytext_remove_range(yw.pText, yw.pTxn, i, 1);
}

void YrsRemoveChars(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, uint32_t const content, uint32_t const length)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += content;
    ytext_remove_range(yw.pText, yw.pTxn, i, length);
}

void YrsSetStyle(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, ::std::u16string_view const rStyle)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += rDoc.GetObject(index)->Len();
    OString const styleName{OUStringToOString(rStyle, RTL_TEXTENCODING_UTF8)};
    YInput const style{yinput_string(styleName.getStr())};
    YInput attrArray[]{ style };
    char const*const attrNames[]{ "para-style" };
    YInput const attrs{yinput_json_map(const_cast<char**>(attrNames), attrArray, 1)};
    ytext_format(yw.pText, yw.pTxn, i, 1, &attrs);
}

void YrsSetParaAttr(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, SfxPoolItem const& rItem)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    i += rDoc.GetObject(index)->Len();
    YrsInsertAttribImplImpl(yw, rItem, i, 1);
}

char const* YrsWhichToAttrName(sal_Int16 const nWhich)
{
    switch (nWhich)
    {
        case EE_CHAR_COLOR:
            return "EE_CHAR_COLOR";
        case EE_CHAR_BKGCOLOR:
            return "EE_CHAR_BKGCOLOR";
        case EE_CHAR_FONTINFO:
            return "EE_CHAR_FONTINFO";
        case EE_CHAR_FONTINFO_CJK:
            return "EE_CHAR_FONTINFO_CJK";
        case EE_CHAR_FONTINFO_CTL:
            return "EE_CHAR_FONTINFO_CTL";
        case EE_CHAR_FONTHEIGHT:
            return "EE_CHAR_FONTHEIGHT";
        case EE_CHAR_FONTHEIGHT_CJK:
            return "EE_CHAR_FONTHEIGHT_CJK";
        case EE_CHAR_FONTHEIGHT_CTL:
            return "EE_CHAR_FONTHEIGHT_CTL";
        case EE_CHAR_FONTWIDTH:
            return "EE_CHAR_FONTWIDTH";
        case EE_CHAR_WEIGHT:
            return "EE_CHAR_WEIGHT";
        case EE_CHAR_WEIGHT_CJK:
            return "EE_CHAR_WEIGHT_CJK";
        case EE_CHAR_WEIGHT_CTL:
            return "EE_CHAR_WEIGHT_CTL";
        case EE_CHAR_UNDERLINE:
            return "EE_CHAR_UNDERLINE";
        case EE_CHAR_OVERLINE:
            return "EE_CHAR_OVERLINE";
        case EE_CHAR_STRIKEOUT:
            return "EE_CHAR_STRIKEOUT";
        case EE_CHAR_ITALIC:
            return "EE_CHAR_ITALIC";
        case EE_CHAR_ITALIC_CJK:
            return "EE_CHAR_ITALIC_CJK";
        case EE_CHAR_ITALIC_CTL:
            return "EE_CHAR_ITALIC_CTL";
        case EE_CHAR_OUTLINE:
            return "EE_CHAR_OUTLINE";
        case EE_CHAR_SHADOW:
            return "EE_CHAR_SHADOW";
        case EE_CHAR_ESCAPEMENT:
            return "EE_CHAR_ESCAPEMENT";
        case EE_CHAR_PAIRKERNING:
            return "EE_CHAR_PAIRKERNING";
        case EE_CHAR_KERNING:
            return "EE_CHAR_KERNING";
        case EE_CHAR_WLM:
            return "EE_CHAR_WLM";
        case EE_CHAR_LANGUAGE:
            return "EE_CHAR_LANGUAGE";
        case EE_CHAR_LANGUAGE_CJK:
            return "EE_CHAR_LANGUAGE_CJK";
        case EE_CHAR_LANGUAGE_CTL:
            return "EE_CHAR_LANGUAGE_CTL";
        case EE_CHAR_EMPHASISMARK:
            return "EE_CHAR_EMPHASISMARK";
        case EE_CHAR_RELIEF:
            return "EE_CHAR_RELIEF";
        case EE_CHAR_CASEMAP:
            return "EE_CHAR_CASEMAP";
        case EE_PARA_WRITINGDIR:
            return "EE_PARA_WRITINGDIR";
        case EE_PARA_HANGINGPUNCTUATION:
            return "EE_PARA_HANGINGPUNCTUATION";
        case EE_PARA_FORBIDDENRULES:
            return "EE_PARA_FORBIDDENRULES";
        case EE_PARA_ASIANCJKSPACING:
            return "EE_PARA_ASIANCJKSPACING";
//TODO complex, but apparently no way to set this in comment? inline constexpr TypedWhichId<SvxNumBulletItem>          EE_PARA_NUMBULLET          (EE_PARA_START+5);
        case EE_PARA_HYPHENATE:
            return "EE_PARA_HYPHENATE";
        case EE_PARA_HYPHENATE_NO_CAPS:
            return "EE_PARA_HYPHENATE_NO_CAPS";
        case EE_PARA_HYPHENATE_NO_LAST_WORD:
            return "EE_PARA_HYPHENATE_NO_LAST_WORD";
        case EE_PARA_BULLETSTATE:
            return "EE_PARA_BULLETSTATE";
//TODO no way to set this in comment? inline constexpr TypedWhichId<SvxLRSpaceItem>            EE_PARA_OUTLLRSPACE        (EE_PARA_START+10);
        case EE_PARA_OUTLLEVEL:
            return "EE_PARA_OUTLLEVEL";
//TODO complex, but apparently no way to set this in comment? inline constexpr TypedWhichId<SvxBulletItem>             EE_PARA_BULLET             (EE_PARA_START+12);
        case EE_PARA_LRSPACE:
            return "EE_PARA_LRSPACE";
        case EE_PARA_ULSPACE:
            return "EE_PARA_ULSPACE";
        case EE_PARA_SBL:
            return "EE_PARA_SBL";
        case EE_PARA_JUST:
            return "EE_PARA_JUST";
        case EE_PARA_TABS:
            return "EE_PARA_TABS";
        case EE_PARA_JUST_METHOD:
            return "EE_PARA_JUST_METHOD";
        case EE_PARA_VER_JUST:
            return "EE_PARA_VER_JUST";
        default:
            assert(false);
    }
}

void YrsRemoveAttrib(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId,
    EditDoc const& rDoc, uint32_t const index, sal_uInt16 const nWhich, sal_Int32 const nStart, sal_Int32 const nEnd)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    YInput const attr{yinput_null()};
    char const*const attrName{YrsWhichToAttrName(nWhich)};
    YInput const attrs{yinput_json_map(const_cast<char**>(&attrName), const_cast<YInput*>(&attr), 1)};
    ytext_format(yw.pText, yw.pTxn, i + nStart, nEnd - nStart, &attrs);
}

void YrsInsertAttrib(IYrsTransactionSupplier *const pYrsSupplier, OString const& rCommentId, EditDoc const& rDoc, uint32_t const index, EditCharAttrib const*const pAttr)
{
    YrsWrite const yw{GetYrsWrite(pYrsSupplier, rCommentId)};
    if (yw.pTxn == nullptr)
    {
        return;
    }
    uint32_t i{0};
    for (auto paras{index}; paras != 0; --paras)
    {
        i += rDoc.GetObject(paras-1)->Len() + 1;
    }
    YrsInsertAttribImpl(yw, i, pAttr);
}

uint64_t YrsReadInt(YOutput const& rValue)
{
    // with the v1 encoding, JSON is being sent apparently (like "family":2) , which has issues with integers being sometimes read as floats so workaround here
    if (rValue.tag == Y_JSON_INT)
    {
        return rValue.value.integer;
    }
    else
    {
        yvalidate(rValue.tag == Y_JSON_NUM);
        return ::std::lround(rValue.value.num);
    }
}

void YrsImplInsertAttr(SfxItemSet & rSet, ::std::vector<sal_uInt16> *const pRemoved,
    char const*const pKey, YOutput const& rValue)
{
    sal_uInt16 nWhich{0};
    if (strcmp(pKey, "EE_CHAR_COLOR") == 0)
    {
        nWhich = EE_CHAR_COLOR;
    }
    else if (strcmp(pKey, "EE_CHAR_BKGCOLOR") == 0)
    {
        nWhich = EE_CHAR_BKGCOLOR;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTINFO") == 0)
    {
        nWhich = EE_CHAR_FONTINFO;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTINFO_CJK") == 0)
    {
        nWhich = EE_CHAR_FONTINFO_CJK;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTINFO_CTL") == 0)
    {
        nWhich = EE_CHAR_FONTINFO_CTL;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTHEIGHT") == 0)
    {
        nWhich = EE_CHAR_FONTHEIGHT;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTHEIGHT_CJK") == 0)
    {
        nWhich = EE_CHAR_FONTHEIGHT_CJK;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTHEIGHT_CTL") == 0)
    {
        nWhich = EE_CHAR_FONTHEIGHT_CTL;
    }
    else if (strcmp(pKey, "EE_CHAR_FONTWIDTH") == 0)
    {
        nWhich = EE_CHAR_FONTWIDTH;
    }
    else if (strcmp(pKey, "EE_CHAR_WEIGHT") == 0)
    {
        nWhich = EE_CHAR_WEIGHT;
    }
    else if (strcmp(pKey, "EE_CHAR_WEIGHT_CJK") == 0)
    {
        nWhich = EE_CHAR_WEIGHT_CJK;
    }
    else if (strcmp(pKey, "EE_CHAR_WEIGHT_CTL") == 0)
    {
        nWhich = EE_CHAR_WEIGHT_CTL;
    }
    else if (strcmp(pKey, "EE_CHAR_UNDERLINE") == 0)
    {
        nWhich = EE_CHAR_UNDERLINE;
    }
    else if (strcmp(pKey, "EE_CHAR_OVERLINE") == 0)
    {
        nWhich = EE_CHAR_OVERLINE;
    }
    else if (strcmp(pKey, "EE_CHAR_STRIKEOUT") == 0)
    {
        nWhich = EE_CHAR_STRIKEOUT;
    }
    else if (strcmp(pKey, "EE_CHAR_ITALIC") == 0)
    {
        nWhich = EE_CHAR_ITALIC;
    }
    else if (strcmp(pKey, "EE_CHAR_ITALIC_CJK") == 0)
    {
        nWhich = EE_CHAR_ITALIC_CJK;
    }
    else if (strcmp(pKey, "EE_CHAR_ITALIC_CTL") == 0)
    {
        nWhich = EE_CHAR_ITALIC_CTL;
    }
    else if (strcmp(pKey, "EE_CHAR_OUTLINE") == 0)
    {
        nWhich = EE_CHAR_OUTLINE;
    }
    else if (strcmp(pKey, "EE_CHAR_SHADOW") == 0)
    {
        nWhich = EE_CHAR_SHADOW;
    }
    else if (strcmp(pKey, "EE_CHAR_ESCAPEMENT") == 0)
    {
        nWhich = EE_CHAR_ESCAPEMENT;
    }
    else if (strcmp(pKey, "EE_CHAR_PAIRKERNING") == 0)
    {
        nWhich = EE_CHAR_PAIRKERNING;
    }
    else if (strcmp(pKey, "EE_CHAR_KERNING") == 0)
    {
        nWhich = EE_CHAR_KERNING;
    }
    else if (strcmp(pKey, "EE_CHAR_WLM") == 0)
    {
        nWhich = EE_CHAR_WLM;
    }
    else if (strcmp(pKey, "EE_CHAR_LANGUAGE") == 0)
    {
        nWhich = EE_CHAR_LANGUAGE;
    }
    else if (strcmp(pKey, "EE_CHAR_LANGUAGE_CJK") == 0)
    {
        nWhich = EE_CHAR_LANGUAGE_CJK;
    }
    else if (strcmp(pKey, "EE_CHAR_LANGUAGE_CTL") == 0)
    {
        nWhich = EE_CHAR_LANGUAGE_CTL;
    }
    else if (strcmp(pKey, "EE_CHAR_EMPHASISMARK") == 0)
    {
        nWhich = EE_CHAR_EMPHASISMARK;
    }
    else if (strcmp(pKey, "EE_CHAR_RELIEF") == 0)
    {
        nWhich = EE_CHAR_RELIEF;
    }
    else if (strcmp(pKey, "EE_CHAR_CASEMAP") == 0)
    {
        nWhich = EE_CHAR_CASEMAP;
    }
    else if (strcmp(pKey, "EE_PARA_WRITINGDIR") == 0)
    {
        nWhich = EE_PARA_WRITINGDIR;
    }
    else if (strcmp(pKey, "EE_PARA_HANGINGPUNCTUATION") == 0)
    {
        nWhich = EE_PARA_HANGINGPUNCTUATION;
    }
    else if (strcmp(pKey, "EE_PARA_FORBIDDENRULES") == 0)
    {
        nWhich = EE_PARA_FORBIDDENRULES;
    }
    else if (strcmp(pKey, "EE_PARA_ASIANCJKSPACING") == 0)
    {
        nWhich = EE_PARA_ASIANCJKSPACING;
    }
    else if (strcmp(pKey, "EE_PARA_HYPHENATE") == 0)
    {
        nWhich = EE_PARA_HYPHENATE;
    }
    else if (strcmp(pKey, "EE_PARA_HYPHENATE_NO_CAPS") == 0)
    {
        nWhich = EE_PARA_HYPHENATE_NO_CAPS;
    }
    else if (strcmp(pKey, "EE_PARA_HYPHENATE_NO_LAST_WORD") == 0)
    {
        nWhich = EE_PARA_HYPHENATE_NO_LAST_WORD;
    }
    else if (strcmp(pKey, "EE_PARA_BULLETSTATE") == 0)
    {
        nWhich = EE_PARA_BULLETSTATE;
    }
    else if (strcmp(pKey, "EE_PARA_OUTLLEVEL") == 0)
    {
        nWhich = EE_PARA_OUTLLEVEL;
    }
    else if (strcmp(pKey, "EE_PARA_LRSPACE") == 0)
    {
        nWhich = EE_PARA_LRSPACE;
    }
    else if (strcmp(pKey, "EE_PARA_ULSPACE") == 0)
    {
        nWhich = EE_PARA_ULSPACE;
    }
    else if (strcmp(pKey, "EE_PARA_SBL") == 0)
    {
        nWhich = EE_PARA_SBL;
    }
    else if (strcmp(pKey, "EE_PARA_JUST") == 0)
    {
        nWhich = EE_PARA_JUST;
    }
    else if (strcmp(pKey, "EE_PARA_TABS") == 0)
    {
        nWhich = EE_PARA_TABS;
    }
    else if (strcmp(pKey, "EE_PARA_JUST_METHOD") == 0)
    {
        nWhich = EE_PARA_JUST_METHOD;
    }
    else if (strcmp(pKey, "EE_PARA_VER_JUST") == 0)
    {
        nWhich = EE_PARA_VER_JUST;
    }
    else if (pKey[0] == 'E' && pKey[1] == 'E' && pKey[2] == '_')
    {
        abort();
    }
    else
    {
        return;
    }

    if (rValue.tag == Y_JSON_NULL)
    {
        assert(pRemoved);
        if (pRemoved)
        {
            pRemoved->emplace_back(nWhich);
        }
        return;
    }
    else switch (nWhich)
    {
        case EE_CHAR_COLOR:
        case EE_CHAR_BKGCOLOR:
        {
            Color const c(ColorTransparency, YrsReadInt(rValue));
            SvxColorItem const item(c, nWhich);
            rSet.Put(item);
            break;
        }
        case EE_CHAR_FONTINFO:
        case EE_CHAR_FONTINFO_CJK:
        case EE_CHAR_FONTINFO_CTL:
        {
            yvalidate(rValue.tag == Y_JSON_MAP);
            ::std::optional<OUString> oFamilyName;
            ::std::optional<OUString> oStyle;
            ::std::optional<FontFamily> oFamily;
            ::std::optional<FontPitch> oPitch;
            ::std::optional<rtl_TextEncoding> oCharset;
            for (decltype(rValue.len) i = 0; i < rValue.len; ++i)
            {
--> --------------------

--> maximum size reached

--> --------------------

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

¤ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ¤

*© 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.