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