diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/bastyp | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/bastyp')
-rw-r--r-- | sw/source/core/bastyp/SwSmartTagMgr.cxx | 71 | ||||
-rw-r--r-- | sw/source/core/bastyp/bparr.cxx | 505 | ||||
-rw-r--r-- | sw/source/core/bastyp/breakit.cxx | 184 | ||||
-rw-r--r-- | sw/source/core/bastyp/calc.cxx | 1442 | ||||
-rw-r--r-- | sw/source/core/bastyp/checkit.cxx | 33 | ||||
-rw-r--r-- | sw/source/core/bastyp/index.cxx | 392 | ||||
-rw-r--r-- | sw/source/core/bastyp/init.cxx | 811 | ||||
-rw-r--r-- | sw/source/core/bastyp/proofreadingiterator.cxx | 67 | ||||
-rw-r--r-- | sw/source/core/bastyp/swcache.cxx | 506 | ||||
-rw-r--r-- | sw/source/core/bastyp/swrect.cxx | 202 | ||||
-rw-r--r-- | sw/source/core/bastyp/swregion.cxx | 229 | ||||
-rw-r--r-- | sw/source/core/bastyp/swtypes.cxx | 66 | ||||
-rw-r--r-- | sw/source/core/bastyp/tabcol.cxx | 85 |
13 files changed, 4593 insertions, 0 deletions
diff --git a/sw/source/core/bastyp/SwSmartTagMgr.cxx b/sw/source/core/bastyp/SwSmartTagMgr.cxx new file mode 100644 index 0000000000..3a28af822d --- /dev/null +++ b/sw/source/core/bastyp/SwSmartTagMgr.cxx @@ -0,0 +1,71 @@ +/* -*- 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 <SwSmartTagMgr.hxx> + +#include <docsh.hxx> +#include <swmodule.hxx> +#include <unotools/configmgr.hxx> +#include <vcl/svapp.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::uno; + +rtl::Reference<SwSmartTagMgr> SwSmartTagMgr::spTheSwSmartTagMgr; + +SwSmartTagMgr& SwSmartTagMgr::Get() +{ + if (!spTheSwSmartTagMgr) + { + OUString sModuleName + = !utl::ConfigManager::IsFuzzing() ? SwDocShell::Factory().GetModuleName() : "Writer"; + spTheSwSmartTagMgr = new SwSmartTagMgr(sModuleName); + spTheSwSmartTagMgr->Init(u"Writer"); + } + return *spTheSwSmartTagMgr; +} + +SwSmartTagMgr::SwSmartTagMgr(const OUString& rModuleName) + : SmartTagMgr(rModuleName) +{ +} + +SwSmartTagMgr::~SwSmartTagMgr() {} + +void SwSmartTagMgr::modified(const lang::EventObject& rEO) +{ + SolarMutexGuard aGuard; + + // Installed recognizers have changed. We remove all existing smart tags: + SwModule::CheckSpellChanges(false, true, true, true); + + SmartTagMgr::modified(rEO); +} + +void SwSmartTagMgr::changesOccurred(const util::ChangesEvent& rEvent) +{ + SolarMutexGuard aGuard; + + // Configuration has changed. We remove all existing smart tags: + SwModule::CheckSpellChanges(false, true, true, true); + + SmartTagMgr::changesOccurred(rEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/bparr.cxx b/sw/source/core/bastyp/bparr.cxx new file mode 100644 index 0000000000..b99385bfd3 --- /dev/null +++ b/sw/source/core/bastyp/bparr.cxx @@ -0,0 +1,505 @@ +/* -*- 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 <bparr.hxx> +#include <tools/long.hxx> +#include <limits.h> +#include <string.h> + +/** Resize block management by this constant. + As a result there are approx. 20 * MAXENTRY == 20000 entries available */ +const sal_uInt16 nBlockGrowSize = 20; + +#if OSL_DEBUG_LEVEL > 2 +#define CHECKIDX( p, n, i, c ) CheckIdx( p, n, i, c ); +void CheckIdx( BlockInfo** ppInf, sal_uInt16 nBlock, sal_Int32 nSize, sal_uInt16 nCur ) +{ + assert( !nSize || nCur < nBlock ); // BigPtrArray: CurIndex invalid + + sal_Int32 nIdx = 0; + for( sal_uInt16 nCnt = 0; nCnt < nBlock; ++nCnt, ++ppInf ) + { + nIdx += (*ppInf)->nElem; + // Array with holes is not allowed + assert( !nCnt || (*(ppInf-1))->nEnd + 1 == (*ppInf)->nStart ); + } + assert(nIdx == nSize); // invalid count in nSize +} +#else +#define CHECKIDX( p, n, i, c ) +#endif + +BigPtrArray::BigPtrArray() +{ + m_nBlock = m_nCur = 0; + m_nSize = 0; + m_nMaxBlock = nBlockGrowSize; + m_ppInf.reset( new BlockInfo* [ m_nMaxBlock ] ); +} + +BigPtrArray::~BigPtrArray() +{ + if( m_nBlock ) + { + BlockInfo** pp = m_ppInf.get(); + for( sal_uInt16 n = 0; n < m_nBlock; ++n, ++pp ) + { + delete *pp; + } + } +} + +// Also moving is done simply here. Optimization is useless because of the +// division of this field into multiple parts. +void BigPtrArray::Move( sal_Int32 from, sal_Int32 to ) +{ + if (from != to) + { + sal_uInt16 cur = Index2Block( from ); + BlockInfo* p = m_ppInf[ cur ]; + BigPtrEntry* pElem = p->mvData[ from - p->nStart ]; + Insert( pElem, to ); // insert first, then delete! + Remove( ( to < from ) ? ( from + 1 ) : from ); + } +} + +BigPtrEntry* BigPtrArray::operator[]( sal_Int32 idx ) const +{ + assert(idx < m_nSize); // operator[]: Index out of bounds + m_nCur = Index2Block( idx ); + BlockInfo* p = m_ppInf[ m_nCur ]; + return p->mvData[ idx - p->nStart ]; +} + +/** Search a block at a given position */ +sal_uInt16 BigPtrArray::Index2Block( sal_Int32 pos ) const +{ + // last used block? + BlockInfo* p = m_ppInf[ m_nCur ]; + if( p->nStart <= pos && p->nEnd >= pos ) + return m_nCur; + // Index = 0? + if( !pos ) + return 0; + + // following one? + if( m_nCur < ( m_nBlock - 1 ) ) + { + p = m_ppInf[ m_nCur+1 ]; + if( p->nStart <= pos && p->nEnd >= pos ) + return m_nCur+1; + } + // previous one? + else if( pos < p->nStart && m_nCur > 0 ) + { + p = m_ppInf[ m_nCur-1 ]; + if( p->nStart <= pos && p->nEnd >= pos ) + return m_nCur-1; + } + + // binary search: always successful + sal_uInt16 lower = 0, upper = m_nBlock - 1; + sal_uInt16 cur = 0; + for(;;) + { + sal_uInt16 n = lower + ( upper - lower ) / 2; + cur = ( n == cur ) ? n+1 : n; + p = m_ppInf[ cur ]; + if( p->nStart <= pos && p->nEnd >= pos ) + return cur; + + if( p->nStart > pos ) + upper = cur; + else + lower = cur; + } +} + +/** Update all index areas + + @param pos last correct block (starting point) +*/ +void BigPtrArray::UpdIndex( sal_uInt16 pos ) +{ + BlockInfo** pp = m_ppInf.get() + pos; + sal_Int32 idx = (*pp)->nEnd + 1; + while( ++pos < m_nBlock ) + { + BlockInfo* p = *++pp; + p->nStart = idx; + idx += p->nElem; + p->nEnd = idx - 1; + } +} + +/** Create and insert new block + + Existing blocks will be moved rearward. + + @param pos Position at which the new block should be created. +*/ +BlockInfo* BigPtrArray::InsBlock( sal_uInt16 pos ) +{ + if( m_nBlock == m_nMaxBlock ) + { + // than extend the array first + BlockInfo** ppNew = new BlockInfo* [ m_nMaxBlock + nBlockGrowSize ]; + memcpy( ppNew, m_ppInf.get(), m_nMaxBlock * sizeof( BlockInfo* )); + m_nMaxBlock += nBlockGrowSize; + m_ppInf.reset( ppNew ); + } + if( pos != m_nBlock ) + { + memmove( m_ppInf.get() + pos+1, m_ppInf.get() + pos, + ( m_nBlock - pos ) * sizeof( BlockInfo* )); + } + ++m_nBlock; + BlockInfo* p = new BlockInfo; + m_ppInf[ pos ] = p; + + if( pos ) + p->nStart = p->nEnd = m_ppInf[ pos-1 ]->nEnd + 1; + else + p->nStart = p->nEnd = 0; + + p->nEnd--; // no elements + p->nElem = 0; + p->pBigArr = this; + return p; +} + +void BigPtrArray::BlockDel( sal_uInt16 nDel ) +{ + m_nBlock = m_nBlock - nDel; + if( m_nMaxBlock - m_nBlock > nBlockGrowSize ) + { + // than shrink array + nDel = (( m_nBlock / nBlockGrowSize ) + 1 ) * nBlockGrowSize; + BlockInfo** ppNew = new BlockInfo* [ nDel ]; + memcpy( ppNew, m_ppInf.get(), m_nBlock * sizeof( BlockInfo* )); + m_ppInf.reset( ppNew ); + m_nMaxBlock = nDel; + } +} + +void BigPtrArray::Insert( BigPtrEntry* pElem, sal_Int32 pos ) +{ + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); + + BlockInfo* p; + sal_uInt16 cur; + if( !m_nSize ) + { + // special case: insert first element + cur = 0; + p = InsBlock( cur ); + } + else if( pos == m_nSize ) + { + // special case: insert at end + cur = m_nBlock - 1; + p = m_ppInf[ cur ]; + if( p->nElem == MAXENTRY ) + // the last block is full, create a new one + p = InsBlock( ++cur ); + } + else + { + // standard case: + cur = Index2Block( pos ); + p = m_ppInf[ cur ]; + } + + if( p->nElem == MAXENTRY ) + { + // does the last entry fit into the next block? + BlockInfo* q; + if( cur < ( m_nBlock - 1 ) && m_ppInf[ cur+1 ]->nElem < MAXENTRY ) + { + q = m_ppInf[ cur+1 ]; + if( q->nElem ) + { + int nCount = q->nElem; + auto pFrom = q->mvData.begin() + nCount; + auto pTo = pFrom + 1; + while( nCount-- ) + { + *--pTo = *--pFrom; + ++((*pTo)->m_nOffset); + } + } + q->nStart--; + q->nEnd--; + } + else + { + // If it does not fit, then insert a new block. But if there is more + // than 50% space in the array then compress first. + if( /*nBlock == nMaxBlock &&*/ + m_nBlock > ( m_nSize / ( MAXENTRY / 2 ) ) && + cur >= Compress() ) + { + // Something was moved before the current position and all + // pointer might be invalid. Thus restart Insert. + Insert( pElem, pos ); + return ; + } + + q = InsBlock( cur+1 ); + } + + // entry does not fit anymore - clear space + BigPtrEntry* pLast = p->mvData[ MAXENTRY-1 ]; + pLast->m_nOffset = 0; + pLast->m_pBlock = q; + + q->mvData[ 0 ] = pLast; + q->nElem++; + q->nEnd++; + + p->nEnd--; + p->nElem--; + } + // now we have free space - insert + pos -= p->nStart; + assert(pos < MAXENTRY); + if( pos != p->nElem ) + { + int nCount = p->nElem - sal_uInt16(pos); + auto pFrom = p->mvData.begin() + p->nElem; + auto pTo = pFrom + 1; + while( nCount-- ) + { + *--pTo = *--pFrom; + ++( *pTo )->m_nOffset; + } + } + // insert element and update indices + pElem->m_nOffset = sal_uInt16(pos); + pElem->m_pBlock = p; + p->mvData[ pos ] = pElem; + p->nEnd++; + p->nElem++; + m_nSize++; + if( cur != ( m_nBlock - 1 ) ) UpdIndex( cur ); + m_nCur = cur; + + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); +} + +void BigPtrArray::Remove( sal_Int32 pos, sal_Int32 n ) +{ + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); + + sal_uInt16 nBlkdel = 0; // deleted blocks + sal_uInt16 cur = Index2Block( pos ); // current block number + sal_uInt16 nBlk1 = cur; // 1st treated block + sal_uInt16 nBlk1del = USHRT_MAX; // 1st deleted block + BlockInfo* p = m_ppInf[ cur ]; + pos -= p->nStart; + + sal_Int32 nElem = n; + while( nElem ) + { + sal_uInt16 nel = p->nElem - sal_uInt16(pos); + if( sal_Int32(nel) > nElem ) + nel = sal_uInt16(nElem); + // move elements if needed + if( ( pos + nel ) < sal_Int32(p->nElem) ) + { + auto pTo = p->mvData.begin() + pos; + auto pFrom = pTo + nel; + int nCount = p->nElem - nel - sal_uInt16(pos); + while( nCount-- ) + { + *pTo = *pFrom++; + (*pTo)->m_nOffset = (*pTo)->m_nOffset - nel; + ++pTo; + } + } + p->nEnd -= nel; + p->nElem = p->nElem - nel; + // possibly delete block completely + if( !p->nElem ) + { + nBlkdel++; + if( USHRT_MAX == nBlk1del ) + nBlk1del = cur; + } + nElem -= nel; + if( !nElem ) + break; + p = m_ppInf[ ++cur ]; + pos = 0; + } + + // update table if blocks were removed + if( nBlkdel ) + { + for( sal_uInt16 i = nBlk1del; i < ( nBlk1del + nBlkdel ); i++ ) + delete m_ppInf[ i ]; + + if( ( nBlk1del + nBlkdel ) < m_nBlock ) + { + memmove( m_ppInf.get() + nBlk1del, m_ppInf.get() + nBlk1del + nBlkdel, + ( m_nBlock - nBlkdel - nBlk1del ) * sizeof( BlockInfo* ) ); + + // UpdateIdx updates the successor thus start before first elem + if( !nBlk1 ) + { + p = m_ppInf[ 0 ]; + p->nStart = 0; + p->nEnd = p->nElem-1; + } + else + { + --nBlk1; + } + } + BlockDel( nBlkdel ); // blocks were deleted + } + + m_nSize -= n; + if( nBlk1 != ( m_nBlock - 1 ) && m_nSize ) + UpdIndex( nBlk1 ); + m_nCur = nBlk1; + + // call Compress() if there is more than 50% space in the array + if( m_nBlock > ( m_nSize / ( MAXENTRY / 2 ) ) ) + Compress(); + + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); +} + +void BigPtrArray::Replace( sal_Int32 idx, BigPtrEntry* pElem) +{ + assert(idx < m_nSize); // Index out of bounds + m_nCur = Index2Block( idx ); + BlockInfo* p = m_ppInf[ m_nCur ]; + pElem->m_nOffset = sal_uInt16(idx - p->nStart); + pElem->m_pBlock = p; + p->mvData[ idx - p->nStart ] = pElem; +} + +/** Compress the array */ +sal_uInt16 BigPtrArray::Compress() +{ + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); + + // Iterate over InfoBlock array from beginning to end. If there is a deleted + // block in between so move all following ones accordingly. The pointer <pp> + // represents the "old" and <qq> the "new" array. + BlockInfo** pp = m_ppInf.get(), **qq = pp; + BlockInfo* p; + BlockInfo* pLast(nullptr); // last empty block + sal_uInt16 nLast = 0; // missing elements + sal_uInt16 nBlkdel = 0; // number of deleted blocks + sal_uInt16 nFirstChgPos = USHRT_MAX; // at which position was the 1st change? + + // convert fill percentage into number of remaining elements + short const nMax = MAXENTRY - tools::Long(MAXENTRY) * COMPRESSLVL / 100; + + for( sal_uInt16 cur = 0; cur < m_nBlock; ++cur ) + { + p = *pp++; + sal_uInt16 n = p->nElem; + // Check if a not completely full block will be ignored. This happens if + // the current block would have to be split but the filling of the + // inspected block is already over its threshold value. In this case we + // do not fill more (it's expensive because of a double memmove() call) + if( nLast && ( n > nLast ) && ( nLast < nMax ) ) + nLast = 0; + if( nLast ) + { + if( USHRT_MAX == nFirstChgPos ) + nFirstChgPos = cur; + + // Not full yet? Then fill up. + if( n > nLast ) + n = nLast; + + // move elements from current to last block + auto pElem = pLast->mvData.begin() + pLast->nElem; + auto pFrom = p->mvData.begin(); + for( sal_uInt16 nCount = n, nOff = pLast->nElem; + nCount; --nCount, ++pElem ) + { + *pElem = *pFrom++; + (*pElem)->m_pBlock = pLast; + (*pElem)->m_nOffset = nOff++; + } + + // adjustment + pLast->nElem = pLast->nElem + n; + nLast = nLast - n; + p->nElem = p->nElem - n; + + // Is the current block now empty as a result? + if( !p->nElem ) + { + // then remove + delete p; + p = nullptr; + ++nBlkdel; + } + else + { + pElem = p->mvData.begin(); + pFrom = pElem + n; + int nCount = p->nElem; + while( nCount-- ) + { + *pElem = *pFrom++; + (*pElem)->m_nOffset = (*pElem)->m_nOffset - n; + ++pElem; + } + } + } + + if( p ) // BlockInfo was not deleted + { + *qq++ = p; // adjust to correct position + + // keep the potentially existing last half-full block + if( !nLast && p->nElem < MAXENTRY ) + { + pLast = p; + nLast = MAXENTRY - p->nElem; + } + } + } + + // if blocks were deleted shrink BlockInfo array if needed + if( nBlkdel ) + BlockDel( nBlkdel ); + + // and re-index + p = m_ppInf[ 0 ]; + p->nEnd = p->nElem - 1; + UpdIndex( 0 ); + + if( m_nCur >= nFirstChgPos ) + m_nCur = 0; + + CHECKIDX( m_ppInf.get(), m_nBlock, m_nSize, m_nCur ); + + return nFirstChgPos; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/breakit.cxx b/sw/source/core/bastyp/breakit.cxx new file mode 100644 index 0000000000..33f55a1d54 --- /dev/null +++ b/sw/source/core/bastyp/breakit.cxx @@ -0,0 +1,184 @@ +/* -*- 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 <breakit.hxx> +#include <swtypes.hxx> + +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/BreakIterator.hpp> +#include <svl/languageoptions.hxx> +#include <unicode/uchar.h> +#include <unotools/localedatawrapper.hxx> +#include <algorithm> +#include <utility> + +using namespace com::sun::star; + +SwBreakIt* g_pBreakIt = nullptr; + +void SwBreakIt::Create_( const uno::Reference<uno::XComponentContext> & rxContext ) +{ + delete g_pBreakIt; + g_pBreakIt = new SwBreakIt( rxContext ); +} + +void SwBreakIt::Delete_() +{ + delete g_pBreakIt; + g_pBreakIt = nullptr; +} + +SwBreakIt * SwBreakIt::Get() +{ + return g_pBreakIt; +} + +SwBreakIt::SwBreakIt( uno::Reference<uno::XComponentContext> xContext ) + : m_xContext(std::move(xContext)) + , m_xBreak(i18n::BreakIterator::create(m_xContext)) + , m_aForbiddenLang(LANGUAGE_DONTKNOW) +{ +} + +void SwBreakIt::GetLocale_( const LanguageType aLang ) +{ + if (m_xLanguageTag) + m_xLanguageTag->reset(aLang); + else + m_xLanguageTag.reset(new LanguageTag(aLang)); +} + +void SwBreakIt::GetLocale_( const LanguageTag& rLanguageTag ) +{ + if (m_xLanguageTag) + *m_xLanguageTag = rLanguageTag; + else + m_xLanguageTag.reset(new LanguageTag(rLanguageTag)); +} + +void SwBreakIt::GetForbidden_( const LanguageType aLang ) +{ + LocaleDataWrapper aWrap(m_xContext, GetLanguageTag(aLang)); + + m_aForbiddenLang = aLang; + m_oForbidden.emplace(aWrap.getForbiddenCharacters()); +} + +sal_uInt16 SwBreakIt::GetRealScriptOfText( const OUString& rText, sal_Int32 nPos ) const +{ + sal_uInt16 nScript = i18n::ScriptType::WEAK; + if (!rText.isEmpty()) + { + if( nPos && nPos == rText.getLength() ) + --nPos; + else if( nPos < 0) + nPos = 0; + + nScript = m_xBreak->getScriptType(rText, nPos); + sal_Int32 nChgPos = 0; + if (i18n::ScriptType::WEAK == nScript && nPos >= 0 && nPos + 1 < rText.getLength()) + { + // A weak character followed by a mark may be meant to combine with + // the mark, so prefer the following character's script + switch (u_charType(rText[nPos + 1])) + { + case U_NON_SPACING_MARK: + case U_ENCLOSING_MARK: + case U_COMBINING_SPACING_MARK: + nScript = m_xBreak->getScriptType(rText, nPos+1); + break; + } + } + if( i18n::ScriptType::WEAK == nScript && nPos ) + { + nChgPos = m_xBreak->beginOfScript(rText, nPos, nScript); + if( 0 < nChgPos ) + nScript = m_xBreak->getScriptType(rText, nChgPos-1); + } + + if( i18n::ScriptType::WEAK == nScript ) + { + nChgPos = m_xBreak->endOfScript(rText, nPos, nScript); + if( rText.getLength() > nChgPos && 0 <= nChgPos ) + nScript = m_xBreak->getScriptType(rText, nChgPos); + } + } + if( i18n::ScriptType::WEAK == nScript ) + nScript = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ); + return nScript; +} + +SvtScriptType SwBreakIt::GetAllScriptsOfText( const OUString& rText ) const +{ + const SvtScriptType coAllScripts = SvtScriptType::LATIN | + SvtScriptType::ASIAN | + SvtScriptType::COMPLEX; + SvtScriptType nRet = SvtScriptType::NONE; + sal_uInt16 nScript = 0; + if (!rText.isEmpty()) + { + for( sal_Int32 n = 0, nEnd = rText.getLength(); n < nEnd; + n = m_xBreak->endOfScript(rText, n, nScript) ) + { + nScript = m_xBreak->getScriptType(rText, n); + switch( nScript ) + { + case i18n::ScriptType::LATIN: nRet |= SvtScriptType::LATIN; break; + case i18n::ScriptType::ASIAN: nRet |= SvtScriptType::ASIAN; break; + case i18n::ScriptType::COMPLEX: nRet |= SvtScriptType::COMPLEX; break; + case i18n::ScriptType::WEAK: + if( nRet == SvtScriptType::NONE ) + nRet |= coAllScripts; + break; + } + if( coAllScripts == nRet ) + break; + } + } + return nRet; +} + +sal_Int32 SwBreakIt::getGraphemeCount(const OUString& rText, + sal_Int32 nStart, sal_Int32 nEnd) const +{ + sal_Int32 nGraphemeCount = 0; + + sal_Int32 nCurPos = std::max(static_cast<sal_Int32>(0), nStart); + while (nCurPos < nEnd) + { + // fdo#49208 cheat and assume that nothing can combine with a space + // to form a single grapheme + if (rText[nCurPos] == ' ') + { + ++nCurPos; + } + else + { + sal_Int32 nCount2 = 1; + nCurPos = m_xBreak->nextCharacters(rText, nCurPos, lang::Locale(), + i18n::CharacterIteratorMode::SKIPCELL, nCount2, nCount2); + } + ++nGraphemeCount; + } + + return nGraphemeCount; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/calc.cxx b/sw/source/core/bastyp/calc.cxx new file mode 100644 index 0000000000..0c9643317a --- /dev/null +++ b/sw/source/core/bastyp/calc.cxx @@ -0,0 +1,1442 @@ +/* -*- 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 <config_features.h> +#include <config_fuzzers.h> + +#include <calc.hxx> +#include <cfloat> +#include <climits> +#include <memory> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <cstdlib> +#include <dbmgr.hxx> +#include <docfld.hxx> +#include <docstat.hxx> +#include <doc.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentStatistics.hxx> +#include <editeng/langitem.hxx> +#include <expfld.hxx> +#include <hintids.hxx> +#include <o3tl/temporary.hxx> +#include <osl/diagnose.h> +#include <rtl/math.hxx> +#include <shellres.hxx> +#include <svl/numformat.hxx> +#include <svl/languageoptions.hxx> +#include <swmodule.hxx> +#include <swtypes.hxx> +#include <unotools/charclass.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/useroptions.hxx> +#include <usrfld.hxx> +#include <utility> +#include <viewsh.hxx> +#include <com/sun/star/i18n/KParseTokens.hpp> +#include <com/sun/star/i18n/KParseType.hpp> + +using namespace ::com::sun::star; + +const char sCalc_Add[] = "add"; +const char sCalc_Sub[] = "sub"; +const char sCalc_Mul[] = "mul"; +const char sCalc_Div[] = "div"; +const char sCalc_Phd[] = "phd"; +const char sCalc_Sqrt[] = "sqrt"; +const char sCalc_Pow[] = "pow"; +const char sCalc_Or[] = "or"; +const char sCalc_Xor[] = "xor"; +const char sCalc_And[] = "and"; +const char sCalc_Not[] = "not"; +const char sCalc_Eq[] = "eq"; +const char sCalc_Neq[] = "neq"; +const char sCalc_Leq[] = "leq"; +const char sCalc_Geq[] = "geq"; +const char sCalc_L[] = "l"; +const char sCalc_G[] = "g"; +const char sCalc_Sum[] = "sum"; +const char sCalc_Mean[] = "mean"; +const char sCalc_Min[] = "min"; +const char sCalc_Max[] = "max"; +const char sCalc_Sin[] = "sin"; +const char sCalc_Cos[] = "cos"; +const char sCalc_Tan[] = "tan"; +const char sCalc_Asin[] = "asin"; +const char sCalc_Acos[] = "acos"; +const char sCalc_Atan[] = "atan"; +const char sCalc_Round[]= "round"; +const char sCalc_Date[] = "date"; +const char sCalc_Product[] = "product"; +const char sCalc_Average[] = "average"; +const char sCalc_Count[]= "count"; +const char sCalc_Sign[] = "sign"; +const char sCalc_Abs[] = "abs"; +const char sCalc_Int[] = "int"; + +// ATTENTION: sorted list of all operators +struct CalcOp +{ + union{ + const char* pName; + const OUString* pUName; + }; + SwCalcOper eOp; +}; + +CalcOp const aOpTable[] = { +/* ABS */ {{sCalc_Abs}, CALC_ABS}, // Abs (since LibreOffice 7.1) +/* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arc cosine +/* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition +/* AND */ {{sCalc_And}, CALC_AND}, // log. AND +/* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arc sine +/* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arc tangent +/* AVERAGE */ {{sCalc_Average}, CALC_AVERAGE}, // Average (since LibreOffice 7.1) +/* COS */ {{sCalc_Cos}, CALC_COS}, // Cosine +/* COUNT */ {{sCalc_Count}, CALC_COUNT}, // Count (since LibreOffice 7.1) +/* DATE */ {{sCalc_Date}, CALC_DATE}, // Date +/* DIV */ {{sCalc_Div}, CALC_DIV}, // Division +/* EQ */ {{sCalc_Eq}, CALC_EQ}, // Equality +/* G */ {{sCalc_G}, CALC_GRE}, // Greater than +/* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // Greater or equal +/* INT */ {{sCalc_Int}, CALC_INT}, // Int (since LibreOffice 7.4) +/* L */ {{sCalc_L}, CALC_LES}, // Less than +/* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // Less or equal +/* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximum value +/* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mean +/* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimum value +/* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplication +/* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // Not equal +/* NOT */ {{sCalc_Not}, CALC_NOT}, // log. NOT +/* OR */ {{sCalc_Or}, CALC_OR}, // log. OR +/* PHD */ {{sCalc_Phd}, CALC_PHD}, // Percentage +/* POW */ {{sCalc_Pow}, CALC_POW}, // Exponentiation +/* PRODUCT */ {{sCalc_Product}, CALC_PRODUCT}, // Product (since LibreOffice 7.1) +/* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Rounding +/* SIGN */ {{sCalc_Sign}, CALC_SIGN}, // Sign (since LibreOffice 7.1) +/* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sine +/* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Square root +/* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraction +/* SUM */ {{sCalc_Sum}, CALC_SUM}, // Sum +/* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangent +/* XOR */ {{sCalc_Xor}, CALC_XOR} // log. XOR +}; + +double const nRoundVal[] = { + 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, + 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14, + 0.5e-15,0.5e-16 +}; + +// First character may be any alphabetic or underscore. +const sal_Int32 coStartFlags = + i18n::KParseTokens::ANY_LETTER_OR_NUMBER | + i18n::KParseTokens::ASC_UNDERSCORE | + i18n::KParseTokens::IGNORE_LEADING_WS; + +// Continuing characters may be any alphanumeric, underscore, or dot. +const sal_Int32 coContFlags = + (coStartFlags | i18n::KParseTokens::ASC_DOT | i18n::KParseTokens::GROUP_SEPARATOR_IN_NUMBER) + & ~i18n::KParseTokens::IGNORE_LEADING_WS; + +extern "C" { +static int OperatorCompare( const void *pFirst, const void *pSecond) +{ + int nRet = 0; + if( CALC_NAME == static_cast<const CalcOp*>(pFirst)->eOp ) + { + if( CALC_NAME == static_cast<const CalcOp*>(pSecond)->eOp ) + nRet = static_cast<const CalcOp*>(pFirst)->pUName->compareTo( + *static_cast<const CalcOp*>(pSecond)->pUName ); + else + nRet = static_cast<const CalcOp*>(pFirst)->pUName->compareToAscii( + static_cast<const CalcOp*>(pSecond)->pName ); + } + else + { + if( CALC_NAME == static_cast<const CalcOp*>(pSecond)->eOp ) + nRet = -1 * static_cast<const CalcOp*>(pSecond)->pUName->compareToAscii( + static_cast<const CalcOp*>(pFirst)->pName ); + else + nRet = strcmp( static_cast<const CalcOp*>(pFirst)->pName, + static_cast<const CalcOp*>(pSecond)->pName ); + } + return nRet; +} +}// extern "C" + +CalcOp* FindOperator( const OUString& rSrch ) +{ + CalcOp aSrch; + aSrch.pUName = &rSrch; + aSrch.eOp = CALC_NAME; + + return static_cast<CalcOp*>(bsearch( static_cast<void*>(&aSrch), + static_cast<void const *>(aOpTable), + SAL_N_ELEMENTS( aOpTable ), + sizeof( CalcOp ), + OperatorCompare )); +} + +// static +LanguageType SwCalc::GetDocAppScriptLang( SwDoc const & rDoc ) +{ + TypedWhichId<SvxLanguageItem> nWhich = + GetWhichOfScript( RES_CHRATR_LANGUAGE, + SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() )); + return rDoc.GetDefault(nWhich).GetLanguage(); +} + +static double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate ) +{ + double nRet = 0; + SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter(); + if( pFormatter ) + { + const Date& rNull = pFormatter->GetNullDate(); + Date aDate( nDate >> 24, (nDate& 0x00FF0000) >> 16, nDate& 0x0000FFFF ); + nRet = aDate - rNull; + } + return nRet; +} + +SwCalc::SwCalc( SwDoc& rD ) + : m_aErrExpr( SwSbxValue(), nullptr ) + , m_nCommandPos(0) + , m_rDoc( rD ) + , m_pCharClass( &GetAppCharClass() ) + , m_nListPor( 0 ) + , m_bHasNumber( false ) + , m_eCurrOper( CALC_NAME ) + , m_eCurrListOper( CALC_NAME ) + , m_eError( SwCalcError::NONE ) +{ + LanguageType eLang = GetDocAppScriptLang( m_rDoc ); + LanguageTag aLanguageTag( eLang ); + + if( eLang != m_pCharClass->getLanguageTag().getLanguageType() ) + { + m_pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), aLanguageTag ); + } + m_xLocaleDataWrapper.reset(new LocaleDataWrapper( std::move(aLanguageTag) )); + + m_sCurrSym = comphelper::string::strip(m_xLocaleDataWrapper->getCurrSymbol(), ' '); + m_sCurrSym = m_pCharClass->lowercase( m_sCurrSym ); + + static constexpr OUString sNTypeTab[] + { + u"false"_ustr, + u"true"_ustr, + u"pi"_ustr, + u"e"_ustr, + u"tables"_ustr, + u"graf"_ustr, + u"ole"_ustr, + u"page"_ustr, + u"para"_ustr, + u"word"_ustr, + u"char"_ustr, + + u"user_firstname"_ustr, + u"user_lastname"_ustr, + u"user_initials"_ustr, + u"user_company"_ustr, + u"user_street"_ustr, + u"user_country"_ustr, + u"user_zipcode"_ustr, + u"user_city"_ustr, + u"user_title"_ustr, + u"user_position"_ustr, + u"user_tel_work"_ustr, + u"user_tel_home"_ustr, + u"user_fax"_ustr, + u"user_email"_ustr, + u"user_state"_ustr, + u"graph"_ustr + }; + static UserOptToken const aAdrToken[ 12 ] = + { + UserOptToken::Company, UserOptToken::Street, UserOptToken::Country, UserOptToken::Zip, + UserOptToken::City, UserOptToken::Title, UserOptToken::Position, UserOptToken::TelephoneWork, + UserOptToken::TelephoneHome, UserOptToken::Fax, UserOptToken::Email, UserOptToken::State + }; + + static sal_uInt16 SwDocStat::* const aDocStat1[ 3 ] = + { + &SwDocStat::nTable, &SwDocStat::nGrf, &SwDocStat::nOLE + }; + static sal_uLong SwDocStat::* const aDocStat2[ 4 ] = + { + &SwDocStat::nPage, &SwDocStat::nPara, + &SwDocStat::nWord, &SwDocStat::nChar + }; + + const SwDocStat& rDocStat = m_rDoc.getIDocumentStatistics().GetDocStat(); + + SwSbxValue nVal; + sal_uInt16 n; + + for( n = 0; n < 25; ++n ) + m_aVarTable.insert( { sNTypeTab[n], SwCalcExp( nVal, nullptr ) } ); + + m_aVarTable.find( sNTypeTab[ 0 ] )->second.nValue.PutBool( false ); + m_aVarTable.find( sNTypeTab[ 1 ] )->second.nValue.PutBool( true ); + m_aVarTable.find( sNTypeTab[ 2 ] )->second.nValue.PutDouble( M_PI ); + m_aVarTable.find( sNTypeTab[ 3 ] )->second.nValue.PutDouble( M_E ); + + for( n = 0; n < 3; ++n ) + m_aVarTable.find( sNTypeTab[ n + 4 ] )->second.nValue.PutLong( rDocStat.*aDocStat1[ n ] ); + for( n = 0; n < 4; ++n ) + m_aVarTable.find( sNTypeTab[ n + 7 ] )->second.nValue.PutLong( rDocStat.*aDocStat2[ n ] ); + + SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions(); + + m_aVarTable.find( sNTypeTab[ 11 ] )->second.nValue.PutString( rUserOptions.GetFirstName() ); + m_aVarTable.find( sNTypeTab[ 12 ] )->second.nValue.PutString( rUserOptions.GetLastName() ); + m_aVarTable.find( sNTypeTab[ 13 ] )->second.nValue.PutString( rUserOptions.GetID() ); + + for( n = 0; n < 11; ++n ) + m_aVarTable.find( sNTypeTab[ n + 14 ] )->second.nValue.PutString( + rUserOptions.GetToken( aAdrToken[ n ] )); + + nVal.PutString( rUserOptions.GetToken( aAdrToken[ 11 ] )); + m_aVarTable.insert( { sNTypeTab[ 25 ], SwCalcExp( nVal, nullptr ) } ); + +} // SwCalc::SwCalc + +void SwCalc::ImplDestroy() +{ + if( m_pCharClass != &GetAppCharClass() ) + delete m_pCharClass; +} + +SwCalc::~SwCalc() +{ + suppress_fun_call_w_exception(ImplDestroy()); +} + +SwSbxValue SwCalc::Calculate( const OUString& rStr ) +{ + m_eError = SwCalcError::NONE; + SwSbxValue nResult; + + if( rStr.isEmpty() ) + return nResult; + + m_nListPor = 0; + m_eCurrListOper = CALC_PLUS; // default: sum + + m_sCommand = rStr; + m_nCommandPos = 0; + + for (;;) + { + m_eCurrOper = GetToken(); + if (m_eCurrOper == CALC_ENDCALC || m_eError != SwCalcError::NONE ) + break; + nResult = Expr(); + } + + if( m_eError != SwCalcError::NONE) + nResult.PutDouble( DBL_MAX ); + + return nResult; +} + +OUString SwCalc::GetStrResult( const SwSbxValue& rVal ) +{ + if( !rVal.IsDouble() ) + { + return rVal.GetOUString(); + } + return GetStrResult( rVal.GetDouble() ); +} + +OUString SwCalc::GetStrResult( double nValue ) +{ + if( nValue >= DBL_MAX ) + switch( m_eError ) + { + case SwCalcError::Syntax : return SwViewShell::GetShellRes()->aCalc_Syntax; + case SwCalcError::DivByZero : return SwViewShell::GetShellRes()->aCalc_ZeroDiv; + case SwCalcError::FaultyBrackets : return SwViewShell::GetShellRes()->aCalc_Brack; + case SwCalcError::OverflowInPower : return SwViewShell::GetShellRes()->aCalc_Pow; + case SwCalcError::Overflow : return SwViewShell::GetShellRes()->aCalc_Overflow; + default : return SwViewShell::GetShellRes()->aCalc_Default; + } + + const sal_Int32 nDecPlaces = 15; + OUString aRetStr( ::rtl::math::doubleToUString( + nValue, + rtl_math_StringFormat_Automatic, + nDecPlaces, + m_xLocaleDataWrapper->getNumDecimalSep()[0], + true )); + return aRetStr; +} + +SwCalcExp* SwCalc::VarInsert( const OUString &rStr ) +{ + OUString aStr = m_pCharClass->lowercase( rStr ); + return VarLook( aStr, true ); +} + +SwCalcExp* SwCalc::VarLook( const OUString& rStr, bool bIns ) +{ + m_aErrExpr.nValue.SetVoidValue(false); + + OUString aStr = m_pCharClass->lowercase( rStr ); + SwCalcExp* pFnd = nullptr; + auto it = m_aVarTable.find(aStr); + if (it != m_aVarTable.end()) + pFnd = &it->second; + + if( !pFnd ) + { + // then check doc + std::unordered_multimap<OUString, const SwFieldType*> & rDocTable + = m_rDoc.getIDocumentFieldsAccess().GetUpdateFields().GetFieldTypeTable(); + auto docIt = rDocTable.find(aStr); + if (docIt != rDocTable.end()) + { + const SwFieldType* pFieldType = docIt->second; + it = m_aVarTable.insert( { aStr, SwCalcExp( SwSbxValue(), pFieldType ) } ).first; + pFnd = &it->second; + } + } + + if( pFnd ) + { + if( pFnd->pFieldType && pFnd->pFieldType->Which() == SwFieldIds::User ) + { + SwUserFieldType* pUField = const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFnd->pFieldType)); + if( nsSwGetSetExpType::GSE_STRING & pUField->GetType() ) + { + pFnd->nValue.PutString( pUField->GetContent() ); + } + else if( !pUField->IsValid() ) + { + // Save the current values... + sal_uInt16 nListPor = m_nListPor; + bool bHasNumber = m_bHasNumber; + SwSbxValue nLastLeft = m_nLastLeft; + SwSbxValue nNumberValue = m_nNumberValue; + sal_Int32 nCommandPos = m_nCommandPos; + SwCalcOper eCurrOper = m_eCurrOper; + SwCalcOper eCurrListOper = m_eCurrListOper; + OUString sCurrCommand = m_sCommand; + + pFnd->nValue.PutDouble( pUField->GetValue( *this ) ); + + // ...and write them back. + m_nListPor = nListPor; + m_bHasNumber = bHasNumber; + m_nLastLeft = nLastLeft; + m_nNumberValue = nNumberValue; + m_nCommandPos = nCommandPos; + m_eCurrOper = eCurrOper; + m_eCurrListOper = eCurrListOper; + m_sCommand = sCurrCommand; + } + else + { + pFnd->nValue.PutDouble( pUField->GetValue() ); + } + } + else if ( !pFnd->pFieldType && pFnd->nValue.IsDBvalue() ) + { + if ( pFnd->nValue.IsString() ) + m_aErrExpr.nValue.PutString( pFnd->nValue.GetOUString() ); + else if ( pFnd->nValue.IsDouble() ) + m_aErrExpr.nValue.PutDouble( pFnd->nValue.GetDouble() ); + pFnd = &m_aErrExpr; + } + return pFnd; + } + + // At this point the "real" case variable has to be used + OUString const sTmpName( ::ReplacePoint(rStr) ); + + if( !bIns ) + { +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwDBManager *pMgr = m_rDoc.GetDBManager(); + OUString sDBName(GetDBName( sTmpName )); + OUString sSourceName(sDBName.getToken(0, DB_DELIM)); + OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM)); + if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() && + pMgr->OpenDataSource(sSourceName, sTableName)) + { + OUString sColumnName( GetColumnName( sTmpName )); + OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name"); + + OUString sDBNum( SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber) ); + sDBNum = m_pCharClass->lowercase(sDBNum); + + // Initialize again because this doesn't happen in docfld anymore for + // elements != SwFieldIds::Database. E.g. if there is an expression field before + // a DB_Field in a document. + const sal_uInt32 nTmpRec = pMgr->GetSelectedRecordId(sSourceName, sTableName); + VarChange(sDBNum, nTmpRec); + + if( sDBNum.equalsIgnoreAsciiCase(sColumnName) ) + { + m_aErrExpr.nValue.PutULong(nTmpRec); + return &m_aErrExpr; + } + + OUString sResult; + double nNumber = DBL_MAX; + + LanguageType nLang = m_xLocaleDataWrapper->getLanguageTag().getLanguageType(); + if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName, + nTmpRec, nLang, sResult, &nNumber )) + { + if (nNumber != DBL_MAX) + m_aErrExpr.nValue.PutDouble( nNumber ); + else + m_aErrExpr.nValue.PutString( sResult ); + + return &m_aErrExpr; + } + } + else +#endif + { + //data source was not available - set return to "NoValue" + m_aErrExpr.nValue.SetVoidValue(true); + } + // NEVER save! + return &m_aErrExpr; + } + + SwCalcExp* pNewExp = &m_aVarTable.insert( { aStr, SwCalcExp( SwSbxValue(), nullptr ) } ).first->second; + + OUString sColumnName( GetColumnName( sTmpName )); + OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" ); + if( sColumnName.equalsIgnoreAsciiCase( + SwFieldType::GetTypeStr( SwFieldTypesEnum::DatabaseSetNumber ) )) + { +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwDBManager *pMgr = m_rDoc.GetDBManager(); + OUString sDBName(GetDBName( sTmpName )); + OUString sSourceName(sDBName.getToken(0, DB_DELIM)); + OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM)); + if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() && + pMgr->OpenDataSource(sSourceName, sTableName) && + !pMgr->IsInMerge()) + { + pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName)); + } + else +#endif + { + pNewExp->nValue.SetVoidValue(true); + } + } + + return pNewExp; +} + +void SwCalc::VarChange( const OUString& rStr, double nValue ) +{ + SwSbxValue aVal( nValue ); + VarChange( rStr, aVal ); +} + +void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue ) +{ + OUString aStr = m_pCharClass->lowercase( rStr ); + + auto it = m_aVarTable.find( aStr ); + if (it != m_aVarTable.end()) + it->second.nValue = rValue; + else + m_aVarTable.insert( { aStr, SwCalcExp( rValue, nullptr ) } ); +} + +bool SwCalc::Push( const SwUserFieldType* pUserFieldType ) +{ + if( m_aRekurStack.end() != std::find(m_aRekurStack.begin(), m_aRekurStack.end(), pUserFieldType ) ) + return false; + + m_aRekurStack.push_back( pUserFieldType ); + return true; +} + +void SwCalc::Pop() +{ + OSL_ENSURE( m_aRekurStack.size(), "SwCalc: Pop on an invalid pointer" ); + + m_aRekurStack.pop_back(); +} + +const CharClass* SwCalc::GetCharClass() const +{ + return m_pCharClass; +} + +void SwCalc::SetCharClass(const LanguageTag& rLanguageTag) +{ + m_pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), rLanguageTag ); +} + +SwCalcOper SwCalc::GetToken() +{ + if( m_nCommandPos >= m_sCommand.getLength() ) + { + m_eCurrOper = CALC_ENDCALC; + return m_eCurrOper; + } + + using namespace ::com::sun::star::i18n; + { + // Parse any token. + ParseResult aRes = m_pCharClass->parseAnyToken( m_sCommand, m_nCommandPos, + coStartFlags, OUString(), + coContFlags, OUString()); + + bool bSetError = true; + sal_Int32 nRealStt = m_nCommandPos + aRes.LeadingWhiteSpace; + if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) ) + { + m_nNumberValue.PutDouble( aRes.Value ); + m_eCurrOper = CALC_NUMBER; + bSetError = false; + } + else if( aRes.TokenType & KParseType::IDENTNAME ) + { + OUString aName( m_sCommand.copy( nRealStt, + aRes.EndPos - nRealStt ) ); + //#101436#: The variable may contain a database name. It must not be + // converted to lower case! Instead all further comparisons must be + // done case-insensitive + OUString sLowerCaseName = m_pCharClass->lowercase( aName ); + // catch currency symbol + if( sLowerCaseName == m_sCurrSym ) + { + m_nCommandPos = aRes.EndPos; + return GetToken(); // call again + } + + // catch operators + CalcOp* pFnd = ::FindOperator( sLowerCaseName ); + if( pFnd ) + { + m_eCurrOper = pFnd->eOp; + switch( m_eCurrOper ) + { + case CALC_SUM: + case CALC_MEAN: + case CALC_AVERAGE: + case CALC_COUNT: + m_eCurrListOper = CALC_PLUS; + break; + case CALC_MIN: + m_eCurrListOper = CALC_MIN_IN; + break; + case CALC_MAX: + m_eCurrListOper = CALC_MAX_IN; + break; + case CALC_DATE: + m_eCurrListOper = CALC_MONTH; + break; + case CALC_PRODUCT: + m_eCurrListOper = CALC_MUL; + break; + default: + break; + } + m_nCommandPos = aRes.EndPos; + return m_eCurrOper; + } + m_aVarName = aName; + m_eCurrOper = CALC_NAME; + bSetError = false; + } + else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING ) + { + m_nNumberValue.PutString( aRes.DequotedNameOrString ); + m_eCurrOper = CALC_NUMBER; + bSetError = false; + } + else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR ) + { + std::u16string_view aName( m_sCommand.subView( nRealStt, + aRes.EndPos - nRealStt )); + if( 1 == aName.size() ) + { + bSetError = false; + sal_Unicode ch = aName[0]; + switch( ch ) + { + case ';': + if( CALC_MONTH == m_eCurrListOper || CALC_DAY == m_eCurrListOper ) + { + m_eCurrOper = m_eCurrListOper; + break; + } + [[fallthrough]]; + case '\n': + m_eCurrOper = CALC_PRINT; + break; + + case '%': + case '^': + case '*': + case '/': + case '+': + case '-': + case '(': + case ')': + m_eCurrOper = SwCalcOper(ch); + break; + + case '=': + case '!': + { + SwCalcOper eTmp2; + if( '=' == ch ) + { + m_eCurrOper = SwCalcOper('='); + eTmp2 = CALC_EQ; + } + else + { + m_eCurrOper = CALC_NOT; + eTmp2 = CALC_NEQ; + } + + if( aRes.EndPos < m_sCommand.getLength() && + '=' == m_sCommand[aRes.EndPos] ) + { + m_eCurrOper = eTmp2; + ++aRes.EndPos; + } + } + break; + + case cListDelim: + m_eCurrOper = m_eCurrListOper; + break; + + case '[': + if( aRes.EndPos < m_sCommand.getLength() ) + { + m_aVarName.setLength(0); + sal_Int32 nFndPos = aRes.EndPos, + nSttPos = nFndPos; + + do { + nFndPos = m_sCommand.indexOf( ']', nFndPos ); + if( -1 != nFndPos ) + { + // ignore the ] + if ('\\' == m_sCommand[nFndPos-1]) + { + m_aVarName.append(m_sCommand.subView(nSttPos, + nFndPos - nSttPos - 1) ); + nSttPos = ++nFndPos; + } + else + break; + } + } while( nFndPos != -1 ); + + if( nFndPos != -1 ) + { + if( nSttPos != nFndPos ) + m_aVarName.append(m_sCommand.subView(nSttPos, + nFndPos - nSttPos) ); + aRes.EndPos = nFndPos + 1; + m_eCurrOper = CALC_NAME; + } + else + bSetError = true; + } + else + { + bSetError = true; + } + break; + + default: + bSetError = true; + break; + } + } + } + else if( aRes.TokenType & KParseType::BOOLEAN ) + { + std::u16string_view aName( m_sCommand.subView( nRealStt, + aRes.EndPos - nRealStt )); + if( !aName.empty() ) + { + sal_Unicode ch = aName[0]; + + bSetError = true; + if ('<' == ch || '>' == ch) + { + bSetError = false; + + SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ; + m_eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE; + + if( 2 == aName.size() && '=' == aName[1] ) + m_eCurrOper = eTmp2; + else if( 1 != aName.size() ) + bSetError = true; + } + } + } + else if( nRealStt == m_sCommand.getLength() ) + { + m_eCurrOper = CALC_ENDCALC; + bSetError = false; + } + + if( bSetError ) + { + m_eError = SwCalcError::Syntax; + m_eCurrOper = CALC_PRINT; + } + m_nCommandPos = aRes.EndPos; + }; + + return m_eCurrOper; +} + +SwSbxValue SwCalc::Term() +{ + SwSbxValue left( Prim() ); + m_nLastLeft = left; + for(;;) + { + sal_uInt16 nSbxOper = USHRT_MAX; + + switch( m_eCurrOper ) + { + case CALC_AND: + { + GetToken(); + bool bB = Prim().GetBool(); + left.PutBool( left.GetBool() && bB ); + } + break; + case CALC_OR: + { + GetToken(); + bool bB = Prim().GetBool(); + left.PutBool( left.GetBool() || bB ); + } + break; + case CALC_XOR: + { + GetToken(); + bool bR = Prim().GetBool(); + bool bL = left.GetBool(); + left.PutBool(bL != bR); + } + break; + + case CALC_EQ: nSbxOper = SbxEQ; break; + case CALC_NEQ: nSbxOper = SbxNE; break; + case CALC_LEQ: nSbxOper = SbxLE; break; + case CALC_GEQ: nSbxOper = SbxGE; break; + case CALC_GRE: nSbxOper = SbxGT; break; + case CALC_LES: nSbxOper = SbxLT; break; + + case CALC_MUL: nSbxOper = SbxMUL; break; + case CALC_DIV: nSbxOper = SbxDIV; break; + + case CALC_MIN_IN: + { + GetToken(); + SwSbxValue e = Prim(); + left = left.GetDouble() < e.GetDouble() ? left : e; + } + break; + case CALC_MAX_IN: + { + GetToken(); + SwSbxValue e = Prim(); + left = left.GetDouble() > e.GetDouble() ? left : e; + } + break; + case CALC_MONTH: + { + GetToken(); + SwSbxValue e = Prim(); + sal_Int32 nYear = static_cast<sal_Int32>(floor( left.GetDouble() )); + nYear = nYear & 0x0000FFFF; + sal_Int32 nMonth = static_cast<sal_Int32>(floor( e.GetDouble() )); + nMonth = ( nMonth & 0x000000FF ) << 16; + left.PutLong( nMonth + nYear ); + m_eCurrOper = CALC_DAY; + } + break; + case CALC_DAY: + { + GetToken(); + SwSbxValue e = Prim(); + sal_Int32 nYearMonth = static_cast<sal_Int32>(floor( left.GetDouble() )); + nYearMonth = nYearMonth & 0x00FFFFFF; + sal_Int32 nDay = static_cast<sal_Int32>(floor( e.GetDouble() )); + nDay = ( nDay & 0x000000FF ) << 24; + left = lcl_ConvertToDateValue( m_rDoc, nDay + nYearMonth ); + } + break; + case CALC_ROUND: + { + GetToken(); + SwSbxValue e = Prim(); + + double fVal = 0; + double fFac = 1; + sal_Int32 nDec = static_cast<sal_Int32>(floor( e.GetDouble() )); + if( nDec < -20 || nDec > 20 ) + { + m_eError = SwCalcError::Overflow; + left.Clear(); + return left; + } + fVal = left.GetDouble(); + if( nDec >= 0) + { + for (sal_Int32 i = 0; i < nDec; ++i ) + fFac *= 10.0; + } + else + { + for (sal_Int32 i = 0; i < -nDec; ++i ) + fFac /= 10.0; + } + + fVal *= fFac; + bool bSign; + if (fVal < 0.0) + { + fVal *= -1.0; + bSign = true; + } + else + { + bSign = false; + } + + // rounding + double fNum = fVal; // find the exponent + int nExp = 0; + if( fNum > 0 ) + { + while( fNum < 1.0 ) + { + fNum *= 10.0; + --nExp; + } + while( fNum >= 10.0 ) + { + fNum /= 10.0; + ++nExp; + } + } + nExp = 15 - nExp; + if( nExp > 15 ) + nExp = 15; + else if( nExp <= 1 ) + nExp = 0; + fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] ); + + if (bSign) + fVal *= -1.0; + + fVal /= fFac; + + left.PutDouble( fVal ); + } + break; + +//#77448# (=2*3^2 != 18) + + default: + return left; + } + + if( USHRT_MAX != nSbxOper ) + { + // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX + SbxOperator eSbxOper = static_cast<SbxOperator>(nSbxOper); + + GetToken(); + if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE ) + { + left.PutBool( left.Compare( eSbxOper, Prim() )); + } + else + { + SwSbxValue aRight( Prim() ); + aRight.MakeDouble(); + left.MakeDouble(); + + if( SbxDIV == eSbxOper && !aRight.GetDouble() ) + m_eError = SwCalcError::DivByZero; + else + left.Compute( eSbxOper, aRight ); + } + } + } +} + +SwSbxValue SwCalc::StdFunc(pfCalc pFnc, bool bChkTrig) +{ + SwSbxValue nErg; + GetToken(); + double nVal = Prim().GetDouble(); + if( !bChkTrig || ( nVal > -1 && nVal < 1 ) ) + nErg.PutDouble( (*pFnc)( nVal ) ); + else + m_eError = SwCalcError::Overflow; + return nErg; +} + +SwSbxValue SwCalc::PrimFunc(bool &rChkPow) +{ + rChkPow = false; + + switch (m_eCurrOper) + { + case CALC_SIN: + SAL_INFO("sw.calc", "sin"); + return StdFunc(&sin, false); + case CALC_COS: + SAL_INFO("sw.calc", "cos"); + return StdFunc(&cos, false); + case CALC_TAN: + SAL_INFO("sw.calc", "tan"); + return StdFunc(&tan, false); + case CALC_ATAN: + SAL_INFO("sw.calc", "atan"); + return StdFunc(&atan, false); + case CALC_ASIN: + SAL_INFO("sw.calc", "asin"); + return StdFunc(&asin, true); + case CALC_ACOS: + SAL_INFO("sw.calc", "acos"); + return StdFunc(&acos, true); + case CALC_ABS: + SAL_INFO("sw.calc", "abs"); + return StdFunc(&abs, false); + case CALC_SIGN: + { + SAL_INFO("sw.calc", "sign"); + SwSbxValue nErg; + GetToken(); + double nVal = Prim().GetDouble(); + nErg.PutDouble( int(0 < nVal) - int(nVal < 0) ); + return nErg; + } + case CALC_INT: + { + SAL_INFO("sw.calc", "int"); + SwSbxValue nErg; + GetToken(); + sal_Int32 nVal = static_cast<sal_Int32>( Prim().GetDouble() ); + nErg.PutDouble( nVal ); + return nErg; + } + case CALC_NOT: + { + SAL_INFO("sw.calc", "not"); + GetToken(); + SwSbxValue nErg = Prim(); + if( SbxSTRING == nErg.GetType() ) + { + nErg.PutBool( nErg.GetOUString().isEmpty() ); + } + else if(SbxBOOL == nErg.GetType() ) + { + nErg.PutBool(!nErg.GetBool()); + } + // Evaluate arguments manually so that the binary NOT below does not + // get called. We want a BOOLEAN NOT. + else if (nErg.IsNumeric()) + { + nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 ); + } + else + { + OSL_FAIL( "unexpected case. computing binary NOT" ); + //!! computes a binary NOT + nErg.Compute( SbxNOT, nErg ); + } + return nErg; + } + case CALC_NUMBER: + { + SAL_INFO("sw.calc", "number: " << m_nNumberValue.GetDouble()); + SwSbxValue nErg; + m_bHasNumber = true; + if( GetToken() == CALC_PHD ) + { + double aTmp = m_nNumberValue.GetDouble(); + aTmp *= 0.01; + nErg.PutDouble( aTmp ); + GetToken(); + } + else if( m_eCurrOper == CALC_NAME ) + { + m_eError = SwCalcError::Syntax; + } + else + { + nErg = m_nNumberValue; + rChkPow = true; + } + return nErg; + } + case CALC_NAME: + { + SAL_INFO("sw.calc", "name"); + SwSbxValue nErg; + switch(SwCalcOper eOper = GetToken()) + { + case CALC_ASSIGN: + { + SwCalcExp* n = VarInsert(m_aVarName.toString()); + GetToken(); + nErg = n->nValue = Expr(); + break; + } + default: + nErg = VarLook(m_aVarName.toString())->nValue; + // Explicitly disallow unknown function names (followed by "("), + // allow unknown variable names (equal to zero) + if (nErg.IsVoidValue() && (eOper == CALC_LP)) + m_eError = SwCalcError::Syntax; + else + rChkPow = true; + break; + } + return nErg; + } + case CALC_MINUS: + { + SAL_INFO("sw.calc", "-"); + SwSbxValue nErg; + GetToken(); + nErg.PutDouble( -(Prim().GetDouble()) ); + return nErg; + } + case CALC_LP: + { + SAL_INFO("sw.calc", "("); + GetToken(); + SwSbxValue nErg = Expr(); + if( m_eCurrOper != CALC_RP ) + { + m_eError = SwCalcError::FaultyBrackets; + } + else + { + GetToken(); + rChkPow = true; // in order for =(7)^2 to work + } + return nErg; + } + case CALC_RP: + // ignore, see tdf#121962 + SAL_INFO("sw.calc", ")"); + break; + case CALC_MEAN: + case CALC_AVERAGE: + { + SAL_INFO("sw.calc", "mean"); + m_nListPor = 1; + m_bHasNumber = CALC_MEAN == m_eCurrOper; + GetToken(); + SwSbxValue nErg = Expr(); + double aTmp = nErg.GetDouble(); + aTmp /= m_nListPor; + if ( !m_bHasNumber ) + m_eError = SwCalcError::DivByZero; + else + nErg.PutDouble( aTmp ); + return nErg; + } + case CALC_COUNT: + { + SAL_INFO("sw.calc", "count"); + m_nListPor = 1; + m_bHasNumber = false; + GetToken(); + SwSbxValue nErg = Expr(); + nErg.PutDouble( m_bHasNumber ? m_nListPor : 0 ); + return nErg; + } + case CALC_SQRT: + { + SAL_INFO("sw.calc", "sqrt"); + GetToken(); + SwSbxValue nErg = Prim(); + if( nErg.GetDouble() < 0 ) + m_eError = SwCalcError::Overflow; + else + nErg.PutDouble( sqrt( nErg.GetDouble() )); + return nErg; + } + case CALC_SUM: + case CALC_PRODUCT: + case CALC_DATE: + case CALC_MIN: + case CALC_MAX: + { + SAL_INFO("sw.calc", "sum/product/date/min/max"); + GetToken(); + SwSbxValue nErg = Expr(); + return nErg; + } + case CALC_ENDCALC: + { + SAL_INFO("sw.calc", "endcalc"); + SwSbxValue nErg; + nErg.Clear(); + return nErg; + } + default: + SAL_INFO("sw.calc", "syntax error"); + m_eError = SwCalcError::Syntax; + break; + } + + return SwSbxValue(); +} + +SwSbxValue SwCalc::Prim() +{ + bool bChkPow; + SwSbxValue nErg = PrimFunc(bChkPow); + + if (bChkPow && m_eCurrOper == CALC_POW) + { + double dleft = nErg.GetDouble(); + GetToken(); + double right = Prim().GetDouble(); + + double fraction; + fraction = modf( right, &o3tl::temporary(double()) ); + if( ( dleft < 0.0 && 0.0 != fraction ) || + ( 0.0 == dleft && right < 0.0 ) ) + { + m_eError = SwCalcError::Overflow; + nErg.Clear(); + } + else + { + dleft = pow(dleft, right ); + if( dleft == HUGE_VAL ) + { + m_eError = SwCalcError::OverflowInPower; + nErg.Clear(); + } + else + { + nErg.PutDouble( dleft ); + } + } + } + + return nErg; +} + +SwSbxValue SwCalc::Expr() +{ + SwSbxValue left = Term(); + m_nLastLeft = left; + for(;;) + { + switch(m_eCurrOper) + { + case CALC_PLUS: + { + GetToken(); + left.MakeDouble(); + SwSbxValue right(Term()); + right.MakeDouble(); + left.Compute(SbxPLUS, right); + m_nListPor++; + break; + } + case CALC_MINUS: + { + GetToken(); + left.MakeDouble(); + SwSbxValue right(Term()); + right.MakeDouble(); + left.Compute(SbxMINUS, right); + break; + } + default: + { + return left; + } + } + } +} + +OUString SwCalc::GetColumnName(const OUString& rName) +{ + sal_Int32 nPos = rName.indexOf(DB_DELIM); + if( -1 != nPos ) + { + nPos = rName.indexOf(DB_DELIM, nPos + 1); + + if( -1 != nPos ) + return rName.copy(nPos + 1); + } + return rName; +} + +OUString SwCalc::GetDBName(std::u16string_view rName) +{ + size_t nPos = rName.find(DB_DELIM); + if( std::u16string_view::npos != nPos ) + { + nPos = rName.find(DB_DELIM, nPos + 1); + + if( std::u16string_view::npos != nPos ) + return OUString(rName.substr( 0, nPos )); + } + SwDBData aData = m_rDoc.GetDBData(); + return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand; +} + +namespace +{ + bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos, + double& rVal, + const LocaleDataWrapper* const pLclData ) + { + assert(pLclData); + const sal_Unicode nCurrCmdPos = rCommandPos; + rtl_math_ConversionStatus eStatus; + const sal_Unicode* pEnd; + rVal = pLclData->stringToDouble( rCommand.getStr() + rCommandPos, + rCommand.getStr() + rCommand.getLength(), + true, + &eStatus, + &pEnd ); + rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr()); + + return rtl_math_ConversionStatus_Ok == eStatus && + nCurrCmdPos != rCommandPos; + } +} + +bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos, + double& rVal ) +{ + const SvtSysLocale aSysLocale; + return lcl_Str2Double( rCommand, rCommandPos, rVal, &aSysLocale.GetLocaleData() ); +} + +bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos, + double& rVal, SwDoc const * const pDoc ) +{ + const SvtSysLocale aSysLocale; + std::unique_ptr<const LocaleDataWrapper> pLclD; + if( pDoc ) + { + LanguageType eLang = GetDocAppScriptLang( *pDoc ); + if (eLang != aSysLocale.GetLanguageTag().getLanguageType()) + { + pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) ); + } + } + + bool const bRet = lcl_Str2Double(rCommand, rCommandPos, rVal, + pLclD ? pLclD.get() : &aSysLocale.GetLocaleData()); + + return bRet; +} + +bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName ) +{ + bool bRet = false; + using namespace ::com::sun::star::i18n; + { + // Parse any token. + ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0, + coStartFlags, OUString(), + coContFlags, OUString() ); + + if( aRes.TokenType & KParseType::IDENTNAME ) + { + bRet = aRes.EndPos == rStr.getLength(); + if( pValidName ) + { + *pValidName = rStr.copy( aRes.LeadingWhiteSpace, + aRes.EndPos - aRes.LeadingWhiteSpace ); + } + } + else if( pValidName ) + pValidName->clear(); + } + return bRet; +} + +SwCalcExp::SwCalcExp(SwSbxValue aVal, const SwFieldType* pType) + : nValue(std::move(aVal)) + , pFieldType(pType) +{ +} + +bool SwSbxValue::GetBool() const +{ + return SbxSTRING == GetType() ? !GetOUString().isEmpty() + : SbxValue::GetBool(); +} + +double SwSbxValue::GetDouble() const +{ + double nRet; + if( SbxSTRING == GetType() ) + { + sal_Int32 nStt = 0; + SwCalc::Str2Double( GetOUString(), nStt, nRet ); + } + else if (IsBool()) + { + nRet = GetBool() ? 1.0 : 0.0; + } + else + { + nRet = SbxValue::GetDouble(); + } + return nRet; +} + +SwSbxValue& SwSbxValue::MakeDouble() +{ + if( GetType() == SbxSTRING || GetType() == SbxBOOL ) + PutDouble( GetDouble() ); + return *this; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/checkit.cxx b/sw/source/core/bastyp/checkit.cxx new file mode 100644 index 0000000000..f6e00314db --- /dev/null +++ b/sw/source/core/bastyp/checkit.cxx @@ -0,0 +1,33 @@ +/* -*- 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 <checkit.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/i18n/InputSequenceChecker.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::i18n; + +SwCheckIt::SwCheckIt() +{ + Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext(); + xCheck = InputSequenceChecker::create(xContext); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/index.cxx b/sw/source/core/bastyp/index.cxx new file mode 100644 index 0000000000..c7ded156ea --- /dev/null +++ b/sw/source/core/bastyp/index.cxx @@ -0,0 +1,392 @@ +/* -*- 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 <contentindex.hxx> + +#include <assert.h> +#include <sal/log.hxx> + +#include <crossrefbookmark.hxx> + +SwContentIndex::SwContentIndex(const SwContentNode * pContentNode, sal_Int32 const nIdx) + : m_nIndex( nIdx ) + , m_pContentNode( const_cast<SwContentNode*>(pContentNode) ) + , m_pNext( nullptr ) + , m_pPrev( nullptr ) + , m_pMark( nullptr ) +{ + Init(m_nIndex); +} + +SwContentIndex::SwContentIndex( const SwContentIndex& rIdx, short nDiff ) + : m_pContentNode( rIdx.m_pContentNode ) + , m_pNext( nullptr ) + , m_pPrev( nullptr ) + , m_pMark( nullptr ) +{ + ChgValue( rIdx, rIdx.m_nIndex + nDiff ); +} + +SwContentIndex::SwContentIndex( const SwContentIndex& rIdx ) + : m_nIndex( rIdx.m_nIndex ) + , m_pContentNode( rIdx.m_pContentNode ) + , m_pNext( nullptr ) + , m_pPrev( nullptr ) + , m_pMark( nullptr ) +{ + ChgValue( rIdx, rIdx.m_nIndex ); +} + +void SwContentIndex::Init(sal_Int32 const nIdx) +{ + if (!m_pContentNode) + { + m_nIndex = 0; // always 0 if no IndexReg + } + else if (!m_pContentNode->m_pFirst) // first Index? + { + assert(!m_pContentNode->m_pLast); + m_pContentNode->m_pFirst = m_pContentNode->m_pLast = this; + m_nIndex = nIdx; + } + else if (nIdx > ((m_pContentNode->m_pLast->m_nIndex + - m_pContentNode->m_pFirst->m_nIndex) / 2)) + { + ChgValue( *m_pContentNode->m_pLast, nIdx ); + } + else + { + ChgValue( *m_pContentNode->m_pFirst, nIdx ); + } +} + +SwContentIndex& SwContentIndex::ChgValue( const SwContentIndex& rIdx, sal_Int32 nNewValue ) +{ + assert(m_pContentNode == rIdx.m_pContentNode); + if (!m_pContentNode) + { + m_nIndex = 0; + return *this; // no IndexReg => no list to sort into; m_nIndex is 0 + } + SwContentIndex* pFnd = const_cast<SwContentIndex*>(&rIdx); + if (rIdx.m_nIndex > nNewValue) // move forwards + { + for (;;) + { + SwContentIndex* pPrv = pFnd->m_pPrev; + if (!pPrv || pPrv->m_nIndex <= nNewValue) + break; + pFnd = pPrv; + } + + if( pFnd != this ) + { + // remove from list at old position + Remove(); + + m_pNext = pFnd; + m_pPrev = pFnd->m_pPrev; + if (m_pPrev) + m_pPrev->m_pNext = this; + else + m_pContentNode->m_pFirst = this; + pFnd->m_pPrev = this; + } + } + else if (rIdx.m_nIndex < nNewValue) + { + for (;;) + { + SwContentIndex* pNxt = pFnd->m_pNext; + if (!pNxt || pNxt->m_nIndex >= nNewValue) + break; + pFnd = pNxt; + } + + if( pFnd != this ) + { + // remove from list at old position + Remove(); + + m_pPrev = pFnd; + m_pNext = pFnd->m_pNext; + if (m_pNext) + m_pNext->m_pPrev = this; + else + m_pContentNode->m_pLast = this; + pFnd->m_pNext = this; + } + } + else if( pFnd != this ) + { + // remove from list at old position + Remove(); + + m_pPrev = pFnd; // == &rIdx here + m_pNext = rIdx.m_pNext; + m_pPrev->m_pNext = this; + + if (!m_pNext) // last in the list + m_pContentNode->m_pLast = this; + else + m_pNext->m_pPrev = this; + } + + if (m_pContentNode->m_pFirst == m_pNext) + m_pContentNode->m_pFirst = this; + if (m_pContentNode->m_pLast == m_pPrev) + m_pContentNode->m_pLast = this; + + m_nIndex = nNewValue; + + return *this; +} + +void SwContentIndex::Remove() +{ + if (!m_pContentNode) + { + assert(!m_pPrev && !m_pNext); + return; + } + + if (m_pPrev) + { + m_pPrev->m_pNext = m_pNext; + } + else if (m_pContentNode->m_pFirst == this) + { + m_pContentNode->m_pFirst = m_pNext; + } + + if (m_pNext) + { + m_pNext->m_pPrev = m_pPrev; + } + else if (m_pContentNode->m_pLast == this) + { + m_pContentNode->m_pLast = m_pPrev; + } +} + +SwContentIndex& SwContentIndex::operator=( const SwContentIndex& rIdx ) +{ + bool bEqual; + if (rIdx.m_pContentNode != m_pContentNode) // unregister! + { + Remove(); + m_pContentNode = rIdx.m_pContentNode; + m_pNext = m_pPrev = nullptr; + bEqual = false; + } + else + bEqual = rIdx.m_nIndex == m_nIndex; + + if( !bEqual ) + ChgValue( rIdx, rIdx.m_nIndex ); + return *this; +} + +SwContentIndex& SwContentIndex::Assign( const SwContentNode* pArr, sal_Int32 nIdx ) +{ + if (pArr != m_pContentNode) // unregister! + { + Remove(); + m_pContentNode = const_cast<SwContentNode*>(pArr); + m_pNext = m_pPrev = nullptr; + Init(nIdx); + } + else if (m_nIndex != nIdx) + { + ChgValue( *this, nIdx ); + } + return *this; +} + +void SwContentIndex::SetMark(const sw::mark::IMark* pMark) +{ + m_pMark = pMark; +} + +SwContentIndexReg::SwContentIndexReg() + : m_pFirst( nullptr ), m_pLast( nullptr ) +{ +} + +SwContentIndexReg::~SwContentIndexReg() +{ + assert(!m_pFirst && !m_pLast && "There are still indices registered"); +} + +void SwContentIndexReg::Update( + SwContentIndex const & rIdx, + const sal_Int32 nDiff, + UpdateMode const eMode) +{ + SwContentIndex* pStt = const_cast<SwContentIndex*>(&rIdx); + const sal_Int32 nNewVal = rIdx.m_nIndex; + if (eMode & UpdateMode::Negative) + { + const sal_Int32 nLast = rIdx.m_nIndex + nDiff; + pStt = rIdx.m_pNext; + // skip over the ones that already have the right value + while (pStt && pStt->m_nIndex == nNewVal) + pStt = pStt->m_pNext; + while (pStt && pStt->m_nIndex <= nLast) + { + pStt->m_nIndex = nNewVal; + pStt = pStt->m_pNext; + } + while( pStt ) + { + pStt->m_nIndex = pStt->m_nIndex - nDiff; + pStt = pStt->m_pNext; + } + } + else + { + while (pStt && pStt->m_nIndex == nNewVal) + { + pStt->m_nIndex = pStt->m_nIndex + nDiff; + pStt = pStt->m_pPrev; + } + pStt = rIdx.m_pNext; + while( pStt ) + { + // HACK: avoid updating position of cross-ref bookmarks + if (!pStt->m_pMark || nullptr == dynamic_cast< + ::sw::mark::CrossRefBookmark const*>(pStt->m_pMark)) + { + pStt->m_nIndex = pStt->m_nIndex + nDiff; + } + pStt = pStt->m_pNext; + } + } +} + +void SwContentIndexReg::MoveTo( SwContentNode& rArr ) +{ + if (!(this != &rArr && m_pFirst)) + return; + + SwContentIndex * pIdx = const_cast<SwContentIndex*>(m_pFirst); + SwContentIndex * pNext; + while( pIdx ) + { + pNext = pIdx->m_pNext; + pIdx->Assign( &rArr, pIdx->GetIndex() ); + pIdx = pNext; + } + m_pFirst = nullptr; + m_pLast = nullptr; +} + +#ifdef DBG_UTIL + +// SwContentIndex + +sal_Int32 SwContentIndex::operator++() +{ + SAL_WARN_IF( !(m_nIndex < SAL_MAX_INT32), "sw.core", + "SwContentIndex::operator++() wraps around" ); + + ChgValue( *this, m_nIndex+1 ); + return m_nIndex; +} + +sal_Int32 SwContentIndex::operator--(int) +{ + SAL_WARN_IF( !(m_nIndex > 0), "sw.core", + "SwContentIndex::operator--(int) wraps around" ); + + const sal_Int32 nOldIndex = m_nIndex; + ChgValue( *this, m_nIndex-1 ); + return nOldIndex; +} + +sal_Int32 SwContentIndex::operator--() +{ + SAL_WARN_IF( !( m_nIndex > 0), "sw.core", + "SwContentIndex::operator--() wraps around" ); + return ChgValue( *this, m_nIndex-1 ).m_nIndex; +} + +sal_Int32 SwContentIndex::operator+=( sal_Int32 const nVal ) +{ + SAL_WARN_IF( !(nVal > 0 ? m_nIndex <= SAL_MAX_INT32 - nVal : m_nIndex >= nVal), "sw.core", + "SwContentIndex SwContentIndex::operator+=(sal_Int32) wraps around" ); + return ChgValue( *this, m_nIndex + nVal ).m_nIndex; +} + +sal_Int32 SwContentIndex::operator-=( sal_Int32 const nVal ) +{ + SAL_WARN_IF( !(m_nIndex >= nVal), "sw.core", + "SwContentIndex::operator-=(sal_Int32) wraps around" ); + return ChgValue( *this, m_nIndex - nVal ).m_nIndex; +} + +bool SwContentIndex::operator< ( const SwContentIndex & rIndex ) const +{ + // Attempt to compare indices into different arrays + assert(m_pContentNode == rIndex.m_pContentNode); + return m_nIndex < rIndex.m_nIndex; +} + +bool SwContentIndex::operator<=( const SwContentIndex & rIndex ) const +{ + // Attempt to compare indices into different arrays + assert(m_pContentNode == rIndex.m_pContentNode); + return m_nIndex <= rIndex.m_nIndex; +} + +bool SwContentIndex::operator> ( const SwContentIndex & rIndex ) const +{ + // Attempt to compare indices into different arrays + assert(m_pContentNode == rIndex.m_pContentNode); + return m_nIndex > rIndex.m_nIndex; +} + +bool SwContentIndex::operator>=( const SwContentIndex & rIndex ) const +{ + // Attempt to compare indices into different arrays + assert(m_pContentNode == rIndex.m_pContentNode); + return m_nIndex >= rIndex.m_nIndex; +} + +SwContentIndex& SwContentIndex::operator= ( sal_Int32 const nVal ) +{ + if (m_nIndex != nVal) + ChgValue( *this, nVal ); + + return *this; +} + +#endif + +std::ostream& operator <<(std::ostream& s, const SwContentIndex& index) +{ + return s << "SwContentIndex offset (" << index.GetIndex() << ")"; +} + +std::ostream& operator <<(std::ostream& s, const SwNodeOffset& index) +{ + return s << sal_Int32(index); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx new file mode 100644 index 0000000000..ce14c81e4d --- /dev/null +++ b/sw/source/core/bastyp/init.cxx @@ -0,0 +1,811 @@ +/* -*- 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 <memory> +#include <acmplwrd.hxx> +#include <breakit.hxx> +#include <cellatr.hxx> +#include <checkit.hxx> +#include <cmdid.h> +#include <comphelper/processfactory.hxx> +#include <doc.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/autokernitem.hxx> +#include <editeng/blinkitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/charhiddenitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/forbiddenruleitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/hngpnctitem.hxx> +#include <editeng/hyphenzoneitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/nhypitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/orphitem.hxx> +#include <editeng/paravertalignitem.hxx> +#include <editeng/pbinitem.hxx> +#include <editeng/pgrditem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/rsiditem.hxx> +#include <svl/grabbagitem.hxx> +#include <svl/voiditem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/swafopt.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/twolinesitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <i18nutil/transliteration.hxx> +#include <editsh.hxx> +#include <fchrfmt.hxx> +#include <fmtanchr.hxx> +#include <fmtautofmt.hxx> +#include <fmtclbl.hxx> +#include <fmtclds.hxx> +#include <fmtcnct.hxx> +#include <fmtcntnt.hxx> +#include <fmteiro.hxx> +#include <fmtflcnt.hxx> +#include <fmtfld.hxx> +#include <fmtfollowtextflow.hxx> +#include <fmtfordr.hxx> +#include <fmtfsize.hxx> +#include <fmtftn.hxx> +#include <fmtftntx.hxx> +#include <formatlinebreak.hxx> +#include <fmthdft.hxx> +#include <fmtinfmt.hxx> +#include <fmtline.hxx> +#include <fmtlsplt.hxx> +#include <fmtmeta.hxx> +#include <formatcontentcontrol.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fmtrfmrk.hxx> +#include <fmtrowsplt.hxx> +#include <formatflysplit.hxx> +#include <formatwraptextatflystart.hxx> +#include <fmtruby.hxx> +#include <fmtsrnd.hxx> +#include <fmturl.hxx> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <fntcache.hxx> +#include <grfatr.hxx> +#include <hfspacingitem.hxx> +#include <hintids.hxx> +#include <init.hxx> +#include <paratr.hxx> +#include <proofreadingiterator.hxx> +#include <editeng/editids.hrc> +#include <svl/macitem.hxx> +#include <svx/sdtaitm.hxx> +#include <swcalwrp.hxx> +#include <SwStyleNameMapper.hxx> +#include <tblafmt.hxx> +#include <tgrditem.hxx> +#include <tools/globname.hxx> +#include <tox.hxx> +#include <unotools/charclass.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/collatorwrapper.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <vcl/mapmod.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <salhelper/singletonref.hxx> +#include <viscrs.hxx> + +using namespace ::com::sun::star; + +// some ranges for sets in collections/ nodes + +// AttrSet range for the 2 break attributes +WhichRangesContainer const aBreakSetRange(svl::Items< + RES_PAGEDESC, RES_BREAK +>); + +// AttrSet range for TextFormatColl +// list attributes ( RES_PARATR_LIST_BEGIN - RES_PARATR_LIST_END ) are not +// included in the paragraph style's itemset. +WhichRangesContainer const aTextFormatCollSetRange(svl::Items< + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + RES_PARATR_LIST_LEVEL, RES_PARATR_LIST_LEVEL, + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + + // FillAttribute support + XATTR_FILL_FIRST, XATTR_FILL_LAST + +>); + +// AttrSet range for GrfFormatColl +WhichRangesContainer const aGrfFormatCollSetRange(svl::Items< + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_GRFATR_BEGIN, RES_GRFATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +// AttrSet range for TextNode +WhichRangesContainer const aTextNodeSetRange(svl::Items< + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + + // FillAttribute support (paragraph FillStyle) + XATTR_FILL_FIRST, XATTR_FILL_LAST + +>); + +// AttrSet range for NoTextNode +WhichRangesContainer const aNoTextNodeSetRange(svl::Items< + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_GRFATR_BEGIN, RES_GRFATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +WhichRangesContainer const aTableSetRange(svl::Items< + RES_FILL_ORDER, RES_FRM_SIZE, + RES_LR_SPACE, RES_BREAK, + RES_HORI_ORIENT, RES_HORI_ORIENT, + RES_BACKGROUND, RES_SHADOW, + RES_KEEP, RES_KEEP, + RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT, + RES_FRAMEDIR, RES_FRAMEDIR, + // #i29550# + RES_COLLAPSING_BORDERS, RES_COLLAPSING_BORDERS, + // <-- collapsing + RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +WhichRangesContainer const aTableLineSetRange(svl::Items< + RES_FILL_ORDER, RES_FRM_SIZE, + RES_LR_SPACE, RES_UL_SPACE, + // HasTextChangesOnly + RES_PRINT, RES_PRINT, + RES_PROTECT, RES_PROTECT, + RES_VERT_ORIENT, RES_VERT_ORIENT, + RES_BACKGROUND, RES_SHADOW, + RES_ROW_SPLIT, RES_ROW_SPLIT, + RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +WhichRangesContainer const aTableBoxSetRange(svl::Items< + RES_FILL_ORDER, RES_FRM_SIZE, + RES_LR_SPACE, RES_UL_SPACE, + // HasTextChangesOnly + RES_PRINT, RES_PRINT, + RES_PROTECT, RES_PROTECT, + RES_VERT_ORIENT, RES_VERT_ORIENT, + RES_BACKGROUND, RES_SHADOW, + RES_FRAMEDIR, RES_FRAMEDIR, + RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG, + RES_BOXATR_BEGIN, RES_BOXATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +// AttrSet range for SwFrameFormat +WhichRangesContainer const aFrameFormatSetRange(svl::Items< + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + + // FillAttribute support (TextFrame, OLE, Writer GraphicObject) + XATTR_FILL_FIRST, XATTR_FILL_LAST + +>); + +// AttrSet range for SwCharFormat +WhichRangesContainer const aCharFormatSetRange(svl::Items< + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +// AttrSet range for character autostyles +WhichRangesContainer const aCharAutoFormatSetRange(svl::Items< + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +// AttrSet range for SwPageDescFormat +WhichRangesContainer const aPgFrameFormatSetRange(svl::Items< + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 +>); + +// create table for accessing default format attributes +SwDfltAttrTab aAttrTab( POOLATTR_END - POOLATTR_BEGIN, nullptr ); + +SfxItemInfo aSlotTab[] = +{ + // _nSID, _bNeedsPoolRegistration, _bShareable + { SID_ATTR_CHAR_CASEMAP, false, true }, // RES_CHRATR_CASEMAP + { SID_ATTR_CHAR_CHARSETCOLOR, false, true }, // RES_CHRATR_CHARSETCOLOR + { SID_ATTR_CHAR_COLOR, true, true }, // RES_CHRATR_COLOR + { SID_ATTR_CHAR_CONTOUR, false, true }, // RES_CHRATR_CONTOUR + { SID_ATTR_CHAR_STRIKEOUT, false, true }, // RES_CHRATR_CROSSEDOUT + { SID_ATTR_CHAR_ESCAPEMENT, false, true }, // RES_CHRATR_ESCAPEMENT + { SID_ATTR_CHAR_FONT, true, true }, // RES_CHRATR_FONT + { SID_ATTR_CHAR_FONTHEIGHT, false, true }, // RES_CHRATR_FONTSIZE + { SID_ATTR_CHAR_KERNING, false, true }, // RES_CHRATR_KERNING + { SID_ATTR_CHAR_LANGUAGE, false, true }, // RES_CHRATR_LANGUAGE + { SID_ATTR_CHAR_POSTURE, false, true }, // RES_CHRATR_POSTURE + { 0, false, true }, // RES_CHRATR_UNUSED1 + { SID_ATTR_CHAR_SHADOWED, false, true }, // RES_CHRATR_SHADOWED + { SID_ATTR_CHAR_UNDERLINE, true, true }, // RES_CHRATR_UNDERLINE + { SID_ATTR_CHAR_WEIGHT, false, true }, // RES_CHRATR_WEIGHT + { SID_ATTR_CHAR_WORDLINEMODE, false, true }, // RES_CHRATR_WORDLINEMODE + { SID_ATTR_CHAR_AUTOKERN, false, true }, // RES_CHRATR_AUTOKERN + { SID_ATTR_FLASH, false, true }, // RES_CHRATR_BLINK + { 0, false, true }, // RES_CHRATR_UNUSED2 + { 0, false, true }, // RES_CHRATR_NOHYPHEN + { SID_ATTR_BRUSH_CHAR, true, true }, // RES_CHRATR_BACKGROUND + { SID_ATTR_CHAR_CJK_FONT, true, true }, // RES_CHRATR_CJK_FONT + { SID_ATTR_CHAR_CJK_FONTHEIGHT, false, true }, // RES_CHRATR_CJK_FONTSIZE + { SID_ATTR_CHAR_CJK_LANGUAGE, false, true }, // RES_CHRATR_CJK_LANGUAGE + { SID_ATTR_CHAR_CJK_POSTURE, false, true }, // RES_CHRATR_CJK_POSTURE + { SID_ATTR_CHAR_CJK_WEIGHT, false, true }, // RES_CHRATR_CJK_WEIGHT + { SID_ATTR_CHAR_CTL_FONT, true, true }, // RES_CHRATR_CTL_FONT + { SID_ATTR_CHAR_CTL_FONTHEIGHT, false, true }, // RES_CHRATR_CTL_FONTSIZE + { SID_ATTR_CHAR_CTL_LANGUAGE, false, true }, // RES_CHRATR_CTL_LANGUAGE + { SID_ATTR_CHAR_CTL_POSTURE, false, true }, // RES_CHRATR_CTL_POSTURE + { SID_ATTR_CHAR_CTL_WEIGHT, false, true }, // RES_CHRATR_CTL_WEIGHT + { SID_ATTR_CHAR_ROTATED, false, true }, // RES_CHRATR_ROTATE + { SID_ATTR_CHAR_EMPHASISMARK, false, true }, // RES_CHRATR_EMPHASIS_MARK + { SID_ATTR_CHAR_TWO_LINES, false, true }, // RES_CHRATR_TWO_LINES + { SID_ATTR_CHAR_SCALEWIDTH, false, true }, // RES_CHRATR_SCALEW + { SID_ATTR_CHAR_RELIEF, false, true }, // RES_CHRATR_RELIEF + { SID_ATTR_CHAR_HIDDEN, false, true }, // RES_CHRATR_HIDDEN + { SID_ATTR_CHAR_OVERLINE, true, true }, // RES_CHRATR_OVERLINE + { 0, false, true }, // RES_CHRATR_RSID + { SID_ATTR_CHAR_BOX, true, true }, // RES_CHRATR_BOX + { SID_ATTR_CHAR_SHADOW, false, true }, // RES_CHRATR_SHADOW + { 0, true, true }, // RES_CHRATR_HIGHLIGHT + { SID_ATTR_CHAR_GRABBAG, false, true }, // RES_CHRATR_GRABBAG + { 0, false, true }, // RES_CHRATR_BIDIRTL + { 0, false, true }, // RES_CHRATR_IDCTHINT + + { 0, true, false }, // RES_TXTATR_REFMARK + { 0, true, false }, // RES_TXTATR_TOXMARK + { 0, false, false }, // RES_TXTATR_META + { 0, false, false }, // RES_TXTATR_METAFIELD + { 0, false, true }, // RES_TXTATR_AUTOFMT + { FN_TXTATR_INET, true, false }, // RES_TXTATR_INETFMT + { 0, false, false }, // RES_TXTATR_CHARFMT + { SID_ATTR_CHAR_CJK_RUBY, true, false }, // RES_TXTATR_CJK_RUBY + { 0, true, true }, // RES_TXTATR_UNKNOWN_CONTAINER + { 0, true, false }, // RES_TXTATR_INPUTFIELD + { 0, false, false }, // RES_TXTATR_CONTENTCONTROL + + { 0, true, false }, // RES_TXTATR_FIELD + { 0, false, false }, // RES_TXTATR_FLYCNT + { 0, false, false }, // RES_TXTATR_FTN + { 0, false, false }, // RES_TXTATR_ANNOTATION + { 0, false, false }, // RES_TXTATR_LINEBREAK + { 0, false, true }, // RES_TXTATR_DUMMY1 + + { SID_ATTR_PARA_LINESPACE, false, true }, // RES_PARATR_LINESPACING + { SID_ATTR_PARA_ADJUST, false, true }, // RES_PARATR_ADJUST + { SID_ATTR_PARA_SPLIT, false, true }, // RES_PARATR_SPLIT + { SID_ATTR_PARA_ORPHANS, false, true }, // RES_PARATR_ORPHANS + { SID_ATTR_PARA_WIDOWS, false, true }, // RES_PARATR_WIDOWS + { SID_ATTR_TABSTOP, true, true }, // RES_PARATR_TABSTOP + { SID_ATTR_PARA_HYPHENZONE, false, true }, // RES_PARATR_HYPHENZONE + { FN_FORMAT_DROPCAPS, false, false }, // RES_PARATR_DROP + { SID_ATTR_PARA_REGISTER, false, true }, // RES_PARATR_REGISTER + { SID_ATTR_PARA_NUMRULE, false, true }, // RES_PARATR_NUMRULE + { SID_ATTR_PARA_SCRIPTSPACE, false, true }, // RES_PARATR_SCRIPTSPACE + { SID_ATTR_PARA_HANGPUNCTUATION, false, true }, // RES_PARATR_HANGINGPUNCTUATION + + { SID_ATTR_PARA_FORBIDDEN_RULES, false, true }, // RES_PARATR_FORBIDDEN_RULES + { SID_PARA_VERTALIGN, false, true }, // RES_PARATR_VERTALIGN + { SID_ATTR_PARA_SNAPTOGRID, false, true }, // RES_PARATR_SNAPTOGRID + { SID_ATTR_BORDER_CONNECT, false, true }, // RES_PARATR_CONNECT_BORDER + + { SID_ATTR_PARA_OUTLINE_LEVEL, false, true }, // RES_PARATR_OUTLINELEVEL //#outline level + { 0, false, true }, // RES_PARATR_RSID + { SID_ATTR_PARA_GRABBAG, false, true }, // RES_PARATR_GRABBAG + { 0, false, true }, // RES_PARATR_LIST_ID + { 0, false, true }, // RES_PARATR_LIST_LEVEL + { 0, false, true }, // RES_PARATR_LIST_ISRESTART + { 0, false, true }, // RES_PARATR_LIST_RESTARTVALUE + { 0, false, true }, // RES_PARATR_LIST_ISCOUNTED + { 0, false, true }, // RES_PARATR_LIST_AUTOFMT + + { 0, false, true }, // RES_FILL_ORDER + { 0, false, true }, // RES_FRM_SIZE + { SID_ATTR_PAGE_PAPERBIN, false, true }, // RES_PAPER_BIN + { SID_ATTR_PARA_FIRSTLINESPACE, false, true }, // RES_MARGIN_FIRSTLINE + { SID_ATTR_PARA_LEFTSPACE, false, true }, // RES_MARGIN_TEXTLEFT + { SID_ATTR_PARA_RIGHTSPACE, false, true }, // RES_MARGIN_RIGHT + { 0, false, true }, // RES_MARGIN_LEFT + { 0, false, true }, // RES_MARGIN_GUTTER + { 0, false, true }, // RES_MARGIN_GUTTER_RIGHT + { SID_ATTR_LRSPACE, false, true }, // RES_LR_SPACE + { SID_ATTR_ULSPACE, false, true }, // RES_UL_SPACE + { 0, true, false }, // RES_PAGEDESC + { SID_ATTR_PARA_PAGEBREAK, false, true }, // RES_BREAK + { 0, false, false }, // RES_CNTNT + { 0, false, true }, // RES_HEADER + { 0, false, true }, // RES_FOOTER + { 0, false, true }, // RES_PRINT + { FN_OPAQUE, false, true }, // RES_OPAQUE + { FN_SET_PROTECT, false, true }, // RES_PROTECT + { FN_SURROUND, false, true }, // RES_SURROUND + { FN_VERT_ORIENT, false, true }, // RES_VERT_ORIENT + { FN_HORI_ORIENT, false, true }, // RES_HORI_ORIENT + { 0, false, false }, // RES_ANCHOR + { SID_ATTR_BRUSH, true, true }, // RES_BACKGROUND + { SID_ATTR_BORDER_OUTER, true, true }, // RES_BOX + { SID_ATTR_BORDER_SHADOW, true, true }, // RES_SHADOW + { SID_ATTR_MACROITEM, false, true }, // RES_FRMMACRO + { FN_ATTR_COLUMNS, false, true }, // RES_COL + { SID_ATTR_PARA_KEEP, false, true }, // RES_KEEP + { 0, true, true }, // RES_URL + { 0, false, true }, // RES_EDIT_IN_READONLY + + { 0, false, true }, // RES_LAYOUT_SPLIT + { 0, false, false }, // RES_CHAIN + { 0, false, true }, // RES_TEXTGRID + { FN_FORMAT_LINENUMBER, false, true }, // RES_LINENUMBER + { 0, false, true }, // RES_FTN_AT_TXTEND + { 0, false, true }, // RES_END_AT_TXTEND + { 0, false, true }, // RES_COLUMNBALANCE + + { SID_ATTR_FRAMEDIRECTION, false, true }, // RES_FRAMEDIR + + { SID_ATTR_HDFT_DYNAMIC_SPACING, false, true }, // RES_HEADER_FOOTER_EAT_SPACING + { FN_TABLE_ROW_SPLIT, false, true }, // RES_ROW_SPLIT + { 0, false, true }, // RES_FLY_SPLIT + // #i18732# - use slot-id define in svx + { SID_SW_FOLLOW_TEXT_FLOW, false, true }, // RES_FOLLOW_TEXT_FLOW + // #i29550# + { SID_SW_COLLAPSING_BORDERS, false, true }, // RES_COLLAPSING_BORDERS + // #i28701# + { SID_SW_WRAP_INFLUENCE_ON_OBJPOS, false, true }, // RES_WRAP_INFLUENCE_ON_OBJPOS + { 0, false, false }, // RES_AUTO_STYLE + { 0, false, true }, // RES_FRMATR_STYLE_NAME + { 0, false, true }, // RES_FRMATR_CONDITIONAL_STYLE_NAME + { 0, false, true }, // RES_FRMATR_GRABBAG + { 0, false, true }, // RES_TEXT_VERT_ADJUST + { 0, false, true }, // RES_BACKGROUND_FULL_SIZE + { 0, false, true }, // RES_RTL_GUTTER + { 0, false, true }, // RES_DECORATIVE + { 0, false, true }, // RES_WRAP_TEXT_AT_FLY_START + + { 0, false, true }, // RES_GRFATR_MIRRORGRF + { SID_ATTR_GRAF_CROP, false, true }, // RES_GRFATR_CROPGRF + { 0, false, true }, // RES_GRFATR_ROTATION, + { 0, false, true }, // RES_GRFATR_LUMINANCE, + { 0, false, true }, // RES_GRFATR_CONTRAST, + { 0, false, true }, // RES_GRFATR_CHANNELR, + { 0, false, true }, // RES_GRFATR_CHANNELG, + { 0, false, true }, // RES_GRFATR_CHANNELB, + { 0, false, true }, // RES_GRFATR_GAMMA, + { 0, false, true }, // RES_GRFATR_INVERT, + { 0, false, true }, // RES_GRFATR_TRANSPARENCY, + { 0, false, true }, // RES_GRFATR_DUMMY4, + { 0, false, true }, // RES_GRFATR_DUMMY5, + { 0, false, true }, // RES_GRFATR_DUMMY6, + + { 0, false, true }, // RES_BOXATR_FORMAT + { 0, true, false }, // RES_BOXATR_FORMULA, + { 0, false, true }, // RES_BOXATR_VALUE + + { 0, true, true } // RES_UNKNOWNATR_CONTAINER +}; + +std::vector<SvGlobalName> *pGlobalOLEExcludeList = nullptr; + +SwAutoCompleteWord* SwDoc::s_pAutoCompleteWords = nullptr; +SwDoc* SwDoc::s_pLast = nullptr; + +SwCheckIt* pCheckIt = nullptr; +static CharClass* pAppCharClass = nullptr; + +static CollatorWrapper* pCollator = nullptr, + *pCaseCollator = nullptr; + +SwCalendarWrapper& s_getCalendarWrapper() +{ + static SwCalendarWrapper aCalendarWrapper; + return aCalendarWrapper; +} + +void InitCore() +{ + SfxPoolItem* pItem; + + aAttrTab[ RES_CHRATR_CASEMAP- POOLATTR_BEGIN ] = new SvxCaseMapItem( SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP); + aAttrTab[ RES_CHRATR_CHARSETCOLOR- POOLATTR_BEGIN ] = new SvxColorItem(RES_CHRATR_CHARSETCOLOR); + aAttrTab[ RES_CHRATR_COLOR- POOLATTR_BEGIN ] = new SvxColorItem(RES_CHRATR_COLOR); + aAttrTab[ RES_CHRATR_CONTOUR- POOLATTR_BEGIN ] = new SvxContourItem( false, RES_CHRATR_CONTOUR ); + aAttrTab[ RES_CHRATR_CROSSEDOUT- POOLATTR_BEGIN ] = new SvxCrossedOutItem( STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ); + aAttrTab[ RES_CHRATR_ESCAPEMENT- POOLATTR_BEGIN ] = new SvxEscapementItem( RES_CHRATR_ESCAPEMENT ); + aAttrTab[ RES_CHRATR_FONT- POOLATTR_BEGIN ] = new SvxFontItem( RES_CHRATR_FONT ); + + aAttrTab[ RES_CHRATR_FONTSIZE- POOLATTR_BEGIN ] = new SvxFontHeightItem( 240, 100, RES_CHRATR_FONTSIZE ); + aAttrTab[ RES_CHRATR_KERNING- POOLATTR_BEGIN ] = new SvxKerningItem( 0, RES_CHRATR_KERNING ); + aAttrTab[ RES_CHRATR_LANGUAGE- POOLATTR_BEGIN ] = new SvxLanguageItem(LANGUAGE_DONTKNOW, RES_CHRATR_LANGUAGE ); + aAttrTab[ RES_CHRATR_POSTURE- POOLATTR_BEGIN ] = new SvxPostureItem( ITALIC_NONE, RES_CHRATR_POSTURE ); + aAttrTab[ RES_CHRATR_UNUSED1- POOLATTR_BEGIN ] = new SfxVoidItem( RES_CHRATR_UNUSED1 ); + aAttrTab[ RES_CHRATR_SHADOWED- POOLATTR_BEGIN ] = new SvxShadowedItem( false, RES_CHRATR_SHADOWED ); + aAttrTab[ RES_CHRATR_UNDERLINE- POOLATTR_BEGIN ] = new SvxUnderlineItem( LINESTYLE_NONE, RES_CHRATR_UNDERLINE ); + aAttrTab[ RES_CHRATR_WEIGHT- POOLATTR_BEGIN ] = new SvxWeightItem( WEIGHT_NORMAL, RES_CHRATR_WEIGHT ); + aAttrTab[ RES_CHRATR_RSID - POOLATTR_BEGIN ] = new SvxRsidItem( 0, RES_CHRATR_RSID ); + aAttrTab[ RES_CHRATR_WORDLINEMODE- POOLATTR_BEGIN ] = new SvxWordLineModeItem( false, RES_CHRATR_WORDLINEMODE ); + aAttrTab[ RES_CHRATR_AUTOKERN- POOLATTR_BEGIN ] = new SvxAutoKernItem( false, RES_CHRATR_AUTOKERN ); + aAttrTab[ RES_CHRATR_BLINK - POOLATTR_BEGIN ] = new SvxBlinkItem( false, RES_CHRATR_BLINK ); + aAttrTab[ RES_CHRATR_NOHYPHEN - POOLATTR_BEGIN ] = new SvxNoHyphenItem( RES_CHRATR_NOHYPHEN ); + aAttrTab[ RES_CHRATR_UNUSED2- POOLATTR_BEGIN ] = new SfxVoidItem( RES_CHRATR_UNUSED2 ); + aAttrTab[ RES_CHRATR_BACKGROUND - POOLATTR_BEGIN ] = new SvxBrushItem( RES_CHRATR_BACKGROUND ); + + // CJK-Attributes + aAttrTab[ RES_CHRATR_CJK_FONT - POOLATTR_BEGIN ] = new SvxFontItem( RES_CHRATR_CJK_FONT ); + aAttrTab[ RES_CHRATR_CJK_FONTSIZE - POOLATTR_BEGIN ] = new SvxFontHeightItem( 240, 100, RES_CHRATR_CJK_FONTSIZE ); + aAttrTab[ RES_CHRATR_CJK_LANGUAGE - POOLATTR_BEGIN ] = new SvxLanguageItem(LANGUAGE_DONTKNOW, RES_CHRATR_CJK_LANGUAGE); + aAttrTab[ RES_CHRATR_CJK_POSTURE - POOLATTR_BEGIN ] = new SvxPostureItem(ITALIC_NONE, RES_CHRATR_CJK_POSTURE ); + aAttrTab[ RES_CHRATR_CJK_WEIGHT - POOLATTR_BEGIN ] = new SvxWeightItem( WEIGHT_NORMAL, RES_CHRATR_CJK_WEIGHT ); + + // CTL-Attributes + aAttrTab[ RES_CHRATR_CTL_FONT - POOLATTR_BEGIN ] = new SvxFontItem( RES_CHRATR_CTL_FONT ); + aAttrTab[ RES_CHRATR_CTL_FONTSIZE - POOLATTR_BEGIN ] = new SvxFontHeightItem( 240, 100, RES_CHRATR_CTL_FONTSIZE ); + aAttrTab[ RES_CHRATR_CTL_LANGUAGE - POOLATTR_BEGIN ] = new SvxLanguageItem(LANGUAGE_DONTKNOW, RES_CHRATR_CTL_LANGUAGE); + aAttrTab[ RES_CHRATR_CTL_POSTURE - POOLATTR_BEGIN ] = new SvxPostureItem(ITALIC_NONE, RES_CHRATR_CTL_POSTURE ); + aAttrTab[ RES_CHRATR_CTL_WEIGHT - POOLATTR_BEGIN ] = new SvxWeightItem( WEIGHT_NORMAL, RES_CHRATR_CTL_WEIGHT ); + + aAttrTab[ RES_CHRATR_ROTATE - POOLATTR_BEGIN ] = new SvxCharRotateItem( 0_deg10, false, RES_CHRATR_ROTATE ); + aAttrTab[ RES_CHRATR_EMPHASIS_MARK - POOLATTR_BEGIN ] = new SvxEmphasisMarkItem( FontEmphasisMark::NONE, RES_CHRATR_EMPHASIS_MARK ); + aAttrTab[ RES_CHRATR_TWO_LINES - POOLATTR_BEGIN ] = new SvxTwoLinesItem( false, 0, 0, RES_CHRATR_TWO_LINES ); + aAttrTab[ RES_CHRATR_SCALEW - POOLATTR_BEGIN ] = new SvxCharScaleWidthItem( 100, RES_CHRATR_SCALEW ); + aAttrTab[ RES_CHRATR_RELIEF - POOLATTR_BEGIN ] = new SvxCharReliefItem( FontRelief::NONE, RES_CHRATR_RELIEF ); + aAttrTab[ RES_CHRATR_HIDDEN - POOLATTR_BEGIN ] = new SvxCharHiddenItem( false, RES_CHRATR_HIDDEN ); + aAttrTab[ RES_CHRATR_OVERLINE- POOLATTR_BEGIN ] = new SvxOverlineItem( LINESTYLE_NONE, RES_CHRATR_OVERLINE ); + aAttrTab[ RES_CHRATR_BOX - POOLATTR_BEGIN ] = new SvxBoxItem( RES_CHRATR_BOX ); + aAttrTab[ RES_CHRATR_SHADOW - POOLATTR_BEGIN ] = new SvxShadowItem( RES_CHRATR_SHADOW ); + aAttrTab[ RES_CHRATR_HIGHLIGHT - POOLATTR_BEGIN ] = new SvxBrushItem( RES_CHRATR_HIGHLIGHT ); + aAttrTab[ RES_CHRATR_GRABBAG - POOLATTR_BEGIN ] = new SfxGrabBagItem( RES_CHRATR_GRABBAG ); + +// CharacterAttr - MSWord weak char direction/script override emulation + aAttrTab[ RES_CHRATR_BIDIRTL - POOLATTR_BEGIN ] = new SfxInt16Item( RES_CHRATR_BIDIRTL, sal_Int16(-1) ); + aAttrTab[ RES_CHRATR_IDCTHINT - POOLATTR_BEGIN ] = new SfxInt16Item( RES_CHRATR_IDCTHINT, sal_Int16(-1) ); + + aAttrTab[ RES_TXTATR_REFMARK - POOLATTR_BEGIN ] = new SwFormatRefMark( OUString() ); + aAttrTab[ RES_TXTATR_TOXMARK - POOLATTR_BEGIN ] = new SwTOXMark; + aAttrTab[ RES_TXTATR_META - POOLATTR_BEGIN ] = SwFormatMeta::CreatePoolDefault(RES_TXTATR_META); + aAttrTab[ RES_TXTATR_METAFIELD - POOLATTR_BEGIN ] = SwFormatMeta::CreatePoolDefault(RES_TXTATR_METAFIELD); + aAttrTab[ RES_TXTATR_AUTOFMT- POOLATTR_BEGIN ] = new SwFormatAutoFormat; + aAttrTab[ RES_TXTATR_INETFMT - POOLATTR_BEGIN ] = new SwFormatINetFormat( OUString(), OUString() ); + aAttrTab[ RES_TXTATR_CHARFMT- POOLATTR_BEGIN ] = new SwFormatCharFormat( nullptr ); + aAttrTab[ RES_TXTATR_CJK_RUBY - POOLATTR_BEGIN ] = new SwFormatRuby( OUString() ); + aAttrTab[ RES_TXTATR_UNKNOWN_CONTAINER - POOLATTR_BEGIN ] = new SvXMLAttrContainerItem( RES_TXTATR_UNKNOWN_CONTAINER ); + aAttrTab[ RES_TXTATR_INPUTFIELD - POOLATTR_BEGIN ] = new SwFormatField( RES_TXTATR_INPUTFIELD ); + aAttrTab[ RES_TXTATR_CONTENTCONTROL - POOLATTR_BEGIN ] = new SwFormatContentControl( RES_TXTATR_CONTENTCONTROL ); + + aAttrTab[ RES_TXTATR_FIELD- POOLATTR_BEGIN ] = new SwFormatField( RES_TXTATR_FIELD ); + aAttrTab[ RES_TXTATR_FLYCNT - POOLATTR_BEGIN ] = new SwFormatFlyCnt( nullptr ); + aAttrTab[ RES_TXTATR_FTN - POOLATTR_BEGIN ] = new SwFormatFootnote; + aAttrTab[ RES_TXTATR_ANNOTATION - POOLATTR_BEGIN ] = new SwFormatField( RES_TXTATR_ANNOTATION ); + aAttrTab[RES_TXTATR_LINEBREAK - POOLATTR_BEGIN] = new SwFormatLineBreak(SwLineBreakClear::NONE); + +// TextAttr - Dummies + aAttrTab[ RES_TXTATR_DUMMY1 - POOLATTR_BEGIN ] = new SfxBoolItem( RES_TXTATR_DUMMY1 ); + + aAttrTab[ RES_PARATR_LINESPACING- POOLATTR_BEGIN ] = new SvxLineSpacingItem( LINE_SPACE_DEFAULT_HEIGHT, RES_PARATR_LINESPACING ); + aAttrTab[ RES_PARATR_ADJUST- POOLATTR_BEGIN ] = new SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ); + aAttrTab[ RES_PARATR_SPLIT- POOLATTR_BEGIN ] = new SvxFormatSplitItem( true, RES_PARATR_SPLIT ); + aAttrTab[ RES_PARATR_WIDOWS- POOLATTR_BEGIN ] = new SvxWidowsItem( 0, RES_PARATR_WIDOWS ); + aAttrTab[ RES_PARATR_ORPHANS- POOLATTR_BEGIN ] = new SvxOrphansItem( 0, RES_PARATR_ORPHANS ); + aAttrTab[ RES_PARATR_TABSTOP- POOLATTR_BEGIN ] = new SvxTabStopItem( 1, SVX_TAB_DEFDIST, SvxTabAdjust::Default, RES_PARATR_TABSTOP ); + + pItem = new SvxHyphenZoneItem( false, RES_PARATR_HYPHENZONE ); + static_cast<SvxHyphenZoneItem*>(pItem)->GetMaxHyphens() = 0; // Default: 0 + aAttrTab[ RES_PARATR_HYPHENZONE- POOLATTR_BEGIN ] = pItem; + + aAttrTab[ RES_PARATR_DROP- POOLATTR_BEGIN ] = new SwFormatDrop; + aAttrTab[ RES_PARATR_REGISTER - POOLATTR_BEGIN ] = new SwRegisterItem( false ); + aAttrTab[ RES_PARATR_NUMRULE - POOLATTR_BEGIN ] = new SwNumRuleItem( OUString() ); + + aAttrTab[ RES_PARATR_SCRIPTSPACE - POOLATTR_BEGIN ] = new SvxScriptSpaceItem( true, RES_PARATR_SCRIPTSPACE ); + aAttrTab[ RES_PARATR_HANGINGPUNCTUATION - POOLATTR_BEGIN ] = new SvxHangingPunctuationItem( true, RES_PARATR_HANGINGPUNCTUATION ); + aAttrTab[ RES_PARATR_FORBIDDEN_RULES - POOLATTR_BEGIN ] = new SvxForbiddenRuleItem( true, RES_PARATR_FORBIDDEN_RULES ); + aAttrTab[ RES_PARATR_VERTALIGN - POOLATTR_BEGIN ] = new SvxParaVertAlignItem( SvxParaVertAlignItem::Align::Automatic, RES_PARATR_VERTALIGN ); + aAttrTab[ RES_PARATR_SNAPTOGRID - POOLATTR_BEGIN ] = new SvxParaGridItem( true, RES_PARATR_SNAPTOGRID ); + aAttrTab[ RES_PARATR_CONNECT_BORDER - POOLATTR_BEGIN ] = new SwParaConnectBorderItem; + + aAttrTab[ RES_PARATR_OUTLINELEVEL - POOLATTR_BEGIN ] = new SfxUInt16Item( RES_PARATR_OUTLINELEVEL, 0 ); + aAttrTab[ RES_PARATR_RSID - POOLATTR_BEGIN ] = new SvxRsidItem( 0, RES_PARATR_RSID ); + aAttrTab[ RES_PARATR_GRABBAG - POOLATTR_BEGIN ] = new SfxGrabBagItem( RES_PARATR_GRABBAG ); + + aAttrTab[ RES_PARATR_LIST_ID - POOLATTR_BEGIN ] = new SfxStringItem( RES_PARATR_LIST_ID, OUString() ); + aAttrTab[ RES_PARATR_LIST_LEVEL - POOLATTR_BEGIN ] = new SfxInt16Item( RES_PARATR_LIST_LEVEL, 0 ); + aAttrTab[ RES_PARATR_LIST_ISRESTART - POOLATTR_BEGIN ] = new SfxBoolItem( RES_PARATR_LIST_ISRESTART, false ); + aAttrTab[ RES_PARATR_LIST_RESTARTVALUE - POOLATTR_BEGIN ] = new SfxInt16Item( RES_PARATR_LIST_RESTARTVALUE, 1 ); + aAttrTab[ RES_PARATR_LIST_ISCOUNTED - POOLATTR_BEGIN ] = new SfxBoolItem( RES_PARATR_LIST_ISCOUNTED, true ); + aAttrTab[ RES_PARATR_LIST_AUTOFMT - POOLATTR_BEGIN ] = new SwFormatAutoFormat(RES_PARATR_LIST_AUTOFMT);//new SfxSetItem(RES_PARATR_LIST_AUTOFMT, std::make_unique<SfxItemSet>(aCharAutoFormatSetRange)); + + aAttrTab[ RES_FILL_ORDER- POOLATTR_BEGIN ] = new SwFormatFillOrder; + aAttrTab[ RES_FRM_SIZE- POOLATTR_BEGIN ] = new SwFormatFrameSize; + aAttrTab[ RES_PAPER_BIN- POOLATTR_BEGIN ] = new SvxPaperBinItem( RES_PAPER_BIN ); + aAttrTab[ RES_MARGIN_FIRSTLINE - POOLATTR_BEGIN ] = new SvxFirstLineIndentItem(RES_MARGIN_FIRSTLINE); + aAttrTab[ RES_MARGIN_TEXTLEFT - POOLATTR_BEGIN ] = new SvxTextLeftMarginItem(RES_MARGIN_TEXTLEFT); + aAttrTab[ RES_MARGIN_RIGHT - POOLATTR_BEGIN ] = new SvxRightMarginItem(RES_MARGIN_RIGHT); + aAttrTab[ RES_MARGIN_LEFT - POOLATTR_BEGIN ] = new SvxLeftMarginItem(RES_MARGIN_LEFT); + aAttrTab[ RES_MARGIN_GUTTER - POOLATTR_BEGIN ] = new SvxGutterLeftMarginItem(RES_MARGIN_GUTTER); + aAttrTab[ RES_MARGIN_GUTTER_RIGHT - POOLATTR_BEGIN ] = new SvxGutterRightMarginItem(RES_MARGIN_GUTTER_RIGHT); + aAttrTab[ RES_LR_SPACE- POOLATTR_BEGIN ] = new SvxLRSpaceItem( RES_LR_SPACE ); + aAttrTab[ RES_UL_SPACE- POOLATTR_BEGIN ] = new SvxULSpaceItem( RES_UL_SPACE ); + aAttrTab[ RES_PAGEDESC- POOLATTR_BEGIN ] = new SwFormatPageDesc; + aAttrTab[ RES_BREAK- POOLATTR_BEGIN ] = new SvxFormatBreakItem( SvxBreak::NONE, RES_BREAK); + aAttrTab[ RES_CNTNT- POOLATTR_BEGIN ] = new SwFormatContent; + aAttrTab[ RES_HEADER- POOLATTR_BEGIN ] = new SwFormatHeader; + aAttrTab[ RES_FOOTER- POOLATTR_BEGIN ] = new SwFormatFooter; + aAttrTab[ RES_PRINT- POOLATTR_BEGIN ] = new SvxPrintItem( RES_PRINT ); + aAttrTab[ RES_OPAQUE- POOLATTR_BEGIN ] = new SvxOpaqueItem( RES_OPAQUE ); + aAttrTab[ RES_PROTECT- POOLATTR_BEGIN ] = new SvxProtectItem( RES_PROTECT ); + aAttrTab[ RES_SURROUND- POOLATTR_BEGIN ] = new SwFormatSurround; + aAttrTab[ RES_VERT_ORIENT- POOLATTR_BEGIN ] = new SwFormatVertOrient; + aAttrTab[ RES_HORI_ORIENT- POOLATTR_BEGIN ] = new SwFormatHoriOrient; + aAttrTab[ RES_ANCHOR- POOLATTR_BEGIN ] = new SwFormatAnchor; + aAttrTab[ RES_BACKGROUND- POOLATTR_BEGIN ] = new SvxBrushItem( RES_BACKGROUND ); + aAttrTab[ RES_BOX- POOLATTR_BEGIN ] = new SvxBoxItem( RES_BOX ); + aAttrTab[ RES_SHADOW- POOLATTR_BEGIN ] = new SvxShadowItem( RES_SHADOW ); + aAttrTab[ RES_FRMMACRO- POOLATTR_BEGIN ] = new SvxMacroItem( RES_FRMMACRO ); + aAttrTab[ RES_COL- POOLATTR_BEGIN ] = new SwFormatCol; + aAttrTab[ RES_KEEP - POOLATTR_BEGIN ] = new SvxFormatKeepItem( false, RES_KEEP ); + aAttrTab[ RES_URL - POOLATTR_BEGIN ] = new SwFormatURL(); + aAttrTab[ RES_EDIT_IN_READONLY - POOLATTR_BEGIN ] = new SwFormatEditInReadonly; + aAttrTab[ RES_LAYOUT_SPLIT - POOLATTR_BEGIN ] = new SwFormatLayoutSplit; + aAttrTab[ RES_CHAIN - POOLATTR_BEGIN ] = new SwFormatChain; + aAttrTab[ RES_TEXTGRID - POOLATTR_BEGIN ] = new SwTextGridItem; + aAttrTab[ RES_HEADER_FOOTER_EAT_SPACING - POOLATTR_BEGIN ] = new SwHeaderAndFooterEatSpacingItem; + aAttrTab[ RES_LINENUMBER - POOLATTR_BEGIN ] = new SwFormatLineNumber; + aAttrTab[ RES_FTN_AT_TXTEND - POOLATTR_BEGIN ] = new SwFormatFootnoteAtTextEnd; + aAttrTab[ RES_END_AT_TXTEND - POOLATTR_BEGIN ] = new SwFormatEndAtTextEnd; + aAttrTab[ RES_COLUMNBALANCE - POOLATTR_BEGIN ] = new SwFormatNoBalancedColumns; + aAttrTab[ RES_FRAMEDIR - POOLATTR_BEGIN ] = new SvxFrameDirectionItem( SvxFrameDirection::Environment, RES_FRAMEDIR ); + aAttrTab[ RES_ROW_SPLIT - POOLATTR_BEGIN ] = new SwFormatRowSplit; + aAttrTab[ RES_FLY_SPLIT - POOLATTR_BEGIN ] = new SwFormatFlySplit; + + // #i18732# + aAttrTab[ RES_FOLLOW_TEXT_FLOW - POOLATTR_BEGIN ] = new SwFormatFollowTextFlow(false); + // collapsing borders #i29550# + aAttrTab[ RES_COLLAPSING_BORDERS - POOLATTR_BEGIN ] = new SfxBoolItem( RES_COLLAPSING_BORDERS, false ); + // #i28701# + // #i35017# - constant name has changed + aAttrTab[ RES_WRAP_INFLUENCE_ON_OBJPOS - POOLATTR_BEGIN ] = new SwFormatWrapInfluenceOnObjPos( text::WrapInfluenceOnPosition::ONCE_CONCURRENT ); + + aAttrTab[ RES_AUTO_STYLE - POOLATTR_BEGIN ] = new SwFormatAutoFormat( RES_AUTO_STYLE ); + aAttrTab[ RES_FRMATR_STYLE_NAME - POOLATTR_BEGIN ] = new SfxStringItem( RES_FRMATR_STYLE_NAME, OUString()); + aAttrTab[ RES_FRMATR_CONDITIONAL_STYLE_NAME - POOLATTR_BEGIN ] = new SfxStringItem( RES_FRMATR_CONDITIONAL_STYLE_NAME, OUString() ); + aAttrTab[ RES_FRMATR_GRABBAG - POOLATTR_BEGIN ] = new SfxGrabBagItem(RES_FRMATR_GRABBAG); + aAttrTab[ RES_TEXT_VERT_ADJUST - POOLATTR_BEGIN ] = new SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP,RES_TEXT_VERT_ADJUST); + aAttrTab[ RES_BACKGROUND_FULL_SIZE - POOLATTR_BEGIN ] = new SfxBoolItem(RES_BACKGROUND_FULL_SIZE, true); + aAttrTab[ RES_RTL_GUTTER - POOLATTR_BEGIN ] = new SfxBoolItem(RES_RTL_GUTTER, false); + aAttrTab[ RES_DECORATIVE - POOLATTR_BEGIN ] = new SfxBoolItem(RES_DECORATIVE, false); + aAttrTab[ RES_WRAP_TEXT_AT_FLY_START - POOLATTR_BEGIN ] = new SwFormatWrapTextAtFlyStart; + + aAttrTab[ RES_GRFATR_MIRRORGRF- POOLATTR_BEGIN ] = new SwMirrorGrf; + aAttrTab[ RES_GRFATR_CROPGRF- POOLATTR_BEGIN ] = new SwCropGrf; + aAttrTab[ RES_GRFATR_ROTATION - POOLATTR_BEGIN ] = new SwRotationGrf; + aAttrTab[ RES_GRFATR_LUMINANCE - POOLATTR_BEGIN ] = new SwLuminanceGrf; + aAttrTab[ RES_GRFATR_CONTRAST - POOLATTR_BEGIN ] = new SwContrastGrf; + aAttrTab[ RES_GRFATR_CHANNELR - POOLATTR_BEGIN ] = new SwChannelRGrf; + aAttrTab[ RES_GRFATR_CHANNELG - POOLATTR_BEGIN ] = new SwChannelGGrf; + aAttrTab[ RES_GRFATR_CHANNELB - POOLATTR_BEGIN ] = new SwChannelBGrf; + aAttrTab[ RES_GRFATR_GAMMA - POOLATTR_BEGIN ] = new SwGammaGrf; + aAttrTab[ RES_GRFATR_INVERT - POOLATTR_BEGIN ] = new SwInvertGrf; + aAttrTab[ RES_GRFATR_TRANSPARENCY - POOLATTR_BEGIN ] = new SwTransparencyGrf; + aAttrTab[ RES_GRFATR_DRAWMODE - POOLATTR_BEGIN ] = new SwDrawModeGrf; + +// GraphicAttr - Dummies + aAttrTab[ RES_GRFATR_DUMMY4 - POOLATTR_BEGIN ] = new SfxBoolItem( RES_GRFATR_DUMMY4 ); + aAttrTab[ RES_GRFATR_DUMMY5 - POOLATTR_BEGIN ] = new SfxBoolItem( RES_GRFATR_DUMMY5 ); + + aAttrTab[ RES_BOXATR_FORMAT- POOLATTR_BEGIN ] = new SwTableBoxNumFormat; + aAttrTab[ RES_BOXATR_FORMULA- POOLATTR_BEGIN ] = new SwTableBoxFormula( OUString() ); + aAttrTab[ RES_BOXATR_VALUE- POOLATTR_BEGIN ] = new SwTableBoxValue; + + aAttrTab[ RES_UNKNOWNATR_CONTAINER- POOLATTR_BEGIN ] = + new SvXMLAttrContainerItem( RES_UNKNOWNATR_CONTAINER ); + + // get the correct fonts: + ::GetDefaultFonts( (aAttrTab[ RES_CHRATR_FONT- POOLATTR_BEGIN ])->StaticWhichCast(RES_CHRATR_FONT), + (aAttrTab[ RES_CHRATR_CJK_FONT - POOLATTR_BEGIN ])->StaticWhichCast(RES_CHRATR_CJK_FONT), + (aAttrTab[ RES_CHRATR_CTL_FONT - POOLATTR_BEGIN ])->StaticWhichCast(RES_CHRATR_CTL_FONT) ); + + SwBreakIt::Create_( ::comphelper::getProcessComponentContext() ); + pCheckIt = nullptr; + + FrameInit(); + TextInit_(); + + SwSelPaintRects::s_pMapMode = new MapMode; + SwFntObj::s_pPixMap = new MapMode; + + pGlobalOLEExcludeList = new std::vector<SvGlobalName>; + + if (!utl::ConfigManager::IsFuzzing()) + { + const SvxSwAutoFormatFlags& rAFlags = SvxAutoCorrCfg::Get().GetAutoCorrect()->GetSwFlags(); + SwDoc::s_pAutoCompleteWords = new SwAutoCompleteWord( rAFlags.nAutoCmpltListLen, + rAFlags.nAutoCmpltWordLen ); + } + else + { + SwDoc::s_pAutoCompleteWords = new SwAutoCompleteWord( 0, 0 ); + } +} + +void FinitCore() +{ + FrameFinit(); + TextFinit(); + + sw::proofreadingiterator::dispose(); + SwBreakIt::Delete_(); + delete pCheckIt; + delete pAppCharClass; + delete pCollator; + delete pCaseCollator; + + // destroy default TableAutoFormat + delete SwTableAutoFormat::s_pDefaultBoxAutoFormat; + + delete SwSelPaintRects::s_pMapMode; + delete SwFntObj::s_pPixMap; + + delete SwEditShell::s_pAutoFormatFlags; + +#if OSL_DEBUG_LEVEL > 0 + // free defaults to prevent assertions + if ( aAttrTab[0]->GetRefCount() ) + SfxItemPool::ReleaseDefaults( &aAttrTab ); +#endif + delete SwDoc::s_pAutoCompleteWords; + + // delete all default attributes + for(SfxPoolItem* pHt : aAttrTab) + { + delete pHt; + } + + delete pGlobalOLEExcludeList; +} + +// returns the APP - CharClass instance - used for all ToUpper/ToLower/... +CharClass& GetAppCharClass() +{ + if ( !pAppCharClass ) + { + pAppCharClass = new CharClass( + ::comphelper::getProcessComponentContext(), + SwBreakIt::Get()->GetLanguageTag( GetAppLanguageTag() )); + } + return *pAppCharClass; +} + +void SwCalendarWrapper::LoadDefaultCalendar( LanguageType eLang ) +{ + if( eLang != m_nLang ) + { + m_nLang = eLang; + loadDefaultCalendar( LanguageTag::convertToLocale( m_nLang )); + } +} + +LanguageType GetAppLanguage() +{ + if (!utl::ConfigManager::IsFuzzing()) + return Application::GetSettings().GetLanguageTag().getLanguageType(); + return LANGUAGE_ENGLISH_US; +} + +const LanguageTag& GetAppLanguageTag() +{ + return Application::GetSettings().GetLanguageTag(); +} + +CollatorWrapper& GetAppCollator() +{ + if( !pCollator ) + { + const lang::Locale& rLcl = g_pBreakIt->GetLocale( GetAppLanguage() ); + + pCollator = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); + pCollator->loadDefaultCollator( rLcl, SW_COLLATOR_IGNORES ); + } + return *pCollator; +} + +CollatorWrapper& GetAppCaseCollator() +{ + if( !pCaseCollator ) + { + const lang::Locale& rLcl = g_pBreakIt->GetLocale( GetAppLanguage() ); + + pCaseCollator = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); + pCaseCollator->loadDefaultCollator( rLcl, 0 ); + } + return *pCaseCollator; +} + +namespace +{ + class TransWrp + { + private: + std::unique_ptr<utl::TransliterationWrapper> m_xTransWrp; + public: + TransWrp() + { + uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + + m_xTransWrp.reset(new ::utl::TransliterationWrapper( xContext, + TransliterationFlags::IGNORE_CASE | + TransliterationFlags::IGNORE_KANA | + TransliterationFlags::IGNORE_WIDTH )); + + m_xTransWrp->loadModuleIfNeeded( GetAppLanguage() ); + } + const ::utl::TransliterationWrapper& getTransliterationWrapper() const + { + return *m_xTransWrp; + } + }; +} + +const ::utl::TransliterationWrapper& GetAppCmpStrIgnore() +{ + static TransWrp theTransWrp; + return theTransWrp.getTransliterationWrapper(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/proofreadingiterator.cxx b/sw/source/core/bastyp/proofreadingiterator.cxx new file mode 100644 index 0000000000..64c0ac2b1d --- /dev/null +++ b/sw/source/core/bastyp/proofreadingiterator.cxx @@ -0,0 +1,67 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/linguistic2/ProofreadingIterator.hpp> +#include <com/sun/star/linguistic2/XProofreadingIterator.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <vcl/svapp.hxx> + +#include <proofreadingiterator.hxx> + +namespace +{ +css::uno::Reference<css::linguistic2::XProofreadingIterator> instance; +bool disposed = false; + +void doDispose(css::uno::Reference<css::linguistic2::XProofreadingIterator> const& inst) +{ + css::uno::Reference<css::lang::XComponent> comp(inst, css::uno::UNO_QUERY); + if (comp.is()) + { + SolarMutexReleaser r; + comp->dispose(); + } +} +} + +css::uno::Reference<css::linguistic2::XProofreadingIterator> +sw::proofreadingiterator::get(css::uno::Reference<css::uno::XComponentContext> const& context) +{ + css::uno::Reference<css::linguistic2::XProofreadingIterator> inst( + css::linguistic2::ProofreadingIterator::create(context)); + bool disp; + { + SolarMutexGuard g; + instance = inst; + disp = disposed; + } + if (disp) + { + doDispose(inst); + } + return inst; +} + +void sw::proofreadingiterator::dispose() +{ + css::uno::Reference<css::linguistic2::XProofreadingIterator> inst; + { + SolarMutexGuard g; + inst = instance; + instance.clear(); + disposed = true; + } + doDispose(inst); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/swcache.cxx b/sw/source/core/bastyp/swcache.cxx new file mode 100644 index 0000000000..531ce2de44 --- /dev/null +++ b/sw/source/core/bastyp/swcache.cxx @@ -0,0 +1,506 @@ +/* -*- 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 <swcache.hxx> + +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <utility> + +#include <limits.h> + +#ifdef DBG_UTIL +void SwCache::Check() +{ + if ( !m_pRealFirst ) + { + assert(m_pFirst == nullptr && m_pLast == nullptr); + return; + } + + // consistency check + assert(m_pLast->GetNext() == nullptr); + assert(m_pRealFirst->GetPrev() == nullptr); + sal_uInt16 nCnt = 0; + bool bFirstFound = false; + SwCacheObj *pObj = m_pRealFirst; + SwCacheObj *const pOldRealFirst = m_pRealFirst; + while ( pObj ) + { + ++nCnt; + if ( pObj == m_pFirst ) + bFirstFound = true; + SwCacheObj* pNext = pObj->GetNext(); + if ( !pNext ) + { + assert(pObj == m_pLast); + } + else + { + assert(pObj == pNext->GetPrev()); + } + pObj = pNext; + assert(pObj != pOldRealFirst); (void) pOldRealFirst; + } + assert(bFirstFound); + SAL_WARN_IF( nCnt + m_aFreePositions.size() != size(), "sw.core", "Lost Chain." ); + SAL_WARN_IF( + size() == m_nCurMax && m_nCurMax != m_aFreePositions.size() + nCnt, "sw.core", + "Lost FreePositions." ); +} + +#define INCREMENT( nVar ) ++nVar +#define CHECK Check(); + +#else +#define INCREMENT( nVar ) +#define CHECK +#endif + +SwCache::SwCache( const sal_uInt16 nInitSize +#ifdef DBG_UTIL + , OString aNm +#endif + ) : + m_pRealFirst( nullptr ), + m_pFirst( nullptr ), + m_pLast( nullptr ), + m_nCurMax( nInitSize ) +#ifdef DBG_UTIL + , m_aName(std::move( aNm )) + , m_nAppend( 0 ) + , m_nInsertFree( 0 ) + , m_nReplace( 0 ) + , m_nGetSuccess( 0 ) + , m_nGetFail( 0 ) + , m_nToTop( 0 ) + , m_nDelete( 0 ) + , m_nGetSeek( 0 ) + , m_nAverageSeekCnt( 0 ) + , m_nFlushCnt( 0 ) + , m_nFlushedObjects( 0 ) + , m_nIncreaseMax( 0 ) + , m_nDecreaseMax( 0 ) +#endif +{ + m_aCacheObjects.reserve( nInitSize ); +} + +SwCache::~SwCache() +{ +#ifdef DBG_UTIL + SAL_INFO( + "sw.core", + m_aName << "; number of new entries: " << m_nAppend + << "; number of insert on free places: " << m_nInsertFree + << "; number of replacements: " << m_nReplace + << "; number of successful Gets: " << m_nGetSuccess + << "; number of failed Gets: " << m_nGetFail + << "; number or reordering (LRU): " << m_nToTop + << "; number of suppressions: " << m_nDelete + << "; number of Gets without Index: " << m_nGetSeek + << "; number of Seek for Get without Index: " << m_nAverageSeekCnt + << "; number of Flush calls: " << m_nFlushCnt + << "; number of flushed objects: " << m_nFlushedObjects + << "; number of Cache expansions: " << m_nIncreaseMax + << "; number of Cache reductions: " << m_nDecreaseMax); + Check(); +#endif +} + +void SwCache::IncreaseMax( const sal_uInt16 nAdd ) +{ + if (o3tl::checked_add(m_nCurMax, nAdd, m_nCurMax)) + { + std::abort(); + } +#ifdef DBG_UTIL + ++m_nIncreaseMax; +#endif +} + +void SwCache::DecreaseMax( const sal_uInt16 nSub ) +{ + if ( m_nCurMax > nSub ) + m_nCurMax = m_nCurMax - sal::static_int_cast< sal_uInt16 >(nSub); +#ifdef DBG_UTIL + ++m_nDecreaseMax; +#endif +} + +void SwCache::Flush() +{ + INCREMENT( m_nFlushCnt ); + SwCacheObj *pObj = m_pRealFirst; + m_pRealFirst = m_pFirst = m_pLast = nullptr; + while ( pObj ) + { + assert(!pObj->IsLocked()); + SwCacheObj *pTmp = pObj; + pObj = pTmp->GetNext(); + m_aFreePositions.push_back( pTmp->GetCachePos() ); + m_aCacheObjects[pTmp->GetCachePos()].reset(); // deletes pTmp + INCREMENT( m_nFlushedObjects ); + } +} + +void SwCache::ToTop( SwCacheObj *pObj ) +{ + INCREMENT( m_nToTop ); + + // cut object out of chain and insert at beginning + if ( m_pRealFirst == pObj ) // pFirst was checked by caller + { + CHECK; + return; + } + + if ( !m_pRealFirst ) + { + // the first will be inserted + assert(!m_pFirst && !m_pLast); + m_pRealFirst = m_pFirst = m_pLast = pObj; + CHECK; + return; + } + + assert(m_pFirst && m_pLast); + + // cut + if ( pObj == m_pLast ) + { + assert(pObj->GetPrev()); + m_pLast = pObj->GetPrev(); + m_pLast->SetNext( nullptr ); + } + else + { + if ( pObj->GetNext() ) + pObj->GetNext()->SetPrev( pObj->GetPrev() ); + if ( pObj->GetPrev() ) + pObj->GetPrev()->SetNext( pObj->GetNext() ); + } + + // paste at the (virtual) beginning + if ( m_pRealFirst == m_pFirst ) + { + m_pRealFirst->SetPrev( pObj ); + pObj->SetNext( m_pRealFirst ); + pObj->SetPrev( nullptr ); + m_pRealFirst = m_pFirst = pObj; + CHECK; + } + else + { + if ( m_pFirst->GetPrev() ) + { + m_pFirst->GetPrev()->SetNext( pObj ); + pObj->SetPrev( m_pFirst->GetPrev() ); + } + else + pObj->SetPrev( nullptr ); + m_pFirst->SetPrev( pObj ); + pObj->SetNext( m_pFirst ); + m_pFirst = pObj; + CHECK; + } +} + +SwCacheObj *SwCache::Get( const void *pOwner, const sal_uInt16 nIndex, + const bool bToTop ) +{ + SwCacheObj *pRet = (nIndex < m_aCacheObjects.size()) ? m_aCacheObjects[ nIndex ].get() : nullptr; + if ( pRet ) + { + if ( !pRet->IsOwner( pOwner ) ) + pRet = nullptr; + else if ( bToTop && pRet != m_pFirst ) + ToTop( pRet ); + } + +#ifdef DBG_UTIL + if ( pRet ) + ++m_nGetSuccess; + else + ++m_nGetFail; +#endif + + return pRet; +} + +SwCacheObj *SwCache::Get( const void *pOwner, const bool bToTop ) +{ + SwCacheObj *pRet = m_pRealFirst; + while ( pRet && !pRet->IsOwner( pOwner ) ) + { + INCREMENT( m_nAverageSeekCnt ); + pRet = pRet->GetNext(); + } + + if ( bToTop && pRet && pRet != m_pFirst ) + ToTop( pRet ); + +#ifdef DBG_UTIL + if ( pRet ) + ++m_nGetSuccess; + else + ++m_nGetFail; + ++m_nGetSeek; +#endif + return pRet; +} + +void SwCache::DeleteObj( SwCacheObj *pObj ) +{ + CHECK; + OSL_ENSURE( !pObj->IsLocked(), "SwCache::Delete: object is locked." ); + if ( pObj->IsLocked() ) + return; + + if ( m_pFirst == pObj ) + { + if ( m_pFirst->GetNext() ) + m_pFirst = m_pFirst->GetNext(); + else + m_pFirst = m_pFirst->GetPrev(); + } + if ( m_pRealFirst == pObj ) + m_pRealFirst = m_pRealFirst->GetNext(); + if ( m_pLast == pObj ) + m_pLast = m_pLast->GetPrev(); + if ( pObj->GetPrev() ) + pObj->GetPrev()->SetNext( pObj->GetNext() ); + if ( pObj->GetNext() ) + pObj->GetNext()->SetPrev( pObj->GetPrev() ); + + m_aFreePositions.push_back( pObj->GetCachePos() ); + assert(m_aCacheObjects[pObj->GetCachePos()].get() == pObj); + m_aCacheObjects[pObj->GetCachePos()] = nullptr; // deletes pObj + + CHECK; + if ( m_aCacheObjects.size() > m_nCurMax && + (m_nCurMax <= (m_aCacheObjects.size() - m_aFreePositions.size())) ) + { + // Shrink if possible.To do so we need enough free positions. + // Unpleasant side effect: positions will be moved and the owner of + // these might not find them afterwards + for ( size_t i = 0; i < m_aCacheObjects.size(); ++i ) + { + SwCacheObj *pTmpObj = m_aCacheObjects[i].get(); + if ( !pTmpObj ) + { + m_aCacheObjects.erase( m_aCacheObjects.begin() + i ); + --i; + } + else + { + pTmpObj->SetCachePos( i ); + } + } + m_aFreePositions.clear(); + } + CHECK; +} + +void SwCache::Delete(void const*const pOwner, sal_uInt16 const nIndex) +{ + INCREMENT( m_nDelete ); + if (SwCacheObj *const pObj = Get(pOwner, nIndex, false)) + DeleteObj(pObj); +} + +void SwCache::Delete( const void *pOwner ) +{ + INCREMENT( m_nDelete ); + SwCacheObj *pObj = Get( pOwner, false ); + if ( pObj ) + DeleteObj( pObj ); +} + +bool SwCache::Insert(SwCacheObj *const pNew, bool const isDuplicateOwnerAllowed) +{ + CHECK; + OSL_ENSURE( !pNew->GetPrev() && !pNew->GetNext(), "New but not new." ); + if (!isDuplicateOwnerAllowed) + { + for (auto const & rpObj : m_aCacheObjects) + { // check owner doesn't have a cache object yet; required for SwTextLine + assert(!rpObj || rpObj->GetOwner() != pNew->GetOwner()); + (void) rpObj; + } + } + + sal_uInt16 nPos; + if ( m_aCacheObjects.size() < m_nCurMax ) + { + // there is still space; insert directly + INCREMENT( m_nAppend ); + nPos = m_aCacheObjects.size(); + m_aCacheObjects.emplace_back(pNew); + } + else if ( !m_aFreePositions.empty() ) + { + // there are placeholders; use the last of those + INCREMENT( m_nInsertFree ); + const sal_uInt16 nFreePos = m_aFreePositions.size() - 1; + nPos = m_aFreePositions[ nFreePos ]; + m_aCacheObjects[nPos].reset(pNew); + m_aFreePositions.erase( m_aFreePositions.begin() + nFreePos ); + } + else + { + INCREMENT( m_nReplace ); + // the last of the LRU has to go + SwCacheObj *pObj = m_pLast; + + while ( pObj && pObj->IsLocked() ) + pObj = pObj->GetPrev(); + if ( !pObj ) + { + SAL_WARN("sw.core", "SwCache overflow."); + IncreaseMax(100); // embiggen & try again + return Insert(pNew, isDuplicateOwnerAllowed); + } + + nPos = pObj->GetCachePos(); + if ( pObj == m_pLast ) + { + m_pLast = pObj->GetPrev(); + assert(m_pLast); // must have capacity > 1 + } + if (pObj == m_pFirst) + { + if (pObj->GetNext()) + { + m_pFirst = pObj->GetNext(); + } + else + { + m_pFirst = pObj->GetPrev(); + } + assert(m_pFirst); // must have capacity > 1 + } + if (pObj == m_pRealFirst) + { + m_pRealFirst = pObj->GetNext(); + assert(m_pRealFirst); // must have capacity > 1 + } + if (pObj->GetPrev()) + { + pObj->GetPrev()->SetNext( pObj->GetNext() ); + } + if (pObj->GetNext()) + { + pObj->GetNext()->SetPrev( pObj->GetPrev() ); + } + m_aCacheObjects[nPos].reset(pNew); + } + pNew->SetCachePos( nPos ); + + if ( m_pFirst ) + { + if ( m_pFirst->GetPrev() ) + { m_pFirst->GetPrev()->SetNext( pNew ); + pNew->SetPrev( m_pFirst->GetPrev() ); + } + m_pFirst->SetPrev( pNew ); + pNew->SetNext( m_pFirst ); + } + else + { + assert(!m_pLast); + m_pLast = pNew; + } + if ( m_pFirst == m_pRealFirst ) + m_pRealFirst = pNew; + m_pFirst = pNew; + + CHECK; + return true; +} + +void SwCache::SetLRUOfst( const sal_uInt16 nOfst ) +{ + assert(nOfst < m_nCurMax); + if ( !m_pRealFirst || ((m_aCacheObjects.size() - m_aFreePositions.size()) < nOfst) ) + return; + + CHECK; + m_pFirst = m_pRealFirst; + for ( sal_uInt16 i = 0; i < m_aCacheObjects.size() && i < nOfst; ++i ) + { + if ( m_pFirst->GetNext() && m_pFirst->GetNext()->GetNext() ) + m_pFirst = m_pFirst->GetNext(); + else + break; + } + CHECK; +} + +SwCacheObj::SwCacheObj( const void *pOwn ) : + m_pNext( nullptr ), + m_pPrev( nullptr ), + m_nCachePos( USHRT_MAX ), + m_nLock( 0 ), + m_pOwner( pOwn ) +{ +} + +SwCacheObj::~SwCacheObj() +{ +} + +#ifdef DBG_UTIL +void SwCacheObj::Lock() +{ + assert( m_nLock < UCHAR_MAX && "Too many Locks for CacheObject." ); + ++m_nLock; +} + +void SwCacheObj::Unlock() +{ + assert( m_nLock && "No more Locks available." ); + --m_nLock; +} +#endif + +SwCacheAccess::~SwCacheAccess() +{ + if ( m_pObj ) + m_pObj->Unlock(); +} + +void SwCacheAccess::Get_(bool const isDuplicateOwnerAllowed) +{ + OSL_ENSURE( !m_pObj, "SwCacheAcces Obj already available." ); + + m_pObj = NewObj(); + if (!m_rCache.Insert(m_pObj, isDuplicateOwnerAllowed)) + { + delete m_pObj; + m_pObj = nullptr; + } + else + { + m_pObj->Lock(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/swrect.cxx b/sw/source/core/bastyp/swrect.cxx new file mode 100644 index 0000000000..97e9683a59 --- /dev/null +++ b/sw/source/core/bastyp/swrect.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <swrect.hxx> + +#include <libxml/xmlwriter.h> + +#ifdef DBG_UTIL +#include <tools/stream.hxx> +#endif + +SwRect::SwRect( const tools::Rectangle &rRect ) : + m_Point( rRect.Left(), rRect.Top() ) +{ + m_Size.setWidth( rRect.IsWidthEmpty() ? 0 : rRect.Right() - rRect.Left() + 1); + m_Size.setHeight(rRect.IsHeightEmpty() ? 0 : rRect.Bottom() - rRect.Top() + 1); +} + +SwRect& SwRect::Union( const SwRect& rRect ) +{ + if( rRect.IsEmpty()) + return *this; + if( IsEmpty()) + { + *this = rRect; + return *this; + } + if ( Top() > rRect.Top() ) + Top( rRect.Top() ); + if ( Left() > rRect.Left() ) + Left( rRect.Left() ); + tools::Long n = rRect.Right(); + if ( Right() < n ) + Right( n ); + n = rRect.Bottom(); + if ( Bottom() < n ) + Bottom( n ); + return *this; +} + +SwRect& SwRect::Intersection( const SwRect& rRect ) +{ + // any similarity between me and given element? + if ( Overlaps( rRect ) ) + { + // get smaller right and lower, and greater left and upper edge + if ( Left() < rRect.Left() ) + Left( rRect.Left() ); + if ( Top() < rRect.Top() ) + Top( rRect.Top() ); + tools::Long n = rRect.Right(); + if ( Right() > n ) + Right( n ); + n = rRect.Bottom(); + if ( Bottom() > n ) + Bottom( n ); + } + else + // Def.: if intersection is empty, set only SSize to 0 + SSize(0, 0); + + return *this; +} + +SwRect& SwRect::Intersection_( const SwRect& rOther ) +{ + // get smaller right and lower, and greater left and upper edge + auto left = std::max( m_Point.X(), rOther.m_Point.X() ); + auto top = std::max( m_Point.Y(), rOther.m_Point.Y() ); + tools::Long right = std::min( m_Point.X() + m_Size.Width(), rOther.m_Point.X() + rOther.m_Size.Width() ); + auto bottom = std::min( m_Point.Y() + m_Size.Height(), rOther.m_Point.Y() + rOther.m_Size.Height() ); + + *this = SwRect( left, top, right - left, bottom - top ); + + return *this; +} + +void SwRect::Justify() +{ + if ( m_Size.getHeight() < 0 ) + { + m_Point.setY(m_Point.getY() + m_Size.getHeight() + 1); + m_Size.setHeight(-m_Size.getHeight()); + } + if ( m_Size.getWidth() < 0 ) + { + m_Point.setX(m_Point.getX() + m_Size.getWidth() + 1); + m_Size.setWidth(-m_Size.getWidth()); + } +} + +// Similar to the inline methods, but we need the function pointers +void SwRect::Width_( const tools::Long nNew ) { m_Size.setWidth(nNew); } +void SwRect::Height_( const tools::Long nNew ) { m_Size.setHeight(nNew); } +void SwRect::Left_( const tools::Long nLeft ){ m_Size.AdjustWidth(m_Point.getX() - nLeft ); m_Point.setX(nLeft); } +void SwRect::Right_( const tools::Long nRight ){ m_Size.setWidth(nRight - m_Point.getX()); } +void SwRect::Top_( const tools::Long nTop ){ m_Size.AdjustHeight(m_Point.getY() - nTop ); m_Point.setY(nTop); } +void SwRect::Bottom_( const tools::Long nBottom ){ m_Size.setHeight(nBottom - m_Point.getY()); } + +tools::Long SwRect::Width_() const{ return m_Size.getWidth(); } +tools::Long SwRect::Height_() const{ return m_Size.getHeight(); } +tools::Long SwRect::Left_() const{ return m_Point.getX(); } +tools::Long SwRect::Right_() const{ return m_Point.getX() + m_Size.getWidth(); } +tools::Long SwRect::Top_() const{ return m_Point.getY(); } +tools::Long SwRect::Bottom_() const{ return m_Point.getY() + m_Size.getHeight(); } + +void SwRect::AddWidth( const tools::Long nAdd ) { m_Size.AdjustWidth(nAdd ); } +void SwRect::AddHeight( const tools::Long nAdd ) { m_Size.AdjustHeight(nAdd ); } +void SwRect::AddLeft( const tools::Long nAdd ){ m_Size.AdjustWidth(-nAdd ); m_Point.setX(m_Point.getX() + nAdd); } +void SwRect::SubLeft( const tools::Long nSub ){ m_Size.AdjustWidth(nSub ); m_Point.setX(m_Point.getX() - nSub); } +void SwRect::AddRight( const tools::Long nAdd ){ m_Size.AdjustWidth(nAdd ); } +void SwRect::AddTop( const tools::Long nAdd ){ m_Size.AdjustHeight(-nAdd ); m_Point.setY(m_Point.getY() + nAdd); } +void SwRect::SubTop( const tools::Long nSub ){ m_Size.AdjustHeight(nSub ); m_Point.setY(m_Point.getY() - nSub); } +void SwRect::AddBottom( const tools::Long nAdd ){ m_Size.AdjustHeight(nAdd ); } +void SwRect::SetPosX( const tools::Long nNew ){ m_Point.setX(nNew); } +void SwRect::SetPosY( const tools::Long nNew ){ m_Point.setY(nNew); } + +Size SwRect::Size_() const { return SSize(); } +Size SwRect::SwappedSize() const { return Size( m_Size.getHeight(), m_Size.getWidth() ); } + +tools::Long SwRect::GetLeftDistance( tools::Long nLimit ) const { return m_Point.getX() - nLimit; } +tools::Long SwRect::GetBottomDistance( tools::Long nLim ) const { return nLim - m_Point.getY() - m_Size.getHeight();} +tools::Long SwRect::GetTopDistance( tools::Long nLimit ) const { return m_Point.getY() - nLimit; } +tools::Long SwRect::GetRightDistance( tools::Long nLim ) const { return nLim - m_Point.getX() - m_Size.getWidth(); } + +bool SwRect::OverStepLeft( tools::Long nLimit ) const + { return nLimit > m_Point.getX() && m_Point.getX() + m_Size.getWidth() > nLimit; } +bool SwRect::OverStepBottom( tools::Long nLimit ) const + { return nLimit > m_Point.getY() && m_Point.getY() + m_Size.getHeight() > nLimit; } +bool SwRect::OverStepTop( tools::Long nLimit ) const + { return nLimit > m_Point.getY() && m_Point.getY() + m_Size.getHeight() > nLimit; } +bool SwRect::OverStepRight( tools::Long nLimit ) const + { return nLimit > m_Point.getX() && m_Point.getX() + m_Size.getWidth() > nLimit; } + +void SwRect::SetLeftAndWidth( tools::Long nLeft, tools::Long nNew ) +{ + m_Point.setX(nLeft); + m_Size.setWidth(nNew); +} +void SwRect::SetTopAndHeight( tools::Long nTop, tools::Long nNew ) +{ + m_Point.setY(nTop); + m_Size.setHeight(nNew); +} +void SwRect::SetRightAndWidth( tools::Long nRight, tools::Long nNew ) +{ + m_Point.setX(nRight - nNew); + m_Size.setWidth(nNew); +} +void SwRect::SetBottomAndHeight( tools::Long nBottom, tools::Long nNew ) +{ + m_Point.setY(nBottom - nNew); + m_Size.setHeight(nNew); +} +void SwRect::SetUpperLeftCorner( const Point& rNew ) + { m_Point = rNew; } +void SwRect::SetUpperRightCorner( const Point& rNew ) + { m_Point = Point(rNew.X() - m_Size.getWidth(), rNew.Y()); } +void SwRect::SetLowerLeftCorner( const Point& rNew ) + { m_Point = Point(rNew.X(), rNew.Y() - m_Size.getHeight()); } + +void SwRect::dumpAsXmlAttributes(xmlTextWriterPtr writer) const +{ + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("left"), "%li", Left()); + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("top"), "%li", Top()); + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("width"), "%li", Width()); + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("height"), "%li", Height()); + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("bottom"), "%li", Bottom()); + (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("right"), "%li", Right()); +} + +#ifdef DBG_UTIL +SvStream& WriteSwRect(SvStream &rStream, const SwRect &rRect) +{ + rStream.WriteChar('[').WriteInt32(rRect.Top()). + WriteChar('/').WriteInt32(rRect.Left()). + WriteChar(',').WriteInt32(rRect.Width()). + WriteChar('x').WriteInt32(rRect.Height()). + WriteOString("] "); + return rStream; +} +#endif + +static_assert( std::is_trivially_copyable< SwRect >::value ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/swregion.cxx b/sw/source/core/bastyp/swregion.cxx new file mode 100644 index 0000000000..b790bf1476 --- /dev/null +++ b/sw/source/core/bastyp/swregion.cxx @@ -0,0 +1,229 @@ +/* -*- 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 <swrect.hxx> +#include <swregion.hxx> +#include <swtypes.hxx> + +SwRegionRects::SwRegionRects( const SwRect &rStartRect, sal_uInt16 nInit ) : + m_aOrigin( rStartRect ) +{ + reserve(nInit); + push_back( m_aOrigin ); +} + +SwRegionRects::SwRegionRects( sal_uInt16 nInit ) : + m_aOrigin() +{ + reserve(nInit); +} + +// If <rDel> is true then this Rect will be overwritten by <rRect> at +// position <nPos>. Otherwise <rRect> is attached at the end. +inline void SwRegionRects::InsertRect( const SwRect &rRect, + const sal_uInt16 nPos, bool &rDel ) +{ + if( rDel ) + { + (*this)[nPos] = rRect; + rDel = false; + } + else + { + push_back( rRect ); + } +} + +void SwRegionRects::operator+=( const SwRect &rRect ) +{ + push_back( rRect ); +} + +/** Delete all overlaps of the Rects in array with the given <rRect> + + To do so, all existing rectangles have to be either split or deleted. + + @param rRect rectangle with the area that should be deleted +*/ +void SwRegionRects::operator-=( const SwRect &rRect ) +{ + sal_uInt16 nMax = size(); + for ( sal_uInt16 i = 0; i < nMax; ++i ) + { + if ( rRect.Overlaps( (*this)[i] ) ) + { + SwRect aTmp( (*this)[i] ); + SwRect aInter( aTmp ); + aInter.Intersection_( rRect ); + + // The first Rect that should be inserted takes position of i. + // This avoids one Delete() call. + bool bDel = true; + + // now split; only those rectangles should be left over that are in + // the "old" but not in the "new" area; hence, not in intersection. + tools::Long nTmp = aInter.Top() - aTmp.Top(); + if ( 0 < nTmp ) + { + const tools::Long nOldVal = aTmp.Height(); + aTmp.Height(nTmp); + InsertRect( aTmp, i, bDel ); + aTmp.Height( nOldVal ); + } + + aTmp.Top( aInter.Top() + aInter.Height() ); + if ( aTmp.Height() > 0 ) + InsertRect( aTmp, i, bDel ); + + aTmp.Top( aInter.Top() ); + aTmp.Bottom( aInter.Bottom() ); + nTmp = aInter.Left() - aTmp.Left(); + if ( 0 < nTmp ) + { + const tools::Long nOldVal = aTmp.Width(); + aTmp.Width( nTmp ); + InsertRect( aTmp, i, bDel ); + aTmp.Width( nOldVal ); + } + + aTmp.Left( aInter.Left() + aInter.Width() ); //+1? + if ( aTmp.Width() > 0 ) + InsertRect( aTmp, i, bDel ); + + if( bDel ) + { + erase( begin() + i ); + --i; // so that we don't forget any + --nMax; // so that we don't check too much + } + } + } +} + +/** invert current rectangle + + Change the shape, such that holes with be areas and areas are holes now. + + Note: If no rects were removed, then the shape is identical to the original + shape. As a result, it will be a NULL-SRectangle after inverting. +*/ +void SwRegionRects::Invert() +{ + // not very elegant and fast, but efficient: + // Create a new region and remove all areas that are left over. Afterwards + // copy all values. + + // To avoid unnecessary memory requirements, create a "useful" initial size: + // Number of rectangles in this area * 2 + 2 for the special case of a + // single hole (so four Rects in the inverse case). + SwRegionRects aInvRegion( m_aOrigin, size()*2+2 ); + for( const_iterator it = begin(); it != end(); ++it ) + aInvRegion -= *it; + + // overwrite all existing + swap( aInvRegion ); +} + +static inline SwTwips CalcArea( const SwRect &rRect ) +{ + return rRect.Width() * rRect.Height(); +} + +void SwRegionRects::LimitToOrigin() +{ + for (size_type i = 0; i < size(); ++i ) + (*this)[ i ].Intersection( m_aOrigin ); +} + +// combine all adjacent rectangles +void SwRegionRects::Compress( CompressType type ) +{ + bool bAgain; + do + { + sort( begin(), end(), []( const SwRect& l, const SwRect& r ) { return l.Top() < r.Top(); } ); + bAgain = false; + bool bRemoved = false; + for (size_type i = 0; i < size(); ++i ) + { + if( (*this)[i].IsEmpty()) + continue; + // Rectangles are sorted by Y axis, so check only pairs of rectangles + // that are possibly overlapping or adjacent or close enough to be grouped by the fuzzy + // code below. + const tools::Long nFuzzy = type == CompressFuzzy ? 1361513 : 0; + const tools::Long yMax = (*this)[i].Top() + (*this)[i].Height() + nFuzzy + / std::max<tools::Long>( 1, (*this)[i].Width()); + for(size_type j = i+1; j < size(); ++j) + { + if( (*this)[j].IsEmpty()) + continue; + if( (*this)[j].Top() > yMax ) + break; + // If one rectangle contains a second completely than the latter + // does not need to be stored and can be deleted + else if ( (*this)[i].Contains( (*this)[j] ) ) + { + (*this)[j].Width(0); // = erase(), see below + bRemoved = true; + } + else if ( (*this)[j].Contains( (*this)[i] ) ) + { + (*this)[i] = (*this)[j]; + (*this)[j].Width(0); + bRemoved = true; + bAgain = true; + } + else + { + // Merge adjacent rectangles (possibly overlapping), such rectangles can be + // detected by their merged areas being equal to the area of the union + // (which is obviously the case if they share one side, and using + // the nFuzzy extra allows merging also rectangles that do not quite cover + // the entire union but it's close enough). + + // For combining as much as possible (and for having less single + // paints), the area of the union can be a little bit larger: + // ( 9622 * 141.5 = 1361513 ~= a quarter (1/4) centimeter wider + // than the width of an A4 page + SwRect aUnion = (*this)[i].GetUnion( (*this)[j] ); + SwRect aInter = (*this)[i].GetIntersection( (*this)[j] ); + if ( CalcArea( (*this)[i] ) + CalcArea( (*this)[j] ) - CalcArea( aInter ) + + nFuzzy >= CalcArea( aUnion ) ) + { + (*this)[i] = aUnion; + (*this)[j].Width(0); + bRemoved = true; + bAgain = true; + } + } + } + } + // Instead of repeated erase() we Width(0) the elements, and now erase + // all empty elements just once. + if( bRemoved ) + resize( std::remove_if(begin(), end(), [](const SwRect& rect) { return rect.IsEmpty(); }) - begin()); + // Code paths setting bAgain alter elements of the vector, possibly breaking + // the Y-axis optimization, so run another pass just to make sure. The adjacent-rects + // merging code may possibly benefit from a repeated pass also if two pairs of merged + // rects might get merged again and this pass skipped that. + } while(bAgain); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/swtypes.cxx b/sw/source/core/bastyp/swtypes.cxx new file mode 100644 index 0000000000..507804363e --- /dev/null +++ b/sw/source/core/bastyp/swtypes.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <swtypes.hxx> + +#include <editeng/unolingu.hxx> +#include <vcl/svapp.hxx> +#include <vcl/graph.hxx> + +using namespace com::sun::star; + +Size GetGraphicSizeTwip(const Graphic& rGraphic, vcl::RenderContext* pOutDev) +{ + const MapMode aMapTwip(MapUnit::MapTwip); + Size aSize(rGraphic.GetPrefSize()); + + if (!aSize.getWidth() && !aSize.getHeight()) + { + const_cast<Graphic&>(rGraphic).makeAvailable(); + aSize = rGraphic.GetPrefSize(); + } + + if (MapUnit::MapPixel == rGraphic.GetPrefMapMode().GetMapUnit()) + { + if (!pOutDev) + pOutDev = Application::GetDefaultDevice(); + aSize = pOutDev->PixelToLogic(aSize, aMapTwip); + } + else + { + aSize = OutputDevice::LogicToLogic(aSize, rGraphic.GetPrefMapMode(), aMapTwip); + } + return aSize; +} + +uno::Reference<linguistic2::XSpellChecker1> GetSpellChecker() +{ + return LinguMgr::GetSpellChecker(); +} + +uno::Reference<linguistic2::XHyphenator> GetHyphenator() { return LinguMgr::GetHyphenator(); } + +uno::Reference<linguistic2::XThesaurus> GetThesaurus() { return LinguMgr::GetThesaurus(); } + +uno::Reference<linguistic2::XLinguProperties> GetLinguPropertySet() +{ + return LinguMgr::GetLinguPropertySet(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/bastyp/tabcol.cxx b/sw/source/core/bastyp/tabcol.cxx new file mode 100644 index 0000000000..4efc9d8ef8 --- /dev/null +++ b/sw/source/core/bastyp/tabcol.cxx @@ -0,0 +1,85 @@ +/* -*- 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 <tabcol.hxx> +#include <limits.h> + +SwTabCols::SwTabCols( sal_uInt16 nSize ) : + m_nLeftMin( 0 ), + m_nLeft( 0 ), + m_nRight( 0 ), + m_nRightMax( 0 ), + m_bLastRowAllowedToChange( true ) +{ + if ( nSize ) + m_aData.reserve( nSize ); +} + +SwTabCols::SwTabCols( const SwTabCols& rCpy ) : + m_nLeftMin( rCpy.GetLeftMin() ), + m_nLeft( rCpy.GetLeft() ), + m_nRight( rCpy.GetRight() ), + m_nRightMax( rCpy.GetRightMax() ), + m_bLastRowAllowedToChange( rCpy.IsLastRowAllowedToChange() ), + m_aData( rCpy.GetData() ) +{ +} + +SwTabCols &SwTabCols::operator=( const SwTabCols& rCpy ) +{ + m_nLeftMin = rCpy.GetLeftMin(); + m_nLeft = rCpy.GetLeft(); + m_nRight = rCpy.GetRight(); + m_nRightMax= rCpy.GetRightMax(); + m_bLastRowAllowedToChange = rCpy.IsLastRowAllowedToChange(); + + Remove( 0, Count() ); + m_aData = rCpy.GetData(); + + return *this; +} + +void SwTabCols::Insert( tools::Long nValue, tools::Long nMin, tools::Long nMax, + bool bValue, size_t nPos ) +{ + SwTabColsEntry aEntry; + aEntry.nPos = nValue; + aEntry.nMin = nMin; + aEntry.nMax = nMax; + aEntry.bHidden = bValue; + m_aData.insert( m_aData.begin() + nPos, aEntry ); +} + +void SwTabCols::Insert( tools::Long nValue, bool bValue, size_t nPos ) +{ + SwTabColsEntry aEntry; + aEntry.nPos = nValue; + aEntry.nMin = 0; + aEntry.nMax = LONG_MAX; + aEntry.bHidden = bValue; + m_aData.insert( m_aData.begin() + nPos, aEntry ); +} + +void SwTabCols::Remove( size_t nPos, size_t nCount ) +{ + SwTabColsEntries::iterator aStart = m_aData.begin() + nPos; + m_aData.erase( aStart, aStart + nCount ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |