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