update dev300-m57
[ooovba.git] / vcl / source / glyphs / gcach_layout.cxx
blob3e976a36fb20188d6f4b2206dc1286a7c2e45d9b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #define ENABLE_ICU_LAYOUT
32 #include <gcach_ftyp.hxx>
33 #include <vcl/sallayout.hxx>
34 #include <vcl/salgdi.hxx>
36 #include <unicode/uchar.h>
38 #include <vcl/svapp.hxx>
40 #include <sal/alloca.h>
42 #if OSL_DEBUG_LEVEL > 1
43 #include <cstdio>
44 #endif
45 #include <rtl/instance.hxx>
47 namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; }
49 // =======================================================================
50 // layout implementation for ServerFont
51 // =======================================================================
53 ServerFontLayout::ServerFontLayout( ServerFont& rFont )
54 : mrServerFont( rFont )
57 void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
59 rSalGraphics.DrawServerFontLayout( *this );
62 // -----------------------------------------------------------------------
64 bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
66 ServerFontLayoutEngine* pLE = NULL;
67 if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) )
68 pLE = mrServerFont.GetLayoutEngine();
69 if( !pLE )
70 pLE = &SimpleLayoutEngine::get();
72 bool bRet = (*pLE)( *this, rArgs );
73 return bRet;
76 // -----------------------------------------------------------------------
78 void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
80 GenericSalLayout::AdjustLayout( rArgs );
82 // apply asian kerning if the glyphs are not already formatted
83 if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
84 && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
85 if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
86 ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
88 // insert kashidas where requested by the formatting array
89 if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
91 int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
92 if( nKashidaIndex != 0 )
94 const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
95 KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
96 // TODO: kashida-GSUB/GPOS
101 // =======================================================================
103 bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
105 FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont());
107 Point aNewPos( 0, 0 );
108 int nOldGlyphId = -1;
109 int nGlyphWidth = 0;
110 GlyphItem aPrevItem;
111 bool bRightToLeft;
113 int nCharPos = -1;
114 bool hasNextPos = rArgs.GetNextPos( &nCharPos, &bRightToLeft );
115 bool isAfterEnd = false;
116 bool bFoundPrintable = false;
117 while ( hasNextPos || ( isAfterEnd && ( !bFoundPrintable || nCharPos < rArgs.mnLength ) ) )
119 sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
120 if( (cChar >= 0xD800) && (cChar <= 0xDFFF) )
122 if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
123 continue;
124 cChar = 0x10000 + ((cChar - 0xD800) << 10)
125 + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00);
128 if( bRightToLeft )
129 cChar = GetMirroredChar( cChar );
131 // Only handle the printable characters
132 if ( u_isprint( UChar32( cChar ) ) )
134 int nGlyphIndex = rFont.GetGlyphIndex( cChar );
135 // when glyph fallback is needed update LayoutArgs
136 if( !nGlyphIndex )
138 rArgs.NeedFallback( nCharPos, bRightToLeft );
139 if( cChar >= 0x10000 ) // handle surrogate pairs
140 rArgs.NeedFallback( nCharPos+1, bRightToLeft );
143 // apply pair kerning to prev glyph if requested
144 if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
146 int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, nGlyphIndex );
147 nGlyphWidth += nKernValue;
148 aPrevItem.mnNewWidth = nGlyphWidth;
151 // finish previous glyph
152 if( nOldGlyphId >= 0 )
154 rLayout.AppendGlyph( aPrevItem );
157 aNewPos.X() += nGlyphWidth;
159 // prepare GlyphItem for appending it in next round
160 if ( !isAfterEnd )
162 nOldGlyphId = nGlyphIndex;
163 const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
164 nGlyphWidth = rGM.GetCharWidth();
165 int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
167 aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
170 // No need to signal the printable chars before the end of the runs
171 bFoundPrintable = isAfterEnd;
174 if ( !isAfterEnd )
176 // Check if we have some more characters
177 // Get the next position
178 hasNextPos = rArgs.GetNextPos( &nCharPos, &bRightToLeft );
180 if ( !hasNextPos && nCharPos < rArgs.mnLength )
181 isAfterEnd = true;
183 else
185 nCharPos++;
186 if ( bFoundPrintable )
188 isAfterEnd = false;
189 nOldGlyphId = -1;
194 // append last glyph item if any
195 if( nOldGlyphId >= 0 )
196 rLayout.AppendGlyph( aPrevItem );
198 return true;
201 // =======================================================================
202 // bridge to ICU LayoutEngine
203 // =======================================================================
205 #ifdef ENABLE_ICU_LAYOUT
207 #define bool_t signed char
209 // disable warnings in icu layout headers
210 #if defined __SUNPRO_CC
211 #pragma disable_warn
212 #endif
214 #include <layout/LayoutEngine.h>
215 #include <layout/LEFontInstance.h>
216 #include <layout/LEScripts.h>
218 // enable warnings again
219 #if defined __SUNPRO_CC
220 #pragma enable_warn
221 #endif
223 #include <unicode/uscript.h>
224 #include <unicode/ubidi.h>
226 using namespace U_ICU_NAMESPACE;
228 static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF;
229 static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE;
231 // -----------------------------------------------------------------------
233 class IcuFontFromServerFont
234 : public LEFontInstance
236 private:
237 FreetypeServerFont& mrServerFont;
239 public:
240 IcuFontFromServerFont( FreetypeServerFont& rFont )
241 : mrServerFont( rFont )
244 virtual const void* getFontTable(LETag tableTag) const;
245 virtual le_int32 getUnitsPerEM() const;
246 virtual float getXPixelsPerEm() const;
247 virtual float getYPixelsPerEm() const;
248 virtual float getScaleFactorX() const;
249 virtual float getScaleFactorY() const;
251 using LEFontInstance::mapCharToGlyph;
252 virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const;
254 virtual le_int32 getAscent() const;
255 virtual le_int32 getDescent() const;
256 virtual le_int32 getLeading() const;
258 virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const;
259 virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const;
262 // -----------------------------------------------------------------------
264 const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const
266 char pTagName[5];
267 pTagName[0] = (char)(nICUTableTag >> 24);
268 pTagName[1] = (char)(nICUTableTag >> 16);
269 pTagName[2] = (char)(nICUTableTag >> 8);
270 pTagName[3] = (char)(nICUTableTag);
271 pTagName[4] = 0;
273 ULONG nLength;
274 const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength );
275 #ifdef VERBOSE_DEBUG
276 fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer);
277 int mnHeight = mrServerFont.GetFontSelData().mnHeight;
278 const char* pName = mrServerFont.GetFontFileName()->getStr();
279 fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName );
280 #endif
281 return (const void*)pBuffer;
284 // -----------------------------------------------------------------------
286 le_int32 IcuFontFromServerFont::getUnitsPerEM() const
288 return mrServerFont.GetEmUnits();
291 // -----------------------------------------------------------------------
293 float IcuFontFromServerFont::getXPixelsPerEm() const
295 const ImplFontSelectData& r = mrServerFont.GetFontSelData();
296 float fX = r.mnWidth ? r.mnWidth : r.mnHeight;
297 return fX;
300 // -----------------------------------------------------------------------
302 float IcuFontFromServerFont::getYPixelsPerEm() const
304 float fY = mrServerFont.GetFontSelData().mnHeight;
305 return fY;
308 // -----------------------------------------------------------------------
310 float IcuFontFromServerFont::getScaleFactorX() const
312 return 1.0;
315 // -----------------------------------------------------------------------
317 float IcuFontFromServerFont::getScaleFactorY() const
319 return 1.0;
322 // -----------------------------------------------------------------------
324 LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const
326 LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch );
327 return nGlyphIndex;
330 // -----------------------------------------------------------------------
332 le_int32 IcuFontFromServerFont::getAscent() const
334 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
335 le_int32 nAscent = (+rMetrics.ascender + 32) >> 6;
336 return nAscent;
339 // -----------------------------------------------------------------------
341 le_int32 IcuFontFromServerFont::getDescent() const
343 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
344 le_int32 nDescent = (-rMetrics.descender + 32) >> 6;
345 return nDescent;
348 // -----------------------------------------------------------------------
350 le_int32 IcuFontFromServerFont::getLeading() const
352 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
353 le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6;
354 return nLeading;
357 // -----------------------------------------------------------------------
359 void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex,
360 LEPoint &advance ) const
362 if( (nGlyphIndex == ICU_MARKED_GLYPH)
363 || (nGlyphIndex == ICU_DELETED_GLYPH) )
365 // deleted glyph or mark glyph has not advance
366 advance.fX = 0;
368 else
370 const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex );
371 advance.fX = rGM.GetCharWidth();
374 advance.fY = 0;
377 // -----------------------------------------------------------------------
379 le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID,
380 le_int32
381 #if OSL_DEBUG_LEVEL > 1
382 pointNumber
383 #endif
385 LEPoint& ) const
387 //TODO: replace dummy implementation
388 #if OSL_DEBUG_LEVEL > 1
389 fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber );
390 #endif
391 return false;
394 // =======================================================================
396 class IcuLayoutEngine : public ServerFontLayoutEngine
398 private:
399 IcuFontFromServerFont maIcuFont;
401 le_int32 meScriptCode;
402 LayoutEngine* mpIcuLE;
404 public:
405 IcuLayoutEngine( FreetypeServerFont& );
406 virtual ~IcuLayoutEngine();
408 virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& );
411 // -----------------------------------------------------------------------
413 IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont )
414 : maIcuFont( rServerFont ),
415 meScriptCode( USCRIPT_INVALID_CODE ),
416 mpIcuLE( NULL )
419 // -----------------------------------------------------------------------
421 IcuLayoutEngine::~IcuLayoutEngine()
423 if( mpIcuLE )
424 delete mpIcuLE;
427 // -----------------------------------------------------------------------
429 static bool lcl_CharIsJoiner(sal_Unicode cChar)
431 return ((cChar == 0x200C) || (cChar == 0x200D));
434 bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
436 LEUnicode* pIcuChars;
437 if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) )
438 pIcuChars = (LEUnicode*)rArgs.mpStr;
439 else
441 // this conversion will only be needed when either
442 // ICU's or OOo's unicodes stop being unsigned shorts
443 // TODO: watch out for surrogates!
444 pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) );
445 for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic )
446 pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] );
449 // allocate temporary arrays, note: round to even
450 int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
452 struct IcuPosition{ float fX, fY; };
453 const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition);
454 LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) );
455 le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) );
456 IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) );
458 FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont());
460 UErrorCode rcI18n = U_ZERO_ERROR;
461 LEErrorCode rcIcu = LE_NO_ERROR;
462 Point aNewPos( 0, 0 );
463 for( int nGlyphCount = 0;; )
465 int nMinRunPos, nEndRunPos;
466 bool bRightToLeft;
467 if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
468 break;
470 // find matching script
471 // TODO: split up bidi run into script runs
472 le_int32 eScriptCode = -1;
473 for( int i = nMinRunPos; i < nEndRunPos; ++i )
475 eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n );
476 if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) )
477 break;
479 if( eScriptCode < 0 ) // TODO: handle errors better
480 eScriptCode = latnScriptCode;
482 // get layout engine matching to this script
483 // no engine change necessary if script is latin
484 if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) )
486 // TODO: cache multiple layout engines when multiple scripts are used
487 delete mpIcuLE;
488 meScriptCode = eScriptCode;
489 le_int32 eLangCode = 0; // TODO: get better value
490 mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu );
491 if( LE_FAILURE(rcIcu) )
493 delete mpIcuLE;
494 mpIcuLE = NULL;
498 // fall back to default layout if needed
499 if( !mpIcuLE )
500 break;
502 // run ICU layout engine
503 // TODO: get enough context, remove extra glyps below
504 int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars,
505 nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength,
506 bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu );
507 if( LE_FAILURE(rcIcu) )
508 return false;
510 // import layout info from icu
511 mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu );
512 mpIcuLE->getCharIndices( pCharIndices, rcIcu );
513 mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu );
514 mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed
515 if( LE_FAILURE(rcIcu) )
516 return false;
518 // layout bidi/script runs and export them to a ServerFontLayout
519 // convert results to GlyphItems
520 int nLastCharPos = -1;
521 int nClusterMinPos = -1;
522 int nClusterMaxPos = -1;
523 bool bClusterStart = true;
524 int nFilteredRunGlyphCount = 0;
525 const IcuPosition* pPos = pGlyphPositions;
526 for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos )
528 LEGlyphID nGlyphIndex = pIcuGlyphs[i];
529 // ignore glyphs which were marked or deleted by ICU
530 if( (nGlyphIndex == ICU_MARKED_GLYPH)
531 || (nGlyphIndex == ICU_DELETED_GLYPH) )
532 continue;
534 // adjust the relative char pos
535 int nCharPos = pCharIndices[i];
536 if( nCharPos >= 0 ) {
537 nCharPos += nMinRunPos;
538 // ICU seems to return bad pCharIndices
539 // for some combinations of ICU+font+text
540 // => better give up now than crash later
541 if( nCharPos >= nEndRunPos )
542 continue;
545 // if needed request glyph fallback by updating LayoutArgs
546 if( !nGlyphIndex )
548 if( nCharPos >= 0 )
550 rArgs.NeedFallback( nCharPos, bRightToLeft );
551 if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) )
552 rArgs.NeedFallback( nCharPos-1, bRightToLeft );
553 else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) )
554 rArgs.NeedFallback( nCharPos+1, bRightToLeft );
557 if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
558 continue;
562 // apply vertical flags, etc.
563 bool bDiacritic = false;
564 if( nCharPos >= 0 )
566 sal_UCS4 aChar = rArgs.mpStr[ nCharPos ];
567 #if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0
568 if( (aChar >= 0xD800) && (aChar <= 0xDFFF) )
570 if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
571 continue;
572 // calculate unicode scalar value of surrogate pair
573 aChar = 0x10000 + ((aChar - 0xD800) << 10);
574 sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ];
575 aChar += aLow & 0x03FF;
577 #endif
578 nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar );
580 // #i99367# HACK: try to detect all diacritics
581 if( aChar>=0x0300 && aChar<0x2100 )
582 bDiacritic = IsDiacritic( aChar );
585 // get glyph position and its metrics
586 aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
587 const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
588 int nGlyphWidth = rGM.GetCharWidth();
589 if( nGlyphWidth <= 0 )
590 bDiacritic |= true;
591 // #i99367# force all diacritics to zero width
592 // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth
593 else if( bDiacritic )
594 nGlyphWidth = 0;
596 // heuristic to detect glyph clusters
597 bool bInCluster = true;
598 if( nLastCharPos == -1 )
600 nClusterMinPos = nClusterMaxPos = nCharPos;
601 bInCluster = false;
603 else if( !bRightToLeft )
605 // left-to-right case
606 if( nClusterMinPos > nCharPos )
607 nClusterMinPos = nCharPos; // extend cluster
608 else if( nCharPos <= nClusterMaxPos )
609 /*NOTHING*/; // inside cluster
610 else if( bDiacritic )
611 nClusterMaxPos = nCharPos; // add diacritic to cluster
612 else {
613 nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
614 bInCluster = false;
617 else
619 // right-to-left case
620 if( nClusterMaxPos < nCharPos )
621 nClusterMaxPos = nCharPos; // extend cluster
622 else if( nCharPos >= nClusterMinPos )
623 /*NOTHING*/; // inside cluster
624 else if( bDiacritic )
626 nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*]
627 if( bClusterStart ) {
628 nClusterMaxPos = nCharPos;
629 bInCluster = false;
632 else
634 nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
635 bInCluster = !bClusterStart;
639 long nGlyphFlags = 0;
640 if( bInCluster )
641 nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
642 if( bRightToLeft )
643 nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
644 if( bDiacritic )
645 nGlyphFlags |= GlyphItem::IS_DIACRITIC;
647 // add resulting glyph item to layout
648 const GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
649 rLayout.AppendGlyph( aGI );
650 ++nFilteredRunGlyphCount;
651 nLastCharPos = nCharPos;
652 bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath
654 aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
655 nGlyphCount += nFilteredRunGlyphCount;
658 // sort glyphs in visual order
659 // and then in logical order (e.g. diacritics after cluster start)
660 rLayout.SortGlyphItems();
662 // determine need for kashida justification
663 if( (rArgs.mpDXArray || rArgs.mnLayoutWidth)
664 && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) )
665 rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
667 return true;
670 #endif // ENABLE_ICU_LAYOUT
672 // =======================================================================
674 ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine()
676 // find best layout engine for font, platform, script and language
677 #ifdef ENABLE_ICU_LAYOUT
678 if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
679 mpLayoutEngine = new IcuLayoutEngine( *this );
680 #endif // ENABLE_ICU_LAYOUT
682 return mpLayoutEngine;
685 // =======================================================================