2000-09-18 23:08:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* $RCSfile: porlay.cxx,v $
|
|
|
|
*
|
2004-06-29 07:09:49 +00:00
|
|
|
* $Revision: 1.49 $
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2004-06-29 07:09:49 +00:00
|
|
|
* last change: $Author: kz $ $Date: 2004-06-29 08:09:49 $
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
|
|
|
* The Contents of this file are made available subject to the terms of
|
|
|
|
* either of the following licenses
|
|
|
|
*
|
|
|
|
* - GNU Lesser General Public License Version 2.1
|
|
|
|
* - Sun Industry Standards Source License Version 1.1
|
|
|
|
*
|
|
|
|
* Sun Microsystems Inc., October, 2000
|
|
|
|
*
|
|
|
|
* GNU Lesser General Public License Version 2.1
|
|
|
|
* =============================================
|
|
|
|
* Copyright 2000 by Sun Microsystems, Inc.
|
|
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Sun Industry Standards Source License Version 1.1
|
|
|
|
* =================================================
|
|
|
|
* The contents of this file are subject to the Sun Industry Standards
|
|
|
|
* Source License Version 1.1 (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.openoffice.org/license.html.
|
|
|
|
*
|
|
|
|
* Software provided under this License is provided on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
|
|
|
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
|
|
|
|
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
|
|
|
|
* See the License for the specific provisions governing your rights and
|
|
|
|
* obligations concerning the Software.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* Copyright: 2000 by Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): _______________________________________
|
|
|
|
*
|
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
#include "errhdl.hxx" // ASSERT
|
|
|
|
|
|
|
|
#include "txtcfg.hxx"
|
|
|
|
#include "porlay.hxx"
|
|
|
|
#include "itrform2.hxx"
|
|
|
|
#include "porglue.hxx"
|
|
|
|
#include "porexp.hxx" // SwQuoVadisPortion
|
|
|
|
#include "blink.hxx" // pBlink
|
|
|
|
#include "redlnitr.hxx" // SwRedlineItr
|
|
|
|
#include "porfly.hxx" // SwFlyCntPortion
|
2000-11-21 10:29:48 +00:00
|
|
|
#ifndef _PORRST_HXX
|
|
|
|
#include <porrst.hxx> // SwHangingPortion
|
|
|
|
#endif
|
2001-02-01 13:05:11 +00:00
|
|
|
#ifndef _PORMULTI_HXX
|
|
|
|
#include <pormulti.hxx> // SwMultiPortion
|
|
|
|
#endif
|
2001-02-20 09:27:05 +00:00
|
|
|
#ifndef _BREAKIT_HXX
|
|
|
|
#include <breakit.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
|
|
|
|
#include <com/sun/star/i18n/ScriptType.hdl>
|
|
|
|
#endif
|
2002-08-12 07:36:16 +00:00
|
|
|
#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
|
|
|
|
#include <com/sun/star/i18n/WordType.hdl>
|
|
|
|
#endif
|
2001-04-09 09:44:17 +00:00
|
|
|
#ifndef _DOC_HXX
|
|
|
|
#include <doc.hxx>
|
|
|
|
#endif
|
2002-06-26 13:38:25 +00:00
|
|
|
#ifdef BIDI
|
|
|
|
#ifndef _PARATR_HXX
|
|
|
|
#include <paratr.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _SVX_ADJITEM_HXX //autogen
|
|
|
|
#include <svx/adjitem.hxx>
|
|
|
|
#endif
|
|
|
|
#endif
|
2001-10-22 12:03:21 +00:00
|
|
|
#ifndef _SVX_SCRIPTTYPEITEM_HXX
|
|
|
|
#include <svx/scripttypeitem.hxx>
|
|
|
|
#endif
|
2004-02-26 14:32:29 +00:00
|
|
|
#ifndef _SVX_CHARHIDDENITEM_HXX
|
|
|
|
#include <svx/charhiddenitem.hxx>
|
|
|
|
#endif
|
2001-11-20 09:52:16 +00:00
|
|
|
#ifndef _SV_OUTDEV_HXX
|
|
|
|
#include <vcl/outdev.hxx>
|
|
|
|
#endif
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
#ifndef _SVX_BLNKITEM_HXX
|
|
|
|
#include <svx/blnkitem.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _SV_MULTISEL_HXX //autogen
|
|
|
|
#include <tools/multisel.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _CHARFMT_HXX //autogen
|
|
|
|
#include <charfmt.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _FCHRFMT_HXX //autogen
|
|
|
|
#include <fchrfmt.hxx>
|
|
|
|
#endif
|
|
|
|
#ifndef _DOCARY_HXX
|
|
|
|
#include <docary.hxx> // SwRedlineTbl
|
|
|
|
#endif
|
|
|
|
#ifndef _REDLINE_HXX
|
|
|
|
#include <redline.hxx> // SwRedline
|
|
|
|
#endif
|
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
using namespace ::com::sun::star;
|
2001-10-22 12:03:21 +00:00
|
|
|
using namespace ::com::sun::star::i18n::ScriptType;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2002-03-21 08:19:43 +00:00
|
|
|
#ifdef BIDI
|
|
|
|
#include <unicode/ubidi.h>
|
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* lcl_IsLigature
|
|
|
|
*
|
|
|
|
* Checks if cCh + cNectCh builds a ligature (used for Kashidas)
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh )
|
|
|
|
{
|
2002-04-10 05:43:43 +00:00
|
|
|
// Lam + Alef
|
2002-04-10 05:12:06 +00:00
|
|
|
return ( 0x644 == cCh && 0x627 == cNextCh ) ||
|
2002-04-10 05:43:43 +00:00
|
|
|
// Beh + Reh
|
2002-04-10 05:12:06 +00:00
|
|
|
( 0x628 == cCh && 0x631 == cNextCh );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* lcl_ConnectToPrev
|
|
|
|
*
|
|
|
|
* Checks if cCh is connectable to cPrevCh (used for Kashidas)
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh )
|
|
|
|
{
|
|
|
|
// Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
|
2003-04-24 08:52:10 +00:00
|
|
|
// Uh, there seem to be some more characters that are not connectable
|
|
|
|
// to the left. So we look for the characters that are actually connectable
|
|
|
|
// to the left. Here is the complete list of WH:
|
|
|
|
sal_Bool bRet = 0x628 == cPrevCh ||
|
|
|
|
( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) ||
|
|
|
|
( 0x633 <= cPrevCh && cPrevCh <= 0x643 ) ||
|
|
|
|
( 0x645 <= cPrevCh && cPrevCh <= 0x647 ) ||
|
|
|
|
0x64A == cPrevCh ||
|
|
|
|
( 0x678 <= cPrevCh && cPrevCh <= 0x687 ) ||
|
|
|
|
( 0x69A <= cPrevCh && cPrevCh <= 0x6B4 ) ||
|
|
|
|
( 0x6B9 <= cPrevCh && cPrevCh <= 0x6C0 ) ||
|
|
|
|
( 0x6C3 <= cPrevCh && cPrevCh <= 0x6D3 );
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// check for ligatures cPrevChar + cChar
|
|
|
|
if ( bRet )
|
|
|
|
bRet = ! lcl_IsLigature( cPrevCh, cCh );
|
2002-03-21 08:19:43 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
return bRet;
|
|
|
|
}
|
2002-03-21 08:19:43 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwLineLayout::~SwLineLayout()
|
|
|
|
*
|
|
|
|
* class SwLineLayout: Das Layout einer einzelnen Zeile. Dazu
|
|
|
|
* gehoeren vor allen Dingen die Dimension, die Anzahl der
|
|
|
|
* Character und der Wortzwischenraeume in der Zeile.
|
|
|
|
* Zeilenobjekte werden in einem eigenen Pool verwaltet, um zu
|
|
|
|
* erreichen, dass sie im Speicher moeglichst beeinander liegen
|
|
|
|
* (d.h. zusammen gepaged werden und den Speicher nicht
|
|
|
|
* fragmentieren).
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
SwLineLayout::~SwLineLayout()
|
|
|
|
{
|
|
|
|
Truncate();
|
|
|
|
if( GetNext() )
|
|
|
|
delete GetNext();
|
|
|
|
if( pBlink )
|
|
|
|
pBlink->Delete( this );
|
|
|
|
delete pSpaceAdd;
|
2001-04-09 09:44:17 +00:00
|
|
|
if ( pKanaComp )
|
|
|
|
delete pKanaComp;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* virtual SwLineLayout::Insert()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
SwLinePortion *SwLineLayout::Insert( SwLinePortion *pIns )
|
|
|
|
{
|
|
|
|
// Erster Attributwechsel, Masse und Laengen
|
|
|
|
// aus *pCurr in die erste Textportion kopieren.
|
|
|
|
if( !pPortion )
|
|
|
|
{
|
|
|
|
if( GetLen() )
|
|
|
|
{
|
|
|
|
pPortion = new SwTxtPortion( *(SwLinePortion*)this );
|
|
|
|
if( IsBlinking() && pBlink )
|
|
|
|
{
|
|
|
|
SetBlinking( sal_False );
|
|
|
|
pBlink->Replace( this, pPortion );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetPortion( pIns );
|
|
|
|
return pIns;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// mit Skope aufrufen, sonst Rekursion !
|
|
|
|
return pPortion->SwLinePortion::Insert( pIns );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* virtual SwLineLayout::Append()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
SwLinePortion *SwLineLayout::Append( SwLinePortion *pIns )
|
|
|
|
{
|
|
|
|
// Erster Attributwechsel, Masse und Laengen
|
|
|
|
// aus *pCurr in die erste Textportion kopieren.
|
|
|
|
if( !pPortion )
|
|
|
|
pPortion = new SwTxtPortion( *(SwLinePortion*)this );
|
|
|
|
// mit Skope aufrufen, sonst Rekursion !
|
|
|
|
return pPortion->SwLinePortion::Append( pIns );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* virtual SwLineLayout::Format()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
// fuer die Sonderbehandlung bei leeren Zeilen
|
|
|
|
|
|
|
|
sal_Bool SwLineLayout::Format( SwTxtFormatInfo &rInf )
|
|
|
|
{
|
|
|
|
if( GetLen() )
|
|
|
|
return SwTxtPortion::Format( rInf );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Height( rInf.GetTxtHeight() );
|
|
|
|
return sal_True;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwLineLayout::CalcLeftMargin()
|
|
|
|
*
|
|
|
|
* Wir sammeln alle FlyPortions am Anfang der Zeile zu einer MarginPortion.
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
SwMarginPortion *SwLineLayout::CalcLeftMargin()
|
|
|
|
{
|
|
|
|
SwMarginPortion *pLeft = (GetPortion() && GetPortion()->IsMarginPortion()) ?
|
|
|
|
(SwMarginPortion *)GetPortion() : 0;
|
|
|
|
if( !GetPortion() )
|
|
|
|
SetPortion( new SwTxtPortion( *(SwLinePortion*)this ) );
|
|
|
|
if( !pLeft )
|
|
|
|
{
|
|
|
|
pLeft = new SwMarginPortion( 0 );
|
|
|
|
pLeft->SetPortion( GetPortion() );
|
|
|
|
SetPortion( pLeft );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pLeft->Height( 0 );
|
|
|
|
pLeft->Width( 0 );
|
|
|
|
pLeft->SetLen( 0 );
|
|
|
|
pLeft->SetAscent( 0 );
|
|
|
|
pLeft->SetPortion( NULL );
|
|
|
|
pLeft->SetFixWidth(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SwLinePortion *pPos = pLeft->GetPortion();
|
|
|
|
while( pPos )
|
|
|
|
{
|
|
|
|
DBG_LOOP;
|
|
|
|
if( pPos->IsFlyPortion() )
|
|
|
|
{
|
|
|
|
// Die FlyPortion wird ausgesogen ...
|
|
|
|
pLeft->Join( (SwGluePortion*)pPos );
|
|
|
|
pPos = pLeft->GetPortion();
|
2001-04-09 09:44:17 +00:00
|
|
|
if( GetpKanaComp() )
|
|
|
|
GetKanaComp().Remove( 0, 1 );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
pPos = 0;
|
|
|
|
}
|
|
|
|
return pLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwLineLayout::CreateSpaceAdd()
|
|
|
|
*************************************************************************/
|
|
|
|
|
2001-04-12 11:42:30 +00:00
|
|
|
void SwLineLayout::CreateSpaceAdd( const short nInit )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
pSpaceAdd = new SvShorts;
|
2001-04-12 11:42:30 +00:00
|
|
|
pSpaceAdd->Insert( nInit, 0 );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwLineLayout::CalcLine()
|
|
|
|
*
|
|
|
|
* Aus FormatLine() ausgelagert.
|
|
|
|
*************************************************************************/
|
|
|
|
|
2000-12-21 08:10:30 +00:00
|
|
|
void SwLineLayout::CalcLine( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const KSHORT nLineWidth = rInf.RealWidth();
|
|
|
|
|
|
|
|
KSHORT nFlyAscent;
|
|
|
|
KSHORT nFlyHeight;
|
|
|
|
KSHORT nFlyDescent;
|
|
|
|
sal_Bool bOnlyPostIts = sal_True;
|
2000-11-21 10:29:48 +00:00
|
|
|
SetHanging( sal_False );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
sal_Bool bTmpDummy = ( 0 == GetLen() );
|
|
|
|
SwFlyCntPortion* pFlyCnt = 0;
|
|
|
|
if( bTmpDummy )
|
|
|
|
{
|
|
|
|
nFlyAscent = 0;
|
|
|
|
nFlyHeight = 0;
|
|
|
|
nFlyDescent = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pPortion )
|
|
|
|
{
|
|
|
|
SetCntnt( sal_False );
|
|
|
|
if( pPortion->IsBreakPortion() )
|
|
|
|
{
|
|
|
|
SetLen( pPortion->GetLen() );
|
|
|
|
if( GetLen() )
|
|
|
|
bTmpDummy = sal_False;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Init( GetPortion() );
|
|
|
|
SwLinePortion *pPos = pPortion;
|
|
|
|
SwLinePortion *pLast = this;
|
|
|
|
KSHORT nMaxDescent = 0;
|
|
|
|
|
|
|
|
// Eine Gruppe ist ein Abschnitt in der Portion-Kette von
|
|
|
|
// pCurr oder einer Fix-Portion bis zum Ende bzw. zur naechsten
|
|
|
|
// Fix-Portion.
|
|
|
|
while( pPos )
|
|
|
|
{
|
|
|
|
DBG_LOOP;
|
|
|
|
ASSERT( POR_LIN != pPos->GetWhichPor(),
|
|
|
|
"SwLineLayout::CalcLine: don't use SwLinePortions !" );
|
|
|
|
// Null-Portions werden eliminiert. Sie koennen entstehen,
|
|
|
|
// wenn zwei FlyFrms ueberlappen.
|
|
|
|
if( !pPos->Compress() )
|
|
|
|
{
|
|
|
|
// 8110: Hoehe und Ascent nur uebernehmen, wenn sonst in der
|
|
|
|
// Zeile nichts mehr los ist.
|
|
|
|
if( !pPos->GetPortion() )
|
|
|
|
{
|
|
|
|
if( !Height() )
|
|
|
|
Height( pPos->Height() );
|
|
|
|
if( !GetAscent() )
|
|
|
|
SetAscent( pPos->GetAscent() );
|
|
|
|
}
|
|
|
|
delete pLast->Cut( pPos );
|
|
|
|
pPos = pLast->GetPortion();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Es gab Attributwechsel: Laengen und Masse aufaddieren;
|
|
|
|
// bzw.Maxima bilden.
|
|
|
|
|
|
|
|
nLineLength += pPos->GetLen();
|
2002-01-31 13:31:03 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
KSHORT nPosHeight = pPos->Height();
|
|
|
|
KSHORT nPosAscent = pPos->GetAscent();
|
|
|
|
AddPrtWidth( pPos->Width() );
|
|
|
|
|
|
|
|
ASSERT( nPosHeight >= nPosAscent,
|
|
|
|
"SwLineLayout::CalcLine: bad ascent or height" );
|
2000-11-21 10:29:48 +00:00
|
|
|
if( pPos->IsHangingPortion() )
|
|
|
|
{
|
|
|
|
SetHanging( sal_True );
|
|
|
|
rInf.GetParaPortion()->SetMargin( sal_True );
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
// Damit ein Paragraphende-Zeichen nicht durch ein Descent zu einer
|
|
|
|
// geaenderten Zeilenhoehe und zum Umformatieren fuehrt.
|
|
|
|
if ( !pPos->IsBreakPortion() || !Height() )
|
|
|
|
{
|
|
|
|
bOnlyPostIts &= pPos->IsPostItsPortion();
|
|
|
|
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() )
|
|
|
|
{
|
|
|
|
KSHORT 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 )
|
|
|
|
Height( nPosHeight );
|
2001-02-01 13:05:11 +00:00
|
|
|
if( pPos->IsFlyCntPortion() || ( pPos->IsMultiPortion()
|
|
|
|
&& ((SwMultiPortion*)pPos)->HasFlyInCntnt() ) )
|
2000-09-18 23:08:29 +00:00
|
|
|
rLine.SetFlyInCntBase();
|
|
|
|
if( pPos->IsFlyCntPortion() &&
|
|
|
|
((SwFlyCntPortion*)pPos)->GetAlign() )
|
|
|
|
{
|
|
|
|
((SwFlyCntPortion*)pPos)->SetMax( sal_False );
|
|
|
|
if( !pFlyCnt || pPos->Height() > pFlyCnt->Height() )
|
|
|
|
pFlyCnt = (SwFlyCntPortion*)pPos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( nAscent < nPosAscent )
|
|
|
|
nAscent = nPosAscent;
|
|
|
|
if( nMaxDescent < nPosHeight - nPosAscent )
|
|
|
|
nMaxDescent = nPosHeight - nPosAscent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( pPos->GetLen() )
|
|
|
|
bTmpDummy = sal_False;
|
|
|
|
if( !HasCntnt() && !pPos->InNumberGrp() )
|
|
|
|
{
|
|
|
|
if ( pPos->InExpGrp() )
|
|
|
|
{
|
|
|
|
XubString aTxt;
|
|
|
|
if( pPos->GetExpTxt( rInf, aTxt ) && aTxt.Len() )
|
|
|
|
SetCntnt( sal_True );
|
|
|
|
}
|
2001-11-19 10:14:15 +00:00
|
|
|
else if( ( pPos->InTxtGrp() || pPos->IsMultiPortion() ) &&
|
|
|
|
pPos->GetLen() )
|
2000-09-18 23:08:29 +00:00
|
|
|
SetCntnt( sal_True );
|
|
|
|
}
|
|
|
|
bTmpDummy = bTmpDummy && !HasCntnt() &&
|
|
|
|
( !pPos->Width() || pPos->IsFlyPortion() );
|
|
|
|
|
|
|
|
pLast = pPos;
|
|
|
|
pPos = pPos->GetPortion();
|
|
|
|
}
|
|
|
|
if( pFlyCnt )
|
|
|
|
{
|
|
|
|
if( pFlyCnt->Height() == Height() )
|
|
|
|
{
|
|
|
|
pFlyCnt->SetMax( sal_True );
|
|
|
|
if( Height() > nMaxDescent + nAscent )
|
|
|
|
{
|
|
|
|
if( 3 == pFlyCnt->GetAlign() ) // Bottom
|
|
|
|
nAscent = Height() - nMaxDescent;
|
|
|
|
else if( 2 == pFlyCnt->GetAlign() ) // Center
|
|
|
|
nAscent = ( Height() + nAscent - nMaxDescent ) / 2;
|
|
|
|
}
|
|
|
|
pFlyCnt->SetAscent( nAscent );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( bTmpDummy && nFlyHeight )
|
|
|
|
{
|
|
|
|
nAscent = nFlyAscent;
|
|
|
|
if( nFlyDescent > nFlyHeight - nFlyAscent )
|
|
|
|
Height( nFlyHeight + nFlyDescent );
|
|
|
|
else
|
|
|
|
Height( nFlyHeight );
|
|
|
|
}
|
|
|
|
else if( nMaxDescent > Height() - nAscent )
|
|
|
|
Height( nMaxDescent + nAscent );
|
|
|
|
if( bOnlyPostIts )
|
|
|
|
{
|
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
|
|
|
|
SetCntnt( !bTmpDummy );
|
|
|
|
// Robust:
|
|
|
|
if( nLineWidth < Width() )
|
|
|
|
Width( nLineWidth );
|
|
|
|
ASSERT( nLineWidth >= Width(), "SwLineLayout::CalcLine: line is bursting" );
|
|
|
|
SetDummy( bTmpDummy );
|
|
|
|
SetRedline( rLine.GetRedln() &&
|
|
|
|
rLine.GetRedln()->CheckLine( rLine.GetStart(), rLine.GetEnd() ) );
|
|
|
|
}
|
|
|
|
|
2004-02-26 16:00:32 +00:00
|
|
|
void SwLineLayout::MaxAscentDescent( SwTwips& _orAscent,
|
|
|
|
SwTwips& _orDescent,
|
|
|
|
SwTwips& _orObjAscent,
|
|
|
|
SwTwips& _orObjDescent,
|
|
|
|
const SwLinePortion* _pDontConsiderPortion ) const
|
|
|
|
{
|
|
|
|
_orAscent = 0;
|
|
|
|
_orDescent = 0;
|
|
|
|
_orObjAscent = 0;
|
|
|
|
_orObjDescent = 0;
|
|
|
|
|
|
|
|
const SwLinePortion* pPortion = this;
|
|
|
|
if ( !pPortion->GetLen() && pPortion->GetPortion() )
|
|
|
|
{
|
|
|
|
pPortion = pPortion->GetPortion();
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( pPortion )
|
|
|
|
{
|
|
|
|
if ( !pPortion->IsBreakPortion() && !pPortion->IsFlyPortion() )
|
|
|
|
{
|
|
|
|
SwTwips nPortionAsc = static_cast<SwTwips>(pPortion->GetAscent());
|
|
|
|
SwTwips nPortionDesc = static_cast<SwTwips>(pPortion->Height()) -
|
|
|
|
nPortionAsc;
|
|
|
|
|
|
|
|
sal_Bool bFlyCmp = pPortion->IsFlyCntPortion()
|
|
|
|
? static_cast<const SwFlyCntPortion*>(pPortion)->IsMax()
|
|
|
|
: ( pPortion != _pDontConsiderPortion );
|
|
|
|
if ( bFlyCmp )
|
|
|
|
{
|
|
|
|
_orObjAscent = Max( _orObjAscent, nPortionAsc );
|
|
|
|
_orObjDescent = Max( _orObjDescent, nPortionDesc );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !pPortion->IsFlyCntPortion() && !pPortion->IsGrfNumPortion() )
|
|
|
|
{
|
|
|
|
_orAscent = Max( _orAscent, nPortionAsc );
|
|
|
|
_orDescent = Max( _orDescent, nPortionDesc );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pPortion = pPortion->GetPortion();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* class SwCharRange
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2001-10-22 12:03:21 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* WhichFont()
|
|
|
|
*
|
|
|
|
* Converts i18n Script Type (LATIN, ASIAN, COMPLEX, WEAK) to
|
|
|
|
* Sw Script Types (SW_LATIN, SW_CJK, SW_CTL), used to identify the font
|
|
|
|
*************************************************************************/
|
|
|
|
|
2003-10-30 09:20:01 +00:00
|
|
|
BYTE SwScriptInfo::WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI )
|
2001-10-22 12:03:21 +00:00
|
|
|
{
|
|
|
|
ASSERT( pTxt || pSI,"How should I determine the script type?" );
|
|
|
|
USHORT nScript;
|
|
|
|
|
|
|
|
// First we try to use our SwScriptInfo
|
|
|
|
if ( pSI )
|
|
|
|
nScript = pSI->ScriptType( nIdx );
|
|
|
|
else
|
|
|
|
// Ok, we have to ask the break iterator
|
|
|
|
nScript = pBreakIt->GetRealScriptOfText( *pTxt, nIdx );
|
|
|
|
|
|
|
|
switch ( nScript ) {
|
|
|
|
case i18n::ScriptType::LATIN : return SW_LATIN;
|
|
|
|
case i18n::ScriptType::ASIAN : return SW_CJK;
|
|
|
|
case i18n::ScriptType::COMPLEX : return SW_CTL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT( sal_False, "Somebody tells lies about the script type!" );
|
|
|
|
return SW_LATIN;
|
|
|
|
}
|
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::InitScriptInfo()
|
|
|
|
*
|
|
|
|
* searches for script changes in rTxt and stores them
|
|
|
|
*************************************************************************/
|
2003-04-01 08:57:40 +00:00
|
|
|
|
|
|
|
void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode )
|
|
|
|
{
|
|
|
|
InitScriptInfo( rNode, nDefaultDir == UBIDI_RTL );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL )
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
|
|
|
if( !pBreakIt->xBreak.is() )
|
|
|
|
return;
|
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
const String& rTxt = rNode.GetTxt();
|
|
|
|
|
|
|
|
//
|
|
|
|
// HIDDEN TEXT INFORMATION
|
|
|
|
//
|
|
|
|
Range aRange( 0, rTxt.Len() ? rTxt.Len() - 1 : 0 );
|
|
|
|
MultiSelection aHiddenMulti( aRange );
|
|
|
|
CalcHiddenRanges( rNode, aHiddenMulti );
|
|
|
|
|
|
|
|
aHiddenChg.Remove( 0, aHiddenChg.Count() );
|
|
|
|
USHORT nHiddenIdx = 0;
|
2004-03-01 12:25:11 +00:00
|
|
|
USHORT i = 0;
|
|
|
|
for( i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
|
|
|
const xub_StrLen nStart = (xub_StrLen)rRange.Min();
|
|
|
|
const xub_StrLen nEnd = (xub_StrLen)rRange.Max() + 1;
|
|
|
|
|
|
|
|
aHiddenChg.Insert( nStart, nHiddenIdx++ );
|
|
|
|
aHiddenChg.Insert( nEnd, nHiddenIdx++ );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// SCRIPT AND SCRIPT RELATED INFORMATION
|
|
|
|
//
|
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
xub_StrLen nChg = nInvalidityPos;
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2001-11-20 09:52:16 +00:00
|
|
|
// STRING_LEN means the data structure is up to date
|
|
|
|
nInvalidityPos = STRING_LEN;
|
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
// this is the default direction
|
2003-04-01 08:57:40 +00:00
|
|
|
nDefaultDir = 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
|
2001-02-20 09:27:05 +00:00
|
|
|
USHORT nCnt = 0;
|
2002-06-26 13:38:25 +00:00
|
|
|
// counter for compression information arrays
|
2001-04-09 09:44:17 +00:00
|
|
|
USHORT nCntComp = 0;
|
2002-06-26 13:38:25 +00:00
|
|
|
// counter for kashida array
|
2002-04-10 05:12:06 +00:00
|
|
|
USHORT nCntKash = 0;
|
2004-02-10 13:57:23 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
BYTE nScript;
|
2001-02-20 09:27:05 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
// compression type
|
2002-06-26 13:38:25 +00:00
|
|
|
const SwCharCompressType aCompEnum = rNode.GetDoc()->GetCharCompressType();
|
|
|
|
|
|
|
|
// justification type
|
|
|
|
const sal_Bool bAdjustBlock = SVX_ADJUST_BLOCK ==
|
|
|
|
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
|
2001-02-20 09:27:05 +00:00
|
|
|
ASSERT( CountScriptChg(), "Where're my changes of script?" );
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2001-04-09 09:44:17 +00:00
|
|
|
if( CHARCOMPRESS_NONE != aCompEnum )
|
|
|
|
{
|
|
|
|
while( nCntComp < CountCompChg() )
|
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( nChg > GetCompStart( nCntComp ) )
|
2001-04-09 09:44:17 +00:00
|
|
|
nCntComp++;
|
2004-02-10 13:57:23 +00:00
|
|
|
else
|
|
|
|
break;
|
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() )
|
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( nChg > GetKashida( nCntKash ) )
|
2002-06-26 13:38:25 +00:00
|
|
|
nCntKash++;
|
2004-02-10 13:57:23 +00:00
|
|
|
else
|
|
|
|
break;
|
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
|
|
|
|
2002-06-26 13:38:25 +00:00
|
|
|
const xub_StrLen 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 &&
|
|
|
|
nScript != pBreakIt->xBreak->getScriptType( rTxt, nChg ) )
|
|
|
|
--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 )
|
|
|
|
nScript = (BYTE)pBreakIt->xBreak->getScriptType( rTxt, 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
|
|
|
|
const USHORT nScriptRemove = aScriptChg.Count() - nCnt;
|
|
|
|
aScriptChg.Remove( nCnt, nScriptRemove );
|
|
|
|
aScriptType.Remove( nCnt, nScriptRemove );
|
|
|
|
|
|
|
|
// get the start of the last compression group
|
|
|
|
USHORT nLastCompression = nChg;
|
|
|
|
if( nCntComp )
|
|
|
|
{
|
|
|
|
--nCntComp;
|
|
|
|
nLastCompression = GetCompStart( nCntComp );
|
|
|
|
if( nChg >= nLastCompression + GetCompLen( nCntComp ) )
|
|
|
|
{
|
|
|
|
nLastCompression = nChg;
|
|
|
|
++nCntComp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove invalid entries from compression information arrays
|
|
|
|
const USHORT nCompRemove = aCompChg.Count() - nCntComp;
|
|
|
|
aCompChg.Remove( nCntComp, nCompRemove );
|
|
|
|
aCompLen.Remove( nCntComp, nCompRemove );
|
|
|
|
aCompType.Remove( nCntComp, nCompRemove );
|
|
|
|
|
|
|
|
// get the start of the last kashida group
|
2003-03-27 14:45:43 +00:00
|
|
|
USHORT nLastKashida = nChg;
|
|
|
|
if( nCntKash && i18n::ScriptType::COMPLEX == nScript )
|
|
|
|
{
|
|
|
|
--nCntKash;
|
|
|
|
nLastKashida = GetKashida( nCntKash );
|
|
|
|
}
|
2002-06-26 13:38:25 +00:00
|
|
|
|
|
|
|
// remove invalid entries from kashida array
|
|
|
|
aKashida.Remove( nCntKash, aKashida.Count() - nCntKash );
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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
|
|
|
//
|
|
|
|
|
2001-11-20 09:52:16 +00:00
|
|
|
if( WEAK == pBreakIt->xBreak->getScriptType( rTxt, 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
|
|
|
|
// all of the characters in this grounp are weak. We have to assign
|
|
|
|
// the scripts to these characters depending on the fonts which are
|
|
|
|
// set for these characters to display them.
|
2001-11-20 09:52:16 +00:00
|
|
|
xub_StrLen nEnd =
|
|
|
|
(xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nChg, WEAK );
|
|
|
|
|
|
|
|
if( nEnd > rTxt.Len() )
|
|
|
|
nEnd = rTxt.Len();
|
|
|
|
|
2002-11-07 08:45:31 +00:00
|
|
|
nScript = (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
|
2001-11-20 09:52:16 +00:00
|
|
|
|
2002-08-02 14:09:42 +00:00
|
|
|
ASSERT( i18n::ScriptType::LATIN == nScript ||
|
|
|
|
i18n::ScriptType::ASIAN == nScript ||
|
|
|
|
i18n::ScriptType::COMPLEX == nScript, "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
|
|
|
|
BYTE nNextScript = ( nEnd < rTxt.Len() ) ?
|
|
|
|
(BYTE)pBreakIt->xBreak->getScriptType( rTxt, nEnd ) :
|
|
|
|
(BYTE)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
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
aScriptChg.Insert( nEnd, nCnt );
|
|
|
|
aScriptType.Insert( nScript, nCnt++ );
|
|
|
|
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
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
while ( nChg < rTxt.Len() || ( !aScriptChg.Count() && !rTxt.Len() ) )
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2001-10-22 12:03:21 +00:00
|
|
|
ASSERT( i18n::ScriptType::WEAK != nScript,
|
|
|
|
"Inserting WEAK into SwScriptInfo structure" );
|
2001-11-07 08:59:11 +00:00
|
|
|
ASSERT( STRING_LEN != nChg, "65K? Strange length of script section" );
|
|
|
|
|
2001-11-20 09:52:16 +00:00
|
|
|
nChg = (xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nChg, nScript );
|
|
|
|
|
2001-10-22 12:03:21 +00:00
|
|
|
if ( nChg > rTxt.Len() )
|
|
|
|
nChg = rTxt.Len();
|
|
|
|
|
2001-04-09 09:44:17 +00:00
|
|
|
aScriptChg.Insert( nChg, nCnt );
|
|
|
|
aScriptType.Insert( nScript, nCnt++ );
|
|
|
|
|
|
|
|
// if current script is asian, we search for compressable characters
|
|
|
|
// in this range
|
|
|
|
if ( CHARCOMPRESS_NONE != aCompEnum &&
|
|
|
|
i18n::ScriptType::ASIAN == nScript )
|
|
|
|
{
|
2001-11-20 09:52:16 +00:00
|
|
|
BYTE ePrevState = NONE;
|
|
|
|
BYTE eState;
|
2002-06-26 13:38:25 +00:00
|
|
|
USHORT 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
|
|
|
{
|
2002-06-26 13:38:25 +00:00
|
|
|
xub_Unicode cChar = rTxt.GetChar( 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
|
|
|
|
case 0x3001: case 0x3002: case 0x3009: case 0x300B:
|
|
|
|
case 0x300D: case 0x300F: case 0x3011: case 0x3015:
|
|
|
|
case 0x3017: case 0x3019: case 0x301B: case 0x301E:
|
|
|
|
case 0x301F:
|
|
|
|
eState = SPECIAL_RIGHT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
eState = ( 0x3040 <= cChar && 0x3100 > cChar ) ?
|
|
|
|
KANA :
|
|
|
|
NONE;
|
|
|
|
}
|
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
|
|
|
|
if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
|
|
|
|
ePrevState != KANA )
|
|
|
|
{
|
|
|
|
aCompChg.Insert( nPrevChg, nCntComp );
|
2001-11-20 09:52:16 +00:00
|
|
|
BYTE nTmpType = ePrevState;
|
2001-04-12 15:17:37 +00:00
|
|
|
aCompType.Insert( nTmpType, nCntComp );
|
2002-06-26 13:38:25 +00:00
|
|
|
aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
|
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
|
|
|
|
if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
|
|
|
|
ePrevState != KANA )
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
2001-04-12 15:17:37 +00:00
|
|
|
aCompChg.Insert( nPrevChg, nCntComp );
|
2001-11-20 09:52:16 +00:00
|
|
|
BYTE nTmpType = ePrevState;
|
2001-04-12 15:17:37 +00:00
|
|
|
aCompType.Insert( nTmpType, nCntComp );
|
2002-06-26 13:38:25 +00:00
|
|
|
aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
|
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
|
|
|
{
|
2002-08-12 07:36:16 +00:00
|
|
|
SwScanner aScanner( rNode, NULL,
|
|
|
|
::com::sun::star::i18n::WordType::DICTIONARY_WORD,
|
|
|
|
nLastKashida, nChg, sal_False, sal_False );
|
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
|
|
|
{
|
|
|
|
const XubString& rWord = aScanner.GetWord();
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
xub_StrLen nIdx = 0;
|
|
|
|
xub_StrLen nKashidaPos = STRING_LEN;
|
|
|
|
xub_Unicode cCh;
|
|
|
|
xub_Unicode cPrevCh = 0;
|
|
|
|
|
|
|
|
while ( nIdx < rWord.Len() )
|
|
|
|
{
|
|
|
|
cCh = rWord.GetChar( nIdx );
|
|
|
|
|
|
|
|
// 1. Priority:
|
|
|
|
// after user inserted kashida
|
|
|
|
if ( 0x640 == cCh )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Priority:
|
|
|
|
// after a Seen or Sad
|
|
|
|
if ( nIdx + 1 < rWord.Len() &&
|
|
|
|
( 0x633 == cCh || 0x635 == cCh ) )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. Priority:
|
|
|
|
// before final form of Teh Marbuta, Hah, Dal
|
|
|
|
// 4. Priority:
|
|
|
|
// before final form of Alef, Lam or Kaf
|
|
|
|
if ( nIdx && nIdx + 1 == rWord.Len() &&
|
|
|
|
( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh ||
|
|
|
|
0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) )
|
|
|
|
{
|
|
|
|
ASSERT( 0 != cPrevCh, "No previous character" )
|
|
|
|
|
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5. Priority:
|
|
|
|
// before media Bah
|
|
|
|
if ( nIdx && nIdx + 1 < rWord.Len() && 0x628 == cCh )
|
|
|
|
{
|
|
|
|
ASSERT( 0 != cPrevCh, "No previous character" )
|
|
|
|
|
|
|
|
// check if next character is Reh, Yeh or Alef Maksura
|
|
|
|
xub_Unicode cNextCh = rWord.GetChar( nIdx + 1 );
|
|
|
|
|
2002-04-18 07:07:00 +00:00
|
|
|
if ( 0x631 == cNextCh || 0x64A == cNextCh ||
|
2002-04-10 05:12:06 +00:00
|
|
|
0x649 == cNextCh )
|
|
|
|
{
|
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 6. Priority:
|
|
|
|
// other connecting possibilities
|
2002-04-18 07:07:00 +00:00
|
|
|
if ( nIdx && nIdx + 1 == rWord.Len() &&
|
|
|
|
0x60C <= cCh && 0x6FE >= cCh )
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
|
|
|
ASSERT( 0 != cPrevCh, "No previous character" )
|
|
|
|
|
|
|
|
// check if character is connectable to previous character,
|
|
|
|
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
|
|
|
|
{
|
|
|
|
// only choose this position if we did not find
|
|
|
|
// a better one:
|
|
|
|
if ( STRING_LEN == nKashidaPos )
|
|
|
|
nKashidaPos = aScanner.GetBegin() + nIdx - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not consider Fathatan, Dammatan, Kasratan, Fatha,
|
|
|
|
// Damma, Kasra, Shadda and Sukun when checking if
|
|
|
|
// a character can be connected to previous character.
|
|
|
|
if ( cCh < 0x64B || cCh > 0x652 )
|
|
|
|
cPrevCh = cCh;
|
|
|
|
|
|
|
|
++nIdx;
|
|
|
|
} // end of current word
|
|
|
|
|
|
|
|
if ( STRING_LEN != nKashidaPos )
|
|
|
|
aKashida.Insert( nKashidaPos, nCntKash++ );
|
|
|
|
} // end of kashida search
|
|
|
|
}
|
2001-04-09 09:44:17 +00:00
|
|
|
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( nChg < rTxt.Len() )
|
|
|
|
nScript = (BYTE)pBreakIt->xBreak->getScriptType( rTxt, 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;
|
2004-02-10 13:57:23 +00:00
|
|
|
};
|
2002-05-02 07:04:29 +00:00
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
#ifndef PRODUCT
|
|
|
|
// check kashida data
|
|
|
|
long nTmpKashidaPos = -1;
|
|
|
|
sal_Bool bWrongKash = sal_False;
|
2004-03-01 12:25:11 +00:00
|
|
|
for (i = 0; i < aKashida.Count(); ++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
|
|
|
{
|
2003-03-27 14:45:43 +00:00
|
|
|
bWrongKash = sal_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
|
|
|
}
|
2003-03-27 14:45:43 +00:00
|
|
|
ASSERT( ! bWrongKash, "Kashida array contains wrong data" )
|
|
|
|
#endif
|
2002-05-02 07:04:29 +00:00
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
// remove invalid entries from direction information arrays
|
2003-04-01 08:57:40 +00:00
|
|
|
const USHORT nDirRemove = aDirChg.Count();
|
|
|
|
aDirChg.Remove( 0, nDirRemove );
|
|
|
|
aDirType.Remove( 0, nDirRemove );
|
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
|
|
|
bool bPerformUBA = UBIDI_LTR != nDefaultDir;
|
2003-04-01 08:57:40 +00:00
|
|
|
nCnt = 0;
|
2004-02-10 13:57:23 +00:00
|
|
|
while( !bPerformUBA && nCnt < CountScriptChg() )
|
2003-04-01 08:57:40 +00:00
|
|
|
{
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( i18n::ScriptType::COMPLEX == GetScriptType( nCnt++ ) )
|
|
|
|
bPerformUBA = true;
|
2003-03-27 14:45:43 +00:00
|
|
|
}
|
2003-04-01 08:57:40 +00:00
|
|
|
|
|
|
|
// do not call the unicode bidi algorithm if not required
|
2004-02-10 13:57:23 +00:00
|
|
|
if ( bPerformUBA )
|
|
|
|
{
|
2003-04-01 08:57:40 +00:00
|
|
|
UpdateBidiInfo( rTxt );
|
2004-02-10 13:57:23 +00:00
|
|
|
|
|
|
|
// #i16354# Change script type for RTL text to CTL.
|
|
|
|
for ( USHORT nDirIdx = 0; nDirIdx < aDirChg.Count(); ++nDirIdx )
|
|
|
|
{
|
|
|
|
if ( GetDirType( nDirIdx ) == UBIDI_RTL )
|
|
|
|
{
|
|
|
|
// nStart ist start of RTL run:
|
|
|
|
const xub_StrLen nStart = nDirIdx > 0 ? GetDirChg( nDirIdx - 1 ) : 0;
|
|
|
|
// nEnd is end of RTL run:
|
|
|
|
const xub_StrLen nEnd = GetDirChg( nDirIdx );
|
|
|
|
// nScriptIdx points into the ScriptArrays:
|
|
|
|
USHORT nScriptIdx = 0;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
xub_StrLen nEndPosOfGroup = GetScriptChg( nScriptIdx );
|
|
|
|
xub_StrLen nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0;
|
|
|
|
BYTE nScriptTypeOfGroup = GetScriptType( nScriptIdx );
|
|
|
|
|
|
|
|
ASSERT( nStartPosOfGroup <= nStart && nEndPosOfGroup > nStart,
|
|
|
|
"Script override with CTL font trouble" )
|
|
|
|
|
|
|
|
// 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 )
|
|
|
|
{
|
|
|
|
aScriptChg.Insert( nStart, nScriptIdx );
|
|
|
|
aScriptType.Insert( nScriptTypeOfGroup, nScriptIdx );
|
|
|
|
++nScriptIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove entries in ScriptArray which end inside the RTL run:
|
|
|
|
while ( nScriptIdx < aScriptChg.Count() && GetScriptChg( nScriptIdx ) <= nEnd )
|
|
|
|
{
|
|
|
|
aScriptChg.Remove( nScriptIdx, 1 );
|
|
|
|
aScriptType.Remove( nScriptIdx, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert a new entry in ScriptArray for the end of the RTL run:
|
|
|
|
aScriptChg.Insert( nEnd, nScriptIdx );
|
|
|
|
aScriptType.Insert( i18n::ScriptType::COMPLEX, nScriptIdx );
|
|
|
|
|
|
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
|
|
BYTE nScriptType;
|
|
|
|
BYTE nLastScriptType = i18n::ScriptType::WEAK;
|
|
|
|
xub_StrLen nScriptChg;
|
|
|
|
xub_StrLen nLastScriptChg = 0;
|
|
|
|
|
|
|
|
for ( int i = 0; i < aScriptChg.Count(); ++i )
|
|
|
|
{
|
|
|
|
nScriptChg = GetScriptChg( i );
|
|
|
|
nScriptType = GetScriptType( i );
|
|
|
|
ASSERT( nLastScriptType != nScriptType &&
|
|
|
|
nLastScriptChg < nScriptChg,
|
|
|
|
"Heavy InitScriptType() confusion" )
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-03-27 14:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SwScriptInfo::UpdateBidiInfo( const String& rTxt )
|
|
|
|
{
|
|
|
|
// remove invalid entries from direction information arrays
|
|
|
|
const USHORT nDirRemove = aDirChg.Count();
|
|
|
|
aDirChg.Remove( 0, nDirRemove );
|
|
|
|
aDirType.Remove( 0, nDirRemove );
|
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
//
|
|
|
|
// Bidi functions from icu 2.0
|
|
|
|
//
|
|
|
|
UErrorCode nError = U_ZERO_ERROR;
|
|
|
|
UBiDi* pBidi = ubidi_openSized( rTxt.Len(), 0, &nError );
|
|
|
|
nError = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
ubidi_setPara( pBidi, rTxt.GetBuffer(), rTxt.Len(),
|
2002-06-26 13:38:25 +00:00
|
|
|
nDefaultDir, NULL, &nError );
|
2002-05-02 07:04:29 +00:00
|
|
|
nError = U_ZERO_ERROR;
|
|
|
|
long 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;
|
2003-03-27 14:45:43 +00:00
|
|
|
// counter for direction information arrays
|
|
|
|
USHORT nCntDir = 0;
|
2002-05-02 07:04:29 +00:00
|
|
|
|
|
|
|
for ( USHORT nIdx = 0; nIdx < nCount; ++nIdx )
|
|
|
|
{
|
|
|
|
ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
|
|
|
|
aDirChg.Insert( (USHORT)nEnd, nCntDir );
|
|
|
|
aDirType.Insert( (BYTE)nCurrDir, nCntDir++ );
|
|
|
|
nStart = nEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
ubidi_close( pBidi );
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::NextScriptChg(..)
|
|
|
|
* 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
|
|
|
|
* STRING_LEN.
|
|
|
|
* Scripts are Asian (Chinese, Japanese, Korean),
|
|
|
|
* Latin ( English etc.)
|
|
|
|
* and Complex ( Hebrew, Arabian )
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
xub_StrLen SwScriptInfo::NextScriptChg( const xub_StrLen nPos ) const
|
|
|
|
{
|
2001-04-09 09:44:17 +00:00
|
|
|
USHORT nEnd = CountScriptChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
2001-02-20 09:27:05 +00:00
|
|
|
if( nPos < GetScriptChg( nX ) )
|
|
|
|
return GetScriptChg( nX );
|
2001-04-09 09:44:17 +00:00
|
|
|
}
|
|
|
|
|
2001-02-20 09:27:05 +00:00
|
|
|
return STRING_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::ScriptType(..)
|
|
|
|
* returns the script of the character at the input position
|
|
|
|
*************************************************************************/
|
|
|
|
|
2001-11-20 09:52:16 +00:00
|
|
|
BYTE SwScriptInfo::ScriptType( const xub_StrLen nPos ) const
|
2001-02-20 09:27:05 +00:00
|
|
|
{
|
2001-04-09 09:44:17 +00:00
|
|
|
USHORT nEnd = CountScriptChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
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
|
2002-11-07 08:45:31 +00:00
|
|
|
return (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
|
2001-02-20 09:27:05 +00:00
|
|
|
}
|
|
|
|
|
2002-03-21 08:19:43 +00:00
|
|
|
xub_StrLen SwScriptInfo::NextDirChg( const xub_StrLen nPos,
|
2002-05-02 07:04:29 +00:00
|
|
|
const BYTE* pLevel ) const
|
2002-03-21 08:19:43 +00:00
|
|
|
{
|
2002-05-02 07:04:29 +00:00
|
|
|
BYTE nCurrDir = pLevel ? *pLevel : 62;
|
2002-03-21 08:19:43 +00:00
|
|
|
USHORT nEnd = CountDirChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
return STRING_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
BYTE SwScriptInfo::DirType( const xub_StrLen nPos ) const
|
|
|
|
{
|
|
|
|
USHORT nEnd = CountDirChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
|
|
|
if( nPos < GetDirChg( nX ) )
|
|
|
|
return GetDirType( nX );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::MaskHiddenRanges(..)
|
|
|
|
* Takes a string and replaced the hidden ranges with cChar.
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
USHORT SwScriptInfo::MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
|
2004-04-27 12:42:37 +00:00
|
|
|
const xub_StrLen nStt, const xub_StrLen nEnd,
|
|
|
|
const xub_Unicode cChar )
|
2004-02-26 14:32:29 +00:00
|
|
|
{
|
2004-04-27 12:42:37 +00:00
|
|
|
ASSERT( rNode.GetTxt().Len() == rText.Len(), "MaskHiddenRanges, string len mismatch" )
|
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
PositionList aList;
|
|
|
|
xub_StrLen nHiddenStart;
|
|
|
|
xub_StrLen nHiddenEnd;
|
|
|
|
USHORT nNumOfHiddenChars = 0;
|
|
|
|
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 )
|
|
|
|
{
|
|
|
|
rText.SetChar( nHiddenStart, cChar );
|
|
|
|
++nNumOfHiddenChars;
|
|
|
|
}
|
|
|
|
++nHiddenStart;
|
2004-02-26 14:32:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nNumOfHiddenChars;
|
|
|
|
}
|
|
|
|
|
2004-06-29 07:09:49 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::DeleteHiddenRanges(..)
|
|
|
|
* Takes a SwTxtNode and deletes the hidden ranges from the node.
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
void SwScriptInfo::DeleteHiddenRanges( SwTxtNode& rNode )
|
|
|
|
{
|
|
|
|
PositionList aList;
|
|
|
|
xub_StrLen nHiddenStart;
|
|
|
|
xub_StrLen nHiddenEnd;
|
|
|
|
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 );
|
|
|
|
rNode.GetDoc()->Delete( aPam );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-26 14:32:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::GetBoundsOfHiddenRange(..)
|
|
|
|
* static version
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos,
|
|
|
|
xub_StrLen& rnStartPos, xub_StrLen& rnEndPos,
|
|
|
|
PositionList* pList )
|
|
|
|
{
|
|
|
|
rnStartPos = STRING_LEN;
|
|
|
|
rnEndPos = 0;
|
|
|
|
|
|
|
|
bool bNewContainsHiddenChars = false;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Optimization: First examine the flags at the text node:
|
|
|
|
//
|
|
|
|
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 );
|
|
|
|
pList->push_back( rNode.GetTxt().Len() );
|
|
|
|
}
|
|
|
|
|
|
|
|
rnStartPos = 0;
|
|
|
|
rnEndPos = rNode.GetTxt().Len();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rNode );
|
|
|
|
if ( pSI )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Check first, if we have a valid SwScriptInfo object for this text node:
|
|
|
|
//
|
|
|
|
bNewContainsHiddenChars = pSI->GetBoundsOfHiddenRange( nPos, rnStartPos, rnEndPos, pList );
|
|
|
|
const bool bNewHiddenCharsHidePara = ( rnStartPos == 0 && rnEndPos >= rNode.GetTxt().Len() );
|
|
|
|
rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// No valid SwScriptInfo Object, we have to do it the hard way:
|
|
|
|
//
|
|
|
|
Range aRange( 0, rNode.GetTxt().Len() ? rNode.GetTxt().Len() - 1 : 0 );
|
|
|
|
MultiSelection aHiddenMulti( aRange );
|
|
|
|
SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti );
|
|
|
|
for( USHORT i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
|
|
|
const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
|
|
|
|
const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
|
|
|
|
|
|
|
|
if ( nHiddenStart > nPos )
|
|
|
|
break;
|
|
|
|
else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
|
|
|
|
{
|
|
|
|
rnStartPos = nHiddenStart;
|
|
|
|
rnEndPos = Min( nHiddenEnd, rNode.GetTxt().Len() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pList )
|
|
|
|
{
|
|
|
|
for( USHORT i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
|
|
|
|
{
|
|
|
|
const Range& rRange = aHiddenMulti.GetRange( i );
|
|
|
|
pList->push_back( (xub_StrLen)rRange.Min() );
|
|
|
|
pList->push_back( (xub_StrLen)rRange.Max() + 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bNewContainsHiddenChars = aHiddenMulti.GetRangeCount() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bNewContainsHiddenChars;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::GetBoundsOfHiddenRange(..)
|
|
|
|
* non-static version
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
bool SwScriptInfo::GetBoundsOfHiddenRange( xub_StrLen nPos, xub_StrLen& rnStartPos,
|
|
|
|
xub_StrLen& rnEndPos, PositionList* pList ) const
|
|
|
|
{
|
|
|
|
rnStartPos = STRING_LEN;
|
|
|
|
rnEndPos = 0;
|
|
|
|
|
|
|
|
USHORT nEnd = CountHiddenChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
|
|
|
const xub_StrLen nHiddenStart = GetHiddenChg( nX++ );
|
|
|
|
const xub_StrLen nHiddenEnd = GetHiddenChg( nX );
|
|
|
|
|
|
|
|
if ( nHiddenStart > nPos )
|
|
|
|
break;
|
|
|
|
else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
|
|
|
|
{
|
|
|
|
rnStartPos = nHiddenStart;
|
|
|
|
rnEndPos = nHiddenEnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pList )
|
|
|
|
{
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
|
|
|
pList->push_back( GetHiddenChg( nX++ ) );
|
|
|
|
pList->push_back( GetHiddenChg( nX ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return CountHiddenChg() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::IsInHiddenRange()
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
bool SwScriptInfo::IsInHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos )
|
|
|
|
{
|
|
|
|
xub_StrLen nStartPos;
|
|
|
|
xub_StrLen nEndPos;
|
|
|
|
SwScriptInfo::GetBoundsOfHiddenRange( rNode, nPos, nStartPos, nEndPos );
|
|
|
|
return nStartPos != STRING_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-04-09 09:44:17 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::CompType(..)
|
|
|
|
* returns the type of the compressed character
|
|
|
|
*************************************************************************/
|
|
|
|
|
2001-11-20 09:52:16 +00:00
|
|
|
BYTE SwScriptInfo::CompType( const xub_StrLen nPos ) const
|
2001-04-09 09:44:17 +00:00
|
|
|
{
|
|
|
|
USHORT nEnd = CountCompChg();
|
|
|
|
for( USHORT nX = 0; nX < nEnd; ++nX )
|
|
|
|
{
|
|
|
|
xub_StrLen nChg = GetCompStart( nX );
|
|
|
|
|
|
|
|
if ( nPos < nChg )
|
|
|
|
return NONE;
|
|
|
|
|
|
|
|
if( nPos < nChg + GetCompLen( nX ) )
|
|
|
|
return GetCompType( nX );
|
|
|
|
}
|
|
|
|
return NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::HasKana()
|
|
|
|
* returns, if there are compressable kanas or specials
|
|
|
|
* betwenn nStart and nEnd
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
USHORT SwScriptInfo::HasKana( xub_StrLen nStart, const xub_StrLen nLen ) const
|
|
|
|
{
|
|
|
|
USHORT nCnt = CountCompChg();
|
|
|
|
xub_StrLen nEnd = nStart + nLen;
|
|
|
|
|
|
|
|
for( USHORT nX = 0; nX < nCnt; ++nX )
|
|
|
|
{
|
|
|
|
xub_StrLen nKanaStart = GetCompStart( nX );
|
|
|
|
xub_StrLen nKanaEnd = nKanaStart + GetCompLen( nX );
|
|
|
|
|
|
|
|
if ( nKanaStart >= nEnd )
|
|
|
|
return USHRT_MAX;
|
|
|
|
|
|
|
|
if ( nStart < nKanaEnd )
|
|
|
|
return nX;
|
|
|
|
}
|
|
|
|
|
|
|
|
return USHRT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::Compress()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
long SwScriptInfo::Compress( long* pKernArray, xub_StrLen nIdx, xub_StrLen nLen,
|
|
|
|
const USHORT nCompress, const USHORT nFontHeight,
|
|
|
|
Point* pPoint ) const
|
|
|
|
{
|
|
|
|
ASSERT( nCompress, "Compression without compression?!" );
|
|
|
|
ASSERT( nLen, "Compression without text?!" );
|
|
|
|
USHORT nCompCount = CountCompChg();
|
|
|
|
|
|
|
|
// In asian typography, there are full width and half width characters.
|
|
|
|
// Full width punctuation characters can be compressed by 50 %
|
|
|
|
// to determine this, we compare the font width with 75 % of its height
|
|
|
|
USHORT nMinWidth = ( 3 * nFontHeight ) / 4;
|
|
|
|
|
|
|
|
USHORT nCompIdx = HasKana( nIdx, nLen );
|
|
|
|
|
|
|
|
if ( USHRT_MAX == nCompIdx )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
xub_StrLen nChg = GetCompStart( nCompIdx );
|
|
|
|
xub_StrLen nCompLen = GetCompLen( nCompIdx );
|
|
|
|
USHORT nI = 0;
|
|
|
|
nLen += nIdx;
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
USHORT nType = GetCompType( nCompIdx );
|
|
|
|
ASSERT( nType == CompType( nIdx ), "Gimme the right type!" );
|
|
|
|
nCompLen += nIdx;
|
|
|
|
if( nCompLen > nLen )
|
|
|
|
nCompLen = nLen;
|
|
|
|
|
|
|
|
// are we allowed to compress the character?
|
|
|
|
if ( pKernArray[ nI ] - nLast < nMinWidth )
|
|
|
|
{
|
|
|
|
nIdx++; nI++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while( nIdx < nCompLen )
|
|
|
|
{
|
|
|
|
ASSERT( SwScriptInfo::NONE != nType, "None compression?!" );
|
|
|
|
|
|
|
|
// nLast is width of current character
|
|
|
|
nLast -= pKernArray[ nI ];
|
|
|
|
|
|
|
|
nLast *= nCompress;
|
|
|
|
long nMove = 0;
|
|
|
|
if( SwScriptInfo::KANA != nType )
|
|
|
|
{
|
|
|
|
nLast /= 20000;
|
|
|
|
if( pPoint && SwScriptInfo::SPECIAL_LEFT == nType )
|
|
|
|
{
|
|
|
|
if( nI )
|
|
|
|
nMove = nLast;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPoint->X() += nLast;
|
|
|
|
nLast = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nLast /= 100000;
|
|
|
|
nSub -= nLast;
|
|
|
|
nLast = pKernArray[ nI ];
|
|
|
|
if( nMove )
|
|
|
|
pKernArray[ nI - 1 ] += nMove;
|
|
|
|
pKernArray[ nI++ ] -= nSub;
|
|
|
|
++nIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( nIdx < nLen )
|
|
|
|
{
|
|
|
|
xub_StrLen nChg;
|
|
|
|
if( ++nCompIdx < nCompCount )
|
|
|
|
{
|
|
|
|
nChg = GetCompStart( nCompIdx );
|
|
|
|
if( nChg > nLen )
|
|
|
|
nChg = nLen;
|
|
|
|
nCompLen = GetCompLen( nCompIdx );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nChg = nLen;
|
|
|
|
while( nIdx < nChg )
|
|
|
|
{
|
|
|
|
nLast = pKernArray[ nI ];
|
|
|
|
pKernArray[ nI++ ] -= nSub;
|
|
|
|
++nIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
} while( nIdx < nLen );
|
|
|
|
return nSub;
|
|
|
|
}
|
|
|
|
|
2002-04-10 05:12:06 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::KashidaJustify()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
USHORT SwScriptInfo::KashidaJustify( long* pKernArray, long* pScrArray,
|
|
|
|
xub_StrLen nStt, xub_StrLen nLen,
|
2002-05-06 14:05:54 +00:00
|
|
|
USHORT nSpace ) const
|
2002-04-10 05:12:06 +00:00
|
|
|
{
|
|
|
|
ASSERT( nLen, "Kashida justification without text?!" )
|
|
|
|
|
|
|
|
// evaluate kashida informatin in collected in SwScriptInfo
|
|
|
|
|
|
|
|
USHORT nCntKash = 0;
|
|
|
|
while( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nStt <= GetKashida( nCntKash ) )
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
nCntKash++;
|
|
|
|
}
|
|
|
|
|
|
|
|
const xub_StrLen nEnd = nStt + nLen;
|
|
|
|
|
|
|
|
if ( ! pKernArray )
|
|
|
|
{
|
|
|
|
USHORT nCntKashEnd = nCntKash;
|
|
|
|
while ( nCntKashEnd < CountKashida() )
|
|
|
|
{
|
|
|
|
if ( nEnd <= GetKashida( nCntKashEnd ) )
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
nCntKashEnd++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nCntKashEnd - nCntKash;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do nothing if there is no more kashida
|
|
|
|
if ( nCntKash < CountKashida() )
|
|
|
|
{
|
|
|
|
xub_StrLen nKashidaPos = GetKashida( nCntKash );
|
|
|
|
xub_StrLen nIdx = nKashidaPos;
|
|
|
|
USHORT nSpaceAdd = nSpace;
|
|
|
|
|
|
|
|
while ( nIdx < nEnd )
|
|
|
|
{
|
|
|
|
USHORT nArrayPos = nIdx - nStt;
|
|
|
|
|
|
|
|
// next kashida position
|
|
|
|
nIdx = ++nCntKash < CountKashida() ? GetKashida( nCntKash ) : nEnd;
|
|
|
|
if ( nIdx > nEnd )
|
|
|
|
nIdx = nEnd;
|
|
|
|
|
|
|
|
const USHORT nArrayEnd = nIdx - nStt;
|
|
|
|
|
|
|
|
while ( nArrayPos < nArrayEnd )
|
|
|
|
{
|
|
|
|
pKernArray[ nArrayPos ] += nSpaceAdd;
|
|
|
|
if ( pScrArray )
|
|
|
|
pScrArray[ nArrayPos ] += nSpaceAdd;
|
|
|
|
++nArrayPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
nSpaceAdd += nSpace;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-20 08:44:17 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::IsArabicLanguage()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
sal_Bool SwScriptInfo::IsArabicLanguage( LanguageType aLang )
|
|
|
|
{
|
|
|
|
return LANGUAGE_ARABIC == aLang || LANGUAGE_ARABIC_SAUDI_ARABIA == aLang ||
|
|
|
|
LANGUAGE_ARABIC_IRAQ == aLang || LANGUAGE_ARABIC_EGYPT == aLang ||
|
|
|
|
LANGUAGE_ARABIC_LIBYA == aLang || LANGUAGE_ARABIC_ALGERIA == aLang ||
|
|
|
|
LANGUAGE_ARABIC_MOROCCO == aLang || LANGUAGE_ARABIC_TUNISIA == aLang ||
|
|
|
|
LANGUAGE_ARABIC_OMAN == aLang || LANGUAGE_ARABIC_YEMEN == aLang ||
|
|
|
|
LANGUAGE_ARABIC_SYRIA == aLang || LANGUAGE_ARABIC_JORDAN == aLang ||
|
|
|
|
LANGUAGE_ARABIC_LEBANON == aLang || LANGUAGE_ARABIC_KUWAIT == aLang ||
|
|
|
|
LANGUAGE_ARABIC_UAE == aLang || LANGUAGE_ARABIC_BAHRAIN == aLang ||
|
|
|
|
LANGUAGE_ARABIC_QATAR == aLang;
|
|
|
|
}
|
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::ThaiJustify()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
USHORT SwScriptInfo::ThaiJustify( const XubString& rTxt, long* pKernArray,
|
|
|
|
long* pScrArray, xub_StrLen nStt,
|
2002-05-06 14:05:54 +00:00
|
|
|
xub_StrLen nLen, USHORT nSpace )
|
2002-05-02 07:04:29 +00:00
|
|
|
{
|
2002-05-06 14:05:54 +00:00
|
|
|
ASSERT( nStt + nLen <= rTxt.Len(), "String in ThaiJustify too small" )
|
|
|
|
|
2002-05-02 07:04:29 +00:00
|
|
|
long nSpaceSum = 0;
|
|
|
|
USHORT nCnt = 0;
|
|
|
|
|
|
|
|
for ( USHORT nI = 0; nI < nLen; ++nI )
|
|
|
|
{
|
|
|
|
const xub_Unicode cCh = rTxt.GetChar( nStt + nI );
|
|
|
|
|
|
|
|
// 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
|
|
|
{
|
|
|
|
nSpaceSum += nSpace;
|
|
|
|
++nCnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
|
|
|
|
if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nCnt;
|
|
|
|
}
|
|
|
|
|
2002-12-02 09:30:44 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::GetScriptInfo()
|
|
|
|
*************************************************************************/
|
|
|
|
|
2003-03-27 14:45:43 +00:00
|
|
|
SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTxtNode& rTNd,
|
|
|
|
sal_Bool bAllowInvalid )
|
2002-12-02 09:30:44 +00:00
|
|
|
{
|
|
|
|
SwClientIter aClientIter( (SwTxtNode&)rTNd );
|
|
|
|
SwClient* pLast = aClientIter.GoStart();
|
2003-03-27 14:45:43 +00:00
|
|
|
SwScriptInfo* pScriptInfo = 0;
|
2002-12-02 09:30:44 +00:00
|
|
|
|
|
|
|
while( pLast )
|
|
|
|
{
|
|
|
|
if ( pLast->ISA( SwTxtFrm ) )
|
|
|
|
{
|
2003-03-27 14:45:43 +00:00
|
|
|
pScriptInfo = (SwScriptInfo*)((SwTxtFrm*)pLast)->GetScriptInfo();
|
2002-12-02 09:30:44 +00:00
|
|
|
if ( pScriptInfo )
|
|
|
|
{
|
2004-02-26 14:32:29 +00:00
|
|
|
if ( !bAllowInvalid && STRING_LEN != pScriptInfo->GetInvalidity() )
|
2002-12-02 09:30:44 +00:00
|
|
|
pScriptInfo = 0;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pLast = ++aClientIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pScriptInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* class SwParaPortion
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
SwParaPortion::SwParaPortion()
|
|
|
|
{
|
|
|
|
FormatReset();
|
2000-11-21 10:29:48 +00:00
|
|
|
bFlys = bFtnNum = bMargin = sal_False;
|
2000-09-18 23:08:29 +00:00
|
|
|
SetWhichPor( POR_PARA );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwParaPortion::GetParLen()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
xub_StrLen SwParaPortion::GetParLen() const
|
|
|
|
{
|
|
|
|
xub_StrLen nLen = 0;
|
|
|
|
const SwLineLayout *pLay = this;
|
|
|
|
while( pLay )
|
|
|
|
{
|
|
|
|
DBG_LOOP;
|
|
|
|
nLen += pLay->GetLen();
|
|
|
|
pLay = pLay->GetNext();
|
|
|
|
}
|
|
|
|
return nLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwParaPortion::FindDropPortion()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
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() )
|
|
|
|
return (SwDropPortion *)pPos;
|
|
|
|
pLay = pLay->GetLen() ? NULL : pLay->GetNext();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwLineLayout::Init()
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2000-11-21 10:29:48 +00:00
|
|
|
/*-----------------16.11.00 11:04-------------------
|
|
|
|
* HangingMargin()
|
|
|
|
* 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 atualized.
|
|
|
|
* --------------------------------------------------*/
|
|
|
|
|
|
|
|
SwTwips SwLineLayout::_GetHangingMargin() const
|
|
|
|
{
|
|
|
|
SwLinePortion* pPor = GetPortion();
|
|
|
|
BOOL bFound = sal_False;
|
|
|
|
SwTwips nDiff = 0;
|
|
|
|
while( pPor)
|
|
|
|
{
|
|
|
|
if( pPor->IsHangingPortion() )
|
|
|
|
{
|
|
|
|
nDiff = ((SwHangingPortion*)pPor)->GetInnerWidth() - pPor->Width();
|
|
|
|
if( nDiff )
|
|
|
|
bFound = sal_True;
|
|
|
|
}
|
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();
|
|
|
|
}
|
|
|
|
if( !bFound ) // actualize the hanging-flag
|
|
|
|
((SwLineLayout*)this)->SetHanging( sal_False );
|
|
|
|
return nDiff;
|
|
|
|
}
|
|
|
|
|
|
|
|
SwTwips SwTxtFrm::HangingMargin() const
|
|
|
|
{
|
|
|
|
ASSERT( HasPara(), "Don't call me without a paraportion" );
|
|
|
|
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 );
|
|
|
|
if( !nRet ) // actualize the margin-flag
|
|
|
|
((SwParaPortion*)GetPara())->SetMargin( sal_False );
|
|
|
|
return nRet;
|
|
|
|
}
|
2004-02-26 14:32:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SwScriptInfo::CalcHiddenRanges()
|
|
|
|
*
|
|
|
|
* Returns a MultiSection indicating the hidden ranges.
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
void SwScriptInfo::CalcHiddenRanges( const SwTxtNode& rNode, MultiSelection& rHiddenMulti )
|
|
|
|
{
|
|
|
|
const SfxPoolItem* pItem = 0;
|
|
|
|
if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( RES_CHRATR_HIDDEN, TRUE, &pItem ) &&
|
|
|
|
((SvxCharHiddenItem*)pItem)->GetValue() )
|
|
|
|
{
|
|
|
|
rHiddenMulti.SelectAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwpHints* pHints = rNode.GetpSwpHints();
|
|
|
|
const SwTxtAttr* pTxtAttr = 0;
|
|
|
|
bool bHidden = false;
|
|
|
|
bool bHiddenSelect = false;
|
|
|
|
|
|
|
|
if( pHints )
|
|
|
|
{
|
|
|
|
MSHORT nTmp = 0;
|
|
|
|
|
|
|
|
while( nTmp < pHints->GetStartCount() )
|
|
|
|
{
|
|
|
|
pTxtAttr = pHints->GetStart( nTmp++ );
|
|
|
|
switch ( pTxtAttr->Which() )
|
|
|
|
{
|
|
|
|
case RES_CHRATR_HIDDEN:
|
|
|
|
{
|
|
|
|
bHidden = sal_True;
|
|
|
|
bHiddenSelect = pTxtAttr->GetCharHidden().GetValue();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RES_TXTATR_CHARFMT:
|
|
|
|
{
|
|
|
|
SwCharFmt* pFmt;
|
|
|
|
const SfxPoolItem* pItem;
|
|
|
|
pFmt = pTxtAttr->GetCharFmt().GetCharFmt();
|
|
|
|
if ( pFmt )
|
|
|
|
{
|
|
|
|
if( SFX_ITEM_SET == pFmt->GetAttrSet().
|
|
|
|
GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
|
|
|
|
{
|
|
|
|
bHidden = sal_True;
|
|
|
|
bHiddenSelect = ((SvxCharHiddenItem*)pItem)->GetValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( bHidden )
|
|
|
|
{
|
|
|
|
xub_StrLen nSt = *pTxtAttr->GetStart();
|
|
|
|
xub_StrLen nEnd = *pTxtAttr->GetEnd();
|
|
|
|
if( nEnd > nSt )
|
|
|
|
{
|
|
|
|
Range aTmp( nSt, nEnd - 1 );
|
|
|
|
if( bHidden )
|
|
|
|
rHiddenMulti.Select( aTmp, bHiddenSelect );
|
|
|
|
}
|
|
|
|
bHidden = sal_False;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are any hidden ranges in the current text node, we have
|
|
|
|
// to unhide the redlining ranges:
|
|
|
|
const SwDoc& rDoc = *rNode.GetDoc();
|
|
|
|
if ( rHiddenMulti.GetRangeCount() && ::IsShowChanges( rDoc.GetRedlineMode() ) )
|
|
|
|
{
|
|
|
|
USHORT nAct = rDoc.GetRedlinePos( rNode );
|
|
|
|
|
|
|
|
for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
|
|
|
|
{
|
|
|
|
const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
|
|
|
|
|
|
|
|
if ( pRed->Start()->nNode > rNode.GetIndex() )
|
|
|
|
break;
|
|
|
|
|
|
|
|
xub_StrLen nRedlStart;
|
|
|
|
xub_StrLen nRedlnEnd;
|
|
|
|
pRed->CalcStartEnd( rNode.GetIndex(), nRedlStart, nRedlnEnd );
|
|
|
|
if ( nRedlnEnd > nRedlStart )
|
|
|
|
{
|
|
|
|
Range aTmp( nRedlStart, nRedlnEnd - 1 );
|
|
|
|
rHiddenMulti.Select( aTmp, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// We calculated a lot of stuff. Finally we can update the flags at the text node.
|
|
|
|
//
|
|
|
|
const bool bNewContainsHiddenChars = rHiddenMulti.GetRangeCount() > 0;
|
|
|
|
bool bNewHiddenCharsHidePara = false;
|
|
|
|
if ( bNewContainsHiddenChars )
|
|
|
|
{
|
|
|
|
const Range& rRange = rHiddenMulti.GetRange( 0 );
|
|
|
|
const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
|
|
|
|
const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
|
|
|
|
bNewHiddenCharsHidePara = ( nHiddenStart == 0 && nHiddenEnd >= rNode.GetTxt().Len() );
|
|
|
|
}
|
|
|
|
rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwTxtNode::CalcHiddenCharFlags() const
|
|
|
|
{
|
|
|
|
xub_StrLen nStartPos;
|
|
|
|
xub_StrLen nEndPos;
|
|
|
|
// Update of the flags is done inside GetBoundsOfHiddenRange()
|
|
|
|
SwScriptInfo::GetBoundsOfHiddenRange( *this, 0, nStartPos, nEndPos );
|
|
|
|
}
|