View | Details | Raw Unified | Return to issue 60594
Collapse All | Expand All

(-)inc/scriptinfo.hxx (-6 / +40 lines)
Lines 107-112 Link Here
107
    SvBytes aDirType;
107
    SvBytes aDirType;
108
    SvXub_StrLens aKashida;
108
    SvXub_StrLens aKashida;
109
    SvXub_StrLens aKashidaInvalid;
109
    SvXub_StrLens aKashidaInvalid;
110
	SvXub_StrLens aNoKashidaLine;
111
	SvXub_StrLens aNoKashidaLineEnd;
110
    SvXub_StrLens aCompChg;
112
    SvXub_StrLens aCompChg;
111
    SvXub_StrLens aCompLen;
113
    SvXub_StrLens aCompLen;
112
    SvXub_StrLens aHiddenChg;
114
    SvXub_StrLens aHiddenChg;
Lines 119-125 Link Here
119
    sal_Bool IsKashidaValid ( xub_StrLen nKashPos ) const;
121
    sal_Bool IsKashidaValid ( xub_StrLen nKashPos ) const;
120
    void MarkKashidaInvalid ( xub_StrLen nKashPos );
122
    void MarkKashidaInvalid ( xub_StrLen nKashPos );
121
    void ClearKashidaInvalid ( xub_StrLen nKashPos );
123
    void ClearKashidaInvalid ( xub_StrLen nKashPos );
122
    bool MarkOrClearKashidaInvalid( xub_StrLen nStt, xub_StrLen nLen, bool bMark );
124
    bool MarkOrClearKashidaInvalid( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount );
125
	bool IsKashidaLine ( xub_StrLen nCharIdx ) const;
126
	
123
127
124
public:
128
public:
125
    enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE };
129
    enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE };
Lines 272-285 Link Here
272
                           xub_StrLen nStt, xub_StrLen nLen,
276
                           xub_StrLen nStt, xub_StrLen nLen,
273
                           long nSpaceAdd = 0) const;
277
                           long nSpaceAdd = 0) const;
274
278
275
/** Marks a kashida as invalid for the given text range.
279
/** Clears array of kashidas marked as invalid
276
   returns true if a kashida was marked invalid
277
 */
280
 */
278
    inline bool MarkKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { return MarkOrClearKashidaInvalid( nStt, nLen, true ); }
281
    inline void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { MarkOrClearKashidaInvalid( nStt, nLen, false, 0 ); }
279
282
280
/** Clears array of kashidas marked as invalid
283
/** Marks nCnt kashida positions as invalid 
284
	pKashidaPositions: array of char indices relative to the paragraph
285
 */
286
	bool MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions );
287
288
/** Marks nCnt kashida positions as invalid 
289
	in the given text range
281
 */
290
 */
282
    inline void ClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen ) { MarkOrClearKashidaInvalid( nStt, nLen, false ); }
291
	inline bool MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen nStt, xub_StrLen nLen ) 
292
		{ return MarkOrClearKashidaInvalid( nStt, nLen, true, nCnt ); }
293
	
294
/** retrieves kashida opportunities for a given text range.
295
	returns the number of kashida positions in the given text range
296
297
	pKashidaPositions: buffer to reveive the char indices of the 
298
					   kashida opportunties relative to the paragraph
299
*/
300
	USHORT GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen, 
301
							  xub_StrLen* pKashidaPosition );
302
303
304
305
	
306
/** Use regular blank justification instead of kashdida justification for the given line of text.
307
	nStt Start char index of the line referring to the paragraph.
308
	nLen Number of characters in the line
309
*/
310
	void SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen );
311
312
/** Clear forced blank justification for a given line.
313
	nStt Start char index of the line referring to the paragraph.
314
	nLen Number of characters in the line
315
*/
316
	void ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen );
283
317
284
/** Checks if language is one of the 16 Arabic languages
318
/** Checks if language is one of the 16 Arabic languages
285
319
(-)text/itradj.cxx (-56 / +188 lines)
Lines 30-35 Link Here
30
30
31
// MARKER(update_precomp.py): autogen include statement, do not remove
31
// MARKER(update_precomp.py): autogen include statement, do not remove
32
#include "precompiled_sw.hxx"
32
#include "precompiled_sw.hxx"
33
#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
34
#include <com/sun/star/i18n/ScriptType.hdl>
35
#endif
36
33
#include <vcl/outdev.hxx>
37
#include <vcl/outdev.hxx>
34
#include <IDocumentSettingAccess.hxx>
38
#include <IDocumentSettingAccess.hxx>
35
39
Lines 46-51 Link Here
46
50
47
#define MIN_TAB_WIDTH 60
51
#define MIN_TAB_WIDTH 60
48
52
53
using namespace ::com::sun::star;
54
49
/*************************************************************************
55
/*************************************************************************
50
 *                    SwTxtAdjuster::FormatBlock()
56
 *                    SwTxtAdjuster::FormatBlock()
51
 *************************************************************************/
