Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <gcach_ftyp.hxx>
21 : #include <sallayout.hxx>
22 : #include <salgdi.hxx>
23 :
24 : #include <vcl/svapp.hxx>
25 :
26 : #include <sal/alloca.h>
27 : #include <rtl/instance.hxx>
28 :
29 : #include <layout/LayoutEngine.h>
30 : #include <layout/LEFontInstance.h>
31 : #include <layout/LEScripts.h>
32 :
33 : #include <unicode/uscript.h>
34 : #include <unicode/ubidi.h>
35 :
36 : // =======================================================================
37 : // layout implementation for ServerFont
38 : // =======================================================================
39 :
40 56398 : ServerFontLayout::ServerFontLayout( ServerFont& rFont )
41 56398 : : mrServerFont( rFont )
42 56398 : {}
43 :
44 7582 : void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
45 : {
46 7582 : rSalGraphics.DrawServerFontLayout( *this );
47 7582 : }
48 :
49 : // -----------------------------------------------------------------------
50 :
51 56398 : bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
52 : {
53 56398 : ServerFontLayoutEngine* pLE = mrServerFont.GetLayoutEngine();
54 : assert(pLE);
55 56398 : bool bRet = pLE ? pLE->layout(*this, rArgs) : false;
56 56398 : return bRet;
57 : }
58 :
59 : // -----------------------------------------------------------------------
60 :
61 58508 : void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
62 : {
63 58508 : GenericSalLayout::AdjustLayout( rArgs );
64 :
65 : // apply asian kerning if the glyphs are not already formatted
66 58508 : if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
67 0 : && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
68 0 : if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
69 0 : ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
70 :
71 : // insert kashidas where requested by the formatting array
72 58508 : if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
73 : {
74 0 : int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
75 0 : if( nKashidaIndex != 0 )
76 : {
77 0 : const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
78 0 : KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
79 : // TODO: kashida-GSUB/GPOS
80 : }
81 : }
82 58508 : }
83 :
84 : // =======================================================================
85 : // bridge to ICU LayoutEngine
86 : // =======================================================================
87 :
88 : using namespace U_ICU_NAMESPACE;
89 :
90 : static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF;
91 : static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE;
92 :
93 : // -----------------------------------------------------------------------
94 :
95 872 : class IcuFontFromServerFont
96 : : public LEFontInstance
97 : {
98 : private:
99 : ServerFont& mrServerFont;
100 :
101 : public:
102 872 : IcuFontFromServerFont( ServerFont& rFont )
103 872 : : mrServerFont( rFont )
104 872 : {}
105 :
106 : virtual const void* getFontTable(LETag tableTag) const;
107 : virtual le_int32 getUnitsPerEM() const;
108 : virtual float getXPixelsPerEm() const;
109 : virtual float getYPixelsPerEm() const;
110 : virtual float getScaleFactorX() const;
111 : virtual float getScaleFactorY() const;
112 :
113 : using LEFontInstance::mapCharToGlyph;
114 : virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const;
115 : virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth ) const;
116 :
117 : virtual le_int32 getAscent() const;
118 : virtual le_int32 getDescent() const;
119 : virtual le_int32 getLeading() const;
120 :
121 : virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const;
122 : virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const;
123 : };
124 :
125 : // -----------------------------------------------------------------------
126 :
127 3199 : const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const
128 : {
129 : char pTagName[5];
130 3199 : pTagName[0] = (char)(nICUTableTag >> 24);
131 3199 : pTagName[1] = (char)(nICUTableTag >> 16);
132 3199 : pTagName[2] = (char)(nICUTableTag >> 8);
133 3199 : pTagName[3] = (char)(nICUTableTag);
134 3199 : pTagName[4] = 0;
135 :
136 : sal_uLong nLength;
137 3199 : const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength );
138 : SAL_INFO("vcl", "IcuGetTable(\"" << pTagName << "\") => " << pBuffer);
139 : SAL_INFO(
140 : "vcl",
141 : "font( h=" << mrServerFont.GetFontSelData().mnHeight << ", \""
142 : << mrServerFont.GetFontFileName()->getStr() << "\" )");
143 3199 : return pBuffer;
144 : }
145 :
146 : // -----------------------------------------------------------------------
147 :
148 897140 : le_int32 IcuFontFromServerFont::getUnitsPerEM() const
149 : {
150 897140 : return mrServerFont.GetEmUnits();
151 : }
152 :
153 : // -----------------------------------------------------------------------
154 :
155 448570 : float IcuFontFromServerFont::getXPixelsPerEm() const
156 : {
157 448570 : const FontSelectPattern& r = mrServerFont.GetFontSelData();
158 448570 : float fX = r.mnWidth ? r.mnWidth : r.mnHeight;
159 448570 : return fX;
160 : }
161 :
162 : // -----------------------------------------------------------------------
163 :
164 448570 : float IcuFontFromServerFont::getYPixelsPerEm() const
165 : {
166 448570 : float fY = mrServerFont.GetFontSelData().mnHeight;
167 448570 : return fY;
168 : }
169 :
170 : // -----------------------------------------------------------------------
171 :
172 7189 : float IcuFontFromServerFont::getScaleFactorX() const
173 : {
174 7189 : return 1.0;
175 : }
176 :
177 : // -----------------------------------------------------------------------
178 :
179 7189 : float IcuFontFromServerFont::getScaleFactorY() const
180 : {
181 7189 : return 1.0;
182 : }
183 :
184 : // -----------------------------------------------------------------------
185 :
186 329840 : LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const
187 : {
188 329840 : LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch );
189 329840 : return nGlyphIndex;
190 : }
191 :
192 225346 : LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch, const LECharMapper *mapper, le_bool /*filterZeroWidth*/ ) const
193 : {
194 : /*
195 : fdo#31821, icu has...
196 : >│93 if (filterZeroWidth && (mappedChar == 0x200C || mappedChar == 0x200D)) { │
197 : │94 return canDisplay(mappedChar) ? 0x0001 : 0xFFFF; │
198 : │95 }
199 : so only the Indic layouts allow the joiners to get mapped to glyphs
200 : */
201 225346 : return LEFontInstance::mapCharToGlyph( ch, mapper, false );
202 : }
203 :
204 : // -----------------------------------------------------------------------
205 :
206 0 : le_int32 IcuFontFromServerFont::getAscent() const
207 : {
208 0 : const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
209 0 : le_int32 nAscent = (+rMetrics.ascender + 32) >> 6;
210 0 : return nAscent;
211 : }
212 :
213 : // -----------------------------------------------------------------------
214 :
215 0 : le_int32 IcuFontFromServerFont::getDescent() const
216 : {
217 0 : const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
218 0 : le_int32 nDescent = (-rMetrics.descender + 32) >> 6;
219 0 : return nDescent;
220 : }
221 :
222 : // -----------------------------------------------------------------------
223 :
224 0 : le_int32 IcuFontFromServerFont::getLeading() const
225 : {
226 0 : const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
227 0 : le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6;
228 0 : return nLeading;
229 : }
230 :
231 : // -----------------------------------------------------------------------
232 :
233 225346 : void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex,
234 : LEPoint &advance ) const
235 : {
236 225346 : if( (nGlyphIndex == ICU_MARKED_GLYPH)
237 : || (nGlyphIndex == ICU_DELETED_GLYPH) )
238 : {
239 : // deleted glyph or mark glyph has not advance
240 0 : advance.fX = 0;
241 : }
242 : else
243 : {
244 225346 : const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex );
245 225346 : advance.fX = rGM.GetCharWidth();
246 : }
247 :
248 225346 : advance.fY = 0;
249 225346 : }
250 :
251 : // -----------------------------------------------------------------------
252 :
253 220 : le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID,
254 : le_int32 pointNumber, LEPoint& ) const
255 : {
256 : //TODO: replace dummy implementation
257 : SAL_INFO("vcl", "getGlyphPoint(" << pointNumber << ")");
258 220 : return false;
259 : }
260 :
261 : // =======================================================================
262 :
263 : class IcuLayoutEngine : public ServerFontLayoutEngine
264 : {
265 : private:
266 : IcuFontFromServerFont maIcuFont;
267 :
268 : le_int32 meScriptCode;
269 : le_int32 mnLayoutFlags;
270 : LayoutEngine* mpIcuLE;
271 :
272 : public:
273 : IcuLayoutEngine( ServerFont& );
274 : virtual ~IcuLayoutEngine();
275 :
276 : virtual bool layout( ServerFontLayout&, ImplLayoutArgs& );
277 : };
278 :
279 : // -----------------------------------------------------------------------
280 :
281 872 : IcuLayoutEngine::IcuLayoutEngine( ServerFont& rServerFont )
282 : : maIcuFont( rServerFont ),
283 : meScriptCode( USCRIPT_INVALID_CODE ),
284 : mnLayoutFlags( 0 ),
285 872 : mpIcuLE( NULL )
286 872 : {}
287 :
288 : // -----------------------------------------------------------------------
289 :
290 2616 : IcuLayoutEngine::~IcuLayoutEngine()
291 : {
292 872 : delete mpIcuLE;
293 1744 : }
294 :
295 : // -----------------------------------------------------------------------
296 :
297 310 : static bool lcl_CharIsJoiner(sal_Unicode cChar)
298 : {
299 310 : return ((cChar == 0x200C) || (cChar == 0x200D));
300 : }
301 :
302 : //See https://bugs.freedesktop.org/show_bug.cgi?id=31016
303 : #define ARABIC_BANDAID
304 :
305 56398 : bool IcuLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
306 : {
307 56398 : le_int32 nLayoutFlags = 0;
308 : #if (U_ICU_VERSION_MAJOR_NUM > 4)
309 : if (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS)
310 : nLayoutFlags |= LayoutEngine::kTypoFlagKern;
311 : if (rArgs.mnFlags & SAL_LAYOUT_ENABLE_LIGATURES)
312 : nLayoutFlags |= LayoutEngine::kTypoFlagLiga;
313 : #else
314 56398 : if (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS)
315 903 : nLayoutFlags |= 0x01;
316 56398 : if (rArgs.mnFlags & SAL_LAYOUT_ENABLE_LIGATURES)
317 0 : nLayoutFlags |= 0x10;
318 : #endif
319 :
320 : LEUnicode* pIcuChars;
321 : if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) )
322 56398 : pIcuChars = (LEUnicode*)rArgs.mpStr;
323 : else
324 : {
325 : // this conversion will only be needed when either
326 : // ICU's or OOo's unicodes stop being unsigned shorts
327 : // TODO: watch out for surrogates!
328 : pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) );
329 : for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic )
330 : pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] );
331 : }
332 :
333 : // allocate temporary arrays, note: round to even
334 56398 : int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
335 :
336 56398 : rLayout.Reserve(nGlyphCapacity);
337 :
338 : struct IcuPosition{ float fX, fY; };
339 56398 : const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition);
340 56398 : LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) );
341 56398 : le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) );
342 56398 : IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) );
343 :
344 56398 : ServerFont& rFont = rLayout.GetServerFont();
345 :
346 56398 : UErrorCode rcI18n = U_ZERO_ERROR;
347 56398 : LEErrorCode rcIcu = LE_NO_ERROR;
348 56398 : Point aNewPos( 0, 0 );
349 112804 : for( int nGlyphCount = 0;; )
350 : {
351 : int nMinRunPos, nEndRunPos;
352 : bool bRightToLeft;
353 112804 : if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
354 : break;
355 :
356 : // find matching script
357 : // TODO: split up bidi run into script runs
358 56406 : le_int32 eScriptCode = -1;
359 280501 : for( int i = nMinRunPos; i < nEndRunPos; ++i )
360 : {
361 224951 : le_int32 eNextScriptCode = uscript_getScript( pIcuChars[i], &rcI18n );
362 224951 : if( (eNextScriptCode > USCRIPT_INHERITED) )
363 : {
364 136083 : eScriptCode = eNextScriptCode;
365 136083 : if (eNextScriptCode != latnScriptCode)
366 856 : break;
367 : }
368 : }
369 56406 : if( eScriptCode < 0 ) // TODO: handle errors better
370 38236 : eScriptCode = latnScriptCode;
371 :
372 : // get layout engine matching to this script and ligature/kerning combination
373 : // no engine change necessary if script is latin
374 56406 : if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) || (mnLayoutFlags != nLayoutFlags) )
375 : {
376 : // TODO: cache multiple layout engines when multiple scripts are used
377 1151 : delete mpIcuLE;
378 1151 : meScriptCode = eScriptCode;
379 1151 : mnLayoutFlags = nLayoutFlags;
380 1151 : le_int32 eLangCode = 0; // TODO: get better value
381 1151 : mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, nLayoutFlags, rcIcu );
382 1151 : if( LE_FAILURE(rcIcu) )
383 : {
384 0 : delete mpIcuLE;
385 0 : mpIcuLE = NULL;
386 : }
387 : }
388 :
389 : // fall back to default layout if needed
390 56406 : if( !mpIcuLE )
391 : break;
392 :
393 : // run ICU layout engine
394 : // TODO: get enough context, remove extra glyps below
395 : int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars,
396 : nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength,
397 56406 : bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu );
398 56406 : if( LE_FAILURE(rcIcu) )
399 0 : return false;
400 :
401 : // import layout info from icu
402 56406 : mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu );
403 56406 : mpIcuLE->getCharIndices( pCharIndices, rcIcu );
404 56406 : mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu );
405 56406 : mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed
406 56406 : if( LE_FAILURE(rcIcu) )
407 0 : return false;
408 :
409 : // layout bidi/script runs and export them to a ServerFontLayout
410 : // convert results to GlyphItems
411 56406 : int nLastCharPos = -1;
412 56406 : int nClusterMinPos = -1;
413 56406 : int nClusterMaxPos = -1;
414 56406 : bool bClusterStart = true;
415 56406 : int nFilteredRunGlyphCount = 0;
416 56406 : const IcuPosition* pPos = pGlyphPositions;
417 281752 : for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos )
418 : {
419 225346 : LEGlyphID nGlyphIndex = pIcuGlyphs[i];
420 : // ignore glyphs which were marked or deleted by ICU
421 225346 : if( (nGlyphIndex == ICU_MARKED_GLYPH)
422 : || (nGlyphIndex == ICU_DELETED_GLYPH) )
423 0 : continue;
424 :
425 : // adjust the relative char pos
426 225346 : int nCharPos = pCharIndices[i];
427 225346 : if( nCharPos >= 0 ) {
428 225346 : nCharPos += nMinRunPos;
429 : // ICU seems to return bad pCharIndices
430 : // for some combinations of ICU+font+text
431 : // => better give up now than crash later
432 225346 : if( nCharPos >= nEndRunPos )
433 0 : continue;
434 : }
435 :
436 : // if needed request glyph fallback by updating LayoutArgs
437 225346 : if( !nGlyphIndex )
438 : {
439 3419 : if( nCharPos >= 0 )
440 : {
441 3419 : rArgs.NeedFallback( nCharPos, bRightToLeft );
442 3419 : if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) )
443 0 : rArgs.NeedFallback( nCharPos-1, bRightToLeft );
444 3419 : else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) )
445 0 : rArgs.NeedFallback( nCharPos+1, bRightToLeft );
446 : }
447 :
448 3419 : if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
449 0 : continue;
450 : }
451 :
452 :
453 : // apply vertical flags, etc.
454 225346 : bool bDiacritic = false;
455 225346 : if( nCharPos >= 0 )
456 : {
457 225346 : sal_UCS4 aChar = rArgs.mpStr[ nCharPos ];
458 225346 : nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar );
459 :
460 : // #i99367# HACK: try to detect all diacritics
461 225346 : if( aChar>=0x0300 && aChar<0x2100 )
462 2705 : bDiacritic = IsDiacritic( aChar );
463 : }
464 :
465 : // get glyph position and its metrics
466 225346 : aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
467 225346 : const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
468 225346 : int nGlyphWidth = rGM.GetCharWidth();
469 225346 : int nNewWidth = nGlyphWidth;
470 225346 : if( nGlyphWidth <= 0 )
471 814 : bDiacritic |= true;
472 : // #i99367# force all diacritics to zero width
473 : // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth
474 224532 : else if( bDiacritic )
475 668 : nGlyphWidth = nNewWidth = 0;
476 : else
477 : {
478 : // Hack, find next +ve width glyph and calculate current
479 : // glyph width by substracting the two posituons
480 223864 : const IcuPosition* pNextPos = pPos+1;
481 223864 : for ( int j = i + 1; j <= nRawRunGlyphCount; ++j, ++pNextPos )
482 : {
483 223864 : if ( j == nRawRunGlyphCount )
484 : {
485 54924 : nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
486 54924 : break;
487 : }
488 :
489 168940 : LEGlyphID nNextGlyphIndex = pIcuGlyphs[j];
490 168940 : if( (nNextGlyphIndex == ICU_MARKED_GLYPH)
491 : || (nNextGlyphIndex == ICU_DELETED_GLYPH) )
492 0 : continue;
493 :
494 168940 : const GlyphMetric& rNextGM = rFont.GetGlyphMetric( nNextGlyphIndex );
495 168940 : int nNextGlyphWidth = rNextGM.GetCharWidth();
496 168940 : if ( nNextGlyphWidth > 0 )
497 : {
498 168940 : nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
499 168940 : break;
500 : }
501 : }
502 : }
503 :
504 : // heuristic to detect glyph clusters
505 225346 : bool bInCluster = true;
506 225346 : if( nLastCharPos == -1 )
507 : {
508 56406 : nClusterMinPos = nClusterMaxPos = nCharPos;
509 56406 : bInCluster = false;
510 : }
511 168940 : else if( !bRightToLeft )
512 : {
513 : // left-to-right case
514 168825 : if( nClusterMinPos > nCharPos )
515 0 : nClusterMinPos = nCharPos; // extend cluster
516 168825 : else if( nCharPos <= nClusterMaxPos )
517 : /*NOTHING*/; // inside cluster
518 168825 : else if( bDiacritic )
519 0 : nClusterMaxPos = nCharPos; // add diacritic to cluster
520 : else {
521 168825 : nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
522 168825 : bInCluster = false;
523 : }
524 : }
525 : else
526 : {
527 : // right-to-left case
528 115 : if( nClusterMaxPos < nCharPos )
529 0 : nClusterMaxPos = nCharPos; // extend cluster
530 115 : else if( nCharPos >= nClusterMinPos )
531 : /*NOTHING*/; // inside cluster
532 115 : else if( bDiacritic )
533 : {
534 0 : nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*]
535 0 : if( bClusterStart ) {
536 0 : nClusterMaxPos = nCharPos;
537 0 : bInCluster = false;
538 : }
539 : }
540 : else
541 : {
542 115 : nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
543 115 : bInCluster = !bClusterStart;
544 : }
545 : }
546 :
547 225346 : long nGlyphFlags = 0;
548 225346 : if( bInCluster )
549 0 : nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
550 225346 : if( bRightToLeft )
551 137 : nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
552 225346 : if( bDiacritic )
553 1482 : nGlyphFlags |= GlyphItem::IS_DIACRITIC;
554 :
555 : // add resulting glyph item to layout
556 225346 : GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
557 : #ifdef ARABIC_BANDAID
558 225346 : aGI.mnNewWidth = nNewWidth;
559 : #endif
560 225346 : rLayout.AppendGlyph( aGI );
561 225346 : ++nFilteredRunGlyphCount;
562 225346 : nLastCharPos = nCharPos;
563 225346 : bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath
564 : }
565 56406 : aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
566 56406 : nGlyphCount += nFilteredRunGlyphCount;
567 : }
568 :
569 : // sort glyphs in visual order
570 : // and then in logical order (e.g. diacritics after cluster start)
571 56398 : rLayout.SortGlyphItems();
572 :
573 : // determine need for kashida justification
574 56398 : if( (rArgs.mpDXArray || rArgs.mnLayoutWidth)
575 : && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) )
576 0 : rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
577 :
578 56398 : return true;
579 : }
580 :
581 : // =======================================================================
582 :
583 56398 : ServerFontLayoutEngine* ServerFont::GetLayoutEngine()
584 : {
585 : // find best layout engine for font, platform, script and language
586 56398 : if (!mpLayoutEngine)
587 872 : mpLayoutEngine = new IcuLayoutEngine(*this);
588 56398 : return mpLayoutEngine;
589 : }
590 :
591 : // =======================================================================
592 :
593 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|