xref: /aoo41x/main/vcl/source/glyphs/gcach_layout.cxx (revision 4bb59e41)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #define ENABLE_ICU_LAYOUT
32 #include <gcach_ftyp.hxx>
33 #include <sallayout.hxx>
34 #include <salgdi.hxx>
35 
36 #include <vcl/svapp.hxx>
37 
38 #include <sal/alloca.h>
39 
40 #if OSL_DEBUG_LEVEL > 1
41 #include <cstdio>
42 #endif
43 #include <rtl/instance.hxx>
44 
45 namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; }
46 
47 // =======================================================================
48 // layout implementation for ServerFont
49 // =======================================================================
50 
51 ServerFontLayout::ServerFontLayout( ServerFont& rFont )
52 :   mrServerFont( rFont )
53 {}
54 
55 void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
56 {
57     rSalGraphics.DrawServerFontLayout( *this );
58 }
59 
60 // -----------------------------------------------------------------------
61 
62 bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
63 {
64     ServerFontLayoutEngine* pLE = NULL;
65     if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) )
66         pLE = mrServerFont.GetLayoutEngine();
67     if( !pLE )
68         pLE = &SimpleLayoutEngine::get();
69 
70     bool bRet = (*pLE)( *this, rArgs );
71     return bRet;
72 }
73 
74 // -----------------------------------------------------------------------
75 
76 void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
77 {
78     GenericSalLayout::AdjustLayout( rArgs );
79 
80     // apply asian kerning if the glyphs are not already formatted
81     if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
82     && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
83         if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
84             ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
85 
86     // insert kashidas where requested by the formatting array
87     if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
88     {
89         int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
90         if( nKashidaIndex != 0 )
91         {
92             const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
93             KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
94             // TODO: kashida-GSUB/GPOS
95         }
96     }
97 }
98 
99 // =======================================================================
100 
101 bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
102 {
103     FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont());
104 
105     Point aNewPos( 0, 0 );
106     int nOldGlyphId = -1;
107     int nGlyphWidth = 0;
108     GlyphItem aPrevItem;
109     bool bRightToLeft;
110     for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
111     {
112         sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
113         if( (cChar >= 0xD800) && (cChar <= 0xDFFF) )
114         {
115             if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
116                 continue;
117             cChar = 0x10000 + ((cChar - 0xD800) << 10)
118                   + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00);
119         }
120 
121         if( bRightToLeft )
122             cChar = GetMirroredChar( cChar );
123         int nGlyphIndex = rFont.GetGlyphIndex( cChar );
124         // when glyph fallback is needed update LayoutArgs
125         if( !nGlyphIndex ) {
126             rArgs.NeedFallback( nCharPos, bRightToLeft );
127 	    if( cChar >= 0x10000 ) // handle surrogate pairs
128                 rArgs.NeedFallback( nCharPos+1, bRightToLeft );
129 	}
130 
131         // apply pair kerning to prev glyph if requested
132         if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
133         {
134             int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, nGlyphIndex );
135             nGlyphWidth += nKernValue;
136             aPrevItem.mnNewWidth = nGlyphWidth;
137         }
138 
139         // finish previous glyph
140         if( nOldGlyphId >= 0 )
141             rLayout.AppendGlyph( aPrevItem );
142         aNewPos.X() += nGlyphWidth;
143 
144         // prepare GlyphItem for appending it in next round
145         nOldGlyphId = nGlyphIndex;
146         const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
147         nGlyphWidth = rGM.GetCharWidth();
148         int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
149         aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
150     }
151 
152     // append last glyph item if any
153     if( nOldGlyphId >= 0 )
154         rLayout.AppendGlyph( aPrevItem );
155 
156     return true;
157 }
158 
159 // =======================================================================
160 // bridge to ICU LayoutEngine
161 // =======================================================================
162 
163 #ifdef ENABLE_ICU_LAYOUT
164 
165 #define bool_t signed char
166 
167 // disable warnings in icu layout headers
168 #if defined __SUNPRO_CC
169 #pragma disable_warn
170 #endif
171 
172 #include <layout/LayoutEngine.h>
173 #include <layout/LEFontInstance.h>
174 #include <layout/LEScripts.h>
175 
176 // enable warnings again
177 #if defined __SUNPRO_CC
178 #pragma enable_warn
179 #endif
180 
181 #include <unicode/uscript.h>
182 #include <unicode/ubidi.h>
183 
184 using namespace U_ICU_NAMESPACE;
185 
186 static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF;
187 static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE;
188 
189 // -----------------------------------------------------------------------
190 
191 class IcuFontFromServerFont
192 : public LEFontInstance
193 {
194 private:
195     FreetypeServerFont&     mrServerFont;
196 
197 public:
198                             IcuFontFromServerFont( FreetypeServerFont& rFont )
199                             : mrServerFont( rFont )
200                             {}
201 
202     virtual const void*     getFontTable(LETag tableTag) const;
203     virtual le_int32        getUnitsPerEM() const;
204     virtual float           getXPixelsPerEm() const;
205     virtual float           getYPixelsPerEm() const;
206     virtual float           getScaleFactorX() const;
207     virtual float           getScaleFactorY() const;
208 
209     using LEFontInstance::mapCharToGlyph;
210     virtual LEGlyphID       mapCharToGlyph( LEUnicode32 ch ) const;
211 
212     virtual le_int32        getAscent() const;
213     virtual le_int32        getDescent() const;
214     virtual le_int32        getLeading() const;
215 
216     virtual void            getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const;
217     virtual le_bool         getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const;
218 };
219 
220 // -----------------------------------------------------------------------
221 
222 const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const
223 {
224     char pTagName[5];
225     pTagName[0] = (char)(nICUTableTag >> 24);
226     pTagName[1] = (char)(nICUTableTag >> 16);
227     pTagName[2] = (char)(nICUTableTag >>  8);
228     pTagName[3] = (char)(nICUTableTag);
229     pTagName[4] = 0;
230 
231     sal_uLong nLength;
232     const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength );
233 #ifdef VERBOSE_DEBUG
234     fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer);
235     int mnHeight = mrServerFont.GetFontSelData().mnHeight;
236     const char* pName = mrServerFont.GetFontFileName()->getStr();
237     fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName );
238 #endif
239     return (const void*)pBuffer;
240 }
241 
242 // -----------------------------------------------------------------------
243 
244 le_int32 IcuFontFromServerFont::getUnitsPerEM() const
245 {
246     return mrServerFont.GetEmUnits();
247 }
248 
249 // -----------------------------------------------------------------------
250 
251 float IcuFontFromServerFont::getXPixelsPerEm() const
252 {
253     const ImplFontSelectData& r = mrServerFont.GetFontSelData();
254     float fX = r.mnWidth ? r.mnWidth : r.mnHeight;
255     return fX;
256 }
257 
258 // -----------------------------------------------------------------------
259 
260 float IcuFontFromServerFont::getYPixelsPerEm() const
261 {
262     float fY = mrServerFont.GetFontSelData().mnHeight;
263     return fY;
264 }
265 
266 // -----------------------------------------------------------------------
267 
268 float IcuFontFromServerFont::getScaleFactorX() const
269 {
270     return 1.0;
271 }
272 
273 // -----------------------------------------------------------------------
274 
275 float IcuFontFromServerFont::getScaleFactorY() const
276 {
277     return 1.0;
278 }
279 
280 // -----------------------------------------------------------------------
281 
282 LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const
283 {
284     LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch );
285     return nGlyphIndex;
286 }
287 
288 // -----------------------------------------------------------------------
289 
290 le_int32 IcuFontFromServerFont::getAscent() const
291 {
292     const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
293     le_int32 nAscent = (+rMetrics.ascender + 32) >> 6;
294     return nAscent;
295 }
296 
297 // -----------------------------------------------------------------------
298 
299 le_int32 IcuFontFromServerFont::getDescent() const
300 {
301     const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
302     le_int32 nDescent = (-rMetrics.descender + 32) >> 6;
303     return nDescent;
304 }
305 
306 // -----------------------------------------------------------------------
307 
308 le_int32 IcuFontFromServerFont::getLeading() const
309 {
310     const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
311     le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6;
312     return nLeading;
313 }
314 
315 // -----------------------------------------------------------------------
316 
317 void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex,
318     LEPoint &advance ) const
319 {
320     if( (nGlyphIndex == ICU_MARKED_GLYPH)
321     ||  (nGlyphIndex == ICU_DELETED_GLYPH) )
322     {
323         // deleted glyph or mark glyph has not advance
324         advance.fX = 0;
325     }
326     else
327     {
328         const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex );
329         advance.fX = rGM.GetCharWidth();
330     }
331 
332     advance.fY = 0;
333 }
334 
335 // -----------------------------------------------------------------------
336 
337 le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID,
338     le_int32
339 #if OSL_DEBUG_LEVEL > 1
340 pointNumber
341 #endif
342     ,
343     LEPoint& ) const
344 {
345     //TODO: replace dummy implementation
346 #if OSL_DEBUG_LEVEL > 1
347     fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber );
348 #endif
349     return false;
350 }
351 
352 // =======================================================================
353 
354 class IcuLayoutEngine : public ServerFontLayoutEngine
355 {
356 private:
357     IcuFontFromServerFont   maIcuFont;
358 
359     le_int32                meScriptCode;
360     LayoutEngine*           mpIcuLE;
361 
362 public:
363                             IcuLayoutEngine( FreetypeServerFont& );
364     virtual                 ~IcuLayoutEngine();
365 
366     virtual bool            operator()( ServerFontLayout&, ImplLayoutArgs& );
367 };
368 
369 // -----------------------------------------------------------------------
370 
371 IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont )
372 :   maIcuFont( rServerFont ),
373     meScriptCode( USCRIPT_INVALID_CODE ),
374     mpIcuLE( NULL )
375 {}
376 
377 // -----------------------------------------------------------------------
378 
379 IcuLayoutEngine::~IcuLayoutEngine()
380 {
381     if( mpIcuLE )
382         delete mpIcuLE;
383 }
384 
385 // -----------------------------------------------------------------------
386 
387 static bool lcl_CharIsJoiner(sal_Unicode cChar)
388 {
389 	return ((cChar == 0x200C) || (cChar == 0x200D));
390 }
391 
392 bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
393 {
394     LEUnicode* pIcuChars;
395     if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) )
396         pIcuChars = (LEUnicode*)rArgs.mpStr;
397     else
398     {
399         // this conversion will only be needed when either
400         // ICU's or OOo's unicodes stop being unsigned shorts
401         // TODO: watch out for surrogates!
402         pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) );
403         for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic )
404             pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] );
405     }
406 
407     // allocate temporary arrays, note: round to even
408     int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
409 
410     struct IcuPosition{ float fX, fY; };
411     const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition);
412     LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) );
413     le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) );
414     IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) );
415 
416     FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont());
417 
418     UErrorCode rcI18n = U_ZERO_ERROR;
419     LEErrorCode rcIcu = LE_NO_ERROR;
420     Point aNewPos( 0, 0 );
421     for( int nGlyphCount = 0;; )
422     {
423         int nMinRunPos, nEndRunPos;
424         bool bRightToLeft;
425         if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
426             break;
427 
428         // find matching script
429         // TODO: split up bidi run into script runs
430         le_int32 eScriptCode = -1;
431         for( int i = nMinRunPos; i < nEndRunPos; ++i )
432         {
433             eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n );
434             if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) )
435                 break;
436         }
437         if( eScriptCode < 0 )   // TODO: handle errors better
438             eScriptCode = latnScriptCode;
439 
440         // get layout engine matching to this script
441         // no engine change necessary if script is latin
442         if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) )
443         {
444             // TODO: cache multiple layout engines when multiple scripts are used
445             delete mpIcuLE;
446             meScriptCode = eScriptCode;
447             le_int32 eLangCode = 0; // TODO: get better value
448             mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu );
449             if( LE_FAILURE(rcIcu) )
450             {
451                 delete mpIcuLE;
452                 mpIcuLE = NULL;
453             }
454         }
455 
456         // fall back to default layout if needed
457         if( !mpIcuLE )
458             break;
459 
460         // run ICU layout engine
461         // TODO: get enough context, remove extra glyps below
462         int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars,
463             nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength,
464             bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu );
465         if( LE_FAILURE(rcIcu) )
466             return false;
467 
468         // import layout info from icu
469         mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu );
470         mpIcuLE->getCharIndices( pCharIndices, rcIcu );
471         mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu );
472         mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed
473         if( LE_FAILURE(rcIcu) )
474             return false;
475 
476         // layout bidi/script runs and export them to a ServerFontLayout
477         // convert results to GlyphItems
478         int nLastCharPos = -1;
479         int nClusterMinPos = -1;
480         int nClusterMaxPos = -1;
481         bool bClusterStart = true;
482         int nFilteredRunGlyphCount = 0;
483         const IcuPosition* pPos = pGlyphPositions;
484         for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos )
485         {
486             LEGlyphID nGlyphIndex = pIcuGlyphs[i];
487             // ignore glyphs which were marked or deleted by ICU
488             if( (nGlyphIndex == ICU_MARKED_GLYPH)
489             ||  (nGlyphIndex == ICU_DELETED_GLYPH) )
490                 continue;
491 
492             // adjust the relative char pos
493             int nCharPos = pCharIndices[i];
494             if( nCharPos >= 0 ) {
495                 nCharPos += nMinRunPos;
496                 // ICU seems to return bad pCharIndices
497                 // for some combinations of ICU+font+text
498                 // => better give up now than crash later
499                 if( nCharPos >= nEndRunPos )
500                     continue;
501             }
502 
503             // if needed request glyph fallback by updating LayoutArgs
504             if( !nGlyphIndex )
505             {
506                 if( nCharPos >= 0 )
507                 {
508                     rArgs.NeedFallback( nCharPos, bRightToLeft );
509                     if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) )
510                         rArgs.NeedFallback( nCharPos-1, bRightToLeft );
511                     else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) )
512                         rArgs.NeedFallback( nCharPos+1, bRightToLeft );
513                 }
514 
515                 if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
516                     continue;
517             }
518 
519 
520             // apply vertical flags, etc.
521 			bool bDiacritic = false;
522             if( nCharPos >= 0 )
523             {
524                 sal_UCS4 aChar = rArgs.mpStr[ nCharPos ];
525 #if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0
526                 if( (aChar >= 0xD800) && (aChar <= 0xDFFF) )
527                 {
528                     if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
529                         continue;
530                     // calculate unicode scalar value of surrogate pair
531                     aChar = 0x10000 + ((aChar - 0xD800) << 10);
532                     sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ];
533                     aChar += aLow & 0x03FF;
534                 }
535 #endif
536                 nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar );
537 
538                 // #i99367# HACK: try to detect all diacritics
539 				if( aChar>=0x0300 && aChar<0x2100 )
540 					bDiacritic = IsDiacritic( aChar );
541             }
542 
543             // get glyph position and its metrics
544             aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
545             const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
546             int nGlyphWidth = rGM.GetCharWidth();
547             int nNewWidth = nGlyphWidth;
548             if( nGlyphWidth <= 0 )
549                 bDiacritic |= true;
550             // #i99367# force all diacritics to zero width
551             // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth
552             else if( bDiacritic )
553                 nGlyphWidth = nNewWidth = 0;
554             else
555             {
556                 // Hack, find next +ve width glyph and calculate current
557                 // glyph width by substracting the two posituons
558                 const IcuPosition* pNextPos = pPos+1;
559                 for ( int j = i + 1; j <= nRawRunGlyphCount; ++j, ++pNextPos )
560                 {
561                     if ( j == nRawRunGlyphCount )
562                     {
563                         nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
564                         break;
565                     }
566 
567                     LEGlyphID nNextGlyphIndex = pIcuGlyphs[j];
568                     if( (nNextGlyphIndex == ICU_MARKED_GLYPH)
569                     ||  (nNextGlyphIndex == ICU_DELETED_GLYPH) )
570                         continue;
571 
572                     const GlyphMetric& rNextGM = rFont.GetGlyphMetric( nNextGlyphIndex );
573                     int nNextGlyphWidth = rNextGM.GetCharWidth();
574                     if ( nNextGlyphWidth > 0 )
575                     {
576                         nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
577                         break;
578                     }
579                 }
580             }
581 
582             // heuristic to detect glyph clusters
583 			bool bInCluster = true;
584             if( nLastCharPos == -1 )
585             {
586 				nClusterMinPos = nClusterMaxPos = nCharPos;
587 				bInCluster = false;
588             }
589             else if( !bRightToLeft )
590 			{
591 				// left-to-right case
592 				if( nClusterMinPos > nCharPos )
593 					nClusterMinPos = nCharPos;		// extend cluster
594 				else if( nCharPos <= nClusterMaxPos )
595 					/*NOTHING*/;					// inside cluster
596 				else if( bDiacritic )
597 					nClusterMaxPos = nCharPos;		// add diacritic to cluster
598 				else {
599 					nClusterMinPos = nClusterMaxPos = nCharPos;	// new cluster
600 					bInCluster = false;
601 				}
602 			}
603 			else
604 			{
605 				// right-to-left case
606 				if( nClusterMaxPos < nCharPos )
607 					nClusterMaxPos = nCharPos;		// extend cluster
608 				else if( nCharPos >= nClusterMinPos )
609 					/*NOTHING*/;					// inside cluster
610 				else if( bDiacritic )
611 				{
612 					nClusterMinPos = nCharPos;		// ICU often has [diacritic* baseglyph*]
613 					if( bClusterStart ) {
614 						nClusterMaxPos = nCharPos;
615 						bInCluster = false;
616 					}
617 				}
618 				else
619 				{
620 					nClusterMinPos = nClusterMaxPos = nCharPos;	// new cluster
621 					bInCluster = !bClusterStart;
622 				}
623             }
624 
625             long nGlyphFlags = 0;
626             if( bInCluster )
627                 nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
628             if( bRightToLeft )
629                 nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
630             if( bDiacritic )
631                 nGlyphFlags |= GlyphItem::IS_DIACRITIC;
632 
633             // add resulting glyph item to layout
634             GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
635             aGI.mnNewWidth = nNewWidth;
636             rLayout.AppendGlyph( aGI );
637             ++nFilteredRunGlyphCount;
638             nLastCharPos = nCharPos;
639             bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath
640         }
641         aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
642         nGlyphCount += nFilteredRunGlyphCount;
643     }
644 
645     // sort glyphs in visual order
646     // and then in logical order (e.g. diacritics after cluster start)
647     rLayout.SortGlyphItems();
648 
649     // determine need for kashida justification
650     if( (rArgs.mpDXArray || rArgs.mnLayoutWidth)
651     &&  ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) )
652         rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
653 
654     return true;
655 }
656 
657 #endif // ENABLE_ICU_LAYOUT
658 
659 // =======================================================================
660 
661 ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine()
662 {
663     // find best layout engine for font, platform, script and language
664 #ifdef ENABLE_ICU_LAYOUT
665     if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
666         mpLayoutEngine = new IcuLayoutEngine( *this );
667 #endif // ENABLE_ICU_LAYOUT
668 
669     return mpLayoutEngine;
670 }
671 
672 // =======================================================================
673 
674