Index: inc/scriptinfo.hxx =================================================================== RCS file: /cvs/sw/sw/source/core/inc/scriptinfo.hxx,v --- inc/scriptinfo.hxx 25 Jun 2008 10:26:33 -0000 1.21.112.2 +++ inc/scriptinfo.hxx 21 Sep 2008 12:01:03 -0000 @@ -107,6 +107,8 @@ SvBytes aDirType; SvXub_StrLens aKashida; SvXub_StrLens aKashidaInvalid; + SvXub_StrLens aNoKashidaLine; + SvXub_StrLens aNoKashidaLineEnd; SvXub_StrLens aCompChg; SvXub_StrLens aCompLen; SvXub_StrLens aHiddenChg; @@ -119,7 +121,9 @@ 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 ); + 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 }; @@ -272,14 +276,44 @@ 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 +/** Clears array of kashidas marked as invalid */ - inline bool MarkKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { return MarkOrClearKashidaInvalid( nStt, nLen, true ); } + inline void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { MarkOrClearKashidaInvalid( nStt, nLen, false, 0 ); } -/** Clears array of kashidas marked as invalid +/** 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 void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { MarkOrClearKashidaInvalid( nStt, nLen, false ); } + 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 ); + + + + +/** 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 +*/ + 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 language is one of the 16 Arabic languages Index: text/itradj.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/itradj.cxx,v --- text/itradj.cxx 14 Jun 2008 06:31:04 -0000 1.24.112.1 +++ text/itradj.cxx 21 Sep 2008 17:16:21 -0000 @@ -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 @@ -46,6 +50,8 @@ #define MIN_TAB_WIDTH 60 +using namespace ::com::sun::star; + /************************************************************************* * SwTxtAdjuster::FormatBlock() *************************************************************************/ @@ -133,7 +139,7 @@ *************************************************************************/ 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?" ); @@ -153,12 +159,22 @@ { while (aItr.GetCurr() != pCurrent && aItr.GetNext()) aItr.Next(); - rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() ); + + 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 = @@ -209,61 +225,38 @@ 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 ( !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 ) { - // i60594 - 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 - } - } - + long nSpaceAdd = nGluePortionWidth / nGluePortion; + + if( rSI.CountKashida() && !bSkipKashida ) + { + if( !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() ); } @@ -292,6 +285,145 @@ } /************************************************************************* + * SwTxtAdjuster::CheckKashidaPositions() + *************************************************************************/ +bool SwTxtAdjuster::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; + LanguageType aLang = GetTxtFrm()->GetTxtNode()-> + GetLang ( nIdx, 1, i18n::ScriptType::COMPLEX ); + if ( !SwScriptInfo::IsArabicLanguage( aLang ) ) + { + 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); +} + + +/************************************************************************* + * SwTxtAdjuster::CheckKashidaWidth() + *************************************************************************/ +bool SwTxtAdjuster::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(); + LanguageType aLang = GetTxtFrm()->GetTxtNode()-> + GetLang ( nIdx, 1, i18n::ScriptType::COMPLEX ); + if ( nFontMinKashida && nKashidasInAttr && SwScriptInfo::IsArabicLanguage( aLang )) + { + 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::CalcKanaAdj() *************************************************************************/ Index: text/itrcrsr.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/itrcrsr.cxx,v --- text/itrcrsr.cxx 11 Jul 2008 14:15:26 -0000 1.81 +++ text/itrcrsr.cxx 21 Sep 2008 20:16:04 -0000 @@ -506,6 +506,7 @@ SwTwips nTmpFirst = 0; SwLinePortion *pPor = pCurr->GetFirstPortion(); SwBidiPortion* pLastBidiPor = 0; + xub_StrLen nLastBidiIdx = 0; SvUShorts* pKanaComp = pCurr->GetpKanaComp(); MSHORT nSpaceIdx = 0; MSHORT nKanaIdx = 0; @@ -649,7 +650,10 @@ // cursor level if ( ((SwMultiPortion*)pPor)->IsBidi() && aInf.GetIdx() + pPor->GetLen() == nOfst ) + { pLastBidiPor = (SwBidiPortion*)pPor; + nLastBidiIdx = aInf.GetIdx(); + } } aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() ); @@ -1086,8 +1090,11 @@ { // we came from inside the bidi portion, we want to blink // behind the portion + xub_StrLen nOldIdx = aInf.GetIdx(); + aInf.SetIdx ( nLastBidiIdx ); pOrig->Pos().X() -= pLastBidiPor->Width() + pLastBidiPor->CalcSpacing( nSpaceAdd, aInf ); + aInf.SetIdx ( nOldIdx ); // Again, there is a special case: logically behind // the portion can actually mean that the cursor is inside Index: text/itrtxt.hxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/itrtxt.hxx,v --- text/itrtxt.hxx 11 Jul 2008 14:15:41 -0000 1.21 +++ text/itrtxt.hxx 21 Sep 2008 07:38:12 -0000 @@ -230,7 +230,7 @@ inline SwTxtAdjuster() { } // 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 ) @@ -249,6 +249,11 @@ // DropCaps-Extrawurst void CalcDropAdjust(); void CalcDropRepaint(); +private: + bool CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, + xub_StrLen& nKashidas, xub_StrLen& nGluePortion ); + bool CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas, + xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd ); }; /************************************************************************* Index: text/porlay.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/porlay.cxx,v --- text/porlay.cxx 14 Jun 2008 06:31:04 -0000 1.67.14.1 +++ text/porlay.cxx 21 Sep 2008 11:02:42 -0000 @@ -181,9 +181,9 @@ 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 ); } /************************************************************************* @@ -198,6 +198,9 @@ // 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 ) || @@ -1827,6 +1830,9 @@ { ASSERT( nLen, "Kashida justification without text?!" ) + if( !IsKashidaLine(nStt)) + return STRING_LEN; + // evaluate kashida informatin in collected in SwScriptInfo USHORT nCntKash = 0; @@ -1949,8 +1955,13 @@ /************************************************************************* * 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 ) +bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount ) { USHORT nCntKash = 0; while( nCntKash < CountKashida() ) @@ -1974,7 +1985,9 @@ if ( IsKashidaValid ( nCntKash ) ) { MarkKashidaInvalid ( nCntKash ); - return true; + --nMarkCount; + if(!nMarkCount) + return true; } } else @@ -1992,10 +2005,44 @@ aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() ); } -/* -USHORT SwScriptInfo::CountKashidaInRange ( xub_StrLen nStt, xub_StrLen nLen ) +/************************************************************************* + * 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; +} + +/************************************************************************* + * 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; + USHORT nCntKash = 0; while( nCntKash < CountKashida() ) { if ( nStt <= GetKashida( nCntKash ) ) @@ -2003,20 +2050,61 @@ else nCntKash++; } - - const xub_StrLen nEnd = nStt + nLen; - + const xub_StrLen nEnd = nStt + nLen; USHORT nCntKashEnd = nCntKash; while ( nCntKashEnd < CountKashida() ) { - if ( nEnd <= GetKashida( nCntKashEnd ) ) + if ( nEnd <= GetKashida( nCntKashEnd ) ) break; else + { + pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd ); nCntKashEnd++; + } + } + return nCntKashEnd - nCntKash; +} + +/************************************************************************* + * 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; } - return nCntKashEnd - nCntKash; } -*/ + +void SwScriptInfo::SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen ) +{ + aNoKashidaLine.Insert( nStt, aNoKashidaLine.Count()); + aNoKashidaLineEnd.Insert( nStt+nLen, aNoKashidaLineEnd.Count()); +} + + /************************************************************************* * SwScriptInfo::ThaiJustify() Index: text/pormulti.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/pormulti.cxx,v --- text/pormulti.cxx 14 Jun 2008 06:31:04 -0000 1.89.112.1 +++ text/pormulti.cxx 21 Sep 2008 07:38:12 -0000 @@ -2393,7 +2393,12 @@ nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt(); } else + { + 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 ) ); Index: text/portxt.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/text/portxt.cxx,v --- text/portxt.cxx 10 Apr 2008 15:31:59 -0000 1.51 +++ text/portxt.cxx 21 Sep 2008 07:38:12 -0000 @@ -157,7 +157,13 @@ rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); if ( SwScriptInfo::IsArabicLanguage( aLang ) ) - return pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos ); + { + 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; + } } // Here starts the good old "Look for blanks and add space to them" part. Index: txtnode/fntcache.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/txtnode/fntcache.cxx,v --- txtnode/fntcache.cxx 25 Jul 2008 11:25:02 -0000 1.98 +++ txtnode/fntcache.cxx 21 Sep 2008 07:38:12 -0000 @@ -1538,12 +1538,13 @@ if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> GetLanguage( SW_CTL ) ) ) { - if ( pSI && pSI->CountKashida() ) + if ( pSI && pSI->CountKashida() && pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), - rInf.GetLen(), nSpaceAdd ); - - bSpecialJust = sal_True; - nSpaceAdd = 0; + rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) + { + bSpecialJust = sal_True; + nSpaceAdd = 0; + } } } } @@ -1697,6 +1698,7 @@ // Modify Printer and ScreenArrays for special justifications // long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; + bool bNoHalfSpace = false; if ( rInf.GetFont() && rInf.GetLen() ) { @@ -1760,10 +1762,13 @@ if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> GetLanguage( SW_CTL ) ) ) { - if ( pSI && pSI->CountKashida() ) - pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), - rInf.GetLen(), nSpaceAdd ); - nSpaceAdd = 0; + if ( pSI && pSI->CountKashida() && + pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), + rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) + nSpaceAdd = 0; + else + bNoHalfSpace = true; + } } } @@ -1842,7 +1847,7 @@ // 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; @@ -2358,11 +2363,10 @@ if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()-> GetLanguage( SW_CTL ) ) ) { - if ( pSI && pSI->CountKashida() ) + if ( pSI && pSI->CountKashida() && pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), - nSpaceAdd ); - - nSpaceAdd = 0; + nSpaceAdd ) != STRING_LEN ) + nSpaceAdd = 0; } } } Index: txtnode/thints.cxx =================================================================== RCS file: /cvs/sw/sw/source/core/txtnode/thints.cxx,v --- txtnode/thints.cxx 8 Jul 2008 08:27:38 -0000 1.65 +++ txtnode/thints.cxx 21 Sep 2008 07:38:12 -0000 @@ -2333,13 +2333,11 @@ { USHORT nWhichId = RES_CHRATR_LANGUAGE; USHORT nRet = LANGUAGE_DONTKNOW; - if( pSwpHints ) - { - if ( ! nScript ) + if ( ! nScript ) nScript = pBreakIt->GetRealScriptOfText( aText, nBegin ); - nWhichId = GetWhichOfScript( nWhichId, nScript ); - + if( pSwpHints ) + { xub_StrLen nEnd = nBegin + nLen; for( USHORT i = 0, nSize = pSwpHints->Count(); i < nSize; ++i ) { @@ -2379,10 +2377,6 @@ } 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());