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