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