diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/inc/scriptinfo.hxx source/core/inc/scriptinfo.hxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/inc/scriptinfo.hxx 2007-09-27 08:58:02.000000000 +0000 +++ source/core/inc/scriptinfo.hxx 2008-05-31 08:20:41.632800000 +0000 @@ -107,6 +107,7 @@ private: SvXub_StrLens aDirChg; SvBytes aDirType; SvXub_StrLens aKashida; + SvXub_StrLens aKashidaInvalid; SvXub_StrLens aCompChg; SvXub_StrLens aCompLen; SvXub_StrLens aHiddenChg; @@ -116,6 +117,10 @@ private: void UpdateBidiInfo( const String& rTxt ); + sal_Bool IsKashidaValid ( xub_StrLen nKashPos ) const; + void MarkKashidaInvalid ( xub_StrLen nKashPos ); + void ClearKashidaInvalid ( xub_StrLen nKashPos ); + public: enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE }; @@ -255,7 +260,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. @@ -263,9 +268,19 @@ 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; + +/** Marks a kashida as invalid for the given text range. + returns true if a kashida was marked invalid +*/ + bool MarkKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ); + +/** Clears array of kashidas marked as invalid +*/ + void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ); + /** Checks if language is one of the 16 Arabic languages diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/frmform.cxx source/core/text/frmform.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/frmform.cxx 2007-09-27 09:12:24.000000000 +0000 +++ source/core/text/frmform.cxx 2008-05-31 08:24:55.395800000 +0000 @@ -2208,7 +2208,7 @@ sal_Bool SwTxtFrm::FormatQuick( bool bFo { //DBG_LOOP; shadows declaration above. //resolved into: -#if OSL_DEBUG_LEVEL > 1 +#ifndef PRODUCT DbgLoop aDbgLoop2( (const void*) this ); #endif nStart = aLine.FormatLine( nStart ); diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/frmpaint.cxx source/core/text/frmpaint.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/frmpaint.cxx 2008-01-17 16:01:25.000000000 +0000 +++ source/core/text/frmpaint.cxx 2008-04-30 06:34:17.468000000 +0000 @@ -789,7 +789,7 @@ void SwTxtFrm::Paint( const SwRect &rRec { //DBG_LOOP; shadows declaration above. //resolved into: -#if OSL_DEBUG_LEVEL > 1 +#ifndef PRODUCT DbgLoop aDbgLoop2( (const void*) this ); #endif aLine.DrawTextLine( rRect, aClip, IsUndersized() ); diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/itradj.cxx source/core/text/itradj.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/itradj.cxx 2007-09-27 09:13:31.000000000 +0000 +++ source/core/text/itradj.cxx 2008-05-30 05:46:14.083461900 +0000 @@ -54,6 +54,8 @@ #include #endif +#include + #define MIN_TAB_WIDTH 60 /************************************************************************* @@ -154,6 +156,17 @@ void SwTxtAdjuster::CalcNewBlock( SwLine xub_StrLen nCharCnt = 0; MSHORT nSpaceIdx = 0; + SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo(); + SwTxtSizeInfo aInf ( GetTxtFrm() ); + SwTxtIter aItr ( GetTxtFrm(), &aInf ); + + if ( rSI.CountKashida() ) + { + while (aItr.GetCurr() != pCurrent && aItr.GetNext()) + aItr.Next(); + rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() ); + } + // Nicht vergessen: // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite ! CalcRightMargin( pCurrent, nReal ); @@ -195,7 +208,7 @@ void SwTxtAdjuster::CalcNewBlock( SwLine else if( pMulti->IsDouble() ) nGluePortion = nGluePortion + ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt(); else if ( pMulti->IsBidi() ) - nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt(); + nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt( GetInfo() ); } if( pPos->InGlueGrp() ) @@ -210,7 +223,57 @@ void SwTxtAdjuster::CalcNewBlock( SwLine if( nGluePortion ) { - const long nSpaceAdd = nGluePortionWidth / nGluePortion; + long nSpaceAdd = nGluePortionWidth / nGluePortion; + + // validate or recalculate for Kashida justification + if ( rSI.CountKashida() ) + { + xub_StrLen nIdx = aItr.GetStart(); + xub_StrLen nEnd = aItr.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. + xub_StrLen nKashidas = rSI.KashidaJustify ( 0, 0, aItr.GetStart(), aItr.GetLength(), 0 ); + + bool bAddSpaceChanged; + while ( nKashidas ) + { + bAddSpaceChanged = false; + nIdx = aItr.GetStart(); + aItr.SeekAndChgAttrIter( nIdx, aInf.GetOut() ); + + while ( nIdx < nEnd ) + { + long nFontMinKashida = aInf.GetOut()->GetMinKashida(); + if ( nFontMinKashida ) + { + while ( nKashidas && nGluePortion > 1 && + nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida ) + { + if ( rSI.MarkKashidaInvalid(aItr.GetStart(), aItr.GetLength()) ) + { + --nGluePortion; + --nKashidas; + nSpaceAdd = nGluePortionWidth / nGluePortion; + bAddSpaceChanged = true; + } + } + } + if ( bAddSpaceChanged ) + break; // start all over again + nIdx = aItr.GetNextAttr(); + if ( nIdx != STRING_LEN ) + aItr.SeekAndChgAttrIter( nIdx, aInf.GetOut() ); + } + if ( !bAddSpaceChanged ) + break; // everything was OK + } + } + pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx ); pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() ); } diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/porlay.cxx source/core/text/porlay.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/porlay.cxx 2007-09-27 09:17:13.000000000 +0000 +++ source/core/text/porlay.cxx 2008-05-31 08:23:30.925800000 +0000 @@ -113,6 +113,104 @@ using namespace i18n::ScriptType; //#ifdef BIDI #include +sal_Bool isAlefChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x622 || cCh == 0x623 || cCh == 0x625 || cCh == 0x627 || + cCh == 0x622 || cCh == 0x671 || cCh == 0x672 || cCh == 0x673 || cCh == 0x675 ); +} + +sal_Bool isWawChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x624 || cCh == 0x648 || cCh == 0x676 || cCh == 0x677 || + ( cCh >= 0x6C4 && cCh <= 0x6CB ) || cCh == 0x6CF ); +} + +sal_Bool isDalChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x62F || cCh == 0x630 || cCh == 0x688 || cCh == 0x689 || cCh == 0x690 ); +} + +sal_Bool isRehChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x631 || cCh == 0x632 || ( cCh >= 0x691 && cCh <= 0x699 )); +} + +sal_Bool isTehMarbutaChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x629 || cCh == 0x6C0 ); +} + +sal_Bool isBaaChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x628 || cCh == 0x62A || cCh == 0x62B || cCh == 0x679 || cCh == 0x680 ); +} + +sal_Bool isYehChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x626 || cCh == 0x649 || cCh == 0x64A || cCh == 0x678 || cCh == 0x6CC || + cCh == 0x6CE || cCh == 0x6D0 || cCh == 0x6D1 ); +} + +sal_Bool isSeenOrSadChar ( xub_Unicode cCh ) +{ + return ( ( cCh >= 0x633 && cCh <= 0x636 ) || ( cCh >= 0x69A && cCh <= 0x69E ) + || cCh == 0x6FA || cCh == 0x6FB ); +} + +sal_Bool isHahChar ( xub_Unicode cCh ) +{ + return ( ( cCh >= 0x62C && cCh <= 0x62E ) || ( cCh >= 0x681 && cCh <= 0x687 ) + || cCh == 0x6BF ); +} + +sal_Bool isTahChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x637 || cCh == 0x638 || cCh == 0x69F ); +} + +sal_Bool isAinChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x639 || cCh == 0x63A || cCh == 0x6A0 || cCh == 0x6FC ); +} + +sal_Bool isKafChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x643 || ( cCh >= 0x6AC && cCh <= 0x6AE ) ); +} + +sal_Bool isLamChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x644 || ( cCh >= 0x6B5 && cCh <= 0x6B8 ) ); +} + +sal_Bool isGafChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x6A9 || cCh == 0x6AB ||( cCh >= 0x6AF && cCh <= 0x6B4 ) ); +} + +sal_Bool isQafChar ( xub_Unicode cCh ) +{ + return ( cCh == 0x642 || cCh == 0x6A7 || cCh == 0x6A8 ); +} + +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 * @@ -127,6 +225,8 @@ sal_Bool lcl_IsLigature( xub_Unicode cCh ( 0x628 == cCh && 0x631 == cNextCh ); } + + /************************************************************************* * lcl_ConnectToPrev * @@ -142,13 +242,16 @@ sal_Bool lcl_ConnectToPrev( xub_Unicode sal_Bool bRet = 0x628 == cPrevCh || ( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) || ( 0x633 <= cPrevCh && cPrevCh <= 0x643 ) || + 0x644 == cPrevCh || // Lam does connect !!! ( 0x645 <= cPrevCh && cPrevCh <= 0x647 ) || + 0x649 == cPrevCh || // Alef Maksura does connect !!! 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 ); @@ -713,6 +816,7 @@ BYTE SwScriptInfo::WhichFont( xub_StrLen return SW_LATIN; } + /************************************************************************* * SwScriptInfo::InitScriptInfo() * @@ -881,7 +985,7 @@ void SwScriptInfo::InitScriptInfo( const // 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 @@ -1025,93 +1129,145 @@ void SwScriptInfo::InitScriptInfo( const 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 + USHORT nPriorityLevel = 7; // 0..6 = level found + // 7 not found + 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 ); + { + nKashidaPos = aScanner.GetBegin() + nIdx; + nPriorityLevel = 0; + } + + // 2. Priority: + // after a Seen or Sad + if (nPriorityLevel >= 1 && nIdx < rWord.Len() - 1) + { + if ( isSeenOrSadChar ( cCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx; + nPriorityLevel = 1; + } + } + // 3. Priority: + // before final form of Teh Marbuta, Hah, Dal + if ( nPriorityLevel >= 2 && nIdx > 0 ) + { + if ( isTehMarbutaChar ( cCh ) || // Teh Marbuta (right joining) + isDalChar ( cCh ) || // Dal (right joining) final form may appear in the middle of word + ( isHahChar ( cCh ) && nIdx == rWord.Len() - 1)) // Hah (dual joining) only at end of word + { + + ASSERT( 0 != cPrevCh, "No previous character" ) + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx - 1; + nPriorityLevel = 2; + } + } + } - 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; - } + // 4. Priority: + // before final form of Alef, Lam or Kaf + if ( nPriorityLevel >= 3 && nIdx > 0 ) + { + if ( isAlefChar ( cCh ) || // Alef (right joining) final form may appear in the middle of word + (( isLamChar ( cCh ) || // Lam + isKafChar ( cCh ) || // Kaf (both dual joining) + isGafChar ( cCh ) ) + && nIdx == rWord.Len() - 1)) // only at end of word + { + ASSERT( 0 != cPrevCh, "No previous character" ) + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx - 1; + nPriorityLevel = 3; + } + } + } + + // 5. Priority: + // before media Bah + + if ( nPriorityLevel >= 4 && nIdx > 0 && nIdx < rWord.Len() - 1 ) + { + if ( isBaaChar ( cCh )) // Bah + { + // check if next character is Reh, Yeh or Alef Maksura + xub_Unicode cNextCh = rWord.GetChar( nIdx + 1 ); + if ( isRehChar ( cNextCh ) || isYehChar ( cNextCh )) + { + ASSERT( 0 != cPrevCh, "No previous character" ) + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx - 1; + nPriorityLevel = 4; + } + } + } } - // 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; - } - } + // 6. Priority: + // before the final form of Waw, Ain, Qaf and Fa + + if ( nPriorityLevel >= 5 && nIdx > 0 ) + { + if ( isWawChar ( cCh ) || // Wav (right joining) + // final form may appear in the middle of word + (( isAinChar ( cCh ) || // Ain (dual joining) + isQafChar ( cCh ) || // Qaf (dual joining) + isFeChar ( cCh ) ) // Feh (dual joining) + && nIdx == rWord.Len() - 1)) // only at end of word + { + ASSERT( 0 != cPrevCh, "No previous character" ) + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx - 1; + nPriorityLevel = 5; + } + } + } + + // other connecting possibilities + if ( nPriorityLevel >= 6 && nIdx > 0 ) + { + // remaining right joiners + // Reh, Zain, Thal, + if ( isRehChar ( cCh ) || // Reh Zain (right joining) + // final form may appear in the middle of word + ( 0x60C <= cCh && 0x6FE >= cCh // all others + && nIdx == rWord.Len() - 1)) // only at end of word + { + ASSERT( 0 != cPrevCh, "No previous character" ) + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aScanner.GetBegin() + nIdx - 1; + nPriorityLevel = 6; + } + } + } - // Do not consider Fathatan, Dammatan, Kasratan, Fatha, + // 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; - } // end of current word + ++nIdx; + } // end of current word if ( STRING_LEN != nKashidaPos ) - aKashida.Insert( nKashidaPos, nCntKash++ ); + { + aKashida.Insert( nKashidaPos, nCntKash++ ); + } } // end of kashida search } @@ -1702,13 +1858,20 @@ long SwScriptInfo::Compress( sal_Int32* * 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?!" ) - // evaluate kashida informatin in collected in SwScriptInfo + // evaluate kashida information in collected in SwScriptInfo USHORT nCntKash = 0; while( nCntKash < CountKashida() ) @@ -1721,50 +1884,60 @@ USHORT SwScriptInfo::KashidaJustify( sal 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++; - } - - return nCntKashEnd - nCntKash; + if ( nEnd <= GetKashida( nCntKashEnd ) ) + break; + else + nCntKashEnd++; } + + USHORT nActualKashCount = nCntKashEnd - nCntKash; + for ( USHORT i = nCntKash; i < nCntKashEnd; ++i ) + { + if ( nActualKashCount && !IsKashidaValid ( i ) ) + --nActualKashCount; + + } - // 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; + if ( !pKernArray ) + return nActualKashCount; - const USHORT nArrayEnd = nIdx - nStt; + // do nothing if there is no more kashida + if ( nCntKash < CountKashida() ) + { + while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd ) + ++nCntKash; + xub_StrLen nKashidaPos = GetKashida( nCntKash ); + xub_StrLen nIdx = nKashidaPos; + long nKashAdd = nSpaceAdd; + + while ( nIdx < nEnd ) + { + USHORT nArrayPos = nIdx - nStt; - while ( nArrayPos < nArrayEnd ) - { - pKernArray[ nArrayPos ] += nKashAdd; - if ( pScrArray ) - pScrArray[ nArrayPos ] += nKashAdd; - ++nArrayPos; - } + // next kashida position + ++nCntKash; + while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd ) + ++nCntKash; + nIdx = nCntKash < CountKashida() && IsKashidaValid ( nCntKash ) ? GetKashida( nCntKash ) : nEnd; + if ( nIdx > nEnd ) + nIdx = nEnd; - nKashAdd += nSpaceAdd; - } - } + const USHORT nArrayEnd = nIdx - nStt; + while ( nArrayPos < nArrayEnd ) + { + pKernArray[ nArrayPos ] += nKashAdd; + if ( pScrArray ) + pScrArray[ nArrayPos ] += nKashAdd; + ++nArrayPos; + } + nKashAdd += nSpaceAdd; + } + } return 0; } @@ -1786,6 +1959,130 @@ sal_Bool SwScriptInfo::IsArabicLanguage( } /************************************************************************* + * SwScriptInfo::IsKashidaValid() + *************************************************************************/ + +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 nStt, xub_StrLen nLen ) +{ + if ( !aKashidaInvalid.Count() ) + return; + 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 + { + ClearKashidaInvalid ( nCntKash ); + nCntKash++; + } + } +} + + +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::MarkKashidaInvalid() + * + *************************************************************************/ + +bool SwScriptInfo::MarkKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) +{ + 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 ( IsKashidaValid ( nCntKash ) ) + { + MarkKashidaInvalid ( nCntKash ); + return true; + } + nCntKash++; + } + } + return false; +} + +void SwScriptInfo::MarkKashidaInvalid ( xub_StrLen nKashPos ) +{ + aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() ); +} + +/* +USHORT SwScriptInfo::CountKashidaInRange ( xub_StrLen nStt, xub_StrLen nLen ) +{ + 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 + nCntKashEnd++; + } + return nCntKashEnd - nCntKash; +} +*/ + +/************************************************************************* * SwScriptInfo::ThaiJustify() *************************************************************************/ diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/pormulti.cxx source/core/text/pormulti.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/pormulti.cxx 2007-09-27 09:18:06.000000000 +0000 +++ source/core/text/pormulti.cxx 2008-05-31 08:30:02.871800000 +0000 @@ -294,9 +294,9 @@ SwBidiPortion::SwBidiPortion( xub_StrLen } -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 @@ -312,6 +312,28 @@ sal_Bool SwBidiPortion::ChgSpaceAdd( SwL 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 @@ -2128,24 +2150,6 @@ BOOL SwTxtFormatter::BuildMultiPortion( } 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; } @@ -2453,7 +2457,7 @@ SwTxtCursorSave::SwTxtCursorSave( SwTxtC nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt(); } else - nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(); + nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt( pTxtCursor->GetInfo() ); if( nSpaceAdd > 0 && !pMulti->HasTabulator() ) pTxtCursor->pCurr->Width( static_cast(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) ); diff -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/pormulti.hxx source/core/text/pormulti.hxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/text/pormulti.hxx 2007-09-27 09:18:18.000000000 +0000 +++ source/core/text/pormulti.hxx 2008-05-31 08:31:45.891800000 +0000 @@ -231,15 +231,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 -rup /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/txtnode/fntcache.cxx source/core/txtnode/fntcache.cxx --- /cygdrive/C/Users/Henner/Downloads/OOSource/OOH680_m12/sw/source/core/txtnode/fntcache.cxx 2008-01-15 07:51:39.000000000 +0000 +++ source/core/txtnode/fntcache.cxx 2008-05-31 09:19:57.182800000 +0000 @@ -887,6 +887,11 @@ static sal_Bool lcl_IsMonoSpaceFont( con return nWidth1 == nWidth2; } +sal_Bool isCharArabic ( xub_Unicode cChar ) +{ + return ( cChar >= 0x0600 && cChar <= 0x06FF ); +} + // ER 09.07.95 20:34 // mit -Ox Optimierung stuerzt's unter win95 ab // JP 12.07.95: unter WNT auch (i386); Alpha ?? @@ -1270,7 +1275,6 @@ void SwFntObj::DrawText( SwDrawTextInfo if ( pSI && pSI->CountKashida() ) pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ); - bSpecialJust = sal_True; nSpaceAdd = 0; } @@ -1426,12 +1430,14 @@ void SwFntObj::DrawText( SwDrawTextInfo // Modify Printer and ScreenArrays for special justifications // long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; + bool bNoHalfSpace = false; if ( rInf.GetFont() && rInf.GetLen() ) { const BYTE nActual = rInf.GetFont()->GetActual(); const SwScriptInfo* pSI = rInf.GetScriptInfo(); + // Kana Compression if ( SW_CJK == nActual && rInf.GetKanaComp() && pSI && pSI->CountCompChg() && @@ -1486,6 +1492,16 @@ void SwFntObj::DrawText( SwDrawTextInfo // Kashida Justification if ( SW_CTL == nActual && nSpaceAdd ) { + // Precaution: This prevents the bad effects of issue 28203, if Arabic characters are used + // without an Arabic language attribute. + // The half spacing makes it impossible to use regular justification of blanks with Arabic characters. + // But there might be situations, where we would want to support this. + for ( xub_StrLen i = 0; i < rInf.GetLen(); ++i ) + { + bNoHalfSpace = isCharArabic ( rInf.GetText().GetChar ( rInf.GetIdx() + i )); + if ( bNoHalfSpace ) + break; + } if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> GetLanguage( SW_CTL ) ) ) { @@ -1571,7 +1587,7 @@ void SwFntObj::DrawText( SwDrawTextInfo // 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 nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2; long nOtherHalf = nSpaceAdd - nHalfSpace; if ( nSpaceAdd && ( cChPrev == CH_BLANK ) ) nSpaceSum = nHalfSpace;