57
 *************************************************************************/
Lines 133-139 Link Here
133
 *************************************************************************/
139
 *************************************************************************/
134
140
135
void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent,
141
void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent,
136
								  const SwLinePortion *pStopAt, SwTwips nReal )
142
								  const SwLinePortion *pStopAt, SwTwips nReal, bool bSkipKashida )
137
{
143
{
138
	ASSERT( GetInfo().IsMulti() || SVX_ADJUST_BLOCK == GetAdjust(),
144
	ASSERT( GetInfo().IsMulti() || SVX_ADJUST_BLOCK == GetAdjust(),
139
			"CalcNewBlock: Why?" );
145
			"CalcNewBlock: Why?" );
Lines 153-164 Link Here
153
    {
159
    {
154
        while (aItr.GetCurr() != pCurrent && aItr.GetNext())
160
        while (aItr.GetCurr() != pCurrent && aItr.GetNext())
155
           aItr.Next();
161
           aItr.Next();
156
        rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() );
162
163
		if( bSkipKashida )
164
		{
165
			rSI.SetNoKashidaLine ( aItr.GetStart(), aItr.GetLength());
166
		}
167
		else
168
		{
169
			rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() );
170
			rSI.ClearNoKashidaLine( aItr.GetStart(), aItr.GetLength() );
171
		}
157
    }
172
    }
158
173
159
    // Nicht vergessen:
174
    // Nicht vergessen:
160
    // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite !
175
    // CalcRightMargin() setzt pCurrent->Width() auf die Zeilenbreite !
161
    CalcRightMargin( pCurrent, nReal );
176
    if (!bSkipKashida) 
177
		CalcRightMargin( pCurrent, nReal );
162
178
163
    // --> FME 2005-06-08 #i49277#
179
    // --> FME 2005-06-08 #i49277#
164
    const sal_Bool bDoNotJustifyLinesWithManualBreak =
180
    const sal_Bool bDoNotJustifyLinesWithManualBreak =
Lines 209-269 Link Here
209
225
210
                const long nGluePortionWidth = static_cast<SwGluePortion*>(pPos)->GetPrtGlue() *
226
                const long nGluePortionWidth = static_cast<SwGluePortion*>(pPos)->GetPrtGlue() *
211
                                               SPACING_PRECISION_FACTOR;
227
                                               SPACING_PRECISION_FACTOR;
212
228
				xub_StrLen nKashidas = 0;	
229
				if( nGluePortion && rSI.CountKashida() && !bSkipKashida )
230
				{
231
					// kashida positions found in SwScriptInfo are not necessarily valid in every font
232
					// if two characters are replaced by a ligature glyph, there will be no place for a kashida
233
					if ( !CheckKashidaPositions ( rSI, aInf, aItr, nKashidas, nGluePortion ))
234
					{
235
						// all kashida positions are invalid
236
						// do regular blank justification
237
						pCurrent->FinishSpaceAdd();
238
						GetInfo().SetIdx( nStart );
239
						CalcNewBlock( pCurrent, pStopAt, nReal, true );
240
						return;
241
					}
242
				}
213
				if( nGluePortion )
243
				if( nGluePortion )
