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