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