214
				{
244
				{
215
                    // i60594
245
					long nSpaceAdd = nGluePortionWidth / nGluePortion;
216
                    long nSpaceAdd = nGluePortionWidth / nGluePortion;
246
					
217
247
					if( rSI.CountKashida() && !bSkipKashida )
218
                    // validate or recalculate for Kashida justification
248
					{
219
                    if ( rSI.CountKashida() )
249
						if( !CheckKashidaWidth( rSI, aInf, aItr, nKashidas, nGluePortion, nGluePortionWidth, nSpaceAdd ))
220
                    {
250
						{
221
                        xub_StrLen nIdx = aItr.GetStart();
251
							// no kashidas left
222
                        xub_StrLen nEnd = aItr.GetEnd();
252
							// do regular blank justification
223
253
							pCurrent->FinishSpaceAdd();
224
254
							GetInfo().SetIdx( nStart );
225
                        // Note on calling KashidaJustify():
255
							CalcNewBlock( pCurrent, pStopAt, nReal, true );
226
                        // Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
256
							return;
227
                        // total number of kashida positions, or the number of kashida positions after some positions
257
						}
228
                        // have been dropped.
258
					}
229
                        // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before.
259
						
230
                        xub_StrLen nKashidas = rSI.KashidaJustify ( 0, 0, aItr.GetStart(), aItr.GetLength(), 0 );
231
232
                        bool bAddSpaceChanged;
233
                        while ( nKashidas )
234
                        {
235
                            bAddSpaceChanged = false;
236
                            nIdx = aItr.GetStart();
237
                            aItr.SeekAndChgAttrIter( nIdx, aInf.GetOut() );
238
239
                            while ( nIdx < nEnd )
240
                            {
241
                                long nFontMinKashida = aInf.GetOut()->GetMinKashida();
242
                                if ( nFontMinKashida )
243
                                {
244
                                    while ( nKashidas && nGluePortion > 1 &&
245
                                            nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida )
246
                                    {
247
                                        if ( rSI.MarkKashidaInvalid(aItr.GetStart(), aItr.GetLength()) )
248
                                        {
249
                                            --nGluePortion;
250
                                            --nKashidas;
251
                                            nSpaceAdd = nGluePortionWidth / nGluePortion;
252
                                            bAddSpaceChanged = true;
253
                                        }
254
                                    }
255
                                }
256
                                if ( bAddSpaceChanged )
257
                                    break; // start all over again
258
                                nIdx = aItr.GetNextAttr();
259
                                if ( nIdx != STRING_LEN )
260
                                        aItr.SeekAndChgAttrIter( nIdx, aInf.GetOut() );
261
                            }
262
                            if ( !bAddSpaceChanged )
263
                                break; // everything was OK
264
                        }
265
                    }
266
267
                    pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx );
260
                    pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx );
268
                    pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
261
                    pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
269
				}
262
				}
Lines 292-297 Link Here
292
}
285
}
293
286
294
/*************************************************************************
287
/*************************************************************************
288
 *                    SwTxtAdjuster::CheckKashidaPositions()
289
 *************************************************************************/
290
bool SwTxtAdjuster::CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, 
291
										   xub_StrLen& nKashidas, xub_StrLen& nGluePortion )
292
{
293
	// i60594 validate Kashida justification
294
    xub_StrLen nIdx = rItr.GetStart();
295
    xub_StrLen nEnd = rItr.GetEnd();
296
297
	// Note on calling KashidaJustify():
298
	// Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
299
	// total number of kashida positions, or the number of kashida positions after some positions
300
	// have been dropped.
301
	// Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before.
302
	nKashidas = rSI.KashidaJustify ( 0, 0, rItr.GetStart(), rItr.GetLength(), 0 );
303
304
	if (!nKashidas) // nothing to do
305
		return true;
306
307
	// kashida positions found in SwScriptInfo are not necessarily valid in every font
308
	// if two characters are replaced by a ligature glyph, there will be no place for a kashida
309
	xub_StrLen* pKashidaPos = new xub_StrLen [ nKashidas ];
310
	xub_StrLen* pKashidaPosDropped = new xub_StrLen [ nKashidas ];
311
	rSI.GetKashidaPositions ( nIdx, rItr.GetLength(), pKashidaPos );
312
	xub_StrLen nKashidaIdx = 0;
313
	while ( nKashidas && nIdx < nEnd ) 
314
	{
315
		rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
316
		xub_StrLen nNext = rItr.GetNextAttr();
317
318
		// is there also a script change before?
319
		// if there is, nNext should point to the script change
320
		xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
321
		if( nNextScript < nNext )
322
			nNext = nNextScript;
323
324
		if ( nNext == STRING_LEN || nNext > nEnd ) 
325
			nNext = nEnd;
326
		xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
327
		if ( nKashidasInAttr )
328
		{
329
			xub_StrLen nKashidasDropped = 0;
330
			LanguageType aLang = GetTxtFrm()->GetTxtNode()->
331
							GetLang ( nIdx, 1, i18n::ScriptType::COMPLEX );
332
			if ( !SwScriptInfo::IsArabicLanguage( aLang ) )
333
			{
334
				nKashidasDropped = nKashidasInAttr;
335
				nKashidas -= nKashidasDropped;
336
			}
337
			else
338
			{
339
				ULONG nOldLayout = rInf.GetOut()->GetLayoutMode();
340
				rInf.GetOut()->SetLayoutMode ( nOldLayout | TEXT_LAYOUT_BIDI_RTL );
341
				nKashidasDropped = rInf.GetOut()->ValidateKashidas ( rInf.GetTxt(), nIdx, nNext - nIdx, 
342
												nKashidasInAttr, pKashidaPos + nKashidaIdx, 
343
												pKashidaPosDropped );
344
			    rInf.GetOut()->SetLayoutMode ( nOldLayout );
345
				if ( nKashidasDropped )
346
				{
347
					rSI.MarkKashidasInvalid ( nKashidasDropped, pKashidaPosDropped );
348
					nKashidas -= nKashidasDropped;
349
					nGluePortion -= nKashidasDropped;
350
				}
351
			}
352
			nKashidaIdx += nKashidasInAttr;
353
		}
354
		nIdx = nNext;
355
	}
356
	delete[] pKashidaPos;
357
	delete[] pKashidaPosDropped;
358
	
359
	// return false if all kashidas have been eliminated
360
	return (nKashidas > 0);
361
}
362
363
364
/*************************************************************************
365
 *                    SwTxtAdjuster::CheckKashidaWidth()
366
 *************************************************************************/
