xref: /AOO41X/main/vcl/win/source/gdi/winlayout.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 #include "rtl/ustring.hxx"
32*cdf0e10cSrcweir 
33*cdf0e10cSrcweir #include "osl/module.h"
34*cdf0e10cSrcweir #include "osl/file.h"
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include "tools/svwin.h"
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include "vcl/svapp.hxx"
39*cdf0e10cSrcweir 
40*cdf0e10cSrcweir #include "win/salgdi.h"
41*cdf0e10cSrcweir #include "win/saldata.hxx"
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir // for GetMirroredChar
44*cdf0e10cSrcweir #include "sft.hxx"
45*cdf0e10cSrcweir #include "sallayout.hxx"
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir #include <cstdio>
48*cdf0e10cSrcweir #include <malloc.h>
49*cdf0e10cSrcweir #ifndef __MINGW32__
50*cdf0e10cSrcweir #define alloca _alloca
51*cdf0e10cSrcweir #endif
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
54*cdf0e10cSrcweir     #include <algorithm>
55*cdf0e10cSrcweir #endif // GCP_KERN_HACK
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir #define USE_UNISCRIBE
59*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
60*cdf0e10cSrcweir #include <Usp10.h>
61*cdf0e10cSrcweir #include <ShLwApi.h>
62*cdf0e10cSrcweir #include <winver.h>
63*cdf0e10cSrcweir #endif // USE_UNISCRIBE
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir #include <hash_map>
66*cdf0e10cSrcweir #include <set>
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir typedef std::hash_map<int,int> IntMap;
69*cdf0e10cSrcweir typedef std::set<int> IntSet;
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir // Graphite headers
72*cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
73*cdf0e10cSrcweir #include <i18npool/mslangid.hxx>
74*cdf0e10cSrcweir #include <graphite/GrClient.h>
75*cdf0e10cSrcweir #include <graphite/WinFont.h>
76*cdf0e10cSrcweir #include <graphite/Segment.h>
77*cdf0e10cSrcweir #include <graphite_layout.hxx>
78*cdf0e10cSrcweir #include <graphite_cache.hxx>
79*cdf0e10cSrcweir #include <graphite_features.hxx>
80*cdf0e10cSrcweir #endif
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir #define DROPPED_OUTGLYPH 0xFFFF
83*cdf0e10cSrcweir 
84*cdf0e10cSrcweir using namespace rtl;
85*cdf0e10cSrcweir 
86*cdf0e10cSrcweir // =======================================================================
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir // win32 specific physical font instance
89*cdf0e10cSrcweir class ImplWinFontEntry : public ImplFontEntry
90*cdf0e10cSrcweir {
91*cdf0e10cSrcweir public:
92*cdf0e10cSrcweir                             ImplWinFontEntry( ImplFontSelectData& );
93*cdf0e10cSrcweir                             ~ImplWinFontEntry();
94*cdf0e10cSrcweir 
95*cdf0e10cSrcweir private:
96*cdf0e10cSrcweir     // TODO: also add HFONT??? Watch out for issues with too many active fonts...
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
99*cdf0e10cSrcweir public:
100*cdf0e10cSrcweir     bool                    HasKernData() const;
101*cdf0e10cSrcweir     void                    SetKernData( int, const KERNINGPAIR* );
102*cdf0e10cSrcweir     int                     GetKerning( sal_Unicode, sal_Unicode ) const;
103*cdf0e10cSrcweir private:
104*cdf0e10cSrcweir     KERNINGPAIR*            mpKerningPairs;
105*cdf0e10cSrcweir     int                     mnKerningPairs;
106*cdf0e10cSrcweir #endif // GCP_KERN_HACK
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
109*cdf0e10cSrcweir public:
110*cdf0e10cSrcweir     SCRIPT_CACHE&           GetScriptCache() const
111*cdf0e10cSrcweir                             { return maScriptCache; }
112*cdf0e10cSrcweir private:
113*cdf0e10cSrcweir     mutable SCRIPT_CACHE    maScriptCache;
114*cdf0e10cSrcweir #endif // USE_UNISCRIBE
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir public:
117*cdf0e10cSrcweir     int                     GetCachedGlyphWidth( int nCharCode ) const;
118*cdf0e10cSrcweir     void                    CacheGlyphWidth( int nCharCode, int nCharWidth );
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir 	bool					InitKashidaHandling( HDC );
121*cdf0e10cSrcweir 	int						GetMinKashidaWidth() const { return mnMinKashidaWidth; }
122*cdf0e10cSrcweir 	int						GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
123*cdf0e10cSrcweir 
124*cdf0e10cSrcweir private:
125*cdf0e10cSrcweir     IntMap                  maWidthMap;
126*cdf0e10cSrcweir 	mutable int				mnMinKashidaWidth;
127*cdf0e10cSrcweir 	mutable int				mnMinKashidaGlyph;
128*cdf0e10cSrcweir };
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir // -----------------------------------------------------------------------
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
133*cdf0e10cSrcweir {
134*cdf0e10cSrcweir     maWidthMap[ nCharCode ] = nCharWidth;
135*cdf0e10cSrcweir }
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
138*cdf0e10cSrcweir {
139*cdf0e10cSrcweir     IntMap::const_iterator it = maWidthMap.find( nCharCode );
140*cdf0e10cSrcweir     if( it == maWidthMap.end() )
141*cdf0e10cSrcweir         return -1;
142*cdf0e10cSrcweir     return it->second;
143*cdf0e10cSrcweir }
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir // =======================================================================
146*cdf0e10cSrcweir 
147*cdf0e10cSrcweir class WinLayout : public SalLayout
148*cdf0e10cSrcweir {
149*cdf0e10cSrcweir public:
150*cdf0e10cSrcweir                         WinLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
151*cdf0e10cSrcweir     virtual void        InitFont() const;
152*cdf0e10cSrcweir     void                SetFontScale( float f ) { mfFontScale = f; }
153*cdf0e10cSrcweir     float               GetFontScale() const    { return mfFontScale; }
154*cdf0e10cSrcweir     HFONT               DisableFontScaling( void) const;
155*cdf0e10cSrcweir 
156*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
157*cdf0e10cSrcweir     SCRIPT_CACHE&       GetScriptCache() const
158*cdf0e10cSrcweir                             { return mrWinFontEntry.GetScriptCache(); }
159*cdf0e10cSrcweir #endif // USE_UNISCRIBE
160*cdf0e10cSrcweir 
161*cdf0e10cSrcweir protected:
162*cdf0e10cSrcweir     HDC                 mhDC;               // WIN32 device handle
163*cdf0e10cSrcweir     HFONT               mhFont;             // WIN32 font handle
164*cdf0e10cSrcweir     int                 mnBaseAdv;          // x-offset relative to Layout origin
165*cdf0e10cSrcweir     float               mfFontScale;        // allows metrics emulation of huge font sizes
166*cdf0e10cSrcweir 
167*cdf0e10cSrcweir     const ImplWinFontData& mrWinFontData;
168*cdf0e10cSrcweir     ImplWinFontEntry&   mrWinFontEntry;
169*cdf0e10cSrcweir };
170*cdf0e10cSrcweir 
171*cdf0e10cSrcweir // =======================================================================
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir class SimpleWinLayout : public WinLayout
174*cdf0e10cSrcweir {
175*cdf0e10cSrcweir public:
176*cdf0e10cSrcweir                     SimpleWinLayout( HDC, BYTE nCharSet, const ImplWinFontData&, ImplWinFontEntry& );
177*cdf0e10cSrcweir     virtual         ~SimpleWinLayout();
178*cdf0e10cSrcweir 
179*cdf0e10cSrcweir     virtual bool    LayoutText( ImplLayoutArgs& );
180*cdf0e10cSrcweir     virtual void    AdjustLayout( ImplLayoutArgs& );
181*cdf0e10cSrcweir     virtual void    DrawText( SalGraphics& ) const;
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir     virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
184*cdf0e10cSrcweir                         sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
185*cdf0e10cSrcweir 
186*cdf0e10cSrcweir     virtual long    FillDXArray( long* pDXArray ) const;
187*cdf0e10cSrcweir     virtual int     GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
188*cdf0e10cSrcweir     virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir     // for glyph+font+script fallback
191*cdf0e10cSrcweir     virtual void    MoveGlyph( int nStart, long nNewXPos );
192*cdf0e10cSrcweir     virtual void    DropGlyph( int nStart );
193*cdf0e10cSrcweir     virtual void    Simplify( bool bIsBase );
194*cdf0e10cSrcweir 
195*cdf0e10cSrcweir protected:
196*cdf0e10cSrcweir     void            Justify( long nNewWidth );
197*cdf0e10cSrcweir     void            ApplyDXArray( const ImplLayoutArgs& );
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir private:
200*cdf0e10cSrcweir     int             mnGlyphCount;
201*cdf0e10cSrcweir     int             mnCharCount;
202*cdf0e10cSrcweir     WCHAR*          mpOutGlyphs;
203*cdf0e10cSrcweir     int*            mpGlyphAdvances;    // if possible this is shared with mpGlyphAdvances[]
204*cdf0e10cSrcweir     int*            mpGlyphOrigAdvs;
205*cdf0e10cSrcweir     int*            mpCharWidths;       // map rel char pos to char width
206*cdf0e10cSrcweir     int*            mpChars2Glyphs;     // map rel char pos to abs glyph pos
207*cdf0e10cSrcweir     int*            mpGlyphs2Chars;     // map abs glyph pos to abs char pos
208*cdf0e10cSrcweir     bool*           mpGlyphRTLFlags;    // BiDi status for glyphs: true=>RTL
209*cdf0e10cSrcweir     mutable long    mnWidth;
210*cdf0e10cSrcweir     bool            mbDisableGlyphs;
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir     int             mnNotdefWidth;
213*cdf0e10cSrcweir     BYTE            mnCharSet;
214*cdf0e10cSrcweir };
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir // =======================================================================
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir WinLayout::WinLayout( HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE )
219*cdf0e10cSrcweir :   mhDC( hDC ),
220*cdf0e10cSrcweir     mhFont( (HFONT)::GetCurrentObject(hDC,OBJ_FONT) ),
221*cdf0e10cSrcweir     mnBaseAdv( 0 ),
222*cdf0e10cSrcweir     mfFontScale( 1.0 ),
223*cdf0e10cSrcweir     mrWinFontData( rWFD ),
224*cdf0e10cSrcweir     mrWinFontEntry( rWFE )
225*cdf0e10cSrcweir {}
226*cdf0e10cSrcweir 
227*cdf0e10cSrcweir // -----------------------------------------------------------------------
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir void WinLayout::InitFont() const
230*cdf0e10cSrcweir {
231*cdf0e10cSrcweir     ::SelectObject( mhDC, mhFont );
232*cdf0e10cSrcweir }
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir // -----------------------------------------------------------------------
235*cdf0e10cSrcweir 
236*cdf0e10cSrcweir // Using reasonably sized fonts to emulate huge fonts works around
237*cdf0e10cSrcweir // a lot of problems in printer and display drivers. Huge fonts are
238*cdf0e10cSrcweir // mostly used by high resolution reference devices which are never
239*cdf0e10cSrcweir // painted to anyway. In the rare case that a huge font needs to be
240*cdf0e10cSrcweir // displayed somewhere then the workaround doesn't help anymore.
241*cdf0e10cSrcweir // If the drivers fail silently for huge fonts, so be it...
242*cdf0e10cSrcweir HFONT WinLayout::DisableFontScaling() const
243*cdf0e10cSrcweir {
244*cdf0e10cSrcweir     if( mfFontScale == 1.0 )
245*cdf0e10cSrcweir         return 0;
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir     LOGFONTW aLogFont;
248*cdf0e10cSrcweir     ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
249*cdf0e10cSrcweir     aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
250*cdf0e10cSrcweir     aLogFont.lfWidth  = (LONG)(mfFontScale * aLogFont.lfWidth);
251*cdf0e10cSrcweir     HFONT hHugeFont = ::CreateFontIndirectW( &aLogFont);
252*cdf0e10cSrcweir     if( !hHugeFont )
253*cdf0e10cSrcweir         return 0;
254*cdf0e10cSrcweir 
255*cdf0e10cSrcweir     return SelectFont( mhDC, hHugeFont );
256*cdf0e10cSrcweir }
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir // =======================================================================
259*cdf0e10cSrcweir 
260*cdf0e10cSrcweir SimpleWinLayout::SimpleWinLayout( HDC hDC, BYTE nCharSet,
261*cdf0e10cSrcweir     const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
262*cdf0e10cSrcweir :   WinLayout( hDC, rWinFontData, rWinFontEntry ),
263*cdf0e10cSrcweir     mnGlyphCount( 0 ),
264*cdf0e10cSrcweir     mnCharCount( 0 ),
265*cdf0e10cSrcweir     mpOutGlyphs( NULL ),
266*cdf0e10cSrcweir     mpGlyphAdvances( NULL ),
267*cdf0e10cSrcweir     mpGlyphOrigAdvs( NULL ),
268*cdf0e10cSrcweir     mpCharWidths( NULL ),
269*cdf0e10cSrcweir     mpChars2Glyphs( NULL ),
270*cdf0e10cSrcweir     mpGlyphs2Chars( NULL ),
271*cdf0e10cSrcweir     mpGlyphRTLFlags( NULL ),
272*cdf0e10cSrcweir     mnWidth( 0 ),
273*cdf0e10cSrcweir     mnNotdefWidth( -1 ),
274*cdf0e10cSrcweir     mnCharSet( nCharSet ),
275*cdf0e10cSrcweir     mbDisableGlyphs( false )
276*cdf0e10cSrcweir {
277*cdf0e10cSrcweir     mbDisableGlyphs = true;
278*cdf0e10cSrcweir }
279*cdf0e10cSrcweir 
280*cdf0e10cSrcweir // -----------------------------------------------------------------------
281*cdf0e10cSrcweir 
282*cdf0e10cSrcweir SimpleWinLayout::~SimpleWinLayout()
283*cdf0e10cSrcweir {
284*cdf0e10cSrcweir     delete[] mpGlyphRTLFlags;
285*cdf0e10cSrcweir     delete[] mpGlyphs2Chars;
286*cdf0e10cSrcweir     delete[] mpChars2Glyphs;
287*cdf0e10cSrcweir     if( mpCharWidths != mpGlyphAdvances )
288*cdf0e10cSrcweir         delete[] mpCharWidths;
289*cdf0e10cSrcweir     delete[] mpGlyphOrigAdvs;
290*cdf0e10cSrcweir     delete[] mpGlyphAdvances;
291*cdf0e10cSrcweir     delete[] mpOutGlyphs;
292*cdf0e10cSrcweir }
293*cdf0e10cSrcweir 
294*cdf0e10cSrcweir // -----------------------------------------------------------------------
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
297*cdf0e10cSrcweir {
298*cdf0e10cSrcweir     // prepare layout
299*cdf0e10cSrcweir     // TODO: fix case when recyclying old SimpleWinLayout object
300*cdf0e10cSrcweir     mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
301*cdf0e10cSrcweir     mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
302*cdf0e10cSrcweir 
303*cdf0e10cSrcweir     if( !mbDisableGlyphs )
304*cdf0e10cSrcweir     {
305*cdf0e10cSrcweir         // Win32 glyph APIs have serious problems with vertical layout
306*cdf0e10cSrcweir         // => workaround is to use the unicode methods then
307*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
308*cdf0e10cSrcweir             mbDisableGlyphs = true;
309*cdf0e10cSrcweir         else
310*cdf0e10cSrcweir             // use cached value from font face
311*cdf0e10cSrcweir             mbDisableGlyphs = mrWinFontData.IsGlyphApiDisabled();
312*cdf0e10cSrcweir     }
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir     // TODO: use a cached value for bDisableAsianKern from upper layers
315*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
316*cdf0e10cSrcweir     {
317*cdf0e10cSrcweir         TEXTMETRICA aTextMetricA;
318*cdf0e10cSrcweir         if( ::GetTextMetricsA( mhDC, &aTextMetricA )
319*cdf0e10cSrcweir         && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) )
320*cdf0e10cSrcweir             rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
321*cdf0e10cSrcweir     }
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir     // layout text
324*cdf0e10cSrcweir     int i, j;
325*cdf0e10cSrcweir 
326*cdf0e10cSrcweir     mnGlyphCount = 0;
327*cdf0e10cSrcweir     bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir     // count the number of chars to process if no RTL run
330*cdf0e10cSrcweir     rArgs.ResetPos();
331*cdf0e10cSrcweir     bool bHasRTL = false;
332*cdf0e10cSrcweir     while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
333*cdf0e10cSrcweir         mnGlyphCount += j - i;
334*cdf0e10cSrcweir 
335*cdf0e10cSrcweir     // if there are RTL runs we need room to remember individual BiDi flags
336*cdf0e10cSrcweir     if( bHasRTL )
337*cdf0e10cSrcweir     {
338*cdf0e10cSrcweir         mpGlyphRTLFlags = new bool[ mnCharCount ];
339*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
340*cdf0e10cSrcweir             mpGlyphRTLFlags[i] = false;
341*cdf0e10cSrcweir     }
342*cdf0e10cSrcweir 
343*cdf0e10cSrcweir     // rewrite the logical string if needed to prepare for the API calls
344*cdf0e10cSrcweir     const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
345*cdf0e10cSrcweir     if( (mnGlyphCount != mnCharCount) || bVertical )
346*cdf0e10cSrcweir     {
347*cdf0e10cSrcweir         // we need to rewrite the pBidiStr when any of
348*cdf0e10cSrcweir         // - BiDirectional layout
349*cdf0e10cSrcweir         // - vertical layout
350*cdf0e10cSrcweir         // - partial runs (e.g. with control chars or for glyph fallback)
351*cdf0e10cSrcweir         // are involved
352*cdf0e10cSrcweir         sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
353*cdf0e10cSrcweir         pBidiStr = pRewrittenStr;
354*cdf0e10cSrcweir 
355*cdf0e10cSrcweir         // note: glyph to char mapping is relative to first character
356*cdf0e10cSrcweir         mpChars2Glyphs = new int[ mnCharCount ];
357*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnCharCount ];
358*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
359*cdf0e10cSrcweir             mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir         mnGlyphCount = 0;
362*cdf0e10cSrcweir         rArgs.ResetPos();
363*cdf0e10cSrcweir         bool bIsRTL = false;
364*cdf0e10cSrcweir         while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
365*cdf0e10cSrcweir         {
366*cdf0e10cSrcweir             do
367*cdf0e10cSrcweir             {
368*cdf0e10cSrcweir                 // get the next leftmost character in this run
369*cdf0e10cSrcweir                 int nCharPos = bIsRTL ? --j : i++;
370*cdf0e10cSrcweir                 sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
371*cdf0e10cSrcweir 
372*cdf0e10cSrcweir                 // in the RTL case mirror the character and remember its RTL status
373*cdf0e10cSrcweir                 if( bIsRTL )
374*cdf0e10cSrcweir                 {
375*cdf0e10cSrcweir                     cChar = ::GetMirroredChar( cChar );
376*cdf0e10cSrcweir                     mpGlyphRTLFlags[ mnGlyphCount ] = true;
377*cdf0e10cSrcweir                 }
378*cdf0e10cSrcweir 
379*cdf0e10cSrcweir                 // for vertical writing use vertical alternatives
380*cdf0e10cSrcweir                 if( bVertical )
381*cdf0e10cSrcweir                 {
382*cdf0e10cSrcweir                     sal_UCS4 cVert = ::GetVerticalChar( cChar );
383*cdf0e10cSrcweir                     if( cVert )
384*cdf0e10cSrcweir                         cChar = cVert;
385*cdf0e10cSrcweir                 }
386*cdf0e10cSrcweir 
387*cdf0e10cSrcweir                 // rewrite the original string
388*cdf0e10cSrcweir                 // update the mappings between original and rewritten string
389*cdf0e10cSrcweir 	       	// TODO: support surrogates in rewritten strings
390*cdf0e10cSrcweir                 pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar);
391*cdf0e10cSrcweir                 mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
392*cdf0e10cSrcweir                 mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
393*cdf0e10cSrcweir                 ++mnGlyphCount;
394*cdf0e10cSrcweir             } while( i < j );
395*cdf0e10cSrcweir         }
396*cdf0e10cSrcweir     }
397*cdf0e10cSrcweir 
398*cdf0e10cSrcweir     mpOutGlyphs     = new WCHAR[ mnGlyphCount ];
399*cdf0e10cSrcweir     mpGlyphAdvances = new int[ mnGlyphCount ];
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir     if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
402*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir #ifndef GCP_KERN_HACK
405*cdf0e10cSrcweir     DWORD nGcpOption = 0;
406*cdf0e10cSrcweir     // enable kerning if requested
407*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
408*cdf0e10cSrcweir         nGcpOption |= GCP_USEKERNING;
409*cdf0e10cSrcweir #endif // GCP_KERN_HACK
410*cdf0e10cSrcweir 
411*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
412*cdf0e10cSrcweir         mpOutGlyphs[i] = pBidiStr[ i ];
413*cdf0e10cSrcweir     mnWidth = 0;
414*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
415*cdf0e10cSrcweir     {
416*cdf0e10cSrcweir         // get the current UCS-4 code point, check for surrogate pairs
417*cdf0e10cSrcweir         const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]);
418*cdf0e10cSrcweir         unsigned nCharCode = pCodes[0];
419*cdf0e10cSrcweir         bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF));
420*cdf0e10cSrcweir         if( bSurrogate )
421*cdf0e10cSrcweir         {
422*cdf0e10cSrcweir             if( nCharCode >= 0xDC00 ) // this part of a surrogate pair was already processed
423*cdf0e10cSrcweir                 continue;
424*cdf0e10cSrcweir             nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00);
425*cdf0e10cSrcweir 	}
426*cdf0e10cSrcweir 
427*cdf0e10cSrcweir         // get the advance width for the current UCS-4 code point
428*cdf0e10cSrcweir         int nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode );
429*cdf0e10cSrcweir         if( nGlyphWidth == -1 )
430*cdf0e10cSrcweir         {
431*cdf0e10cSrcweir             ABC aABC;
432*cdf0e10cSrcweir             SIZE aExtent;
433*cdf0e10cSrcweir             if( ::GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) )
434*cdf0e10cSrcweir                 nGlyphWidth = aExtent.cx;
435*cdf0e10cSrcweir             else if( ::GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) )
436*cdf0e10cSrcweir                 nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC;
437*cdf0e10cSrcweir             else if( !::GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth )
438*cdf0e10cSrcweir                  &&  !::GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) )
439*cdf0e10cSrcweir                     nGlyphWidth = 0;
440*cdf0e10cSrcweir             mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
441*cdf0e10cSrcweir         }
442*cdf0e10cSrcweir         mpGlyphAdvances[ i ] = nGlyphWidth;
443*cdf0e10cSrcweir         mnWidth += nGlyphWidth;
444*cdf0e10cSrcweir 
445*cdf0e10cSrcweir         // remaining codes of surrogate pair get a zero width
446*cdf0e10cSrcweir         if( bSurrogate && ((i+1) < mnGlyphCount) )
447*cdf0e10cSrcweir             mpGlyphAdvances[ i+1 ] = 0;
448*cdf0e10cSrcweir 
449*cdf0e10cSrcweir         // check with the font face if glyph fallback is needed
450*cdf0e10cSrcweir         if( mrWinFontData.HasChar( nCharCode ) )
451*cdf0e10cSrcweir             continue;
452*cdf0e10cSrcweir 
453*cdf0e10cSrcweir         // request glyph fallback at this position in the string
454*cdf0e10cSrcweir         bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
455*cdf0e10cSrcweir         int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
456*cdf0e10cSrcweir         rArgs.NeedFallback( nCharPos, bRTL );
457*cdf0e10cSrcweir         if( bSurrogate && ((nCharPos+1) < rArgs.mnLength) )
458*cdf0e10cSrcweir             rArgs.NeedFallback( nCharPos+1, bRTL );
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir         // replace the current glyph shape with the NotDef glyph shape
461*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
462*cdf0e10cSrcweir         {
463*cdf0e10cSrcweir             // when we already are layouting for glyph fallback
464*cdf0e10cSrcweir             // then a new unresolved glyph is not interesting
465*cdf0e10cSrcweir             mnNotdefWidth = 0;
466*cdf0e10cSrcweir             mpOutGlyphs[i] = DROPPED_OUTGLYPH;
467*cdf0e10cSrcweir         }
468*cdf0e10cSrcweir         else
469*cdf0e10cSrcweir         {
470*cdf0e10cSrcweir             if( mnNotdefWidth < 0 )
471*cdf0e10cSrcweir             {
472*cdf0e10cSrcweir                 // get the width of the NotDef glyph
473*cdf0e10cSrcweir                 SIZE aExtent;
474*cdf0e10cSrcweir                 WCHAR cNotDef = rArgs.mpStr[ nCharPos ];
475*cdf0e10cSrcweir                 mnNotdefWidth = 0;
476*cdf0e10cSrcweir                 if( ::GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) )
477*cdf0e10cSrcweir                     mnNotdefWidth = aExtent.cx;
478*cdf0e10cSrcweir             }
479*cdf0e10cSrcweir             // use a better NotDef glyph
480*cdf0e10cSrcweir             if( !mbDisableGlyphs && !bSurrogate )
481*cdf0e10cSrcweir                 mpOutGlyphs[i] = 0;
482*cdf0e10cSrcweir         }
483*cdf0e10cSrcweir         if( bSurrogate && ((i+1) < mnGlyphCount) )
484*cdf0e10cSrcweir             mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir         // adjust the current glyph width to the NotDef glyph width
487*cdf0e10cSrcweir         mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
488*cdf0e10cSrcweir         mpGlyphAdvances[i] = mnNotdefWidth;
489*cdf0e10cSrcweir         if( mpGlyphOrigAdvs )
490*cdf0e10cSrcweir             mpGlyphOrigAdvs[i] = mnNotdefWidth;
491*cdf0e10cSrcweir     }
492*cdf0e10cSrcweir 
493*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
494*cdf0e10cSrcweir     // apply kerning if the layout engine has not yet done it
495*cdf0e10cSrcweir     if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
496*cdf0e10cSrcweir     {
497*cdf0e10cSrcweir #else // GCP_KERN_HACK
498*cdf0e10cSrcweir     // apply just asian kerning
499*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
500*cdf0e10cSrcweir     {
501*cdf0e10cSrcweir         if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
502*cdf0e10cSrcweir #endif // GCP_KERN_HACK
503*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
504*cdf0e10cSrcweir                 mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir         // #99658# also apply asian kerning on the substring border
507*cdf0e10cSrcweir         int nLen = mnGlyphCount;
508*cdf0e10cSrcweir         if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
509*cdf0e10cSrcweir             ++nLen;
510*cdf0e10cSrcweir         for( i = 1; i < nLen; ++i )
511*cdf0e10cSrcweir         {
512*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
513*cdf0e10cSrcweir             if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
514*cdf0e10cSrcweir             {
515*cdf0e10cSrcweir                 int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
516*cdf0e10cSrcweir                 mpGlyphAdvances[ i-1 ] += nKernAmount;
517*cdf0e10cSrcweir                 mnWidth += nKernAmount;
518*cdf0e10cSrcweir             }
519*cdf0e10cSrcweir             else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
520*cdf0e10cSrcweir #endif // GCP_KERN_HACK
521*cdf0e10cSrcweir 
522*cdf0e10cSrcweir             if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1])))
523*cdf0e10cSrcweir             &&  ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) )
524*cdf0e10cSrcweir             {
525*cdf0e10cSrcweir                 long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
526*cdf0e10cSrcweir                 long nKernNext  = -CalcAsianKerning( pBidiStr[i], false, bVertical );
527*cdf0e10cSrcweir 
528*cdf0e10cSrcweir                 long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
529*cdf0e10cSrcweir                 if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
530*cdf0e10cSrcweir                 {
531*cdf0e10cSrcweir                     nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
532*cdf0e10cSrcweir                     mpGlyphAdvances[i-1] += nDelta;
533*cdf0e10cSrcweir                     mnWidth += nDelta;
534*cdf0e10cSrcweir                 }
535*cdf0e10cSrcweir             }
536*cdf0e10cSrcweir         }
537*cdf0e10cSrcweir     }
538*cdf0e10cSrcweir 
539*cdf0e10cSrcweir     // calculate virtual char widths
540*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
541*cdf0e10cSrcweir         mpCharWidths = mpGlyphAdvances;
542*cdf0e10cSrcweir     else
543*cdf0e10cSrcweir     {
544*cdf0e10cSrcweir         mpCharWidths = new int[ mnCharCount ];
545*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
546*cdf0e10cSrcweir             mpCharWidths[ i ] = 0;
547*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
548*cdf0e10cSrcweir         {
549*cdf0e10cSrcweir             int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
550*cdf0e10cSrcweir             if( j >= 0 )
551*cdf0e10cSrcweir                 mpCharWidths[ j ] += mpGlyphAdvances[ i ];
552*cdf0e10cSrcweir         }
553*cdf0e10cSrcweir     }
554*cdf0e10cSrcweir 
555*cdf0e10cSrcweir     // scale layout metrics if needed
556*cdf0e10cSrcweir 	// TODO: does it make the code more simple if the metric scaling
557*cdf0e10cSrcweir 	// is moved to the methods that need metric scaling (e.g. FillDXArray())?
558*cdf0e10cSrcweir     if( mfFontScale != 1.0 )
559*cdf0e10cSrcweir     {
560*cdf0e10cSrcweir         mnWidth   = (long)(mnWidth * mfFontScale);
561*cdf0e10cSrcweir         mnBaseAdv = (int)(mnBaseAdv * mfFontScale);
562*cdf0e10cSrcweir         for( i = 0; i < mnCharCount; ++i )
563*cdf0e10cSrcweir             mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
564*cdf0e10cSrcweir         if( mpGlyphAdvances != mpCharWidths )
565*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
566*cdf0e10cSrcweir                 mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
567*cdf0e10cSrcweir         if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
568*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
569*cdf0e10cSrcweir                 mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale);
570*cdf0e10cSrcweir     }
571*cdf0e10cSrcweir 
572*cdf0e10cSrcweir     return true;
573*cdf0e10cSrcweir }
574*cdf0e10cSrcweir 
575*cdf0e10cSrcweir // -----------------------------------------------------------------------
576*cdf0e10cSrcweir 
577*cdf0e10cSrcweir int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart,
578*cdf0e10cSrcweir     long* pGlyphAdvances, int* pCharIndexes ) const
579*cdf0e10cSrcweir {
580*cdf0e10cSrcweir     // return zero if no more glyph found
581*cdf0e10cSrcweir     if( nStart >= mnGlyphCount )
582*cdf0e10cSrcweir         return 0;
583*cdf0e10cSrcweir 
584*cdf0e10cSrcweir     // calculate glyph position relative to layout base
585*cdf0e10cSrcweir     // TODO: avoid for nStart!=0 case by reusing rPos
586*cdf0e10cSrcweir     long nXOffset = mnBaseAdv;
587*cdf0e10cSrcweir     for( int i = 0; i < nStart; ++i )
588*cdf0e10cSrcweir         nXOffset += mpGlyphAdvances[ i ];
589*cdf0e10cSrcweir 
590*cdf0e10cSrcweir     // calculate absolute position in pixel units
591*cdf0e10cSrcweir     Point aRelativePos( nXOffset, 0 );
592*cdf0e10cSrcweir     rPos = GetDrawPosition( aRelativePos );
593*cdf0e10cSrcweir 
594*cdf0e10cSrcweir     int nCount = 0;
595*cdf0e10cSrcweir     while( nCount < nLen )
596*cdf0e10cSrcweir     {
597*cdf0e10cSrcweir         // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
598*cdf0e10cSrcweir         sal_GlyphId nGlyphIndex = mpOutGlyphs[ nStart ];
599*cdf0e10cSrcweir         if( mbDisableGlyphs )
600*cdf0e10cSrcweir         {
601*cdf0e10cSrcweir             if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
602*cdf0e10cSrcweir             {
603*cdf0e10cSrcweir                 const sal_UCS4 cChar = static_cast<sal_UCS4>(nGlyphIndex & GF_IDXMASK);
604*cdf0e10cSrcweir                 if( mrWinFontData.HasGSUBstitutions( mhDC )
605*cdf0e10cSrcweir                 &&  mrWinFontData.IsGSUBstituted( cChar ) )
606*cdf0e10cSrcweir                     nGlyphIndex |= GF_GSUB | GF_ROTL;
607*cdf0e10cSrcweir                 else
608*cdf0e10cSrcweir                 {
609*cdf0e10cSrcweir                     nGlyphIndex |= GetVerticalFlags( cChar );
610*cdf0e10cSrcweir                     if( (nGlyphIndex & GF_ROTMASK) == 0 )
611*cdf0e10cSrcweir                         nGlyphIndex |= GF_VERT;
612*cdf0e10cSrcweir                 }
613*cdf0e10cSrcweir             }
614*cdf0e10cSrcweir             nGlyphIndex |= GF_ISCHAR;
615*cdf0e10cSrcweir         }
616*cdf0e10cSrcweir         ++nCount;
617*cdf0e10cSrcweir         *(pGlyphs++) = nGlyphIndex;
618*cdf0e10cSrcweir         if( pGlyphAdvances )
619*cdf0e10cSrcweir             *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
620*cdf0e10cSrcweir         if( pCharIndexes )
621*cdf0e10cSrcweir         {
622*cdf0e10cSrcweir             int nCharPos;
623*cdf0e10cSrcweir             if( !mpGlyphs2Chars )
624*cdf0e10cSrcweir                 nCharPos = nStart + mnMinCharPos;
625*cdf0e10cSrcweir             else
626*cdf0e10cSrcweir                 nCharPos = mpGlyphs2Chars[nStart];
627*cdf0e10cSrcweir             *(pCharIndexes++) = nCharPos;
628*cdf0e10cSrcweir         }
629*cdf0e10cSrcweir 
630*cdf0e10cSrcweir         // stop at last glyph
631*cdf0e10cSrcweir         if( ++nStart >= mnGlyphCount )
632*cdf0e10cSrcweir             break;
633*cdf0e10cSrcweir 
634*cdf0e10cSrcweir         // stop when next x-position is unexpected
635*cdf0e10cSrcweir         if( !pGlyphAdvances && mpGlyphOrigAdvs )
636*cdf0e10cSrcweir             if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
637*cdf0e10cSrcweir                 break;
638*cdf0e10cSrcweir     }
639*cdf0e10cSrcweir 
640*cdf0e10cSrcweir     return nCount;
641*cdf0e10cSrcweir }
642*cdf0e10cSrcweir 
643*cdf0e10cSrcweir // -----------------------------------------------------------------------
644*cdf0e10cSrcweir 
645*cdf0e10cSrcweir void SimpleWinLayout::DrawText( SalGraphics& rGraphics ) const
646*cdf0e10cSrcweir {
647*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
648*cdf0e10cSrcweir         return;
649*cdf0e10cSrcweir 
650*cdf0e10cSrcweir     WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
651*cdf0e10cSrcweir     HDC aHDC = rWinGraphics.mhDC;
652*cdf0e10cSrcweir 
653*cdf0e10cSrcweir     HFONT hOrigFont = DisableFontScaling();
654*cdf0e10cSrcweir 
655*cdf0e10cSrcweir     UINT mnDrawOptions = ETO_GLYPH_INDEX;
656*cdf0e10cSrcweir     if( mbDisableGlyphs )
657*cdf0e10cSrcweir         mnDrawOptions = 0;
658*cdf0e10cSrcweir 
659*cdf0e10cSrcweir     Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
660*cdf0e10cSrcweir 
661*cdf0e10cSrcweir     // #108267#, break up into glyph portions of a limited size required by Win32 API
662*cdf0e10cSrcweir     const unsigned int maxGlyphCount = 8192;
663*cdf0e10cSrcweir     UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
664*cdf0e10cSrcweir     UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir     if( numGlyphPortions )
667*cdf0e10cSrcweir     {
668*cdf0e10cSrcweir         // #108267#,#109387# break up string into smaller chunks
669*cdf0e10cSrcweir         // the output positions will be updated by windows (SetTextAlign)
670*cdf0e10cSrcweir         POINT oldPos;
671*cdf0e10cSrcweir         UINT oldTa = ::GetTextAlign( aHDC );
672*cdf0e10cSrcweir         ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP );
673*cdf0e10cSrcweir         ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos );
674*cdf0e10cSrcweir         unsigned int i = 0;
675*cdf0e10cSrcweir         for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount )
676*cdf0e10cSrcweir             ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
677*cdf0e10cSrcweir                 mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i );
678*cdf0e10cSrcweir         ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
679*cdf0e10cSrcweir             mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i );
680*cdf0e10cSrcweir         ::MoveToEx( aHDC, oldPos.x, oldPos.y, (LPPOINT) NULL);
681*cdf0e10cSrcweir         ::SetTextAlign( aHDC, oldTa );
682*cdf0e10cSrcweir     }
683*cdf0e10cSrcweir     else
684*cdf0e10cSrcweir         ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), mnDrawOptions, NULL,
685*cdf0e10cSrcweir             mpOutGlyphs, mnGlyphCount, mpGlyphAdvances );
686*cdf0e10cSrcweir 
687*cdf0e10cSrcweir     if( hOrigFont )
688*cdf0e10cSrcweir         DeleteFont( SelectFont( aHDC, hOrigFont ) );
689*cdf0e10cSrcweir }
690*cdf0e10cSrcweir 
691*cdf0e10cSrcweir // -----------------------------------------------------------------------
692*cdf0e10cSrcweir 
693*cdf0e10cSrcweir long SimpleWinLayout::FillDXArray( long* pDXArray ) const
694*cdf0e10cSrcweir {
695*cdf0e10cSrcweir     if( !mnWidth )
696*cdf0e10cSrcweir     {
697*cdf0e10cSrcweir         long mnWidth = mnBaseAdv;
698*cdf0e10cSrcweir         for( int i = 0; i < mnGlyphCount; ++i )
699*cdf0e10cSrcweir             mnWidth += mpGlyphAdvances[ i ];
700*cdf0e10cSrcweir     }
701*cdf0e10cSrcweir 
702*cdf0e10cSrcweir     if( pDXArray != NULL )
703*cdf0e10cSrcweir     {
704*cdf0e10cSrcweir         for( int i = 0; i < mnCharCount; ++i )
705*cdf0e10cSrcweir              pDXArray[ i ] = mpCharWidths[ i ];
706*cdf0e10cSrcweir     }
707*cdf0e10cSrcweir 
708*cdf0e10cSrcweir     return mnWidth;
709*cdf0e10cSrcweir }
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir // -----------------------------------------------------------------------
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir int SimpleWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
714*cdf0e10cSrcweir // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
715*cdf0e10cSrcweir {
716*cdf0e10cSrcweir     if( mnWidth )
717*cdf0e10cSrcweir         if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
718*cdf0e10cSrcweir             return STRING_LEN;
719*cdf0e10cSrcweir 
720*cdf0e10cSrcweir     long nExtraWidth = mnBaseAdv * nFactor;
721*cdf0e10cSrcweir     for( int n = 0; n < mnCharCount; ++n )
722*cdf0e10cSrcweir     {
723*cdf0e10cSrcweir         // skip unused characters
724*cdf0e10cSrcweir         if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
725*cdf0e10cSrcweir             continue;
726*cdf0e10cSrcweir         // add char widths until max
727*cdf0e10cSrcweir         nExtraWidth += mpCharWidths[ n ] * nFactor;
728*cdf0e10cSrcweir         if( nExtraWidth >= nMaxWidth )
729*cdf0e10cSrcweir             return (mnMinCharPos + n);
730*cdf0e10cSrcweir         nExtraWidth += nCharExtra;
731*cdf0e10cSrcweir     }
732*cdf0e10cSrcweir 
733*cdf0e10cSrcweir     return STRING_LEN;
734*cdf0e10cSrcweir }
735*cdf0e10cSrcweir 
736*cdf0e10cSrcweir // -----------------------------------------------------------------------
737*cdf0e10cSrcweir 
738*cdf0e10cSrcweir void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
739*cdf0e10cSrcweir {
740*cdf0e10cSrcweir     long nXPos = mnBaseAdv;
741*cdf0e10cSrcweir 
742*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
743*cdf0e10cSrcweir     {
744*cdf0e10cSrcweir         for( int i = 0; i < nMaxIdx; i += 2 )
745*cdf0e10cSrcweir         {
746*cdf0e10cSrcweir             pCaretXArray[ i ] = nXPos;
747*cdf0e10cSrcweir             nXPos += mpGlyphAdvances[ i>>1 ];
748*cdf0e10cSrcweir             pCaretXArray[ i+1 ] = nXPos;
749*cdf0e10cSrcweir         }
750*cdf0e10cSrcweir     }
751*cdf0e10cSrcweir     else
752*cdf0e10cSrcweir     {
753*cdf0e10cSrcweir         int  i;
754*cdf0e10cSrcweir         for( i = 0; i < nMaxIdx; ++i )
755*cdf0e10cSrcweir             pCaretXArray[ i ] = -1;
756*cdf0e10cSrcweir 
757*cdf0e10cSrcweir         // assign glyph positions to character positions
758*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
759*cdf0e10cSrcweir         {
760*cdf0e10cSrcweir             int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
761*cdf0e10cSrcweir             long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
762*cdf0e10cSrcweir             nCurrIdx *= 2;
763*cdf0e10cSrcweir             if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
764*cdf0e10cSrcweir             {
765*cdf0e10cSrcweir                 // normal positions for LTR case
766*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = nXPos;
767*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = nXRight;
768*cdf0e10cSrcweir             }
769*cdf0e10cSrcweir             else
770*cdf0e10cSrcweir             {
771*cdf0e10cSrcweir                 // reverse positions for RTL case
772*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = nXRight;
773*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = nXPos;
774*cdf0e10cSrcweir             }
775*cdf0e10cSrcweir             nXPos += mpGlyphAdvances[ i ];
776*cdf0e10cSrcweir         }
777*cdf0e10cSrcweir     }
778*cdf0e10cSrcweir }
779*cdf0e10cSrcweir 
780*cdf0e10cSrcweir // -----------------------------------------------------------------------
781*cdf0e10cSrcweir 
782*cdf0e10cSrcweir void SimpleWinLayout::Justify( long nNewWidth )
783*cdf0e10cSrcweir {
784*cdf0e10cSrcweir     long nOldWidth = mnWidth;
785*cdf0e10cSrcweir     mnWidth = nNewWidth;
786*cdf0e10cSrcweir 
787*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
788*cdf0e10cSrcweir         return;
789*cdf0e10cSrcweir 
790*cdf0e10cSrcweir     if( nNewWidth == nOldWidth )
791*cdf0e10cSrcweir         return;
792*cdf0e10cSrcweir 
793*cdf0e10cSrcweir     // the rightmost glyph cannot be stretched
794*cdf0e10cSrcweir     const int nRight = mnGlyphCount - 1;
795*cdf0e10cSrcweir     nOldWidth -= mpGlyphAdvances[ nRight ];
796*cdf0e10cSrcweir     nNewWidth -= mpGlyphAdvances[ nRight ];
797*cdf0e10cSrcweir 
798*cdf0e10cSrcweir     // count stretchable glyphs
799*cdf0e10cSrcweir     int nStretchable = 0, i;
800*cdf0e10cSrcweir     for( i = 0; i < nRight; ++i )
801*cdf0e10cSrcweir         if( mpGlyphAdvances[i] >= 0 )
802*cdf0e10cSrcweir             ++nStretchable;
803*cdf0e10cSrcweir 
804*cdf0e10cSrcweir     // stretch these glyphs
805*cdf0e10cSrcweir     int nDiffWidth = nNewWidth - nOldWidth;
806*cdf0e10cSrcweir     for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
807*cdf0e10cSrcweir     {
808*cdf0e10cSrcweir         if( mpGlyphAdvances[i] <= 0 )
809*cdf0e10cSrcweir             continue;
810*cdf0e10cSrcweir         int nDeltaWidth = nDiffWidth / nStretchable;
811*cdf0e10cSrcweir         mpGlyphAdvances[i] += nDeltaWidth;
812*cdf0e10cSrcweir         --nStretchable;
813*cdf0e10cSrcweir         nDiffWidth -= nDeltaWidth;
814*cdf0e10cSrcweir     }
815*cdf0e10cSrcweir }
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir // -----------------------------------------------------------------------
818*cdf0e10cSrcweir 
819*cdf0e10cSrcweir void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
820*cdf0e10cSrcweir {
821*cdf0e10cSrcweir     SalLayout::AdjustLayout( rArgs );
822*cdf0e10cSrcweir 
823*cdf0e10cSrcweir     // adjust positions if requested
824*cdf0e10cSrcweir     if( rArgs.mpDXArray )
825*cdf0e10cSrcweir         ApplyDXArray( rArgs );
826*cdf0e10cSrcweir     else if( rArgs.mnLayoutWidth )
827*cdf0e10cSrcweir         Justify( rArgs.mnLayoutWidth );
828*cdf0e10cSrcweir     else
829*cdf0e10cSrcweir         return;
830*cdf0e10cSrcweir 
831*cdf0e10cSrcweir     // recalculate virtual char widths if they were changed
832*cdf0e10cSrcweir     if( mpCharWidths != mpGlyphAdvances )
833*cdf0e10cSrcweir     {
834*cdf0e10cSrcweir         int i;
835*cdf0e10cSrcweir         if( !mpGlyphs2Chars )
836*cdf0e10cSrcweir         {
837*cdf0e10cSrcweir             // standard LTR case
838*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
839*cdf0e10cSrcweir                  mpCharWidths[ i ] = mpGlyphAdvances[ i ];
840*cdf0e10cSrcweir         }
841*cdf0e10cSrcweir         else
842*cdf0e10cSrcweir         {
843*cdf0e10cSrcweir             // BiDi or complex case
844*cdf0e10cSrcweir             for( i = 0; i < mnCharCount; ++i )
845*cdf0e10cSrcweir                 mpCharWidths[ i ] = 0;
846*cdf0e10cSrcweir             for( i = 0; i < mnGlyphCount; ++i )
847*cdf0e10cSrcweir             {
848*cdf0e10cSrcweir                 int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
849*cdf0e10cSrcweir                 if( j >= 0 )
850*cdf0e10cSrcweir                     mpCharWidths[ j ] += mpGlyphAdvances[ i ];
851*cdf0e10cSrcweir             }
852*cdf0e10cSrcweir         }
853*cdf0e10cSrcweir     }
854*cdf0e10cSrcweir }
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir // -----------------------------------------------------------------------
857*cdf0e10cSrcweir 
858*cdf0e10cSrcweir void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
859*cdf0e10cSrcweir {
860*cdf0e10cSrcweir     // try to avoid disturbance of text flow for LSB rounding case;
861*cdf0e10cSrcweir     const long* pDXArray = rArgs.mpDXArray;
862*cdf0e10cSrcweir 
863*cdf0e10cSrcweir     int i = 0;
864*cdf0e10cSrcweir     long nOldWidth = mnBaseAdv;
865*cdf0e10cSrcweir     for(; i < mnCharCount; ++i )
866*cdf0e10cSrcweir     {
867*cdf0e10cSrcweir         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
868*cdf0e10cSrcweir         if( j >= 0 )
869*cdf0e10cSrcweir         {
870*cdf0e10cSrcweir             nOldWidth += mpGlyphAdvances[ j ];
871*cdf0e10cSrcweir             int nDiff = nOldWidth - pDXArray[ i ];
872*cdf0e10cSrcweir 
873*cdf0e10cSrcweir             // disabled because of #104768#
874*cdf0e10cSrcweir             // works great for static text, but problems when typing
875*cdf0e10cSrcweir             // if( nDiff>+1 || nDiff<-1 )
876*cdf0e10cSrcweir             // only bother with changing anything when something moved
877*cdf0e10cSrcweir             if( nDiff != 0 )
878*cdf0e10cSrcweir                 break;
879*cdf0e10cSrcweir         }
880*cdf0e10cSrcweir     }
881*cdf0e10cSrcweir     if( i >= mnCharCount )
882*cdf0e10cSrcweir         return;
883*cdf0e10cSrcweir 
884*cdf0e10cSrcweir     if( !mpGlyphOrigAdvs )
885*cdf0e10cSrcweir     {
886*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
887*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
888*cdf0e10cSrcweir             mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
889*cdf0e10cSrcweir     }
890*cdf0e10cSrcweir 
891*cdf0e10cSrcweir     mnWidth = mnBaseAdv;
892*cdf0e10cSrcweir     for( i = 0; i < mnCharCount; ++i )
893*cdf0e10cSrcweir     {
894*cdf0e10cSrcweir         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
895*cdf0e10cSrcweir         if( j >= 0 )
896*cdf0e10cSrcweir             mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
897*cdf0e10cSrcweir         mnWidth = pDXArray[i];
898*cdf0e10cSrcweir     }
899*cdf0e10cSrcweir }
900*cdf0e10cSrcweir 
901*cdf0e10cSrcweir // -----------------------------------------------------------------------
902*cdf0e10cSrcweir 
903*cdf0e10cSrcweir void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
904*cdf0e10cSrcweir {
905*cdf0e10cSrcweir    if( nStart > mnGlyphCount )
906*cdf0e10cSrcweir         return;
907*cdf0e10cSrcweir 
908*cdf0e10cSrcweir     // calculate the current x-position of the requested glyph
909*cdf0e10cSrcweir     // TODO: cache absolute positions
910*cdf0e10cSrcweir     int nXPos = mnBaseAdv;
911*cdf0e10cSrcweir     for( int i = 0; i < nStart; ++i )
912*cdf0e10cSrcweir         nXPos += mpGlyphAdvances[i];
913*cdf0e10cSrcweir 
914*cdf0e10cSrcweir     // calculate the difference to the current glyph position
915*cdf0e10cSrcweir     int nDelta = nNewXPos - nXPos;
916*cdf0e10cSrcweir 
917*cdf0e10cSrcweir     // adjust the width of the layout if it was already cached
918*cdf0e10cSrcweir     if( mnWidth )
919*cdf0e10cSrcweir         mnWidth += nDelta;
920*cdf0e10cSrcweir 
921*cdf0e10cSrcweir     // depending on whether the requested glyph is leftmost in the layout
922*cdf0e10cSrcweir     // adjust either the layout's or the requested glyph's relative position
923*cdf0e10cSrcweir     if( nStart > 0 )
924*cdf0e10cSrcweir         mpGlyphAdvances[ nStart-1 ] += nDelta;
925*cdf0e10cSrcweir     else
926*cdf0e10cSrcweir         mnBaseAdv += nDelta;
927*cdf0e10cSrcweir }
928*cdf0e10cSrcweir 
929*cdf0e10cSrcweir // -----------------------------------------------------------------------
930*cdf0e10cSrcweir 
931*cdf0e10cSrcweir void SimpleWinLayout::DropGlyph( int nStart )
932*cdf0e10cSrcweir {
933*cdf0e10cSrcweir     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
934*cdf0e10cSrcweir }
935*cdf0e10cSrcweir 
936*cdf0e10cSrcweir // -----------------------------------------------------------------------
937*cdf0e10cSrcweir 
938*cdf0e10cSrcweir void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
939*cdf0e10cSrcweir {
940*cdf0e10cSrcweir     // return early if no glyph has been dropped
941*cdf0e10cSrcweir     int i = mnGlyphCount;
942*cdf0e10cSrcweir     while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
943*cdf0e10cSrcweir     if( i < 0 )
944*cdf0e10cSrcweir         return;
945*cdf0e10cSrcweir 
946*cdf0e10cSrcweir     // convert the layout to a sparse layout if it is not already
947*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
948*cdf0e10cSrcweir     {
949*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnGlyphCount ];
950*cdf0e10cSrcweir         mpCharWidths = new int[ mnCharCount ];
951*cdf0e10cSrcweir         // assertion: mnGlyphCount == mnCharCount
952*cdf0e10cSrcweir         for( int k = 0; k < mnGlyphCount; ++k )
953*cdf0e10cSrcweir         {
954*cdf0e10cSrcweir             mpGlyphs2Chars[ k ] = mnMinCharPos + k;
955*cdf0e10cSrcweir             mpCharWidths[ k ] = mpGlyphAdvances[ k ];
956*cdf0e10cSrcweir         }
957*cdf0e10cSrcweir     }
958*cdf0e10cSrcweir 
959*cdf0e10cSrcweir     // remove dropped glyphs that are rightmost in the layout
960*cdf0e10cSrcweir     for( i = mnGlyphCount; --i >= 0; )
961*cdf0e10cSrcweir     {
962*cdf0e10cSrcweir         if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
963*cdf0e10cSrcweir             break;
964*cdf0e10cSrcweir         if( mnWidth )
965*cdf0e10cSrcweir             mnWidth -= mpGlyphAdvances[ i ];
966*cdf0e10cSrcweir         int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
967*cdf0e10cSrcweir         if( nRelCharPos >= 0 )
968*cdf0e10cSrcweir             mpCharWidths[ nRelCharPos ] = 0;
969*cdf0e10cSrcweir     }
970*cdf0e10cSrcweir     mnGlyphCount = i + 1;
971*cdf0e10cSrcweir 
972*cdf0e10cSrcweir     // keep original glyph widths around
973*cdf0e10cSrcweir     if( !mpGlyphOrigAdvs )
974*cdf0e10cSrcweir     {
975*cdf0e10cSrcweir         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
976*cdf0e10cSrcweir         for( int k = 0; k < mnGlyphCount; ++k )
977*cdf0e10cSrcweir             mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
978*cdf0e10cSrcweir     }
979*cdf0e10cSrcweir 
980*cdf0e10cSrcweir     // remove dropped glyphs inside the layout
981*cdf0e10cSrcweir     int nNewGC = 0;
982*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
983*cdf0e10cSrcweir     {
984*cdf0e10cSrcweir         if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
985*cdf0e10cSrcweir         {
986*cdf0e10cSrcweir             // adjust relative position to last valid glyph
987*cdf0e10cSrcweir             int nDroppedWidth = mpGlyphAdvances[ i ];
988*cdf0e10cSrcweir             mpGlyphAdvances[ i ] = 0;
989*cdf0e10cSrcweir             if( nNewGC > 0 )
990*cdf0e10cSrcweir                 mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
991*cdf0e10cSrcweir             else
992*cdf0e10cSrcweir                 mnBaseAdv += nDroppedWidth;
993*cdf0e10cSrcweir 
994*cdf0e10cSrcweir             // zero the virtual char width for the char that has a fallback
995*cdf0e10cSrcweir             int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
996*cdf0e10cSrcweir             if( nRelCharPos >= 0 )
997*cdf0e10cSrcweir                 mpCharWidths[ nRelCharPos ] = 0;
998*cdf0e10cSrcweir         }
999*cdf0e10cSrcweir         else
1000*cdf0e10cSrcweir         {
1001*cdf0e10cSrcweir             if( nNewGC != i )
1002*cdf0e10cSrcweir             {
1003*cdf0e10cSrcweir                 // rearrange the glyph array to get rid of the dropped glyph
1004*cdf0e10cSrcweir                 mpOutGlyphs[ nNewGC ]     = mpOutGlyphs[ i ];
1005*cdf0e10cSrcweir                 mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
1006*cdf0e10cSrcweir                 mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
1007*cdf0e10cSrcweir                 mpGlyphs2Chars[ nNewGC ]  = mpGlyphs2Chars[ i ];
1008*cdf0e10cSrcweir             }
1009*cdf0e10cSrcweir             ++nNewGC;
1010*cdf0e10cSrcweir         }
1011*cdf0e10cSrcweir     }
1012*cdf0e10cSrcweir 
1013*cdf0e10cSrcweir     mnGlyphCount = nNewGC;
1014*cdf0e10cSrcweir     if( mnGlyphCount <= 0 )
1015*cdf0e10cSrcweir         mnWidth = mnBaseAdv = 0;
1016*cdf0e10cSrcweir }
1017*cdf0e10cSrcweir 
1018*cdf0e10cSrcweir // =======================================================================
1019*cdf0e10cSrcweir 
1020*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir struct VisualItem
1023*cdf0e10cSrcweir {
1024*cdf0e10cSrcweir public:
1025*cdf0e10cSrcweir     SCRIPT_ITEM*    mpScriptItem;
1026*cdf0e10cSrcweir     int             mnMinGlyphPos;
1027*cdf0e10cSrcweir     int             mnEndGlyphPos;
1028*cdf0e10cSrcweir     int             mnMinCharPos;
1029*cdf0e10cSrcweir     int             mnEndCharPos;
1030*cdf0e10cSrcweir     //long          mnPixelWidth;
1031*cdf0e10cSrcweir     int             mnXOffset;
1032*cdf0e10cSrcweir     ABC             maABCWidths;
1033*cdf0e10cSrcweir     bool            mbHasKashidas;
1034*cdf0e10cSrcweir 
1035*cdf0e10cSrcweir public:
1036*cdf0e10cSrcweir     bool            IsEmpty() const { return (mnEndGlyphPos <= 0); }
1037*cdf0e10cSrcweir     bool            IsRTL() const { return mpScriptItem->a.fRTL; }
1038*cdf0e10cSrcweir     bool            HasKashidas() const { return mbHasKashidas; }
1039*cdf0e10cSrcweir };
1040*cdf0e10cSrcweir 
1041*cdf0e10cSrcweir // -----------------------------------------------------------------------
1042*cdf0e10cSrcweir 
1043*cdf0e10cSrcweir class UniscribeLayout : public WinLayout
1044*cdf0e10cSrcweir {
1045*cdf0e10cSrcweir public:
1046*cdf0e10cSrcweir                     UniscribeLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
1047*cdf0e10cSrcweir 
1048*cdf0e10cSrcweir     virtual bool    LayoutText( ImplLayoutArgs& );
1049*cdf0e10cSrcweir     virtual void    AdjustLayout( ImplLayoutArgs& );
1050*cdf0e10cSrcweir     virtual void    DrawText( SalGraphics& ) const;
1051*cdf0e10cSrcweir     virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
1052*cdf0e10cSrcweir                         sal_Int32* pGlyphAdvances, int* pCharPosAry ) const;
1053*cdf0e10cSrcweir 
1054*cdf0e10cSrcweir     virtual long    FillDXArray( long* pDXArray ) const;
1055*cdf0e10cSrcweir     virtual int     GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
1056*cdf0e10cSrcweir     virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
1057*cdf0e10cSrcweir     virtual bool    IsKashidaPosValid ( int nCharPos ) const;
1058*cdf0e10cSrcweir 
1059*cdf0e10cSrcweir     // for glyph+font+script fallback
1060*cdf0e10cSrcweir     virtual void    MoveGlyph( int nStart, long nNewXPos );
1061*cdf0e10cSrcweir     virtual void    DropGlyph( int nStart );
1062*cdf0e10cSrcweir     virtual void    Simplify( bool bIsBase );
1063*cdf0e10cSrcweir     virtual void    DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; }
1064*cdf0e10cSrcweir 
1065*cdf0e10cSrcweir protected:
1066*cdf0e10cSrcweir     virtual         ~UniscribeLayout();
1067*cdf0e10cSrcweir 
1068*cdf0e10cSrcweir     void            Justify( long nNewWidth );
1069*cdf0e10cSrcweir     void            ApplyDXArray( const ImplLayoutArgs& );
1070*cdf0e10cSrcweir 
1071*cdf0e10cSrcweir     bool            GetItemSubrange( const VisualItem&,
1072*cdf0e10cSrcweir                         int& rMinIndex, int& rEndIndex ) const;
1073*cdf0e10cSrcweir 
1074*cdf0e10cSrcweir private:
1075*cdf0e10cSrcweir     // item specific info
1076*cdf0e10cSrcweir     SCRIPT_ITEM*    mpScriptItems;      // in logical order
1077*cdf0e10cSrcweir     VisualItem*     mpVisualItems;      // in visual order
1078*cdf0e10cSrcweir     int             mnItemCount;        // number of visual items
1079*cdf0e10cSrcweir 
1080*cdf0e10cSrcweir     // string specific info
1081*cdf0e10cSrcweir     // everything is in logical order
1082*cdf0e10cSrcweir     int             mnCharCapacity;
1083*cdf0e10cSrcweir     WORD*           mpLogClusters;      // map from absolute_char_pos to relative_glyph_pos
1084*cdf0e10cSrcweir     int*            mpCharWidths;       // map from absolute_char_pos to char_width
1085*cdf0e10cSrcweir     int             mnSubStringMin;     // char_pos of first char in context
1086*cdf0e10cSrcweir 
1087*cdf0e10cSrcweir     // glyph specific info
1088*cdf0e10cSrcweir     // everything is in visual order
1089*cdf0e10cSrcweir     int             mnGlyphCount;
1090*cdf0e10cSrcweir     int             mnGlyphCapacity;
1091*cdf0e10cSrcweir     int*            mpGlyphAdvances;    // glyph advance width before justification
1092*cdf0e10cSrcweir     int*            mpJustifications;   // glyph advance width after justification
1093*cdf0e10cSrcweir     WORD*           mpOutGlyphs;        // glyphids in visual order
1094*cdf0e10cSrcweir     GOFFSET*        mpGlyphOffsets;     // glyph offsets to the "naive" layout
1095*cdf0e10cSrcweir     SCRIPT_VISATTR* mpVisualAttrs;      // glyph visual attributes
1096*cdf0e10cSrcweir     mutable int*    mpGlyphs2Chars;     // map from absolute_glyph_pos to absolute_char_pos
1097*cdf0e10cSrcweir 
1098*cdf0e10cSrcweir     // kashida stuff
1099*cdf0e10cSrcweir     void InitKashidaHandling();
1100*cdf0e10cSrcweir     void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
1101*cdf0e10cSrcweir     bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
1102*cdf0e10cSrcweir 
1103*cdf0e10cSrcweir     int            mnMinKashidaWidth;
1104*cdf0e10cSrcweir     int            mnMinKashidaGlyph;
1105*cdf0e10cSrcweir     bool           mbDisableGlyphInjection;
1106*cdf0e10cSrcweir };
1107*cdf0e10cSrcweir 
1108*cdf0e10cSrcweir // -----------------------------------------------------------------------
1109*cdf0e10cSrcweir // dynamic loading of usp library
1110*cdf0e10cSrcweir 
1111*cdf0e10cSrcweir static oslModule aUspModule = NULL;
1112*cdf0e10cSrcweir static bool bUspEnabled = true;
1113*cdf0e10cSrcweir 
1114*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptIsComplex)( const WCHAR*, int, DWORD ));
1115*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptItemize)( const WCHAR*, int, int,
1116*cdf0e10cSrcweir     const SCRIPT_CONTROL*, const SCRIPT_STATE*, SCRIPT_ITEM*, int* ));
1117*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptShape)( HDC, SCRIPT_CACHE*, const WCHAR*,
1118*cdf0e10cSrcweir     int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*, int* ));
1119*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptPlace)( HDC, SCRIPT_CACHE*, const WORD*, int,
1120*cdf0e10cSrcweir     const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*, int*, GOFFSET*, ABC* ));
1121*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptGetLogicalWidths)( const SCRIPT_ANALYSIS*,
1122*cdf0e10cSrcweir     int, int, const int*, const WORD*, const SCRIPT_VISATTR*, int* ));
1123*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptApplyLogicalWidth)( const int*, int, int, const WORD*,
1124*cdf0e10cSrcweir     const SCRIPT_VISATTR*, const int*, const SCRIPT_ANALYSIS*, ABC*, int* ));
1125*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptJustify)( const SCRIPT_VISATTR*,
1126*cdf0e10cSrcweir     const int*, int, int, int, int* ));
1127*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptTextOut)( const HDC, SCRIPT_CACHE*,
1128*cdf0e10cSrcweir     int, int, UINT, const RECT*, const SCRIPT_ANALYSIS*, const WCHAR*,
1129*cdf0e10cSrcweir     int, const WORD*, int, const int*, const int*, const GOFFSET* ));
1130*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptGetFontProperties)( HDC, SCRIPT_CACHE*, SCRIPT_FONTPROPERTIES* ));
1131*cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptFreeCache)( SCRIPT_CACHE* ));
1132*cdf0e10cSrcweir 
1133*cdf0e10cSrcweir static bool bManualCellAlign = true;
1134*cdf0e10cSrcweir 
1135*cdf0e10cSrcweir // -----------------------------------------------------------------------
1136*cdf0e10cSrcweir 
1137*cdf0e10cSrcweir static bool InitUSP()
1138*cdf0e10cSrcweir {
1139*cdf0e10cSrcweir     OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
1140*cdf0e10cSrcweir     aUspModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
1141*cdf0e10cSrcweir     if( !aUspModule )
1142*cdf0e10cSrcweir         return (bUspEnabled = false);
1143*cdf0e10cSrcweir 
1144*cdf0e10cSrcweir     pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD))
1145*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" );
1146*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptIsComplex);
1147*cdf0e10cSrcweir 
1148*cdf0e10cSrcweir     pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int,
1149*cdf0e10cSrcweir         const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*))
1150*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" );
1151*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptItemize);
1152*cdf0e10cSrcweir 
1153*cdf0e10cSrcweir     pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*,
1154*cdf0e10cSrcweir         int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*))
1155*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" );
1156*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptShape);
1157*cdf0e10cSrcweir 
1158*cdf0e10cSrcweir     pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int,
1159*cdf0e10cSrcweir         const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*))
1160*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" );
1161*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptPlace);
1162*cdf0e10cSrcweir 
1163*cdf0e10cSrcweir     pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*,
1164*cdf0e10cSrcweir         int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*))
1165*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" );
1166*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptGetLogicalWidths);
1167*cdf0e10cSrcweir 
1168*cdf0e10cSrcweir     pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*,
1169*cdf0e10cSrcweir         const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*))
1170*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" );
1171*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptApplyLogicalWidth);
1172*cdf0e10cSrcweir 
1173*cdf0e10cSrcweir     pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*,
1174*cdf0e10cSrcweir         int,int,int,int*))
1175*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" );
1176*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptJustify);
1177*cdf0e10cSrcweir 
1178*cdf0e10cSrcweir     pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*))
1179*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" );
1180*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptGetFontProperties);
1181*cdf0e10cSrcweir 
1182*cdf0e10cSrcweir     pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*,
1183*cdf0e10cSrcweir         int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*,
1184*cdf0e10cSrcweir         int,const WORD*,int,const int*,const int*,const GOFFSET*))
1185*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" );
1186*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptTextOut);
1187*cdf0e10cSrcweir 
1188*cdf0e10cSrcweir     pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*))
1189*cdf0e10cSrcweir         osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" );
1190*cdf0e10cSrcweir     bUspEnabled &= (NULL != pScriptFreeCache);
1191*cdf0e10cSrcweir 
1192*cdf0e10cSrcweir     if( !bUspEnabled )
1193*cdf0e10cSrcweir     {
1194*cdf0e10cSrcweir         osl_unloadModule( aUspModule );
1195*cdf0e10cSrcweir         aUspModule = NULL;
1196*cdf0e10cSrcweir     }
1197*cdf0e10cSrcweir 
1198*cdf0e10cSrcweir 	// get the DLL version info
1199*cdf0e10cSrcweir 	int nUspVersion = 0;
1200*cdf0e10cSrcweir 	// TODO: there must be a simpler way to get the friggin version info from OSL?
1201*cdf0e10cSrcweir 	rtl_uString* pModuleURL = NULL;
1202*cdf0e10cSrcweir 	osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL );
1203*cdf0e10cSrcweir 	rtl_uString* pModuleFileName = NULL;
1204*cdf0e10cSrcweir 	if( pModuleURL )
1205*cdf0e10cSrcweir 		osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
1206*cdf0e10cSrcweir 	const sal_Unicode* pModuleFileCStr = NULL;
1207*cdf0e10cSrcweir 	if( pModuleFileName )
1208*cdf0e10cSrcweir 		pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
1209*cdf0e10cSrcweir 	if( pModuleFileCStr )
1210*cdf0e10cSrcweir 	{
1211*cdf0e10cSrcweir 		DWORD nHandle;
1212*cdf0e10cSrcweir 		DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
1213*cdf0e10cSrcweir 		char* pBuffer = (char*)alloca( nBufSize );
1214*cdf0e10cSrcweir 		BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
1215*cdf0e10cSrcweir 		VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
1216*cdf0e10cSrcweir 		UINT nFixedFileSize = 0;
1217*cdf0e10cSrcweir 		if( bRC )
1218*cdf0e10cSrcweir 			::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
1219*cdf0e10cSrcweir 		if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
1220*cdf0e10cSrcweir 			nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
1221*cdf0e10cSrcweir 						+ LOWORD(pFixedFileInfo->dwProductVersionMS);
1222*cdf0e10cSrcweir 	}
1223*cdf0e10cSrcweir 
1224*cdf0e10cSrcweir 	// #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
1225*cdf0e10cSrcweir 	if( nUspVersion >= 10600 )
1226*cdf0e10cSrcweir 		bManualCellAlign = false;
1227*cdf0e10cSrcweir 
1228*cdf0e10cSrcweir     return bUspEnabled;
1229*cdf0e10cSrcweir }
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir // -----------------------------------------------------------------------
1232*cdf0e10cSrcweir 
1233*cdf0e10cSrcweir UniscribeLayout::UniscribeLayout( HDC hDC,
1234*cdf0e10cSrcweir     const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
1235*cdf0e10cSrcweir :   WinLayout( hDC, rWinFontData, rWinFontEntry ),
1236*cdf0e10cSrcweir     mnItemCount( 0 ),
1237*cdf0e10cSrcweir     mpScriptItems( NULL ),
1238*cdf0e10cSrcweir     mpVisualItems( NULL ),
1239*cdf0e10cSrcweir     mpLogClusters( NULL ),
1240*cdf0e10cSrcweir     mpCharWidths( NULL ),
1241*cdf0e10cSrcweir     mnCharCapacity( 0 ),
1242*cdf0e10cSrcweir     mnSubStringMin( 0 ),
1243*cdf0e10cSrcweir     mnGlyphCapacity( 0 ),
1244*cdf0e10cSrcweir     mnGlyphCount( 0 ),
1245*cdf0e10cSrcweir     mpOutGlyphs( NULL ),
1246*cdf0e10cSrcweir     mpGlyphAdvances( NULL ),
1247*cdf0e10cSrcweir     mpJustifications( NULL ),
1248*cdf0e10cSrcweir     mpGlyphOffsets( NULL ),
1249*cdf0e10cSrcweir     mpVisualAttrs( NULL ),
1250*cdf0e10cSrcweir     mpGlyphs2Chars( NULL ),
1251*cdf0e10cSrcweir     mnMinKashidaGlyph( 0 ),
1252*cdf0e10cSrcweir     mbDisableGlyphInjection( false )
1253*cdf0e10cSrcweir {}
1254*cdf0e10cSrcweir 
1255*cdf0e10cSrcweir // -----------------------------------------------------------------------
1256*cdf0e10cSrcweir 
1257*cdf0e10cSrcweir UniscribeLayout::~UniscribeLayout()
1258*cdf0e10cSrcweir {
1259*cdf0e10cSrcweir     delete[] mpScriptItems;
1260*cdf0e10cSrcweir     delete[] mpVisualItems;
1261*cdf0e10cSrcweir     delete[] mpLogClusters;
1262*cdf0e10cSrcweir     delete[] mpCharWidths;
1263*cdf0e10cSrcweir     delete[] mpOutGlyphs;
1264*cdf0e10cSrcweir     delete[] mpGlyphAdvances;
1265*cdf0e10cSrcweir     delete[] mpJustifications;
1266*cdf0e10cSrcweir     delete[] mpGlyphOffsets;
1267*cdf0e10cSrcweir     delete[] mpVisualAttrs;
1268*cdf0e10cSrcweir     delete[] mpGlyphs2Chars;
1269*cdf0e10cSrcweir }
1270*cdf0e10cSrcweir 
1271*cdf0e10cSrcweir // -----------------------------------------------------------------------
1272*cdf0e10cSrcweir 
1273*cdf0e10cSrcweir bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
1274*cdf0e10cSrcweir {
1275*cdf0e10cSrcweir     // for a base layout only the context glyphs have to be dropped
1276*cdf0e10cSrcweir     // => when the whole string is involved there is no extra context
1277*cdf0e10cSrcweir     typedef std::vector<int> TIntVector;
1278*cdf0e10cSrcweir     TIntVector aDropChars;
1279*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
1280*cdf0e10cSrcweir     {
1281*cdf0e10cSrcweir         // calculate superfluous context char positions
1282*cdf0e10cSrcweir         aDropChars.push_back( 0 );
1283*cdf0e10cSrcweir         aDropChars.push_back( rArgs.mnLength );
1284*cdf0e10cSrcweir         int nMin, nEnd;
1285*cdf0e10cSrcweir         bool bRTL;
1286*cdf0e10cSrcweir         for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
1287*cdf0e10cSrcweir         {
1288*cdf0e10cSrcweir             aDropChars.push_back( nMin );
1289*cdf0e10cSrcweir             aDropChars.push_back( nEnd );
1290*cdf0e10cSrcweir         }
1291*cdf0e10cSrcweir         // prepare aDropChars for binary search which will allow to
1292*cdf0e10cSrcweir         // not bother with visual items that will be dropped anyway
1293*cdf0e10cSrcweir         std::sort( aDropChars.begin(), aDropChars.end() );
1294*cdf0e10cSrcweir     }
1295*cdf0e10cSrcweir 
1296*cdf0e10cSrcweir     // prepare layout
1297*cdf0e10cSrcweir     // TODO: fix case when recyclying old UniscribeLayout object
1298*cdf0e10cSrcweir     mnMinCharPos = rArgs.mnMinCharPos;
1299*cdf0e10cSrcweir     mnEndCharPos = rArgs.mnEndCharPos;
1300*cdf0e10cSrcweir 
1301*cdf0e10cSrcweir     // determine script items from string
1302*cdf0e10cSrcweir 
1303*cdf0e10cSrcweir     // prepare itemization
1304*cdf0e10cSrcweir     // TODO: try to avoid itemization since it costs a lot of performance
1305*cdf0e10cSrcweir     SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0};
1306*cdf0e10cSrcweir     aScriptState.uBidiLevel         = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL));
1307*cdf0e10cSrcweir     aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG));
1308*cdf0e10cSrcweir     aScriptState.fDigitSubstitute   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1309*cdf0e10cSrcweir     aScriptState.fArabicNumContext  = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
1310*cdf0e10cSrcweir     DWORD nLangId = 0;  // TODO: get language from font
1311*cdf0e10cSrcweir     SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0};
1312*cdf0e10cSrcweir     aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
1313*cdf0e10cSrcweir     aScriptControl.fContextDigits   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1314*cdf0e10cSrcweir     // determine relevant substring and work only on it
1315*cdf0e10cSrcweir     // when Bidi status is unknown we need to look at the whole string though
1316*cdf0e10cSrcweir     mnSubStringMin = 0;
1317*cdf0e10cSrcweir     int nSubStringEnd = rArgs.mnLength;
1318*cdf0e10cSrcweir     if( aScriptState.fOverrideDirection )
1319*cdf0e10cSrcweir     {
1320*cdf0e10cSrcweir         // TODO: limit substring to portion limits
1321*cdf0e10cSrcweir         mnSubStringMin = rArgs.mnMinCharPos - 8;
1322*cdf0e10cSrcweir         if( mnSubStringMin < 0 )
1323*cdf0e10cSrcweir             mnSubStringMin = 0;
1324*cdf0e10cSrcweir         nSubStringEnd = rArgs.mnEndCharPos + 8;
1325*cdf0e10cSrcweir         if( nSubStringEnd > rArgs.mnLength )
1326*cdf0e10cSrcweir             nSubStringEnd = rArgs.mnLength;
1327*cdf0e10cSrcweir 
1328*cdf0e10cSrcweir     }
1329*cdf0e10cSrcweir 
1330*cdf0e10cSrcweir     // now itemize the substring with its context
1331*cdf0e10cSrcweir     for( int nItemCapacity = 16;; nItemCapacity *= 8 )
1332*cdf0e10cSrcweir     {
1333*cdf0e10cSrcweir         mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
1334*cdf0e10cSrcweir         HRESULT nRC = (*pScriptItemize)(
1335*cdf0e10cSrcweir             reinterpret_cast<LPCWSTR>(rArgs.mpStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
1336*cdf0e10cSrcweir             nItemCapacity - 1, &aScriptControl, &aScriptState,
1337*cdf0e10cSrcweir             mpScriptItems, &mnItemCount );
1338*cdf0e10cSrcweir         if( !nRC )  // break loop when everything is correctly itemized
1339*cdf0e10cSrcweir             break;
1340*cdf0e10cSrcweir 
1341*cdf0e10cSrcweir         // prepare bigger buffers for another itemization round
1342*cdf0e10cSrcweir         delete[] mpScriptItems;
1343*cdf0e10cSrcweir         mpScriptItems = NULL;
1344*cdf0e10cSrcweir         if( nRC != E_OUTOFMEMORY )
1345*cdf0e10cSrcweir             return false;
1346*cdf0e10cSrcweir         if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
1347*cdf0e10cSrcweir             return false;
1348*cdf0e10cSrcweir     }
1349*cdf0e10cSrcweir 
1350*cdf0e10cSrcweir     // calculate the order of visual items
1351*cdf0e10cSrcweir     int nItem, i;
1352*cdf0e10cSrcweir 
1353*cdf0e10cSrcweir     // adjust char positions by substring offset
1354*cdf0e10cSrcweir     for( nItem = 0; nItem <= mnItemCount; ++nItem )
1355*cdf0e10cSrcweir         mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
1356*cdf0e10cSrcweir     // default visual item ordering
1357*cdf0e10cSrcweir     mpVisualItems = new VisualItem[ mnItemCount ];
1358*cdf0e10cSrcweir     for( nItem = 0; nItem < mnItemCount; ++nItem )
1359*cdf0e10cSrcweir     {
1360*cdf0e10cSrcweir         // initialize char specific item info
1361*cdf0e10cSrcweir         VisualItem& rVisualItem = mpVisualItems[ nItem ];
1362*cdf0e10cSrcweir         SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
1363*cdf0e10cSrcweir         rVisualItem.mpScriptItem = pScriptItem;
1364*cdf0e10cSrcweir         rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
1365*cdf0e10cSrcweir         rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
1366*cdf0e10cSrcweir     }
1367*cdf0e10cSrcweir 
1368*cdf0e10cSrcweir     // reorder visual item order if needed
1369*cdf0e10cSrcweir     if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
1370*cdf0e10cSrcweir     {
1371*cdf0e10cSrcweir         // force RTL item ordering if requested
1372*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL )
1373*cdf0e10cSrcweir         {
1374*cdf0e10cSrcweir             VisualItem* pVI0 = &mpVisualItems[ 0 ];
1375*cdf0e10cSrcweir             VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
1376*cdf0e10cSrcweir             while( pVI0 < --pVI1 )
1377*cdf0e10cSrcweir             {
1378*cdf0e10cSrcweir                 VisualItem aVtmp = *pVI0;
1379*cdf0e10cSrcweir                 *(pVI0++) = *pVI1;
1380*cdf0e10cSrcweir                 *pVI1 = aVtmp;
1381*cdf0e10cSrcweir             }
1382*cdf0e10cSrcweir         }
1383*cdf0e10cSrcweir     }
1384*cdf0e10cSrcweir     else if( mnItemCount > 1 )
1385*cdf0e10cSrcweir     {
1386*cdf0e10cSrcweir         // apply bidi algorithm's rule L2 on item level
1387*cdf0e10cSrcweir         // TODO: use faster L2 algorithm
1388*cdf0e10cSrcweir         int nMaxBidiLevel = 0;
1389*cdf0e10cSrcweir         VisualItem* pVI = &mpVisualItems[0];
1390*cdf0e10cSrcweir         VisualItem* const pVIend = pVI + mnItemCount;
1391*cdf0e10cSrcweir         for(; pVI < pVIend; ++pVI )
1392*cdf0e10cSrcweir             if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
1393*cdf0e10cSrcweir                 nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
1394*cdf0e10cSrcweir 
1395*cdf0e10cSrcweir         while( --nMaxBidiLevel >= 0 )
1396*cdf0e10cSrcweir         {
1397*cdf0e10cSrcweir             for( pVI = &mpVisualItems[0]; pVI < pVIend; )
1398*cdf0e10cSrcweir             {
1399*cdf0e10cSrcweir                 // find item range that needs reordering
1400*cdf0e10cSrcweir                 for(; pVI < pVIend; ++pVI )
1401*cdf0e10cSrcweir                     if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
1402*cdf0e10cSrcweir                         break;
1403*cdf0e10cSrcweir                 VisualItem* pVImin = pVI++;
1404*cdf0e10cSrcweir                 for(; pVI < pVIend; ++pVI )
1405*cdf0e10cSrcweir                     if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
1406*cdf0e10cSrcweir                         break;
1407*cdf0e10cSrcweir                 VisualItem* pVImax = pVI++;
1408*cdf0e10cSrcweir 
1409*cdf0e10cSrcweir                 // reverse order of items in this range
1410*cdf0e10cSrcweir                 while( pVImin < --pVImax )
1411*cdf0e10cSrcweir                 {
1412*cdf0e10cSrcweir                     VisualItem aVtmp = *pVImin;
1413*cdf0e10cSrcweir                     *(pVImin++) = *pVImax;
1414*cdf0e10cSrcweir                     *pVImax = aVtmp;
1415*cdf0e10cSrcweir                 }
1416*cdf0e10cSrcweir             }
1417*cdf0e10cSrcweir         }
1418*cdf0e10cSrcweir     }
1419*cdf0e10cSrcweir 
1420*cdf0e10cSrcweir     // allocate arrays
1421*cdf0e10cSrcweir     // TODO: when reusing object reuse old allocations or delete them
1422*cdf0e10cSrcweir     // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
1423*cdf0e10cSrcweir     mnCharCapacity  = nSubStringEnd;
1424*cdf0e10cSrcweir     mpLogClusters   = new WORD[ mnCharCapacity ];
1425*cdf0e10cSrcweir     mpCharWidths    = new int[ mnCharCapacity ];
1426*cdf0e10cSrcweir 
1427*cdf0e10cSrcweir     mnGlyphCount    = 0;
1428*cdf0e10cSrcweir     mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
1429*cdf0e10cSrcweir     mpGlyphAdvances = new int[ mnGlyphCapacity ];
1430*cdf0e10cSrcweir     mpOutGlyphs     = new WORD[ mnGlyphCapacity ];
1431*cdf0e10cSrcweir     mpGlyphOffsets  = new GOFFSET[ mnGlyphCapacity ];
1432*cdf0e10cSrcweir     mpVisualAttrs   = new SCRIPT_VISATTR[ mnGlyphCapacity ];
1433*cdf0e10cSrcweir 
1434*cdf0e10cSrcweir     long nXOffset = 0;
1435*cdf0e10cSrcweir     for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
1436*cdf0e10cSrcweir         mpCharWidths[j] = 0;
1437*cdf0e10cSrcweir 
1438*cdf0e10cSrcweir     // layout script items
1439*cdf0e10cSrcweir     SCRIPT_CACHE& rScriptCache = GetScriptCache();
1440*cdf0e10cSrcweir     for( nItem = 0; nItem < mnItemCount; ++nItem )
1441*cdf0e10cSrcweir     {
1442*cdf0e10cSrcweir         VisualItem& rVisualItem = mpVisualItems[ nItem ];
1443*cdf0e10cSrcweir 
1444*cdf0e10cSrcweir         // initialize glyph specific item info
1445*cdf0e10cSrcweir         rVisualItem.mnMinGlyphPos = mnGlyphCount;
1446*cdf0e10cSrcweir         rVisualItem.mnEndGlyphPos = 0;
1447*cdf0e10cSrcweir         rVisualItem.mnXOffset     = nXOffset;
1448*cdf0e10cSrcweir         //rVisualItem.mnPixelWidth  = 0;
1449*cdf0e10cSrcweir 
1450*cdf0e10cSrcweir         // shortcut ignorable items
1451*cdf0e10cSrcweir         if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
1452*cdf0e10cSrcweir          || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
1453*cdf0e10cSrcweir         {
1454*cdf0e10cSrcweir             for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
1455*cdf0e10cSrcweir                 mpLogClusters[i] = sal::static_int_cast<WORD>(~0U);
1456*cdf0e10cSrcweir             continue;
1457*cdf0e10cSrcweir         }
1458*cdf0e10cSrcweir 
1459*cdf0e10cSrcweir         // override bidi analysis if requested
1460*cdf0e10cSrcweir         if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
1461*cdf0e10cSrcweir         {
1462*cdf0e10cSrcweir             // FIXME: is this intended ?
1463*cdf0e10cSrcweir             rVisualItem.mpScriptItem->a.fRTL                 = (aScriptState.uBidiLevel & 1);
1464*cdf0e10cSrcweir             rVisualItem.mpScriptItem->a.s.uBidiLevel         = aScriptState.uBidiLevel;
1465*cdf0e10cSrcweir             rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
1466*cdf0e10cSrcweir         }
1467*cdf0e10cSrcweir 
1468*cdf0e10cSrcweir         // convert the unicodes to glyphs
1469*cdf0e10cSrcweir         int nGlyphCount = 0;
1470*cdf0e10cSrcweir         int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
1471*cdf0e10cSrcweir         HRESULT nRC = (*pScriptShape)( mhDC, &rScriptCache,
1472*cdf0e10cSrcweir             reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
1473*cdf0e10cSrcweir             nCharCount,
1474*cdf0e10cSrcweir             mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
1475*cdf0e10cSrcweir             &rVisualItem.mpScriptItem->a,
1476*cdf0e10cSrcweir             mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1477*cdf0e10cSrcweir             mpLogClusters + rVisualItem.mnMinCharPos,
1478*cdf0e10cSrcweir             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1479*cdf0e10cSrcweir             &nGlyphCount );
1480*cdf0e10cSrcweir 
1481*cdf0e10cSrcweir         // find and handle problems in the unicode to glyph conversion
1482*cdf0e10cSrcweir         if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
1483*cdf0e10cSrcweir         {
1484*cdf0e10cSrcweir             // the whole visual item needs a fallback, but make sure that the next
1485*cdf0e10cSrcweir             // fallback request is limited to the characters in the original request
1486*cdf0e10cSrcweir             // => this is handled in ImplLayoutArgs::PrepareFallback()
1487*cdf0e10cSrcweir             rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
1488*cdf0e10cSrcweir                 rVisualItem.IsRTL() );
1489*cdf0e10cSrcweir 
1490*cdf0e10cSrcweir             // don't bother to do a default layout in a fallback level
1491*cdf0e10cSrcweir             if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
1492*cdf0e10cSrcweir                 continue;
1493*cdf0e10cSrcweir 
1494*cdf0e10cSrcweir             // the primitive layout engine is good enough for the default layout
1495*cdf0e10cSrcweir             rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
1496*cdf0e10cSrcweir             nRC = (*pScriptShape)( mhDC, &rScriptCache,
1497*cdf0e10cSrcweir                 reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
1498*cdf0e10cSrcweir                 nCharCount,
1499*cdf0e10cSrcweir                 mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
1500*cdf0e10cSrcweir                 &rVisualItem.mpScriptItem->a,
1501*cdf0e10cSrcweir                 mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1502*cdf0e10cSrcweir                 mpLogClusters + rVisualItem.mnMinCharPos,
1503*cdf0e10cSrcweir                 mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1504*cdf0e10cSrcweir                 &nGlyphCount );
1505*cdf0e10cSrcweir 
1506*cdf0e10cSrcweir             if( nRC != 0 )
1507*cdf0e10cSrcweir                 continue;
1508*cdf0e10cSrcweir 
1509*cdf0e10cSrcweir #if 0       // keep the glyphs for now because they are better than nothing
1510*cdf0e10cSrcweir             // mark as NotDef glyphs
1511*cdf0e10cSrcweir             for( i = 0; i < nGlyphCount; ++i )
1512*cdf0e10cSrcweir                 mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 0;
1513*cdf0e10cSrcweir #endif
1514*cdf0e10cSrcweir         }
1515*cdf0e10cSrcweir         else if( nRC != 0 )
1516*cdf0e10cSrcweir             // something undefined happened => give up for this visual item
1517*cdf0e10cSrcweir             continue;
1518*cdf0e10cSrcweir         else // if( nRC == 0 )
1519*cdf0e10cSrcweir         {
1520*cdf0e10cSrcweir             // check if there are any NotDef glyphs
1521*cdf0e10cSrcweir             for( i = 0; i < nGlyphCount; ++i )
1522*cdf0e10cSrcweir                 if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
1523*cdf0e10cSrcweir                     break;
1524*cdf0e10cSrcweir             if( i < nGlyphCount )
1525*cdf0e10cSrcweir             {
1526*cdf0e10cSrcweir                 // clip charpos limits to the layout string without context
1527*cdf0e10cSrcweir                 int nMinCharPos = rVisualItem.mnMinCharPos;
1528*cdf0e10cSrcweir                 if( nMinCharPos < rArgs.mnMinCharPos )
1529*cdf0e10cSrcweir                     nMinCharPos = rArgs.mnMinCharPos;
1530*cdf0e10cSrcweir                 int nEndCharPos = rVisualItem.mnEndCharPos;
1531*cdf0e10cSrcweir                 if( nEndCharPos > rArgs.mnEndCharPos )
1532*cdf0e10cSrcweir                     nEndCharPos = rArgs.mnEndCharPos;
1533*cdf0e10cSrcweir                 // request fallback for individual NotDef glyphs
1534*cdf0e10cSrcweir                 do
1535*cdf0e10cSrcweir                 {
1536*cdf0e10cSrcweir                     // ignore non-NotDef glyphs
1537*cdf0e10cSrcweir                     if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
1538*cdf0e10cSrcweir                         continue;
1539*cdf0e10cSrcweir                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
1540*cdf0e10cSrcweir                     // request fallback for the whole cell that resulted in a NotDef glyph
1541*cdf0e10cSrcweir                     // TODO: optimize algorithm
1542*cdf0e10cSrcweir                     const bool bRTL = rVisualItem.IsRTL();
1543*cdf0e10cSrcweir                     if( !bRTL )
1544*cdf0e10cSrcweir                     {
1545*cdf0e10cSrcweir                         // request fallback for the left-to-right cell
1546*cdf0e10cSrcweir                         for( int c = nMinCharPos; c < nEndCharPos; ++c )
1547*cdf0e10cSrcweir                         {
1548*cdf0e10cSrcweir                             if( mpLogClusters[ c ] == i )
1549*cdf0e10cSrcweir                             {
1550*cdf0e10cSrcweir                                 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1551*cdf0e10cSrcweir                                 if( rArgs.mpStr[ c ] == 0x2060 )
1552*cdf0e10cSrcweir                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1553*cdf0e10cSrcweir                                 else
1554*cdf0e10cSrcweir                                 // <--
1555*cdf0e10cSrcweir                                     rArgs.NeedFallback( c, false );
1556*cdf0e10cSrcweir                            }
1557*cdf0e10cSrcweir                         }
1558*cdf0e10cSrcweir                     }
1559*cdf0e10cSrcweir                     else
1560*cdf0e10cSrcweir                     {
1561*cdf0e10cSrcweir                         // request fallback for the right to left cell
1562*cdf0e10cSrcweir                         for( int c = nEndCharPos; --c >= nMinCharPos; )
1563*cdf0e10cSrcweir                         {
1564*cdf0e10cSrcweir                             if( mpLogClusters[ c ] == i )
1565*cdf0e10cSrcweir                             {
1566*cdf0e10cSrcweir                                 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1567*cdf0e10cSrcweir                                 if( rArgs.mpStr[ c ] == 0x2060 )
1568*cdf0e10cSrcweir                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1569*cdf0e10cSrcweir                                 else
1570*cdf0e10cSrcweir                                 // <--
1571*cdf0e10cSrcweir                                     rArgs.NeedFallback( c, true );
1572*cdf0e10cSrcweir                             }
1573*cdf0e10cSrcweir                         }
1574*cdf0e10cSrcweir                     }
1575*cdf0e10cSrcweir                 } while( ++i < nGlyphCount );
1576*cdf0e10cSrcweir             }
1577*cdf0e10cSrcweir         }
1578*cdf0e10cSrcweir 
1579*cdf0e10cSrcweir         // now place the glyphs
1580*cdf0e10cSrcweir         nRC = (*pScriptPlace)( mhDC, &rScriptCache,
1581*cdf0e10cSrcweir             mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1582*cdf0e10cSrcweir             nGlyphCount,
1583*cdf0e10cSrcweir             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1584*cdf0e10cSrcweir             &rVisualItem.mpScriptItem->a,
1585*cdf0e10cSrcweir             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1586*cdf0e10cSrcweir             mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
1587*cdf0e10cSrcweir             &rVisualItem.maABCWidths );
1588*cdf0e10cSrcweir 
1589*cdf0e10cSrcweir         if( nRC != 0 )
1590*cdf0e10cSrcweir             continue;
1591*cdf0e10cSrcweir 
1592*cdf0e10cSrcweir         // calculate the logical char widths from the glyph layout
1593*cdf0e10cSrcweir         nRC = (*pScriptGetLogicalWidths)(
1594*cdf0e10cSrcweir             &rVisualItem.mpScriptItem->a,
1595*cdf0e10cSrcweir             nCharCount, nGlyphCount,
1596*cdf0e10cSrcweir             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1597*cdf0e10cSrcweir             mpLogClusters + rVisualItem.mnMinCharPos,
1598*cdf0e10cSrcweir             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1599*cdf0e10cSrcweir             mpCharWidths + rVisualItem.mnMinCharPos );
1600*cdf0e10cSrcweir 
1601*cdf0e10cSrcweir         // update the glyph counters
1602*cdf0e10cSrcweir         mnGlyphCount += nGlyphCount;
1603*cdf0e10cSrcweir         rVisualItem.mnEndGlyphPos = mnGlyphCount;
1604*cdf0e10cSrcweir 
1605*cdf0e10cSrcweir         // update nXOffset
1606*cdf0e10cSrcweir         int nEndGlyphPos;
1607*cdf0e10cSrcweir         if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
1608*cdf0e10cSrcweir             for(; i < nEndGlyphPos; ++i )
1609*cdf0e10cSrcweir                 nXOffset += mpGlyphAdvances[ i ];
1610*cdf0e10cSrcweir 
1611*cdf0e10cSrcweir         // TODO: shrink glyphpos limits to match charpos/fallback limits
1612*cdf0e10cSrcweir         //pVI->mnMinGlyphPos = nMinGlyphPos;
1613*cdf0e10cSrcweir         //pVI->mnEndGlyphPos = nEndGlyphPos;
1614*cdf0e10cSrcweir 
1615*cdf0e10cSrcweir         // drop the superfluous context glyphs
1616*cdf0e10cSrcweir         TIntVector::const_iterator it = aDropChars.begin();
1617*cdf0e10cSrcweir         while( it != aDropChars.end() )
1618*cdf0e10cSrcweir         {
1619*cdf0e10cSrcweir             // find matching "drop range"
1620*cdf0e10cSrcweir             int nMinDropPos = *(it++); // begin of drop range
1621*cdf0e10cSrcweir             if( nMinDropPos >= rVisualItem.mnEndCharPos )
1622*cdf0e10cSrcweir                 break;
1623*cdf0e10cSrcweir             int nEndDropPos = *(it++); // end of drop range
1624*cdf0e10cSrcweir             if( nEndDropPos <= rVisualItem.mnMinCharPos )
1625*cdf0e10cSrcweir                 continue;
1626*cdf0e10cSrcweir             // clip "drop range" to visual item's char range
1627*cdf0e10cSrcweir             if( nMinDropPos <= rVisualItem.mnMinCharPos )
1628*cdf0e10cSrcweir             {
1629*cdf0e10cSrcweir                 nMinDropPos = rVisualItem.mnMinCharPos;
1630*cdf0e10cSrcweir                 // drop the whole visual item if possible
1631*cdf0e10cSrcweir                 if( nEndDropPos >= rVisualItem.mnEndCharPos )
1632*cdf0e10cSrcweir                 {
1633*cdf0e10cSrcweir                     rVisualItem.mnEndGlyphPos = 0;
1634*cdf0e10cSrcweir                     break;
1635*cdf0e10cSrcweir                 }
1636*cdf0e10cSrcweir             }
1637*cdf0e10cSrcweir             if( nEndDropPos > rVisualItem.mnEndCharPos )
1638*cdf0e10cSrcweir                 nEndDropPos = rVisualItem.mnEndCharPos;
1639*cdf0e10cSrcweir 
1640*cdf0e10cSrcweir             // drop the glyphs which correspond to the charpos range
1641*cdf0e10cSrcweir             // drop the corresponding glyphs in the cluster
1642*cdf0e10cSrcweir             for( int c = nMinDropPos; c < nEndDropPos; ++c )
1643*cdf0e10cSrcweir             {
1644*cdf0e10cSrcweir                 int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
1645*cdf0e10cSrcweir                 // no need to bother when the cluster was already dropped
1646*cdf0e10cSrcweir                 if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
1647*cdf0e10cSrcweir                 {
1648*cdf0e10cSrcweir                     for(;;)
1649*cdf0e10cSrcweir                     {
1650*cdf0e10cSrcweir                         mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
1651*cdf0e10cSrcweir                         // until the end of visual item
1652*cdf0e10cSrcweir                         if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
1653*cdf0e10cSrcweir                             break;
1654*cdf0e10cSrcweir                         // until the next cluster start
1655*cdf0e10cSrcweir                         if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
1656*cdf0e10cSrcweir                             break;
1657*cdf0e10cSrcweir                     }
1658*cdf0e10cSrcweir                 }
1659*cdf0e10cSrcweir             }
1660*cdf0e10cSrcweir         }
1661*cdf0e10cSrcweir     }
1662*cdf0e10cSrcweir 
1663*cdf0e10cSrcweir     // scale layout metrics if needed
1664*cdf0e10cSrcweir 	// TODO: does it make the code more simple if the metric scaling
1665*cdf0e10cSrcweir 	// is moved to the methods that need metric scaling (e.g. FillDXArray())?
1666*cdf0e10cSrcweir     if( mfFontScale != 1.0 )
1667*cdf0e10cSrcweir     {
1668*cdf0e10cSrcweir         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1669*cdf0e10cSrcweir 
1670*cdf0e10cSrcweir         for( i = 0; i < mnItemCount; ++i )
1671*cdf0e10cSrcweir             mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
1672*cdf0e10cSrcweir 
1673*cdf0e10cSrcweir         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1674*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
1675*cdf0e10cSrcweir         {
1676*cdf0e10cSrcweir             mpGlyphAdvances[i]   = (int)(mpGlyphAdvances[i] * mfFontScale);
1677*cdf0e10cSrcweir             mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
1678*cdf0e10cSrcweir             mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
1679*cdf0e10cSrcweir             // mpJustifications are still NULL
1680*cdf0e10cSrcweir         }
1681*cdf0e10cSrcweir 
1682*cdf0e10cSrcweir         for( i = mnSubStringMin; i < nSubStringEnd; ++i )
1683*cdf0e10cSrcweir             mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
1684*cdf0e10cSrcweir     }
1685*cdf0e10cSrcweir 
1686*cdf0e10cSrcweir     return true;
1687*cdf0e10cSrcweir }
1688*cdf0e10cSrcweir 
1689*cdf0e10cSrcweir // -----------------------------------------------------------------------
1690*cdf0e10cSrcweir 
1691*cdf0e10cSrcweir // calculate the range of relevant glyphs for this visual item
1692*cdf0e10cSrcweir bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
1693*cdf0e10cSrcweir     int& rMinGlyphPos, int& rEndGlyphPos ) const
1694*cdf0e10cSrcweir {
1695*cdf0e10cSrcweir     // return early when nothing of interest in this item
1696*cdf0e10cSrcweir     if( rVisualItem.IsEmpty()
1697*cdf0e10cSrcweir      || (rVisualItem.mnEndCharPos <= mnMinCharPos)
1698*cdf0e10cSrcweir      || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
1699*cdf0e10cSrcweir         return false;
1700*cdf0e10cSrcweir 
1701*cdf0e10cSrcweir     // default: subrange is complete range
1702*cdf0e10cSrcweir     rMinGlyphPos = rVisualItem.mnMinGlyphPos;
1703*cdf0e10cSrcweir     rEndGlyphPos = rVisualItem.mnEndGlyphPos;
1704*cdf0e10cSrcweir 
1705*cdf0e10cSrcweir     // return early when the whole item is of interest
1706*cdf0e10cSrcweir     if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
1707*cdf0e10cSrcweir      && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
1708*cdf0e10cSrcweir         return true;
1709*cdf0e10cSrcweir 
1710*cdf0e10cSrcweir     // get glyph range from char range by looking at cluster boundries
1711*cdf0e10cSrcweir     // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
1712*cdf0e10cSrcweir     rMinGlyphPos = rVisualItem.mnEndGlyphPos;
1713*cdf0e10cSrcweir     int nMaxGlyphPos = 0;
1714*cdf0e10cSrcweir 
1715*cdf0e10cSrcweir     int i = mnMinCharPos;
1716*cdf0e10cSrcweir     if( i < rVisualItem.mnMinCharPos )
1717*cdf0e10cSrcweir         i = rVisualItem.mnMinCharPos;
1718*cdf0e10cSrcweir     int nCharPosLimit = rVisualItem.mnEndCharPos;
1719*cdf0e10cSrcweir     if( nCharPosLimit > mnEndCharPos )
1720*cdf0e10cSrcweir         nCharPosLimit = mnEndCharPos;
1721*cdf0e10cSrcweir     for(; i < nCharPosLimit; ++i )
1722*cdf0e10cSrcweir     {
1723*cdf0e10cSrcweir         int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
1724*cdf0e10cSrcweir         if( rMinGlyphPos > n )
1725*cdf0e10cSrcweir             rMinGlyphPos = n;
1726*cdf0e10cSrcweir         if( nMaxGlyphPos < n )
1727*cdf0e10cSrcweir             nMaxGlyphPos = n;
1728*cdf0e10cSrcweir     }
1729*cdf0e10cSrcweir 	if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
1730*cdf0e10cSrcweir 		nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
1731*cdf0e10cSrcweir 
1732*cdf0e10cSrcweir     // extend the glyph range to account for all glyphs in referenced clusters
1733*cdf0e10cSrcweir     if( !rVisualItem.IsRTL() ) // LTR-item
1734*cdf0e10cSrcweir     {
1735*cdf0e10cSrcweir         // extend to rightmost glyph of rightmost referenced cluster
1736*cdf0e10cSrcweir         for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
1737*cdf0e10cSrcweir             if( mpVisualAttrs[i].fClusterStart )
1738*cdf0e10cSrcweir                 break;
1739*cdf0e10cSrcweir     }
1740*cdf0e10cSrcweir     else // RTL-item
1741*cdf0e10cSrcweir     {
1742*cdf0e10cSrcweir         // extend to leftmost glyph of leftmost referenced cluster
1743*cdf0e10cSrcweir         for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
1744*cdf0e10cSrcweir             if( mpVisualAttrs[i].fClusterStart )
1745*cdf0e10cSrcweir                 break;
1746*cdf0e10cSrcweir     }
1747*cdf0e10cSrcweir     rEndGlyphPos = nMaxGlyphPos + 1;
1748*cdf0e10cSrcweir 
1749*cdf0e10cSrcweir     return true;
1750*cdf0e10cSrcweir }
1751*cdf0e10cSrcweir 
1752*cdf0e10cSrcweir // -----------------------------------------------------------------------
1753*cdf0e10cSrcweir 
1754*cdf0e10cSrcweir int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
1755*cdf0e10cSrcweir     int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
1756*cdf0e10cSrcweir {
1757*cdf0e10cSrcweir     // HACK to allow fake-glyph insertion (e.g. for kashidas)
1758*cdf0e10cSrcweir     // TODO: use iterator idiom instead of GetNextGlyphs(...)
1759*cdf0e10cSrcweir     // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
1760*cdf0e10cSrcweir     int nSubIter = nStartx8 & 0xff;
1761*cdf0e10cSrcweir     int nStart = nStartx8 >> 8;
1762*cdf0e10cSrcweir 
1763*cdf0e10cSrcweir     // check the glyph iterator
1764*cdf0e10cSrcweir     if( nStart > mnGlyphCount )       // nStart>MAX means no more glyphs
1765*cdf0e10cSrcweir         return 0;
1766*cdf0e10cSrcweir 
1767*cdf0e10cSrcweir     // find the visual item for the nStart glyph position
1768*cdf0e10cSrcweir     int nItem = 0;
1769*cdf0e10cSrcweir     const VisualItem* pVI = mpVisualItems;
1770*cdf0e10cSrcweir     if( nStart <= 0 )                 // nStart<=0 requests the first visible glyph
1771*cdf0e10cSrcweir     {
1772*cdf0e10cSrcweir         // find first visible item
1773*cdf0e10cSrcweir         for(; nItem < mnItemCount; ++nItem, ++pVI )
1774*cdf0e10cSrcweir             if( !pVI->IsEmpty() )
1775*cdf0e10cSrcweir                 break;
1776*cdf0e10cSrcweir         // it is possible that there are glyphs but no valid visual item
1777*cdf0e10cSrcweir         // TODO: get rid of these visual items more early
1778*cdf0e10cSrcweir         if( nItem < mnItemCount )
1779*cdf0e10cSrcweir             nStart = pVI->mnMinGlyphPos;
1780*cdf0e10cSrcweir     }
1781*cdf0e10cSrcweir     else //if( nStart > 0 )           // nStart>0 means absolute glyph pos +1
1782*cdf0e10cSrcweir     {
1783*cdf0e10cSrcweir         --nStart;
1784*cdf0e10cSrcweir 
1785*cdf0e10cSrcweir         // find matching item
1786*cdf0e10cSrcweir         for(; nItem < mnItemCount; ++nItem, ++pVI )
1787*cdf0e10cSrcweir             if( (nStart >= pVI->mnMinGlyphPos)
1788*cdf0e10cSrcweir             &&  (nStart < pVI->mnEndGlyphPos) )
1789*cdf0e10cSrcweir                 break;
1790*cdf0e10cSrcweir     }
1791*cdf0e10cSrcweir 
1792*cdf0e10cSrcweir     // after the last visual item there are no more glyphs
1793*cdf0e10cSrcweir     if( (nItem >= mnItemCount) || (nStart < 0) )
1794*cdf0e10cSrcweir     {
1795*cdf0e10cSrcweir         nStartx8 = (mnGlyphCount + 1) << 8;
1796*cdf0e10cSrcweir         return 0;
1797*cdf0e10cSrcweir     }
1798*cdf0e10cSrcweir 
1799*cdf0e10cSrcweir     // calculate the first glyph in the next visual item
1800*cdf0e10cSrcweir     int nNextItemStart = mnGlyphCount;
1801*cdf0e10cSrcweir     while( ++nItem < mnItemCount )
1802*cdf0e10cSrcweir     {
1803*cdf0e10cSrcweir         if( mpVisualItems[nItem].IsEmpty() )
1804*cdf0e10cSrcweir             continue;
1805*cdf0e10cSrcweir         nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
1806*cdf0e10cSrcweir         break;
1807*cdf0e10cSrcweir     }
1808*cdf0e10cSrcweir 
1809*cdf0e10cSrcweir     // get the range of relevant glyphs in this visual item
1810*cdf0e10cSrcweir     int nMinGlyphPos, nEndGlyphPos;
1811*cdf0e10cSrcweir     bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
1812*cdf0e10cSrcweir     DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
1813*cdf0e10cSrcweir     if( !bRC )
1814*cdf0e10cSrcweir     {
1815*cdf0e10cSrcweir         nStartx8 = (mnGlyphCount + 1) << 8;
1816*cdf0e10cSrcweir         return 0;
1817*cdf0e10cSrcweir     }
1818*cdf0e10cSrcweir 
1819*cdf0e10cSrcweir     // make sure nStart is inside the range of relevant glyphs
1820*cdf0e10cSrcweir     if( nStart < nMinGlyphPos )
1821*cdf0e10cSrcweir         nStart = nMinGlyphPos;
1822*cdf0e10cSrcweir 
1823*cdf0e10cSrcweir     // calculate the start glyph xoffset relative to layout's base position,
1824*cdf0e10cSrcweir     // advance to next visual glyph position by using adjusted glyph widths
1825*cdf0e10cSrcweir     // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
1826*cdf0e10cSrcweir     long nXOffset = pVI->mnXOffset;
1827*cdf0e10cSrcweir     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
1828*cdf0e10cSrcweir     for( int i = nMinGlyphPos; i < nStart; ++i )
1829*cdf0e10cSrcweir         nXOffset += pGlyphWidths[ i ];
1830*cdf0e10cSrcweir 
1831*cdf0e10cSrcweir     // adjust the nXOffset relative to glyph cluster start
1832*cdf0e10cSrcweir     int c = mnMinCharPos;
1833*cdf0e10cSrcweir     if( !pVI->IsRTL() ) // LTR-case
1834*cdf0e10cSrcweir     {
1835*cdf0e10cSrcweir         // LTR case: subtract the remainder of the cell from xoffset
1836*cdf0e10cSrcweir         int nTmpIndex = mpLogClusters[c];
1837*cdf0e10cSrcweir         while( (--c >= pVI->mnMinCharPos)
1838*cdf0e10cSrcweir             && (nTmpIndex == mpLogClusters[c]) )
1839*cdf0e10cSrcweir             nXOffset -= mpCharWidths[c];
1840*cdf0e10cSrcweir     }
1841*cdf0e10cSrcweir     else // RTL-case
1842*cdf0e10cSrcweir     {
1843*cdf0e10cSrcweir         // RTL case: add the remainder of the cell from xoffset
1844*cdf0e10cSrcweir         int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
1845*cdf0e10cSrcweir         while( (--c >= pVI->mnMinCharPos)
1846*cdf0e10cSrcweir             && (nTmpIndex == mpLogClusters[c]) )
1847*cdf0e10cSrcweir             nXOffset += mpCharWidths[c];
1848*cdf0e10cSrcweir 
1849*cdf0e10cSrcweir         // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
1850*cdf0e10cSrcweir 		if( mpJustifications && !bManualCellAlign )
1851*cdf0e10cSrcweir            nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
1852*cdf0e10cSrcweir     }
1853*cdf0e10cSrcweir 
1854*cdf0e10cSrcweir     // create mpGlyphs2Chars[] if it is needed later
1855*cdf0e10cSrcweir     if( pCharPosAry && !mpGlyphs2Chars )
1856*cdf0e10cSrcweir     {
1857*cdf0e10cSrcweir         // create and reset the new array
1858*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnGlyphCapacity ];
1859*cdf0e10cSrcweir         for( int i = 0; i < mnGlyphCount; ++i )
1860*cdf0e10cSrcweir             mpGlyphs2Chars[i] = -1;
1861*cdf0e10cSrcweir         // calculate the char->glyph mapping
1862*cdf0e10cSrcweir         for( nItem = 0; nItem < mnItemCount; ++nItem )
1863*cdf0e10cSrcweir         {
1864*cdf0e10cSrcweir             // ignore invisible visual items
1865*cdf0e10cSrcweir             const VisualItem& rVI = mpVisualItems[ nItem ];
1866*cdf0e10cSrcweir             if( rVI.IsEmpty() )
1867*cdf0e10cSrcweir                 continue;
1868*cdf0e10cSrcweir             // calculate the mapping by using mpLogClusters[]
1869*cdf0e10cSrcweir             // mpGlyphs2Chars[] should obey the logical order
1870*cdf0e10cSrcweir             // => reversing the loop does this by overwriting higher logicals
1871*cdf0e10cSrcweir             for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
1872*cdf0e10cSrcweir             {
1873*cdf0e10cSrcweir                 int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
1874*cdf0e10cSrcweir                 mpGlyphs2Chars[i] = c;
1875*cdf0e10cSrcweir             }
1876*cdf0e10cSrcweir         }
1877*cdf0e10cSrcweir     }
1878*cdf0e10cSrcweir 
1879*cdf0e10cSrcweir     // calculate the absolute position of the first result glyph in pixel units
1880*cdf0e10cSrcweir     const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
1881*cdf0e10cSrcweir     Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
1882*cdf0e10cSrcweir     rPos = GetDrawPosition( aRelativePos );
1883*cdf0e10cSrcweir 
1884*cdf0e10cSrcweir 	// fill the result arrays
1885*cdf0e10cSrcweir     int nCount = 0;
1886*cdf0e10cSrcweir     while( nCount < nLen )
1887*cdf0e10cSrcweir     {
1888*cdf0e10cSrcweir         // prepare return values
1889*cdf0e10cSrcweir         sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
1890*cdf0e10cSrcweir         int nGlyphWidth = pGlyphWidths[ nStart ];
1891*cdf0e10cSrcweir         int nCharPos = -1;    // no need to determine charpos
1892*cdf0e10cSrcweir         if( mpGlyphs2Chars )  // unless explicitly requested+provided
1893*cdf0e10cSrcweir             nCharPos = mpGlyphs2Chars[ nStart ];
1894*cdf0e10cSrcweir 
1895*cdf0e10cSrcweir         // inject kashida glyphs if needed
1896*cdf0e10cSrcweir         if( !mbDisableGlyphInjection
1897*cdf0e10cSrcweir         && mpJustifications
1898*cdf0e10cSrcweir         && mnMinKashidaWidth
1899*cdf0e10cSrcweir         && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
1900*cdf0e10cSrcweir         {
1901*cdf0e10cSrcweir 			// prepare draw position adjustment
1902*cdf0e10cSrcweir 			int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
1903*cdf0e10cSrcweir         	// calculate space available for the injected glyphs
1904*cdf0e10cSrcweir    	        nGlyphWidth = mpGlyphAdvances[ nStart ];
1905*cdf0e10cSrcweir 	        const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
1906*cdf0e10cSrcweir 			const int nToFillWidth = nExtraWidth - nExtraOfs;
1907*cdf0e10cSrcweir 	        if( (4*nToFillWidth >= mnMinKashidaWidth)    // prevent glyph-injection if there is no room
1908*cdf0e10cSrcweir 	        ||  ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
1909*cdf0e10cSrcweir 	        {
1910*cdf0e10cSrcweir 	        	// handle if there is not sufficient room for a full glyph
1911*cdf0e10cSrcweir 	        	if( nToFillWidth < mnMinKashidaWidth )
1912*cdf0e10cSrcweir 	        	{
1913*cdf0e10cSrcweir 	        		// overlap it with the previously injected glyph if possible
1914*cdf0e10cSrcweir 	        		int nOverlap = mnMinKashidaWidth - nToFillWidth;
1915*cdf0e10cSrcweir 	        		// else overlap it with both neighboring glyphs
1916*cdf0e10cSrcweir 					if( nSubIter <= 1 )
1917*cdf0e10cSrcweir 						nOverlap /= 2;
1918*cdf0e10cSrcweir 					nExtraOfs -= nOverlap;
1919*cdf0e10cSrcweir 	        	}
1920*cdf0e10cSrcweir 	        	nGlyphWidth = mnMinKashidaWidth;
1921*cdf0e10cSrcweir 	        	aGlyphId = mnMinKashidaGlyph;
1922*cdf0e10cSrcweir 				nCharPos = -1;
1923*cdf0e10cSrcweir 	        }
1924*cdf0e10cSrcweir 	        else
1925*cdf0e10cSrcweir 	        {
1926*cdf0e10cSrcweir 	        	nExtraOfs += nToFillWidth;	// at right of cell
1927*cdf0e10cSrcweir 	        	nSubIter = 0;				// done with glyph injection
1928*cdf0e10cSrcweir 	        }
1929*cdf0e10cSrcweir             if( !bManualCellAlign )
1930*cdf0e10cSrcweir                 nExtraOfs -= nExtraWidth;	// adjust for right-aligned cells
1931*cdf0e10cSrcweir 
1932*cdf0e10cSrcweir 			// adjust the draw position for the injected-glyphs case
1933*cdf0e10cSrcweir 			if( nExtraOfs )
1934*cdf0e10cSrcweir 			{
1935*cdf0e10cSrcweir 				aRelativePos.X() += nExtraOfs;
1936*cdf0e10cSrcweir 				rPos = GetDrawPosition( aRelativePos );
1937*cdf0e10cSrcweir 			}
1938*cdf0e10cSrcweir         }
1939*cdf0e10cSrcweir 
1940*cdf0e10cSrcweir         // update return values
1941*cdf0e10cSrcweir         *(pGlyphs++) = aGlyphId;
1942*cdf0e10cSrcweir         if( pGlyphAdvances )
1943*cdf0e10cSrcweir             *(pGlyphAdvances++) = nGlyphWidth;
1944*cdf0e10cSrcweir         if( pCharPosAry )
1945*cdf0e10cSrcweir             *(pCharPosAry++) = nCharPos;
1946*cdf0e10cSrcweir 
1947*cdf0e10cSrcweir         // increment counter of returned glyphs
1948*cdf0e10cSrcweir         ++nCount;
1949*cdf0e10cSrcweir 
1950*cdf0e10cSrcweir         // reduce code complexity by returning early in glyph-injection case
1951*cdf0e10cSrcweir        	if( nSubIter != 0 )
1952*cdf0e10cSrcweir        		break;
1953*cdf0e10cSrcweir 
1954*cdf0e10cSrcweir         // stop after the last visible glyph in this visual item
1955*cdf0e10cSrcweir         if( ++nStart >= nEndGlyphPos )
1956*cdf0e10cSrcweir         {
1957*cdf0e10cSrcweir             nStart = nNextItemStart;
1958*cdf0e10cSrcweir             break;
1959*cdf0e10cSrcweir         }
1960*cdf0e10cSrcweir 
1961*cdf0e10cSrcweir         // RTL-justified glyph positioning is not easy
1962*cdf0e10cSrcweir         // simplify the code by just returning only one glyph at a time
1963*cdf0e10cSrcweir         if( mpJustifications && pVI->IsRTL() )
1964*cdf0e10cSrcweir             break;
1965*cdf0e10cSrcweir 
1966*cdf0e10cSrcweir         // stop when the x-position of the next glyph is unexpected
1967*cdf0e10cSrcweir         if( !pGlyphAdvances  )
1968*cdf0e10cSrcweir             if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
1969*cdf0e10cSrcweir              || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
1970*cdf0e10cSrcweir                 break;
1971*cdf0e10cSrcweir 
1972*cdf0e10cSrcweir         // stop when the y-position of the next glyph is unexpected
1973*cdf0e10cSrcweir         if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
1974*cdf0e10cSrcweir             break;
1975*cdf0e10cSrcweir     }
1976*cdf0e10cSrcweir 
1977*cdf0e10cSrcweir     ++nStart;
1978*cdf0e10cSrcweir     nStartx8 = (nStart << 8) + nSubIter;
1979*cdf0e10cSrcweir     return nCount;
1980*cdf0e10cSrcweir }
1981*cdf0e10cSrcweir 
1982*cdf0e10cSrcweir // -----------------------------------------------------------------------
1983*cdf0e10cSrcweir 
1984*cdf0e10cSrcweir void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
1985*cdf0e10cSrcweir {
1986*cdf0e10cSrcweir     DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
1987*cdf0e10cSrcweir     int nStart = nStartx8 >> 8;
1988*cdf0e10cSrcweir     if( nStart > mnGlyphCount )
1989*cdf0e10cSrcweir         return;
1990*cdf0e10cSrcweir 
1991*cdf0e10cSrcweir     VisualItem* pVI = mpVisualItems;
1992*cdf0e10cSrcweir     int nMinGlyphPos = 0, nEndGlyphPos;
1993*cdf0e10cSrcweir     if( nStart == 0 )               // nStart==0 for first visible glyph
1994*cdf0e10cSrcweir     {
1995*cdf0e10cSrcweir         for( int i = mnItemCount; --i >= 0; ++pVI )
1996*cdf0e10cSrcweir             if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
1997*cdf0e10cSrcweir                 break;
1998*cdf0e10cSrcweir         nStart = nMinGlyphPos;
1999*cdf0e10cSrcweir         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" );
2000*cdf0e10cSrcweir     }
2001*cdf0e10cSrcweir     else //if( nStart > 0 )         // nStart>0 means absolute_glyphpos+1
2002*cdf0e10cSrcweir     {
2003*cdf0e10cSrcweir         --nStart;
2004*cdf0e10cSrcweir         for( int i = mnItemCount; --i >= 0; ++pVI )
2005*cdf0e10cSrcweir             if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
2006*cdf0e10cSrcweir                 break;
2007*cdf0e10cSrcweir         bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
2008*cdf0e10cSrcweir 	(void)bRC; // avoid var-not-used warning
2009*cdf0e10cSrcweir         DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
2010*cdf0e10cSrcweir     }
2011*cdf0e10cSrcweir 
2012*cdf0e10cSrcweir     long nDelta = nNewXPos - pVI->mnXOffset;
2013*cdf0e10cSrcweir     if( nStart > nMinGlyphPos )
2014*cdf0e10cSrcweir     {
2015*cdf0e10cSrcweir         // move the glyph by expanding its left glyph but ignore dropped glyphs
2016*cdf0e10cSrcweir         int i, nLastUndropped = nMinGlyphPos - 1;
2017*cdf0e10cSrcweir         for( i = nMinGlyphPos; i < nStart; ++i )
2018*cdf0e10cSrcweir 		{
2019*cdf0e10cSrcweir 			if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
2020*cdf0e10cSrcweir 			{
2021*cdf0e10cSrcweir 	            nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
2022*cdf0e10cSrcweir 				nLastUndropped = i;
2023*cdf0e10cSrcweir 			}
2024*cdf0e10cSrcweir 		}
2025*cdf0e10cSrcweir 		if (nLastUndropped >= nMinGlyphPos)
2026*cdf0e10cSrcweir 		{
2027*cdf0e10cSrcweir 			mpGlyphAdvances[ nLastUndropped ] += nDelta;
2028*cdf0e10cSrcweir 			if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
2029*cdf0e10cSrcweir 		}
2030*cdf0e10cSrcweir 		else
2031*cdf0e10cSrcweir 		{
2032*cdf0e10cSrcweir 			pVI->mnXOffset += nDelta;
2033*cdf0e10cSrcweir 		}
2034*cdf0e10cSrcweir     }
2035*cdf0e10cSrcweir     else
2036*cdf0e10cSrcweir     {
2037*cdf0e10cSrcweir         // move the visual item by having an offset
2038*cdf0e10cSrcweir         pVI->mnXOffset += nDelta;
2039*cdf0e10cSrcweir     }
2040*cdf0e10cSrcweir     // move subsequent items - this often isn't necessary because subsequent
2041*cdf0e10cSrcweir     // moves will correct subsequent items. However, if there is a contiguous
2042*cdf0e10cSrcweir     // range not involving fallback which spans items, this will be needed
2043*cdf0e10cSrcweir     while (++pVI - mpVisualItems < mnItemCount)
2044*cdf0e10cSrcweir     {
2045*cdf0e10cSrcweir         pVI->mnXOffset += nDelta;
2046*cdf0e10cSrcweir     }
2047*cdf0e10cSrcweir }
2048*cdf0e10cSrcweir 
2049*cdf0e10cSrcweir // -----------------------------------------------------------------------
2050*cdf0e10cSrcweir 
2051*cdf0e10cSrcweir void UniscribeLayout::DropGlyph( int nStartx8 )
2052*cdf0e10cSrcweir {
2053*cdf0e10cSrcweir     DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
2054*cdf0e10cSrcweir     int nStart = nStartx8 >> 8;
2055*cdf0e10cSrcweir     DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
2056*cdf0e10cSrcweir 
2057*cdf0e10cSrcweir     if( nStart > 0 )        // nStart>0 means absolute glyph pos + 1
2058*cdf0e10cSrcweir         --nStart;
2059*cdf0e10cSrcweir     else                    // nStart<=0 for first visible glyph
2060*cdf0e10cSrcweir     {
2061*cdf0e10cSrcweir         VisualItem* pVI = mpVisualItems;
2062*cdf0e10cSrcweir         for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
2063*cdf0e10cSrcweir             if( GetItemSubrange( *pVI, nStart, nDummy ) )
2064*cdf0e10cSrcweir                 break;
2065*cdf0e10cSrcweir         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
2066*cdf0e10cSrcweir 		int nOffset = 0;
2067*cdf0e10cSrcweir 		int j = pVI->mnMinGlyphPos;
2068*cdf0e10cSrcweir 		while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
2069*cdf0e10cSrcweir 		if (j == nStart)
2070*cdf0e10cSrcweir 		{
2071*cdf0e10cSrcweir 			pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
2072*cdf0e10cSrcweir 		}
2073*cdf0e10cSrcweir     }
2074*cdf0e10cSrcweir 
2075*cdf0e10cSrcweir     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
2076*cdf0e10cSrcweir }
2077*cdf0e10cSrcweir 
2078*cdf0e10cSrcweir // -----------------------------------------------------------------------
2079*cdf0e10cSrcweir 
2080*cdf0e10cSrcweir void UniscribeLayout::Simplify( bool /*bIsBase*/ )
2081*cdf0e10cSrcweir {
2082*cdf0e10cSrcweir     static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH;
2083*cdf0e10cSrcweir     int i;
2084*cdf0e10cSrcweir     // if there are no dropped glyphs don't bother
2085*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
2086*cdf0e10cSrcweir         if( mpOutGlyphs[ i ] == cDroppedGlyph )
2087*cdf0e10cSrcweir             break;
2088*cdf0e10cSrcweir     if( i >= mnGlyphCount )
2089*cdf0e10cSrcweir         return;
2090*cdf0e10cSrcweir 
2091*cdf0e10cSrcweir     // prepare for sparse layout
2092*cdf0e10cSrcweir     // => make sure mpGlyphs2Chars[] exists
2093*cdf0e10cSrcweir     if( !mpGlyphs2Chars )
2094*cdf0e10cSrcweir     {
2095*cdf0e10cSrcweir         mpGlyphs2Chars = new int[ mnGlyphCapacity ];
2096*cdf0e10cSrcweir         for( i = 0; i < mnGlyphCount; ++i )
2097*cdf0e10cSrcweir             mpGlyphs2Chars[ i ] = -1;
2098*cdf0e10cSrcweir         for( int nItem = 0; nItem < mnItemCount; ++nItem )
2099*cdf0e10cSrcweir         {
2100*cdf0e10cSrcweir             // skip invisible items
2101*cdf0e10cSrcweir             VisualItem& rVI = mpVisualItems[ nItem ];
2102*cdf0e10cSrcweir             if( rVI.IsEmpty() )
2103*cdf0e10cSrcweir                 continue;
2104*cdf0e10cSrcweir             for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
2105*cdf0e10cSrcweir             {
2106*cdf0e10cSrcweir                 int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2107*cdf0e10cSrcweir                 mpGlyphs2Chars[ j ] = i;
2108*cdf0e10cSrcweir             }
2109*cdf0e10cSrcweir         }
2110*cdf0e10cSrcweir     }
2111*cdf0e10cSrcweir 
2112*cdf0e10cSrcweir     // remove the dropped glyphs
2113*cdf0e10cSrcweir     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2114*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2115*cdf0e10cSrcweir     {
2116*cdf0e10cSrcweir         VisualItem& rVI = mpVisualItems[ nItem ];
2117*cdf0e10cSrcweir         if( rVI.IsEmpty() )
2118*cdf0e10cSrcweir             continue;
2119*cdf0e10cSrcweir 
2120*cdf0e10cSrcweir         // mark replaced character widths
2121*cdf0e10cSrcweir         for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
2122*cdf0e10cSrcweir         {
2123*cdf0e10cSrcweir             int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2124*cdf0e10cSrcweir             if( mpOutGlyphs[ j ] == cDroppedGlyph )
2125*cdf0e10cSrcweir                 mpCharWidths[ i ] = 0;
2126*cdf0e10cSrcweir         }
2127*cdf0e10cSrcweir 
2128*cdf0e10cSrcweir         // handle dropped glyphs at start of visual item
2129*cdf0e10cSrcweir         int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
2130*cdf0e10cSrcweir         GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
2131*cdf0e10cSrcweir         i = nMinGlyphPos;
2132*cdf0e10cSrcweir         while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
2133*cdf0e10cSrcweir         {
2134*cdf0e10cSrcweir             //rVI.mnXOffset += pGlyphWidths[ i ];
2135*cdf0e10cSrcweir             rVI.mnMinGlyphPos = ++i;
2136*cdf0e10cSrcweir         }
2137*cdf0e10cSrcweir 
2138*cdf0e10cSrcweir         // when all glyphs in item got dropped mark it as empty
2139*cdf0e10cSrcweir         if( i >= nEndGlyphPos )
2140*cdf0e10cSrcweir         {
2141*cdf0e10cSrcweir             rVI.mnEndGlyphPos = 0;
2142*cdf0e10cSrcweir             continue;
2143*cdf0e10cSrcweir         }
2144*cdf0e10cSrcweir 		// If there are still glyphs in the cluster and mnMinGlyphPos
2145*cdf0e10cSrcweir 		// has changed then we need to remove the dropped glyphs at start
2146*cdf0e10cSrcweir 		// to correct logClusters, which is unsigned and relative to the
2147*cdf0e10cSrcweir 		// item start.
2148*cdf0e10cSrcweir 		if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
2149*cdf0e10cSrcweir 		{
2150*cdf0e10cSrcweir 			// drop any glyphs in the visual item outside the range
2151*cdf0e10cSrcweir 			for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
2152*cdf0e10cSrcweir 				mpOutGlyphs[ i ] = cDroppedGlyph;
2153*cdf0e10cSrcweir 			rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
2154*cdf0e10cSrcweir 		}
2155*cdf0e10cSrcweir 
2156*cdf0e10cSrcweir         // handle dropped glyphs in the middle of visual item
2157*cdf0e10cSrcweir         for(; i < nEndGlyphPos; ++i )
2158*cdf0e10cSrcweir             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2159*cdf0e10cSrcweir                 break;
2160*cdf0e10cSrcweir         int j = i;
2161*cdf0e10cSrcweir         while( ++i < nEndGlyphPos )
2162*cdf0e10cSrcweir         {
2163*cdf0e10cSrcweir             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2164*cdf0e10cSrcweir                 continue;
2165*cdf0e10cSrcweir             mpOutGlyphs[ j ]      = mpOutGlyphs[ i ];
2166*cdf0e10cSrcweir             mpGlyphOffsets[ j ]   = mpGlyphOffsets[ i ];
2167*cdf0e10cSrcweir             mpVisualAttrs[ j ]    = mpVisualAttrs[ i ];
2168*cdf0e10cSrcweir             mpGlyphAdvances[ j ]  = mpGlyphAdvances[ i ];
2169*cdf0e10cSrcweir             if( mpJustifications )
2170*cdf0e10cSrcweir                 mpJustifications[ j ] = mpJustifications[ i ];
2171*cdf0e10cSrcweir             const int k = mpGlyphs2Chars[ i ];
2172*cdf0e10cSrcweir             mpGlyphs2Chars[ j ]   = k;
2173*cdf0e10cSrcweir             const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
2174*cdf0e10cSrcweir             if( k < 0) // extra glyphs are already mapped
2175*cdf0e10cSrcweir                 continue;
2176*cdf0e10cSrcweir             mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
2177*cdf0e10cSrcweir         }
2178*cdf0e10cSrcweir 
2179*cdf0e10cSrcweir         rVI.mnEndGlyphPos = j;
2180*cdf0e10cSrcweir     }
2181*cdf0e10cSrcweir }
2182*cdf0e10cSrcweir 
2183*cdf0e10cSrcweir // -----------------------------------------------------------------------
2184*cdf0e10cSrcweir 
2185*cdf0e10cSrcweir void UniscribeLayout::DrawText( SalGraphics& ) const
2186*cdf0e10cSrcweir {
2187*cdf0e10cSrcweir     HFONT hOrigFont = DisableFontScaling();
2188*cdf0e10cSrcweir 
2189*cdf0e10cSrcweir     int nBaseClusterOffset = 0;
2190*cdf0e10cSrcweir     int nBaseGlyphPos = -1;
2191*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2192*cdf0e10cSrcweir     {
2193*cdf0e10cSrcweir         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2194*cdf0e10cSrcweir 
2195*cdf0e10cSrcweir         // skip if there is nothing to display
2196*cdf0e10cSrcweir         int nMinGlyphPos, nEndGlyphPos;
2197*cdf0e10cSrcweir         if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2198*cdf0e10cSrcweir             continue;
2199*cdf0e10cSrcweir 
2200*cdf0e10cSrcweir         if( nBaseGlyphPos < 0 )
2201*cdf0e10cSrcweir         {
2202*cdf0e10cSrcweir             // adjust draw position relative to cluster start
2203*cdf0e10cSrcweir             if( rVisualItem.IsRTL() )
2204*cdf0e10cSrcweir                 nBaseGlyphPos = nEndGlyphPos - 1;
2205*cdf0e10cSrcweir             else
2206*cdf0e10cSrcweir                 nBaseGlyphPos = nMinGlyphPos;
2207*cdf0e10cSrcweir 
2208*cdf0e10cSrcweir             const int* pGlyphWidths;
2209*cdf0e10cSrcweir             if( mpJustifications )
2210*cdf0e10cSrcweir                 pGlyphWidths = mpJustifications;
2211*cdf0e10cSrcweir             else
2212*cdf0e10cSrcweir                 pGlyphWidths = mpGlyphAdvances;
2213*cdf0e10cSrcweir 
2214*cdf0e10cSrcweir             int i = mnMinCharPos;
2215*cdf0e10cSrcweir             while( (--i >= rVisualItem.mnMinCharPos)
2216*cdf0e10cSrcweir                 && (nBaseGlyphPos == mpLogClusters[i]) )
2217*cdf0e10cSrcweir                  nBaseClusterOffset += mpCharWidths[i];
2218*cdf0e10cSrcweir 
2219*cdf0e10cSrcweir             if( !rVisualItem.IsRTL() )
2220*cdf0e10cSrcweir                 nBaseClusterOffset = -nBaseClusterOffset;
2221*cdf0e10cSrcweir         }
2222*cdf0e10cSrcweir 
2223*cdf0e10cSrcweir         // now draw the matching glyphs in this item
2224*cdf0e10cSrcweir         Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
2225*cdf0e10cSrcweir         Point aPos = GetDrawPosition( aRelPos );
2226*cdf0e10cSrcweir         SCRIPT_CACHE& rScriptCache = GetScriptCache();
2227*cdf0e10cSrcweir         (*pScriptTextOut)( mhDC, &rScriptCache,
2228*cdf0e10cSrcweir             aPos.X(), aPos.Y(), 0, NULL,
2229*cdf0e10cSrcweir             &rVisualItem.mpScriptItem->a, NULL, 0,
2230*cdf0e10cSrcweir             mpOutGlyphs + nMinGlyphPos,
2231*cdf0e10cSrcweir             nEndGlyphPos - nMinGlyphPos,
2232*cdf0e10cSrcweir             mpGlyphAdvances + nMinGlyphPos,
2233*cdf0e10cSrcweir             mpJustifications ? mpJustifications + nMinGlyphPos : NULL,
2234*cdf0e10cSrcweir             mpGlyphOffsets + nMinGlyphPos );
2235*cdf0e10cSrcweir     }
2236*cdf0e10cSrcweir 
2237*cdf0e10cSrcweir     if( hOrigFont )
2238*cdf0e10cSrcweir         DeleteFont( SelectFont( mhDC, hOrigFont ) );
2239*cdf0e10cSrcweir }
2240*cdf0e10cSrcweir 
2241*cdf0e10cSrcweir // -----------------------------------------------------------------------
2242*cdf0e10cSrcweir 
2243*cdf0e10cSrcweir long UniscribeLayout::FillDXArray( long* pDXArray ) const
2244*cdf0e10cSrcweir {
2245*cdf0e10cSrcweir     // calculate width of the complete layout
2246*cdf0e10cSrcweir     long nWidth = mnBaseAdv;
2247*cdf0e10cSrcweir     for( int nItem = mnItemCount; --nItem >= 0; )
2248*cdf0e10cSrcweir     {
2249*cdf0e10cSrcweir         const VisualItem& rVI = mpVisualItems[ nItem ];
2250*cdf0e10cSrcweir 
2251*cdf0e10cSrcweir         // skip if there is nothing to display
2252*cdf0e10cSrcweir         int nMinGlyphPos, nEndGlyphPos;
2253*cdf0e10cSrcweir         if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
2254*cdf0e10cSrcweir             continue;
2255*cdf0e10cSrcweir 
2256*cdf0e10cSrcweir         // width = xoffset + width of last item
2257*cdf0e10cSrcweir         nWidth = rVI.mnXOffset;
2258*cdf0e10cSrcweir         const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2259*cdf0e10cSrcweir         for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2260*cdf0e10cSrcweir             nWidth += pGlyphWidths[i];
2261*cdf0e10cSrcweir         break;
2262*cdf0e10cSrcweir     }
2263*cdf0e10cSrcweir 
2264*cdf0e10cSrcweir     // copy the virtual char widths into pDXArray[]
2265*cdf0e10cSrcweir     if( pDXArray )
2266*cdf0e10cSrcweir         for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2267*cdf0e10cSrcweir             pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
2268*cdf0e10cSrcweir 
2269*cdf0e10cSrcweir     return nWidth;
2270*cdf0e10cSrcweir }
2271*cdf0e10cSrcweir 
2272*cdf0e10cSrcweir // -----------------------------------------------------------------------
2273*cdf0e10cSrcweir 
2274*cdf0e10cSrcweir int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2275*cdf0e10cSrcweir {
2276*cdf0e10cSrcweir     long nWidth = 0;
2277*cdf0e10cSrcweir     for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2278*cdf0e10cSrcweir     {
2279*cdf0e10cSrcweir         nWidth += mpCharWidths[ i ] * nFactor;
2280*cdf0e10cSrcweir 
2281*cdf0e10cSrcweir         // check if the nMaxWidth still fits the current sub-layout
2282*cdf0e10cSrcweir         if( nWidth >= nMaxWidth )
2283*cdf0e10cSrcweir         {
2284*cdf0e10cSrcweir             // go back to cluster start
2285*cdf0e10cSrcweir             // we have to find the visual item first since the mpLogClusters[]
2286*cdf0e10cSrcweir             // needed to find the cluster start is relative to to the visual item
2287*cdf0e10cSrcweir             int nMinGlyphIndex = 0;
2288*cdf0e10cSrcweir             for( int nItem = 0; nItem < mnItemCount; ++nItem )
2289*cdf0e10cSrcweir             {
2290*cdf0e10cSrcweir                 const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2291*cdf0e10cSrcweir                 nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2292*cdf0e10cSrcweir                 if( (i >= rVisualItem.mnMinCharPos)
2293*cdf0e10cSrcweir                 &&  (i < rVisualItem.mnEndCharPos) )
2294*cdf0e10cSrcweir                     break;
2295*cdf0e10cSrcweir             }
2296*cdf0e10cSrcweir             // now go back to the matching cluster start
2297*cdf0e10cSrcweir             do
2298*cdf0e10cSrcweir             {
2299*cdf0e10cSrcweir                 int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
2300*cdf0e10cSrcweir                 if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
2301*cdf0e10cSrcweir                     return i;
2302*cdf0e10cSrcweir             } while( --i >= mnMinCharPos );
2303*cdf0e10cSrcweir 
2304*cdf0e10cSrcweir             // if the cluster starts before the start of the visual item
2305*cdf0e10cSrcweir             // then set the visual breakpoint before this item
2306*cdf0e10cSrcweir             return mnMinCharPos;
2307*cdf0e10cSrcweir         }
2308*cdf0e10cSrcweir 
2309*cdf0e10cSrcweir         // the visual break also depends on the nCharExtra between the characters
2310*cdf0e10cSrcweir         nWidth += nCharExtra;
2311*cdf0e10cSrcweir     }
2312*cdf0e10cSrcweir 
2313*cdf0e10cSrcweir     // the whole layout did fit inside the nMaxWidth
2314*cdf0e10cSrcweir     return STRING_LEN;
2315*cdf0e10cSrcweir }
2316*cdf0e10cSrcweir 
2317*cdf0e10cSrcweir // -----------------------------------------------------------------------
2318*cdf0e10cSrcweir 
2319*cdf0e10cSrcweir void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
2320*cdf0e10cSrcweir {
2321*cdf0e10cSrcweir     int i;
2322*cdf0e10cSrcweir     for( i = 0; i < nMaxIdx; ++i )
2323*cdf0e10cSrcweir         pCaretXArray[ i ] = -1;
2324*cdf0e10cSrcweir     long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) );
2325*cdf0e10cSrcweir     for( i = 0; i <= mnGlyphCount; ++i )
2326*cdf0e10cSrcweir         pGlyphPos[ i ] = -1;
2327*cdf0e10cSrcweir 
2328*cdf0e10cSrcweir     long nXPos = 0;
2329*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2330*cdf0e10cSrcweir     {
2331*cdf0e10cSrcweir         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2332*cdf0e10cSrcweir         if( rVisualItem.IsEmpty() )
2333*cdf0e10cSrcweir             continue;
2334*cdf0e10cSrcweir 
2335*cdf0e10cSrcweir         if (mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK)
2336*cdf0e10cSrcweir         {
2337*cdf0e10cSrcweir             nXPos = rVisualItem.mnXOffset;
2338*cdf0e10cSrcweir         }
2339*cdf0e10cSrcweir         // get glyph positions
2340*cdf0e10cSrcweir         // TODO: handle when rVisualItem's glyph range is only partially used
2341*cdf0e10cSrcweir         for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2342*cdf0e10cSrcweir         {
2343*cdf0e10cSrcweir             pGlyphPos[ i ] = nXPos;
2344*cdf0e10cSrcweir             nXPos += mpGlyphAdvances[ i ];
2345*cdf0e10cSrcweir         }
2346*cdf0e10cSrcweir         // rightmost position of this visualitem
2347*cdf0e10cSrcweir         pGlyphPos[ i ] = nXPos;
2348*cdf0e10cSrcweir 
2349*cdf0e10cSrcweir         // convert glyph positions to character positions
2350*cdf0e10cSrcweir         i = rVisualItem.mnMinCharPos;
2351*cdf0e10cSrcweir         if( i < mnMinCharPos )
2352*cdf0e10cSrcweir             i = mnMinCharPos;
2353*cdf0e10cSrcweir         for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
2354*cdf0e10cSrcweir         {
2355*cdf0e10cSrcweir             int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
2356*cdf0e10cSrcweir             int nCurrIdx = i * 2;
2357*cdf0e10cSrcweir             if( !rVisualItem.IsRTL() )
2358*cdf0e10cSrcweir             {
2359*cdf0e10cSrcweir                 // normal positions for LTR case
2360*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j ];
2361*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
2362*cdf0e10cSrcweir             }
2363*cdf0e10cSrcweir             else
2364*cdf0e10cSrcweir             {
2365*cdf0e10cSrcweir                 // reverse positions for RTL case
2366*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j+1 ];
2367*cdf0e10cSrcweir                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
2368*cdf0e10cSrcweir             }
2369*cdf0e10cSrcweir         }
2370*cdf0e10cSrcweir     }
2371*cdf0e10cSrcweir 
2372*cdf0e10cSrcweir     if (!(mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK))
2373*cdf0e10cSrcweir     {
2374*cdf0e10cSrcweir         nXPos = 0;
2375*cdf0e10cSrcweir         // fixup unknown character positions to neighbor
2376*cdf0e10cSrcweir         for( i = 0; i < nMaxIdx; ++i )
2377*cdf0e10cSrcweir         {
2378*cdf0e10cSrcweir             if( pCaretXArray[ i ] >= 0 )
2379*cdf0e10cSrcweir                 nXPos = pCaretXArray[ i ];
2380*cdf0e10cSrcweir             else
2381*cdf0e10cSrcweir                 pCaretXArray[ i ] = nXPos;
2382*cdf0e10cSrcweir         }
2383*cdf0e10cSrcweir     }
2384*cdf0e10cSrcweir }
2385*cdf0e10cSrcweir 
2386*cdf0e10cSrcweir // -----------------------------------------------------------------------
2387*cdf0e10cSrcweir 
2388*cdf0e10cSrcweir void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
2389*cdf0e10cSrcweir {
2390*cdf0e10cSrcweir     SalLayout::AdjustLayout( rArgs );
2391*cdf0e10cSrcweir 
2392*cdf0e10cSrcweir     // adjust positions if requested
2393*cdf0e10cSrcweir     if( rArgs.mpDXArray )
2394*cdf0e10cSrcweir         ApplyDXArray( rArgs );
2395*cdf0e10cSrcweir     else if( rArgs.mnLayoutWidth )
2396*cdf0e10cSrcweir         Justify( rArgs.mnLayoutWidth );
2397*cdf0e10cSrcweir }
2398*cdf0e10cSrcweir 
2399*cdf0e10cSrcweir // -----------------------------------------------------------------------
2400*cdf0e10cSrcweir 
2401*cdf0e10cSrcweir void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
2402*cdf0e10cSrcweir {
2403*cdf0e10cSrcweir     const long* pDXArray = rArgs.mpDXArray;
2404*cdf0e10cSrcweir 
2405*cdf0e10cSrcweir     // increase char widths in string range to desired values
2406*cdf0e10cSrcweir     bool bModified = false;
2407*cdf0e10cSrcweir     int nOldWidth = 0;
2408*cdf0e10cSrcweir     DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
2409*cdf0e10cSrcweir     int i,j;
2410*cdf0e10cSrcweir     for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
2411*cdf0e10cSrcweir     {
2412*cdf0e10cSrcweir         int nNewCharWidth = (pDXArray[j] - nOldWidth);
2413*cdf0e10cSrcweir         // TODO: nNewCharWidth *= mnUnitsPerPixel;
2414*cdf0e10cSrcweir         if( mpCharWidths[i] != nNewCharWidth )
2415*cdf0e10cSrcweir         {
2416*cdf0e10cSrcweir             mpCharWidths[i] = nNewCharWidth;
2417*cdf0e10cSrcweir             bModified = true;
2418*cdf0e10cSrcweir         }
2419*cdf0e10cSrcweir         nOldWidth = pDXArray[j];
2420*cdf0e10cSrcweir     }
2421*cdf0e10cSrcweir 
2422*cdf0e10cSrcweir     if( !bModified )
2423*cdf0e10cSrcweir         return;
2424*cdf0e10cSrcweir 
2425*cdf0e10cSrcweir     // initialize justifications array
2426*cdf0e10cSrcweir     mpJustifications = new int[ mnGlyphCapacity ];
2427*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCount; ++i )
2428*cdf0e10cSrcweir         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2429*cdf0e10cSrcweir 
2430*cdf0e10cSrcweir     // apply new widths to script items
2431*cdf0e10cSrcweir     long nXOffset = 0;
2432*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2433*cdf0e10cSrcweir     {
2434*cdf0e10cSrcweir         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2435*cdf0e10cSrcweir 
2436*cdf0e10cSrcweir         // set the position of this visual item
2437*cdf0e10cSrcweir         rVisualItem.mnXOffset = nXOffset;
2438*cdf0e10cSrcweir 
2439*cdf0e10cSrcweir         // ignore empty visual items
2440*cdf0e10cSrcweir         if( rVisualItem.IsEmpty() )
2441*cdf0e10cSrcweir         {
2442*cdf0e10cSrcweir             for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
2443*cdf0e10cSrcweir               nXOffset += mpCharWidths[i];
2444*cdf0e10cSrcweir             continue;
2445*cdf0e10cSrcweir         }
2446*cdf0e10cSrcweir         // ignore irrelevant visual items
2447*cdf0e10cSrcweir         if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
2448*cdf0e10cSrcweir          || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
2449*cdf0e10cSrcweir             continue;
2450*cdf0e10cSrcweir 
2451*cdf0e10cSrcweir 		// if needed prepare special handling for arabic justification
2452*cdf0e10cSrcweir 		rVisualItem.mbHasKashidas = false;
2453*cdf0e10cSrcweir 		if( rVisualItem.IsRTL() )
2454*cdf0e10cSrcweir         {
2455*cdf0e10cSrcweir 			for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2456*cdf0e10cSrcweir                 if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 )  //  any Arabic justification
2457*cdf0e10cSrcweir                 {                                                        //  excluding SCRIPT_JUSTIFY_NONE
2458*cdf0e10cSrcweir                     // yes
2459*cdf0e10cSrcweir                     rVisualItem.mbHasKashidas = true;
2460*cdf0e10cSrcweir                     // so prepare for kashida handling
2461*cdf0e10cSrcweir                     InitKashidaHandling();
2462*cdf0e10cSrcweir 					break;
2463*cdf0e10cSrcweir 				}
2464*cdf0e10cSrcweir 
2465*cdf0e10cSrcweir 			if( rVisualItem.HasKashidas() )
2466*cdf0e10cSrcweir 				for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2467*cdf0e10cSrcweir 				{
2468*cdf0e10cSrcweir                     // TODO: check if we still need this hack after correction of kashida placing?
2469*cdf0e10cSrcweir                     // (i87688): apparently yes, we still need it!
2470*cdf0e10cSrcweir                     if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
2471*cdf0e10cSrcweir                         // usp decided that justification can't be applied here
2472*cdf0e10cSrcweir 						// but maybe our Kashida algorithm thinks differently.
2473*cdf0e10cSrcweir 						// To avoid trouble (gaps within words, last character of
2474*cdf0e10cSrcweir 						// a word gets a Kashida appended) override this.
2475*cdf0e10cSrcweir 
2476*cdf0e10cSrcweir 						// I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
2477*cdf0e10cSrcweir 						// just because this previous hack (which I haven't understand, sorry) used
2478*cdf0e10cSrcweir 						// the same value to replace. Don't know if this is really the best
2479*cdf0e10cSrcweir 						// thing to do, but it seems to fix things
2480*cdf0e10cSrcweir 						mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2481*cdf0e10cSrcweir 				}
2482*cdf0e10cSrcweir         }
2483*cdf0e10cSrcweir 
2484*cdf0e10cSrcweir         // convert virtual charwidths to glyph justification values
2485*cdf0e10cSrcweir         HRESULT nRC = (*pScriptApplyLogicalWidth)(
2486*cdf0e10cSrcweir             mpCharWidths + rVisualItem.mnMinCharPos,
2487*cdf0e10cSrcweir             rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
2488*cdf0e10cSrcweir             rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2489*cdf0e10cSrcweir             mpLogClusters + rVisualItem.mnMinCharPos,
2490*cdf0e10cSrcweir             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2491*cdf0e10cSrcweir             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2492*cdf0e10cSrcweir             &rVisualItem.mpScriptItem->a,
2493*cdf0e10cSrcweir             &rVisualItem.maABCWidths,
2494*cdf0e10cSrcweir             mpJustifications + rVisualItem.mnMinGlyphPos );
2495*cdf0e10cSrcweir 
2496*cdf0e10cSrcweir         if( nRC != 0 )
2497*cdf0e10cSrcweir         {
2498*cdf0e10cSrcweir             delete[] mpJustifications;
2499*cdf0e10cSrcweir             mpJustifications = NULL;
2500*cdf0e10cSrcweir             break;
2501*cdf0e10cSrcweir         }
2502*cdf0e10cSrcweir 
2503*cdf0e10cSrcweir         // to prepare for the next visual item
2504*cdf0e10cSrcweir         // update nXOffset to the next items position
2505*cdf0e10cSrcweir         // before the mpJustifications[] array gets modified
2506*cdf0e10cSrcweir         int nMinGlyphPos, nEndGlyphPos;
2507*cdf0e10cSrcweir         if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2508*cdf0e10cSrcweir         {
2509*cdf0e10cSrcweir             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2510*cdf0e10cSrcweir                 nXOffset += mpJustifications[ i ];
2511*cdf0e10cSrcweir 
2512*cdf0e10cSrcweir             if( rVisualItem.mbHasKashidas )
2513*cdf0e10cSrcweir 				KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
2514*cdf0e10cSrcweir         }
2515*cdf0e10cSrcweir 
2516*cdf0e10cSrcweir 		// workaround needed for older USP versions:
2517*cdf0e10cSrcweir         // right align the justification-adjusted glyphs in their cells for RTL-items
2518*cdf0e10cSrcweir 		// unless the right alignment is done by inserting kashidas
2519*cdf0e10cSrcweir         if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
2520*cdf0e10cSrcweir         {
2521*cdf0e10cSrcweir             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2522*cdf0e10cSrcweir             {
2523*cdf0e10cSrcweir                 const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
2524*cdf0e10cSrcweir 				// #i99862# skip diacritics, we mustn't add extra justification to diacritics
2525*cdf0e10cSrcweir 				int nIdxAdd = i - 1;
2526*cdf0e10cSrcweir 				while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
2527*cdf0e10cSrcweir 					--nIdxAdd;
2528*cdf0e10cSrcweir                 if( nIdxAdd < nMinGlyphPos )
2529*cdf0e10cSrcweir                     rVisualItem.mnXOffset += nXOffsetAdjust;
2530*cdf0e10cSrcweir                 else
2531*cdf0e10cSrcweir                     mpJustifications[nIdxAdd] += nXOffsetAdjust;
2532*cdf0e10cSrcweir                 mpJustifications[i] -= nXOffsetAdjust;
2533*cdf0e10cSrcweir             }
2534*cdf0e10cSrcweir         }
2535*cdf0e10cSrcweir     }
2536*cdf0e10cSrcweir }
2537*cdf0e10cSrcweir 
2538*cdf0e10cSrcweir // -----------------------------------------------------------------------
2539*cdf0e10cSrcweir 
2540*cdf0e10cSrcweir void UniscribeLayout::InitKashidaHandling()
2541*cdf0e10cSrcweir {
2542*cdf0e10cSrcweir 	if( mnMinKashidaGlyph != 0 )	// already initialized
2543*cdf0e10cSrcweir 		return;
2544*cdf0e10cSrcweir 
2545*cdf0e10cSrcweir 	mrWinFontEntry.InitKashidaHandling( mhDC );
2546*cdf0e10cSrcweir 	mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
2547*cdf0e10cSrcweir 	mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
2548*cdf0e10cSrcweir }
2549*cdf0e10cSrcweir 
2550*cdf0e10cSrcweir // adjust the kashida placement matching to the WriterEngine
2551*cdf0e10cSrcweir void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
2552*cdf0e10cSrcweir {
2553*cdf0e10cSrcweir 	// workaround needed for all known USP versions:
2554*cdf0e10cSrcweir 	// ApplyLogicalWidth does not match ScriptJustify behaviour
2555*cdf0e10cSrcweir 	for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2556*cdf0e10cSrcweir 	{
2557*cdf0e10cSrcweir 		// check for vowels
2558*cdf0e10cSrcweir 		if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
2559*cdf0e10cSrcweir 		&&  (1U << mpVisualAttrs[i].uJustification) & 0xFF83 )	// all Arabic justifiction types
2560*cdf0e10cSrcweir 		{														// including SCRIPT_JUSTIFY_NONE
2561*cdf0e10cSrcweir 			// vowel, we do it like ScriptJustify does
2562*cdf0e10cSrcweir 			// the vowel gets the extra width
2563*cdf0e10cSrcweir 			long nSpaceAdded =  mpJustifications[ i ] - mpGlyphAdvances[ i ];
2564*cdf0e10cSrcweir 			mpJustifications [ i ] = mpGlyphAdvances [ i ];
2565*cdf0e10cSrcweir 			mpJustifications [ i - 1 ] += nSpaceAdded;
2566*cdf0e10cSrcweir 		}
2567*cdf0e10cSrcweir 	}
2568*cdf0e10cSrcweir 
2569*cdf0e10cSrcweir 	// redistribute the widths for kashidas
2570*cdf0e10cSrcweir 	for( int i = nMinGlyphPos; i < nEndGlyphPos; )
2571*cdf0e10cSrcweir 		KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
2572*cdf0e10cSrcweir }
2573*cdf0e10cSrcweir 
2574*cdf0e10cSrcweir bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
2575*cdf0e10cSrcweir {
2576*cdf0e10cSrcweir 	// doing pixel work within a word.
2577*cdf0e10cSrcweir 	// sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
2578*cdf0e10cSrcweir 
2579*cdf0e10cSrcweir 	// find the next kashida
2580*cdf0e10cSrcweir 	int nMinPos = *pnCurrentPos;
2581*cdf0e10cSrcweir 	int nMaxPos = *pnCurrentPos;
2582*cdf0e10cSrcweir 	for( int i = nMaxPos; i < nEndGlyphPos; ++i )
2583*cdf0e10cSrcweir 	{
2584*cdf0e10cSrcweir 		if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
2585*cdf0e10cSrcweir 		&&  (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
2586*cdf0e10cSrcweir 			break;
2587*cdf0e10cSrcweir 		nMaxPos = i;
2588*cdf0e10cSrcweir 	}
2589*cdf0e10cSrcweir 	*pnCurrentPos = nMaxPos + 1;
2590*cdf0e10cSrcweir 	if( nMinPos == nMaxPos )
2591*cdf0e10cSrcweir 		return false;
2592*cdf0e10cSrcweir 
2593*cdf0e10cSrcweir 	// calculate the available space for an extra kashida
2594*cdf0e10cSrcweir 	long nMaxAdded = 0;
2595*cdf0e10cSrcweir 	int nKashPos = -1;
2596*cdf0e10cSrcweir 	for( int i = nMaxPos; i >= nMinPos; --i )
2597*cdf0e10cSrcweir 	{
2598*cdf0e10cSrcweir 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2599*cdf0e10cSrcweir 		if( nSpaceAdded > nMaxAdded )
2600*cdf0e10cSrcweir 		{
2601*cdf0e10cSrcweir 			nKashPos = i;
2602*cdf0e10cSrcweir 			nMaxAdded = nSpaceAdded;
2603*cdf0e10cSrcweir 		}
2604*cdf0e10cSrcweir 	}
2605*cdf0e10cSrcweir 
2606*cdf0e10cSrcweir 	// return early if there is no need for an extra kashida
2607*cdf0e10cSrcweir 	if ( nMaxAdded <= 0 )
2608*cdf0e10cSrcweir 		return false;
2609*cdf0e10cSrcweir 	// return early if there is not enough space for an extra kashida
2610*cdf0e10cSrcweir 	if( 2*nMaxAdded < mnMinKashidaWidth )
2611*cdf0e10cSrcweir 		return false;
2612*cdf0e10cSrcweir 
2613*cdf0e10cSrcweir 	// redistribute the extra spacing to the kashida position
2614*cdf0e10cSrcweir 	for( int i = nMinPos; i <= nMaxPos; ++i )
2615*cdf0e10cSrcweir 	{
2616*cdf0e10cSrcweir 		if( i == nKashPos )
2617*cdf0e10cSrcweir 			continue;
2618*cdf0e10cSrcweir 		// everything else should not have extra spacing
2619*cdf0e10cSrcweir 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2620*cdf0e10cSrcweir 		if( nSpaceAdded > 0 )
2621*cdf0e10cSrcweir 		{
2622*cdf0e10cSrcweir 			mpJustifications[ i ] -= nSpaceAdded;
2623*cdf0e10cSrcweir 			mpJustifications[ nKashPos ] += nSpaceAdded;
2624*cdf0e10cSrcweir 		}
2625*cdf0e10cSrcweir 	}
2626*cdf0e10cSrcweir 
2627*cdf0e10cSrcweir 	// check if we fulfill minimal kashida width
2628*cdf0e10cSrcweir 	long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
2629*cdf0e10cSrcweir 	if( nSpaceAdded < mnMinKashidaWidth )
2630*cdf0e10cSrcweir 	{
2631*cdf0e10cSrcweir 		// ugly: steal some pixels
2632*cdf0e10cSrcweir 		long nSteal = 1;
2633*cdf0e10cSrcweir 		if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
2634*cdf0e10cSrcweir 			nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
2635*cdf0e10cSrcweir 		for( int i = nMinPos; i <= nMaxPos; ++i )
2636*cdf0e10cSrcweir 		{
2637*cdf0e10cSrcweir 			if( i == nKashPos )
2638*cdf0e10cSrcweir 				continue;
2639*cdf0e10cSrcweir 			nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
2640*cdf0e10cSrcweir 			if ( nSteal > 0 )
2641*cdf0e10cSrcweir 			{
2642*cdf0e10cSrcweir 				mpJustifications [ i ] -= nSteal;
2643*cdf0e10cSrcweir 				mpJustifications [ nKashPos ] += nSteal;
2644*cdf0e10cSrcweir 				nSpaceAdded += nSteal;
2645*cdf0e10cSrcweir 			}
2646*cdf0e10cSrcweir 			if( nSpaceAdded >= mnMinKashidaWidth )
2647*cdf0e10cSrcweir 				return true;
2648*cdf0e10cSrcweir 		}
2649*cdf0e10cSrcweir 	}
2650*cdf0e10cSrcweir 
2651*cdf0e10cSrcweir 	// blank padding
2652*cdf0e10cSrcweir 	long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
2653*cdf0e10cSrcweir 	if( nSpaceMissing > 0 )
2654*cdf0e10cSrcweir 	{
2655*cdf0e10cSrcweir 		// inner glyph: distribute extra space evenly
2656*cdf0e10cSrcweir 		if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
2657*cdf0e10cSrcweir 		{
2658*cdf0e10cSrcweir 			mpJustifications [ nKashPos ] += nSpaceMissing;
2659*cdf0e10cSrcweir 			long nHalfSpace = nSpaceMissing / 2;
2660*cdf0e10cSrcweir 			mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
2661*cdf0e10cSrcweir 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
2662*cdf0e10cSrcweir 		}
2663*cdf0e10cSrcweir 		// rightmost: left glyph gets extra space
2664*cdf0e10cSrcweir 		else if( nMinPos > nMinGlyphPos )
2665*cdf0e10cSrcweir 		{
2666*cdf0e10cSrcweir 			mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
2667*cdf0e10cSrcweir 			mpJustifications [ nKashPos ] += nSpaceMissing;
2668*cdf0e10cSrcweir 		}
2669*cdf0e10cSrcweir 		// leftmost: right glyph gets extra space
2670*cdf0e10cSrcweir 		else if( nMaxPos < nEndGlyphPos - 1 )
2671*cdf0e10cSrcweir 		{
2672*cdf0e10cSrcweir 			mpJustifications [ nKashPos ] += nSpaceMissing;
2673*cdf0e10cSrcweir 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
2674*cdf0e10cSrcweir 		}
2675*cdf0e10cSrcweir 		else
2676*cdf0e10cSrcweir 			return false;
2677*cdf0e10cSrcweir 	}
2678*cdf0e10cSrcweir 
2679*cdf0e10cSrcweir 	return true;
2680*cdf0e10cSrcweir }
2681*cdf0e10cSrcweir 
2682*cdf0e10cSrcweir // -----------------------------------------------------------------------
2683*cdf0e10cSrcweir 
2684*cdf0e10cSrcweir void UniscribeLayout::Justify( long nNewWidth )
2685*cdf0e10cSrcweir {
2686*cdf0e10cSrcweir     long nOldWidth = 0;
2687*cdf0e10cSrcweir     int i;
2688*cdf0e10cSrcweir     for( i = mnMinCharPos; i < mnEndCharPos; ++i )
2689*cdf0e10cSrcweir         nOldWidth += mpCharWidths[ i ];
2690*cdf0e10cSrcweir 	if( nOldWidth <= 0 )
2691*cdf0e10cSrcweir 		return;
2692*cdf0e10cSrcweir 
2693*cdf0e10cSrcweir     nNewWidth *= mnUnitsPerPixel;	// convert into font units
2694*cdf0e10cSrcweir     if( nNewWidth == nOldWidth )
2695*cdf0e10cSrcweir         return;
2696*cdf0e10cSrcweir     // prepare to distribute the extra width evenly among the visual items
2697*cdf0e10cSrcweir     const double fStretch = (double)nNewWidth / nOldWidth;
2698*cdf0e10cSrcweir 
2699*cdf0e10cSrcweir     // initialize justifications array
2700*cdf0e10cSrcweir     mpJustifications = new int[ mnGlyphCapacity ];
2701*cdf0e10cSrcweir     for( i = 0; i < mnGlyphCapacity; ++i )
2702*cdf0e10cSrcweir         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2703*cdf0e10cSrcweir 
2704*cdf0e10cSrcweir     // justify stretched script items
2705*cdf0e10cSrcweir     long nXOffset = 0;
2706*cdf0e10cSrcweir     SCRIPT_CACHE& rScriptCache = GetScriptCache();
2707*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2708*cdf0e10cSrcweir     {
2709*cdf0e10cSrcweir         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2710*cdf0e10cSrcweir         if( rVisualItem.IsEmpty() )
2711*cdf0e10cSrcweir             continue;
2712*cdf0e10cSrcweir 
2713*cdf0e10cSrcweir         if( (rVisualItem.mnMinCharPos < mnEndCharPos)
2714*cdf0e10cSrcweir          && (rVisualItem.mnEndCharPos > mnMinCharPos) )
2715*cdf0e10cSrcweir         {
2716*cdf0e10cSrcweir             long nItemWidth = 0;
2717*cdf0e10cSrcweir             for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
2718*cdf0e10cSrcweir                 nItemWidth += mpCharWidths[ i ];
2719*cdf0e10cSrcweir             nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
2720*cdf0e10cSrcweir 
2721*cdf0e10cSrcweir             HRESULT nRC = (*pScriptJustify) (
2722*cdf0e10cSrcweir                 mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2723*cdf0e10cSrcweir                 mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2724*cdf0e10cSrcweir                 rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2725*cdf0e10cSrcweir                 nItemWidth,
2726*cdf0e10cSrcweir                 mnMinKashidaWidth,
2727*cdf0e10cSrcweir                 mpJustifications + rVisualItem.mnMinGlyphPos );
2728*cdf0e10cSrcweir 
2729*cdf0e10cSrcweir             rVisualItem.mnXOffset = nXOffset;
2730*cdf0e10cSrcweir             nXOffset += nItemWidth;
2731*cdf0e10cSrcweir         }
2732*cdf0e10cSrcweir     }
2733*cdf0e10cSrcweir }
2734*cdf0e10cSrcweir 
2735*cdf0e10cSrcweir // -----------------------------------------------------------------------
2736*cdf0e10cSrcweir 
2737*cdf0e10cSrcweir bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
2738*cdf0e10cSrcweir {
2739*cdf0e10cSrcweir 	// we have to find the visual item first since the mpLogClusters[]
2740*cdf0e10cSrcweir     // needed to find the cluster start is relative to to the visual item
2741*cdf0e10cSrcweir     int nMinGlyphIndex = -1;
2742*cdf0e10cSrcweir     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2743*cdf0e10cSrcweir     {
2744*cdf0e10cSrcweir         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2745*cdf0e10cSrcweir         if( (nCharPos >= rVisualItem.mnMinCharPos)
2746*cdf0e10cSrcweir         &&  (nCharPos < rVisualItem.mnEndCharPos) )
2747*cdf0e10cSrcweir 		{
2748*cdf0e10cSrcweir 			nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2749*cdf0e10cSrcweir             break;
2750*cdf0e10cSrcweir 		}
2751*cdf0e10cSrcweir     }
2752*cdf0e10cSrcweir 	// Invalid char pos or leftmost glyph in visual item
2753*cdf0e10cSrcweir     if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
2754*cdf0e10cSrcweir 		return false;
2755*cdf0e10cSrcweir 
2756*cdf0e10cSrcweir //	This test didn't give the expected results
2757*cdf0e10cSrcweir /*	if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
2758*cdf0e10cSrcweir 	// two chars, one glyph
2759*cdf0e10cSrcweir 		return false;*/
2760*cdf0e10cSrcweir 
2761*cdf0e10cSrcweir 	const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
2762*cdf0e10cSrcweir 	if( nGlyphPos <= 0 )
2763*cdf0e10cSrcweir 		return true;
2764*cdf0e10cSrcweir 	// justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
2765*cdf0e10cSrcweir 	// and not SCRIPT_JUSTIFY_ARABIC_BLANK
2766*cdf0e10cSrcweir 	// special case: glyph to the left is vowel (no advance width)
2767*cdf0e10cSrcweir 	if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
2768*cdf0e10cSrcweir 		|| ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
2769*cdf0e10cSrcweir 			&& mpGlyphAdvances [ nGlyphPos-1 ] ))
2770*cdf0e10cSrcweir 		return false;
2771*cdf0e10cSrcweir 	return true;
2772*cdf0e10cSrcweir }
2773*cdf0e10cSrcweir 
2774*cdf0e10cSrcweir #endif // USE_UNISCRIBE
2775*cdf0e10cSrcweir 
2776*cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2777*cdf0e10cSrcweir 
2778*cdf0e10cSrcweir class GraphiteLayoutWinImpl : public GraphiteLayout
2779*cdf0e10cSrcweir {
2780*cdf0e10cSrcweir public:
2781*cdf0e10cSrcweir     GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
2782*cdf0e10cSrcweir         throw()
2783*cdf0e10cSrcweir     : GraphiteLayout(font), mrFont(rFont) {};
2784*cdf0e10cSrcweir     virtual ~GraphiteLayoutWinImpl() throw() {};
2785*cdf0e10cSrcweir     virtual sal_GlyphId getKashidaGlyph(int & rWidth);
2786*cdf0e10cSrcweir private:
2787*cdf0e10cSrcweir     ImplWinFontEntry & mrFont;
2788*cdf0e10cSrcweir };
2789*cdf0e10cSrcweir 
2790*cdf0e10cSrcweir sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
2791*cdf0e10cSrcweir {
2792*cdf0e10cSrcweir     rWidth = mrFont.GetMinKashidaWidth();
2793*cdf0e10cSrcweir     return mrFont.GetMinKashidaGlyph();
2794*cdf0e10cSrcweir }
2795*cdf0e10cSrcweir 
2796*cdf0e10cSrcweir // This class uses the SIL Graphite engine to provide complex text layout services to the VCL
2797*cdf0e10cSrcweir // @author tse
2798*cdf0e10cSrcweir //
2799*cdf0e10cSrcweir class GraphiteWinLayout : public WinLayout
2800*cdf0e10cSrcweir {
2801*cdf0e10cSrcweir private:
2802*cdf0e10cSrcweir     mutable GraphiteWinFont mpFont;
2803*cdf0e10cSrcweir     grutils::GrFeatureParser * mpFeatures;
2804*cdf0e10cSrcweir     mutable GraphiteLayoutWinImpl maImpl;
2805*cdf0e10cSrcweir public:
2806*cdf0e10cSrcweir     GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
2807*cdf0e10cSrcweir 
2808*cdf0e10cSrcweir     static bool IsGraphiteEnabledFont(HDC hDC) throw();
2809*cdf0e10cSrcweir 
2810*cdf0e10cSrcweir     // used by upper layers
2811*cdf0e10cSrcweir     virtual bool  LayoutText( ImplLayoutArgs& );    // first step of layout
2812*cdf0e10cSrcweir     virtual void  AdjustLayout( ImplLayoutArgs& );  // adjusting after fallback etc.
2813*cdf0e10cSrcweir     //  virtual void  InitFont() const;
2814*cdf0e10cSrcweir     virtual void  DrawText( SalGraphics& ) const;
2815*cdf0e10cSrcweir 
2816*cdf0e10cSrcweir     // methods using string indexing
2817*cdf0e10cSrcweir     virtual int   GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
2818*cdf0e10cSrcweir     virtual long  FillDXArray( long* pDXArray ) const;
2819*cdf0e10cSrcweir 
2820*cdf0e10cSrcweir     virtual void  GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
2821*cdf0e10cSrcweir 
2822*cdf0e10cSrcweir     // methods using glyph indexing
2823*cdf0e10cSrcweir     virtual int   GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
2824*cdf0e10cSrcweir                       long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
2825*cdf0e10cSrcweir 
2826*cdf0e10cSrcweir     // used by glyph+font+script fallback
2827*cdf0e10cSrcweir     virtual void    MoveGlyph( int nStart, long nNewXPos );
2828*cdf0e10cSrcweir     virtual void    DropGlyph( int nStart );
2829*cdf0e10cSrcweir     virtual void    Simplify( bool bIsBase );
2830*cdf0e10cSrcweir     ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
2831*cdf0e10cSrcweir protected:
2832*cdf0e10cSrcweir     virtual void    ReplaceDC(gr::Segment & segment) const;
2833*cdf0e10cSrcweir     virtual void    RestoreDC(gr::Segment & segment) const;
2834*cdf0e10cSrcweir };
2835*cdf0e10cSrcweir 
2836*cdf0e10cSrcweir bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
2837*cdf0e10cSrcweir {
2838*cdf0e10cSrcweir   return gr::WinFont::FontHasGraphiteTables(hDC);
2839*cdf0e10cSrcweir }
2840*cdf0e10cSrcweir 
2841*cdf0e10cSrcweir GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
2842*cdf0e10cSrcweir   : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
2843*cdf0e10cSrcweir     maImpl(mpFont, rWFE)
2844*cdf0e10cSrcweir {
2845*cdf0e10cSrcweir     const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
2846*cdf0e10cSrcweir     rtl::OString name = rtl::OUStringToOString(
2847*cdf0e10cSrcweir         rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
2848*cdf0e10cSrcweir     sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
2849*cdf0e10cSrcweir     if (nFeat > 0)
2850*cdf0e10cSrcweir     {
2851*cdf0e10cSrcweir         rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
2852*cdf0e10cSrcweir         mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
2853*cdf0e10cSrcweir     }
2854*cdf0e10cSrcweir     else
2855*cdf0e10cSrcweir     {
2856*cdf0e10cSrcweir         mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
2857*cdf0e10cSrcweir     }
2858*cdf0e10cSrcweir     maImpl.SetFeatures(mpFeatures);
2859*cdf0e10cSrcweir }
2860*cdf0e10cSrcweir 
2861*cdf0e10cSrcweir void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
2862*cdf0e10cSrcweir {
2863*cdf0e10cSrcweir     COLORREF color = GetTextColor(mhDC);
2864*cdf0e10cSrcweir     dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
2865*cdf0e10cSrcweir     SetTextColor(mhDC, color);
2866*cdf0e10cSrcweir }
2867*cdf0e10cSrcweir 
2868*cdf0e10cSrcweir void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
2869*cdf0e10cSrcweir {
2870*cdf0e10cSrcweir     dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
2871*cdf0e10cSrcweir }
2872*cdf0e10cSrcweir 
2873*cdf0e10cSrcweir bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
2874*cdf0e10cSrcweir {
2875*cdf0e10cSrcweir     if (args.mnMinCharPos >= args.mnEndCharPos)
2876*cdf0e10cSrcweir     {
2877*cdf0e10cSrcweir         maImpl.clear();
2878*cdf0e10cSrcweir         return true;
2879*cdf0e10cSrcweir     }
2880*cdf0e10cSrcweir     HFONT hUnRotatedFont;
2881*cdf0e10cSrcweir     if (args.mnOrientation)
2882*cdf0e10cSrcweir     {
2883*cdf0e10cSrcweir         // Graphite gets very confused if the font is rotated
2884*cdf0e10cSrcweir         LOGFONTW aLogFont;
2885*cdf0e10cSrcweir         ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
2886*cdf0e10cSrcweir         aLogFont.lfEscapement = 0;
2887*cdf0e10cSrcweir         aLogFont.lfOrientation = 0;
2888*cdf0e10cSrcweir         hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
2889*cdf0e10cSrcweir         ::SelectFont(mhDC, hUnRotatedFont);
2890*cdf0e10cSrcweir     }
2891*cdf0e10cSrcweir     WinLayout::AdjustLayout(args);
2892*cdf0e10cSrcweir     mpFont.replaceDC(mhDC);
2893*cdf0e10cSrcweir     maImpl.SetFontScale(WinLayout::mfFontScale);
2894*cdf0e10cSrcweir     //bool succeeded = maImpl.LayoutText(args);
2895*cdf0e10cSrcweir #ifdef GRCACHE
2896*cdf0e10cSrcweir     GrSegRecord * pSegRecord = NULL;
2897*cdf0e10cSrcweir     gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
2898*cdf0e10cSrcweir #else
2899*cdf0e10cSrcweir     gr::Segment * pSegment = maImpl.CreateSegment(args);
2900*cdf0e10cSrcweir #endif
2901*cdf0e10cSrcweir     bool bSucceeded = false;
2902*cdf0e10cSrcweir     if (pSegment)
2903*cdf0e10cSrcweir     {
2904*cdf0e10cSrcweir         // replace the DC on the font within the segment
2905*cdf0e10cSrcweir         ReplaceDC(*pSegment);
2906*cdf0e10cSrcweir         // create glyph vectors
2907*cdf0e10cSrcweir #ifdef GRCACHE
2908*cdf0e10cSrcweir         bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
2909*cdf0e10cSrcweir #else
2910*cdf0e10cSrcweir         bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
2911*cdf0e10cSrcweir #endif
2912*cdf0e10cSrcweir         // restore original DC
2913*cdf0e10cSrcweir         RestoreDC(*pSegment);
2914*cdf0e10cSrcweir #ifdef GRCACHE
2915*cdf0e10cSrcweir         if (pSegRecord) pSegRecord->unlock();
2916*cdf0e10cSrcweir         else delete pSegment;
2917*cdf0e10cSrcweir #else
2918*cdf0e10cSrcweir         delete pSegment;
2919*cdf0e10cSrcweir #endif
2920*cdf0e10cSrcweir     }
2921*cdf0e10cSrcweir     mpFont.restoreDC();
2922*cdf0e10cSrcweir     if (args.mnOrientation)
2923*cdf0e10cSrcweir     {
2924*cdf0e10cSrcweir         // restore the rotated font
2925*cdf0e10cSrcweir         ::SelectFont(mhDC, mhFont);
2926*cdf0e10cSrcweir         ::DeleteObject(hUnRotatedFont);
2927*cdf0e10cSrcweir     }
2928*cdf0e10cSrcweir     return bSucceeded;
2929*cdf0e10cSrcweir }
2930*cdf0e10cSrcweir 
2931*cdf0e10cSrcweir void  GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
2932*cdf0e10cSrcweir {
2933*cdf0e10cSrcweir     WinLayout::AdjustLayout(rArgs);
2934*cdf0e10cSrcweir     maImpl.DrawBase() = WinLayout::maDrawBase;
2935*cdf0e10cSrcweir     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2936*cdf0e10cSrcweir     if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
2937*cdf0e10cSrcweir     {
2938*cdf0e10cSrcweir         mrWinFontEntry.InitKashidaHandling(mhDC);
2939*cdf0e10cSrcweir     }
2940*cdf0e10cSrcweir     maImpl.AdjustLayout(rArgs);
2941*cdf0e10cSrcweir }
2942*cdf0e10cSrcweir 
2943*cdf0e10cSrcweir void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
2944*cdf0e10cSrcweir {
2945*cdf0e10cSrcweir     HFONT hOrigFont = DisableFontScaling();
2946*cdf0e10cSrcweir     HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
2947*cdf0e10cSrcweir     maImpl.DrawBase() = WinLayout::maDrawBase;
2948*cdf0e10cSrcweir     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2949*cdf0e10cSrcweir     const int MAX_GLYPHS = 2;
2950*cdf0e10cSrcweir     sal_GlyphId glyphIntStr[MAX_GLYPHS];
2951*cdf0e10cSrcweir     WORD glyphWStr[MAX_GLYPHS];
2952*cdf0e10cSrcweir     int glyphIndex = 0;
2953*cdf0e10cSrcweir     Point aPos(0,0);
2954*cdf0e10cSrcweir     int nGlyphs = 0;
2955*cdf0e10cSrcweir     do
2956*cdf0e10cSrcweir     {
2957*cdf0e10cSrcweir         nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
2958*cdf0e10cSrcweir         if (nGlyphs < 1)
2959*cdf0e10cSrcweir           break;
2960*cdf0e10cSrcweir         std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
2961*cdf0e10cSrcweir         ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
2962*cdf0e10cSrcweir 		              NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
2963*cdf0e10cSrcweir     } while (nGlyphs);
2964*cdf0e10cSrcweir     if( hOrigFont )
2965*cdf0e10cSrcweir           DeleteFont( SelectFont( mhDC, hOrigFont ) );
2966*cdf0e10cSrcweir }
2967*cdf0e10cSrcweir 
2968*cdf0e10cSrcweir int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2969*cdf0e10cSrcweir {
2970*cdf0e10cSrcweir     mpFont.replaceDC(mhDC);
2971*cdf0e10cSrcweir     int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
2972*cdf0e10cSrcweir     mpFont.restoreDC();
2973*cdf0e10cSrcweir     return nBreak;
2974*cdf0e10cSrcweir }
2975*cdf0e10cSrcweir 
2976*cdf0e10cSrcweir long  GraphiteWinLayout::FillDXArray( long* pDXArray ) const
2977*cdf0e10cSrcweir {
2978*cdf0e10cSrcweir     return maImpl.FillDXArray(pDXArray);
2979*cdf0e10cSrcweir }
2980*cdf0e10cSrcweir 
2981*cdf0e10cSrcweir void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
2982*cdf0e10cSrcweir {
2983*cdf0e10cSrcweir 	maImpl.GetCaretPositions(nArraySize, pCaretXArray);
2984*cdf0e10cSrcweir }
2985*cdf0e10cSrcweir 
2986*cdf0e10cSrcweir int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
2987*cdf0e10cSrcweir         ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
2988*cdf0e10cSrcweir {
2989*cdf0e10cSrcweir     maImpl.DrawBase() = WinLayout::maDrawBase;
2990*cdf0e10cSrcweir     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2991*cdf0e10cSrcweir     return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
2992*cdf0e10cSrcweir }
2993*cdf0e10cSrcweir 
2994*cdf0e10cSrcweir void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
2995*cdf0e10cSrcweir {
2996*cdf0e10cSrcweir 	maImpl.MoveGlyph(glyph_idx, new_x_pos);
2997*cdf0e10cSrcweir }
2998*cdf0e10cSrcweir 
2999*cdf0e10cSrcweir void GraphiteWinLayout::DropGlyph( int glyph_idx )
3000*cdf0e10cSrcweir {
3001*cdf0e10cSrcweir 	maImpl.DropGlyph(glyph_idx);
3002*cdf0e10cSrcweir }
3003*cdf0e10cSrcweir 
3004*cdf0e10cSrcweir void GraphiteWinLayout::Simplify( bool is_base )
3005*cdf0e10cSrcweir {
3006*cdf0e10cSrcweir 	maImpl.Simplify(is_base);
3007*cdf0e10cSrcweir }
3008*cdf0e10cSrcweir #endif // ENABLE_GRAPHITE
3009*cdf0e10cSrcweir // =======================================================================
3010*cdf0e10cSrcweir 
3011*cdf0e10cSrcweir SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
3012*cdf0e10cSrcweir {
3013*cdf0e10cSrcweir     DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
3014*cdf0e10cSrcweir 
3015*cdf0e10cSrcweir 	WinLayout* pWinLayout = NULL;
3016*cdf0e10cSrcweir 
3017*cdf0e10cSrcweir     const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ];
3018*cdf0e10cSrcweir     ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
3019*cdf0e10cSrcweir 
3020*cdf0e10cSrcweir #if defined( USE_UNISCRIBE )
3021*cdf0e10cSrcweir     if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
3022*cdf0e10cSrcweir     &&   (aUspModule || (bUspEnabled && InitUSP())) )   // CTL layout engine
3023*cdf0e10cSrcweir     {
3024*cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
3025*cdf0e10cSrcweir         if (rFontFace.SupportsGraphite())
3026*cdf0e10cSrcweir             pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
3027*cdf0e10cSrcweir         else
3028*cdf0e10cSrcweir #endif // ENABLE_GRAPHITE
3029*cdf0e10cSrcweir         // script complexity is determined in upper layers
3030*cdf0e10cSrcweir         pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
3031*cdf0e10cSrcweir         // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
3032*cdf0e10cSrcweir         // the created UniscribeLayout, otherwise the data passed into the
3033*cdf0e10cSrcweir         // constructor might become invalid too early
3034*cdf0e10cSrcweir     }
3035*cdf0e10cSrcweir     else
3036*cdf0e10cSrcweir #endif // USE_UNISCRIBE
3037*cdf0e10cSrcweir     {
3038*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
3039*cdf0e10cSrcweir         if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
3040*cdf0e10cSrcweir         {
3041*cdf0e10cSrcweir             // TODO: directly cache kerning info in the rFontInstance
3042*cdf0e10cSrcweir             // TODO: get rid of kerning methods+data in WinSalGraphics object
3043*cdf0e10cSrcweir             GetKernPairs( 0, NULL );
3044*cdf0e10cSrcweir             rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
3045*cdf0e10cSrcweir         }
3046*cdf0e10cSrcweir #endif // GCP_KERN_HACK
3047*cdf0e10cSrcweir 
3048*cdf0e10cSrcweir         BYTE eCharSet = ANSI_CHARSET;
3049*cdf0e10cSrcweir         if( mpLogFont )
3050*cdf0e10cSrcweir             eCharSet = mpLogFont->lfCharSet;
3051*cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
3052*cdf0e10cSrcweir         if (rFontFace.SupportsGraphite())
3053*cdf0e10cSrcweir             pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
3054*cdf0e10cSrcweir         else
3055*cdf0e10cSrcweir #endif // ENABLE_GRAPHITE
3056*cdf0e10cSrcweir             pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
3057*cdf0e10cSrcweir     }
3058*cdf0e10cSrcweir 
3059*cdf0e10cSrcweir     if( mfFontScale != 1.0 )
3060*cdf0e10cSrcweir         pWinLayout->SetFontScale( mfFontScale );
3061*cdf0e10cSrcweir 
3062*cdf0e10cSrcweir     return pWinLayout;
3063*cdf0e10cSrcweir }
3064*cdf0e10cSrcweir 
3065*cdf0e10cSrcweir // -----------------------------------------------------------------------
3066*cdf0e10cSrcweir 
3067*cdf0e10cSrcweir int	WinSalGraphics::GetMinKashidaWidth()
3068*cdf0e10cSrcweir {
3069*cdf0e10cSrcweir 	if( !mpWinFontEntry[0] )
3070*cdf0e10cSrcweir 		return 0;
3071*cdf0e10cSrcweir 	mpWinFontEntry[0]->InitKashidaHandling( mhDC );
3072*cdf0e10cSrcweir 	int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
3073*cdf0e10cSrcweir 	return nMinKashida;
3074*cdf0e10cSrcweir }
3075*cdf0e10cSrcweir 
3076*cdf0e10cSrcweir // =======================================================================
3077*cdf0e10cSrcweir 
3078*cdf0e10cSrcweir ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
3079*cdf0e10cSrcweir :   ImplFontEntry( rFSD )
3080*cdf0e10cSrcweir ,   maWidthMap( 512 )
3081*cdf0e10cSrcweir ,   mpKerningPairs( NULL )
3082*cdf0e10cSrcweir ,   mnKerningPairs( -1 )
3083*cdf0e10cSrcweir ,	mnMinKashidaWidth( -1 )
3084*cdf0e10cSrcweir ,	mnMinKashidaGlyph( -1 )
3085*cdf0e10cSrcweir {
3086*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
3087*cdf0e10cSrcweir     maScriptCache = NULL;
3088*cdf0e10cSrcweir #endif // USE_UNISCRIBE
3089*cdf0e10cSrcweir }
3090*cdf0e10cSrcweir 
3091*cdf0e10cSrcweir // -----------------------------------------------------------------------
3092*cdf0e10cSrcweir 
3093*cdf0e10cSrcweir ImplWinFontEntry::~ImplWinFontEntry()
3094*cdf0e10cSrcweir {
3095*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
3096*cdf0e10cSrcweir     if( maScriptCache != NULL )
3097*cdf0e10cSrcweir         (*pScriptFreeCache)( &maScriptCache );
3098*cdf0e10cSrcweir #endif // USE_UNISCRIBE
3099*cdf0e10cSrcweir #ifdef GCP_KERN_HACK
3100*cdf0e10cSrcweir     delete[] mpKerningPairs;
3101*cdf0e10cSrcweir #endif // GCP_KERN_HACK
3102*cdf0e10cSrcweir }
3103*cdf0e10cSrcweir 
3104*cdf0e10cSrcweir // -----------------------------------------------------------------------
3105*cdf0e10cSrcweir 
3106*cdf0e10cSrcweir bool ImplWinFontEntry::HasKernData() const
3107*cdf0e10cSrcweir {
3108*cdf0e10cSrcweir     return (mnKerningPairs >= 0);
3109*cdf0e10cSrcweir }
3110*cdf0e10cSrcweir 
3111*cdf0e10cSrcweir // -----------------------------------------------------------------------
3112*cdf0e10cSrcweir 
3113*cdf0e10cSrcweir void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
3114*cdf0e10cSrcweir {
3115*cdf0e10cSrcweir     mnKerningPairs = nPairCount;
3116*cdf0e10cSrcweir     mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
3117*cdf0e10cSrcweir     ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) );
3118*cdf0e10cSrcweir }
3119*cdf0e10cSrcweir 
3120*cdf0e10cSrcweir // -----------------------------------------------------------------------
3121*cdf0e10cSrcweir 
3122*cdf0e10cSrcweir int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
3123*cdf0e10cSrcweir {
3124*cdf0e10cSrcweir     int nKernAmount = 0;
3125*cdf0e10cSrcweir     if( mpKerningPairs )
3126*cdf0e10cSrcweir     {
3127*cdf0e10cSrcweir         const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
3128*cdf0e10cSrcweir         const KERNINGPAIR* pFirstPair = mpKerningPairs;
3129*cdf0e10cSrcweir         const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
3130*cdf0e10cSrcweir         const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
3131*cdf0e10cSrcweir             pEndPair, aRefPair, ImplCmpKernData );
3132*cdf0e10cSrcweir         if( (pPair != pEndPair)
3133*cdf0e10cSrcweir         &&  (pPair->wFirst == aRefPair.wFirst)
3134*cdf0e10cSrcweir         &&  (pPair->wSecond == aRefPair.wSecond) )
3135*cdf0e10cSrcweir             nKernAmount = pPair->iKernAmount;
3136*cdf0e10cSrcweir     }
3137*cdf0e10cSrcweir 
3138*cdf0e10cSrcweir     return nKernAmount;
3139*cdf0e10cSrcweir }
3140*cdf0e10cSrcweir 
3141*cdf0e10cSrcweir // -----------------------------------------------------------------------
3142*cdf0e10cSrcweir 
3143*cdf0e10cSrcweir bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
3144*cdf0e10cSrcweir {
3145*cdf0e10cSrcweir 	if( mnMinKashidaWidth >= 0 )	// already cached?
3146*cdf0e10cSrcweir 		return mnMinKashidaWidth;
3147*cdf0e10cSrcweir 
3148*cdf0e10cSrcweir 	// initialize the kashida width
3149*cdf0e10cSrcweir 	mnMinKashidaWidth = 0;
3150*cdf0e10cSrcweir 	mnMinKashidaGlyph = 0;
3151*cdf0e10cSrcweir #ifdef USE_UNISCRIBE
3152*cdf0e10cSrcweir 	if (aUspModule || (bUspEnabled && InitUSP()))
3153*cdf0e10cSrcweir 	{
3154*cdf0e10cSrcweir 		SCRIPT_FONTPROPERTIES aFontProperties;
3155*cdf0e10cSrcweir 		aFontProperties.cBytes = sizeof (aFontProperties);
3156*cdf0e10cSrcweir 		SCRIPT_CACHE& rScriptCache = GetScriptCache();
3157*cdf0e10cSrcweir 		HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
3158*cdf0e10cSrcweir 		if( nRC != 0 )
3159*cdf0e10cSrcweir 			return false;
3160*cdf0e10cSrcweir 		mnMinKashidaWidth = aFontProperties.iKashidaWidth;
3161*cdf0e10cSrcweir 		mnMinKashidaGlyph = aFontProperties.wgKashida;
3162*cdf0e10cSrcweir     }
3163*cdf0e10cSrcweir #endif // USE_UNISCRIBE
3164*cdf0e10cSrcweir 
3165*cdf0e10cSrcweir 	return true;
3166*cdf0e10cSrcweir }
3167*cdf0e10cSrcweir 
3168*cdf0e10cSrcweir // =======================================================================
3169*cdf0e10cSrcweir 
3170*cdf0e10cSrcweir ImplFontData* ImplWinFontData::Clone() const
3171*cdf0e10cSrcweir {
3172*cdf0e10cSrcweir     if( mpUnicodeMap )
3173*cdf0e10cSrcweir         mpUnicodeMap->AddReference();
3174*cdf0e10cSrcweir     ImplFontData* pClone = new ImplWinFontData( *this );
3175*cdf0e10cSrcweir     return pClone;
3176*cdf0e10cSrcweir }
3177*cdf0e10cSrcweir 
3178*cdf0e10cSrcweir // -----------------------------------------------------------------------
3179*cdf0e10cSrcweir 
3180*cdf0e10cSrcweir ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
3181*cdf0e10cSrcweir {
3182*cdf0e10cSrcweir     ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD );
3183*cdf0e10cSrcweir     return pEntry;
3184*cdf0e10cSrcweir }
3185*cdf0e10cSrcweir 
3186*cdf0e10cSrcweir // =======================================================================
3187