From 6ecc856f8cc90bd18b29523460570e9358792d34 Mon Sep 17 00:00:00 2001 From: Jens-Heiner Rechtien Date: Mon, 5 Jan 2009 15:33:41 +0000 Subject: CWS-TOOLING: integrate CWS kashidafix 2008-12-15 15:31:40 +0100 hde r265507 : #i97098# 2008-12-15 15:30:52 +0100 hde r265506 : #i97098# 2008-12-10 14:08:07 +0100 fredrikh r265184 : i97098 2008-11-27 15:07:01 +0100 hdu r264493 : #i60594# only determine GetNextGlyphs() charpos if requested+available 2008-11-27 14:09:42 +0100 hdu r264487 : #i60594# simplify RTL-glyph-injection also for manual-cell-aligned cases 2008-11-26 13:25:08 +0100 fme r264379 : #i60594# Kashida fixes - syntax error 2008-11-26 13:16:22 +0100 hdu r264374 : #i60594# allow glyph injection even if there is not enough room if they can overlap 2008-11-25 16:40:20 +0100 hdu r264314 : #i60594# fix glyph-injection for PDF-export for usp>=1.6 2008-11-24 16:17:11 +0100 hdu r264254 : #i71804# adjust glyph-fallback usp-methods for new glyph-injection infrastructure 2008-11-24 16:15:30 +0100 hdu r264253 : #i71804# disable glyph-injection for glyph-fallback mixing 2008-11-20 08:29:15 +0100 fme r264027 : #i60594# Fix correction 2008-11-14 10:10:54 +0100 fme r263666 : CWS-TOOLING: rebase CWS kashidafix to trunk@263288 (milestone: DEV300:m35) 2008-10-30 16:35:30 +0100 fme r262834 : #i60594# migrate cws kashidafix to SVN. --- sw/inc/breakit.hxx | 4 +- sw/inc/viewsh.hxx | 4 +- sw/source/core/bastyp/breakit.cxx | 7 +- sw/source/core/inc/scriptinfo.hxx | 72 +- sw/source/core/inc/txtfrm.hxx | 11 +- sw/source/core/text/ScriptInfo.cxx | 1366 ----------------------------------- sw/source/core/text/inftxt.cxx | 7 +- sw/source/core/text/itradj.cxx | 203 +++++- sw/source/core/text/itrcrsr.cxx | 10 +- sw/source/core/text/itrform2.cxx | 18 +- sw/source/core/text/itrtxt.hxx | 4 +- sw/source/core/text/porfld.cxx | 21 +- sw/source/core/text/porlay.cxx | 371 +++++++++- sw/source/core/text/pormulti.cxx | 54 +- sw/source/core/text/pormulti.hxx | 8 +- sw/source/core/text/portxt.cxx | 25 +- sw/source/core/text/txtfrm.cxx | 25 +- sw/source/core/txtnode/fntcache.cxx | 97 +-- sw/source/core/txtnode/swfont.cxx | 10 +- sw/source/core/txtnode/thints.cxx | 20 +- sw/source/core/view/viewsh.cxx | 10 +- 21 files changed, 803 insertions(+), 1544 deletions(-) delete mode 100644 sw/source/core/text/ScriptInfo.cxx diff --git a/sw/inc/breakit.hxx b/sw/inc/breakit.hxx index 53940bd00e37..7855b8a68728 100644 --- a/sw/inc/breakit.hxx +++ b/sw/inc/breakit.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: breakit.hxx,v $ - * $Revision: 1.12 $ + * $Revision: 1.12.112.1 $ * * This file is part of OpenOffice.org. * @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ public: // @@@ backward compatibility @@@ com::sun::star::uno::Reference< com::sun::star::i18n::XBreakIterator > xBreak; + com::sun::star::uno::Reference< com::sun::star::i18n::XScriptTypeDetector > xCTLDetect; const com::sun::star::uno::Reference< com::sun::star::i18n::XBreakIterator > & GetBreakIter() { diff --git a/sw/inc/viewsh.hxx b/sw/inc/viewsh.hxx index 318490a5113e..6a7918a414b3 100644 --- a/sw/inc/viewsh.hxx +++ b/sw/inc/viewsh.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: viewsh.hxx,v $ - * $Revision: 1.64.210.2 $ + * $Revision: 1.65.40.1 $ * * This file is part of OpenOffice.org. * @@ -231,7 +231,7 @@ public: inline sal_Bool HasInvalidRect() const { return aInvalidRect.HasArea(); } void ChgHyphenation() { Reformat(); } - void ChgNumberDigits() { Reformat(); } + void ChgNumberDigits(); //Methoden fuer Paint- und Scrollrects, die auf allen Shells im //Ring arbeiten. diff --git a/sw/source/core/bastyp/breakit.cxx b/sw/source/core/bastyp/breakit.cxx index 113899e5348a..f463c818c604 100644 --- a/sw/source/core/bastyp/breakit.cxx +++ b/sw/source/core/bastyp/breakit.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: breakit.cxx,v $ - * $Revision: 1.16 $ + * $Revision: 1.16.112.1 $ * * This file is part of OpenOffice.org. * @@ -79,6 +79,11 @@ SwBreakIt::SwBreakIt( m_xMSF->createInstance( rtl::OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), uno::UNO_QUERY); + + xCTLDetect = uno::Reference< i18n::XScriptTypeDetector >( + m_xMSF->createInstance( + rtl::OUString::createFromAscii( "com.sun.star.i18n.ScriptTypeDetector" ) ), + uno::UNO_QUERY); } } diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index 55e1d722042d..39dded3d3257 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: scriptinfo.hxx,v $ - * $Revision: 1.21 $ + * $Revision: 1.21.112.4 $ * * This file is part of OpenOffice.org. * @@ -106,6 +106,9 @@ private: SvXub_StrLens aDirChg; SvBytes aDirType; SvXub_StrLens aKashida; + SvXub_StrLens aKashidaInvalid; + SvXub_StrLens aNoKashidaLine; + SvXub_StrLens aNoKashidaLineEnd; SvXub_StrLens aCompChg; SvXub_StrLens aCompLen; SvXub_StrLens aHiddenChg; @@ -115,6 +118,12 @@ private: void UpdateBidiInfo( const String& rTxt ); + sal_Bool IsKashidaValid ( xub_StrLen nKashPos ) const; + void MarkKashidaInvalid ( xub_StrLen nKashPos ); + void ClearKashidaInvalid ( xub_StrLen nKashPos ); + bool MarkOrClearKashidaInvalid( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount ); + bool IsKashidaLine ( xub_StrLen nCharIdx ) const; + public: enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE }; @@ -254,7 +263,7 @@ public: The printers kerning array. Optional. @param pScrArray The screen kerning array. Optional. - @param nIdx + @param nStt Start referring to the paragraph. @param nLen The number of characters to be considered. @@ -262,18 +271,59 @@ public: The value which has to be added to a kashida opportunity. @return The number of kashida opportunities in the given range */ - USHORT KashidaJustify( sal_Int32* pKernArray ,sal_Int32* pScrArray, - xub_StrLen nIdx, xub_StrLen nLen, - long nSpaceAdd = 0 ) const; + USHORT KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray, + xub_StrLen nStt, xub_StrLen nLen, + long nSpaceAdd = 0) const; + +/** Clears array of kashidas marked as invalid + */ + inline void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { MarkOrClearKashidaInvalid( nStt, nLen, false, 0 ); } + +/** Marks nCnt kashida positions as invalid + pKashidaPositions: array of char indices relative to the paragraph +*/ + bool MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions ); + +/** Marks nCnt kashida positions as invalid + in the given text range + */ + inline bool MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen nStt, xub_StrLen nLen ) + { return MarkOrClearKashidaInvalid( nStt, nLen, true, nCnt ); } + +/** retrieves kashida opportunities for a given text range. + returns the number of kashida positions in the given text range + + pKashidaPositions: buffer to reveive the char indices of the + kashida opportunties relative to the paragraph +*/ + USHORT GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen, + xub_StrLen* pKashidaPosition ); + -/** Checks if language is one of the 16 Arabic languages - @descr Checks if language is one of the 16 Arabic languages - @param aLang - The language which has to be checked. - @return Returns if the language is an Arabic language + +/** Use regular blank justification instead of kashdida justification for the given line of text. + nStt Start char index of the line referring to the paragraph. + nLen Number of characters in the line */ - static BOOL IsArabicLanguage( LanguageType aLang ); + void SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen ); + +/** Clear forced blank justification for a given line. + nStt Start char index of the line referring to the paragraph. + nLen Number of characters in the line +*/ + void ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen ); + +/** Checks if text is Arabic text. + + @descr Checks if text is Arabic text. + @param rTxt + The text to check + @param nStt + Start index of the text + @return Returns if the language is an Arabic language + */ + static sal_Bool IsArabicText( const XubString& rTxt, xub_StrLen nStt, xub_StrLen nLen ); /** Performes a thai justification on the kerning array diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 4e7293d9b6d8..b0b2b807ab43 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: txtfrm.hxx,v $ - * $Revision: 1.56.212.1 $ + * $Revision: 1.56.110.1 $ * * This file is part of OpenOffice.org. * @@ -824,4 +824,13 @@ public: void SetAuto(); }; +class SwDigitModeModifier +{ + const OutputDevice& rOut; + LanguageType nOldLanguageType; +public: + SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ); + ~SwDigitModeModifier(); +}; + #endif 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 - * - * 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 -#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ -#include -#endif -#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL -#include -#endif -#include -#include -#include -#include -#include -#include -#include // GetCurFld -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace ::com::sun::star; -using namespace ::com::sun::star::i18n::ScriptType; - -#include - -/************************************************************************* - * 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 ); -} - diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index e367f72a7fd5..268c30a802e7 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: inftxt.cxx,v $ - * $Revision: 1.123 $ + * $Revision: 1.123.20.1 $ * * This file is part of OpenOffice.org. * @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -344,7 +343,7 @@ void SwTxtSizeInfo::CtorInitTxtSizeInfo( SwTxtFrm *pFrame, SwFont *pNewFnt, nDirection = DIR_LEFT2RIGHT; } - LanguageType eLang; +/* LanguageType eLang; const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions(); if ( SvtCTLOptions::NUMERALS_HINDI == rCTLOptions.GetCTLTextNumerals() ) eLang = LANGUAGE_ARABIC; @@ -354,7 +353,7 @@ void SwTxtSizeInfo::CtorInitTxtSizeInfo( SwTxtFrm *pFrame, SwFont *pNewFnt, eLang = (LanguageType)::GetAppLanguage(); pOut->SetDigitLanguage( eLang ); - pRef->SetDigitLanguage( eLang ); + pRef->SetDigitLanguage( eLang );*/ // // The Options diff --git a/sw/source/core/text/itradj.cxx b/sw/source/core/text/itradj.cxx index e31afabf0762..b4b16d3f3ecb 100644 --- a/sw/source/core/text/itradj.cxx +++ b/sw/source/core/text/itradj.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: itradj.cxx,v $ - * $Revision: 1.24 $ + * $Revision: 1.24.112.4 $ * * This file is part of OpenOffice.org. * @@ -30,6 +30,10 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" +#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ +#include +#endif +#include #include #include "frame.hxx" // CalcFlyAdjust() @@ -45,6 +49,8 @@ #define MIN_TAB_WIDTH 60 +using namespace ::com::sun::star; + /************************************************************************* * SwTxtAdjuster::FormatBlock() *************************************************************************/ @@ -123,6 +129,140 @@ void SwTxtAdjuster::FormatBlock( ) GetInfo().GetParaPortion()->GetRepaint()->SetOfst(0); } +/************************************************************************* + * lcl_CheckKashidaPositions() + *************************************************************************/ +bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, + xub_StrLen& nKashidas, xub_StrLen& nGluePortion ) +{ + // i60594 validate Kashida justification + xub_StrLen nIdx = rItr.GetStart(); + xub_StrLen nEnd = rItr.GetEnd(); + + // Note on calling KashidaJustify(): + // Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean + // total number of kashida positions, or the number of kashida positions after some positions + // have been dropped. + // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before. + nKashidas = rSI.KashidaJustify ( 0, 0, rItr.GetStart(), rItr.GetLength(), 0 ); + + if (!nKashidas) // nothing to do + return true; + + // kashida positions found in SwScriptInfo are not necessarily valid in every font + // if two characters are replaced by a ligature glyph, there will be no place for a kashida + xub_StrLen* pKashidaPos = new xub_StrLen [ nKashidas ]; + xub_StrLen* pKashidaPosDropped = new xub_StrLen [ nKashidas ]; + rSI.GetKashidaPositions ( nIdx, rItr.GetLength(), pKashidaPos ); + xub_StrLen nKashidaIdx = 0; + while ( nKashidas && nIdx < nEnd ) + { + rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() ); + xub_StrLen nNext = rItr.GetNextAttr(); + + // is there also a script change before? + // if there is, nNext should point to the script change + xub_StrLen nNextScript = rSI.NextScriptChg( nIdx ); + if( nNextScript < nNext ) + nNext = nNextScript; + + if ( nNext == STRING_LEN || nNext > nEnd ) + nNext = nEnd; + xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx ); + if ( nKashidasInAttr ) + { + xub_StrLen nKashidasDropped = 0; + if ( !SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) ) + { + nKashidasDropped = nKashidasInAttr; + nKashidas -= nKashidasDropped; + } + else + { + ULONG nOldLayout = rInf.GetOut()->GetLayoutMode(); + rInf.GetOut()->SetLayoutMode ( nOldLayout | TEXT_LAYOUT_BIDI_RTL ); + nKashidasDropped = rInf.GetOut()->ValidateKashidas ( rInf.GetTxt(), nIdx, nNext - nIdx, + nKashidasInAttr, pKashidaPos + nKashidaIdx, + pKashidaPosDropped ); + rInf.GetOut()->SetLayoutMode ( nOldLayout ); + if ( nKashidasDropped ) + { + rSI.MarkKashidasInvalid ( nKashidasDropped, pKashidaPosDropped ); + nKashidas -= nKashidasDropped; + nGluePortion -= nKashidasDropped; + } + } + nKashidaIdx += nKashidasInAttr; + } + nIdx = nNext; + } + delete[] pKashidaPos; + delete[] pKashidaPosDropped; + + // return false if all kashidas have been eliminated + return (nKashidas > 0); +} + +/************************************************************************* + * lcl_CheckKashidaWidth() + *************************************************************************/ +bool lcl_CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas, + xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd ) +{ + // check kashida width + // if width is smaller than minimal kashida width allowed by fonts in the current line + // drop one kashida after the other until kashida width is OK + bool bAddSpaceChanged; + while ( nKashidas ) + { + bAddSpaceChanged = false; + xub_StrLen nIdx = rItr.GetStart(); + xub_StrLen nEnd = rItr.GetEnd(); + while ( nIdx < nEnd ) + { + rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() ); + xub_StrLen nNext = rItr.GetNextAttr(); + + // is there also a script change before? + // if there is, nNext should point to the script change + xub_StrLen nNextScript = rSI.NextScriptChg( nIdx ); + if( nNextScript < nNext ) + nNext = nNextScript; + + if ( nNext == STRING_LEN || nNext > nEnd ) + nNext = nEnd; + xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx ); + + long nFontMinKashida = rInf.GetOut()->GetMinKashida(); + if ( nFontMinKashida && nKashidasInAttr && SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) ) + { + xub_StrLen nKashidasDropped = 0; + while ( nKashidas && nGluePortion && nKashidasInAttr && + nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida ) + { + --nGluePortion; + --nKashidas; + --nKashidasInAttr; + ++nKashidasDropped; + if( !nKashidas || !nGluePortion ) // nothing left, return false to + return false; // do regular blank justification + + nSpaceAdd = nGluePortionWidth / nGluePortion; + bAddSpaceChanged = true; + } + if( nKashidasDropped ) + rSI.MarkKashidasInvalid( nKashidasDropped, nIdx, nNext - nIdx ); + } + if ( bAddSpaceChanged ) + break; // start all over again + nIdx = nNext; + } + if ( !bAddSpaceChanged ) + break; // everything was OK + } + return true; +} + /************************************************************************* * SwTxtAdjuster::CalcNewBlock() * @@ -132,7 +272,7 @@ void SwTxtAdjuster::FormatBlock( ) *************************************************************************/ void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent, - const SwLinePortion *pStopAt, SwTwips nReal ) + const SwLinePortion *pStopAt, SwTwips nReal, bool bSkipKashida ) { ASSERT( GetInfo().IsMulti() || SVX_ADJUST_BLOCK == GetAdjust(), "CalcNewBlock: Why?" ); @@ -143,9 +283,31 @@ void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent, xub_StrLen nCharCnt = 0; MSHORT nSpaceIdx = 0; + // i60591: hennerdrews + SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo(); + SwTxtSizeInfo aInf ( GetTxtFrm() ); + SwTxtIter aItr ( GetTxtFrm(), &aInf ); + + if ( rSI.CountKashida() ) + { + while (aItr.GetCurr() != pCurrent && aItr.GetNext()) + aItr.Next(); + + if( bSkipKashida ) + { + rSI.SetNoKashidaLine ( aItr.GetStart(), aItr.GetLength()); + } + else + { + rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() ); + rSI.ClearNoKashidaLine( aItr.GetStart(), aItr.GetLength() ); + } + } + // Nicht vergessen: // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite ! - CalcRightMargin( pCurrent, nReal ); + if (!bSkipKashida) + CalcRightMargin( pCurrent, nReal ); // --> FME 2005-06-08 #i49277# const sal_Bool bDoNotJustifyLinesWithManualBreak = @@ -184,7 +346,7 @@ void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent, else if( pMulti->IsDouble() ) nGluePortion = nGluePortion + ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt(); else if ( pMulti->IsBidi() ) - nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt(); + nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt( GetInfo() ); // i60594 } if( pPos->InGlueGrp() ) @@ -197,9 +359,40 @@ void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent, const long nGluePortionWidth = static_cast(pPos)->GetPrtGlue() * SPACING_PRECISION_FACTOR; + xub_StrLen nKashidas = 0; + if( nGluePortion && rSI.CountKashida() && !bSkipKashida ) + { + // kashida positions found in SwScriptInfo are not necessarily valid in every font + // if two characters are replaced by a ligature glyph, there will be no place for a kashida + if ( !lcl_CheckKashidaPositions ( rSI, aInf, aItr, nKashidas, nGluePortion )) + { + // all kashida positions are invalid + // do regular blank justification + pCurrent->FinishSpaceAdd(); + GetInfo().SetIdx( nStart ); + CalcNewBlock( pCurrent, pStopAt, nReal, true ); + return; + } + } + if( nGluePortion ) { - const long nSpaceAdd = nGluePortionWidth / nGluePortion; + long nSpaceAdd = nGluePortionWidth / nGluePortion; + + // i60594 + if( rSI.CountKashida() && !bSkipKashida ) + { + if( !lcl_CheckKashidaWidth( rSI, aInf, aItr, nKashidas, nGluePortion, nGluePortionWidth, nSpaceAdd )) + { + // no kashidas left + // do regular blank justification + pCurrent->FinishSpaceAdd(); + GetInfo().SetIdx( nStart ); + CalcNewBlock( pCurrent, pStopAt, nReal, true ); + return; + } + } + pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx ); pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() ); } diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx index 21012c8eda7b..6436fe23fc20 100644 --- a/sw/source/core/text/itrcrsr.cxx +++ b/sw/source/core/text/itrcrsr.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: itrcrsr.cxx,v $ - * $Revision: 1.81 $ + * $Revision: 1.81.40.1 $ * * This file is part of OpenOffice.org. * @@ -506,6 +506,7 @@ void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst, SwTwips nTmpFirst = 0; SwLinePortion *pPor = pCurr->GetFirstPortion(); SwBidiPortion* pLastBidiPor = 0; + SwTwips nLastBidiPorWidth = 0; SvUShorts* pKanaComp = pCurr->GetpKanaComp(); MSHORT nSpaceIdx = 0; MSHORT nKanaIdx = 0; @@ -649,7 +650,11 @@ void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst, // cursor level if ( ((SwMultiPortion*)pPor)->IsBidi() && aInf.GetIdx() + pPor->GetLen() == nOfst ) + { pLastBidiPor = (SwBidiPortion*)pPor; + nLastBidiPorWidth = pLastBidiPor->Width() + + pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );; + } } aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() ); @@ -1086,8 +1091,7 @@ void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst, { // we came from inside the bidi portion, we want to blink // behind the portion - pOrig->Pos().X() -= pLastBidiPor->Width() + - pLastBidiPor->CalcSpacing( nSpaceAdd, aInf ); + pOrig->Pos().X() -= nLastBidiPorWidth; // Again, there is a special case: logically behind // the portion can actually mean that the cursor is inside diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 0fe7b2ffe31c..00440427eaf8 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: itrform2.cxx,v $ - * $Revision: 1.107 $ + * $Revision: 1.107.20.2 $ * * This file is part of OpenOffice.org. * @@ -879,17 +879,17 @@ SwTxtPortion *SwTxtFormatter::NewTxtPortion( SwTxtFormatInfo &rInf ) Seek( rInf.GetIdx() ); SwTxtPortion *pPor = WhichTxtPor( rInf ); - // maximal bis zum naechsten Attributwchsel. - xub_StrLen nNextAttr = GetNextAttr(); + // until next attribute change: + const xub_StrLen nNextAttr = GetNextAttr(); xub_StrLen nNextChg = Min( nNextAttr, rInf.GetTxt().Len() ); - nNextAttr = pScriptInfo->NextScriptChg( rInf.GetIdx() ); + // end of script type: + const xub_StrLen nNextScript = pScriptInfo->NextScriptChg( rInf.GetIdx() ); + nNextChg = Min( nNextChg, nNextScript ); - xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() ); - nNextAttr = Min( nNextAttr, nNextDir ); - - if( nNextChg > nNextAttr ) - nNextChg = nNextAttr; + // end of direction: + const xub_StrLen nNextDir = pScriptInfo->NextDirChg( rInf.GetIdx() ); + nNextChg = Min( nNextChg, nNextDir ); // 7515, 7516, 3470, 6441 : Turbo-Boost // Es wird unterstellt, dass die Buchstaben eines Fonts nicht diff --git a/sw/source/core/text/itrtxt.hxx b/sw/source/core/text/itrtxt.hxx index 923748ee901b..58e77479f51e 100644 --- a/sw/source/core/text/itrtxt.hxx +++ b/sw/source/core/text/itrtxt.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: itrtxt.hxx,v $ - * $Revision: 1.22 $ + * $Revision: 1.21.40.3 $ * * This file is part of OpenOffice.org. * @@ -230,7 +230,7 @@ protected: inline SwTxtAdjuster(SwTxtNode* pTxtNode) : SwTxtMargin(pTxtNode) { } // spannt beim Blocksatz die Glues auf. void CalcNewBlock( SwLineLayout *pCurr, const SwLinePortion *pStopAt, - SwTwips nReal = 0 ); + SwTwips nReal = 0, bool bSkipKashida = false ); SwTwips CalcKanaAdj( SwLineLayout *pCurr ); public: inline SwTxtAdjuster( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf ) : SwTxtMargin(pTxtFrm!=NULL?pTxtFrm->GetTxtNode():NULL) diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index ba7fd2813155..8443bf2c2e9b 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: porfld.cxx,v $ - * $Revision: 1.62 $ + * $Revision: 1.62.110.1 $ * * This file is part of OpenOffice.org. * @@ -262,6 +262,25 @@ void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf ) ubidi_close( pBidi ); const xub_StrLen nNextDirChg = (xub_StrLen)nEnd; nNextScriptChg = Min( nNextScriptChg, nNextDirChg ); + + // #i89825# change the script type also to CTL + // if there is no strong LTR char in the LTR run (numbers) + if ( nCurrDir != UBIDI_RTL ) + { + nCurrDir = UBIDI_RTL; + for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx ) + { + UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx )); + if ( nCharDir == U_LEFT_TO_RIGHT || + nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || + nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) + { + nCurrDir = UBIDI_LTR; + break; + } + } + } + if ( nCurrDir == UBIDI_RTL ) nTmp = SW_CTL; } diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 9adc64345cd0..bcd08a324b61 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: porlay.cxx,v $ - * $Revision: 1.67 $ + * $Revision: 1.67.14.4 $ * * This file is part of OpenOffice.org. * @@ -48,6 +48,9 @@ #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ #include #endif +#ifndef _COM_SUN_STAR_I18N_CTLSCRIPTTYPE_HDL_ +#include +#endif #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL #include #endif @@ -58,6 +61,7 @@ #include #include #include +#include #include #include #include // SwRedlineTbl @@ -76,6 +80,7 @@ using namespace i18n::ScriptType; //#ifdef BIDI #include +#include //unicode::getUnicodeScriptType sal_Bool isAlefChar ( xub_Unicode cCh ) { @@ -161,6 +166,16 @@ sal_Bool isFeChar ( xub_Unicode cCh ) { return ( cCh == 0x641 || ( cCh >= 0x6A1 && cCh <= 0x6A6 ) ); } +sal_Bool isTransparentChar ( xub_Unicode cCh ) +{ + return ( ( cCh >= 0x610 && cCh <= 0x61A ) || + ( cCh >= 0x64B && cCh <= 0x65E ) || + ( cCh == 0x670 ) || + ( cCh >= 0x6D6 && cCh <= 0x6DC ) || + ( cCh >= 0x6DF && cCh <= 0x6E4 ) || + ( cCh >= 0x6E7 && cCh <= 0x6E8 ) || + ( cCh >= 0x6EA && cCh <= 0x6ED )); +} /************************************************************************* * lcl_IsLigature @@ -171,9 +186,9 @@ sal_Bool isFeChar ( xub_Unicode cCh ) sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh ) { // Lam + Alef - return ( 0x644 == cCh && 0x627 == cNextCh ) || + return ( isLamChar ( cCh ) && isAlefChar ( cNextCh )); // || // Beh + Reh - ( 0x628 == cCh && 0x631 == cNextCh ); + // ( 0x628 == cCh && 0x631 == cNextCh ); } /************************************************************************* @@ -188,6 +203,10 @@ sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh ) // 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: + + // (hennerdrewes) to do: this should be reworked + // use the isXXXChar functions to exclude the non-connecting character classes + sal_Bool bRet = 0x628 == cPrevCh || ( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) || ( 0x633 <= cPrevCh && cPrevCh <= 0x643 ) || @@ -207,8 +226,21 @@ sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh ) return bRet; } -//#endif - +/************************************************************************* + * lcl_HasStrongLTR + *************************************************************************/ + bool lcl_HasStrongLTR ( const String& rTxt, xub_StrLen nStart, xub_StrLen nEnd ) + { + for ( xub_StrLen nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx ) + { + const UCharDirection nCharDir = u_charDirection ( rTxt.GetChar ( nCharIdx )); + if ( nCharDir == U_LEFT_TO_RIGHT || + nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || + nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) + return true; + } + return false; + } /************************************************************************* * SwLineLayout::~SwLineLayout() @@ -981,11 +1013,32 @@ void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL ) "Inserting WEAK into SwScriptInfo structure" ); ASSERT( STRING_LEN != nChg, "65K? Strange length of script section" ); - nChg = (xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nChg, nScript ); + xub_StrLen nSearchStt = nChg; + nChg = (xub_StrLen)pBreakIt->xBreak->endOfScript( rTxt, nSearchStt, nScript ); if ( nChg > rTxt.Len() ) nChg = rTxt.Len(); + // --> FME 2008-09-17 #i28203# + // for 'complex' portions, we make sure that a portion does not contain more + // than one script: + if( pBreakIt->xCTLDetect.is() && i18n::ScriptType::COMPLEX == nScript ) + { + const short nScriptType = pBreakIt->xCTLDetect->getCTLScriptType( rTxt, nSearchStt ); + xub_StrLen nNextCTLScriptStart = nSearchStt; + short nCurrentScriptType = nScriptType; + while( com::sun::star::i18n::CTLScriptType::CTL_UNKNOWN == nCurrentScriptType || nScriptType == nCurrentScriptType ) + { + nNextCTLScriptStart = (xub_StrLen)pBreakIt->xCTLDetect->endOfCTLScriptType( rTxt, nNextCTLScriptStart ); + if( nNextCTLScriptStart < rTxt.Len() && nNextCTLScriptStart < nChg ) + nCurrentScriptType = pBreakIt->xCTLDetect->getCTLScriptType( rTxt, nNextCTLScriptStart ); + else + break; + } + nChg = Min( nChg, nNextCTLScriptStart ); + } + // <-- + aScriptChg.Insert( nChg, nCnt ); aScriptType.Insert( nScript, nCnt++ ); @@ -1206,7 +1259,7 @@ void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL ) // 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 ) + if ( !isTransparentChar ( cCh) ) cPrevCh = cCh; ++nIdx; @@ -1260,15 +1313,21 @@ void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL ) { UpdateBidiInfo( rTxt ); - // #i16354# Change script type for RTL text to CTL. + // #i16354# Change script type for RTL text to CTL: + // 1. All text in RTL runs will use the CTL font + // #i89825# change the script type also to CTL (hennerdrewes) + // 2. Text in embedded LTR runs that does not have any strong LTR characters (numbers!) for ( USHORT nDirIdx = 0; nDirIdx < aDirChg.Count(); ++nDirIdx ) { - if ( GetDirType( nDirIdx ) == UBIDI_RTL ) - { + const BYTE nCurrDirType = GetDirType( nDirIdx ); // 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 ); + + if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run + ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( rTxt, nStart, nEnd ) ) ) // non-strong text in embedded LTR run + { // nScriptIdx points into the ScriptArrays: USHORT nScriptIdx = 0; @@ -1279,8 +1338,8 @@ void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL ) while ( GetScriptChg( nScriptIdx ) <= nStart ) ++nScriptIdx; - xub_StrLen nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0; - BYTE nScriptTypeOfGroup = GetScriptType( nScriptIdx ); + const xub_StrLen nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0; + const BYTE nScriptTypeOfGroup = GetScriptType( nScriptIdx ); ASSERT( nStartPosOfGroup <= nStart && GetScriptChg( nScriptIdx ) > nStart, "Script override with CTL font trouble" ) @@ -1804,12 +1863,22 @@ long SwScriptInfo::Compress( sal_Int32* pKernArray, xub_StrLen nIdx, xub_StrLen * SwScriptInfo::KashidaJustify() *************************************************************************/ -USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray, - xub_StrLen nStt, xub_StrLen nLen, - long nSpaceAdd ) const +// Note on calling KashidaJustify(): +// Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean +// total number of kashida positions, or the number of kashida positions after some positions +// have been dropped, depending on the state of the aKashidaInvalid array. + +USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, + sal_Int32* pScrArray, + xub_StrLen nStt, + xub_StrLen nLen, + long nSpaceAdd ) const { ASSERT( nLen, "Kashida justification without text?!" ) + if( !IsKashidaLine(nStt)) + return STRING_LEN; + // evaluate kashida informatin in collected in SwScriptInfo USHORT nCntKash = 0; @@ -1823,23 +1892,32 @@ USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray const xub_StrLen nEnd = nStt + nLen; - if ( ! pKernArray ) + USHORT nCntKashEnd = nCntKash; + while ( nCntKashEnd < CountKashida() ) { - USHORT nCntKashEnd = nCntKash; - while ( nCntKashEnd < CountKashida() ) - { - if ( nEnd <= GetKashida( nCntKashEnd ) ) - break; - else - nCntKashEnd++; - } + if ( nEnd <= GetKashida( nCntKashEnd ) ) + break; + else + nCntKashEnd++; + } - return nCntKashEnd - nCntKash; + USHORT nActualKashCount = nCntKashEnd - nCntKash; + for ( USHORT i = nCntKash; i < nCntKashEnd; ++i ) + { + if ( nActualKashCount && !IsKashidaValid ( i ) ) + --nActualKashCount; } + if ( !pKernArray ) + return nActualKashCount; + // do nothing if there is no more kashida if ( nCntKash < CountKashida() ) { + // skip any invalid kashidas + while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd ) + ++nCntKash; + xub_StrLen nKashidaPos = GetKashida( nCntKash ); xub_StrLen nIdx = nKashidaPos; long nKashAdd = nSpaceAdd; @@ -1849,7 +1927,11 @@ USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray USHORT nArrayPos = nIdx - nStt; // next kashida position - nIdx = ++nCntKash < CountKashida() ? GetKashida( nCntKash ) : nEnd; + ++nCntKash; + while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd ) + ++nCntKash; + + nIdx = nCntKash < CountKashida() && IsKashidaValid ( nCntKash ) ? GetKashida( nCntKash ) : nEnd; if ( nIdx > nEnd ) nIdx = nEnd; @@ -1859,10 +1941,9 @@ USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray { pKernArray[ nArrayPos ] += nKashAdd; if ( pScrArray ) - pScrArray[ nArrayPos ] += nKashAdd; + pScrArray[ nArrayPos ] += nKashAdd; ++nArrayPos; } - nKashAdd += nSpaceAdd; } } @@ -1871,20 +1952,230 @@ USHORT SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray } /************************************************************************* - * SwScriptInfo::IsArabicLanguage() + * SwScriptInfo::IsArabicText() + * + * Checks if the current text is 'Arabic' text. Note that only the first + * character has to be checked because a ctl portion only contains one + * script, see NewTxtPortion + *************************************************************************/ +sal_Bool SwScriptInfo::IsArabicText( const XubString& rTxt, xub_StrLen nStt, xub_StrLen nLen ) +{ + using namespace ::com::sun::star::i18n; + static ScriptTypeList typeList[] = { + { UnicodeScript_kArabic, UnicodeScript_kArabic, UnicodeScript_kArabic }, // 11, + { UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, UnicodeScript_kScriptCount } // 88 + }; + + // go forward if current position does not hold a regular character: + const CharClass& rCC = GetAppCharClass(); + sal_Int32 nIdx = nStt; + const xub_StrLen nEnd = nStt + nLen; + while ( nIdx < nEnd && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) ) + { + ++nIdx; + } + + if( nIdx == nEnd ) +{ + // no regular character found in this portion. Go backward: + --nIdx; + while ( nIdx >= 0 && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) ) + { + --nIdx; + } + } + + if( nIdx >= 0 ) + { + const xub_Unicode cCh = rTxt.GetChar( (xub_StrLen)nIdx ); + const sal_Int16 type = unicode::getUnicodeScriptType( cCh, typeList, UnicodeScript_kScriptCount ); + return type == UnicodeScript_kArabic; + } + return sal_False; +} + +/************************************************************************* + * SwScriptInfo::IsKashidaValid() *************************************************************************/ -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; +sal_Bool SwScriptInfo::IsKashidaValid ( xub_StrLen nKashPos ) const +{ + for ( xub_StrLen i = 0; i < aKashidaInvalid.Count(); ++i ) + { + if ( aKashidaInvalid [ i ] == nKashPos ) + return false; + } + return true; +} + +/************************************************************************* + * SwScriptInfo::ClearKashidaInvalid() + *************************************************************************/ + +void SwScriptInfo::ClearKashidaInvalid ( xub_StrLen nKashPos ) +{ + for ( xub_StrLen i = 0; i < aKashidaInvalid.Count(); ++i ) + { + if ( aKashidaInvalid [ i ] == nKashPos ) + { + aKashidaInvalid.Remove (i, 1); + return; + } + } +} + +/************************************************************************* + * SwScriptInfo::MarkOrClearKashidaInvalid() + *************************************************************************/ +// bMark == true: +// marks the first valid kashida in the given text range as invalid + +// bMark == false: +// clears all kashida invalid flags in the given text range + +bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount ) +{ + USHORT nCntKash = 0; + while( nCntKash < CountKashida() ) + { + if ( nStt <= GetKashida( nCntKash ) ) + break; + else + nCntKash++; + } + + const xub_StrLen nEnd = nStt + nLen; + + while ( nCntKash < CountKashida() ) + { + if ( nEnd <= GetKashida( nCntKash ) ) + break; + else + { + if(bMark) + { + if ( IsKashidaValid ( nCntKash ) ) + { + MarkKashidaInvalid ( nCntKash ); + --nMarkCount; + if(!nMarkCount) + return true; + } + } + else + { + ClearKashidaInvalid ( nCntKash ); + } + nCntKash++; + } + } + return false; +} + +void SwScriptInfo::MarkKashidaInvalid ( xub_StrLen nKashPos ) +{ + aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() ); +} + +/************************************************************************* + * SwScriptInfo::GetKashidaPositions() + *************************************************************************/ +// retrieve the kashida positions in the given text range +USHORT SwScriptInfo::GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen, + xub_StrLen* pKashidaPosition ) +{ + USHORT nCntKash = 0; + while( nCntKash < CountKashida() ) + { + if ( nStt <= GetKashida( nCntKash ) ) + break; + else + nCntKash++; + } + + const xub_StrLen nEnd = nStt + nLen; + + USHORT nCntKashEnd = nCntKash; + while ( nCntKashEnd < CountKashida() ) + { + if ( nEnd <= GetKashida( nCntKashEnd ) ) + break; + else + { + pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd ); + nCntKashEnd++; + } + } + return nCntKashEnd - nCntKash; +} + +void SwScriptInfo::SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen ) +{ + aNoKashidaLine.Insert( nStt, aNoKashidaLine.Count()); + aNoKashidaLineEnd.Insert( nStt+nLen, aNoKashidaLineEnd.Count()); +} + +/************************************************************************* + * SwScriptInfo::IsKashidaLine() + *************************************************************************/ +// determines if the line uses kashida justification + +bool SwScriptInfo::IsKashidaLine ( xub_StrLen nCharIdx ) const +{ + for( xub_StrLen i = 0; i < aNoKashidaLine.Count(); ++i ) + { + if( nCharIdx >= aNoKashidaLine[ i ] && nCharIdx < aNoKashidaLineEnd[ i ]) + return false; + } + return true; +} +/************************************************************************* + * SwScriptInfo::ClearKashidaLine() + *************************************************************************/ + +void SwScriptInfo::ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen ) +{ + xub_StrLen i = 0; + while( i < aNoKashidaLine.Count()) + { + if( nStt + nLen >= aNoKashidaLine[ i ] && nStt < aNoKashidaLineEnd [ i ] ) + { + aNoKashidaLine.Remove(i, 1); + aNoKashidaLineEnd.Remove(i, 1); + } + else + ++i; + } +} + +/************************************************************************* + * SwScriptInfo::MarkKashidasInvalid() + *************************************************************************/ +// mark the given character indices as invalid kashida positions +bool SwScriptInfo::MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions ) +{ + ASSERT( pKashidaPositions && nCnt > 0, "Where are kashidas?" ) + + USHORT nCntKash = 0; + xub_StrLen nKashidaPosIdx = 0; + + while ( nCntKash < CountKashida() && nKashidaPosIdx < nCnt ) + { + if ( pKashidaPositions [nKashidaPosIdx] > GetKashida( nCntKash ) ) + { + nCntKash++; + continue; + } + + if ( pKashidaPositions [nKashidaPosIdx] == GetKashida( nCntKash ) && IsKashidaValid ( nCntKash ) ) + { + MarkKashidaInvalid ( nCntKash ); + } + else + return false; // something is wrong + nKashidaPosIdx++; + } + return true; } /************************************************************************* diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx index 7e3c0881109c..0776feeeb21d 100644 --- a/sw/source/core/text/pormulti.cxx +++ b/sw/source/core/text/pormulti.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: pormulti.cxx,v $ - * $Revision: 1.89 $ + * $Revision: 1.89.112.2 $ * * This file is part of OpenOffice.org. * @@ -231,9 +231,9 @@ SwBidiPortion::SwBidiPortion( xub_StrLen nEnd, BYTE nLv ) } -long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const +long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const { - return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR; + return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR; } sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const @@ -249,6 +249,28 @@ sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const return bRet; } +xub_StrLen SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const +{ + // Calculate number of blanks for justified alignment + SwLinePortion* pPor = GetRoot().GetFirstPortion(); + xub_StrLen nTmpStart = rInf.GetIdx(); + xub_StrLen nNull = 0; + xub_StrLen nBlanks; + + for( nBlanks = 0; pPor; pPor = pPor->GetPortion() ) + { + if( pPor->InTxtGrp() ) + nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull ); + else if ( pPor->IsMultiPortion() && + ((SwMultiPortion*)pPor)->IsBidi() ) + nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf ); + + ((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() ); + } + ((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart ); + return nBlanks; +} + /*-----------------01.11.00 14:22------------------- * SwDoubleLinePortion::SwDoubleLinePortion(..) * This constructor is for the continuation of a doubleline portion @@ -2065,25 +2087,6 @@ BOOL SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf, } else if ( rMulti.IsBidi() ) { - // Calculate number of blanks for justified alignment - SwLinePortion* pPor = rMulti.GetRoot().GetFirstPortion(); - xub_StrLen nTmpStart = rInf.GetIdx(); - xub_StrLen nNull = 0; - xub_StrLen nBlanks; - - for( nBlanks = 0; pPor; pPor = pPor->GetPortion() ) - { - if( pPor->InTxtGrp() ) - nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull ); - else if ( pPor->IsMultiPortion() && - ((SwMultiPortion*)pPor)->IsBidi() ) - nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt(); - - rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() ); - } - rInf.SetIdx( nTmpStart ); - ((SwBidiPortion&)rMulti).SetSpaceCnt( nBlanks ); - bRet = rMulti.GetLen() < nMultiLen || pNextFirst; } @@ -2390,7 +2393,12 @@ SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor, nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt(); } else - nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(); + { + const xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx(); + pTxtCursor->GetInfo().SetIdx ( nCurrStart ); + nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo()); + pTxtCursor->GetInfo().SetIdx ( nOldIdx ); + } if( nSpaceAdd > 0 && !pMulti->HasTabulator() ) pTxtCursor->pCurr->Width( static_cast(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) ); diff --git a/sw/source/core/text/pormulti.hxx b/sw/source/core/text/pormulti.hxx index 93d930c97035..fcb2fea9c818 100644 --- a/sw/source/core/text/pormulti.hxx +++ b/sw/source/core/text/pormulti.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: pormulti.hxx,v $ - * $Revision: 1.26 $ + * $Revision: 1.26.112.1 $ * * This file is part of OpenOffice.org. * @@ -226,15 +226,13 @@ public: class SwBidiPortion : public SwMultiPortion { BYTE nLevel; - xub_StrLen nBlanks; // Number of blanks public: SwBidiPortion( xub_StrLen nEnd, BYTE nLv ); inline BYTE GetLevel() const { return nLevel; } - // Set/Get number of blanks for justified alignment - inline void SetSpaceCnt( xub_StrLen nNew ) { nBlanks = nNew; } - inline xub_StrLen GetSpaceCnt() const { return nBlanks; } + // Get number of blanks for justified alignment + xub_StrLen GetSpaceCnt( const SwTxtSizeInfo &rInf ) const; // Calculates extra spacing based on number of blanks virtual long CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const; // Manipulate the spacing array at pCurr diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx index 0e62d09744de..43d44f56fcf3 100644 --- a/sw/source/core/text/portxt.cxx +++ b/sw/source/core/text/portxt.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: portxt.cxx,v $ - * $Revision: 1.52 $ + * $Revision: 1.51.112.3 $ * * This file is part of OpenOffice.org. * @@ -131,6 +131,19 @@ USHORT lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr, } } + // Kashida Justification: Insert Kashidas + if ( nEnd > nPos && pSI && COMPLEX == nScript ) + { + if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) ) + { + const USHORT nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos ); + // i60591: need to check result of KashidaJustify + // determine if kashida justification is applicable + if( nKashRes != STRING_LEN ) + return nKashRes; + } + } + // Thai Justification: Each character cell gets some extra space if ( nEnd > nPos && COMPLEX == nScript ) { @@ -154,16 +167,6 @@ USHORT lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr, } } - // Kashida Justification: Insert Kashidas - if ( nEnd > nPos && pSI && COMPLEX == nScript ) - { - LanguageType aLang = - rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); - - if ( SwScriptInfo::IsArabicLanguage( aLang ) ) - return pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos ); - } - // Here starts the good old "Look for blanks and add space to them" part. // Note: We do not want to add space to an isolated latin blank in front // of some complex characters in RTL environment diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 6acf9352d785..5feee9e59045 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: txtfrm.cxx,v $ - * $Revision: 1.108 $ + * $Revision: 1.108.30.1 $ * * This file is part of OpenOffice.org. * @@ -32,6 +32,7 @@ #include "precompiled_sw.hxx" #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include // GetDoc() #include // InvalidateSpelling @@ -288,6 +290,27 @@ void SwLayoutModeModifier::SetAuto() ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode ); } +SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) : + rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() ) +{ + LanguageType eLang = eCurLang; + const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals(); + + if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals ) + eLang = LANGUAGE_ARABIC; + else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals ) + eLang = LANGUAGE_ENGLISH; + else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals ) + eLang = (LanguageType)::GetAppLanguage(); + + ((OutputDevice&)rOut).SetDigitLanguage( eLang ); +} + +SwDigitModeModifier::~SwDigitModeModifier() +{ + ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType ); +} + /************************************************************************* * SwTxtFrm::Init() *************************************************************************/ diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 4eeb8f3238bf..338417c79731 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -1512,10 +1512,24 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } } - // Thai Justification + // Kashida Justification if ( SW_CTL == nActual && nSpaceAdd ) { + if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) + { + if ( pSI && pSI->CountKashida() && + pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), + rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) + { + bSpecialJust = sal_True; + nSpaceAdd = 0; + } + } + } + // Thai Justification + if ( SW_CTL == nActual && nSpaceAdd ) + { LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); if ( LANGUAGE_THAI == aLang ) @@ -1532,21 +1546,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) nSpaceAdd = 0; } } - - // Kashida Justification - if ( SW_CTL == nActual && nSpaceAdd ) - { - if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> - GetLanguage( SW_CTL ) ) ) - { - if ( pSI && pSI->CountKashida() ) - pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), - rInf.GetLen(), nSpaceAdd ); - - bSpecialJust = sal_True; - nSpaceAdd = 0; - } - } } long nKernSum = rInf.GetKern(); @@ -1698,6 +1697,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) // Modify Printer and ScreenArrays for special justifications // long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; + bool bNoHalfSpace = false; if ( rInf.GetFont() && rInf.GetLen() ) { @@ -1737,6 +1737,20 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } } + // Kashida Justification + if ( SW_CTL == nActual && nSpaceAdd ) + { + if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) + { + if ( pSI && pSI->CountKashida() && + pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), + rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) + nSpaceAdd = 0; + else + bNoHalfSpace = true; + } + } + // Thai Justification if ( SW_CTL == nActual && nSpaceAdd ) { @@ -1754,19 +1768,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) nSpaceAdd = 0; } } - - // Kashida Justification - if ( SW_CTL == nActual && nSpaceAdd ) - { - if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> - GetLanguage( SW_CTL ) ) ) - { - if ( pSI && pSI->CountKashida() ) - pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), - rInf.GetLen(), nSpaceAdd ); - nSpaceAdd = 0; - } - } } nScrPos = pScrArray[ 0 ]; @@ -1843,8 +1844,9 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) // vor bzw. hinter den kompletten Zwischenraum gesetzt werden, // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen. long nSpaceSum = 0; - long nHalfSpace = pPrtFont->IsWordLineMode() ? 0 : nSpaceAdd / 2; - long nOtherHalf = nSpaceAdd - nHalfSpace; + // in word line mode and for Arabic, we disable the half space trick: + const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2; + const long nOtherHalf = nSpaceAdd - nHalfSpace; if ( nSpaceAdd && ( cChPrev == CH_BLANK ) ) nSpaceSum = nHalfSpace; for ( xub_StrLen i=1; iIsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK ) + pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd; } // the layout engine requires the total width of the output @@ -2292,6 +2300,7 @@ xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf ) sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; + // be sure to have the correct layout mode at the printer if ( pPrinter ) { pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); @@ -2337,6 +2346,18 @@ xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf ) } + // Kashida Justification + if ( SW_CTL == nActual && rInf.GetSpace() ) + { + if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) + { + if ( pSI && pSI->CountKashida() && + pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), + nSpaceAdd ) != STRING_LEN ) + nSpaceAdd = 0; + } + } + // Thai Justification if ( SW_CTL == nActual && nSpaceAdd ) { @@ -2353,20 +2374,6 @@ xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf ) nSpaceAdd = 0; } } - - // Kashida Justification - if ( SW_CTL == nActual && rInf.GetSpace() ) - { - if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> - GetLanguage( SW_CTL ) ) ) - { - if ( pSI && pSI->CountKashida() ) - pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), - nSpaceAdd ); - - nSpaceAdd = 0; - } - } } long nLeft = 0; diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx index 8efc0795a6b9..fc73941ad58f 100644 --- a/sw/source/core/txtnode/swfont.cxx +++ b/sw/source/core/txtnode/swfont.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: swfont.cxx,v $ - * $Revision: 1.59 $ + * $Revision: 1.59.24.1 $ * * This file is part of OpenOffice.org. * @@ -734,6 +734,8 @@ Size SwSubFont::_GetTxtSize( SwDrawTextInfo& rInf ) !IsSameInstance( rInf.GetpOut()->GetFont() ) ) ChgFnt( rInf.GetShell(), rInf.GetOut() ); + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + Size aTxtSize; xub_StrLen nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len() : rInf.GetLen() ); @@ -849,6 +851,8 @@ void SwSubFont::_DrawText( SwDrawTextInfo &rInf, const BOOL bGrey ) if( !pLastFont || pLastFont->GetOwner()!=pMagic ) ChgFnt( rInf.GetShell(), rInf.GetOut() ); + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + Point aPos( rInf.GetPos() ); const Point &rOld = rInf.GetPos(); rInf.SetPos( aPos ); @@ -976,6 +980,8 @@ void SwSubFont::_DrawStretchText( SwDrawTextInfo &rInf ) if ( !pLastFont || pLastFont->GetOwner() != pMagic ) ChgFnt( rInf.GetShell(), rInf.GetOut() ); + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + rInf.ApplyAutoColor(); Point aPos( rInf.GetPos() ); @@ -1046,6 +1052,8 @@ xub_StrLen SwSubFont::_GetCrsrOfst( SwDrawTextInfo& rInf ) if ( !pLastFont || pLastFont->GetOwner()!=pMagic ) ChgFnt( rInf.GetShell(), rInf.GetOut() ); + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + xub_StrLen nLn = rInf.GetLen() == STRING_LEN ? rInf.GetText().Len() : rInf.GetLen(); rInf.SetLen( nLn ); diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx index 03232f4fa655..e52bf2ba8ff0 100644 --- a/sw/source/core/txtnode/thints.cxx +++ b/sw/source/core/txtnode/thints.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: thints.cxx,v $ - * $Revision: 1.65 $ + * $Revision: 1.65.62.1 $ * * This file is part of OpenOffice.org. * @@ -2331,21 +2331,23 @@ void SwTxtNode::ClearSwpHintsArr( bool bDelFields ) USHORT SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen, USHORT nScript ) const { - USHORT nWhichId = RES_CHRATR_LANGUAGE; USHORT nRet = LANGUAGE_DONTKNOW; - if( pSwpHints ) - { + if ( ! nScript ) nScript = pBreakIt->GetRealScriptOfText( aText, nBegin ); - nWhichId = GetWhichOfScript( nWhichId, nScript ); + // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0 + const USHORT nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript ); + // <-- - xub_StrLen nEnd = nBegin + nLen; + if( pSwpHints ) + { + const xub_StrLen nEnd = nBegin + nLen; for( USHORT i = 0, nSize = pSwpHints->Count(); i < nSize; ++i ) { // ist der Attribut-Anfang schon groesser als der Idx ? const SwTxtAttr *pHt = pSwpHints->operator[](i); - xub_StrLen nAttrStart = *pHt->GetStart(); + const xub_StrLen nAttrStart = *pHt->GetStart(); if( nEnd < nAttrStart ) break; @@ -2379,10 +2381,6 @@ USHORT SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen, } if( LANGUAGE_DONTKNOW == nRet ) { - if( !pSwpHints ) - nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, - pBreakIt->GetRealScriptOfText( aText, nBegin )); - nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage(); if( LANGUAGE_DONTKNOW == nRet ) nRet = static_cast(GetAppLanguage()); diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx index 1214e7c9cda3..4b27fad5b60d 100644 --- a/sw/source/core/view/viewsh.cxx +++ b/sw/source/core/view/viewsh.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: viewsh.cxx,v $ - * $Revision: 1.87 $ + * $Revision: 1.87.42.1 $ * * This file is part of OpenOffice.org. * @@ -1007,6 +1007,14 @@ void ViewShell::Reformat() } } + void ViewShell::ChgNumberDigits() + { + SdrModel* pTmpDrawModel = getIDocumentDrawModelAccess()->GetDrawModel(); + if ( pTmpDrawModel ) + pTmpDrawModel->ReformatAllTextObjects(); + Reformat(); + } + /****************************************************************************** |* |* ViewShell::CalcLayout() -- cgit