367
bool SwTxtAdjuster::CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas, 
368
										 xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd )
369
{
370
	// check kashida width
371
	// if width is smaller than minimal kashida width allowed by fonts in the current line
372
	// drop one kashida after the other until kashida width is OK
373
    bool bAddSpaceChanged;
374
    while ( nKashidas )
375
    {
376
        bAddSpaceChanged = false;
377
        xub_StrLen nIdx = rItr.GetStart();
378
		xub_StrLen nEnd = rItr.GetEnd();
379
        while ( nIdx < nEnd )
380
        {
381
			rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
382
			xub_StrLen nNext = rItr.GetNextAttr();
383
384
			// is there also a script change before?
385
			// if there is, nNext should point to the script change
386
			xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
387
			if( nNextScript < nNext )
388
				nNext = nNextScript;
389
390
			if ( nNext == STRING_LEN || nNext > nEnd ) 
391
				nNext = nEnd;
392
			xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
393
        
394
            long nFontMinKashida = rInf.GetOut()->GetMinKashida();
395
			LanguageType aLang = GetTxtFrm()->GetTxtNode()->
396
							GetLang ( nIdx, 1, i18n::ScriptType::COMPLEX );
397
            if ( nFontMinKashida && nKashidasInAttr && SwScriptInfo::IsArabicLanguage( aLang ))
398
            {
399
				xub_StrLen nKashidasDropped = 0;
400
                while ( nKashidas && nGluePortion && nKashidasInAttr &&
401
                        nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida )
402
                {
403
                    --nGluePortion;
404
                    --nKashidas;
405
					--nKashidasInAttr;
406
					++nKashidasDropped;
407
					if( !nKashidas || !nGluePortion ) // nothing left, return false to 
408
						return false;				  // do regular blank justification
409
					
410
                    nSpaceAdd = nGluePortionWidth / nGluePortion;
411
                    bAddSpaceChanged = true;
412
                }
413
				if( nKashidasDropped )
414
					rSI.MarkKashidasInvalid( nKashidasDropped, nIdx, nNext - nIdx );
415
            }
416
            if ( bAddSpaceChanged )
417
                break; // start all over again
418
            nIdx = nNext;
419
        }
420
        if ( !bAddSpaceChanged )
421
            break; // everything was OK
422
    }
423
	return true;
424
}
425
426
/*************************************************************************
295
 *                    SwTxtAdjuster::CalcKanaAdj()
427
 *                    SwTxtAdjuster::CalcKanaAdj()
296
 *************************************************************************/
428
 *************************************************************************/
297
429
(-)text/itrcrsr.cxx (+7 lines)
Lines 506-511 Link Here
506
        SwTwips nTmpFirst = 0;
506
        SwTwips nTmpFirst = 0;
507
		SwLinePortion *pPor = pCurr->GetFirstPortion();
507
		SwLinePortion *pPor = pCurr->GetFirstPortion();
508
        SwBidiPortion* pLastBidiPor = 0;
508
        SwBidiPortion* pLastBidiPor = 0;
509
		xub_StrLen nLastBidiIdx = 0;
509
        SvUShorts* pKanaComp = pCurr->GetpKanaComp();
510
        SvUShorts* pKanaComp = pCurr->GetpKanaComp();
510
        MSHORT nSpaceIdx = 0;
511
        MSHORT nSpaceIdx = 0;
511
        MSHORT nKanaIdx = 0;
512
        MSHORT nKanaIdx = 0;
Lines 649-655 Link Here
649
                        // cursor level
650
                        // cursor level
650
                        if ( ((SwMultiPortion*)pPor)->IsBidi() &&
651
                        if ( ((SwMultiPortion*)pPor)->IsBidi() &&
651
                             aInf.GetIdx() + pPor->GetLen() == nOfst )
652
                             aInf.GetIdx() + pPor->GetLen() == nOfst )
