summaryrefslogtreecommitdiff
path: root/sw/source/core/text/ScriptInfo.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/ScriptInfo.cxx')
-rw-r--r--sw/source/core/text/ScriptInfo.cxx1366
1 files changed, 0 insertions, 1366 deletions
diff --git a/sw/source/core/text/ScriptInfo.cxx b/sw/source/core/text/ScriptInfo.cxx
deleted file mode 100644
index 232789db081d..000000000000
--- a/sw/source/core/text/ScriptInfo.cxx
+++ /dev/null
@@ -1,1366 +0,0 @@
-/*************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2008 by Sun Microsystems, Inc.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * $RCSfile: ScriptInfo.cxx,v $
- * $Revision: 1.6 $
- *
- * This file is part of OpenOffice.org.
- *
- * OpenOffice.org is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 3
- * only, as published by the Free Software Foundation.
- *
- * OpenOffice.org 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 version 3 for more details
- * (a copy is included in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU Lesser General Public License
- * version 3 along with OpenOffice.org. If not, see
- * <http://www.openoffice.org/license.html>
- * for a copy of the LGPLv3 License.
- *
- ************************************************************************/
-
-// MARKER(update_precomp.py): autogen include statement, do not remove
-#include "precompiled_sw.hxx"
-
-
-#include "errhdl.hxx" // ASSERT
-#include <scriptinfo.hxx>
-#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
-#include <com/sun/star/i18n/ScriptType.hdl>
-#endif
-#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
-#include <com/sun/star/i18n/WordType.hdl>
-#endif
-#include <tools/multisel.hxx>
-#include <svx/scripttypeitem.hxx>
-#include <pam.hxx>
-#include <docary.hxx>
-#include <section.hxx>
-#include <redline.hxx>
-#include <ndtxt.hxx> // GetCurFld
-#include <breakit.hxx>
-#include <txatbase.hxx>
-#include <charfmt.hxx>
-#include <fchrfmt.hxx>
-#include <svx/adjitem.hxx>
-#include <svx/charhiddenitem.hxx>
-#include <swfont.hxx>
-#include <txtfrm.hxx>
-
-#include <paratr.hxx>
-#include <IDocumentRedlineAccess.hxx>
-
-using namespace ::com::sun::star;
-using namespace ::com::sun::star::i18n::ScriptType;
-
-#include <unicode/ubidi.h>
-
-/*************************************************************************
- * lcl_IsLigature
- *
- * Checks if cCh + cNectCh builds a ligature (used for Kashidas)
- *************************************************************************/
-
-sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh )
-{
- // Lam + Alef
- return ( 0x644 == cCh && 0x627 == cNextCh ) ||
- // Beh + Reh
- ( 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
- // 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 );
-
- // check for ligatures cPrevChar + cChar
- if ( bRet )
- bRet = ! lcl_IsLigature( cPrevCh, cCh );
-
- return bRet;
-}
-
-/*************************************************************************
- * WhichFont()
- *
- * Converts i18n Script Type (LATIN, ASIAN, COMPLEX, WEAK) to
- * Sw Script Types (SW_LATIN, SW_CJK, SW_CTL), used to identify the font
- *************************************************************************/
-
-BYTE SwScriptInfo::WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI )
-{
- 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;
-}
-
-/*************************************************************************
- * SwScriptInfo::InitScriptInfo()
- *
- * searches for script changes in rTxt and stores them
- *************************************************************************/
-
-void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode )
-{
- InitScriptInfo( rNode, nDefaultDir == UBIDI_RTL );
-}
-
-void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL )
-{
- if( !pBreakIt->xBreak.is() )
- return;
-
- 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;
- USHORT i = 0;
- for( i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
- {
- 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
- //
-
- xub_StrLen nChg = nInvalidityPos;
-
- // STRING_LEN means the data structure is up to date
- nInvalidityPos = STRING_LEN;
-
- // this is the default direction
- nDefaultDir = bRTL ? UBIDI_RTL : UBIDI_LTR;
-
- // counter for script info arrays
- USHORT nCnt = 0;
- // counter for compression information arrays
- USHORT nCntComp = 0;
- // counter for kashida array
- USHORT nCntKash = 0;
-
- BYTE nScript;
-
- // compression type
- const SwCharCompressType aCompEnum = rNode.getIDocumentSettingAccess()->getCharacterCompressionType();
-
- // justification type
- const sal_Bool bAdjustBlock = SVX_ADJUST_BLOCK ==
- rNode.GetSwAttrSet().GetAdjust().GetAdjust();
-
- //
- // FIND INVALID RANGES IN SCRIPT INFO ARRAYS:
- //
-
- if( nChg )
- {
- // 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
- ASSERT( CountScriptChg(), "Where're my changes of script?" );
- while( nCnt < CountScriptChg() )
- {
- if ( nChg > GetScriptChg( nCnt ) )
- nCnt++;
- else
- {
- nScript = GetScriptType( nCnt );
- break;
- }
- }
- if( CHARCOMPRESS_NONE != aCompEnum )
- {
- while( nCntComp < CountCompChg() )
- {
- if ( nChg > GetCompStart( nCntComp ) )
- nCntComp++;
- else
- break;
- }
- }
- if ( bAdjustBlock )
- {
- while( nCntKash < CountKashida() )
- {
- if ( nChg > GetKashida( nCntKash ) )
- nCntKash++;
- else
- break;
- }
- }
- }
-
- //
- // ADJUST nChg VALUE:
- //
-
- // by stepping back one position we know that we are inside a group
- // declared as an nScript group
- if ( nChg )
- --nChg;
-
- const xub_StrLen nGrpStart = nCnt ? GetScriptChg( nCnt - 1 ) : 0;
-
- // 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;
-
- // 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 );
-
- //
- // 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
- USHORT nLastKashida = nChg;
- if( nCntKash && i18n::ScriptType::COMPLEX == nScript )
- {
- --nCntKash;
- nLastKashida = GetKashida( nCntKash );
- }
-
- // remove invalid entries from kashida array
- aKashida.Remove( nCntKash, aKashida.Count() - nCntKash );
-
- //
- // TAKE CARE OF WEAK CHARACTERS: WE MUST FIND AN APPROPRIATE
- // SCRIPT FOR WEAK CHARACTERS AT THE BEGINNING OF A PARAGRAPH
- //
-
- if( WEAK == pBreakIt->xBreak->getScriptType( rTxt, nChg ) )
- {
- // 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.
- xub_StrLen nEnd =
- (xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nChg, WEAK );
-
- if( nEnd > rTxt.Len() )
- nEnd = rTxt.Len();
-
- nScript = (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
-
- ASSERT( i18n::ScriptType::LATIN == nScript ||
- i18n::ScriptType::ASIAN == nScript ||
- i18n::ScriptType::COMPLEX == nScript, "Wrong default language" );
-
- nChg = nEnd;
-
- // 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;
-
- if ( nScript != nNextScript )
- {
- aScriptChg.Insert( nEnd, nCnt );
- aScriptType.Insert( nScript, nCnt++ );
- nScript = nNextScript;
- }
- }
-
- //
- // UPDATE THE SCRIPT INFO ARRAYS:
- //
-
- while ( nChg < rTxt.Len() || ( !aScriptChg.Count() && !rTxt.Len() ) )
- {
- ASSERT( i18n::ScriptType::WEAK != nScript,
- "Inserting WEAK into SwScriptInfo structure" );
- ASSERT( STRING_LEN != nChg, "65K? Strange length of script section" );
-
- nChg = (xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nChg, nScript );
-
- if ( nChg > rTxt.Len() )
- nChg = rTxt.Len();
-
- 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 )
- {
- BYTE ePrevState = NONE;
- BYTE eState;
- USHORT nPrevChg = nLastCompression;
-
- while ( nLastCompression < nChg )
- {
- xub_Unicode cChar = rTxt.GetChar( nLastCompression );
-
- // examine current character
- switch ( cChar )
- {
- // 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;
- }
-
- // insert range of compressable characters
- if( ePrevState != eState )
- {
- if ( ePrevState != NONE )
- {
- // insert start and type
- if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
- ePrevState != KANA )
- {
- aCompChg.Insert( nPrevChg, nCntComp );
- BYTE nTmpType = ePrevState;
- aCompType.Insert( nTmpType, nCntComp );
- aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
- }
- }
-
- ePrevState = eState;
- nPrevChg = nLastCompression;
- }
-
- nLastCompression++;
- }
-
- // we still have to examine last entry
- if ( ePrevState != NONE )
- {
- // insert start and type
- if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
- ePrevState != KANA )
- {
- aCompChg.Insert( nPrevChg, nCntComp );
- BYTE nTmpType = ePrevState;
- aCompType.Insert( nTmpType, nCntComp );
- aCompLen.Insert( nLastCompression - nPrevChg, nCntComp++ );
- }
- }
- }
-
- // we search for connecting opportunities (kashida)
- else if ( bAdjustBlock && i18n::ScriptType::COMPLEX == nScript )
- {
- SwScanner aScanner( rNode,
- i18n::WordType::DICTIONARY_WORD,
- nLastKashida, nChg );
-
- // the search has to be performed on a per word base
- while ( aScanner.NextWord() )
- {
- const XubString& rWord = aScanner.GetWord();
-
- 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 );
-
- if ( 0x631 == cNextCh || 0x64A == cNextCh ||
- 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
- if ( nIdx && nIdx + 1 == rWord.Len() &&
- 0x60C <= cCh && 0x6FE >= cCh )
- {
- 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
- }
-
- if ( nChg < rTxt.Len() )
- nScript = (BYTE)pBreakIt->xBreak->getScriptType( rTxt, nChg );
-
- nLastCompression = nChg;
- nLastKashida = nChg;
- };
-
-#ifndef PRODUCT
- // check kashida data
- long nTmpKashidaPos = -1;
- sal_Bool bWrongKash = sal_False;
- for (i = 0; i < aKashida.Count(); ++i )
- {
- long nCurrKashidaPos = GetKashida( i );
- if ( nCurrKashidaPos <= nTmpKashidaPos )
- {
- bWrongKash = sal_True;
- break;
- }
- nTmpKashidaPos = nCurrKashidaPos;
- }
- ASSERT( ! bWrongKash, "Kashida array contains wrong data" )
-#endif
-
- // remove invalid entries from direction information arrays
- const USHORT nDirRemove = aDirChg.Count();
- aDirChg.Remove( 0, nDirRemove );
- aDirType.Remove( 0, nDirRemove );
-
- // Perform Unicode Bidi Algorithm for text direction information
- bool bPerformUBA = UBIDI_LTR != nDefaultDir;
- nCnt = 0;
- while( !bPerformUBA && nCnt < CountScriptChg() )
- {
- if ( i18n::ScriptType::COMPLEX == GetScriptType( nCnt++ ) )
- bPerformUBA = true;
- }
-
- // do not call the unicode bidi algorithm if not required
- if ( bPerformUBA )
- {
- UpdateBidiInfo( rTxt );
-
- // #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
- }
- }
- }
-}
-
-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 );
-
- //
- // 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(),
- nDefaultDir, NULL, &nError );
- nError = U_ZERO_ERROR;
- long nCount = ubidi_countRuns( pBidi, &nError );
- int32_t nStart = 0;
- int32_t nEnd;
- UBiDiLevel nCurrDir;
- // counter for direction information arrays
- USHORT nCntDir = 0;
-
- 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 );
-}
-
-
-/*************************************************************************
- * 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
-{
- USHORT nEnd = CountScriptChg();
- for( USHORT nX = 0; nX < nEnd; ++nX )
- {
- if( nPos < GetScriptChg( nX ) )
- return GetScriptChg( nX );
- }
-
- return STRING_LEN;
-}
-
-/*************************************************************************
- * SwScriptInfo::ScriptType(..)
- * returns the script of the character at the input position
- *************************************************************************/
-
-BYTE SwScriptInfo::ScriptType( const xub_StrLen nPos ) const
-{
- USHORT nEnd = CountScriptChg();
- for( USHORT nX = 0; nX < nEnd; ++nX )
- {
- if( nPos < GetScriptChg( nX ) )
- return GetScriptType( nX );
- }
-
- // the default is the application language script
- return (BYTE)GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
-}
-
-xub_StrLen SwScriptInfo::NextDirChg( const xub_StrLen nPos,
- const BYTE* pLevel ) const
-{
- BYTE nCurrDir = pLevel ? *pLevel : 62;
- USHORT nEnd = CountDirChg();
- for( USHORT nX = 0; nX < nEnd; ++nX )
- {
- if( nPos < GetDirChg( nX ) &&
- ( nX + 1 == nEnd || GetDirType( nX + 1 ) <= nCurrDir ) )
- 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;
-}
-
-/*************************************************************************
- * SwScriptInfo::MaskHiddenRanges(..)
- * Takes a string and replaced the hidden ranges with cChar.
- **************************************************************************/
-
-USHORT SwScriptInfo::MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
- const xub_StrLen nStt, const xub_StrLen nEnd,
- const xub_Unicode cChar )
-{
- ASSERT( rNode.GetTxt().Len() == rText.Len(), "MaskHiddenRanges, string len mismatch" )
-
- 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++);
-
- if ( nHiddenEnd < nStt || nHiddenStart > nEnd )
- continue;
-
- while ( nHiddenStart < nHiddenEnd && nHiddenStart < nEnd )
- {
- if ( nHiddenStart >= nStt && nHiddenStart < nEnd )
- {
- rText.SetChar( nHiddenStart, cChar );
- ++nNumOfHiddenChars;
- }
- ++nHiddenStart;
- }
- }
-
- return nNumOfHiddenChars;
-}
-
-/*************************************************************************
- * 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;
-}
-
-
-#if OSL_DEBUG_LEVEL > 1
-/*************************************************************************
- * SwScriptInfo::CompType(..)
- * returns the type of the compressed character
- *************************************************************************/
-
-BYTE SwScriptInfo::CompType( const xub_StrLen nPos ) const
-{
- 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;
-}
-#endif
-
-/*************************************************************************
- * 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 );
-#if OSL_DEBUG_LEVEL > 1
- ASSERT( nType == CompType( nIdx ), "Gimme the right type!" );
-#endif
- 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;
-}
-
-/*************************************************************************
- * SwScriptInfo::KashidaJustify()
- *************************************************************************/
-
-USHORT SwScriptInfo::KashidaJustify( long* pKernArray, long* pScrArray,
- xub_StrLen nStt, xub_StrLen nLen,
- long nSpaceAdd ) const
-{
- 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;
- long nKashAdd = nSpaceAdd;
-
- 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 ] += nKashAdd;
- if ( pScrArray )
- pScrArray[ nArrayPos ] += nKashAdd;
- ++nArrayPos;
- }
-
- nKashAdd += nSpaceAdd;
- }
- }
-
- return 0;
-}
-
-/*************************************************************************
- * 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;
-}
-
-/*************************************************************************
- * SwScriptInfo::ThaiJustify()
- *************************************************************************/
-
-USHORT SwScriptInfo::ThaiJustify( const XubString& rTxt, long* pKernArray,
- long* pScrArray, xub_StrLen nStt,
- xub_StrLen nLen, xub_StrLen nNumberOfBlanks,
- long nSpaceAdd )
-{
- ASSERT( nStt + nLen <= rTxt.Len(), "String in ThaiJustify too small" )
-
- SwTwips nNumOfTwipsToDistribute = nSpaceAdd * nNumberOfBlanks /
- SPACING_PRECISION_FACTOR;
-
- 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 ) &&
- ( 0xE47 > cCh || cCh > 0xE4E ) && cCh != 0xE31 )
- {
- if ( nNumberOfBlanks > 0 )
- {
- nSpaceAdd = nNumOfTwipsToDistribute / nNumberOfBlanks;
- --nNumberOfBlanks;
- nNumOfTwipsToDistribute -= nSpaceAdd;
- }
- nSpaceSum += nSpaceAdd;
- ++nCnt;
- }
-
- if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
- if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
- }
-
- return nCnt;
-}
-
-/*************************************************************************
- * SwScriptInfo::GetScriptInfo()
- *************************************************************************/
-
-SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTxtNode& rTNd,
- sal_Bool bAllowInvalid )
-{
- SwClientIter aClientIter( (SwTxtNode&)rTNd );
- SwClient* pLast = aClientIter.GoStart();
- SwScriptInfo* pScriptInfo = 0;
-
- while( pLast )
- {
- if ( pLast->ISA( SwTxtFrm ) )
- {
- pScriptInfo = (SwScriptInfo*)((SwTxtFrm*)pLast)->GetScriptInfo();
- if ( pScriptInfo )
- {
- if ( !bAllowInvalid && STRING_LEN != pScriptInfo->GetInvalidity() )
- pScriptInfo = 0;
- else break;
- }
- }
- pLast = ++aClientIter;
- }
-
- return pScriptInfo;
-}
-
-/*************************************************************************
- * 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 )
- {
- USHORT 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 IDocumentRedlineAccess& rIDRA = *rNode.getIDocumentRedlineAccess();
- if ( rHiddenMulti.GetRangeCount() && IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineMode() ) )
- {
- USHORT nAct = rIDRA.GetRedlinePos( rNode, USHRT_MAX );
-
- for ( ; nAct < rIDRA.GetRedlineTbl().Count(); nAct++ )
- {
- const SwRedline* pRed = rIDRA.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 );
-}
-