2010-10-14 08:30:41 +02:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2011-03-31 10:05:04 +02:00
|
|
|
/*
|
|
|
|
* 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 .
|
|
|
|
*/
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
#include "porlay.hxx"
|
|
|
|
#include "itrform2.hxx"
|
|
|
|
#include "porglue.hxx"
|
2013-10-22 15:58:57 +03:00
|
|
|
#include "porexp.hxx"
|
2017-10-23 22:30:30 +02:00
|
|
|
#include <blink.hxx>
|
2013-10-22 15:58:57 +03:00
|
|
|
#include "redlnitr.hxx"
|
|
|
|
#include "porfly.hxx"
|
2017-10-06 19:07:48 +03:00
|
|
|
#include "porrst.hxx"
|
|
|
|
#include "pormulti.hxx"
|
|
|
|
#include "pordrop.hxx"
|
2001-02-20 09:27:05 +00:00
|
|
|
#include <breakit.hxx>
|
2009-08-17 14:12:14 +00:00
|
|
|
#include <unicode/uchar.h>
|
2012-06-21 17:39:01 +01:00
|
|
|
#include <com/sun/star/i18n/ScriptType.hpp>
|
2016-10-09 15:03:18 +08:00
|
|
|
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
|
2012-06-21 17:39:01 +01:00
|
|
|
#include <com/sun/star/i18n/CTLScriptType.hpp>
|
|
|
|
#include <com/sun/star/i18n/WordType.hpp>
|
2002-06-26 13:38:25 +00:00
|
|
|
#include <paratr.hxx>
|
2013-02-12 13:41:53 -05:00
|
|
|
#include <editeng/adjustitem.hxx>
|
2010-01-08 18:32:51 +01:00
|
|
|
#include <editeng/scripttypeitem.hxx>
|
|
|
|
#include <editeng/charhiddenitem.hxx>
|
2001-11-20 09:52:16 +00:00
|
|
|
#include <vcl/outdev.hxx>
|
2017-02-13 08:17:10 +02:00
|
|
|
#include <svl/asiancfg.hxx>
|
2013-02-12 13:41:53 -05:00
|
|
|
#include <editeng/blinkitem.hxx>
|
2004-02-26 14:32:29 +00:00
|
|
|
#include <tools/multisel.hxx>
|
2009-01-05 15:33:41 +00:00
|
|
|
#include <unotools/charclass.hxx>
|
2013-04-05 18:40:39 +02:00
|
|
|
#include <i18nlangtag/mslangid.hxx>
|
2004-02-26 14:32:29 +00:00
|
|
|
#include <charfmt.hxx>
|
|
|
|
#include <fchrfmt.hxx>
|
2013-10-22 15:58:57 +03:00
|
|
|
#include <docary.hxx>
|
|
|
|
#include <redline.hxx>
|
2004-09-08 15:12:39 +00:00
|
|
|
#include <section.hxx>
|
2015-03-18 13:58:25 +01:00
|
|
|
#include <calbck.hxx>
|
2006-08-14 15:41:13 +00:00
|
|
|
#include <IDocumentRedlineAccess.hxx>
|
|
|
|
#include <IDocumentSettingAccess.hxx>
|
2006-11-01 14:13:17 +00:00
|
|
|
#include <IDocumentContentOperations.hxx>
|
2006-08-14 15:41:13 +00:00
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
using namespace ::com::sun::star;
|
2007-09-27 08:17:13 +00:00
|
|
|
using namespace i18n::ScriptType;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2002-03-21 08:19:43 +00:00
|
|
|
#include <unicode/ubidi.h>
|
2012-03-07 23:50:19 +00:00
|
|
|
#include <i18nutil/scripttypedetector.hxx>
|
|
|
|
#include <i18nutil/unicode.hxx>
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2011-08-31 23:58:51 +02:00
|
|
|
#define IS_JOINING_GROUP(c, g) ( u_getIntPropertyValue( (c), UCHAR_JOINING_GROUP ) == U_JG_##g )
|
|
|
|
#define isAinChar(c) IS_JOINING_GROUP((c), AIN)
|
|
|
|
#define isAlefChar(c) IS_JOINING_GROUP((c), ALEF)
|
|
|
|
#define isDalChar(c) IS_JOINING_GROUP((c), DAL)
|
2016-11-07 09:28:11 +01:00
|
|
|
#if U_ICU_VERSION_MAJOR_NUM >= 58
|
2016-11-07 00:41:44 +02:00
|
|
|
#define isFehChar(c) (IS_JOINING_GROUP((c), FEH) || IS_JOINING_GROUP((c), AFRICAN_FEH))
|
2016-11-07 09:28:11 +01:00
|
|
|
#else
|
|
|
|
#define isFehChar(c) IS_JOINING_GROUP((c), FEH)
|
|
|
|
#endif
|
2011-08-31 23:58:51 +02:00
|
|
|
#define isGafChar(c) IS_JOINING_GROUP((c), GAF)
|
2016-11-06 22:06:44 +02:00
|
|
|
#define isHehChar(c) IS_JOINING_GROUP((c), HEH)
|
2011-08-31 23:58:51 +02:00
|
|
|
#define isKafChar(c) IS_JOINING_GROUP((c), KAF)
|
|
|
|
#define isLamChar(c) IS_JOINING_GROUP((c), LAM)
|
2016-11-07 09:28:11 +01:00
|
|
|
#if U_ICU_VERSION_MAJOR_NUM >= 58
|
2016-11-07 00:41:44 +02:00
|
|
|
#define isQafChar(c) (IS_JOINING_GROUP((c), QAF) || IS_JOINING_GROUP((c), AFRICAN_QAF))
|
2016-11-07 09:28:11 +01:00
|
|
|
#else
|
|
|
|
#define isQafChar(c) IS_JOINING_GROUP((c), QAF)
|
|
|
|
#endif
|
2011-08-31 23:58:51 +02:00
|
|
|
#define isRehChar(c) IS_JOINING_GROUP((c), REH)
|
2016-11-06 23:07:31 +02:00
|
|
|
#define isTahChar(c) IS_JOINING_GROUP((c), TAH)
|
2011-08-31 23:58:51 +02:00
|
|
|
#define isTehMarbutaChar(c) IS_JOINING_GROUP((c), TEH_MARBUTA)
|
|
|
|
#define isWawChar(c) IS_JOINING_GROUP((c), WAW)
|
|
|
|
#define isSeenOrSadChar(c) (IS_JOINING_GROUP((c), SAD) || IS_JOINING_GROUP((c), SEEN))
|
2008-06-06 07:16:21 +00:00
|
|
|
|
2016-11-07 00:41:44 +02:00
|
|
|
// Beh and charters that behave like Beh in medial form.
|
|
|
|
bool isBehChar(sal_Unicode cCh)
|
|
|
|
{
|
|
|
|
bool bRet = false;
|
|
|
|
switch (u_getIntPropertyValue(cCh, UCHAR_JOINING_GROUP))
|
|
|
|
{
|
|
|
|
case U_JG_BEH:
|
|
|
|
case U_JG_NOON:
|
2016-11-07 10:22:53 +01:00
|
|
|
#if U_ICU_VERSION_MAJOR_NUM >= 58
|
2016-11-07 00:41:44 +02:00
|
|
|
case U_JG_AFRICAN_NOON:
|
2016-11-07 10:22:53 +01:00
|
|
|
#endif
|
2016-11-07 00:41:44 +02:00
|
|
|
case U_JG_NYA:
|
|
|
|
case U_JG_YEH:
|
|
|
|
case U_JG_FARSI_YEH:
|
|
|
|
case U_JG_BURUSHASKI_YEH_BARREE:
|
|
|
|
bRet = true;
|
2016-11-07 06:53:38 +02:00
|
|
|
break;
|
2016-11-07 00:41:44 +02:00
|
|
|
default:
|
|
|
|
bRet = false;
|
2016-11-07 06:53:38 +02:00
|
|
|
break;
|
2016-11-07 00:41:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Yeh and charters that behave like Yeh in final form.
|
|
|
|
bool isYehChar(sal_Unicode cCh)
|
|
|
|
{
|
|
|
|
bool bRet = false;
|
|
|
|
switch (u_getIntPropertyValue(cCh, UCHAR_JOINING_GROUP))
|
|
|
|
{
|
|
|
|
case U_JG_YEH:
|
|
|
|
case U_JG_FARSI_YEH:
|
|
|
|
case U_JG_YEH_BARREE:
|
|
|
|
case U_JG_BURUSHASKI_YEH_BARREE:
|
|
|
|
case U_JG_YEH_WITH_TAIL:
|
|
|
|
bRet = true;
|
2016-11-07 06:53:38 +02:00
|
|
|
break;
|
2016-11-07 00:41:44 +02:00
|
|
|
default:
|
|
|
|
bRet = false;
|
2016-11-07 06:53:38 +02:00
|
|
|
break;
|
2016-11-07 00:41:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
2012-12-06 20:59:29 +09:00
|
|
|
bool isTransparentChar ( sal_Unicode cCh )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2011-08-31 23:58:51 +02:00
|
|
|
return u_getIntPropertyValue( cCh, UCHAR_JOINING_TYPE ) == U_JT_TRANSPARENT;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2008-06-06 07:16:21 +00:00
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Checks if cCh + cNectCh builds a ligature (used for Kashidas)
|
2012-12-06 20:59:29 +09:00
|
|
|
static bool lcl_IsLigature( sal_Unicode cCh, sal_Unicode cNextCh )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2002-04-10 05:43:43 +00:00
|
|
|
// Lam + Alef
|
2009-02-16 09:03:54 +00:00
|
|
|
return ( isLamChar ( cCh ) && isAlefChar ( cNextCh ));
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Checks if cCh is connectable to cPrevCh (used for Kashidas)
|
2012-12-06 20:59:29 +09:00
|
|
|
static bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2011-08-31 23:58:51 +02:00
|
|
|
const int32_t nJoiningType = u_getIntPropertyValue( cPrevCh, UCHAR_JOINING_TYPE );
|
2012-12-06 20:59:29 +09:00
|
|
|
bool bRet = nJoiningType != U_JT_RIGHT_JOINING && nJoiningType != U_JT_NON_JOINING;
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// check for ligatures cPrevChar + cChar
|
2009-02-16 09:03:54 +00:00
|
|
|
if( bRet )
|
|
|
|
bRet = !lcl_IsLigature( cPrevCh, cCh );
|
2011-08-31 23:58:51 +02:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
return bRet;
|
|
|
|
}
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
static bool lcl_HasStrongLTR ( const OUString& rText, sal_Int32 nStart, sal_Int32 nEnd )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2013-10-28 12:21:40 +02:00
|
|
|
for( sal_Int32 nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const UCharDirection nCharDir = u_charDirection ( rText[ nCharIdx ] );
|
2009-01-05 15:33:41 +00:00
|
|
|
if ( nCharDir == U_LEFT_TO_RIGHT ||
|
|
|
|
nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
|
|
|
|
nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// class SwLineLayout: This is the layout of a single line, which is made
|
2016-01-09 22:55:28 +01:00
|
|
|
// up of its dimension, the character count and the word spacing in the line.
|
2014-04-18 17:02:13 -04:00
|
|
|
// Line objects are managed in an own pool, in order to store them continuously
|
|
|
|
// in memory so that they are paged out together and don't fragment memory.
|
2000-09-18 23:08:29 +00:00
|
|
|
SwLineLayout::~SwLineLayout()
|
|
|
|
{
|
|
|
|
Truncate();
|
2015-11-14 09:07:13 +01:00
|
|
|
delete m_pNext;
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pBlink )
|
|
|
|
pBlink->Delete( this );
|
2015-11-14 09:07:13 +01:00
|
|
|
delete m_pLLSpaceAdd;
|
|
|
|
delete m_pKanaComp;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SwLinePortion *SwLineLayout::Insert( SwLinePortion *pIns )
|
|
|
|
{
|
2016-04-29 13:15:58 +02:00
|
|
|
// First attribute change: copy mass and length from *pIns into the first
|
|
|
|
// text portion
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pPortion )
|
|
|
|
{
|
|
|
|
if( GetLen() )
|
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
pPortion = SwTextPortion::CopyLinePortion(*this);
|
2000-09-18 23:08:29 +00:00
|
|
|
if( IsBlinking() && pBlink )
|
|
|
|
{
|
2014-02-09 21:04:06 +01:00
|
|
|
SetBlinking( false );
|
2000-09-18 23:08:29 +00:00
|
|
|
pBlink->Replace( this, pPortion );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetPortion( pIns );
|
|
|
|
return pIns;
|
|
|
|
}
|
|
|
|
}
|
2012-06-05 13:57:00 +02:00
|
|
|
// Call with scope or we'll end up with recursion!
|
2000-09-18 23:08:29 +00:00
|
|
|
return pPortion->SwLinePortion::Insert( pIns );
|
|
|
|
}
|
|
|
|
|
|
|
|
SwLinePortion *SwLineLayout::Append( SwLinePortion *pIns )
|
|
|
|
{
|
2012-06-05 13:57:00 +02:00
|
|
|
// First attribute change: copy mass and length from *pIns into the first
|
|
|
|
// text portion
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pPortion )
|
2015-05-20 13:05:49 +02:00
|
|
|
pPortion = SwTextPortion::CopyLinePortion(*this);
|
2012-06-05 13:57:00 +02:00
|
|
|
// Call with scope or we'll end up with recursion!
|
2000-09-18 23:08:29 +00:00
|
|
|
return pPortion->SwLinePortion::Append( pIns );
|
|
|
|
}
|
|
|
|
|
2012-06-05 13:57:00 +02:00
|
|
|
// For special treatment of empty lines
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
bool SwLineLayout::Format( SwTextFormatInfo &rInf )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
if( GetLen() )
|
2015-05-20 13:05:49 +02:00
|
|
|
return SwTextPortion::Format( rInf );
|
2014-01-26 18:20:06 +01:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
Height( rInf.GetTextHeight() );
|
2014-02-07 23:49:13 +01:00
|
|
|
return true;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// We collect all FlyPortions at the beginning of the line and make that a
|
|
|
|
// MarginPortion.
|
2000-09-18 23:08:29 +00:00
|
|
|
SwMarginPortion *SwLineLayout::CalcLeftMargin()
|
|
|
|
{
|
|
|
|
SwMarginPortion *pLeft = (GetPortion() && GetPortion()->IsMarginPortion()) ?
|
2015-11-10 10:25:48 +01:00
|
|
|
static_cast<SwMarginPortion *>(GetPortion()) : nullptr;
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !GetPortion() )
|
2015-05-20 13:05:49 +02:00
|
|
|
SetPortion(SwTextPortion::CopyLinePortion(*this));
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pLeft )
|
|
|
|
{
|
2016-09-08 09:23:17 +02:00
|
|
|
pLeft = new SwMarginPortion;
|
2000-09-18 23:08:29 +00:00
|
|
|
pLeft->SetPortion( GetPortion() );
|
|
|
|
SetPortion( pLeft );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pLeft->Height( 0 );
|
|
|
|
pLeft->Width( 0 );
|
|
|
|
pLeft->SetLen( 0 );
|
|
|
|
pLeft->SetAscent( 0 );
|
2015-11-10 10:25:48 +01:00
|
|
|
pLeft->SetPortion( nullptr );
|
2000-09-18 23:08:29 +00:00
|
|
|
pLeft->SetFixWidth(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SwLinePortion *pPos = pLeft->GetPortion();
|
|
|
|
while( pPos )
|
|
|
|
{
|
|
|
|
if( pPos->IsFlyPortion() )
|
|
|
|
{
|
2012-06-05 13:57:00 +02:00
|
|
|
// The FlyPortion get's sucked out ...
|
2014-11-21 14:36:31 +02:00
|
|
|
pLeft->Join( static_cast<SwGluePortion*>(pPos) );
|
2000-09-18 23:08:29 +00:00
|
|
|
pPos = pLeft->GetPortion();
|
2011-07-13 15:55:53 +01:00
|
|
|
if( GetpKanaComp() && !GetKanaComp().empty() )
|
|
|
|
GetKanaComp().pop_front();
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
else
|
2015-11-10 10:25:48 +01:00
|
|
|
pPos = nullptr;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
return pLeft;
|
|
|
|
}
|
|
|
|
|
2005-04-18 13:37:24 +00:00
|
|
|
void SwLineLayout::InitSpaceAdd()
|
|
|
|
{
|
2015-11-14 09:07:13 +01:00
|
|
|
if ( !m_pLLSpaceAdd )
|
2005-04-18 13:37:24 +00:00
|
|
|
CreateSpaceAdd();
|
|
|
|
else
|
|
|
|
SetLLSpaceAdd( 0, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwLineLayout::CreateSpaceAdd( const long nInit )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2015-11-14 09:07:13 +01:00
|
|
|
m_pLLSpaceAdd = new std::vector<long>;
|
2005-04-18 13:37:24 +00:00
|
|
|
SetLLSpaceAdd( nInit, 0 );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Returns true if there are only blanks in [nStt, nEnd[
|
2015-05-20 13:05:49 +02:00
|
|
|
static bool lcl_HasOnlyBlanks( const OUString& rText, sal_Int32 nStt, sal_Int32 nEnd )
|
2006-03-21 14:40:07 +00:00
|
|
|
{
|
|
|
|
bool bBlankOnly = true;
|
|
|
|
while ( nStt < nEnd )
|
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const sal_Unicode cChar = rText[ nStt++ ];
|
2006-03-21 14:40:07 +00:00
|
|
|
if ( ' ' != cChar && 0x3000 != cChar )
|
|
|
|
{
|
|
|
|
bBlankOnly = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bBlankOnly;
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Swapped out from FormatLine()
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwLineLayout::CalcLine( SwTextFormatter &rLine, SwTextFormatInfo &rInf )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2014-07-22 17:14:17 +02:00
|
|
|
const sal_uInt16 nLineWidth = rInf.RealWidth();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2014-07-22 17:14:17 +02:00
|
|
|
sal_uInt16 nFlyAscent = 0;
|
|
|
|
sal_uInt16 nFlyHeight = 0;
|
|
|
|
sal_uInt16 nFlyDescent = 0;
|
2012-12-06 20:59:29 +09:00
|
|
|
bool bOnlyPostIts = true;
|
2014-02-09 21:04:06 +01:00
|
|
|
SetHanging( false );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2014-02-15 11:40:16 +01:00
|
|
|
bool bTmpDummy = !GetLen();
|
2015-11-10 10:25:48 +01:00
|
|
|
SwFlyCntPortion* pFlyCnt = nullptr;
|
2000-09-18 23:08:29 +00:00
|
|
|
if( bTmpDummy )
|
|
|
|
{
|
|
|
|
nFlyAscent = 0;
|
|
|
|
nFlyHeight = 0;
|
|
|
|
nFlyDescent = 0;
|
|
|
|
}
|
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i3952#
|
2006-03-21 14:40:07 +00:00
|
|
|
const bool bIgnoreBlanksAndTabsForLineHeightCalculation =
|
2015-11-25 06:03:10 -05:00
|
|
|
rInf.GetTextFrame()->GetNode()->getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION);
|
2006-03-21 14:40:07 +00:00
|
|
|
|
|
|
|
bool bHasBlankPortion = false;
|
|
|
|
bool bHasOnlyBlankPortions = true;
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pPortion )
|
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
SetContent( false );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pPortion->IsBreakPortion() )
|
|
|
|
{
|
|
|
|
SetLen( pPortion->GetLen() );
|
|
|
|
if( GetLen() )
|
2014-02-15 11:40:16 +01:00
|
|
|
bTmpDummy = false;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const sal_uInt16 nLineHeight = Height();
|
2000-09-18 23:08:29 +00:00
|
|
|
Init( GetPortion() );
|
|
|
|
SwLinePortion *pPos = pPortion;
|
|
|
|
SwLinePortion *pLast = this;
|
2014-07-22 17:14:17 +02:00
|
|
|
sal_uInt16 nMaxDescent = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2012-06-05 13:57:00 +02:00
|
|
|
// A group is a segment in the portion chain of pCurr or a fixed
|
|
|
|
// portion spanning to the end or the next fixed portion
|
2000-09-18 23:08:29 +00:00
|
|
|
while( pPos )
|
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( POR_LIN == pPos->GetWhichPor(),
|
|
|
|
"sw.core", "SwLineLayout::CalcLine: don't use SwLinePortions !" );
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2015-11-25 06:03:10 -05:00
|
|
|
// Null portions are eliminated. They can form if two FlyFrames
|
2012-06-05 13:57:00 +02:00
|
|
|
// overlap.
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pPos->Compress() )
|
|
|
|
{
|
2012-06-05 13:57:00 +02:00
|
|
|
// Only take over Height and Ascent if the rest of the line
|
|
|
|
// is empty.
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pPos->GetPortion() )
|
|
|
|
{
|
|
|
|
if( !Height() )
|
|
|
|
Height( pPos->Height() );
|
|
|
|
if( !GetAscent() )
|
|
|
|
SetAscent( pPos->GetAscent() );
|
|
|
|
}
|
|
|
|
delete pLast->Cut( pPos );
|
|
|
|
pPos = pLast->GetPortion();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nPorSttIdx = rInf.GetLineStart() + nLineLength;
|
2014-01-26 19:17:41 +01:00
|
|
|
nLineLength += pPos->GetLen();
|
2006-03-21 14:40:07 +00:00
|
|
|
AddPrtWidth( pPos->Width() );
|
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i3952#
|
2006-03-21 14:40:07 +00:00
|
|
|
if ( bIgnoreBlanksAndTabsForLineHeightCalculation )
|
|
|
|
{
|
|
|
|
if ( pPos->InTabGrp() || pPos->IsHolePortion() ||
|
|
|
|
( pPos->IsTextPortion() &&
|
2015-05-20 13:05:49 +02:00
|
|
|
lcl_HasOnlyBlanks( rInf.GetText(), nPorSttIdx, nPorSttIdx + pPos->GetLen() ) ) )
|
2006-03-21 14:40:07 +00:00
|
|
|
{
|
|
|
|
pLast = pPos;
|
|
|
|
pPos = pPos->GetPortion();
|
|
|
|
bHasBlankPortion = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-01 20:17:41 +02:00
|
|
|
// Ignore drop portion height
|
|
|
|
if( pPos->IsDropPortion() && static_cast<SwDropPortion*>(pPos)->GetLines() > 1)
|
|
|
|
{
|
|
|
|
pLast = pPos;
|
|
|
|
pPos = pPos->GetPortion();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-03-21 14:40:07 +00:00
|
|
|
bHasOnlyBlankPortions = false;
|
|
|
|
|
2012-06-05 13:57:00 +02:00
|
|
|
// We had an attribute change: Sum up/build maxima of length and mass
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2014-07-22 17:14:17 +02:00
|
|
|
sal_uInt16 nPosHeight = pPos->Height();
|
|
|
|
sal_uInt16 nPosAscent = pPos->GetAscent();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( nPosHeight < nPosAscent,
|
|
|
|
"sw.core", "SwLineLayout::CalcLine: bad ascent or height" );
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2000-11-21 10:29:48 +00:00
|
|
|
if( pPos->IsHangingPortion() )
|
|
|
|
{
|
2014-02-09 21:04:06 +01:00
|
|
|
SetHanging();
|
|
|
|
rInf.GetParaPortion()->SetMargin();
|
2000-11-21 10:29:48 +00:00
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2012-06-05 13:57:00 +02:00
|
|
|
// To prevent that a paragraph-end-character does not change
|
|
|
|
// the line height through a Descent and thus causing the line
|
|
|
|
// to reformat.
|
2000-09-18 23:08:29 +00:00
|
|
|
if ( !pPos->IsBreakPortion() || !Height() )
|
|
|
|
{
|
2012-12-06 20:59:29 +09:00
|
|
|
if (!pPos->IsPostItsPortion()) bOnlyPostIts = false;
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
if( bTmpDummy && !nLineLength )
|
|
|
|
{
|
|
|
|
if( pPos->IsFlyPortion() )
|
|
|
|
{
|
|
|
|
if( nFlyHeight < nPosHeight )
|
|
|
|
nFlyHeight = nPosHeight;
|
|
|
|
if( nFlyAscent < nPosAscent )
|
|
|
|
nFlyAscent = nPosAscent;
|
|
|
|
if( nFlyDescent < nPosHeight - nPosAscent )
|
|
|
|
nFlyDescent = nPosHeight - nPosAscent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( pPos->InNumberGrp() )
|
|
|
|
{
|
2014-07-22 17:14:17 +02:00
|
|
|
sal_uInt16 nTmp = rInf.GetFont()->GetAscent(
|
2003-10-15 08:56:56 +00:00
|
|
|
rInf.GetVsh(), *rInf.GetOut() );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( nTmp > nPosAscent )
|
|
|
|
{
|
|
|
|
nPosHeight += nTmp - nPosAscent;
|
|
|
|
nPosAscent = nTmp;
|
|
|
|
}
|
|
|
|
nTmp = rInf.GetFont()->GetHeight( rInf.GetVsh(),
|
2003-10-15 08:56:56 +00:00
|
|
|
*rInf.GetOut() );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( nTmp > nPosHeight )
|
|
|
|
nPosHeight = nTmp;
|
|
|
|
}
|
|
|
|
Height( nPosHeight );
|
|
|
|
nAscent = nPosAscent;
|
|
|
|
nMaxDescent = nPosHeight - nPosAscent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !pPos->IsFlyPortion() )
|
|
|
|
{
|
|
|
|
if( Height() < nPosHeight )
|
2012-06-08 12:50:59 +02:00
|
|
|
{
|
|
|
|
// Height is set to 0 when Init() is called.
|
2012-06-08 14:07:13 +02:00
|
|
|
if (bIgnoreBlanksAndTabsForLineHeightCalculation && pPos->GetWhichPor() == POR_FLYCNT)
|
2012-06-08 12:50:59 +02:00
|
|
|
// Compat flag set: take the line height, if it's larger.
|
|
|
|
Height(std::max(nPosHeight, nLineHeight));
|
|
|
|
else
|
|
|
|
// Just care about the portion height.
|
|
|
|
Height(nPosHeight);
|
|
|
|
}
|
2016-12-22 02:44:13 +01:00
|
|
|
SwFlyCntPortion* pAsFly(nullptr);
|
|
|
|
if(pPos->IsFlyCntPortion())
|
|
|
|
pAsFly = static_cast<SwFlyCntPortion*>(pPos);
|
|
|
|
if( pAsFly || ( pPos->IsMultiPortion()
|
2015-05-20 13:05:49 +02:00
|
|
|
&& static_cast<SwMultiPortion*>(pPos)->HasFlyInContent() ) )
|
2000-09-18 23:08:29 +00:00
|
|
|
rLine.SetFlyInCntBase();
|
2016-12-22 02:44:13 +01:00
|
|
|
if(pAsFly && pAsFly->GetAlign() != sw::LineAlign::NONE)
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2016-12-22 02:44:13 +01:00
|
|
|
pAsFly->SetMax(false);
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pFlyCnt || pPos->Height() > pFlyCnt->Height() )
|
2016-12-22 02:44:13 +01:00
|
|
|
pFlyCnt = pAsFly;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( nAscent < nPosAscent )
|
|
|
|
nAscent = nPosAscent;
|
|
|
|
if( nMaxDescent < nPosHeight - nPosAscent )
|
|
|
|
nMaxDescent = nPosHeight - nPosAscent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( pPos->GetLen() )
|
2014-02-15 11:40:16 +01:00
|
|
|
bTmpDummy = false;
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
if( !HasContent() && !pPos->InNumberGrp() )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
if ( pPos->InExpGrp() )
|
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
OUString aText;
|
|
|
|
if( pPos->GetExpText( rInf, aText ) && !aText.isEmpty() )
|
|
|
|
SetContent();
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2015-05-20 13:05:49 +02:00
|
|
|
else if( ( pPos->InTextGrp() || pPos->IsMultiPortion() ) &&
|
2001-11-19 10:14:15 +00:00
|
|
|
pPos->GetLen() )
|
2015-05-20 13:05:49 +02:00
|
|
|
SetContent();
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
bTmpDummy &= !HasContent() && ( !pPos->Width() || pPos->IsFlyPortion() );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
pLast = pPos;
|
|
|
|
pPos = pPos->GetPortion();
|
|
|
|
}
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pFlyCnt )
|
|
|
|
{
|
|
|
|
if( pFlyCnt->Height() == Height() )
|
|
|
|
{
|
2014-02-08 01:28:46 +01:00
|
|
|
pFlyCnt->SetMax( true );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( Height() > nMaxDescent + nAscent )
|
|
|
|
{
|
2016-12-22 02:44:13 +01:00
|
|
|
if( sw::LineAlign::BOTTOM == pFlyCnt->GetAlign() )
|
2000-09-18 23:08:29 +00:00
|
|
|
nAscent = Height() - nMaxDescent;
|
2016-12-22 02:44:13 +01:00
|
|
|
else if( sw::LineAlign::CENTER == pFlyCnt->GetAlign() )
|
2000-09-18 23:08:29 +00:00
|
|
|
nAscent = ( Height() + nAscent - nMaxDescent ) / 2;
|
|
|
|
}
|
|
|
|
pFlyCnt->SetAscent( nAscent );
|
|
|
|
}
|
|
|
|
}
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
if( bTmpDummy && nFlyHeight )
|
|
|
|
{
|
|
|
|
nAscent = nFlyAscent;
|
|
|
|
if( nFlyDescent > nFlyHeight - nFlyAscent )
|
|
|
|
Height( nFlyHeight + nFlyDescent );
|
|
|
|
else
|
|
|
|
Height( nFlyHeight );
|
|
|
|
}
|
|
|
|
else if( nMaxDescent > Height() - nAscent )
|
|
|
|
Height( nMaxDescent + nAscent );
|
2006-03-21 14:40:07 +00:00
|
|
|
|
|
|
|
if( bOnlyPostIts && !( bHasBlankPortion && bHasOnlyBlankPortions ) )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2003-10-15 08:56:56 +00:00
|
|
|
Height( rInf.GetFont()->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
|
|
|
|
nAscent = rInf.GetFont()->GetAscent( rInf.GetVsh(), *rInf.GetOut() );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2006-03-21 14:40:07 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
SetContent( !bTmpDummy );
|
2006-03-21 14:40:07 +00:00
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i3952#
|
2006-03-21 14:40:07 +00:00
|
|
|
if ( bIgnoreBlanksAndTabsForLineHeightCalculation &&
|
2015-05-20 13:05:49 +02:00
|
|
|
lcl_HasOnlyBlanks( rInf.GetText(), rInf.GetLineStart(), rInf.GetLineStart() + GetLen() ) )
|
2006-03-21 14:40:07 +00:00
|
|
|
{
|
|
|
|
bHasBlankPortion = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i3952#
|
2006-03-21 14:40:07 +00:00
|
|
|
if ( bHasBlankPortion && bHasOnlyBlankPortions )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 nTmpAscent = GetAscent();
|
|
|
|
sal_uInt16 nTmpHeight = Height();
|
2006-03-21 14:40:07 +00:00
|
|
|
rLine.GetAttrHandler().GetDefaultAscentAndHeight( rInf.GetVsh(), *rInf.GetOut(), nTmpAscent, nTmpHeight );
|
|
|
|
SetAscent( nTmpAscent );
|
|
|
|
Height( nTmpHeight );
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
// Robust:
|
|
|
|
if( nLineWidth < Width() )
|
|
|
|
Width( nLineWidth );
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( nLineWidth < Width(), "sw.core", "SwLineLayout::CalcLine: line is bursting" );
|
2000-09-18 23:08:29 +00:00
|
|
|
SetDummy( bTmpDummy );
|
|
|
|
SetRedline( rLine.GetRedln() &&
|
|
|
|
rLine.GetRedln()->CheckLine( rLine.GetStart(), rLine.GetEnd() ) );
|
|
|
|
}
|
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i47162# - add optional parameter <_bNoFlyCntPorAndLinePor>
|
2005-09-28 10:19:35 +00:00
|
|
|
// to control, if the fly content portions and line portion are considered.
|
2004-02-26 16:00:32 +00:00
|
|
|
void SwLineLayout::MaxAscentDescent( SwTwips& _orAscent,
|
|
|
|
SwTwips& _orDescent,
|
|
|
|
SwTwips& _orObjAscent,
|
|
|
|
SwTwips& _orObjDescent,
|
2005-09-28 10:19:35 +00:00
|
|
|
const SwLinePortion* _pDontConsiderPortion,
|
|
|
|
const bool _bNoFlyCntPorAndLinePor ) const
|
2004-02-26 16:00:32 +00:00
|
|
|
{
|
|
|
|
_orAscent = 0;
|
|
|
|
_orDescent = 0;
|
|
|
|
_orObjAscent = 0;
|
|
|
|
_orObjDescent = 0;
|
|
|
|
|
2007-09-27 08:17:13 +00:00
|
|
|
const SwLinePortion* pTmpPortion = this;
|
|
|
|
if ( !pTmpPortion->GetLen() && pTmpPortion->GetPortion() )
|
2004-02-26 16:00:32 +00:00
|
|
|
{
|
2007-09-27 08:17:13 +00:00
|
|
|
pTmpPortion = pTmpPortion->GetPortion();
|
2004-02-26 16:00:32 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 08:17:13 +00:00
|
|
|
while ( pTmpPortion )
|
2004-02-26 16:00:32 +00:00
|
|
|
{
|
2007-09-27 08:17:13 +00:00
|
|
|
if ( !pTmpPortion->IsBreakPortion() && !pTmpPortion->IsFlyPortion() &&
|
2005-09-28 10:19:35 +00:00
|
|
|
( !_bNoFlyCntPorAndLinePor ||
|
2007-09-27 08:17:13 +00:00
|
|
|
( !pTmpPortion->IsFlyCntPortion() &&
|
|
|
|
!(pTmpPortion == this && pTmpPortion->GetPortion() ) ) ) )
|
2004-02-26 16:00:32 +00:00
|
|
|
{
|
2007-09-27 08:17:13 +00:00
|
|
|
SwTwips nPortionAsc = static_cast<SwTwips>(pTmpPortion->GetAscent());
|
|
|
|
SwTwips nPortionDesc = static_cast<SwTwips>(pTmpPortion->Height()) -
|
2004-02-26 16:00:32 +00:00
|
|
|
nPortionAsc;
|
|
|
|
|
2014-02-15 11:40:16 +01:00
|
|
|
const bool bFlyCmp = pTmpPortion->IsFlyCntPortion() ?
|
2007-09-27 08:17:13 +00:00
|
|
|
static_cast<const SwFlyCntPortion*>(pTmpPortion)->IsMax() :
|
|
|
|
!( pTmpPortion == _pDontConsiderPortion );
|
|
|
|
|
2004-02-26 16:00:32 +00:00
|
|
|
if ( bFlyCmp )
|
|
|
|
{
|
2013-04-11 00:21:40 -03:00
|
|
|
_orObjAscent = std::max( _orObjAscent, nPortionAsc );
|
|
|
|
_orObjDescent = std::max( _orObjDescent, nPortionDesc );
|
2004-02-26 16:00:32 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 08:17:13 +00:00
|
|
|
if ( !pTmpPortion->IsFlyCntPortion() && !pTmpPortion->IsGrfNumPortion() )
|
2004-02-26 16:00:32 +00:00
|
|
|
{
|
2013-04-11 00:21:40 -03:00
|
|
|
_orAscent = std::max( _orAscent, nPortionAsc );
|
|
|
|
_orDescent = std::max( _orDescent, nPortionDesc );
|
2004-02-26 16:00:32 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-27 08:17:13 +00:00
|
|
|
pTmpPortion = pTmpPortion->GetPortion();
|
2004-02-26 16:00:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 12:13:26 +01:00
|
|
|
void SwLineLayout::ResetFlags()
|
|
|
|
{
|
2017-06-30 13:08:51 +02:00
|
|
|
m_bFormatAdj = m_bDummy = m_bEndHyph = m_bMidHyph = m_bFly
|
2016-12-06 12:13:26 +01:00
|
|
|
= m_bRest = m_bBlinking = m_bClipping = m_bContent = m_bRedline
|
|
|
|
= m_bForcedLeftMargin = m_bHanging = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SwLineLayout::SwLineLayout()
|
|
|
|
: m_pNext( nullptr ), m_pLLSpaceAdd( nullptr ), m_pKanaComp( nullptr ), m_nRealHeight( 0 ),
|
|
|
|
m_bUnderscore( false )
|
|
|
|
{
|
|
|
|
ResetFlags();
|
|
|
|
SetWhichPor( POR_LAY );
|
|
|
|
}
|
|
|
|
|
|
|
|
SwLinePortion *SwLineLayout::GetFirstPortion() const
|
|
|
|
{
|
|
|
|
const SwLinePortion *pRet = pPortion ? pPortion : this;
|
|
|
|
return const_cast<SwLinePortion*>(pRet);
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
SwCharRange &SwCharRange::operator+=(const SwCharRange &rRange)
|
|
|
|
{
|
|
|
|
if(0 != rRange.nLen ) {
|
|
|
|
if(0 == nLen) {
|
|
|
|
nStart = rRange.nStart;
|
|
|
|
nLen = rRange.nLen ;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(rRange.nStart + rRange.nLen > nStart + nLen) {
|
|
|
|
nLen = rRange.nStart + rRange.nLen - nStart;
|
|
|
|
}
|
|
|
|
if(rRange.nStart < nStart) {
|
|
|
|
nLen += nStart - rRange.nStart;
|
|
|
|
nStart = rRange.nStart;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
SwScriptInfo::SwScriptInfo()
|
|
|
|
: nInvalidityPos(0)
|
|
|
|
, nDefaultDir(0)
|
2006-01-10 12:40:07 +00:00
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
SwScriptInfo::~SwScriptInfo()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Converts i18n Script Type (LATIN, ASIAN, COMPLEX, WEAK) to
|
2016-03-30 18:30:47 +02:00
|
|
|
// Sw Script Types (SwFontScript::Latin, SwFontScript::CJK, SwFontScript::CTL), used to identify the font
|
|
|
|
SwFontScript SwScriptInfo::WhichFont( sal_Int32 nIdx, const OUString* pText, const SwScriptInfo* pSI )
|
2001-10-22 12:03:21 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
assert((pSI || pText) && "How should I determine the script type?");
|
2014-08-31 17:43:26 +02:00
|
|
|
const sal_uInt16 nScript = pSI
|
|
|
|
? pSI->ScriptType( nIdx ) // use our SwScriptInfo if available
|
2015-05-20 13:05:49 +02:00
|
|
|
: g_pBreakIt->GetRealScriptOfText( *pText, nIdx ); // else ask the break iterator
|
2001-10-22 12:03:21 +00:00
|
|
|
|
|
|
|
switch ( nScript ) {
|
2016-03-30 18:30:47 +02:00
|
|
|
case i18n::ScriptType::LATIN : return SwFontScript::Latin;
|
|
|
|
case i18n::ScriptType::ASIAN : return SwFontScript::CJK;
|
|
|
|
case i18n::ScriptType::COMPLEX : return SwFontScript::CTL;
|
2001-10-22 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2011-03-19 14:13:18 +01:00
|
|
|
OSL_FAIL( "Somebody tells lies about the script type!" );
|
2016-03-30 18:30:47 +02:00
|
|
|
return SwFontScript::Latin;
|
2001-10-22 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
// searches for script changes in rText and stores them
|
|
|
|
void SwScriptInfo::InitScriptInfo( const SwTextNode& rNode )
|
2003-04-01 08:57:40 +00:00
|
|
|
{
|
|
|
|
InitScriptInfo( rNode, nDefaultDir == UBIDI_RTL );
|
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwScriptInfo::InitScriptInfo( const SwTextNode& rNode, bool bRTL )
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2017-04-19 11:20:17 +01:00
|
|
|
assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
|
2001-02-20 09:27:05 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
const OUString& rText = rNode.GetText();
|
2004-02-26 14:32:29 +00:00
|
|
|
|
|
|
|
// HIDDEN TEXT INFORMATION
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
Range aRange( 0, !rText.isEmpty() ? rText.getLength() - 1 : 0 );
|
2004-02-26 14:32:29 +00:00
|
|
|
MultiSelection aHiddenMulti( aRange );
|
|
|
|
CalcHiddenRanges( rNode, aHiddenMulti );
|
|
|
|
|
2010-10-05 20:01:23 +02:00
|
|
|
aHiddenChg.clear();
|
2014-02-02 16:28:50 +01:00
|
|
|
for( size_t i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nStart = rRange.Min();
|
|
|
|
const sal_Int32 nEnd = rRange.Max() + 1;
|
2004-02-26 14:32:29 +00:00
|
|
|
|
2010-10-05 20:01:23 +02:00
|
|
|
aHiddenChg.push_back( nStart );
|
|
|
|
aHiddenChg.push_back( nEnd );
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SCRIPT AND SCRIPT RELATED INFORMATION
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nChg = nInvalidityPos;
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
// COMPLETE_STRING means the data structure is up to date
|
|
|
|
nInvalidityPos = COMPLETE_STRING;
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
// this is the default direction
|
2011-01-17 15:06:54 +01:00
|
|
|
nDefaultDir = static_cast<sal_uInt8>(bRTL ? UBIDI_RTL : UBIDI_LTR);
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
// counter for script info arrays
|
2014-08-31 17:43:26 +02:00
|
|
|
size_t nCnt = 0;
|
2002-06-26 13:38:25 +00:00
|
|
|
// counter for compression information arrays
|
2014-08-31 17:43:26 +02:00
|
|
|
size_t nCntComp = 0;
|
2002-06-26 13:38:25 +00:00
|
|
|
// counter for kashida array
|
2014-08-31 17:43:26 +02:00
|
|
|
size_t nCntKash = 0;
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2015-04-15 09:36:39 +02:00
|
|
|
sal_Int16 nScript = i18n::ScriptType::LATIN;
|
2001-02-20 09:27:05 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// compression type
|
2017-02-13 08:17:10 +02:00
|
|
|
const CharCompressType aCompEnum = rNode.getIDocumentSettingAccess()->getCharacterCompressionType();
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// justification type
|
2017-03-07 11:19:35 +02:00
|
|
|
const bool bAdjustBlock = SvxAdjust::Block ==
|
2002-06-26 13:38:25 +00:00
|
|
|
rNode.GetSwAttrSet().GetAdjust().GetAdjust();
|
|
|
|
|
|
|
|
// FIND INVALID RANGES IN SCRIPT INFO ARRAYS:
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
if( nChg )
|
|
|
|
{
|
2002-06-26 13:38:25 +00:00
|
|
|
// if change position = 0 we do not use any data from the arrays
|
|
|
|
// because by deleting all characters of the first group at the beginning
|
|
|
|
// of a paragraph nScript is set to a wrong value
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( !CountScriptChg(), "sw.core", "Where're my changes of script?" );
|
2001-02-20 09:27:05 +00:00
|
|
|
while( nCnt < CountScriptChg() )
|
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( nChg > GetScriptChg( nCnt ) )
|
|
|
|
nCnt++;
|
|
|
|
else
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
|
|
|
nScript = GetScriptType( nCnt );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-02-13 08:17:10 +02:00
|
|
|
if( CharCompressType::NONE != aCompEnum )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
|
|
|
while( nCntComp < CountCompChg() )
|
|
|
|
{
|
2014-01-26 18:32:50 +01:00
|
|
|
if ( nChg <= GetCompStart( nCntComp ) )
|
2004-02-10 13:57:23 +00:00
|
|
|
break;
|
2014-01-26 18:32:50 +01:00
|
|
|
nCntComp++;
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-26 13:38:25 +00:00
|
|
|
if ( bAdjustBlock )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2002-06-26 13:38:25 +00:00
|
|
|
while( nCntKash < CountKashida() )
|
|
|
|
{
|
2014-01-26 18:32:50 +01:00
|
|
|
if ( nChg <= GetKashida( nCntKash ) )
|
2004-02-10 13:57:23 +00:00
|
|
|
break;
|
2014-01-26 18:32:50 +01:00
|
|
|
nCntKash++;
|
2002-06-26 13:38:25 +00:00
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
// ADJUST nChg VALUE:
|
2001-11-30 14:29:03 +00:00
|
|
|
|
|
|
|
// by stepping back one position we know that we are inside a group
|
|
|
|
// declared as an nScript group
|
2001-11-07 08:59:11 +00:00
|
|
|
if ( nChg )
|
2001-11-30 14:29:03 +00:00
|
|
|
--nChg;
|
2001-02-20 09:27:05 +00:00
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nGrpStart = nCnt ? GetScriptChg( nCnt - 1 ) : 0;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
// we go back in our group until we reach the first character of
|
|
|
|
// type nScript
|
|
|
|
while ( nChg > nGrpStart &&
|
2015-05-20 13:05:49 +02:00
|
|
|
nScript != g_pBreakIt->GetBreakIter()->getScriptType( rText, nChg ) )
|
2002-04-10 05:12:06 +00:00
|
|
|
--nChg;
|
2001-11-30 14:29:03 +00:00
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
// If we are at the start of a group, we do not trust nScript,
|
|
|
|
// we better get nScript from the breakiterator:
|
|
|
|
if ( nChg == nGrpStart )
|
2015-05-20 13:05:49 +02:00
|
|
|
nScript = (sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( rText, nChg );
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// INVALID DATA FROM THE SCRIPT INFO ARRAYS HAS TO BE DELETED:
|
|
|
|
|
|
|
|
// remove invalid entries from script information arrays
|
2011-02-08 14:05:29 +00:00
|
|
|
aScriptChanges.erase( aScriptChanges.begin() + nCnt, aScriptChanges.end() );
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// get the start of the last compression group
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nLastCompression = nChg;
|
2002-06-26 13:38:25 +00:00
|
|
|
if( nCntComp )
|
|
|
|
{
|
|
|
|
--nCntComp;
|
|
|
|
nLastCompression = GetCompStart( nCntComp );
|
|
|
|
if( nChg >= nLastCompression + GetCompLen( nCntComp ) )
|
|
|
|
{
|
|
|
|
nLastCompression = nChg;
|
|
|
|
++nCntComp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove invalid entries from compression information arrays
|
2011-02-08 16:12:13 +00:00
|
|
|
aCompressionChanges.erase(aCompressionChanges.begin() + nCntComp, aCompressionChanges.end() );
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// get the start of the last kashida group
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nLastKashida = nChg;
|
2003-03-27 14:45:43 +00:00
|
|
|
if( nCntKash && i18n::ScriptType::COMPLEX == nScript )
|
|
|
|
{
|
|
|
|
--nCntKash;
|
|
|
|
nLastKashida = GetKashida( nCntKash );
|
|
|
|
}
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// remove invalid entries from kashida array
|
2010-10-07 20:14:31 +02:00
|
|
|
aKashida.erase( aKashida.begin() + nCntKash, aKashida.end() );
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// TAKE CARE OF WEAK CHARACTERS: WE MUST FIND AN APPROPRIATE
|
2003-04-01 08:57:40 +00:00
|
|
|
// SCRIPT FOR WEAK CHARACTERS AT THE BEGINNING OF A PARAGRAPH
|
2002-06-26 13:38:25 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
if( WEAK == g_pBreakIt->GetBreakIter()->getScriptType( rText, nChg ) )
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2002-06-26 13:38:25 +00:00
|
|
|
// If the beginning of the current group is weak, this means that
|
2015-07-02 18:25:58 +02:00
|
|
|
// all of the characters in this group are weak. We have to assign
|
2002-06-26 13:38:25 +00:00
|
|
|
// the scripts to these characters depending on the fonts which are
|
|
|
|
// set for these characters to display them.
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nEnd =
|
2015-05-20 13:05:49 +02:00
|
|
|
g_pBreakIt->GetBreakIter()->endOfScript( rText, nChg, WEAK );
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
if (nEnd > rText.getLength() || nEnd < 0)
|
|
|
|
nEnd = rText.getLength();
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2015-04-15 09:36:39 +02:00
|
|
|
nScript = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() );
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( i18n::ScriptType::LATIN != nScript &&
|
|
|
|
i18n::ScriptType::ASIAN != nScript &&
|
|
|
|
i18n::ScriptType::COMPLEX != nScript, "sw.core", "Wrong default language" );
|
2001-12-14 11:13:58 +00:00
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
nChg = nEnd;
|
2001-12-14 11:13:58 +00:00
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
// Get next script type or set to weak in order to exit
|
2015-05-20 13:05:49 +02:00
|
|
|
sal_uInt8 nNextScript = ( nEnd < rText.getLength() ) ?
|
|
|
|
(sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( rText, nEnd ) :
|
2011-01-17 15:06:54 +01:00
|
|
|
(sal_uInt8)WEAK;
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( nScript != nNextScript )
|
2001-11-20 09:52:16 +00:00
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aScriptChanges.emplace_back(nEnd, nScript );
|
2011-02-08 14:05:29 +00:00
|
|
|
nCnt++;
|
2004-02-10 13:57:23 +00:00
|
|
|
nScript = nNextScript;
|
2001-11-20 09:52:16 +00:00
|
|
|
}
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
2001-10-22 12:03:21 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
// UPDATE THE SCRIPT INFO ARRAYS:
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
while ( nChg < rText.getLength() || ( aScriptChanges.empty() && rText.isEmpty() ) )
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( i18n::ScriptType::WEAK == nScript,
|
|
|
|
"sw.core", "Inserting WEAK into SwScriptInfo structure" );
|
2001-11-07 08:59:11 +00:00
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nSearchStt = nChg;
|
2015-05-20 13:05:49 +02:00
|
|
|
nChg = g_pBreakIt->GetBreakIter()->endOfScript( rText, nSearchStt, nScript );
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
if (nChg > rText.getLength() || nChg < 0)
|
|
|
|
nChg = rText.getLength();
|
2001-10-22 12:03:21 +00:00
|
|
|
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i28203#
|
2009-01-05 15:33:41 +00:00
|
|
|
// for 'complex' portions, we make sure that a portion does not contain more
|
|
|
|
// than one script:
|
2012-03-07 23:50:19 +00:00
|
|
|
if( i18n::ScriptType::COMPLEX == nScript )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const short nScriptType = ScriptTypeDetector::getCTLScriptType( rText, nSearchStt );
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nNextCTLScriptStart = nSearchStt;
|
2009-01-05 15:33:41 +00:00
|
|
|
short nCurrentScriptType = nScriptType;
|
2015-11-06 10:51:51 +02:00
|
|
|
while( css::i18n::CTLScriptType::CTL_UNKNOWN == nCurrentScriptType || nScriptType == nCurrentScriptType )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
nNextCTLScriptStart = ScriptTypeDetector::endOfCTLScriptType( rText, nNextCTLScriptStart );
|
|
|
|
if( nNextCTLScriptStart >= rText.getLength() || nNextCTLScriptStart >= nChg )
|
2009-01-05 15:33:41 +00:00
|
|
|
break;
|
2015-05-20 13:05:49 +02:00
|
|
|
nCurrentScriptType = ScriptTypeDetector::getCTLScriptType( rText, nNextCTLScriptStart );
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2013-04-11 00:21:40 -03:00
|
|
|
nChg = std::min( nChg, nNextCTLScriptStart );
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2009-08-17 14:12:14 +00:00
|
|
|
// special case for dotted circle since it can be used with complex
|
|
|
|
// before a mark, so we want it associated with the mark's script
|
2015-05-20 13:05:49 +02:00
|
|
|
if (nChg < rText.getLength() && nChg > 0 && (i18n::ScriptType::WEAK ==
|
|
|
|
g_pBreakIt->GetBreakIter()->getScriptType(rText,nChg - 1)))
|
2009-08-17 14:12:14 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
int8_t nType = u_charType(rText[nChg] );
|
2009-08-17 14:12:14 +00:00
|
|
|
if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
|
|
|
|
nType == U_COMBINING_SPACING_MARK )
|
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aScriptChanges.emplace_back(nChg-1, nScript );
|
2009-08-17 14:12:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aScriptChanges.emplace_back(nChg, nScript );
|
2009-08-17 14:12:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aScriptChanges.emplace_back(nChg, nScript );
|
2009-08-17 14:12:14 +00:00
|
|
|
}
|
2011-02-08 14:05:29 +00:00
|
|
|
++nCnt;
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
// if current script is asian, we search for compressable characters
|
|
|
|
// in this range
|
2017-02-13 08:17:10 +02:00
|
|
|
if ( CharCompressType::NONE != aCompEnum &&
|
2001-04-09 09:44:17 +00:00
|
|
|
i18n::ScriptType::ASIAN == nScript )
|
|
|
|
{
|
2014-08-31 17:55:44 +02:00
|
|
|
CompType ePrevState = NONE;
|
|
|
|
CompType eState = NONE;
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nPrevChg = nLastCompression;
|
2001-04-12 15:17:37 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
while ( nLastCompression < nChg )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
sal_Unicode cChar = rText[ nLastCompression ];
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2001-04-12 15:17:37 +00:00
|
|
|
// examine current character
|
|
|
|
switch ( cChar )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2001-04-12 15:17:37 +00:00
|
|
|
// Left punctuation found
|
|
|
|
case 0x3008: case 0x300A: case 0x300C: case 0x300E:
|
|
|
|
case 0x3010: case 0x3014: case 0x3016: case 0x3018:
|
|
|
|
case 0x301A: case 0x301D:
|
|
|
|
eState = SPECIAL_LEFT;
|
|
|
|
break;
|
|
|
|
// Right punctuation found
|
2015-10-21 22:34:08 +08:00
|
|
|
case 0x3009: case 0x300B:
|
2001-04-12 15:17:37 +00:00
|
|
|
case 0x300D: case 0x300F: case 0x3011: case 0x3015:
|
|
|
|
case 0x3017: case 0x3019: case 0x301B: case 0x301E:
|
|
|
|
case 0x301F:
|
|
|
|
eState = SPECIAL_RIGHT;
|
|
|
|
break;
|
2015-10-21 22:34:08 +08:00
|
|
|
case 0x3001: case 0x3002: // Fullstop or comma
|
|
|
|
eState = SPECIAL_MIDDLE ;
|
|
|
|
break;
|
2001-04-12 15:17:37 +00:00
|
|
|
default:
|
2014-08-31 17:55:44 +02:00
|
|
|
eState = ( 0x3040 <= cChar && 0x3100 > cChar ) ? KANA : NONE;
|
2001-04-12 15:17:37 +00:00
|
|
|
}
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2001-04-12 15:17:37 +00:00
|
|
|
// insert range of compressable characters
|
|
|
|
if( ePrevState != eState )
|
|
|
|
{
|
|
|
|
if ( ePrevState != NONE )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2001-04-12 15:17:37 +00:00
|
|
|
// insert start and type
|
2017-02-13 08:17:10 +02:00
|
|
|
if ( CharCompressType::PunctuationAndKana == aCompEnum ||
|
2001-04-12 15:17:37 +00:00
|
|
|
ePrevState != KANA )
|
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aCompressionChanges.emplace_back(nPrevChg, nLastCompression - nPrevChg, ePrevState );
|
2001-04-12 15:17:37 +00:00
|
|
|
}
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
2001-04-12 15:17:37 +00:00
|
|
|
|
|
|
|
ePrevState = eState;
|
2002-06-26 13:38:25 +00:00
|
|
|
nPrevChg = nLastCompression;
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
2001-04-12 15:17:37 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
nLastCompression++;
|
2001-04-12 15:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// we still have to examine last entry
|
|
|
|
if ( ePrevState != NONE )
|
|
|
|
{
|
|
|
|
// insert start and type
|
2017-02-13 08:17:10 +02:00
|
|
|
if ( CharCompressType::PunctuationAndKana == aCompEnum ||
|
2001-04-12 15:17:37 +00:00
|
|
|
ePrevState != KANA )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2017-09-13 14:56:28 +02:00
|
|
|
aCompressionChanges.emplace_back(nPrevChg, nLastCompression - nPrevChg, ePrevState );
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// we search for connecting opportunities (kashida)
|
2002-06-26 13:38:25 +00:00
|
|
|
else if ( bAdjustBlock && i18n::ScriptType::COMPLEX == nScript )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2015-11-10 10:25:48 +01:00
|
|
|
SwScanner aScanner( rNode, rNode.GetText(), nullptr, ModelToViewHelper(),
|
2007-09-27 08:17:13 +00:00
|
|
|
i18n::WordType::DICTIONARY_WORD,
|
2004-09-17 13:01:01 +00:00
|
|
|
nLastKashida, nChg );
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
// the search has to be performed on a per word base
|
2002-08-12 07:36:16 +00:00
|
|
|
while ( aScanner.NextWord() )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2013-09-09 15:15:00 +02:00
|
|
|
const OUString& rWord = aScanner.GetWord();
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2013-09-09 15:15:00 +02:00
|
|
|
sal_Int32 nIdx = 0;
|
|
|
|
sal_Int32 nKashidaPos = -1;
|
2012-10-19 05:34:48 -05:00
|
|
|
sal_Unicode cCh;
|
|
|
|
sal_Unicode cPrevCh = 0;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
int nPriorityLevel = 7; // 0..6 = level found
|
2008-06-06 07:16:21 +00:00
|
|
|
// 7 not found
|
2009-02-16 09:03:54 +00:00
|
|
|
|
2013-09-09 15:15:00 +02:00
|
|
|
sal_Int32 nWordLen = rWord.getLength();
|
2009-02-16 09:03:54 +00:00
|
|
|
|
|
|
|
// ignore trailing vowel chars
|
2013-09-09 15:15:00 +02:00
|
|
|
while( nWordLen && isTransparentChar( rWord[ nWordLen - 1 ] ))
|
2009-02-16 09:03:54 +00:00
|
|
|
--nWordLen;
|
|
|
|
|
|
|
|
while (nIdx < nWordLen)
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2013-09-09 15:15:00 +02:00
|
|
|
cCh = rWord[ nIdx ];
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
// 1. Priority:
|
|
|
|
// after user inserted kashida
|
|
|
|
if ( 0x640 == cCh )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx;
|
2008-06-06 07:16:21 +00:00
|
|
|
nPriorityLevel = 0;
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Priority:
|
|
|
|
// after a Seen or Sad
|
2009-02-16 09:03:54 +00:00
|
|
|
if (nPriorityLevel >= 1 && nIdx < nWordLen - 1)
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2009-02-16 09:03:54 +00:00
|
|
|
if( isSeenOrSadChar( cCh )
|
2013-09-09 15:15:00 +02:00
|
|
|
&& (rWord[ nIdx+1 ] != 0x200C) ) // #i98410#: prevent ZWNJ expansion
|
2008-06-06 07:16:21 +00:00
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx;
|
|
|
|
nPriorityLevel = 1;
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 3. Priority:
|
2016-11-06 22:06:44 +02:00
|
|
|
// before final form of Teh Marbuta, Heh, Dal
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( nPriorityLevel >= 2 && nIdx > 0 )
|
|
|
|
{
|
|
|
|
if ( isTehMarbutaChar ( cCh ) || // Teh Marbuta (right joining)
|
|
|
|
isDalChar ( cCh ) || // Dal (right joining) final form may appear in the middle of word
|
2016-11-06 22:06:44 +02:00
|
|
|
( isHehChar ( cCh ) && nIdx == nWordLen - 1)) // Heh (dual joining) only at end of word
|
2008-06-06 07:16:21 +00:00
|
|
|
{
|
|
|
|
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
|
2008-06-06 07:16:21 +00:00
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
nPriorityLevel = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// 4. Priority:
|
2016-11-06 23:07:31 +02:00
|
|
|
// before final form of Alef, Tah, Lam, Kaf or Gaf
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( nPriorityLevel >= 3 && nIdx > 0 )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( isAlefChar ( cCh ) || // Alef (right joining) final form may appear in the middle of word
|
2016-11-06 23:07:31 +02:00
|
|
|
(( isLamChar ( cCh ) || // Lam,
|
|
|
|
isTahChar ( cCh ) || // Tah,
|
|
|
|
isKafChar ( cCh ) || // Kaf (all dual joining)
|
2008-06-06 07:16:21 +00:00
|
|
|
isGafChar ( cCh ) )
|
2009-02-16 09:03:54 +00:00
|
|
|
&& nIdx == nWordLen - 1)) // only at end of word
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
|
2008-06-06 07:16:21 +00:00
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
nPriorityLevel = 3;
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5. Priority:
|
2016-11-07 00:41:44 +02:00
|
|
|
// before medial Beh-like
|
2009-02-16 09:03:54 +00:00
|
|
|
if ( nPriorityLevel >= 4 && nIdx > 0 && nIdx < nWordLen - 1 )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2016-11-07 00:41:44 +02:00
|
|
|
if ( isBehChar ( cCh ) )
|
2008-06-06 07:16:21 +00:00
|
|
|
{
|
2016-11-07 00:41:44 +02:00
|
|
|
// check if next character is Reh or Yeh-like
|
2013-09-09 15:15:00 +02:00
|
|
|
sal_Unicode cNextCh = rWord[ nIdx + 1 ];
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( isRehChar ( cNextCh ) || isYehChar ( cNextCh ))
|
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
|
2008-06-06 07:16:21 +00:00
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
nPriorityLevel = 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2008-06-06 07:16:21 +00:00
|
|
|
// 6. Priority:
|
2016-11-06 22:16:07 +02:00
|
|
|
// before the final form of Waw, Ain, Qaf and Feh
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( nPriorityLevel >= 5 && nIdx > 0 )
|
|
|
|
{
|
|
|
|
if ( isWawChar ( cCh ) || // Wav (right joining)
|
|
|
|
// final form may appear in the middle of word
|
|
|
|
(( isAinChar ( cCh ) || // Ain (dual joining)
|
|
|
|
isQafChar ( cCh ) || // Qaf (dual joining)
|
2011-08-31 23:58:51 +02:00
|
|
|
isFehChar ( cCh ) ) // Feh (dual joining)
|
2009-02-16 09:03:54 +00:00
|
|
|
&& nIdx == nWordLen - 1)) // only at end of word
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
|
2002-04-10 05:12:06 +00:00
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
2008-06-06 07:16:21 +00:00
|
|
|
{
|
2002-04-10 05:12:06 +00:00
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
2008-06-06 07:16:21 +00:00
|
|
|
nPriorityLevel = 5;
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// other connecting possibilities
|
2008-06-06 07:16:21 +00:00
|
|
|
if ( nPriorityLevel >= 6 && nIdx > 0 )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2016-11-06 22:44:15 +02:00
|
|
|
// Reh, Zain
|
|
|
|
if ( isRehChar ( cCh ) )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
|
2008-06-06 07:16:21 +00:00
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
2002-04-10 05:12:06 +00:00
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
2008-06-06 07:16:21 +00:00
|
|
|
nPriorityLevel = 6;
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-06 22:44:15 +02:00
|
|
|
// Do not consider vowel marks when checking if a character
|
|
|
|
// can be connected to previous character.
|
2009-01-05 15:33:41 +00:00
|
|
|
if ( !isTransparentChar ( cCh) )
|
2002-04-10 05:12:06 +00:00
|
|
|
cPrevCh = cCh;
|
|
|
|
|
2008-06-06 07:16:21 +00:00
|
|
|
++nIdx;
|
2002-04-10 05:12:06 +00:00
|
|
|
} // end of current word
|
|
|
|
|
2013-09-09 15:15:00 +02:00
|
|
|
if ( -1 != nKashidaPos )
|
2010-10-05 20:01:23 +02:00
|
|
|
{
|
|
|
|
aKashida.insert( aKashida.begin() + nCntKash, nKashidaPos);
|
|
|
|
nCntKash++;
|
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
} // end of kashida search
|
|
|
|
}
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
if ( nChg < rText.getLength() )
|
|
|
|
nScript = (sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( rText, nChg );
|
2001-10-22 12:03:21 +00:00
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
nLastCompression = nChg;
|
2002-04-10 05:12:06 +00:00
|
|
|
nLastKashida = nChg;
|
2011-02-10 11:25:21 +00:00
|
|
|
}
|
2002-05-02 07:04:29 +00:00
|
|
|
|
2011-11-24 00:52:07 +01:00
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
2003-03-27 14:45:43 +00:00
|
|
|
// check kashida data
|
|
|
|
long nTmpKashidaPos = -1;
|
2012-12-06 20:59:29 +09:00
|
|
|
bool bWrongKash = false;
|
2014-02-02 16:28:50 +01:00
|
|
|
for (size_t i = 0; i < aKashida.size(); ++i )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2003-03-27 14:45:43 +00:00
|
|
|
long nCurrKashidaPos = GetKashida( i );
|
|
|
|
if ( nCurrKashidaPos <= nTmpKashidaPos )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2012-12-06 20:59:29 +09:00
|
|
|
bWrongKash = true;
|
2002-05-02 07:04:29 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-03-27 14:45:43 +00:00
|
|
|
nTmpKashidaPos = nCurrKashidaPos;
|
2002-05-02 07:04:29 +00:00
|
|
|
}
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( bWrongKash, "sw.core", "Kashida array contains wrong data" );
|
2003-03-27 14:45:43 +00:00
|
|
|
#endif
|
2002-05-02 07:04:29 +00:00
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
// remove invalid entries from direction information arrays
|
2011-02-08 15:05:14 +00:00
|
|
|
aDirectionChanges.clear();
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2003-04-01 08:57:40 +00:00
|
|
|
// Perform Unicode Bidi Algorithm for text direction information
|
2004-02-10 13:57:23 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
UpdateBidiInfo( rText );
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2009-01-05 15:33:41 +00:00
|
|
|
// #i16354# Change script type for RTL text to CTL:
|
|
|
|
// 1. All text in RTL runs will use the CTL font
|
|
|
|
// #i89825# change the script type also to CTL (hennerdrewes)
|
|
|
|
// 2. Text in embedded LTR runs that does not have any strong LTR characters (numbers!)
|
2014-08-31 17:43:26 +02:00
|
|
|
for ( size_t nDirIdx = 0; nDirIdx < aDirectionChanges.size(); ++nDirIdx )
|
2004-02-10 13:57:23 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
const sal_uInt8 nCurrDirType = GetDirType( nDirIdx );
|
2017-04-11 07:00:58 +00:00
|
|
|
// nStart is start of RTL run:
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nStart = nDirIdx > 0 ? GetDirChg( nDirIdx - 1 ) : 0;
|
2004-02-10 13:57:23 +00:00
|
|
|
// nEnd is end of RTL run:
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nEnd = GetDirChg( nDirIdx );
|
2009-01-05 15:33:41 +00:00
|
|
|
|
|
|
|
if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run
|
2015-05-20 13:05:49 +02:00
|
|
|
( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( rText, nStart, nEnd ) ) ) // non-strong text in embedded LTR run
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
// nScriptIdx points into the ScriptArrays:
|
2010-10-05 20:01:23 +02:00
|
|
|
size_t nScriptIdx = 0;
|
2004-02-10 13:57:23 +00:00
|
|
|
|
|
|
|
// Skip entries in ScriptArray which are not inside the RTL run:
|
|
|
|
// Make nScriptIdx become the index of the script group with
|
|
|
|
// 1. nStartPosOfGroup <= nStart and
|
|
|
|
// 2. nEndPosOfGroup > nStart
|
|
|
|
while ( GetScriptChg( nScriptIdx ) <= nStart )
|
|
|
|
++nScriptIdx;
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0;
|
2011-01-17 15:06:54 +01:00
|
|
|
const sal_uInt8 nScriptTypeOfGroup = GetScriptType( nScriptIdx );
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( nStartPosOfGroup > nStart || GetScriptChg( nScriptIdx ) <= nStart,
|
|
|
|
"sw.core", "Script override with CTL font trouble" );
|
2004-02-10 13:57:23 +00:00
|
|
|
|
|
|
|
// Check if we have to insert a new script change at
|
|
|
|
// position nStart. If nStartPosOfGroup < nStart,
|
|
|
|
// we have to insert a new script change:
|
|
|
|
if ( nStart > 0 && nStartPosOfGroup < nStart )
|
|
|
|
{
|
2011-02-08 14:05:29 +00:00
|
|
|
aScriptChanges.insert(aScriptChanges.begin() + nScriptIdx,
|
|
|
|
ScriptChangeInfo(nStart, nScriptTypeOfGroup) );
|
2004-02-10 13:57:23 +00:00
|
|
|
++nScriptIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove entries in ScriptArray which end inside the RTL run:
|
2011-02-08 14:05:29 +00:00
|
|
|
while ( nScriptIdx < aScriptChanges.size() && GetScriptChg( nScriptIdx ) <= nEnd )
|
2004-02-10 13:57:23 +00:00
|
|
|
{
|
2011-02-08 14:05:29 +00:00
|
|
|
aScriptChanges.erase(aScriptChanges.begin() + nScriptIdx);
|
2004-02-10 13:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Insert a new entry in ScriptArray for the end of the RTL run:
|
2011-02-08 14:05:29 +00:00
|
|
|
aScriptChanges.insert(aScriptChanges.begin() + nScriptIdx,
|
|
|
|
ScriptChangeInfo(nEnd, i18n::ScriptType::COMPLEX) );
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2014-01-21 17:18:42 +02:00
|
|
|
#if OSL_DEBUG_LEVEL > 1
|
2011-02-08 14:05:29 +00:00
|
|
|
// Check that ScriptChangeInfos are in increasing order of
|
|
|
|
// position and that we don't have "empty" changes.
|
2011-03-14 16:51:14 +00:00
|
|
|
sal_uInt8 nLastTyp = i18n::ScriptType::WEAK;
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nLastPos = 0;
|
2013-01-05 16:21:52 +01:00
|
|
|
for (std::vector<ScriptChangeInfo>::const_iterator i2 = aScriptChanges.begin(); i2 != aScriptChanges.end(); ++i2)
|
2004-02-10 13:57:23 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( nLastTyp == i2->type ||
|
|
|
|
nLastPos >= i2->position,
|
|
|
|
"sw.core", "Heavy InitScriptType() confusion" );
|
2011-02-08 14:05:29 +00:00
|
|
|
nLastPos = i2->position;
|
|
|
|
nLastTyp = i2->type;
|
2004-02-10 13:57:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-03-27 14:45:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwScriptInfo::UpdateBidiInfo( const OUString& rText )
|
2003-03-27 14:45:43 +00:00
|
|
|
{
|
|
|
|
// remove invalid entries from direction information arrays
|
2011-02-08 15:05:14 +00:00
|
|
|
aDirectionChanges.clear();
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
// Bidi functions from icu 2.0
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
UErrorCode nError = U_ZERO_ERROR;
|
2015-05-20 13:05:49 +02:00
|
|
|
UBiDi* pBidi = ubidi_openSized( rText.getLength(), 0, &nError );
|
2002-05-02 07:04:29 +00:00
|
|
|
nError = U_ZERO_ERROR;
|
|
|
|
|
Remove MinGW support
In OOo times, there'd originally been efforts to allow building on Windows with
MinGW. Later, in LO times, this has been shifted to an attempt of cross-
compiling for Windows on Linux. That attempt can be considered abandoned, and
the relevant code rotting.
Due to this heritage, there are now three kinds of MinGW-specific code in LO:
* Code from the original OOo native Windows effort that is no longer relevant
for the LO cross-compilation effort, but has never been removed properly.
* Code from the original OOo native Windows effort that is re-purposed for the
LO cross-compilation effort.
* Code that has been added specifially for the LO cross-compilation effort.
All three kinds of code are removed.
(An unrelated, remaining use of MinGW is for --enable-build-unowinreg, utilizing
--with-mingw-cross-compiler, MINGWCXX, and MINGWSTRIP.)
Change-Id: I49daad8669b4cbe49fa923050c4a4a6ff7dda568
Reviewed-on: https://gerrit.libreoffice.org/34127
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2017-02-10 14:05:21 +01:00
|
|
|
ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(rText.getStr()), rText.getLength(),
|
2015-11-10 10:25:48 +01:00
|
|
|
nDefaultDir, nullptr, &nError );
|
2002-05-02 07:04:29 +00:00
|
|
|
nError = U_ZERO_ERROR;
|
2014-01-14 16:50:42 +00:00
|
|
|
int nCount = ubidi_countRuns( pBidi, &nError );
|
2003-11-07 14:12:04 +00:00
|
|
|
int32_t nStart = 0;
|
|
|
|
int32_t nEnd;
|
2002-05-02 07:04:29 +00:00
|
|
|
UBiDiLevel nCurrDir;
|
2014-01-14 16:50:42 +00:00
|
|
|
for ( int nIdx = 0; nIdx < nCount; ++nIdx )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
|
|
|
ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
|
2017-09-13 14:56:28 +02:00
|
|
|
aDirectionChanges.emplace_back(nEnd, nCurrDir );
|
2002-05-02 07:04:29 +00:00
|
|
|
nStart = nEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
ubidi_close( pBidi );
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// returns the position of the next character which belongs to another script
|
|
|
|
// than the character of the actual (input) position.
|
|
|
|
// If there's no script change until the end of the paragraph, it will return
|
|
|
|
// COMPLETE_STRING.
|
|
|
|
// Scripts are Asian (Chinese, Japanese, Korean),
|
|
|
|
// Latin ( English etc.)
|
|
|
|
// and Complex ( Hebrew, Arabian )
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 SwScriptInfo::NextScriptChg(const sal_Int32 nPos) const
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nEnd = CountScriptChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2001-02-20 09:27:05 +00:00
|
|
|
if( nPos < GetScriptChg( nX ) )
|
|
|
|
return GetScriptChg( nX );
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
return COMPLETE_STRING;
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// returns the script of the character at the input position
|
2015-04-15 09:36:39 +02:00
|
|
|
sal_Int16 SwScriptInfo::ScriptType(const sal_Int32 nPos) const
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nEnd = CountScriptChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2001-02-20 09:27:05 +00:00
|
|
|
if( nPos < GetScriptChg( nX ) )
|
|
|
|
return GetScriptType( nX );
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
|
2001-10-22 12:03:21 +00:00
|
|
|
// the default is the application language script
|
2017-04-17 21:35:35 +02:00
|
|
|
return SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() );
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 SwScriptInfo::NextDirChg( const sal_Int32 nPos,
|
2011-01-17 15:06:54 +01:00
|
|
|
const sal_uInt8* pLevel ) const
|
2002-03-21 08:19:43 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const sal_uInt8 nCurrDir = pLevel ? *pLevel : 62;
|
|
|
|
const size_t nEnd = CountDirChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2002-03-21 08:19:43 +00:00
|
|
|
{
|
|
|
|
if( nPos < GetDirChg( nX ) &&
|
2002-05-02 07:04:29 +00:00
|
|
|
( nX + 1 == nEnd || GetDirType( nX + 1 ) <= nCurrDir ) )
|
2002-03-21 08:19:43 +00:00
|
|
|
return GetDirChg( nX );
|
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
return COMPLETE_STRING;
|
2002-03-21 08:19:43 +00:00
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_uInt8 SwScriptInfo::DirType(const sal_Int32 nPos) const
|
2002-03-21 08:19:43 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nEnd = CountDirChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2002-03-21 08:19:43 +00:00
|
|
|
{
|
|
|
|
if( nPos < GetDirChg( nX ) )
|
|
|
|
return GetDirType( nX );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Takes a string and replaced the hidden ranges with cChar.
|
2015-05-20 13:05:49 +02:00
|
|
|
sal_Int32 SwScriptInfo::MaskHiddenRanges( const SwTextNode& rNode, OUStringBuffer & rText,
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nStt, const sal_Int32 nEnd,
|
2012-10-19 05:34:48 -05:00
|
|
|
const sal_Unicode cChar )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
assert(rNode.GetText().getLength() == rText.getLength());
|
2004-04-27 12:42:37 +00:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
PositionList aList;
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nHiddenStart;
|
|
|
|
sal_Int32 nHiddenEnd;
|
2014-08-31 17:43:26 +02:00
|
|
|
sal_Int32 nNumOfHiddenChars = 0;
|
2004-02-26 14:32:29 +00:00
|
|
|
GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
|
|
|
|
PositionList::const_reverse_iterator rFirst( aList.end() );
|
|
|
|
PositionList::const_reverse_iterator rLast( aList.begin() );
|
|
|
|
while ( rFirst != rLast )
|
|
|
|
{
|
|
|
|
nHiddenEnd = *(rFirst++);
|
|
|
|
nHiddenStart = *(rFirst++);
|
|
|
|
|
2004-04-27 12:42:37 +00:00
|
|
|
if ( nHiddenEnd < nStt || nHiddenStart > nEnd )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while ( nHiddenStart < nHiddenEnd && nHiddenStart < nEnd )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2004-04-27 12:42:37 +00:00
|
|
|
if ( nHiddenStart >= nStt && nHiddenStart < nEnd )
|
|
|
|
{
|
2013-02-17 00:14:26 +01:00
|
|
|
rText[nHiddenStart] = cChar;
|
2004-04-27 12:42:37 +00:00
|
|
|
++nNumOfHiddenChars;
|
|
|
|
}
|
|
|
|
++nHiddenStart;
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nNumOfHiddenChars;
|
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
// Takes a SwTextNode and deletes the hidden ranges from the node.
|
|
|
|
void SwScriptInfo::DeleteHiddenRanges( SwTextNode& rNode )
|
2006-11-01 14:13:17 +00:00
|
|
|
{
|
|
|
|
PositionList aList;
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nHiddenStart;
|
|
|
|
sal_Int32 nHiddenEnd;
|
2006-11-01 14:13:17 +00:00
|
|
|
GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
|
|
|
|
PositionList::const_reverse_iterator rFirst( aList.end() );
|
|
|
|
PositionList::const_reverse_iterator rLast( aList.begin() );
|
|
|
|
while ( rFirst != rLast )
|
|
|
|
{
|
|
|
|
nHiddenEnd = *(rFirst++);
|
|
|
|
nHiddenStart = *(rFirst++);
|
|
|
|
|
|
|
|
SwPaM aPam( rNode, nHiddenStart, rNode, nHiddenEnd );
|
2015-07-03 11:31:14 +02:00
|
|
|
rNode.getIDocumentContentOperations().DeleteRange( aPam );
|
2006-11-01 14:13:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTextNode& rNode, sal_Int32 nPos,
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32& rnStartPos, sal_Int32& rnEndPos,
|
2004-02-26 14:32:29 +00:00
|
|
|
PositionList* pList )
|
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
rnStartPos = COMPLETE_STRING;
|
2004-02-26 14:32:29 +00:00
|
|
|
rnEndPos = 0;
|
|
|
|
|
|
|
|
bool bNewContainsHiddenChars = false;
|
|
|
|
|
|
|
|
// Optimization: First examine the flags at the text node:
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
if ( !rNode.IsCalcHiddenCharFlags() )
|
|
|
|
{
|
|
|
|
bool bWholePara = rNode.HasHiddenCharAttribute( true );
|
|
|
|
bool bContainsHiddenChars = rNode.HasHiddenCharAttribute( false );
|
|
|
|
if ( !bContainsHiddenChars )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( bWholePara )
|
|
|
|
{
|
|
|
|
if ( pList )
|
|
|
|
{
|
|
|
|
pList->push_back( 0 );
|
2015-05-20 13:05:49 +02:00
|
|
|
pList->push_back(rNode.GetText().getLength());
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rnStartPos = 0;
|
2015-05-20 13:05:49 +02:00
|
|
|
rnEndPos = rNode.GetText().getLength();
|
2004-02-26 14:32:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rNode );
|
|
|
|
if ( pSI )
|
|
|
|
{
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
// Check first, if we have a valid SwScriptInfo object for this text node:
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
bNewContainsHiddenChars = pSI->GetBoundsOfHiddenRange( nPos, rnStartPos, rnEndPos, pList );
|
2013-02-18 18:36:45 +01:00
|
|
|
const bool bNewHiddenCharsHidePara =
|
2015-05-20 13:05:49 +02:00
|
|
|
rnStartPos == 0 && rnEndPos >= rNode.GetText().getLength();
|
2004-02-26 14:32:29 +00:00
|
|
|
rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
// No valid SwScriptInfo Object, we have to do it the hard way:
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
Range aRange(0, (!rNode.GetText().isEmpty())
|
|
|
|
? rNode.GetText().getLength() - 1
|
2013-02-18 18:36:45 +01:00
|
|
|
: 0);
|
2004-02-26 14:32:29 +00:00
|
|
|
MultiSelection aHiddenMulti( aRange );
|
|
|
|
SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti );
|
2014-02-02 16:28:50 +01:00
|
|
|
for( size_t i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nHiddenStart = rRange.Min();
|
|
|
|
const sal_Int32 nHiddenEnd = rRange.Max() + 1;
|
2004-02-26 14:32:29 +00:00
|
|
|
|
|
|
|
if ( nHiddenStart > nPos )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
rnStartPos = nHiddenStart;
|
2013-02-18 18:36:45 +01:00
|
|
|
rnEndPos = std::min<sal_Int32>(nHiddenEnd,
|
2015-05-20 13:05:49 +02:00
|
|
|
rNode.GetText().getLength());
|
2004-02-26 14:32:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pList )
|
|
|
|
{
|
2014-02-02 16:28:50 +01:00
|
|
|
for( size_t i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
2014-01-14 16:50:42 +00:00
|
|
|
pList->push_back( rRange.Min() );
|
|
|
|
pList->push_back( rRange.Max() + 1 );
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bNewContainsHiddenChars = aHiddenMulti.GetRangeCount() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bNewContainsHiddenChars;
|
|
|
|
}
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
bool SwScriptInfo::GetBoundsOfHiddenRange( sal_Int32 nPos, sal_Int32& rnStartPos,
|
|
|
|
sal_Int32& rnEndPos, PositionList* pList ) const
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
rnStartPos = COMPLETE_STRING;
|
2004-02-26 14:32:29 +00:00
|
|
|
rnEndPos = 0;
|
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nEnd = CountHiddenChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nHiddenStart = GetHiddenChg( nX++ );
|
|
|
|
const sal_Int32 nHiddenEnd = GetHiddenChg( nX );
|
2004-02-26 14:32:29 +00:00
|
|
|
|
|
|
|
if ( nHiddenStart > nPos )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
rnStartPos = nHiddenStart;
|
|
|
|
rnEndPos = nHiddenEnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pList )
|
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
pList->push_back( GetHiddenChg( nX++ ) );
|
|
|
|
pList->push_back( GetHiddenChg( nX ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return CountHiddenChg() > 0;
|
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
bool SwScriptInfo::IsInHiddenRange( const SwTextNode& rNode, sal_Int32 nPos )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nStartPos;
|
|
|
|
sal_Int32 nEndPos;
|
2004-02-26 14:32:29 +00:00
|
|
|
SwScriptInfo::GetBoundsOfHiddenRange( rNode, nPos, nStartPos, nEndPos );
|
2014-01-14 16:50:42 +00:00
|
|
|
return nStartPos != COMPLETE_STRING;
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
|
2011-11-24 00:52:00 +01:00
|
|
|
#ifdef DBG_UTIL
|
2014-04-18 17:02:13 -04:00
|
|
|
// returns the type of the compressed character
|
2014-08-31 17:55:44 +02:00
|
|
|
SwScriptInfo::CompType SwScriptInfo::DbgCompType( const sal_Int32 nPos ) const
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nEnd = CountCompChg();
|
|
|
|
for( size_t nX = 0; nX < nEnd; ++nX )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const sal_Int32 nChg = GetCompStart( nX );
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
if ( nPos < nChg )
|
|
|
|
return NONE;
|
|
|
|
|
|
|
|
if( nPos < nChg + GetCompLen( nX ) )
|
|
|
|
return GetCompType( nX );
|
|
|
|
}
|
|
|
|
return NONE;
|
|
|
|
}
|
2004-08-12 11:36:37 +00:00
|
|
|
#endif
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// returns, if there are compressable kanas or specials
|
|
|
|
// between nStart and nEnd
|
2014-08-31 17:43:26 +02:00
|
|
|
size_t SwScriptInfo::HasKana( sal_Int32 nStart, const sal_Int32 nLen ) const
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nCnt = CountCompChg();
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nEnd = nStart + nLen;
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
for( size_t nX = 0; nX < nCnt; ++nX )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nKanaStart = GetCompStart( nX );
|
|
|
|
sal_Int32 nKanaEnd = nKanaStart + GetCompLen( nX );
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
if ( nKanaStart >= nEnd )
|
2014-08-31 17:43:26 +02:00
|
|
|
return SAL_MAX_SIZE;
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
if ( nStart < nKanaEnd )
|
|
|
|
return nX;
|
|
|
|
}
|
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
return SAL_MAX_SIZE;
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 18:21:12 +02:00
|
|
|
long SwScriptInfo::Compress( long* pKernArray, sal_Int32 nIdx, sal_Int32 nLen,
|
2011-01-17 15:06:54 +01:00
|
|
|
const sal_uInt16 nCompress, const sal_uInt16 nFontHeight,
|
2015-10-21 22:34:08 +08:00
|
|
|
bool bCenter,
|
2001-04-09 09:44:17 +00:00
|
|
|
Point* pPoint ) const
|
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( !nCompress, "sw.core", "Compression without compression?!" );
|
|
|
|
SAL_WARN_IF( !nLen, "sw.core", "Compression without text?!" );
|
2014-08-31 17:43:26 +02:00
|
|
|
const size_t nCompCount = CountCompChg();
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
// In asian typography, there are full width and half width characters.
|
2014-05-05 22:27:38 +02:00
|
|
|
// Full width punctuation characters can be compressed by 50%
|
|
|
|
// to determine this, we compare the font width with 75% of its height
|
2014-08-31 17:43:26 +02:00
|
|
|
const long nMinWidth = ( 3 * nFontHeight ) / 4;
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
size_t nCompIdx = HasKana( nIdx, nLen );
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2014-08-31 17:43:26 +02:00
|
|
|
if ( SAL_MAX_SIZE == nCompIdx )
|
2001-04-09 09:44:17 +00:00
|
|
|
return 0;
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nChg = GetCompStart( nCompIdx );
|
|
|
|
sal_Int32 nCompLen = GetCompLen( nCompIdx );
|
2014-08-31 17:43:26 +02:00
|
|
|
sal_Int32 nI = 0;
|
2014-01-26 19:17:41 +01:00
|
|
|
nLen += nIdx;
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
if( nChg > nIdx )
|
|
|
|
{
|
|
|
|
nI = nChg - nIdx;
|
|
|
|
nIdx = nChg;
|
|
|
|
}
|
|
|
|
else if( nIdx < nChg + nCompLen )
|
|
|
|
nCompLen -= nIdx - nChg;
|
|
|
|
|
|
|
|
if( nIdx > nLen || nCompIdx >= nCompCount )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
long nSub = 0;
|
|
|
|
long nLast = nI ? pKernArray[ nI - 1 ] : 0;
|
|
|
|
do
|
|
|
|
{
|
2014-08-31 17:55:44 +02:00
|
|
|
const CompType nType = GetCompType( nCompIdx );
|
2011-11-24 00:52:00 +01:00
|
|
|
#ifdef DBG_UTIL
|
2014-08-31 17:55:44 +02:00
|
|
|
SAL_WARN_IF( nType != DbgCompType( nIdx ), "sw.core", "Gimme the right type!" );
|
2004-10-22 07:13:56 +00:00
|
|
|
#endif
|
2014-01-26 19:17:41 +01:00
|
|
|
nCompLen += nIdx;
|
2001-04-09 09:44:17 +00:00
|
|
|
if( nCompLen > nLen )
|
|
|
|
nCompLen = nLen;
|
|
|
|
|
|
|
|
// are we allowed to compress the character?
|
|
|
|
if ( pKernArray[ nI ] - nLast < nMinWidth )
|
|
|
|
{
|
|
|
|
nIdx++; nI++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while( nIdx < nCompLen )
|
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( SwScriptInfo::NONE == nType, "sw.core", "None compression?!" );
|
2001-04-09 09:44:17 +00:00
|
|
|
|
|
|
|
// nLast is width of current character
|
|
|
|
nLast -= pKernArray[ nI ];
|
|
|
|
|
|
|
|
nLast *= nCompress;
|
|
|
|
long nMove = 0;
|
|
|
|
if( SwScriptInfo::KANA != nType )
|
|
|
|
{
|
2015-10-21 22:34:08 +08:00
|
|
|
nLast /= 24000;
|
2001-04-09 09:44:17 +00:00
|
|
|
if( pPoint && SwScriptInfo::SPECIAL_LEFT == nType )
|
|
|
|
{
|
|
|
|
if( nI )
|
|
|
|
nMove = nLast;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPoint->X() += nLast;
|
|
|
|
nLast = 0;
|
|
|
|
}
|
|
|
|
}
|
2015-10-21 22:34:08 +08:00
|
|
|
else if( bCenter && SwScriptInfo::SPECIAL_MIDDLE == nType )
|
|
|
|
nMove = nLast / 2;
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
nLast /= 100000;
|
|
|
|
nSub -= nLast;
|
|
|
|
nLast = pKernArray[ nI ];
|
2015-10-21 22:34:08 +08:00
|
|
|
if( nI && nMove )
|
2001-04-09 09:44:17 +00:00
|
|
|
pKernArray[ nI - 1 ] += nMove;
|
|
|
|
pKernArray[ nI++ ] -= nSub;
|
|
|
|
++nIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-26 18:32:50 +01:00
|
|
|
if( nIdx >= nLen )
|
|
|
|
break;
|
|
|
|
|
|
|
|
sal_Int32 nTmpChg = nLen;
|
|
|
|
if( ++nCompIdx < nCompCount )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2014-01-26 18:32:50 +01:00
|
|
|
nTmpChg = GetCompStart( nCompIdx );
|
|
|
|
if( nTmpChg > nLen )
|
2007-09-27 08:17:13 +00:00
|
|
|
nTmpChg = nLen;
|
2014-01-26 18:32:50 +01:00
|
|
|
nCompLen = GetCompLen( nCompIdx );
|
|
|
|
}
|
|
|
|
|
|
|
|
while( nIdx < nTmpChg )
|
|
|
|
{
|
|
|
|
nLast = pKernArray[ nI ];
|
|
|
|
pKernArray[ nI++ ] -= nSub;
|
|
|
|
++nIdx;
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
} while( nIdx < nLen );
|
|
|
|
return nSub;
|
|
|
|
}
|
|
|
|
|
2009-01-05 15:33:41 +00:00
|
|
|
// Note on calling KashidaJustify():
|
|
|
|
// Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
|
|
|
|
// total number of kashida positions, or the number of kashida positions after some positions
|
|
|
|
// have been dropped, depending on the state of the aKashidaInvalid array.
|
|
|
|
|
2014-07-18 18:21:12 +02:00
|
|
|
sal_Int32 SwScriptInfo::KashidaJustify( long* pKernArray,
|
|
|
|
long* pScrArray,
|
|
|
|
sal_Int32 nStt,
|
|
|
|
sal_Int32 nLen,
|
|
|
|
long nSpaceAdd ) const
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( !nLen, "sw.core", "Kashida justification without text?!" );
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2009-01-05 15:33:41 +00:00
|
|
|
if( !IsKashidaLine(nStt))
|
2014-01-13 14:18:14 +00:00
|
|
|
return -1;
|
2009-01-05 15:33:41 +00:00
|
|
|
|
2012-06-05 13:57:00 +02:00
|
|
|
// evaluate kashida information in collected in SwScriptInfo
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKash = 0;
|
2002-04-10 05:12:06 +00:00
|
|
|
while( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nStt <= GetKashida( nCntKash ) )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
++nCntKash;
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
const sal_Int32 nEnd = nStt + nLen;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKashEnd = nCntKash;
|
2009-01-05 15:33:41 +00:00
|
|
|
while ( nCntKashEnd < CountKashida() )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
2014-01-26 17:25:33 +01:00
|
|
|
if ( nEnd <= GetKashida( nCntKashEnd ) )
|
2009-01-05 15:33:41 +00:00
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
++nCntKashEnd;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2002-04-10 05:12:06 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nActualKashCount = nCntKashEnd - nCntKash;
|
|
|
|
for (size_t i = nCntKash; i < nCntKashEnd; ++i)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
|
|
|
if ( nActualKashCount && !IsKashidaValid ( i ) )
|
|
|
|
--nActualKashCount;
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
|
2009-01-05 15:33:41 +00:00
|
|
|
if ( !pKernArray )
|
|
|
|
return nActualKashCount;
|
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// do nothing if there is no more kashida
|
|
|
|
if ( nCntKash < CountKashida() )
|
|
|
|
{
|
2009-01-05 15:33:41 +00:00
|
|
|
// skip any invalid kashidas
|
|
|
|
while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
|
|
|
|
++nCntKash;
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
sal_Int32 nKashidaPos = GetKashida( nCntKash );
|
|
|
|
sal_Int32 nIdx = nKashidaPos;
|
2005-04-18 13:37:24 +00:00
|
|
|
long nKashAdd = nSpaceAdd;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
while ( nIdx < nEnd )
|
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
sal_Int32 nArrayPos = nIdx - nStt;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
// next kashida position
|
2009-01-05 15:33:41 +00:00
|
|
|
++nCntKash;
|
|
|
|
while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
|
|
|
|
++nCntKash;
|
|
|
|
|
|
|
|
nIdx = nCntKash < CountKashida() && IsKashidaValid ( nCntKash ) ? GetKashida( nCntKash ) : nEnd;
|
2002-04-10 05:12:06 +00:00
|
|
|
if ( nIdx > nEnd )
|
|
|
|
nIdx = nEnd;
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
const sal_Int32 nArrayEnd = nIdx - nStt;
|
2002-04-10 05:12:06 +00:00
|
|
|
|
|
|
|
while ( nArrayPos < nArrayEnd )
|
|
|
|
{
|
2005-04-18 13:37:24 +00:00
|
|
|
pKernArray[ nArrayPos ] += nKashAdd;
|
2002-04-10 05:12:06 +00:00
|
|
|
if ( pScrArray )
|
2009-01-05 15:33:41 +00:00
|
|
|
pScrArray[ nArrayPos ] += nKashAdd;
|
2002-04-10 05:12:06 +00:00
|
|
|
++nArrayPos;
|
|
|
|
}
|
2005-04-18 13:37:24 +00:00
|
|
|
nKashAdd += nSpaceAdd;
|
2002-04-10 05:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Checks if the current text is 'Arabic' text. Note that only the first
|
|
|
|
// character has to be checked because a ctl portion only contains one
|
2015-05-20 13:05:49 +02:00
|
|
|
// script, see NewTextPortion
|
|
|
|
bool SwScriptInfo::IsArabicText( const OUString& rText, sal_Int32 nStt, sal_Int32 nLen )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
|
|
|
using namespace ::com::sun::star::i18n;
|
2013-08-09 09:14:53 +09:00
|
|
|
static const ScriptTypeList typeList[] = {
|
2017-03-31 13:49:52 +02:00
|
|
|
{ UnicodeScript_kArabic, UnicodeScript_kArabic, (sal_Int16)UnicodeScript_kArabic }, // 11,
|
|
|
|
{ UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, (sal_Int16)UnicodeScript_kScriptCount } // 88
|
2009-01-05 15:33:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// go forward if current position does not hold a regular character:
|
|
|
|
const CharClass& rCC = GetAppCharClass();
|
|
|
|
sal_Int32 nIdx = nStt;
|
2012-05-02 22:40:44 +01:00
|
|
|
const sal_Int32 nEnd = nStt + nLen;
|
2015-05-20 13:05:49 +02:00
|
|
|
while ( nIdx < nEnd && !rCC.isLetterNumeric( rText, nIdx ) )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
|
|
|
++nIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( nIdx == nEnd )
|
2009-01-06 12:54:16 +00:00
|
|
|
{
|
2009-01-05 15:33:41 +00:00
|
|
|
// no regular character found in this portion. Go backward:
|
|
|
|
--nIdx;
|
2015-05-20 13:05:49 +02:00
|
|
|
while ( nIdx >= 0 && !rCC.isLetterNumeric( rText, nIdx ) )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
|
|
|
--nIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( nIdx >= 0 )
|
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const sal_Unicode cCh = rText[nIdx];
|
2017-03-31 13:49:52 +02:00
|
|
|
const sal_Int16 type = unicode::getUnicodeScriptType( cCh, typeList, (sal_Int16)UnicodeScript_kScriptCount );
|
|
|
|
return type == (sal_Int16)UnicodeScript_kArabic;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2012-05-02 22:40:44 +01:00
|
|
|
return false;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
bool SwScriptInfo::IsKashidaValid(sal_Int32 nKashPos) const
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2016-05-11 09:53:50 +02:00
|
|
|
for (sal_Int32 i : aKashidaInvalid)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2016-05-11 09:53:50 +02:00
|
|
|
if ( i == nKashPos )
|
2009-01-05 15:33:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
void SwScriptInfo::ClearKashidaInvalid(sal_Int32 nKashPos)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2010-10-05 20:01:23 +02:00
|
|
|
for ( size_t i = 0; i < aKashidaInvalid.size(); ++i )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
|
|
|
if ( aKashidaInvalid [ i ] == nKashPos )
|
|
|
|
{
|
2014-01-26 17:25:33 +01:00
|
|
|
aKashidaInvalid.erase ( aKashidaInvalid.begin() + i );
|
|
|
|
return;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// bMark == true:
|
|
|
|
// marks the first valid kashida in the given text range as invalid
|
|
|
|
// bMark == false:
|
|
|
|
// clears all kashida invalid flags in the given text range
|
2014-01-13 14:18:14 +00:00
|
|
|
bool SwScriptInfo::MarkOrClearKashidaInvalid(sal_Int32 nStt, sal_Int32 nLen,
|
|
|
|
bool bMark, sal_Int32 nMarkCount)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKash = 0;
|
2009-01-05 15:33:41 +00:00
|
|
|
while( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nStt <= GetKashida( nCntKash ) )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
nCntKash++;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
const sal_Int32 nEnd = nStt + nLen;
|
2009-01-05 15:33:41 +00:00
|
|
|
|
|
|
|
while ( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nEnd <= GetKashida( nCntKash ) )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
if(bMark)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-26 18:20:06 +01:00
|
|
|
if ( IsKashidaValid ( nCntKash ) )
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-26 18:20:06 +01:00
|
|
|
MarkKashidaInvalid ( nCntKash );
|
|
|
|
--nMarkCount;
|
|
|
|
if (!nMarkCount)
|
|
|
|
return true;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
2014-01-26 18:20:06 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ClearKashidaInvalid ( nCntKash );
|
|
|
|
}
|
|
|
|
nCntKash++;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
void SwScriptInfo::MarkKashidaInvalid(sal_Int32 nKashPos)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
aKashidaInvalid.push_back(nKashPos);
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// retrieve the kashida positions in the given text range
|
2016-01-20 16:36:19 +02:00
|
|
|
void SwScriptInfo::GetKashidaPositions(sal_Int32 nStt, sal_Int32 nLen,
|
2014-01-13 14:18:14 +00:00
|
|
|
sal_Int32* pKashidaPosition)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKash = 0;
|
2009-01-05 15:33:41 +00:00
|
|
|
while( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nStt <= GetKashida( nCntKash ) )
|
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
nCntKash++;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
const sal_Int32 nEnd = nStt + nLen;
|
2009-01-05 15:33:41 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKashEnd = nCntKash;
|
2009-01-05 15:33:41 +00:00
|
|
|
while ( nCntKashEnd < CountKashida() )
|
|
|
|
{
|
2014-01-26 17:25:33 +01:00
|
|
|
if ( nEnd <= GetKashida( nCntKashEnd ) )
|
2009-01-05 15:33:41 +00:00
|
|
|
break;
|
2014-01-26 18:20:06 +01:00
|
|
|
pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd );
|
|
|
|
nCntKashEnd++;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
void SwScriptInfo::SetNoKashidaLine(sal_Int32 nStt, sal_Int32 nLen)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2010-10-05 20:01:23 +02:00
|
|
|
aNoKashidaLine.push_back( nStt );
|
|
|
|
aNoKashidaLineEnd.push_back( nStt+nLen );
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2002-06-20 08:44:17 +00:00
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// determines if the line uses kashida justification
|
2014-01-13 14:18:14 +00:00
|
|
|
bool SwScriptInfo::IsKashidaLine(sal_Int32 nCharIdx) const
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
for (size_t i = 0; i < aNoKashidaLine.size(); ++i)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
if (nCharIdx >= aNoKashidaLine[ i ] && nCharIdx < aNoKashidaLineEnd[ i ])
|
|
|
|
return false;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
2014-01-13 14:18:14 +00:00
|
|
|
return true;
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
void SwScriptInfo::ClearNoKashidaLine(sal_Int32 nStt, sal_Int32 nLen)
|
2002-06-20 08:44:17 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t i = 0;
|
|
|
|
while( i < aNoKashidaLine.size())
|
|
|
|
{
|
|
|
|
if( nStt + nLen >= aNoKashidaLine[ i ] && nStt < aNoKashidaLineEnd [ i ] )
|
|
|
|
{
|
|
|
|
aNoKashidaLine.erase(aNoKashidaLine.begin() + i);
|
|
|
|
aNoKashidaLineEnd.erase(aNoKashidaLineEnd.begin() + i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++i;
|
|
|
|
}
|
2009-01-05 15:33:41 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// mark the given character indices as invalid kashida positions
|
2017-06-08 12:03:12 +02:00
|
|
|
bool SwScriptInfo::MarkKashidasInvalid(sal_Int32 nCnt, const sal_Int32* pKashidaPositions)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
SAL_WARN_IF( !pKashidaPositions || nCnt == 0, "sw.core", "Where are kashidas?" );
|
2009-01-05 15:33:41 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
size_t nCntKash = 0;
|
|
|
|
sal_Int32 nKashidaPosIdx = 0;
|
2009-01-05 15:33:41 +00:00
|
|
|
|
2014-01-13 14:18:14 +00:00
|
|
|
while (nCntKash < CountKashida() && nKashidaPosIdx < nCnt)
|
2009-01-05 15:33:41 +00:00
|
|
|
{
|
2014-01-13 14:18:14 +00:00
|
|
|
if ( pKashidaPositions [nKashidaPosIdx] > GetKashida( nCntKash ) )
|
|
|
|
{
|
|
|
|
++nCntKash;
|
|
|
|
continue;
|
|
|
|
}
|
2009-01-05 15:33:41 +00:00
|
|
|
|
2014-01-26 18:32:50 +01:00
|
|
|
if ( pKashidaPositions [nKashidaPosIdx] != GetKashida( nCntKash ) || !IsKashidaValid ( nCntKash ) )
|
2014-01-13 14:18:14 +00:00
|
|
|
return false; // something is wrong
|
2014-01-26 18:32:50 +01:00
|
|
|
|
|
|
|
MarkKashidaInvalid ( nCntKash );
|
2014-01-13 14:18:14 +00:00
|
|
|
nKashidaPosIdx++;
|
|
|
|
}
|
|
|
|
return true;
|
2002-06-20 08:44:17 +00:00
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
sal_Int32 SwScriptInfo::ThaiJustify( const OUString& rText, long* pKernArray,
|
2014-07-18 18:21:12 +02:00
|
|
|
long* pScrArray, sal_Int32 nStt,
|
|
|
|
sal_Int32 nLen, sal_Int32 nNumberOfBlanks,
|
|
|
|
long nSpaceAdd )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
SAL_WARN_IF( nStt + nLen > rText.getLength(), "sw.core", "String in ThaiJustify too small" );
|
2002-05-06 14:05:54 +00:00
|
|
|
|
2005-04-18 13:37:24 +00:00
|
|
|
SwTwips nNumOfTwipsToDistribute = nSpaceAdd * nNumberOfBlanks /
|
|
|
|
SPACING_PRECISION_FACTOR;
|
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
long nSpaceSum = 0;
|
2012-05-02 22:40:44 +01:00
|
|
|
sal_Int32 nCnt = 0;
|
2002-05-02 07:04:29 +00:00
|
|
|
|
2012-05-02 22:40:44 +01:00
|
|
|
for (sal_Int32 nI = 0; nI < nLen; ++nI)
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const sal_Unicode cCh = rText[nStt + nI];
|
2002-05-02 07:04:29 +00:00
|
|
|
|
|
|
|
// check if character is not above or below base
|
|
|
|
if ( ( 0xE34 > cCh || cCh > 0xE3A ) &&
|
2002-05-06 14:05:54 +00:00
|
|
|
( 0xE47 > cCh || cCh > 0xE4E ) && cCh != 0xE31 )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2005-04-18 13:37:24 +00:00
|
|
|
if ( nNumberOfBlanks > 0 )
|
|
|
|
{
|
|
|
|
nSpaceAdd = nNumOfTwipsToDistribute / nNumberOfBlanks;
|
|
|
|
--nNumberOfBlanks;
|
|
|
|
nNumOfTwipsToDistribute -= nSpaceAdd;
|
|
|
|
}
|
|
|
|
nSpaceSum += nSpaceAdd;
|
2002-05-02 07:04:29 +00:00
|
|
|
++nCnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
|
|
|
|
if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nCnt;
|
|
|
|
}
|
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTextNode& rTNd,
|
2014-02-15 11:40:16 +01:00
|
|
|
bool bAllowInvalid )
|
2002-12-02 09:30:44 +00:00
|
|
|
{
|
2015-11-25 06:03:10 -05:00
|
|
|
SwIterator<SwTextFrame,SwTextNode> aIter( rTNd );
|
2015-11-10 10:25:48 +01:00
|
|
|
SwScriptInfo* pScriptInfo = nullptr;
|
2002-12-02 09:30:44 +00:00
|
|
|
|
2015-11-25 06:03:10 -05:00
|
|
|
for( SwTextFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
|
2002-12-02 09:30:44 +00:00
|
|
|
{
|
2015-03-26 15:31:55 +01:00
|
|
|
pScriptInfo = const_cast<SwScriptInfo*>(pLast->GetScriptInfo());
|
2014-01-26 17:25:33 +01:00
|
|
|
if ( pScriptInfo )
|
|
|
|
{
|
2014-01-26 18:32:50 +01:00
|
|
|
if ( bAllowInvalid || COMPLETE_STRING == pScriptInfo->GetInvalidityA() )
|
|
|
|
break;
|
2015-11-10 10:25:48 +01:00
|
|
|
pScriptInfo = nullptr;
|
2002-12-02 09:30:44 +00:00
|
|
|
}
|
2014-01-26 17:25:33 +01:00
|
|
|
}
|
2002-12-02 09:30:44 +00:00
|
|
|
|
|
|
|
return pScriptInfo;
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
SwParaPortion::SwParaPortion()
|
|
|
|
{
|
|
|
|
FormatReset();
|
2015-11-13 09:06:48 +01:00
|
|
|
m_bFlys = m_bFootnoteNum = m_bMargin = false;
|
2000-09-18 23:08:29 +00:00
|
|
|
SetWhichPor( POR_PARA );
|
|
|
|
}
|
|
|
|
|
2006-01-10 12:40:07 +00:00
|
|
|
SwParaPortion::~SwParaPortion()
|
|
|
|
{
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 SwParaPortion::GetParLen() const
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nLen = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
const SwLineLayout *pLay = this;
|
|
|
|
while( pLay )
|
|
|
|
{
|
2014-01-26 19:17:41 +01:00
|
|
|
nLen += pLay->GetLen();
|
2000-09-18 23:08:29 +00:00
|
|
|
pLay = pLay->GetNext();
|
|
|
|
}
|
|
|
|
return nLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwDropPortion *SwParaPortion::FindDropPortion() const
|
|
|
|
{
|
|
|
|
const SwLineLayout *pLay = this;
|
|
|
|
while( pLay && pLay->IsDummy() )
|
|
|
|
pLay = pLay->GetNext();
|
|
|
|
while( pLay )
|
|
|
|
{
|
|
|
|
const SwLinePortion *pPos = pLay->GetPortion();
|
|
|
|
while ( pPos && !pPos->GetLen() )
|
|
|
|
pPos = pPos->GetPortion();
|
|
|
|
if( pPos && pPos->IsDropPortion() )
|
2014-11-21 14:36:31 +02:00
|
|
|
return static_cast<const SwDropPortion *>(pPos);
|
2015-11-10 10:25:48 +01:00
|
|
|
pLay = pLay->GetLen() ? nullptr : pLay->GetNext();
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2015-11-10 10:25:48 +01:00
|
|
|
return nullptr;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SwLineLayout::Init( SwLinePortion* pNextPortion )
|
|
|
|
{
|
|
|
|
Height( 0 );
|
|
|
|
Width( 0 );
|
|
|
|
SetLen( 0 );
|
|
|
|
SetAscent( 0 );
|
2001-08-30 10:47:34 +00:00
|
|
|
SetRealHeight( 0 );
|
2000-09-18 23:08:29 +00:00
|
|
|
SetPortion( pNextPortion );
|
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// looks for hanging punctuation portions in the paragraph
|
|
|
|
// and return the maximum right offset of them.
|
|
|
|
// If no such portion is found, the Margin/Hanging-flags will be updated.
|
2016-04-22 10:08:07 +02:00
|
|
|
SwTwips SwLineLayout::GetHangingMargin_() const
|
2000-11-21 10:29:48 +00:00
|
|
|
{
|
|
|
|
SwLinePortion* pPor = GetPortion();
|
2012-12-06 20:59:29 +09:00
|
|
|
bool bFound = false;
|
2000-11-21 10:29:48 +00:00
|
|
|
SwTwips nDiff = 0;
|
|
|
|
while( pPor)
|
|
|
|
{
|
|
|
|
if( pPor->IsHangingPortion() )
|
|
|
|
{
|
2014-11-21 14:36:31 +02:00
|
|
|
nDiff = static_cast<SwHangingPortion*>(pPor)->GetInnerWidth() - pPor->Width();
|
2000-11-21 10:29:48 +00:00
|
|
|
if( nDiff )
|
2012-12-06 20:59:29 +09:00
|
|
|
bFound = true;
|
2000-11-21 10:29:48 +00:00
|
|
|
}
|
2001-11-27 12:49:52 +00:00
|
|
|
// the last post its portion
|
|
|
|
else if ( pPor->IsPostItsPortion() && ! pPor->GetPortion() )
|
|
|
|
nDiff = nAscent;
|
|
|
|
|
2000-11-21 10:29:48 +00:00
|
|
|
pPor = pPor->GetPortion();
|
|
|
|
}
|
2012-06-05 13:57:00 +02:00
|
|
|
if( !bFound ) // update the hanging-flag
|
2014-11-24 10:39:29 +02:00
|
|
|
const_cast<SwLineLayout*>(this)->SetHanging( false );
|
2000-11-21 10:29:48 +00:00
|
|
|
return nDiff;
|
|
|
|
}
|
|
|
|
|
2015-11-25 06:03:10 -05:00
|
|
|
SwTwips SwTextFrame::HangingMargin() const
|
2000-11-21 10:29:48 +00:00
|
|
|
{
|
2012-06-08 13:15:12 +02:00
|
|
|
SAL_WARN_IF( !HasPara(), "sw.core", "Don't call me without a paraportion" );
|
2000-11-21 10:29:48 +00:00
|
|
|
if( !GetPara()->IsMargin() )
|
|
|
|
return 0;
|
|
|
|
const SwLineLayout* pLine = GetPara();
|
|
|
|
SwTwips nRet = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SwTwips nDiff = pLine->GetHangingMargin();
|
|
|
|
if( nDiff > nRet )
|
|
|
|
nRet = nDiff;
|
|
|
|
pLine = pLine->GetNext();
|
|
|
|
} while ( pLine );
|
2012-06-05 13:57:00 +02:00
|
|
|
if( !nRet ) // update the margin-flag
|
2014-11-24 10:39:29 +02:00
|
|
|
const_cast<SwParaPortion*>(GetPara())->SetMargin( false );
|
2000-11-21 10:29:48 +00:00
|
|
|
return nRet;
|
|
|
|
}
|
2004-02-26 14:32:29 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelection &rHiddenMulti)
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
assert((rNode.GetText().isEmpty() && rHiddenMulti.GetTotalRange().Len() == 1)
|
|
|
|
|| (rNode.GetText().getLength() == rHiddenMulti.GetTotalRange().Len()));
|
2012-08-03 10:54:11 +01:00
|
|
|
|
2015-11-10 10:25:48 +01:00
|
|
|
const SfxPoolItem* pItem = nullptr;
|
2014-09-10 17:53:41 +02:00
|
|
|
if( SfxItemState::SET == rNode.GetSwAttrSet().GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) &&
|
2014-11-21 14:36:31 +02:00
|
|
|
static_cast<const SvxCharHiddenItem*>(pItem)->GetValue() )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
rHiddenMulti.SelectAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwpHints* pHints = rNode.GetpSwpHints();
|
|
|
|
|
|
|
|
if( pHints )
|
|
|
|
{
|
2015-08-27 16:38:21 +02:00
|
|
|
for( size_t nTmp = 0; nTmp < pHints->Count(); ++nTmp )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2015-08-27 16:38:21 +02:00
|
|
|
const SwTextAttr* pTextAttr = pHints->Get( nTmp );
|
2012-08-03 09:07:14 +01:00
|
|
|
const SvxCharHiddenItem* pHiddenItem =
|
2015-05-20 13:05:49 +02:00
|
|
|
static_cast<const SvxCharHiddenItem*>( CharFormat::GetItem( *pTextAttr, RES_CHRATR_HIDDEN ) );
|
2007-09-27 08:17:13 +00:00
|
|
|
if( pHiddenItem )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const sal_Int32 nSt = pTextAttr->GetStart();
|
|
|
|
const sal_Int32 nEnd = *pTextAttr->End();
|
2004-02-26 14:32:29 +00:00
|
|
|
if( nEnd > nSt )
|
|
|
|
{
|
|
|
|
Range aTmp( nSt, nEnd - 1 );
|
2007-09-27 08:17:13 +00:00
|
|
|
rHiddenMulti.Select( aTmp, pHiddenItem->GetValue() );
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 09:07:14 +01:00
|
|
|
}
|
2004-02-26 14:32:29 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwScriptInfo::selectRedLineDeleted(const SwTextNode& rNode, MultiSelection &rHiddenMulti, bool bSelect)
|
2012-08-03 09:07:14 +01:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
assert((rNode.GetText().isEmpty() && rHiddenMulti.GetTotalRange().Len() == 1)
|
|
|
|
|| (rNode.GetText().getLength() == rHiddenMulti.GetTotalRange().Len()));
|
2012-08-03 10:54:11 +01:00
|
|
|
|
2015-07-03 11:31:14 +02:00
|
|
|
const IDocumentRedlineAccess& rIDRA = rNode.getIDocumentRedlineAccess();
|
2016-09-07 13:10:40 +02:00
|
|
|
if ( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
Complete the transition of SwRedlineTable::size_type
...from 9ca8a63fff65acf2ea13b391495ad232f4636548 "Use consistent integer types
in the SwRedlineTable interface". This all started as an attempt to reduce the
number of places a to-be-committed improved loplugin:loopvartoosmall complains
about. Lets see where it ends...
SwRedlineTable::size_type is now the size_type of the underlying std::vector, no
longer sal_uInt16 from ancient times. I tried hard to find all places that are
affected by this change, changing types of affected variables and non-static
data members as needed. Some notes:
* The original code used USHRT_MAX as a "not found" value. I replaced that with
a new SwRedlineTable::npos, of type SwRedlineTable::size_type but still for
now of value USHRT_MAX. This should eventually be changed to something more
sensible, like std::numeric_limits<SwRedlineTable::size_type>::max() (which is
best done after we have constexpr support in all toolchains, so that npos can
be constexpr). It is important that the value of npos is towards positive
infinity, as many places in the code use
for (i = f(); // may return npos
i < table.size(); ++i)
table[i] ...
* There are some borders where values of SwRedlineTable::size_type are converted
into different types, for various reasons. But all of those other types
should be large enough for practical purposes (at least 32 bits wide):
MakrEntry::m_nIdx: long int
SvxRedlinTable::InsertEntry: sal_uIntPtr nPos
SwRangeRedline: size_t
SwRedlineItr: sal_Int32
SwVbaRevision::GetPosition: sal_Int32
SwXRedlines: sal_Int32
* .uno:TrackedChangeIndex= transports textual representations of such values.
libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx treats them purely as
strings, while SwTiledRenderingTest converts them to int.
* TODO: The one place I'm unsure about is SfxUInt16Items with IDs
FN_REDLINE_ACCEPT_DIRECT, FN_REDLINE_REJECT_DIRECT, and FN_REDLINE_NEXT_CHANGE
in sw/source/uibase/uiview/view2.cxx. For now, I kept those as
SfxUInt16Items and take care to "map" USHRT_MAX to npos when reading from
those items. But I have no idea where instances of those items would actually
be created, and what it would mean to change those items' types?
Change-Id: Ib7a14dc67e2b970766966e43f4732abd9f045ff8
Reviewed-on: https://gerrit.libreoffice.org/34775
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2017-03-02 08:35:18 +01:00
|
|
|
SwRedlineTable::size_type nAct = rIDRA.GetRedlinePos( rNode, USHRT_MAX );
|
2004-02-26 14:32:29 +00:00
|
|
|
|
2015-05-20 13:05:49 +02:00
|
|
|
for ( ; nAct < rIDRA.GetRedlineTable().size(); nAct++ )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2015-05-20 13:05:49 +02:00
|
|
|
const SwRangeRedline* pRed = rIDRA.GetRedlineTable()[ nAct ];
|
2004-02-26 14:32:29 +00:00
|
|
|
|
2014-11-03 09:49:37 +00:00
|
|
|
if (pRed->Start()->nNode > rNode.GetIndex())
|
2004-02-26 14:32:29 +00:00
|
|
|
break;
|
|
|
|
|
2014-11-03 09:49:37 +00:00
|
|
|
if (pRed->GetType() != nsRedlineType_t::REDLINE_DELETE)
|
|
|
|
continue;
|
|
|
|
|
2014-01-14 16:50:42 +00:00
|
|
|
sal_Int32 nRedlStart;
|
|
|
|
sal_Int32 nRedlnEnd;
|
2004-02-26 14:32:29 +00:00
|
|
|
pRed->CalcStartEnd( rNode.GetIndex(), nRedlStart, nRedlnEnd );
|
2012-08-03 10:54:11 +01:00
|
|
|
//clip it if the redline extends past the end of the nodes text
|
2015-05-20 13:05:49 +02:00
|
|
|
nRedlnEnd = std::min<sal_Int32>(nRedlnEnd, rNode.GetText().getLength());
|
2004-02-26 14:32:29 +00:00
|
|
|
if ( nRedlnEnd > nRedlStart )
|
|
|
|
{
|
|
|
|
Range aTmp( nRedlStart, nRedlnEnd - 1 );
|
2012-08-03 09:07:14 +01:00
|
|
|
rHiddenMulti.Select( aTmp, bSelect );
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 09:07:14 +01:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:13 -04:00
|
|
|
// Returns a MultiSection indicating the hidden ranges.
|
2015-05-20 13:05:49 +02:00
|
|
|
void SwScriptInfo::CalcHiddenRanges( const SwTextNode& rNode, MultiSelection& rHiddenMulti )
|
2012-08-03 09:07:14 +01:00
|
|
|
{
|
|
|
|
selectHiddenTextProperty(rNode, rHiddenMulti);
|
|
|
|
|
|
|
|
// If there are any hidden ranges in the current text node, we have
|
|
|
|
// to unhide the redlining ranges:
|
|
|
|
selectRedLineDeleted(rNode, rHiddenMulti, false);
|
2004-02-26 14:32:29 +00:00
|
|
|
|
|
|
|
// We calculated a lot of stuff. Finally we can update the flags at the text node.
|
2014-02-25 21:01:20 +01:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
const bool bNewContainsHiddenChars = rHiddenMulti.GetRangeCount() > 0;
|
|
|
|
bool bNewHiddenCharsHidePara = false;
|
|
|
|
if ( bNewContainsHiddenChars )
|
|
|
|
{
|
|
|
|
const Range& rRange = rHiddenMulti.GetRange( 0 );
|
2014-01-14 16:50:42 +00:00
|
|
|
const sal_Int32 nHiddenStart = rRange.Min();
|
|
|
|
const sal_Int32 nHiddenEnd = rRange.Max() + 1;
|
2013-02-18 18:36:45 +01:00
|
|
|
bNewHiddenCharsHidePara =
|
2015-05-20 13:05:49 +02:00
|
|
|
(nHiddenStart == 0 && nHiddenEnd >= rNode.GetText().getLength());
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
|
|
|
|
}
|
|
|
|
|
2016-10-09 15:03:18 +08:00
|
|
|
sal_Int32 SwScriptInfo::CountCJKCharacters( const OUString &rText, sal_Int32 nPos, sal_Int32 nEnd, LanguageType aLang)
|
|
|
|
{
|
|
|
|
sal_Int32 nCount = 0;
|
2017-04-19 11:20:17 +01:00
|
|
|
if (nEnd > nPos)
|
2016-10-09 15:03:18 +08:00
|
|
|
{
|
|
|
|
sal_Int32 nDone = 0;
|
|
|
|
const lang::Locale &rLocale = g_pBreakIt->GetLocale( aLang );
|
|
|
|
while ( nPos < nEnd )
|
|
|
|
{
|
|
|
|
nPos = g_pBreakIt->GetBreakIter()->nextCharacters( rText, nPos,
|
|
|
|
rLocale,
|
|
|
|
i18n::CharacterIteratorMode::SKIPCELL, 1, nDone );
|
|
|
|
nCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nCount = nEnd - nPos ;
|
|
|
|
|
|
|
|
return nCount;
|
|
|
|
}
|
2016-10-16 11:25:04 +08:00
|
|
|
|
|
|
|
void SwScriptInfo::CJKJustify( const OUString& rText, long* pKernArray,
|
|
|
|
long* pScrArray, sal_Int32 nStt,
|
|
|
|
sal_Int32 nLen, LanguageType aLang,
|
2017-03-31 23:13:32 +08:00
|
|
|
long nSpaceAdd, bool bIsSpaceStop )
|
2016-10-16 11:25:04 +08:00
|
|
|
{
|
|
|
|
assert( pKernArray != nullptr && nStt >= 0 );
|
2017-04-19 11:20:17 +01:00
|
|
|
if (nLen > 0)
|
2016-10-16 11:25:04 +08:00
|
|
|
{
|
2017-03-31 23:13:32 +08:00
|
|
|
long nSpaceSum = 0;
|
2016-10-16 11:25:04 +08:00
|
|
|
const lang::Locale &rLocale = g_pBreakIt->GetLocale( aLang );
|
|
|
|
sal_Int32 nDone = 0;
|
2017-03-31 23:13:32 +08:00
|
|
|
sal_Int32 nNext = nStt;
|
2016-10-16 11:25:04 +08:00
|
|
|
for ( sal_Int32 nI = 0; nI < nLen ; ++nI )
|
|
|
|
{
|
|
|
|
if ( nI + nStt == nNext )
|
|
|
|
{
|
|
|
|
nNext = g_pBreakIt->GetBreakIter()->nextCharacters( rText, nNext,
|
|
|
|
rLocale,
|
|
|
|
i18n::CharacterIteratorMode::SKIPCELL, 1, nDone );
|
2017-03-31 23:13:32 +08:00
|
|
|
if (nNext < nStt + nLen || !bIsSpaceStop)
|
|
|
|
nSpaceSum += nSpaceAdd;
|
2016-10-16 11:25:04 +08:00
|
|
|
}
|
|
|
|
pKernArray[ nI ] += nSpaceSum;
|
|
|
|
if ( pScrArray )
|
|
|
|
pScrArray[ nI ] += nSpaceSum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-14 08:30:41 +02:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|