653
                        {
652
                             pLastBidiPor = (SwBidiPortion*)pPor;
654
                             pLastBidiPor = (SwBidiPortion*)pPor;
655
							 nLastBidiIdx = aInf.GetIdx();
656
						}
653
                    }
657
                    }
654
658
655
					aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
659
					aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
Lines 1086-1093 Link Here
1086
                {
1090
                {
1087
                    // we came from inside the bidi portion, we want to blink
1091
                    // we came from inside the bidi portion, we want to blink
1088
                    // behind the portion
1092
                    // behind the portion
1093
                    xub_StrLen nOldIdx = aInf.GetIdx();
1094
					aInf.SetIdx ( nLastBidiIdx );
1089
                    pOrig->Pos().X() -= pLastBidiPor->Width() +
1095
                    pOrig->Pos().X() -= pLastBidiPor->Width() +
1090
                                        pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );
1096
                                        pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );
1097
					aInf.SetIdx ( nOldIdx );
1091
1098
1092
                    // Again, there is a special case: logically behind
1099
                    // Again, there is a special case: logically behind
1093
                    // the portion can actually mean that the cursor is inside
1100
                    // the portion can actually mean that the cursor is inside
(-)text/itrtxt.hxx (-1 / +6 lines)
Lines 230-236 Link Here
230
	inline SwTxtAdjuster() { }
230
	inline SwTxtAdjuster() { }
231
	// spannt beim Blocksatz die Glues auf.
231
	// spannt beim Blocksatz die Glues auf.
232
	void CalcNewBlock( SwLineLayout *pCurr, const SwLinePortion *pStopAt,
232
	void CalcNewBlock( SwLineLayout *pCurr, const SwLinePortion *pStopAt,
233
		SwTwips nReal = 0 );
233
		SwTwips nReal = 0, bool bSkipKashida = false );
234
    SwTwips CalcKanaAdj( SwLineLayout *pCurr );
234
    SwTwips CalcKanaAdj( SwLineLayout *pCurr );
235
public:
235
public:
236
    inline SwTxtAdjuster( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf )
236
    inline SwTxtAdjuster( SwTxtFrm *pTxtFrm, SwTxtSizeInfo *pTxtSizeInf )
Lines 249-254 Link Here
249
	// DropCaps-Extrawurst
249
	// DropCaps-Extrawurst
250
	void CalcDropAdjust();
250
	void CalcDropAdjust();
251
	void CalcDropRepaint();
251
	void CalcDropRepaint();
252
private:
253
	bool CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, 
254
										   xub_StrLen& nKashidas, xub_StrLen& nGluePortion );
255
	bool CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas, 
256
										 xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd );
252
};
257
};
253
258
254
/*************************************************************************
259
/*************************************************************************
(-)text/porlay.cxx (-13 / +101 lines)
Lines 181-189 Link Here
181
sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh )
181
sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh )
182
{
182
{
183
            // Lam + Alef
183
            // Lam + Alef
184
    return ( 0x644 == cCh && 0x627 == cNextCh ) ||
184
    return ( isLamChar ( cCh ) && isAlefChar ( cNextCh )); // ||
185
            // Beh + Reh
185
            // Beh + Reh
186
           ( 0x628 == cCh && 0x631 == cNextCh );
186
            //  ( 0x628 == cCh && 0x631 == cNextCh );
187
}
187
}
188
188
189
/*************************************************************************
189
/*************************************************************************
Lines 198-203 Link Here
198
    // Uh, there seem to be some more characters that are not connectable
198
    // Uh, there seem to be some more characters that are not connectable
199
    // to the left. So we look for the characters that are actually connectable
199
    // to the left. So we look for the characters that are actually connectable
200
    // to the left. Here is the complete list of WH:
200
    // to the left. Here is the complete list of WH:
201
202
	// (hennerdrewes) to do: this should be reworked
203
	// use the isXXXChar functions to exclude the non-connecting character classes
201
    sal_Bool bRet = 0x628 == cPrevCh ||
204
    sal_Bool bRet = 0x628 == cPrevCh ||
202
                    ( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) ||
205
                    ( 0x62A <= cPrevCh && cPrevCh <= 0x62E ) ||
203
                    ( 0x633 <= cPrevCh && cPrevCh <= 0x643 ) ||
206
                    ( 0x633 <= cPrevCh && cPrevCh <= 0x643 ) ||
Lines 1827-1832 Link Here
1827
{
1830
{
1828
    ASSERT( nLen, "Kashida justification without text?!" )
1831
    ASSERT( nLen, "Kashida justification without text?!" )
1829
1832
1833
	if( !IsKashidaLine(nStt))
1834
		return STRING_LEN;
1835
1830
    // evaluate kashida informatin in collected in SwScriptInfo
1836
    // evaluate kashida informatin in collected in SwScriptInfo
1831
1837
1832
    USHORT nCntKash = 0;
1838
    USHORT nCntKash = 0;
Lines 1949-1956 Link Here
1949
/*************************************************************************
1955
/*************************************************************************
1950
 *                      SwScriptInfo::MarkOrClearKashidaInvalid()
1956
 *                      SwScriptInfo::MarkOrClearKashidaInvalid()
1951
 *************************************************************************/
