xref: /aoo41x/main/vcl/os2/source/gdi/os2layout.cxx (revision cdf0e10c)
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 #include <tools/svwin.h>
29*cdf0e10cSrcweir 
30*cdf0e10cSrcweir #include <rtl/ustring.hxx>
31*cdf0e10cSrcweir #include <osl/module.h>
32*cdf0e10cSrcweir #include <salgdi.h>
33*cdf0e10cSrcweir #include <saldata.hxx>
34*cdf0e10cSrcweir #include <vcl/sallayout.hxx>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #ifndef __H_FT2LIB
37*cdf0e10cSrcweir #include <wingdi.h>
38*cdf0e10cSrcweir #include <ft2lib.h>
39*cdf0e10cSrcweir #endif
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir #include <cstdio>
42*cdf0e10cSrcweir #include <malloc.h>
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
45*cdf0e10cSrcweir     #include <algorithm>
46*cdf0e10cSrcweir #endif // GCP_KERN_HACK
47*cdf0e10cSrcweir 
48*cdf0e10cSrcweir // for GetMirroredChar
49*cdf0e10cSrcweir #include <vcl/svapp.hxx>
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir #include <hash_map>
52*cdf0e10cSrcweir typedef std::hash_map<int,int> IntMap;
53*cdf0e10cSrcweir 
54*cdf0e10cSrcweir #define DROPPED_OUTGLYPH 0xFFFF
55*cdf0e10cSrcweir 
56*cdf0e10cSrcweir using namespace rtl;
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir // =======================================================================
59*cdf0e10cSrcweir 
60*cdf0e10cSrcweir // OS/2 specific physical font instance
61*cdf0e10cSrcweir class ImplOs2FontEntry : public ImplFontEntry
62*cdf0e10cSrcweir {
63*cdf0e10cSrcweir public:
64*cdf0e10cSrcweir 	ImplOs2FontEntry( ImplFontSelectData& );
65*cdf0e10cSrcweir 	~ImplOs2FontEntry();
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir private:
68*cdf0e10cSrcweir     // TODO: also add HFONT??? Watch out for issues with too many active fonts...
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
71*cdf0e10cSrcweir public:
72*cdf0e10cSrcweir     bool                    HasKernData() const;
73*cdf0e10cSrcweir     void                    SetKernData( int, const KERNINGPAIRS* );
74*cdf0e10cSrcweir     int                     GetKerning( sal_Unicode, sal_Unicode ) const;
75*cdf0e10cSrcweir private:
76*cdf0e10cSrcweir     KERNINGPAIRS*        	mpKerningPairs;
77*cdf0e10cSrcweir     int                     mnKerningPairs;
78*cdf0e10cSrcweir #endif // GCP_KERN_HACK
79*cdf0e10cSrcweir 
80*cdf0e10cSrcweir public:
81*cdf0e10cSrcweir     int                     GetCachedGlyphWidth( int nCharCode ) const;
82*cdf0e10cSrcweir     void                    CacheGlyphWidth( int nCharCode, int nCharWidth );
83*cdf0e10cSrcweir private:
84*cdf0e10cSrcweir     IntMap                  maWidthMap;
85*cdf0e10cSrcweir };
86*cdf0e10cSrcweir 
87*cdf0e10cSrcweir // -----------------------------------------------------------------------
88*cdf0e10cSrcweir 
89*cdf0e10cSrcweir inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
90*cdf0e10cSrcweir {
91*cdf0e10cSrcweir     maWidthMap[ nCharCode ] = nCharWidth;
92*cdf0e10cSrcweir }
93*cdf0e10cSrcweir 
94*cdf0e10cSrcweir inline int ImplOs2FontEntry::GetCachedGlyphWidth( int nCharCode ) const
95*cdf0e10cSrcweir {
96*cdf0e10cSrcweir     IntMap::const_iterator it = maWidthMap.find( nCharCode );
97*cdf0e10cSrcweir     if( it == maWidthMap.end() )
98*cdf0e10cSrcweir         return -1;
99*cdf0e10cSrcweir     return it->second;
100*cdf0e10cSrcweir }
101*cdf0e10cSrcweir 
102*cdf0e10cSrcweir // =======================================================================
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir class Os2Layout : public SalLayout
105*cdf0e10cSrcweir {
106*cdf0e10cSrcweir public:
107*cdf0e10cSrcweir                         Os2Layout( HDC, const ImplOs2FontData&, ImplOs2FontEntry& );
108*cdf0e10cSrcweir     virtual void        InitFont() const;
109*cdf0e10cSrcweir     void                SetFontScale( float f ) { mfFontScale = f; }
110*cdf0e10cSrcweir     float               GetFontScale() const    { return mfFontScale; }
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir protected:
113*cdf0e10cSrcweir 	HPS					mhPS;				// OS2 device handle
114*cdf0e10cSrcweir 	FATTRS   			mhFont;
115*cdf0e10cSrcweir     int                 mnBaseAdv;          // x-offset relative to Layout origin
116*cdf0e10cSrcweir     float               mfFontScale;        // allows metrics emulation of huge font sizes
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir     const ImplOs2FontData&    mrOs2FontData;
119*cdf0e10cSrcweir     ImplOs2FontEntry&   mrOs2FontEntry;
120*cdf0e10cSrcweir };
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir // =======================================================================
123*cdf0e10cSrcweir 
124*cdf0e10cSrcweir class Os2SalLayout : public Os2Layout
125*cdf0e10cSrcweir {
126*cdf0e10cSrcweir public:
127*cdf0e10cSrcweir                     Os2SalLayout( HPS, BYTE nCharSet, const ImplOs2FontData&, ImplOs2FontEntry& );
128*cdf0e10cSrcweir     virtual         ~Os2SalLayout();
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir     virtual bool    LayoutText( ImplLayoutArgs& );
131*cdf0e10cSrcweir     virtual void    AdjustLayout( ImplLayoutArgs& );
132*cdf0e10cSrcweir     virtual void    DrawText( SalGraphics& ) const;
133*cdf0e10cSrcweir 
134*cdf0e10cSrcweir     virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
135*cdf0e10cSrcweir                         sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir     virtual long    FillDXArray( long* pDXArray ) const;
138*cdf0e10cSrcweir     virtual int     GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
139*cdf0e10cSrcweir     virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
140*cdf0e10cSrcweir 
141*cdf0e10cSrcweir     // for glyph+font+script fallback
142*cdf0e10cSrcweir     virtual void    MoveGlyph( int nStart, long nNewXPos );
143*cdf0e10cSrcweir     virtual void    DropGlyph( int nStart );
144*cdf0e10cSrcweir     virtual void    Simplify( bool bIsBase );
145*cdf0e10cSrcweir 
146*cdf0e10cSrcweir protected:
147*cdf0e10cSrcweir     void            Justify( long nNewWidth );
148*cdf0e10cSrcweir     void            ApplyDXArray( const ImplLayoutArgs& );
149*cdf0e10cSrcweir 
150*cdf0e10cSrcweir protected:
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir private:
153*cdf0e10cSrcweir     int             mnGlyphCount;
154*cdf0e10cSrcweir     int             mnCharCount;
155*cdf0e10cSrcweir     sal_Unicode*    mpOutGlyphs;
156*cdf0e10cSrcweir     int*            mpGlyphAdvances;    // if possible this is shared with mpGlyphAdvances[]
157*cdf0e10cSrcweir     int*            mpGlyphOrigAdvs;
158*cdf0e10cSrcweir     int*            mpCharWidths;       // map rel char pos to char width
159*cdf0e10cSrcweir     int*            mpChars2Glyphs;     // map rel char pos to abs glyph pos
160*cdf0e10cSrcweir     int*            mpGlyphs2Chars;     // map abs glyph pos to abs char pos
161*cdf0e10cSrcweir     bool*           mpGlyphRTLFlags;    // BiDi status for glyphs: true=>RTL
162*cdf0e10cSrcweir     mutable long    mnWidth;
163*cdf0e10cSrcweir     bool            mbDisableGlyphs;
164*cdf0e10cSrcweir 
165*cdf0e10cSrcweir     int             mnNotdefWidth;
166*cdf0e10cSrcweir     BYTE            mnCharSet;
167*cdf0e10cSrcweir 
168*cdf0e10cSrcweir };
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir // =======================================================================
171*cdf0e10cSrcweir 
172*cdf0e10cSrcweir Os2Layout::Os2Layout( HPS hPS, const ImplOs2FontData& rWFD, ImplOs2FontEntry& rWFE )
173*cdf0e10cSrcweir :   mhPS( hPS ),
174*cdf0e10cSrcweir     mnBaseAdv( 0 ),
175*cdf0e10cSrcweir     mfFontScale( 1.0 ),
176*cdf0e10cSrcweir     mrOs2FontData( rWFD ),
177*cdf0e10cSrcweir     mrOs2FontEntry( rWFE )
178*cdf0e10cSrcweir {
179*cdf0e10cSrcweir 	BOOL fSuccess;
180*cdf0e10cSrcweir 	fSuccess = Ft2QueryLogicalFont( mhPS, LCID_BASE, NULL, &mhFont, sizeof(FATTRS));
181*cdf0e10cSrcweir }
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir // -----------------------------------------------------------------------
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir void Os2Layout::InitFont() const
186*cdf0e10cSrcweir {
187*cdf0e10cSrcweir 	// select fallback level 0 font
188*cdf0e10cSrcweir 	APIRET rc = Ft2CreateLogFont( mhPS, NULL, LCID_BASE, (PFATTRS)&mhFont);
189*cdf0e10cSrcweir }
190*cdf0e10cSrcweir 
191*cdf0e10cSrcweir // =======================================================================
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir Os2SalLayout::Os2SalLayout( HPS hPS, BYTE nCharSet,
194*cdf0e10cSrcweir     const ImplOs2FontData& rOs2FontData, ImplOs2FontEntry& rOs2FontEntry )
195*cdf0e10cSrcweir :   Os2Layout( hPS, rOs2FontData, rOs2FontEntry ),
196*cdf0e10cSrcweir     mnGlyphCount( 0 ),
197*cdf0e10cSrcweir     mnCharCount( 0 ),
198*cdf0e10cSrcweir     mpOutGlyphs( NULL ),
199*cdf0e10cSrcweir     mpGlyphAdvances( NULL ),
200*cdf0e10cSrcweir     mpGlyphOrigAdvs( NULL ),
201*cdf0e10cSrcweir     mpCharWidths( NULL ),
202*cdf0e10cSrcweir     mpChars2Glyphs( NULL ),
203*cdf0e10cSrcweir     mpGlyphs2Chars( NULL ),
204*cdf0e10cSrcweir     mpGlyphRTLFlags( NULL ),
205*cdf0e10cSrcweir     mnWidth( 0 ),
206*cdf0e10cSrcweir     mnNotdefWidth( -1 ),
207*cdf0e10cSrcweir     mnCharSet( nCharSet ),
208*cdf0e10cSrcweir     mbDisableGlyphs( false )
209*cdf0e10cSrcweir {
210*cdf0e10cSrcweir     mbDisableGlyphs = true;
211*cdf0e10cSrcweir }
212*cdf0e10cSrcweir 
213*cdf0e10cSrcweir // -----------------------------------------------------------------------
214*cdf0e10cSrcweir 
215*cdf0e10cSrcweir Os2SalLayout::~Os2SalLayout()
216*cdf0e10cSrcweir {
217*cdf0e10cSrcweir     delete[] mpGlyphRTLFlags;
218*cdf0e10cSrcweir     delete[] mpGlyphs2Chars;
219*cdf0e10cSrcweir     delete[] mpChars2Glyphs;
220*cdf0e10cSrcweir     if( mpCharWidths != mpGlyphAdvances )
221*cdf0e10cSrcweir         delete[] mpCharWidths;
222*cdf0e10cSrcweir     delete[] mpGlyphOrigAdvs;
223*cdf0e10cSrcweir     delete[] mpGlyphAdvances;
224*cdf0e10cSrcweir     delete[] mpOutGlyphs;
225*cdf0e10cSrcweir }
226*cdf0e10cSrcweir 
227*cdf0e10cSrcweir // -----------------------------------------------------------------------
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir bool Os2SalLayout::LayoutText( ImplLayoutArgs& rArgs )
230*cdf0e10cSrcweir {
231*cdf0e10cSrcweir     // prepare layout
232*cdf0e10cSrcweir     // TODO: fix case when recyclying old Os2SalLayout object
233*cdf0e10cSrcweir     mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
234*cdf0e10cSrcweir     mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
235*cdf0e10cSrcweir 
236*cdf0e10cSrcweir     if( !mbDisableGlyphs )
237*cdf0e10cSrcweir     {
238*cdf0e10cSrcweir         // Win32 glyph APIs have serious problems with vertical layout
239*cdf0e10cSrcweir         // => workaround is to use the unicode methods then
240*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
241*cdf0e10cSrcweir             mbDisableGlyphs = true;
242*cdf0e10cSrcweir         else
243*cdf0e10cSrcweir             // use cached value from font face
244*cdf0e10cSrcweir             mbDisableGlyphs = mrOs2FontData.IsGlyphApiDisabled();
245*cdf0e10cSrcweir     }
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir     // TODO: use a cached value for bDisableAsianKern from upper layers
248*cdf0e10cSrcweir #if 0
249*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
250*cdf0e10cSrcweir     {
251*cdf0e10cSrcweir         TEXTMETRICA aTextMetricA;
252*cdf0e10cSrcweir         if( ::GetTextMetricsA( mhDC, &aTextMetricA )
253*cdf0e10cSrcweir         && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) )
254*cdf0e10cSrcweir             rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
255*cdf0e10cSrcweir     }
256*cdf0e10cSrcweir #endif
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir     // layout text
259*cdf0e10cSrcweir     int i, j;
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir     mnGlyphCount = 0;
262*cdf0e10cSrcweir     bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
263*cdf0e10cSrcweir 
264*cdf0e10cSrcweir     // count the number of chars to process if no RTL run
265*cdf0e10cSrcweir     rArgs.ResetPos();
266*cdf0e10cSrcweir     bool bHasRTL = false;
267*cdf0e10cSrcweir     while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
268*cdf0e10cSrcweir         mnGlyphCount += j - i;
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir     // if there are RTL runs we need room to remember individual BiDi flags
271*cdf0e10cSrcweir     if( bHasRTL )
272*cdf0e10cSrcweir     {
273*cdf0e10cSrcweir         mpGlyphRTLFlags = new bool[ mnCharCount ];
274*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
275*cdf0e10cSrcweir             mpGlyphRTLFlags[i] = false;
276*cdf0e10cSrcweir     }
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir     // rewrite the logical string if needed to prepare for the API calls
279*cdf0e10cSrcweir     const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
280*cdf0e10cSrcweir     if( (mnGlyphCount != mnCharCount) || bVertical )
281*cdf0e10cSrcweir     {
282*cdf0e10cSrcweir         // we need to rewrite the pBidiStr when any of
283*cdf0e10cSrcweir         // - BiDirectional layout
284*cdf0e10cSrcweir         // - vertical layout
285*cdf0e10cSrcweir         // - partial runs (e.g. with control chars or for glyph fallback)
286*cdf0e10cSrcweir         // are involved
287*cdf0e10cSrcweir         sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
288*cdf0e10cSrcweir         pBidiStr = pRewrittenStr;
289*cdf0e10cSrcweir 
290*cdf0e10cSrcweir         // note: glyph to char mapping is relative to first character
291*cdf0e10cSrcweir         mpChars2Glyphs = new int[ mnCharCount ];
292*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnCharCount ];
293*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
294*cdf0e10cSrcweir             mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir         mnGlyphCount = 0;
297*cdf0e10cSrcweir         rArgs.ResetPos();
298*cdf0e10cSrcweir         bool bIsRTL = false;
299*cdf0e10cSrcweir         while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
300*cdf0e10cSrcweir         {
301*cdf0e10cSrcweir             do
302*cdf0e10cSrcweir             {
303*cdf0e10cSrcweir                 // get the next leftmost character in this run
304*cdf0e10cSrcweir                 int nCharPos = bIsRTL ? --j : i++;
305*cdf0e10cSrcweir                 sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir                 // in the RTL case mirror the character and remember its RTL status
308*cdf0e10cSrcweir                 if( bIsRTL )
309*cdf0e10cSrcweir                 {
310*cdf0e10cSrcweir                     cChar = ::GetMirroredChar( cChar );
311*cdf0e10cSrcweir                     mpGlyphRTLFlags[ mnGlyphCount ] = true;
312*cdf0e10cSrcweir                 }
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir                 // for vertical writing use vertical alternatives
315*cdf0e10cSrcweir                 if( bVertical )
316*cdf0e10cSrcweir                 {
317*cdf0e10cSrcweir                     sal_Unicode cVert = ::GetVerticalChar( cChar );
318*cdf0e10cSrcweir                     if( cVert )
319*cdf0e10cSrcweir                         cChar = cVert;
320*cdf0e10cSrcweir                 }
321*cdf0e10cSrcweir 
322*cdf0e10cSrcweir                 // rewrite the original string
323*cdf0e10cSrcweir                 // update the mappings between original and rewritten string
324*cdf0e10cSrcweir                 pRewrittenStr[ mnGlyphCount ] = cChar;
325*cdf0e10cSrcweir                 mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
326*cdf0e10cSrcweir                 mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
327*cdf0e10cSrcweir                 ++mnGlyphCount;
328*cdf0e10cSrcweir             } while( i < j );
329*cdf0e10cSrcweir         }
330*cdf0e10cSrcweir     }
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir     mpOutGlyphs     = new sal_Unicode[ mnGlyphCount ];
333*cdf0e10cSrcweir     mpGlyphAdvances = new int[ mnGlyphCount ];
334*cdf0e10cSrcweir 
335*cdf0e10cSrcweir     if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
336*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir #ifndef GCP_KERN_HACK
339*cdf0e10cSrcweir     DWORD nGcpOption = 0;
340*cdf0e10cSrcweir     // enable kerning if requested
341*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
342*cdf0e10cSrcweir         nGcpOption |= GCP_USEKERNING;
343*cdf0e10cSrcweir #endif // GCP_KERN_HACK
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir 	LONG	lLcid = Ft2QueryCharSet( mhPS);
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
348*cdf0e10cSrcweir         mpOutGlyphs[i] = pBidiStr[ i ];
349*cdf0e10cSrcweir     mnWidth = 0;
350*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
351*cdf0e10cSrcweir     {
352*cdf0e10cSrcweir         const sal_Unicode* pCodes = &pBidiStr[i];
353*cdf0e10cSrcweir         // check for surrogate pairs
354*cdf0e10cSrcweir         if( (pCodes[0] & 0xFC00) == 0xDC00 )
355*cdf0e10cSrcweir             continue;
356*cdf0e10cSrcweir         bool bSurrogate = ((pCodes[0] & 0xFC00) == 0xD800);
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir         // get the width of the corresponding code point
359*cdf0e10cSrcweir         int nCharCode = pCodes[0];
360*cdf0e10cSrcweir         if( bSurrogate )
361*cdf0e10cSrcweir             nCharCode = 0x10000 + ((pCodes[0] & 0x03FF) << 10) + (pCodes[1] & 0x03FF);
362*cdf0e10cSrcweir         int nGlyphWidth = mrOs2FontEntry.GetCachedGlyphWidth( nCharCode );
363*cdf0e10cSrcweir         if( nGlyphWidth == -1 )
364*cdf0e10cSrcweir         {
365*cdf0e10cSrcweir 			if (!Ft2QueryStringWidthW( mhPS, (LPWSTR)&pCodes[0], 1, (LONG*)&nGlyphWidth))
366*cdf0e10cSrcweir 				nGlyphWidth = 0;
367*cdf0e10cSrcweir             mrOs2FontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
368*cdf0e10cSrcweir         }
369*cdf0e10cSrcweir         mpGlyphAdvances[ i ] = nGlyphWidth;
370*cdf0e10cSrcweir         mnWidth += nGlyphWidth;
371*cdf0e10cSrcweir 
372*cdf0e10cSrcweir         // remaining codes of surrogate pair get a zero width
373*cdf0e10cSrcweir         if( bSurrogate )
374*cdf0e10cSrcweir             mpGlyphAdvances[ i+1 ] = 0;
375*cdf0e10cSrcweir 
376*cdf0e10cSrcweir         // check with the font face if glyph fallback is needed
377*cdf0e10cSrcweir         if( mrOs2FontData.HasChar( nCharCode ) )
378*cdf0e10cSrcweir             continue;
379*cdf0e10cSrcweir 		// Type1 charmaps are not complete (or buggy), use FT2 to check again
380*cdf0e10cSrcweir 		if (Ft2FontSupportsUnicodeChar( mhPS, lLcid, TRUE, nCharCode))
381*cdf0e10cSrcweir 			continue;
382*cdf0e10cSrcweir 
383*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0
384*cdf0e10cSrcweir 		debug_printf("Os2SalLayout::LayoutText font does not support unicode char\n");
385*cdf0e10cSrcweir #endif
386*cdf0e10cSrcweir         // request glyph fallback at this position in the string
387*cdf0e10cSrcweir         bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
388*cdf0e10cSrcweir         int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
389*cdf0e10cSrcweir         rArgs.NeedFallback( nCharPos, bRTL );
390*cdf0e10cSrcweir         if( bSurrogate )
391*cdf0e10cSrcweir             rArgs.NeedFallback( nCharPos+1, bRTL );
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
394*cdf0e10cSrcweir         {
395*cdf0e10cSrcweir             // when we already are layouting for glyph fallback
396*cdf0e10cSrcweir             // then a new unresolved glyph is not interesting
397*cdf0e10cSrcweir             mnNotdefWidth = 0;
398*cdf0e10cSrcweir             mpOutGlyphs[i] = DROPPED_OUTGLYPH;
399*cdf0e10cSrcweir             if( mbDisableGlyphs && bSurrogate )
400*cdf0e10cSrcweir                 mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
401*cdf0e10cSrcweir         }
402*cdf0e10cSrcweir         else
403*cdf0e10cSrcweir         {
404*cdf0e10cSrcweir             if( mnNotdefWidth < 0 )
405*cdf0e10cSrcweir             {
406*cdf0e10cSrcweir                 // get the width of the NotDef glyph
407*cdf0e10cSrcweir                 LONG aExtent;
408*cdf0e10cSrcweir                 mnNotdefWidth = 0;
409*cdf0e10cSrcweir 				if (Ft2QueryStringWidthW( mhPS, (LPWSTR)&rArgs.mpStr[ nCharPos ], 1, &aExtent))
410*cdf0e10cSrcweir                     mnNotdefWidth = aExtent;
411*cdf0e10cSrcweir             }
412*cdf0e10cSrcweir             // use a better NotDef glyph
413*cdf0e10cSrcweir             if( !mbDisableGlyphs )
414*cdf0e10cSrcweir                 mpOutGlyphs[i] = 0;
415*cdf0e10cSrcweir         }
416*cdf0e10cSrcweir 
417*cdf0e10cSrcweir         // replace the current glyph with the NotDef glyph
418*cdf0e10cSrcweir         mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
419*cdf0e10cSrcweir         mpGlyphAdvances[i] = mnNotdefWidth;
420*cdf0e10cSrcweir         if( mpGlyphOrigAdvs )
421*cdf0e10cSrcweir             mpGlyphOrigAdvs[i] = mnNotdefWidth;
422*cdf0e10cSrcweir     }
423*cdf0e10cSrcweir 
424*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
425*cdf0e10cSrcweir     // apply kerning if the layout engine has not yet done it
426*cdf0e10cSrcweir     if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
427*cdf0e10cSrcweir     {
428*cdf0e10cSrcweir #else // GCP_KERN_HACK
429*cdf0e10cSrcweir     // apply just asian kerning
430*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
431*cdf0e10cSrcweir     {
432*cdf0e10cSrcweir         if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
433*cdf0e10cSrcweir #endif // GCP_KERN_HACK
434*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
435*cdf0e10cSrcweir                 mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
436*cdf0e10cSrcweir 
437*cdf0e10cSrcweir         // #99658# also apply asian kerning on the substring border
438*cdf0e10cSrcweir         int nLen = mnGlyphCount;
439*cdf0e10cSrcweir         if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
440*cdf0e10cSrcweir             ++nLen;
441*cdf0e10cSrcweir         for( i = 1; i < nLen; ++i )
442*cdf0e10cSrcweir         {
443*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
444*cdf0e10cSrcweir             if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
445*cdf0e10cSrcweir             {
446*cdf0e10cSrcweir                 int nKernAmount = mrOs2FontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
447*cdf0e10cSrcweir                 mpGlyphAdvances[ i-1 ] += nKernAmount;
448*cdf0e10cSrcweir                 mnWidth += nKernAmount;
449*cdf0e10cSrcweir             }
450*cdf0e10cSrcweir             else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
451*cdf0e10cSrcweir #endif // GCP_KERN_HACK
452*cdf0e10cSrcweir 
453*cdf0e10cSrcweir             if( (0x3000 == (0xFF00 & pBidiStr[i-1]))
454*cdf0e10cSrcweir             &&  (0x3000 == (0xFF00 & pBidiStr[i])) )
455*cdf0e10cSrcweir             {
456*cdf0e10cSrcweir                 long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
457*cdf0e10cSrcweir                 long nKernNext  = -CalcAsianKerning( pBidiStr[i], false, bVertical );
458*cdf0e10cSrcweir 
459*cdf0e10cSrcweir                 long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
460*cdf0e10cSrcweir                 if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
461*cdf0e10cSrcweir                 {
462*cdf0e10cSrcweir                     nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
463*cdf0e10cSrcweir                     mpGlyphAdvances[i-1] += nDelta;
464*cdf0e10cSrcweir                     mnWidth += nDelta;
465*cdf0e10cSrcweir                 }
466*cdf0e10cSrcweir             }
467*cdf0e10cSrcweir         }
468*cdf0e10cSrcweir     }
469*cdf0e10cSrcweir 
470*cdf0e10cSrcweir     // calculate virtual char widths
471*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
472*cdf0e10cSrcweir         mpCharWidths = mpGlyphAdvances;
473*cdf0e10cSrcweir     else
474*cdf0e10cSrcweir     {
475*cdf0e10cSrcweir         mpCharWidths = new int[ mnCharCount ];
476*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
477*cdf0e10cSrcweir             mpCharWidths[ i ] = 0;
478*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
479*cdf0e10cSrcweir         {
480*cdf0e10cSrcweir             int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
481*cdf0e10cSrcweir             if( j >= 0 )
482*cdf0e10cSrcweir                 mpCharWidths[ j ] += mpGlyphAdvances[ i ];
483*cdf0e10cSrcweir         }
484*cdf0e10cSrcweir     }
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir     // scale layout metrics if needed
487*cdf0e10cSrcweir     if( mfFontScale != 1.0 )
488*cdf0e10cSrcweir     {
489*cdf0e10cSrcweir         mnWidth   *= mfFontScale;
490*cdf0e10cSrcweir         mnBaseAdv *= mfFontScale;
491*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
492*cdf0e10cSrcweir             mpCharWidths[ i ] *= mfFontScale;
493*cdf0e10cSrcweir         if( mpGlyphAdvances != mpCharWidths )
494*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
495*cdf0e10cSrcweir                 mpGlyphAdvances[ i ] *= mfFontScale;
496*cdf0e10cSrcweir         if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
497*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
498*cdf0e10cSrcweir                 mpGlyphOrigAdvs[ i ] *= mfFontScale;
499*cdf0e10cSrcweir     }
500*cdf0e10cSrcweir 
501*cdf0e10cSrcweir     return true;
502*cdf0e10cSrcweir }
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir // -----------------------------------------------------------------------
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir int Os2SalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart,
507*cdf0e10cSrcweir     sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
508*cdf0e10cSrcweir {
509*cdf0e10cSrcweir     // return zero if no more glyph found
510*cdf0e10cSrcweir     if( nStart >= mnGlyphCount )
511*cdf0e10cSrcweir         return 0;
512*cdf0e10cSrcweir 
513*cdf0e10cSrcweir     // calculate glyph position relative to layout base
514*cdf0e10cSrcweir     // TODO: avoid for nStart!=0 case by reusing rPos
515*cdf0e10cSrcweir     long nXOffset = mnBaseAdv;
516*cdf0e10cSrcweir     for( int i = 0; i < nStart; ++i )
517*cdf0e10cSrcweir         nXOffset += mpGlyphAdvances[ i ];
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir     // calculate absolute position in pixel units
520*cdf0e10cSrcweir     Point aRelativePos( nXOffset, 0 );
521*cdf0e10cSrcweir     rPos = GetDrawPosition( aRelativePos );
522*cdf0e10cSrcweir 
523*cdf0e10cSrcweir     int nCount = 0;
524*cdf0e10cSrcweir     while( nCount < nLen )
525*cdf0e10cSrcweir     {
526*cdf0e10cSrcweir         // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
527*cdf0e10cSrcweir         long nGlyphIndex = mpOutGlyphs[ nStart ];
528*cdf0e10cSrcweir         if( mbDisableGlyphs )
529*cdf0e10cSrcweir         {
530*cdf0e10cSrcweir             if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
531*cdf0e10cSrcweir             {
532*cdf0e10cSrcweir                 sal_Unicode cChar = (sal_Unicode)(nGlyphIndex & GF_IDXMASK);
533*cdf0e10cSrcweir #ifdef GNG_VERT_HACK
534*cdf0e10cSrcweir                 if( mrOs2FontData.HasGSUBstitutions( mhPS )
535*cdf0e10cSrcweir                 &&  mrOs2FontData.IsGSUBstituted( cChar ) )
536*cdf0e10cSrcweir                     nGlyphIndex |= GF_ROTL | GF_GSUB;
537*cdf0e10cSrcweir                 else
538*cdf0e10cSrcweir #endif // GNG_VERT_HACK
539*cdf0e10cSrcweir                 {
540*cdf0e10cSrcweir                     nGlyphIndex |= GetVerticalFlags( cChar );
541*cdf0e10cSrcweir                     if( !(nGlyphIndex & GF_ROTMASK) )
542*cdf0e10cSrcweir                         nGlyphIndex |= GF_VERT;
543*cdf0e10cSrcweir                 }
544*cdf0e10cSrcweir             }
545*cdf0e10cSrcweir             nGlyphIndex |= GF_ISCHAR;
546*cdf0e10cSrcweir         }
547*cdf0e10cSrcweir         ++nCount;
548*cdf0e10cSrcweir         *(pGlyphs++) = nGlyphIndex;
549*cdf0e10cSrcweir         if( pGlyphAdvances )
550*cdf0e10cSrcweir             *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
551*cdf0e10cSrcweir         if( pCharIndexes )
552*cdf0e10cSrcweir         {
553*cdf0e10cSrcweir             int nCharPos;
554*cdf0e10cSrcweir             if( !mpGlyphs2Chars )
555*cdf0e10cSrcweir                 nCharPos = nStart + mnMinCharPos;
556*cdf0e10cSrcweir             else
557*cdf0e10cSrcweir                 nCharPos = mpGlyphs2Chars[nStart];
558*cdf0e10cSrcweir             *(pCharIndexes++) = nCharPos;
559*cdf0e10cSrcweir         }
560*cdf0e10cSrcweir 
561*cdf0e10cSrcweir         // stop at last glyph
562*cdf0e10cSrcweir         if( ++nStart >= mnGlyphCount )
563*cdf0e10cSrcweir             break;
564*cdf0e10cSrcweir 
565*cdf0e10cSrcweir         // stop when next x-position is unexpected
566*cdf0e10cSrcweir         if( !pGlyphAdvances && mpGlyphOrigAdvs )
567*cdf0e10cSrcweir             if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
568*cdf0e10cSrcweir                 break;
569*cdf0e10cSrcweir     }
570*cdf0e10cSrcweir 
571*cdf0e10cSrcweir     return nCount;
572*cdf0e10cSrcweir }
573*cdf0e10cSrcweir 
574*cdf0e10cSrcweir // -----------------------------------------------------------------------
575*cdf0e10cSrcweir 
576*cdf0e10cSrcweir void Os2SalLayout::DrawText( SalGraphics& rGraphics ) const
577*cdf0e10cSrcweir {
578*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
579*cdf0e10cSrcweir         return;
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir 	Point 	aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
582*cdf0e10cSrcweir 	POINTL	aPt;
583*cdf0e10cSrcweir 	APIRET	rc;
584*cdf0e10cSrcweir 
585*cdf0e10cSrcweir 	aPt.x = aPos.X();
586*cdf0e10cSrcweir 	aPt.y = static_cast<Os2SalGraphics&>(rGraphics).mnHeight - aPos.Y();
587*cdf0e10cSrcweir 
588*cdf0e10cSrcweir 	// ft2lib doesn't work with printer hps, so we fallback to codepage printing
589*cdf0e10cSrcweir 	// until cp1200 support will work.
590*cdf0e10cSrcweir 	if (static_cast<Os2SalGraphics&>(rGraphics).mbPrinter) {
591*cdf0e10cSrcweir 		// convert to codepage
592*cdf0e10cSrcweir 		ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
593*cdf0e10cSrcweir 		// gliph size is not recalculated, so it could be wrong!
594*cdf0e10cSrcweir 		rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
595*cdf0e10cSrcweir 					&aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
596*cdf0e10cSrcweir 					(LONG*)mpGlyphAdvances, 0);
597*cdf0e10cSrcweir 	} else {
598*cdf0e10cSrcweir 		// try unicode rendering to screen
599*cdf0e10cSrcweir 		rc = Ft2CharStringPosAtW( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
600*cdf0e10cSrcweir 					&aPt, NULL, CHS_VECTOR, mnGlyphCount, (LPWSTR)mpOutGlyphs,
601*cdf0e10cSrcweir 					(LONG*)mpGlyphAdvances, 0);
602*cdf0e10cSrcweir 		if (rc == GPI_ERROR) {
603*cdf0e10cSrcweir 			// if *W fails, convert to codepage and use *A (fallback to GPI into ft2)
604*cdf0e10cSrcweir 			ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
605*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>10
606*cdf0e10cSrcweir 			debug_printf("Os2SalLayout::DrawText HPS %08x PosAtW failed '%s'!\n",static_cast<Os2SalGraphics&>(rGraphics).mhPS,str.GetBuffer());
607*cdf0e10cSrcweir #endif
608*cdf0e10cSrcweir 			// gliph size is not recalculated, so it could be wrong!
609*cdf0e10cSrcweir 			rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
610*cdf0e10cSrcweir 						&aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
611*cdf0e10cSrcweir 						(LONG*)mpGlyphAdvances, 0);
612*cdf0e10cSrcweir 		}
613*cdf0e10cSrcweir 	}
614*cdf0e10cSrcweir }
615*cdf0e10cSrcweir 
616*cdf0e10cSrcweir // -----------------------------------------------------------------------
617*cdf0e10cSrcweir 
618*cdf0e10cSrcweir long Os2SalLayout::FillDXArray( long* pDXArray ) const
619*cdf0e10cSrcweir {
620*cdf0e10cSrcweir     if( !mnWidth )
621*cdf0e10cSrcweir     {
622*cdf0e10cSrcweir         long mnWidth = mnBaseAdv;
623*cdf0e10cSrcweir         for( int i = 0; i < mnGlyphCount; ++i )
624*cdf0e10cSrcweir             mnWidth += mpGlyphAdvances[ i ];
625*cdf0e10cSrcweir     }
626*cdf0e10cSrcweir 
627*cdf0e10cSrcweir     if( pDXArray != NULL )
628*cdf0e10cSrcweir     {
629*cdf0e10cSrcweir         for( int i = 0; i < mnCharCount; ++i )
630*cdf0e10cSrcweir              pDXArray[ i ] = mpCharWidths[ i ];
631*cdf0e10cSrcweir     }
632*cdf0e10cSrcweir 
633*cdf0e10cSrcweir     return mnWidth;
634*cdf0e10cSrcweir }
635*cdf0e10cSrcweir 
636*cdf0e10cSrcweir // -----------------------------------------------------------------------
637*cdf0e10cSrcweir 
638*cdf0e10cSrcweir int Os2SalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
639*cdf0e10cSrcweir // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
640*cdf0e10cSrcweir {
641*cdf0e10cSrcweir     if( mnWidth )
642*cdf0e10cSrcweir         if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
643*cdf0e10cSrcweir             return STRING_LEN;
644*cdf0e10cSrcweir 
645*cdf0e10cSrcweir     long nExtraWidth = mnBaseAdv * nFactor;
646*cdf0e10cSrcweir     for( int n = 0; n < mnCharCount; ++n )
647*cdf0e10cSrcweir     {
648*cdf0e10cSrcweir         // skip unused characters
649*cdf0e10cSrcweir         if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
650*cdf0e10cSrcweir             continue;
651*cdf0e10cSrcweir         // add char widths until max
652*cdf0e10cSrcweir         nExtraWidth += mpCharWidths[ n ] * nFactor;
653*cdf0e10cSrcweir         if( nExtraWidth >= nMaxWidth )
654*cdf0e10cSrcweir             return (mnMinCharPos + n);
655*cdf0e10cSrcweir         nExtraWidth += nCharExtra;
656*cdf0e10cSrcweir     }
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir     return STRING_LEN;
659*cdf0e10cSrcweir }
660*cdf0e10cSrcweir 
661*cdf0e10cSrcweir // -----------------------------------------------------------------------
662*cdf0e10cSrcweir 
663*cdf0e10cSrcweir void Os2SalLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
664*cdf0e10cSrcweir {
665*cdf0e10cSrcweir     long nXPos = mnBaseAdv;
666*cdf0e10cSrcweir 
667*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
668*cdf0e10cSrcweir     {
669*cdf0e10cSrcweir         for( int i = 0; i < nMaxIdx; i += 2 )
670*cdf0e10cSrcweir         {
671*cdf0e10cSrcweir             pCaretXArray[ i ] = nXPos;
672*cdf0e10cSrcweir             nXPos += mpGlyphAdvances[ i>>1 ];
673*cdf0e10cSrcweir             pCaretXArray[ i+1 ] = nXPos;
674*cdf0e10cSrcweir         }
675*cdf0e10cSrcweir     }
676*cdf0e10cSrcweir     else
677*cdf0e10cSrcweir     {
678*cdf0e10cSrcweir         int  i;
679*cdf0e10cSrcweir         for( i = 0; i < nMaxIdx; ++i )
680*cdf0e10cSrcweir             pCaretXArray[ i ] = -1;
681*cdf0e10cSrcweir 
682*cdf0e10cSrcweir         // assign glyph positions to character positions
683*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
684*cdf0e10cSrcweir         {
685*cdf0e10cSrcweir             int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
686*cdf0e10cSrcweir             long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
687*cdf0e10cSrcweir             nCurrIdx *= 2;
688*cdf0e10cSrcweir             if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
689*cdf0e10cSrcweir             {
690*cdf0e10cSrcweir                 // normal positions for LTR case
691*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = nXPos;
692*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = nXRight;
693*cdf0e10cSrcweir             }
694*cdf0e10cSrcweir             else
695*cdf0e10cSrcweir             {
696*cdf0e10cSrcweir                 // reverse positions for RTL case
697*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = nXRight;
698*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = nXPos;
699*cdf0e10cSrcweir             }
700*cdf0e10cSrcweir             nXPos += mpGlyphAdvances[ i ];
701*cdf0e10cSrcweir         }
702*cdf0e10cSrcweir     }
703*cdf0e10cSrcweir }
704*cdf0e10cSrcweir 
705*cdf0e10cSrcweir // -----------------------------------------------------------------------
706*cdf0e10cSrcweir 
707*cdf0e10cSrcweir void Os2SalLayout::Justify( long nNewWidth )
708*cdf0e10cSrcweir {
709*cdf0e10cSrcweir     long nOldWidth = mnWidth;
710*cdf0e10cSrcweir     mnWidth = nNewWidth;
711*cdf0e10cSrcweir 
712*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
713*cdf0e10cSrcweir         return;
714*cdf0e10cSrcweir 
715*cdf0e10cSrcweir     if( nNewWidth == nOldWidth )
716*cdf0e10cSrcweir         return;
717*cdf0e10cSrcweir 
718*cdf0e10cSrcweir     // the rightmost glyph cannot be stretched
719*cdf0e10cSrcweir     const int nRight = mnGlyphCount - 1;
720*cdf0e10cSrcweir     nOldWidth -= mpGlyphAdvances[ nRight ];
721*cdf0e10cSrcweir     nNewWidth -= mpGlyphAdvances[ nRight ];
722*cdf0e10cSrcweir 
723*cdf0e10cSrcweir     // count stretchable glyphs
724*cdf0e10cSrcweir     int nStretchable = 0, i;
725*cdf0e10cSrcweir     for( i = 0; i < nRight; ++i )
726*cdf0e10cSrcweir         if( mpGlyphAdvances[i] >= 0 )
727*cdf0e10cSrcweir             ++nStretchable;
728*cdf0e10cSrcweir 
729*cdf0e10cSrcweir     // stretch these glyphs
730*cdf0e10cSrcweir     int nDiffWidth = nNewWidth - nOldWidth;
731*cdf0e10cSrcweir     for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
732*cdf0e10cSrcweir     {
733*cdf0e10cSrcweir         if( mpGlyphAdvances[i] <= 0 )
734*cdf0e10cSrcweir             continue;
735*cdf0e10cSrcweir         int nDeltaWidth = nDiffWidth / nStretchable;
736*cdf0e10cSrcweir         mpGlyphAdvances[i] += nDeltaWidth;
737*cdf0e10cSrcweir         --nStretchable;
738*cdf0e10cSrcweir         nDiffWidth -= nDeltaWidth;
739*cdf0e10cSrcweir     }
740*cdf0e10cSrcweir }
741*cdf0e10cSrcweir 
742*cdf0e10cSrcweir // -----------------------------------------------------------------------
743*cdf0e10cSrcweir 
744*cdf0e10cSrcweir void Os2SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
745*cdf0e10cSrcweir {
746*cdf0e10cSrcweir     SalLayout::AdjustLayout( rArgs );
747*cdf0e10cSrcweir 
748*cdf0e10cSrcweir     // adjust positions if requested
749*cdf0e10cSrcweir     if( rArgs.mpDXArray )
750*cdf0e10cSrcweir         ApplyDXArray( rArgs );
751*cdf0e10cSrcweir     else if( rArgs.mnLayoutWidth )
752*cdf0e10cSrcweir         Justify( rArgs.mnLayoutWidth );
753*cdf0e10cSrcweir     else
754*cdf0e10cSrcweir         return;
755*cdf0e10cSrcweir 
756*cdf0e10cSrcweir     // recalculate virtual char widths if they were changed
757*cdf0e10cSrcweir     if( mpCharWidths != mpGlyphAdvances )
758*cdf0e10cSrcweir     {
759*cdf0e10cSrcweir         int i;
760*cdf0e10cSrcweir         if( !mpGlyphs2Chars )
761*cdf0e10cSrcweir         {
762*cdf0e10cSrcweir             // standard LTR case
763*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
764*cdf0e10cSrcweir                  mpCharWidths[ i ] = mpGlyphAdvances[ i ];
765*cdf0e10cSrcweir         }
766*cdf0e10cSrcweir         else
767*cdf0e10cSrcweir         {
768*cdf0e10cSrcweir             // BiDi or complex case
769*cdf0e10cSrcweir             for( i = 0; i < mnCharCount; ++i )
770*cdf0e10cSrcweir                 mpCharWidths[ i ] = 0;
771*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
772*cdf0e10cSrcweir             {
773*cdf0e10cSrcweir                 int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
774*cdf0e10cSrcweir                 if( j >= 0 )
775*cdf0e10cSrcweir                     mpCharWidths[ j ] += mpGlyphAdvances[ i ];
776*cdf0e10cSrcweir             }
777*cdf0e10cSrcweir         }
778*cdf0e10cSrcweir     }
779*cdf0e10cSrcweir }
780*cdf0e10cSrcweir 
781*cdf0e10cSrcweir // -----------------------------------------------------------------------
782*cdf0e10cSrcweir 
783*cdf0e10cSrcweir void Os2SalLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
784*cdf0e10cSrcweir {
785*cdf0e10cSrcweir     // try to avoid disturbance of text flow for LSB rounding case;
786*cdf0e10cSrcweir     const long* pDXArray = rArgs.mpDXArray;
787*cdf0e10cSrcweir 
788*cdf0e10cSrcweir     int i = 0;
789*cdf0e10cSrcweir     long nOldWidth = mnBaseAdv;
790*cdf0e10cSrcweir     for(; i < mnCharCount; ++i )
791*cdf0e10cSrcweir     {
792*cdf0e10cSrcweir         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
793*cdf0e10cSrcweir         if( j >= 0 )
794*cdf0e10cSrcweir         {
795*cdf0e10cSrcweir             nOldWidth += mpGlyphAdvances[ j ];
796*cdf0e10cSrcweir             int nDiff = nOldWidth - pDXArray[ i ];
797*cdf0e10cSrcweir 
798*cdf0e10cSrcweir 	       // disabled because of #104768#
799*cdf0e10cSrcweir             // works great for static text, but problems when typing
800*cdf0e10cSrcweir             // if( nDiff>+1 || nDiff<-1 )
801*cdf0e10cSrcweir             // only bother with changing anything when something moved
802*cdf0e10cSrcweir             if( nDiff != 0 )
803*cdf0e10cSrcweir                 break;
804*cdf0e10cSrcweir         }
805*cdf0e10cSrcweir     }
806*cdf0e10cSrcweir     if( i >= mnCharCount )
807*cdf0e10cSrcweir         return;
808*cdf0e10cSrcweir 
809*cdf0e10cSrcweir     if( !mpGlyphOrigAdvs )
810*cdf0e10cSrcweir     {
811*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
812*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
813*cdf0e10cSrcweir             mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
814*cdf0e10cSrcweir     }
815*cdf0e10cSrcweir 
816*cdf0e10cSrcweir     mnWidth = mnBaseAdv;
817*cdf0e10cSrcweir     for( i = 0; i < mnCharCount; ++i )
818*cdf0e10cSrcweir     {
819*cdf0e10cSrcweir         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
820*cdf0e10cSrcweir         if( j >= 0 )
821*cdf0e10cSrcweir             mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
822*cdf0e10cSrcweir         mnWidth = pDXArray[i];
823*cdf0e10cSrcweir     }
824*cdf0e10cSrcweir }
825*cdf0e10cSrcweir 
826*cdf0e10cSrcweir // -----------------------------------------------------------------------
827*cdf0e10cSrcweir 
828*cdf0e10cSrcweir void Os2SalLayout::MoveGlyph( int nStart, long nNewXPos )
829*cdf0e10cSrcweir {
830*cdf0e10cSrcweir    if( nStart > mnGlyphCount )
831*cdf0e10cSrcweir         return;
832*cdf0e10cSrcweir 
833*cdf0e10cSrcweir     // calculate the current x-position of the requested glyph
834*cdf0e10cSrcweir     // TODO: cache absolute positions
835*cdf0e10cSrcweir     int nXPos = mnBaseAdv;
836*cdf0e10cSrcweir     for( int i = 0; i < nStart; ++i )
837*cdf0e10cSrcweir         nXPos += mpGlyphAdvances[i];
838*cdf0e10cSrcweir 
839*cdf0e10cSrcweir     // calculate the difference to the current glyph position
840*cdf0e10cSrcweir     int nDelta = nNewXPos - nXPos;
841*cdf0e10cSrcweir 
842*cdf0e10cSrcweir     // adjust the width of the layout if it was already cached
843*cdf0e10cSrcweir     if( mnWidth )
844*cdf0e10cSrcweir         mnWidth += nDelta;
845*cdf0e10cSrcweir 
846*cdf0e10cSrcweir     // depending on whether the requested glyph is leftmost in the layout
847*cdf0e10cSrcweir     // adjust either the layout's or the requested glyph's relative position
848*cdf0e10cSrcweir     if( nStart > 0 )
849*cdf0e10cSrcweir         mpGlyphAdvances[ nStart-1 ] += nDelta;
850*cdf0e10cSrcweir     else
851*cdf0e10cSrcweir         mnBaseAdv += nDelta;
852*cdf0e10cSrcweir }
853*cdf0e10cSrcweir 
854*cdf0e10cSrcweir // -----------------------------------------------------------------------
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir void Os2SalLayout::DropGlyph( int nStart )
857*cdf0e10cSrcweir {
858*cdf0e10cSrcweir     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
859*cdf0e10cSrcweir }
860*cdf0e10cSrcweir 
861*cdf0e10cSrcweir // -----------------------------------------------------------------------
862*cdf0e10cSrcweir 
863*cdf0e10cSrcweir void Os2SalLayout::Simplify( bool bIsBase )
864*cdf0e10cSrcweir {
865*cdf0e10cSrcweir     // return early if no glyph has been dropped
866*cdf0e10cSrcweir     int i = mnGlyphCount;
867*cdf0e10cSrcweir     while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
868*cdf0e10cSrcweir     if( i < 0 )
869*cdf0e10cSrcweir         return;
870*cdf0e10cSrcweir 
871*cdf0e10cSrcweir     // convert the layout to a sparse layout if it is not already
872*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
873*cdf0e10cSrcweir     {
874*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnGlyphCount ];
875*cdf0e10cSrcweir         mpCharWidths = new int[ mnCharCount ];
876*cdf0e10cSrcweir         // assertion: mnGlyphCount == mnCharCount
877*cdf0e10cSrcweir         for( int k = 0; k < mnGlyphCount; ++k )
878*cdf0e10cSrcweir         {
879*cdf0e10cSrcweir             mpGlyphs2Chars[ k ] = mnMinCharPos + k;
880*cdf0e10cSrcweir             mpCharWidths[ k ] = mpGlyphAdvances[ k ];
881*cdf0e10cSrcweir         }
882*cdf0e10cSrcweir     }
883*cdf0e10cSrcweir 
884*cdf0e10cSrcweir     // remove dropped glyphs that are rightmost in the layout
885*cdf0e10cSrcweir     for( i = mnGlyphCount; --i >= 0; )
886*cdf0e10cSrcweir     {
887*cdf0e10cSrcweir         if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
888*cdf0e10cSrcweir             break;
889*cdf0e10cSrcweir         if( mnWidth )
890*cdf0e10cSrcweir             mnWidth -= mpGlyphAdvances[ i ];
891*cdf0e10cSrcweir         int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
892*cdf0e10cSrcweir         if( nRelCharPos >= 0 )
893*cdf0e10cSrcweir             mpCharWidths[ nRelCharPos ] = 0;
894*cdf0e10cSrcweir     }
895*cdf0e10cSrcweir     mnGlyphCount = i + 1;
896*cdf0e10cSrcweir 
897*cdf0e10cSrcweir     // keep original glyph widths around
898*cdf0e10cSrcweir     if( !mpGlyphOrigAdvs )
899*cdf0e10cSrcweir     {
900*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
901*cdf0e10cSrcweir         for( int k = 0; k < mnGlyphCount; ++k )
902*cdf0e10cSrcweir             mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
903*cdf0e10cSrcweir     }
904*cdf0e10cSrcweir 
905*cdf0e10cSrcweir     // remove dropped glyphs inside the layout
906*cdf0e10cSrcweir     int nNewGC = 0;
907*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
908*cdf0e10cSrcweir     {
909*cdf0e10cSrcweir         if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
910*cdf0e10cSrcweir         {
911*cdf0e10cSrcweir             // adjust relative position to last valid glyph
912*cdf0e10cSrcweir             int nDroppedWidth = mpGlyphAdvances[ i ];
913*cdf0e10cSrcweir             mpGlyphAdvances[ i ] = 0;
914*cdf0e10cSrcweir             if( nNewGC > 0 )
915*cdf0e10cSrcweir                 mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
916*cdf0e10cSrcweir             else
917*cdf0e10cSrcweir                 mnBaseAdv += nDroppedWidth;
918*cdf0e10cSrcweir 
919*cdf0e10cSrcweir             // zero the virtual char width for the char that has a fallback
920*cdf0e10cSrcweir             int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
921*cdf0e10cSrcweir             if( nRelCharPos >= 0 )
922*cdf0e10cSrcweir                 mpCharWidths[ nRelCharPos ] = 0;
923*cdf0e10cSrcweir         }
924*cdf0e10cSrcweir         else
925*cdf0e10cSrcweir         {
926*cdf0e10cSrcweir             if( nNewGC != i )
927*cdf0e10cSrcweir             {
928*cdf0e10cSrcweir                 // rearrange the glyph array to get rid of the dropped glyph
929*cdf0e10cSrcweir                 mpOutGlyphs[ nNewGC ]     = mpOutGlyphs[ i ];
930*cdf0e10cSrcweir                 mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
931*cdf0e10cSrcweir                 mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
932*cdf0e10cSrcweir                 mpGlyphs2Chars[ nNewGC ]  = mpGlyphs2Chars[ i ];
933*cdf0e10cSrcweir             }
934*cdf0e10cSrcweir             ++nNewGC;
935*cdf0e10cSrcweir         }
936*cdf0e10cSrcweir     }
937*cdf0e10cSrcweir 
938*cdf0e10cSrcweir     mnGlyphCount = nNewGC;
939*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
940*cdf0e10cSrcweir         mnWidth = mnBaseAdv = 0;
941*cdf0e10cSrcweir }
942*cdf0e10cSrcweir 
943*cdf0e10cSrcweir // =======================================================================
944*cdf0e10cSrcweir 
945*cdf0e10cSrcweir SalLayout* Os2SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
946*cdf0e10cSrcweir {
947*cdf0e10cSrcweir 	Os2SalLayout* pLayout = NULL;
948*cdf0e10cSrcweir     DBG_ASSERT( mpOs2FontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
949*cdf0e10cSrcweir 
950*cdf0e10cSrcweir     const ImplOs2FontData& rFontFace      = *mpOs2FontData[ nFallbackLevel ];
951*cdf0e10cSrcweir     ImplOs2FontEntry& rFontInstance = *mpOs2FontEntry[ nFallbackLevel ];
952*cdf0e10cSrcweir 
953*cdf0e10cSrcweir     {
954*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
955*cdf0e10cSrcweir         if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
956*cdf0e10cSrcweir         {
957*cdf0e10cSrcweir             // TODO: directly cache kerning info in the rFontInstance
958*cdf0e10cSrcweir             // TODO: get rid of kerning methods+data in WinSalGraphics object
959*cdf0e10cSrcweir             GetKernPairs( 0, NULL );
960*cdf0e10cSrcweir             rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
961*cdf0e10cSrcweir         }
962*cdf0e10cSrcweir #endif // GCP_KERN_HACK
963*cdf0e10cSrcweir 
964*cdf0e10cSrcweir         //BYTE eCharSet = ANSI_CHARSET;
965*cdf0e10cSrcweir         //if( mpLogFont )
966*cdf0e10cSrcweir         //    eCharSet = mpLogFont->lfCharSet;
967*cdf0e10cSrcweir         pLayout = new Os2SalLayout( mhPS, 0, rFontFace, rFontInstance );
968*cdf0e10cSrcweir     }
969*cdf0e10cSrcweir 
970*cdf0e10cSrcweir     if( mfFontScale != 1.0 )
971*cdf0e10cSrcweir         pLayout->SetFontScale( mfFontScale );
972*cdf0e10cSrcweir 
973*cdf0e10cSrcweir 	return pLayout;
974*cdf0e10cSrcweir }
975*cdf0e10cSrcweir 
976*cdf0e10cSrcweir // =======================================================================
977*cdf0e10cSrcweir 
978*cdf0e10cSrcweir ImplOs2FontEntry::ImplOs2FontEntry( ImplFontSelectData& rFSD )
979*cdf0e10cSrcweir :   ImplFontEntry( rFSD ),
980*cdf0e10cSrcweir 	maWidthMap( 512 )
981*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
982*cdf0e10cSrcweir 	,mpKerningPairs( NULL )
983*cdf0e10cSrcweir 	,mnKerningPairs( -1 )
984*cdf0e10cSrcweir #endif // GCP_KERN_HACK
985*cdf0e10cSrcweir {
986*cdf0e10cSrcweir }
987*cdf0e10cSrcweir 
988*cdf0e10cSrcweir // -----------------------------------------------------------------------
989*cdf0e10cSrcweir 
990*cdf0e10cSrcweir ImplOs2FontEntry::~ImplOs2FontEntry()
991*cdf0e10cSrcweir {
992*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
993*cdf0e10cSrcweir     delete[] mpKerningPairs;
994*cdf0e10cSrcweir #endif // GCP_KERN_HACK
995*cdf0e10cSrcweir }
996*cdf0e10cSrcweir 
997*cdf0e10cSrcweir // -----------------------------------------------------------------------
998*cdf0e10cSrcweir 
999*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
1000*cdf0e10cSrcweir bool ImplOs2FontEntry::HasKernData() const
1001*cdf0e10cSrcweir {
1002*cdf0e10cSrcweir     return (mnKerningPairs >= 0);
1003*cdf0e10cSrcweir }
1004*cdf0e10cSrcweir 
1005*cdf0e10cSrcweir // -----------------------------------------------------------------------
1006*cdf0e10cSrcweir 
1007*cdf0e10cSrcweir void ImplOs2FontEntry::SetKernData( int nPairCount, const KERNINGPAIRS* pPairData )
1008*cdf0e10cSrcweir {
1009*cdf0e10cSrcweir     mnKerningPairs = nPairCount;
1010*cdf0e10cSrcweir     mpKerningPairs = new KERNINGPAIRS[ mnKerningPairs ];
1011*cdf0e10cSrcweir     ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIRS) );
1012*cdf0e10cSrcweir }
1013*cdf0e10cSrcweir 
1014*cdf0e10cSrcweir // -----------------------------------------------------------------------
1015*cdf0e10cSrcweir 
1016*cdf0e10cSrcweir int ImplOs2FontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
1017*cdf0e10cSrcweir {
1018*cdf0e10cSrcweir     int nKernAmount = 0;
1019*cdf0e10cSrcweir     if( mpKerningPairs )
1020*cdf0e10cSrcweir     {
1021*cdf0e10cSrcweir         const KERNINGPAIRS aRefPair = { cLeft, cRight, 0 };
1022*cdf0e10cSrcweir         const KERNINGPAIRS* pFirstPair = mpKerningPairs;
1023*cdf0e10cSrcweir         const KERNINGPAIRS* pEndPair = mpKerningPairs + mnKerningPairs;
1024*cdf0e10cSrcweir         const KERNINGPAIRS* pPair = std::lower_bound( pFirstPair,
1025*cdf0e10cSrcweir             pEndPair, aRefPair, ImplCmpKernData );
1026*cdf0e10cSrcweir         if( (pPair != pEndPair)
1027*cdf0e10cSrcweir         &&  (pPair->sFirstChar == aRefPair.sFirstChar)
1028*cdf0e10cSrcweir         &&  (pPair->sSecondChar == aRefPair.sSecondChar) )
1029*cdf0e10cSrcweir             nKernAmount = pPair->lKerningAmount;
1030*cdf0e10cSrcweir     }
1031*cdf0e10cSrcweir 
1032*cdf0e10cSrcweir     return nKernAmount;
1033*cdf0e10cSrcweir }
1034*cdf0e10cSrcweir #endif // GCP_KERN_HACK
1035*cdf0e10cSrcweir 
1036*cdf0e10cSrcweir // =======================================================================
1037*cdf0e10cSrcweir 
1038*cdf0e10cSrcweir ImplFontData* ImplOs2FontData::Clone() const
1039*cdf0e10cSrcweir {
1040*cdf0e10cSrcweir     if( mpUnicodeMap )
1041*cdf0e10cSrcweir         mpUnicodeMap->AddReference();
1042*cdf0e10cSrcweir     ImplFontData* pClone = new ImplOs2FontData( *this );
1043*cdf0e10cSrcweir     return pClone;
1044*cdf0e10cSrcweir }
1045*cdf0e10cSrcweir 
1046*cdf0e10cSrcweir // -----------------------------------------------------------------------
1047*cdf0e10cSrcweir 
1048*cdf0e10cSrcweir ImplFontEntry* ImplOs2FontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
1049*cdf0e10cSrcweir {
1050*cdf0e10cSrcweir     //debug_printf("ImplOs2FontData::CreateFontInstance\n");
1051*cdf0e10cSrcweir     ImplFontEntry* pEntry = new ImplOs2FontEntry( rFSD );
1052*cdf0e10cSrcweir     return pEntry;
1053*cdf0e10cSrcweir }
1054*cdf0e10cSrcweir 
1055*cdf0e10cSrcweir // =======================================================================
1056*cdf0e10cSrcweir 
1057