1957
 *************************************************************************/
1958
// bMark == true:
1959
// marks the first valid kashida in the given text range as invalid
1960
1961
// bMark == false:
1962
// clears all kashida invalid flags in the given text range
1952
1963
1953
bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark )
1964
bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount )
1954
{
1965
{
1955
    USHORT nCntKash = 0;
1966
    USHORT nCntKash = 0;
1956
    while( nCntKash < CountKashida() )
1967
    while( nCntKash < CountKashida() )
Lines 1974-1980 Link Here
1974
                if ( IsKashidaValid ( nCntKash ) )
1985
                if ( IsKashidaValid ( nCntKash ) )
1975
                {
1986
                {
1976
                    MarkKashidaInvalid ( nCntKash );
1987
                    MarkKashidaInvalid ( nCntKash );
1977
                    return true;
1988
					--nMarkCount;
1989
					if(!nMarkCount)
1990
						return true;
1978
                }
1991
                }
1979
            }
1992
            }
1980
            else
1993
            else
Lines 1992-2001 Link Here
1992
    aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() );
2005
    aKashidaInvalid.Insert( nKashPos, aKashidaInvalid.Count() );
1993
}
2006
}
1994
2007
1995
/*
2008
/*************************************************************************
1996
USHORT SwScriptInfo::CountKashidaInRange ( xub_StrLen nStt, xub_StrLen nLen )
2009
 *                      SwScriptInfo::MarkKashidasInvalid()
2010
 *************************************************************************/
2011
// mark the given character indices as invalid kashida positions
2012
bool SwScriptInfo::MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions )
2013
{
2014
	ASSERT( pKashidaPositions && nCnt > 0, "Where are kashidas?" )
2015
	
2016
	USHORT nCntKash = 0;
2017
	xub_StrLen nKashidaPosIdx = 0;
2018
2019
    while ( nCntKash < CountKashida() && nKashidaPosIdx < nCnt )
2020
    {
2021
		if ( pKashidaPositions [nKashidaPosIdx] > GetKashida( nCntKash ) )
2022
		{
2023
			nCntKash++;
2024
			continue;
2025
		}
2026
2027
        if ( pKashidaPositions [nKashidaPosIdx] == GetKashida( nCntKash ) && IsKashidaValid ( nCntKash ) )
2028
		{
2029
            MarkKashidaInvalid ( nCntKash );
2030
		}
2031
		else
2032
			return false; // something is wrong 
2033
		nKashidaPosIdx++;
2034
	}
2035
	return true;
2036
}
2037
2038
/*************************************************************************
2039
 *                      SwScriptInfo::GetKashidaPositions()
2040
 *************************************************************************/
2041
// retrieve the kashida positions in the given text range
2042
USHORT SwScriptInfo::GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen, 
2043
							  xub_StrLen* pKashidaPosition )
1997
{
2044
{
1998
   USHORT nCntKash = 0;
2045
	USHORT nCntKash = 0;
1999
    while( nCntKash < CountKashida() )
2046
    while( nCntKash < CountKashida() )
2000
    {
2047
    {
2001
        if ( nStt <= GetKashida( nCntKash ) )
2048
        if ( nStt <= GetKashida( nCntKash ) )
Lines 2003-2022 Link Here
2003
        else
2050
        else
2004
            nCntKash++;
2051
            nCntKash++;
2005
    }
2052
    }
2006
2053
	const xub_StrLen nEnd = nStt + nLen;
2007
    const xub_StrLen nEnd = nStt + nLen;
2008
2009
    USHORT nCntKashEnd = nCntKash;
2054
    USHORT nCntKashEnd = nCntKash;
2010
    while ( nCntKashEnd < CountKashida() )
2055
    while ( nCntKashEnd < CountKashida() )
2011
    {
2056
    {
2012
       if ( nEnd <= GetKashida( nCntKashEnd ) )
2057
		if ( nEnd <= GetKashida( nCntKashEnd ) )
2013
            break;
2058
            break;
2014
        else
2059
        else
2060
		{
2061
			pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd );
2015
            nCntKashEnd++;
2062
            nCntKashEnd++;
2063
		}
2064
    }
2065
	return nCntKashEnd - nCntKash;
2066
}
2067
2068
/*************************************************************************
2069
 *                      SwScriptInfo::IsKashidaLine()
2070
 *************************************************************************/
2071
// determines if the line uses kashida justification
2072
2073
bool SwScriptInfo::IsKashidaLine ( xub_StrLen nCharIdx ) const
2074
{
2075
	for( xub_StrLen i = 0; i < aNoKashidaLine.Count(); ++i )
2076
    {
2077
		if( nCharIdx >= aNoKashidaLine[ i ] && nCharIdx < aNoKashidaLineEnd[ i ])
2078
			return false;
2079
    }
2080
	return true;
2081
}
2082
/*************************************************************************
2083
 *                      SwScriptInfo::ClearKashidaLine()
2084
 *************************************************************************/
2085
2086
void SwScriptInfo::ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
2087
{
2088
	xub_StrLen i = 0;
2089
	while( i < aNoKashidaLine.Count())
2090
	{
2091
		if( nStt + nLen >= aNoKashidaLine[ i ] && nStt < aNoKashidaLineEnd [ i ] )
2092
		{
2093
			aNoKashidaLine.Remove(i, 1);
2094
			aNoKashidaLineEnd.Remove(i, 1);
2095
		}
2096
		else
2097
			++i;
2016
    }
2098
    }
2017
   return nCntKashEnd - nCntKash;
2018
}
2099
}
2019
*/
2100
2101
void SwScriptInfo::SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
2102
{
2103
	aNoKashidaLine.Insert( nStt, aNoKashidaLine.Count());
2104
	aNoKashidaLineEnd.Insert( nStt+nLen, aNoKashidaLineEnd.Count());
2105
}
2106
2107
2020
2108
2021
/*************************************************************************
2109
/*************************************************************************
2022
 *                      SwScriptInfo::ThaiJustify()
2110
 *                      SwScriptInfo::ThaiJustify()
(-)text/pormulti.cxx (+5 lines)
Lines 2393-2399 Link Here
2393
            nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
2393
            nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
2394
        }
2394
        }
2395
        else
2395
        else
2396
		{
2397
			xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx();
2398
			pTxtCursor->GetInfo().SetIdx ( nCurrStart );
2396
            nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
2399
            nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
2400
			pTxtCursor->GetInfo().SetIdx ( nOldIdx );
2401
		}
2397
2402
2398
		if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
2403
		if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
2399
            pTxtCursor->pCurr->Width( static_cast<USHORT>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
2404
            pTxtCursor->pCurr->Width( static_cast<USHORT>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
(-)text/portxt.cxx (-1 / +7 lines)
Lines 157-163 Link Here
157
            rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
157
            rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
158
158
159
        if ( SwScriptInfo::IsArabicLanguage( aLang ) )
159
        if ( SwScriptInfo::IsArabicLanguage( aLang ) )
160
            return pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
160
		{	
161
			USHORT nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
162
			// i60591: need to check result of KashidaJustify 
163
			// determine if kashida justification is applicable
164
			if( nKashRes != STRING_LEN )
165
				return nKashRes;
166
		}
161
    }
167
    }
162
168
163
    // Here starts the good old "Look for blanks and add space to them" part.
169
    // Here starts the good old "Look for blanks and add space to them" part.
(-)txtnode/fntcache.cxx (-14 / +18 lines)
Lines 1538-1549 Link Here
1538
                    if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
1538
                    if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
1539
                                                         GetLanguage( SW_CTL ) ) )
1539
                                                         GetLanguage( SW_CTL ) ) )
1540
                    {
1540
                    {
1541
                        if ( pSI && pSI->CountKashida() )
1541
                        if ( pSI && pSI->CountKashida() && 
1542
                            pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(),
1542
                            pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(),
1543
                                                rInf.GetLen(), nSpaceAdd );
1543
                                                rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
1544
1544
						{
1545
                        bSpecialJust = sal_True;
1545
							bSpecialJust = sal_True;
1546
                        nSpaceAdd = 0;
1546
							nSpaceAdd = 0;
1547
						}
1547
                    }
1548
                    }
1548
                }
1549
                }
1549
            }
1550
            }
Lines 1697-1702 Link Here
1697
        // Modify Printer and ScreenArrays for special justifications
1698
        // Modify Printer and ScreenArrays for special justifications
1698
        //
1699
        //
1699
        long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1700
        long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1701
		bool bNoHalfSpace = false;
1700
1702
1701
        if ( rInf.GetFont() && rInf.GetLen() )
1703
        if ( rInf.GetFont() && rInf.GetLen() )
1702
        {
1704
        {
Lines 1760-1769 Link Here
1760
                if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
1762
                if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
1761
                                                        GetLanguage( SW_CTL ) ) )
1763
                                                        GetLanguage( SW_CTL ) ) )
1762
                {
1764
                {
1763
                    if ( pSI && pSI->CountKashida() )
1765
                    if ( pSI && pSI->CountKashida() && 
1764
                        pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(),
1766
						pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(),
1765
                                             rInf.GetLen(), nSpaceAdd );
1767
                                             rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
1766
                    nSpaceAdd = 0;
1768
						nSpaceAdd = 0;
1769
					else
1770
						bNoHalfSpace = true;
1771
1767
                }
1772
                }
1768
            }
1773
            }
1769
        }
1774
        }
Lines 1842-1848 Link Here
1842
            // vor bzw. hinter den kompletten Zwischenraum gesetzt werden,
1847
            // vor bzw. hinter den kompletten Zwischenraum gesetzt werden,
1843
            // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen.
1848
            // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen.
1844
            long nSpaceSum = 0;
1849
            long nSpaceSum = 0;
1845
            long nHalfSpace = pPrtFont->IsWordLineMode() ? 0 : nSpaceAdd / 2;
1850
            long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
1846
            long nOtherHalf = nSpaceAdd - nHalfSpace;
1851
            long nOtherHalf = nSpaceAdd - nHalfSpace;
1847
            if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1852
            if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1848
                nSpaceSum = nHalfSpace;
1853
                nSpaceSum = nHalfSpace;
Lines 2358-2368 Link Here
2358
            if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
2363
            if ( SwScriptInfo::IsArabicLanguage( rInf.GetFont()->
2359
                                                    GetLanguage( SW_CTL ) ) )
2364
                                                    GetLanguage( SW_CTL ) ) )
2360
            {
2365
            {
2361
                if ( pSI && pSI->CountKashida() )
2366
                if ( pSI && pSI->CountKashida() &&
2362
                    pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(),
2367
                    pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(),
2363
                                         nSpaceAdd );
2368
                                         nSpaceAdd ) != STRING_LEN )
2364
2369
					nSpaceAdd = 0;
2365
                nSpaceAdd = 0;
2366
            }
2370
            }
2367
        }
2371
        }
2368
    }
2372
    }
(-)txtnode/thints.cxx (-9 / +3 lines)
Lines 2333-2345 Link Here
2333
{
2333
{
2334
	USHORT nWhichId = RES_CHRATR_LANGUAGE;
2334
	USHORT nWhichId = RES_CHRATR_LANGUAGE;
2335
	USHORT nRet = LANGUAGE_DONTKNOW;
2335
	USHORT nRet = LANGUAGE_DONTKNOW;
2336
	if( pSwpHints )
2336
	if ( ! nScript )
2337
	{
2338
        if ( ! nScript )
2339
            nScript = pBreakIt->GetRealScriptOfText( aText, nBegin );
2337
            nScript = pBreakIt->GetRealScriptOfText( aText, nBegin );
2340
2341
        nWhichId = GetWhichOfScript( nWhichId, nScript );
2338
        nWhichId = GetWhichOfScript( nWhichId, nScript );
2342
2339
	if( pSwpHints )
2340
	{
2343
		xub_StrLen nEnd = nBegin + nLen;
2341
		xub_StrLen nEnd = nBegin + nLen;
2344
		for( USHORT i = 0, nSize = pSwpHints->Count(); i < nSize; ++i )
2342
		for( USHORT i = 0, nSize = pSwpHints->Count(); i < nSize; ++i )
2345
		{
2343
		{
Lines 2379-2388 Link Here
2379
	}
2377
	}
2380
	if( LANGUAGE_DONTKNOW == nRet )
2378
	if( LANGUAGE_DONTKNOW == nRet )
2381
	{
2379
	{
2382
		if( !pSwpHints )
2383
			nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE,
2384
                        pBreakIt->GetRealScriptOfText( aText, nBegin ));
2385
2386
		nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
2380
		nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
2387
		if( LANGUAGE_DONTKNOW == nRet )
2381
		if( LANGUAGE_DONTKNOW == nRet )
2388
            nRet = static_cast<USHORT>(GetAppLanguage());
2382
            nRet = static_cast<USHORT>(GetAppLanguage());

Return to issue 60594