xref: /aoo42x/main/vcl/win/source/gdi/winlayout.cxx (revision 79aad27f)
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     OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
1136     aUspModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
1137     if( !aUspModule )
1138         return (bUspEnabled = false);
1139 
1140     pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD))
1141         osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" );
1142     bUspEnabled &= (NULL != pScriptIsComplex);
1143 
1144     pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int,
1145         const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*))
1146         osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" );
1147     bUspEnabled &= (NULL != pScriptItemize);
1148 
1149     pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*,
1150         int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*))
1151         osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" );
1152     bUspEnabled &= (NULL != pScriptShape);
1153 
1154     pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int,
1155         const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*))
1156         osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" );
1157     bUspEnabled &= (NULL != pScriptPlace);
1158 
1159     pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*,
1160         int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*))
1161         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" );
1162     bUspEnabled &= (NULL != pScriptGetLogicalWidths);
1163 
1164     pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*,
1165         const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*))
1166         osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" );
1167     bUspEnabled &= (NULL != pScriptApplyLogicalWidth);
1168 
1169     pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*,
1170         int,int,int,int*))
1171         osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" );
1172     bUspEnabled &= (NULL != pScriptJustify);
1173 
1174     pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*))
1175         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" );
1176     bUspEnabled &= (NULL != pScriptGetFontProperties);
1177 
1178     pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*,
1179         int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*,
1180         int,const WORD*,int,const int*,const int*,const GOFFSET*))
1181         osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" );
1182     bUspEnabled &= (NULL != pScriptTextOut);
1183 
1184     pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*))
1185         osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" );
1186     bUspEnabled &= (NULL != pScriptFreeCache);
1187 
1188     if( !bUspEnabled )
1189     {
1190         osl_unloadModule( aUspModule );
1191         aUspModule = NULL;
1192     }
1193 
1194 	// get the DLL version info
1195 	int nUspVersion = 0;
1196 	// TODO: there must be a simpler way to get the friggin version info from OSL?
1197 	rtl_uString* pModuleURL = NULL;
1198 	osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL );
1199 	rtl_uString* pModuleFileName = NULL;
1200 	if( pModuleURL )
1201 		osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
1202 	const sal_Unicode* pModuleFileCStr = NULL;
1203 	if( pModuleFileName )
1204 		pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
1205 	if( pModuleFileCStr )
1206 	{
1207 		DWORD nHandle;
1208 		DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
1209 		char* pBuffer = (char*)alloca( nBufSize );
1210 		BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
1211 		VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
1212 		UINT nFixedFileSize = 0;
1213 		if( bRC )
1214 			::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
1215 		if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
1216 			nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
1217 						+ LOWORD(pFixedFileInfo->dwProductVersionMS);
1218 	}
1219 
1220 	// #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
1221 	if( nUspVersion >= 10600 )
1222 		bManualCellAlign = false;
1223 
1224     return bUspEnabled;
1225 }
1226 
1227 // -----------------------------------------------------------------------
1228 
1229 UniscribeLayout::UniscribeLayout( HDC hDC,
1230     const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
1231 :   WinLayout( hDC, rWinFontData, rWinFontEntry ),
1232     mnItemCount( 0 ),
1233     mpScriptItems( NULL ),
1234     mpVisualItems( NULL ),
1235     mpLogClusters( NULL ),
1236     mpCharWidths( NULL ),
1237     mnCharCapacity( 0 ),
1238     mnSubStringMin( 0 ),
1239     mnGlyphCapacity( 0 ),
1240     mnGlyphCount( 0 ),
1241     mpOutGlyphs( NULL ),
1242     mpGlyphAdvances( NULL ),
1243     mpJustifications( NULL ),
1244     mpGlyphOffsets( NULL ),
1245     mpVisualAttrs( NULL ),
1246     mpGlyphs2Chars( NULL ),
1247     mnMinKashidaGlyph( 0 ),
1248     mbDisableGlyphInjection( false )
1249 {}
1250 
1251 // -----------------------------------------------------------------------
1252 
1253 UniscribeLayout::~UniscribeLayout()
1254 {
1255     delete[] mpScriptItems;
1256     delete[] mpVisualItems;
1257     delete[] mpLogClusters;
1258     delete[] mpCharWidths;
1259     delete[] mpOutGlyphs;
1260     delete[] mpGlyphAdvances;
1261     delete[] mpJustifications;
1262     delete[] mpGlyphOffsets;
1263     delete[] mpVisualAttrs;
1264     delete[] mpGlyphs2Chars;
1265 }
1266 
1267 // -----------------------------------------------------------------------
1268 
1269 bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
1270 {
1271     // for a base layout only the context glyphs have to be dropped
1272     // => when the whole string is involved there is no extra context
1273     typedef std::vector<int> TIntVector;
1274     TIntVector aDropChars;
1275     if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
1276     {
1277         // calculate superfluous context char positions
1278         aDropChars.push_back( 0 );
1279         aDropChars.push_back( rArgs.mnLength );
1280         int nMin, nEnd;
1281         bool bRTL;
1282         for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
1283         {
1284             aDropChars.push_back( nMin );
1285             aDropChars.push_back( nEnd );
1286         }
1287         // prepare aDropChars for binary search which will allow to
1288         // not bother with visual items that will be dropped anyway
1289         std::sort( aDropChars.begin(), aDropChars.end() );
1290     }
1291 
1292     // prepare layout
1293     // TODO: fix case when recyclying old UniscribeLayout object
1294     mnMinCharPos = rArgs.mnMinCharPos;
1295     mnEndCharPos = rArgs.mnEndCharPos;
1296 
1297     // determine script items from string
1298 
1299     // prepare itemization
1300     // TODO: try to avoid itemization since it costs a lot of performance
1301     SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0};
1302     aScriptState.uBidiLevel         = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL));
1303     aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG));
1304     aScriptState.fDigitSubstitute   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1305     aScriptState.fArabicNumContext  = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
1306     DWORD nLangId = 0;  // TODO: get language from font
1307     SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0};
1308     aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
1309     aScriptControl.fContextDigits   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1310     // determine relevant substring and work only on it
1311     // when Bidi status is unknown we need to look at the whole string though
1312     mnSubStringMin = 0;
1313     int nSubStringEnd = rArgs.mnLength;
1314     if( aScriptState.fOverrideDirection )
1315     {
1316         // TODO: limit substring to portion limits
1317         mnSubStringMin = rArgs.mnMinCharPos - 8;
1318         if( mnSubStringMin < 0 )
1319             mnSubStringMin = 0;
1320         nSubStringEnd = rArgs.mnEndCharPos + 8;
1321         if( nSubStringEnd > rArgs.mnLength )
1322             nSubStringEnd = rArgs.mnLength;
1323 
1324     }
1325 
1326     // now itemize the substring with its context
1327     for( int nItemCapacity = 16;; nItemCapacity *= 8 )
1328     {
1329         mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
1330         HRESULT nRC = (*pScriptItemize)(
1331             reinterpret_cast<LPCWSTR>(rArgs.mpStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
1332             nItemCapacity - 1, &aScriptControl, &aScriptState,
1333             mpScriptItems, &mnItemCount );
1334         if( !nRC )  // break loop when everything is correctly itemized
1335             break;
1336 
1337         // prepare bigger buffers for another itemization round
1338         delete[] mpScriptItems;
1339         mpScriptItems = NULL;
1340         if( nRC != E_OUTOFMEMORY )
1341             return false;
1342         if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
1343             return false;
1344     }
1345 
1346     // calculate the order of visual items
1347     int nItem, i;
1348 
1349     // adjust char positions by substring offset
1350     for( nItem = 0; nItem <= mnItemCount; ++nItem )
1351         mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
1352     // default visual item ordering
1353     mpVisualItems = new VisualItem[ mnItemCount ];
1354     for( nItem = 0; nItem < mnItemCount; ++nItem )
1355     {
1356         // initialize char specific item info
1357         VisualItem& rVisualItem = mpVisualItems[ nItem ];
1358         SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
1359         rVisualItem.mpScriptItem = pScriptItem;
1360         rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
1361         rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
1362     }
1363 
1364     // reorder visual item order if needed
1365     if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
1366     {
1367         // force RTL item ordering if requested
1368         if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL )
1369         {
1370             VisualItem* pVI0 = &mpVisualItems[ 0 ];
1371             VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
1372             while( pVI0 < --pVI1 )
1373             {
1374                 VisualItem aVtmp = *pVI0;
1375                 *(pVI0++) = *pVI1;
1376                 *pVI1 = aVtmp;
1377             }
1378         }
1379     }
1380     else if( mnItemCount > 1 )
1381     {
1382         // apply bidi algorithm's rule L2 on item level
1383         // TODO: use faster L2 algorithm
1384         int nMaxBidiLevel = 0;
1385         VisualItem* pVI = &mpVisualItems[0];
1386         VisualItem* const pVIend = pVI + mnItemCount;
1387         for(; pVI < pVIend; ++pVI )
1388             if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
1389                 nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
1390 
1391         while( --nMaxBidiLevel >= 0 )
1392         {
1393             for( pVI = &mpVisualItems[0]; pVI < pVIend; )
1394             {
1395                 // find item range that needs reordering
1396                 for(; pVI < pVIend; ++pVI )
1397                     if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
1398                         break;
1399                 VisualItem* pVImin = pVI++;
1400                 for(; pVI < pVIend; ++pVI )
1401                     if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
1402                         break;
1403                 VisualItem* pVImax = pVI++;
1404 
1405                 // reverse order of items in this range
1406                 while( pVImin < --pVImax )
1407                 {
1408                     VisualItem aVtmp = *pVImin;
1409                     *(pVImin++) = *pVImax;
1410                     *pVImax = aVtmp;
1411                 }
1412             }
1413         }
1414     }
1415 
1416     // allocate arrays
1417     // TODO: when reusing object reuse old allocations or delete them
1418     // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
1419     mnCharCapacity  = nSubStringEnd;
1420     mpLogClusters   = new WORD[ mnCharCapacity ];
1421     mpCharWidths    = new int[ mnCharCapacity ];
1422 
1423     mnGlyphCount    = 0;
1424     mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
1425     mpGlyphAdvances = new int[ mnGlyphCapacity ];
1426     mpOutGlyphs     = new WORD[ mnGlyphCapacity ];
1427     mpGlyphOffsets  = new GOFFSET[ mnGlyphCapacity ];
1428     mpVisualAttrs   = new SCRIPT_VISATTR[ mnGlyphCapacity ];
1429 
1430     long nXOffset = 0;
1431     for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
1432         mpCharWidths[j] = 0;
1433 
1434     // layout script items
1435     SCRIPT_CACHE& rScriptCache = GetScriptCache();
1436     for( nItem = 0; nItem < mnItemCount; ++nItem )
1437     {
1438         VisualItem& rVisualItem = mpVisualItems[ nItem ];
1439 
1440         // initialize glyph specific item info
1441         rVisualItem.mnMinGlyphPos = mnGlyphCount;
1442         rVisualItem.mnEndGlyphPos = 0;
1443         rVisualItem.mnXOffset     = nXOffset;
1444         //rVisualItem.mnPixelWidth  = 0;
1445 
1446         // shortcut ignorable items
1447         if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
1448          || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
1449         {
1450             for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
1451                 mpLogClusters[i] = sal::static_int_cast<WORD>(~0U);
1452             continue;
1453         }
1454 
1455         // override bidi analysis if requested
1456         if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
1457         {
1458             // FIXME: is this intended ?
1459             rVisualItem.mpScriptItem->a.fRTL                 = (aScriptState.uBidiLevel & 1);
1460             rVisualItem.mpScriptItem->a.s.uBidiLevel         = aScriptState.uBidiLevel;
1461             rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
1462         }
1463 
1464         // convert the unicodes to glyphs
1465         int nGlyphCount = 0;
1466         int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
1467         HRESULT nRC = (*pScriptShape)( mhDC, &rScriptCache,
1468             reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
1469             nCharCount,
1470             mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
1471             &rVisualItem.mpScriptItem->a,
1472             mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1473             mpLogClusters + rVisualItem.mnMinCharPos,
1474             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1475             &nGlyphCount );
1476 
1477         // find and handle problems in the unicode to glyph conversion
1478         if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
1479         {
1480             // the whole visual item needs a fallback, but make sure that the next
1481             // fallback request is limited to the characters in the original request
1482             // => this is handled in ImplLayoutArgs::PrepareFallback()
1483             rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
1484                 rVisualItem.IsRTL() );
1485 
1486             // don't bother to do a default layout in a fallback level
1487             if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
1488                 continue;
1489 
1490             // the primitive layout engine is good enough for the default layout
1491             rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
1492             nRC = (*pScriptShape)( mhDC, &rScriptCache,
1493                 reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
1494                 nCharCount,
1495                 mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
1496                 &rVisualItem.mpScriptItem->a,
1497                 mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1498                 mpLogClusters + rVisualItem.mnMinCharPos,
1499                 mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1500                 &nGlyphCount );
1501 
1502             if( nRC != 0 )
1503                 continue;
1504 
1505 #if 0       // keep the glyphs for now because they are better than nothing
1506             // mark as NotDef glyphs
1507             for( i = 0; i < nGlyphCount; ++i )
1508                 mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 0;
1509 #endif
1510         }
1511         else if( nRC != 0 )
1512             // something undefined happened => give up for this visual item
1513             continue;
1514         else // if( nRC == 0 )
1515         {
1516             // check if there are any NotDef glyphs
1517             for( i = 0; i < nGlyphCount; ++i )
1518                 if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
1519                     break;
1520             if( i < nGlyphCount )
1521             {
1522                 // clip charpos limits to the layout string without context
1523                 int nMinCharPos = rVisualItem.mnMinCharPos;
1524                 if( nMinCharPos < rArgs.mnMinCharPos )
1525                     nMinCharPos = rArgs.mnMinCharPos;
1526                 int nEndCharPos = rVisualItem.mnEndCharPos;
1527                 if( nEndCharPos > rArgs.mnEndCharPos )
1528                     nEndCharPos = rArgs.mnEndCharPos;
1529                 // request fallback for individual NotDef glyphs
1530                 do
1531                 {
1532                     // ignore non-NotDef glyphs
1533                     if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
1534                         continue;
1535                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
1536                     // request fallback for the whole cell that resulted in a NotDef glyph
1537                     // TODO: optimize algorithm
1538                     const bool bRTL = rVisualItem.IsRTL();
1539                     if( !bRTL )
1540                     {
1541                         // request fallback for the left-to-right cell
1542                         for( int c = nMinCharPos; c < nEndCharPos; ++c )
1543                         {
1544                             if( mpLogClusters[ c ] == i )
1545                             {
1546                                 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1547                                 if( rArgs.mpStr[ c ] == 0x2060 )
1548                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1549                                 else
1550                                 // <--
1551                                     rArgs.NeedFallback( c, false );
1552                            }
1553                         }
1554                     }
1555                     else
1556                     {
1557                         // request fallback for the right to left cell
1558                         for( int c = nEndCharPos; --c >= nMinCharPos; )
1559                         {
1560                             if( mpLogClusters[ c ] == i )
1561                             {
1562                                 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1563                                 if( rArgs.mpStr[ c ] == 0x2060 )
1564                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1565                                 else
1566                                 // <--
1567                                     rArgs.NeedFallback( c, true );
1568                             }
1569                         }
1570                     }
1571                 } while( ++i < nGlyphCount );
1572             }
1573         }
1574 
1575         // now place the glyphs
1576         nRC = (*pScriptPlace)( mhDC, &rScriptCache,
1577             mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1578             nGlyphCount,
1579             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1580             &rVisualItem.mpScriptItem->a,
1581             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1582             mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
1583             &rVisualItem.maABCWidths );
1584 
1585         if( nRC != 0 )
1586             continue;
1587 
1588         // calculate the logical char widths from the glyph layout
1589         nRC = (*pScriptGetLogicalWidths)(
1590             &rVisualItem.mpScriptItem->a,
1591             nCharCount, nGlyphCount,
1592             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1593             mpLogClusters + rVisualItem.mnMinCharPos,
1594             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1595             mpCharWidths + rVisualItem.mnMinCharPos );
1596 
1597         // update the glyph counters
1598         mnGlyphCount += nGlyphCount;
1599         rVisualItem.mnEndGlyphPos = mnGlyphCount;
1600 
1601         // update nXOffset
1602         int nEndGlyphPos;
1603         if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
1604             for(; i < nEndGlyphPos; ++i )
1605                 nXOffset += mpGlyphAdvances[ i ];
1606 
1607         // TODO: shrink glyphpos limits to match charpos/fallback limits
1608         //pVI->mnMinGlyphPos = nMinGlyphPos;
1609         //pVI->mnEndGlyphPos = nEndGlyphPos;
1610 
1611         // drop the superfluous context glyphs
1612         TIntVector::const_iterator it = aDropChars.begin();
1613         while( it != aDropChars.end() )
1614         {
1615             // find matching "drop range"
1616             int nMinDropPos = *(it++); // begin of drop range
1617             if( nMinDropPos >= rVisualItem.mnEndCharPos )
1618                 break;
1619             int nEndDropPos = *(it++); // end of drop range
1620             if( nEndDropPos <= rVisualItem.mnMinCharPos )
1621                 continue;
1622             // clip "drop range" to visual item's char range
1623             if( nMinDropPos <= rVisualItem.mnMinCharPos )
1624             {
1625                 nMinDropPos = rVisualItem.mnMinCharPos;
1626                 // drop the whole visual item if possible
1627                 if( nEndDropPos >= rVisualItem.mnEndCharPos )
1628                 {
1629                     rVisualItem.mnEndGlyphPos = 0;
1630                     break;
1631                 }
1632             }
1633             if( nEndDropPos > rVisualItem.mnEndCharPos )
1634                 nEndDropPos = rVisualItem.mnEndCharPos;
1635 
1636             // drop the glyphs which correspond to the charpos range
1637             // drop the corresponding glyphs in the cluster
1638             for( int c = nMinDropPos; c < nEndDropPos; ++c )
1639             {
1640                 int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
1641                 // no need to bother when the cluster was already dropped
1642                 if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
1643                 {
1644                     for(;;)
1645                     {
1646                         mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
1647                         // until the end of visual item
1648                         if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
1649                             break;
1650                         // until the next cluster start
1651                         if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
1652                             break;
1653                     }
1654                 }
1655             }
1656         }
1657     }
1658 
1659     // scale layout metrics if needed
1660 	// TODO: does it make the code more simple if the metric scaling
1661 	// is moved to the methods that need metric scaling (e.g. FillDXArray())?
1662     if( mfFontScale != 1.0 )
1663     {
1664         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1665 
1666         for( i = 0; i < mnItemCount; ++i )
1667             mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
1668 
1669         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1670         for( i = 0; i < mnGlyphCount; ++i )
1671         {
1672             mpGlyphAdvances[i]   = (int)(mpGlyphAdvances[i] * mfFontScale);
1673             mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
1674             mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
1675             // mpJustifications are still NULL
1676         }
1677 
1678         for( i = mnSubStringMin; i < nSubStringEnd; ++i )
1679             mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
1680     }
1681 
1682     return true;
1683 }
1684 
1685 // -----------------------------------------------------------------------
1686 
1687 // calculate the range of relevant glyphs for this visual item
1688 bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
1689     int& rMinGlyphPos, int& rEndGlyphPos ) const
1690 {
1691     // return early when nothing of interest in this item
1692     if( rVisualItem.IsEmpty()
1693      || (rVisualItem.mnEndCharPos <= mnMinCharPos)
1694      || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
1695         return false;
1696 
1697     // default: subrange is complete range
1698     rMinGlyphPos = rVisualItem.mnMinGlyphPos;
1699     rEndGlyphPos = rVisualItem.mnEndGlyphPos;
1700 
1701     // return early when the whole item is of interest
1702     if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
1703      && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
1704         return true;
1705 
1706     // get glyph range from char range by looking at cluster boundries
1707     // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
1708     rMinGlyphPos = rVisualItem.mnEndGlyphPos;
1709     int nMaxGlyphPos = 0;
1710 
1711     int i = mnMinCharPos;
1712     if( i < rVisualItem.mnMinCharPos )
1713         i = rVisualItem.mnMinCharPos;
1714     int nCharPosLimit = rVisualItem.mnEndCharPos;
1715     if( nCharPosLimit > mnEndCharPos )
1716         nCharPosLimit = mnEndCharPos;
1717     for(; i < nCharPosLimit; ++i )
1718     {
1719         int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
1720         if( rMinGlyphPos > n )
1721             rMinGlyphPos = n;
1722         if( nMaxGlyphPos < n )
1723             nMaxGlyphPos = n;
1724     }
1725 	if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
1726 		nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
1727 
1728     // extend the glyph range to account for all glyphs in referenced clusters
1729     if( !rVisualItem.IsRTL() ) // LTR-item
1730     {
1731         // extend to rightmost glyph of rightmost referenced cluster
1732         for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
1733             if( mpVisualAttrs[i].fClusterStart )
1734                 break;
1735     }
1736     else // RTL-item
1737     {
1738         // extend to leftmost glyph of leftmost referenced cluster
1739         for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
1740             if( mpVisualAttrs[i].fClusterStart )
1741                 break;
1742     }
1743     rEndGlyphPos = nMaxGlyphPos + 1;
1744 
1745     return true;
1746 }
1747 
1748 // -----------------------------------------------------------------------
1749 
1750 int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
1751     int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
1752 {
1753     // HACK to allow fake-glyph insertion (e.g. for kashidas)
1754     // TODO: use iterator idiom instead of GetNextGlyphs(...)
1755     // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
1756     int nSubIter = nStartx8 & 0xff;
1757     int nStart = nStartx8 >> 8;
1758 
1759     // check the glyph iterator
1760     if( nStart > mnGlyphCount )       // nStart>MAX means no more glyphs
1761         return 0;
1762 
1763     // find the visual item for the nStart glyph position
1764     int nItem = 0;
1765     const VisualItem* pVI = mpVisualItems;
1766     if( nStart <= 0 )                 // nStart<=0 requests the first visible glyph
1767     {
1768         // find first visible item
1769         for(; nItem < mnItemCount; ++nItem, ++pVI )
1770             if( !pVI->IsEmpty() )
1771                 break;
1772         // it is possible that there are glyphs but no valid visual item
1773         // TODO: get rid of these visual items more early
1774         if( nItem < mnItemCount )
1775             nStart = pVI->mnMinGlyphPos;
1776     }
1777     else //if( nStart > 0 )           // nStart>0 means absolute glyph pos +1
1778     {
1779         --nStart;
1780 
1781         // find matching item
1782         for(; nItem < mnItemCount; ++nItem, ++pVI )
1783             if( (nStart >= pVI->mnMinGlyphPos)
1784             &&  (nStart < pVI->mnEndGlyphPos) )
1785                 break;
1786     }
1787 
1788     // after the last visual item there are no more glyphs
1789     if( (nItem >= mnItemCount) || (nStart < 0) )
1790     {
1791         nStartx8 = (mnGlyphCount + 1) << 8;
1792         return 0;
1793     }
1794 
1795     // calculate the first glyph in the next visual item
1796     int nNextItemStart = mnGlyphCount;
1797     while( ++nItem < mnItemCount )
1798     {
1799         if( mpVisualItems[nItem].IsEmpty() )
1800             continue;
1801         nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
1802         break;
1803     }
1804 
1805     // get the range of relevant glyphs in this visual item
1806     int nMinGlyphPos, nEndGlyphPos;
1807     bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
1808     DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
1809     if( !bRC )
1810     {
1811         nStartx8 = (mnGlyphCount + 1) << 8;
1812         return 0;
1813     }
1814 
1815     // make sure nStart is inside the range of relevant glyphs
1816     if( nStart < nMinGlyphPos )
1817         nStart = nMinGlyphPos;
1818 
1819     // calculate the start glyph xoffset relative to layout's base position,
1820     // advance to next visual glyph position by using adjusted glyph widths
1821     // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
1822     long nXOffset = pVI->mnXOffset;
1823     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
1824     for( int i = nMinGlyphPos; i < nStart; ++i )
1825         nXOffset += pGlyphWidths[ i ];
1826 
1827     // adjust the nXOffset relative to glyph cluster start
1828     int c = mnMinCharPos;
1829     if( !pVI->IsRTL() ) // LTR-case
1830     {
1831         // LTR case: subtract the remainder of the cell from xoffset
1832         int nTmpIndex = mpLogClusters[c];
1833         while( (--c >= pVI->mnMinCharPos)
1834             && (nTmpIndex == mpLogClusters[c]) )
1835             nXOffset -= mpCharWidths[c];
1836     }
1837     else // RTL-case
1838     {
1839         // RTL case: add the remainder of the cell from xoffset
1840         int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
1841         while( (--c >= pVI->mnMinCharPos)
1842             && (nTmpIndex == mpLogClusters[c]) )
1843             nXOffset += mpCharWidths[c];
1844 
1845         // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
1846 		if( mpJustifications && !bManualCellAlign )
1847            nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
1848     }
1849 
1850     // create mpGlyphs2Chars[] if it is needed later
1851     if( pCharPosAry && !mpGlyphs2Chars )
1852     {
1853         // create and reset the new array
1854         mpGlyphs2Chars = new int[ mnGlyphCapacity ];
1855         for( int i = 0; i < mnGlyphCount; ++i )
1856             mpGlyphs2Chars[i] = -1;
1857         // calculate the char->glyph mapping
1858         for( nItem = 0; nItem < mnItemCount; ++nItem )
1859         {
1860             // ignore invisible visual items
1861             const VisualItem& rVI = mpVisualItems[ nItem ];
1862             if( rVI.IsEmpty() )
1863                 continue;
1864             // calculate the mapping by using mpLogClusters[]
1865             // mpGlyphs2Chars[] should obey the logical order
1866             // => reversing the loop does this by overwriting higher logicals
1867             for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
1868             {
1869                 int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
1870                 mpGlyphs2Chars[i] = c;
1871             }
1872         }
1873     }
1874 
1875     // calculate the absolute position of the first result glyph in pixel units
1876     const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
1877     Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
1878     rPos = GetDrawPosition( aRelativePos );
1879 
1880 	// fill the result arrays
1881     int nCount = 0;
1882     while( nCount < nLen )
1883     {
1884         // prepare return values
1885         sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
1886         int nGlyphWidth = pGlyphWidths[ nStart ];
1887         int nCharPos = -1;    // no need to determine charpos
1888         if( mpGlyphs2Chars )  // unless explicitly requested+provided
1889             nCharPos = mpGlyphs2Chars[ nStart ];
1890 
1891         // inject kashida glyphs if needed
1892         if( !mbDisableGlyphInjection
1893         && mpJustifications
1894         && mnMinKashidaWidth
1895         && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
1896         {
1897 			// prepare draw position adjustment
1898 			int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
1899         	// calculate space available for the injected glyphs
1900    	        nGlyphWidth = mpGlyphAdvances[ nStart ];
1901 	        const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
1902 			const int nToFillWidth = nExtraWidth - nExtraOfs;
1903 	        if( (4*nToFillWidth >= mnMinKashidaWidth)    // prevent glyph-injection if there is no room
1904 	        ||  ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
1905 	        {
1906 	        	// handle if there is not sufficient room for a full glyph
1907 	        	if( nToFillWidth < mnMinKashidaWidth )
1908 	        	{
1909 	        		// overlap it with the previously injected glyph if possible
1910 	        		int nOverlap = mnMinKashidaWidth - nToFillWidth;
1911 	        		// else overlap it with both neighboring glyphs
1912 					if( nSubIter <= 1 )
1913 						nOverlap /= 2;
1914 					nExtraOfs -= nOverlap;
1915 	        	}
1916 	        	nGlyphWidth = mnMinKashidaWidth;
1917 	        	aGlyphId = mnMinKashidaGlyph;
1918 				nCharPos = -1;
1919 	        }
1920 	        else
1921 	        {
1922 	        	nExtraOfs += nToFillWidth;	// at right of cell
1923 	        	nSubIter = 0;				// done with glyph injection
1924 	        }
1925             if( !bManualCellAlign )
1926                 nExtraOfs -= nExtraWidth;	// adjust for right-aligned cells
1927 
1928 			// adjust the draw position for the injected-glyphs case
1929 			if( nExtraOfs )
1930 			{
1931 				aRelativePos.X() += nExtraOfs;
1932 				rPos = GetDrawPosition( aRelativePos );
1933 			}
1934         }
1935 
1936         // update return values
1937         *(pGlyphs++) = aGlyphId;
1938         if( pGlyphAdvances )
1939             *(pGlyphAdvances++) = nGlyphWidth;
1940         if( pCharPosAry )
1941             *(pCharPosAry++) = nCharPos;
1942 
1943         // increment counter of returned glyphs
1944         ++nCount;
1945 
1946         // reduce code complexity by returning early in glyph-injection case
1947        	if( nSubIter != 0 )
1948        		break;
1949 
1950         // stop after the last visible glyph in this visual item
1951         if( ++nStart >= nEndGlyphPos )
1952         {
1953             nStart = nNextItemStart;
1954             break;
1955         }
1956 
1957         // RTL-justified glyph positioning is not easy
1958         // simplify the code by just returning only one glyph at a time
1959         if( mpJustifications && pVI->IsRTL() )
1960             break;
1961 
1962         // stop when the x-position of the next glyph is unexpected
1963         if( !pGlyphAdvances  )
1964             if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
1965              || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
1966                 break;
1967 
1968         // stop when the y-position of the next glyph is unexpected
1969         if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
1970             break;
1971     }
1972 
1973     ++nStart;
1974     nStartx8 = (nStart << 8) + nSubIter;
1975     return nCount;
1976 }
1977 
1978 // -----------------------------------------------------------------------
1979 
1980 void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
1981 {
1982     DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
1983     int nStart = nStartx8 >> 8;
1984     if( nStart > mnGlyphCount )
1985         return;
1986 
1987     VisualItem* pVI = mpVisualItems;
1988     int nMinGlyphPos = 0, nEndGlyphPos;
1989     if( nStart == 0 )               // nStart==0 for first visible glyph
1990     {
1991         for( int i = mnItemCount; --i >= 0; ++pVI )
1992             if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
1993                 break;
1994         nStart = nMinGlyphPos;
1995         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" );
1996     }
1997     else //if( nStart > 0 )         // nStart>0 means absolute_glyphpos+1
1998     {
1999         --nStart;
2000         for( int i = mnItemCount; --i >= 0; ++pVI )
2001             if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
2002                 break;
2003         bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
2004 	(void)bRC; // avoid var-not-used warning
2005         DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
2006     }
2007 
2008     long nDelta = nNewXPos - pVI->mnXOffset;
2009     if( nStart > nMinGlyphPos )
2010     {
2011         // move the glyph by expanding its left glyph but ignore dropped glyphs
2012         int i, nLastUndropped = nMinGlyphPos - 1;
2013         for( i = nMinGlyphPos; i < nStart; ++i )
2014 		{
2015 			if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
2016 			{
2017 	            nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
2018 				nLastUndropped = i;
2019 			}
2020 		}
2021 		if (nLastUndropped >= nMinGlyphPos)
2022 		{
2023 			mpGlyphAdvances[ nLastUndropped ] += nDelta;
2024 			if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
2025 		}
2026 		else
2027 		{
2028 			pVI->mnXOffset += nDelta;
2029 		}
2030     }
2031     else
2032     {
2033         // move the visual item by having an offset
2034         pVI->mnXOffset += nDelta;
2035     }
2036     // move subsequent items - this often isn't necessary because subsequent
2037     // moves will correct subsequent items. However, if there is a contiguous
2038     // range not involving fallback which spans items, this will be needed
2039     while (++pVI - mpVisualItems < mnItemCount)
2040     {
2041         pVI->mnXOffset += nDelta;
2042     }
2043 }
2044 
2045 // -----------------------------------------------------------------------
2046 
2047 void UniscribeLayout::DropGlyph( int nStartx8 )
2048 {
2049     DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
2050     int nStart = nStartx8 >> 8;
2051     DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
2052 
2053     if( nStart > 0 )        // nStart>0 means absolute glyph pos + 1
2054         --nStart;
2055     else                    // nStart<=0 for first visible glyph
2056     {
2057         VisualItem* pVI = mpVisualItems;
2058         for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
2059             if( GetItemSubrange( *pVI, nStart, nDummy ) )
2060                 break;
2061         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
2062 		int nOffset = 0;
2063 		int j = pVI->mnMinGlyphPos;
2064 		while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
2065 		if (j == nStart)
2066 		{
2067 			pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
2068 		}
2069     }
2070 
2071     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
2072 }
2073 
2074 // -----------------------------------------------------------------------
2075 
2076 void UniscribeLayout::Simplify( bool /*bIsBase*/ )
2077 {
2078     static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH;
2079     int i;
2080     // if there are no dropped glyphs don't bother
2081     for( i = 0; i < mnGlyphCount; ++i )
2082         if( mpOutGlyphs[ i ] == cDroppedGlyph )
2083             break;
2084     if( i >= mnGlyphCount )
2085         return;
2086 
2087     // prepare for sparse layout
2088     // => make sure mpGlyphs2Chars[] exists
2089     if( !mpGlyphs2Chars )
2090     {
2091         mpGlyphs2Chars = new int[ mnGlyphCapacity ];
2092         for( i = 0; i < mnGlyphCount; ++i )
2093             mpGlyphs2Chars[ i ] = -1;
2094         for( int nItem = 0; nItem < mnItemCount; ++nItem )
2095         {
2096             // skip invisible items
2097             VisualItem& rVI = mpVisualItems[ nItem ];
2098             if( rVI.IsEmpty() )
2099                 continue;
2100             for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
2101             {
2102                 int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2103                 mpGlyphs2Chars[ j ] = i;
2104             }
2105         }
2106     }
2107 
2108     // remove the dropped glyphs
2109     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2110     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2111     {
2112         VisualItem& rVI = mpVisualItems[ nItem ];
2113         if( rVI.IsEmpty() )
2114             continue;
2115 
2116         // mark replaced character widths
2117         for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
2118         {
2119             int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2120             if( mpOutGlyphs[ j ] == cDroppedGlyph )
2121                 mpCharWidths[ i ] = 0;
2122         }
2123 
2124         // handle dropped glyphs at start of visual item
2125         int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
2126         GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
2127         i = nMinGlyphPos;
2128         while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
2129         {
2130             //rVI.mnXOffset += pGlyphWidths[ i ];
2131             rVI.mnMinGlyphPos = ++i;
2132         }
2133 
2134         // when all glyphs in item got dropped mark it as empty
2135         if( i >= nEndGlyphPos )
2136         {
2137             rVI.mnEndGlyphPos = 0;
2138             continue;
2139         }
2140 		// If there are still glyphs in the cluster and mnMinGlyphPos
2141 		// has changed then we need to remove the dropped glyphs at start
2142 		// to correct logClusters, which is unsigned and relative to the
2143 		// item start.
2144 		if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
2145 		{
2146 			// drop any glyphs in the visual item outside the range
2147 			for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
2148 				mpOutGlyphs[ i ] = cDroppedGlyph;
2149 			rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
2150 		}
2151 
2152         // handle dropped glyphs in the middle of visual item
2153         for(; i < nEndGlyphPos; ++i )
2154             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2155                 break;
2156         int j = i;
2157         while( ++i < nEndGlyphPos )
2158         {
2159             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2160                 continue;
2161             mpOutGlyphs[ j ]      = mpOutGlyphs[ i ];
2162             mpGlyphOffsets[ j ]   = mpGlyphOffsets[ i ];
2163             mpVisualAttrs[ j ]    = mpVisualAttrs[ i ];
2164             mpGlyphAdvances[ j ]  = mpGlyphAdvances[ i ];
2165             if( mpJustifications )
2166                 mpJustifications[ j ] = mpJustifications[ i ];
2167             const int k = mpGlyphs2Chars[ i ];
2168             mpGlyphs2Chars[ j ]   = k;
2169             const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
2170             if( k < 0) // extra glyphs are already mapped
2171                 continue;
2172             mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
2173         }
2174 
2175         rVI.mnEndGlyphPos = j;
2176     }
2177 }
2178 
2179 // -----------------------------------------------------------------------
2180 
2181 void UniscribeLayout::DrawText( SalGraphics& ) const
2182 {
2183     HFONT hOrigFont = DisableFontScaling();
2184 
2185     int nBaseClusterOffset = 0;
2186     int nBaseGlyphPos = -1;
2187     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2188     {
2189         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2190 
2191         // skip if there is nothing to display
2192         int nMinGlyphPos, nEndGlyphPos;
2193         if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2194             continue;
2195 
2196         if( nBaseGlyphPos < 0 )
2197         {
2198             // adjust draw position relative to cluster start
2199             if( rVisualItem.IsRTL() )
2200                 nBaseGlyphPos = nEndGlyphPos - 1;
2201             else
2202                 nBaseGlyphPos = nMinGlyphPos;
2203 
2204             const int* pGlyphWidths;
2205             if( mpJustifications )
2206                 pGlyphWidths = mpJustifications;
2207             else
2208                 pGlyphWidths = mpGlyphAdvances;
2209 
2210             int i = mnMinCharPos;
2211             while( (--i >= rVisualItem.mnMinCharPos)
2212                 && (nBaseGlyphPos == mpLogClusters[i]) )
2213                  nBaseClusterOffset += mpCharWidths[i];
2214 
2215             if( !rVisualItem.IsRTL() )
2216                 nBaseClusterOffset = -nBaseClusterOffset;
2217         }
2218 
2219         // now draw the matching glyphs in this item
2220         Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
2221         Point aPos = GetDrawPosition( aRelPos );
2222         SCRIPT_CACHE& rScriptCache = GetScriptCache();
2223         (*pScriptTextOut)( mhDC, &rScriptCache,
2224             aPos.X(), aPos.Y(), 0, NULL,
2225             &rVisualItem.mpScriptItem->a, NULL, 0,
2226             mpOutGlyphs + nMinGlyphPos,
2227             nEndGlyphPos - nMinGlyphPos,
2228             mpGlyphAdvances + nMinGlyphPos,
2229             mpJustifications ? mpJustifications + nMinGlyphPos : NULL,
2230             mpGlyphOffsets + nMinGlyphPos );
2231     }
2232 
2233     if( hOrigFont )
2234         DeleteFont( SelectFont( mhDC, hOrigFont ) );
2235 }
2236 
2237 // -----------------------------------------------------------------------
2238 
2239 long UniscribeLayout::FillDXArray( long* pDXArray ) const
2240 {
2241     // calculate width of the complete layout
2242     long nWidth = mnBaseAdv;
2243     for( int nItem = mnItemCount; --nItem >= 0; )
2244     {
2245         const VisualItem& rVI = mpVisualItems[ nItem ];
2246 
2247         // skip if there is nothing to display
2248         int nMinGlyphPos, nEndGlyphPos;
2249         if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
2250             continue;
2251 
2252         // width = xoffset + width of last item
2253         nWidth = rVI.mnXOffset;
2254         const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2255         for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2256             nWidth += pGlyphWidths[i];
2257         break;
2258     }
2259 
2260     // copy the virtual char widths into pDXArray[]
2261     if( pDXArray )
2262         for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2263             pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
2264 
2265     return nWidth;
2266 }
2267 
2268 // -----------------------------------------------------------------------
2269 
2270 int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2271 {
2272     long nWidth = 0;
2273     for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2274     {
2275         nWidth += mpCharWidths[ i ] * nFactor;
2276 
2277         // check if the nMaxWidth still fits the current sub-layout
2278         if( nWidth >= nMaxWidth )
2279         {
2280             // go back to cluster start
2281             // we have to find the visual item first since the mpLogClusters[]
2282             // needed to find the cluster start is relative to to the visual item
2283             int nMinGlyphIndex = 0;
2284             for( int nItem = 0; nItem < mnItemCount; ++nItem )
2285             {
2286                 const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2287                 nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2288                 if( (i >= rVisualItem.mnMinCharPos)
2289                 &&  (i < rVisualItem.mnEndCharPos) )
2290                     break;
2291             }
2292             // now go back to the matching cluster start
2293             do
2294             {
2295                 int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
2296                 if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
2297                     return i;
2298             } while( --i >= mnMinCharPos );
2299 
2300             // if the cluster starts before the start of the visual item
2301             // then set the visual breakpoint before this item
2302             return mnMinCharPos;
2303         }
2304 
2305         // the visual break also depends on the nCharExtra between the characters
2306         nWidth += nCharExtra;
2307     }
2308 
2309     // the whole layout did fit inside the nMaxWidth
2310     return STRING_LEN;
2311 }
2312 
2313 // -----------------------------------------------------------------------
2314 
2315 void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
2316 {
2317     int i;
2318     for( i = 0; i < nMaxIdx; ++i )
2319         pCaretXArray[ i ] = -1;
2320     long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) );
2321     for( i = 0; i <= mnGlyphCount; ++i )
2322         pGlyphPos[ i ] = -1;
2323 
2324     long nXPos = 0;
2325     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2326     {
2327         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2328         if( rVisualItem.IsEmpty() )
2329             continue;
2330 
2331         if (mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK)
2332         {
2333             nXPos = rVisualItem.mnXOffset;
2334         }
2335         // get glyph positions
2336         // TODO: handle when rVisualItem's glyph range is only partially used
2337         for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2338         {
2339             pGlyphPos[ i ] = nXPos;
2340             nXPos += mpGlyphAdvances[ i ];
2341         }
2342         // rightmost position of this visualitem
2343         pGlyphPos[ i ] = nXPos;
2344 
2345         // convert glyph positions to character positions
2346         i = rVisualItem.mnMinCharPos;
2347         if( i < mnMinCharPos )
2348             i = mnMinCharPos;
2349         for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
2350         {
2351             int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
2352             int nCurrIdx = i * 2;
2353             if( !rVisualItem.IsRTL() )
2354             {
2355                 // normal positions for LTR case
2356                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j ];
2357                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
2358             }
2359             else
2360             {
2361                 // reverse positions for RTL case
2362                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j+1 ];
2363                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
2364             }
2365         }
2366     }
2367 
2368     if (!(mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK))
2369     {
2370         nXPos = 0;
2371         // fixup unknown character positions to neighbor
2372         for( i = 0; i < nMaxIdx; ++i )
2373         {
2374             if( pCaretXArray[ i ] >= 0 )
2375                 nXPos = pCaretXArray[ i ];
2376             else
2377                 pCaretXArray[ i ] = nXPos;
2378         }
2379     }
2380 }
2381 
2382 // -----------------------------------------------------------------------
2383 
2384 void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
2385 {
2386     SalLayout::AdjustLayout( rArgs );
2387 
2388     // adjust positions if requested
2389     if( rArgs.mpDXArray )
2390         ApplyDXArray( rArgs );
2391     else if( rArgs.mnLayoutWidth )
2392         Justify( rArgs.mnLayoutWidth );
2393 }
2394 
2395 // -----------------------------------------------------------------------
2396 
2397 void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
2398 {
2399     const long* pDXArray = rArgs.mpDXArray;
2400 
2401     // increase char widths in string range to desired values
2402     bool bModified = false;
2403     int nOldWidth = 0;
2404     DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
2405     int i,j;
2406     for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
2407     {
2408         int nNewCharWidth = (pDXArray[j] - nOldWidth);
2409         // TODO: nNewCharWidth *= mnUnitsPerPixel;
2410         if( mpCharWidths[i] != nNewCharWidth )
2411         {
2412             mpCharWidths[i] = nNewCharWidth;
2413             bModified = true;
2414         }
2415         nOldWidth = pDXArray[j];
2416     }
2417 
2418     if( !bModified )
2419         return;
2420 
2421     // initialize justifications array
2422     mpJustifications = new int[ mnGlyphCapacity ];
2423     for( i = 0; i < mnGlyphCount; ++i )
2424         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2425 
2426     // apply new widths to script items
2427     long nXOffset = 0;
2428     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2429     {
2430         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2431 
2432         // set the position of this visual item
2433         rVisualItem.mnXOffset = nXOffset;
2434 
2435         // ignore empty visual items
2436         if( rVisualItem.IsEmpty() )
2437         {
2438             for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
2439               nXOffset += mpCharWidths[i];
2440             continue;
2441         }
2442         // ignore irrelevant visual items
2443         if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
2444          || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
2445             continue;
2446 
2447 		// if needed prepare special handling for arabic justification
2448 		rVisualItem.mbHasKashidas = false;
2449 		if( rVisualItem.IsRTL() )
2450         {
2451 			for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2452                 if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 )  //  any Arabic justification
2453                 {                                                        //  excluding SCRIPT_JUSTIFY_NONE
2454                     // yes
2455                     rVisualItem.mbHasKashidas = true;
2456                     // so prepare for kashida handling
2457                     InitKashidaHandling();
2458 					break;
2459 				}
2460 
2461 			if( rVisualItem.HasKashidas() )
2462 				for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2463 				{
2464                     // TODO: check if we still need this hack after correction of kashida placing?
2465                     // (i87688): apparently yes, we still need it!
2466                     if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
2467                         // usp decided that justification can't be applied here
2468 						// but maybe our Kashida algorithm thinks differently.
2469 						// To avoid trouble (gaps within words, last character of
2470 						// a word gets a Kashida appended) override this.
2471 
2472 						// I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
2473 						// just because this previous hack (which I haven't understand, sorry) used
2474 						// the same value to replace. Don't know if this is really the best
2475 						// thing to do, but it seems to fix things
2476 						mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2477 				}
2478         }
2479 
2480         // convert virtual charwidths to glyph justification values
2481         HRESULT nRC = (*pScriptApplyLogicalWidth)(
2482             mpCharWidths + rVisualItem.mnMinCharPos,
2483             rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
2484             rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2485             mpLogClusters + rVisualItem.mnMinCharPos,
2486             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2487             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2488             &rVisualItem.mpScriptItem->a,
2489             &rVisualItem.maABCWidths,
2490             mpJustifications + rVisualItem.mnMinGlyphPos );
2491 
2492         if( nRC != 0 )
2493         {
2494             delete[] mpJustifications;
2495             mpJustifications = NULL;
2496             break;
2497         }
2498 
2499         // to prepare for the next visual item
2500         // update nXOffset to the next items position
2501         // before the mpJustifications[] array gets modified
2502         int nMinGlyphPos, nEndGlyphPos;
2503         if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2504         {
2505             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2506                 nXOffset += mpJustifications[ i ];
2507 
2508             if( rVisualItem.mbHasKashidas )
2509 				KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
2510         }
2511 
2512 		// workaround needed for older USP versions:
2513         // right align the justification-adjusted glyphs in their cells for RTL-items
2514 		// unless the right alignment is done by inserting kashidas
2515         if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
2516         {
2517             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2518             {
2519                 const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
2520 				// #i99862# skip diacritics, we mustn't add extra justification to diacritics
2521 				int nIdxAdd = i - 1;
2522 				while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
2523 					--nIdxAdd;
2524                 if( nIdxAdd < nMinGlyphPos )
2525                     rVisualItem.mnXOffset += nXOffsetAdjust;
2526                 else
2527                     mpJustifications[nIdxAdd] += nXOffsetAdjust;
2528                 mpJustifications[i] -= nXOffsetAdjust;
2529             }
2530         }
2531     }
2532 }
2533 
2534 // -----------------------------------------------------------------------
2535 
2536 void UniscribeLayout::InitKashidaHandling()
2537 {
2538 	if( mnMinKashidaGlyph != 0 )	// already initialized
2539 		return;
2540 
2541 	mrWinFontEntry.InitKashidaHandling( mhDC );
2542 	mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
2543 	mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
2544 }
2545 
2546 // adjust the kashida placement matching to the WriterEngine
2547 void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
2548 {
2549 	// workaround needed for all known USP versions:
2550 	// ApplyLogicalWidth does not match ScriptJustify behaviour
2551 	for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2552 	{
2553 		// check for vowels
2554 		if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
2555 		&&  (1U << mpVisualAttrs[i].uJustification) & 0xFF83 )	// all Arabic justifiction types
2556 		{														// including SCRIPT_JUSTIFY_NONE
2557 			// vowel, we do it like ScriptJustify does
2558 			// the vowel gets the extra width
2559 			long nSpaceAdded =  mpJustifications[ i ] - mpGlyphAdvances[ i ];
2560 			mpJustifications [ i ] = mpGlyphAdvances [ i ];
2561 			mpJustifications [ i - 1 ] += nSpaceAdded;
2562 		}
2563 	}
2564 
2565 	// redistribute the widths for kashidas
2566 	for( int i = nMinGlyphPos; i < nEndGlyphPos; )
2567 		KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
2568 }
2569 
2570 bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
2571 {
2572 	// doing pixel work within a word.
2573 	// sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
2574 
2575 	// find the next kashida
2576 	int nMinPos = *pnCurrentPos;
2577 	int nMaxPos = *pnCurrentPos;
2578 	for( int i = nMaxPos; i < nEndGlyphPos; ++i )
2579 	{
2580 		if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
2581 		&&  (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
2582 			break;
2583 		nMaxPos = i;
2584 	}
2585 	*pnCurrentPos = nMaxPos + 1;
2586 	if( nMinPos == nMaxPos )
2587 		return false;
2588 
2589 	// calculate the available space for an extra kashida
2590 	long nMaxAdded = 0;
2591 	int nKashPos = -1;
2592 	for( int i = nMaxPos; i >= nMinPos; --i )
2593 	{
2594 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2595 		if( nSpaceAdded > nMaxAdded )
2596 		{
2597 			nKashPos = i;
2598 			nMaxAdded = nSpaceAdded;
2599 		}
2600 	}
2601 
2602 	// return early if there is no need for an extra kashida
2603 	if ( nMaxAdded <= 0 )
2604 		return false;
2605 	// return early if there is not enough space for an extra kashida
2606 	if( 2*nMaxAdded < mnMinKashidaWidth )
2607 		return false;
2608 
2609 	// redistribute the extra spacing to the kashida position
2610 	for( int i = nMinPos; i <= nMaxPos; ++i )
2611 	{
2612 		if( i == nKashPos )
2613 			continue;
2614 		// everything else should not have extra spacing
2615 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2616 		if( nSpaceAdded > 0 )
2617 		{
2618 			mpJustifications[ i ] -= nSpaceAdded;
2619 			mpJustifications[ nKashPos ] += nSpaceAdded;
2620 		}
2621 	}
2622 
2623 	// check if we fulfill minimal kashida width
2624 	long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
2625 	if( nSpaceAdded < mnMinKashidaWidth )
2626 	{
2627 		// ugly: steal some pixels
2628 		long nSteal = 1;
2629 		if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
2630 			nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
2631 		for( int i = nMinPos; i <= nMaxPos; ++i )
2632 		{
2633 			if( i == nKashPos )
2634 				continue;
2635 			nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
2636 			if ( nSteal > 0 )
2637 			{
2638 				mpJustifications [ i ] -= nSteal;
2639 				mpJustifications [ nKashPos ] += nSteal;
2640 				nSpaceAdded += nSteal;
2641 			}
2642 			if( nSpaceAdded >= mnMinKashidaWidth )
2643 				return true;
2644 		}
2645 	}
2646 
2647 	// blank padding
2648 	long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
2649 	if( nSpaceMissing > 0 )
2650 	{
2651 		// inner glyph: distribute extra space evenly
2652 		if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
2653 		{
2654 			mpJustifications [ nKashPos ] += nSpaceMissing;
2655 			long nHalfSpace = nSpaceMissing / 2;
2656 			mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
2657 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
2658 		}
2659 		// rightmost: left glyph gets extra space
2660 		else if( nMinPos > nMinGlyphPos )
2661 		{
2662 			mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
2663 			mpJustifications [ nKashPos ] += nSpaceMissing;
2664 		}
2665 		// leftmost: right glyph gets extra space
2666 		else if( nMaxPos < nEndGlyphPos - 1 )
2667 		{
2668 			mpJustifications [ nKashPos ] += nSpaceMissing;
2669 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
2670 		}
2671 		else
2672 			return false;
2673 	}
2674 
2675 	return true;
2676 }
2677 
2678 // -----------------------------------------------------------------------
2679 
2680 void UniscribeLayout::Justify( long nNewWidth )
2681 {
2682     long nOldWidth = 0;
2683     int i;
2684     for( i = mnMinCharPos; i < mnEndCharPos; ++i )
2685         nOldWidth += mpCharWidths[ i ];
2686 	if( nOldWidth <= 0 )
2687 		return;
2688 
2689     nNewWidth *= mnUnitsPerPixel;	// convert into font units
2690     if( nNewWidth == nOldWidth )
2691         return;
2692     // prepare to distribute the extra width evenly among the visual items
2693     const double fStretch = (double)nNewWidth / nOldWidth;
2694 
2695     // initialize justifications array
2696     mpJustifications = new int[ mnGlyphCapacity ];
2697     for( i = 0; i < mnGlyphCapacity; ++i )
2698         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2699 
2700     // justify stretched script items
2701     long nXOffset = 0;
2702     SCRIPT_CACHE& rScriptCache = GetScriptCache();
2703     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2704     {
2705         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2706         if( rVisualItem.IsEmpty() )
2707             continue;
2708 
2709         if( (rVisualItem.mnMinCharPos < mnEndCharPos)
2710          && (rVisualItem.mnEndCharPos > mnMinCharPos) )
2711         {
2712             long nItemWidth = 0;
2713             for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
2714                 nItemWidth += mpCharWidths[ i ];
2715             nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
2716 
2717             HRESULT nRC = (*pScriptJustify) (
2718                 mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2719                 mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2720                 rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2721                 nItemWidth,
2722                 mnMinKashidaWidth,
2723                 mpJustifications + rVisualItem.mnMinGlyphPos );
2724 
2725             rVisualItem.mnXOffset = nXOffset;
2726             nXOffset += nItemWidth;
2727         }
2728     }
2729 }
2730 
2731 // -----------------------------------------------------------------------
2732 
2733 bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
2734 {
2735 	// we have to find the visual item first since the mpLogClusters[]
2736     // needed to find the cluster start is relative to to the visual item
2737     int nMinGlyphIndex = -1;
2738     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2739     {
2740         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2741         if( (nCharPos >= rVisualItem.mnMinCharPos)
2742         &&  (nCharPos < rVisualItem.mnEndCharPos) )
2743 		{
2744 			nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2745             break;
2746 		}
2747     }
2748 	// Invalid char pos or leftmost glyph in visual item
2749     if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
2750 		return false;
2751 
2752 //	This test didn't give the expected results
2753 /*	if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
2754 	// two chars, one glyph
2755 		return false;*/
2756 
2757 	const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
2758 	if( nGlyphPos <= 0 )
2759 		return true;
2760 	// justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
2761 	// and not SCRIPT_JUSTIFY_ARABIC_BLANK
2762 	// special case: glyph to the left is vowel (no advance width)
2763 	if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
2764 		|| ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
2765 			&& mpGlyphAdvances [ nGlyphPos-1 ] ))
2766 		return false;
2767 	return true;
2768 }
2769 
2770 #endif // USE_UNISCRIBE
2771 
2772 #ifdef ENABLE_GRAPHITE
2773 
2774 class GraphiteLayoutWinImpl : public GraphiteLayout
2775 {
2776 public:
2777     GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
2778         throw()
2779     : GraphiteLayout(font), mrFont(rFont) {};
2780     virtual ~GraphiteLayoutWinImpl() throw() {};
2781     virtual sal_GlyphId getKashidaGlyph(int & rWidth);
2782 private:
2783     ImplWinFontEntry & mrFont;
2784 };
2785 
2786 sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
2787 {
2788     rWidth = mrFont.GetMinKashidaWidth();
2789     return mrFont.GetMinKashidaGlyph();
2790 }
2791 
2792 // This class uses the SIL Graphite engine to provide complex text layout services to the VCL
2793 // @author tse
2794 //
2795 class GraphiteWinLayout : public WinLayout
2796 {
2797 private:
2798     mutable GraphiteWinFont mpFont;
2799     grutils::GrFeatureParser * mpFeatures;
2800     mutable GraphiteLayoutWinImpl maImpl;
2801 public:
2802     GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw();
2803 
2804     static bool IsGraphiteEnabledFont(HDC hDC) throw();
2805 
2806     // used by upper layers
2807     virtual bool  LayoutText( ImplLayoutArgs& );    // first step of layout
2808     virtual void  AdjustLayout( ImplLayoutArgs& );  // adjusting after fallback etc.
2809     //  virtual void  InitFont() const;
2810     virtual void  DrawText( SalGraphics& ) const;
2811 
2812     // methods using string indexing
2813     virtual int   GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
2814     virtual long  FillDXArray( long* pDXArray ) const;
2815 
2816     virtual void  GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
2817 
2818     // methods using glyph indexing
2819     virtual int   GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
2820                       long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
2821 
2822     // used by glyph+font+script fallback
2823     virtual void    MoveGlyph( int nStart, long nNewXPos );
2824     virtual void    DropGlyph( int nStart );
2825     virtual void    Simplify( bool bIsBase );
2826     ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
2827 protected:
2828     virtual void    ReplaceDC(gr::Segment & segment) const;
2829     virtual void    RestoreDC(gr::Segment & segment) const;
2830 };
2831 
2832 bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
2833 {
2834   return gr::WinFont::FontHasGraphiteTables(hDC);
2835 }
2836 
2837 GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
2838   : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
2839     maImpl(mpFont, rWFE)
2840 {
2841     const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
2842     rtl::OString name = rtl::OUStringToOString(
2843         rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
2844     sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
2845     if (nFeat > 0)
2846     {
2847         rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
2848         mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
2849     }
2850     else
2851     {
2852         mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
2853     }
2854     maImpl.SetFeatures(mpFeatures);
2855 }
2856 
2857 void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
2858 {
2859     COLORREF color = GetTextColor(mhDC);
2860     dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
2861     SetTextColor(mhDC, color);
2862 }
2863 
2864 void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
2865 {
2866     dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
2867 }
2868 
2869 bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
2870 {
2871     if (args.mnMinCharPos >= args.mnEndCharPos)
2872     {
2873         maImpl.clear();
2874         return true;
2875     }
2876     HFONT hUnRotatedFont;
2877     if (args.mnOrientation)
2878     {
2879         // Graphite gets very confused if the font is rotated
2880         LOGFONTW aLogFont;
2881         ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
2882         aLogFont.lfEscapement = 0;
2883         aLogFont.lfOrientation = 0;
2884         hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
2885         ::SelectFont(mhDC, hUnRotatedFont);
2886     }
2887     WinLayout::AdjustLayout(args);
2888     mpFont.replaceDC(mhDC);
2889     maImpl.SetFontScale(WinLayout::mfFontScale);
2890     //bool succeeded = maImpl.LayoutText(args);
2891 #ifdef GRCACHE
2892     GrSegRecord * pSegRecord = NULL;
2893     gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
2894 #else
2895     gr::Segment * pSegment = maImpl.CreateSegment(args);
2896 #endif
2897     bool bSucceeded = false;
2898     if (pSegment)
2899     {
2900         // replace the DC on the font within the segment
2901         ReplaceDC(*pSegment);
2902         // create glyph vectors
2903 #ifdef GRCACHE
2904         bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
2905 #else
2906         bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
2907 #endif
2908         // restore original DC
2909         RestoreDC(*pSegment);
2910 #ifdef GRCACHE
2911         if (pSegRecord) pSegRecord->unlock();
2912         else delete pSegment;
2913 #else
2914         delete pSegment;
2915 #endif
2916     }
2917     mpFont.restoreDC();
2918     if (args.mnOrientation)
2919     {
2920         // restore the rotated font
2921         ::SelectFont(mhDC, mhFont);
2922         ::DeleteObject(hUnRotatedFont);
2923     }
2924     return bSucceeded;
2925 }
2926 
2927 void  GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
2928 {
2929     WinLayout::AdjustLayout(rArgs);
2930     maImpl.DrawBase() = WinLayout::maDrawBase;
2931     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2932     if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
2933     {
2934         mrWinFontEntry.InitKashidaHandling(mhDC);
2935     }
2936     maImpl.AdjustLayout(rArgs);
2937 }
2938 
2939 void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
2940 {
2941     HFONT hOrigFont = DisableFontScaling();
2942     HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
2943     maImpl.DrawBase() = WinLayout::maDrawBase;
2944     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2945     const int MAX_GLYPHS = 2;
2946     sal_GlyphId glyphIntStr[MAX_GLYPHS];
2947     WORD glyphWStr[MAX_GLYPHS];
2948     int glyphIndex = 0;
2949     Point aPos(0,0);
2950     int nGlyphs = 0;
2951     do
2952     {
2953         nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
2954         if (nGlyphs < 1)
2955           break;
2956         std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
2957         ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
2958 		              NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
2959     } while (nGlyphs);
2960     if( hOrigFont )
2961           DeleteFont( SelectFont( mhDC, hOrigFont ) );
2962 }
2963 
2964 int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2965 {
2966     mpFont.replaceDC(mhDC);
2967     int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
2968     mpFont.restoreDC();
2969     return nBreak;
2970 }
2971 
2972 long  GraphiteWinLayout::FillDXArray( long* pDXArray ) const
2973 {
2974     return maImpl.FillDXArray(pDXArray);
2975 }
2976 
2977 void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
2978 {
2979 	maImpl.GetCaretPositions(nArraySize, pCaretXArray);
2980 }
2981 
2982 int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
2983         ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
2984 {
2985     maImpl.DrawBase() = WinLayout::maDrawBase;
2986     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2987     return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
2988 }
2989 
2990 void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
2991 {
2992 	maImpl.MoveGlyph(glyph_idx, new_x_pos);
2993 }
2994 
2995 void GraphiteWinLayout::DropGlyph( int glyph_idx )
2996 {
2997 	maImpl.DropGlyph(glyph_idx);
2998 }
2999 
3000 void GraphiteWinLayout::Simplify( bool is_base )
3001 {
3002 	maImpl.Simplify(is_base);
3003 }
3004 #endif // ENABLE_GRAPHITE
3005 // =======================================================================
3006 
3007 SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
3008 {
3009     DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
3010 
3011 	WinLayout* pWinLayout = NULL;
3012 
3013     const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ];
3014     ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
3015 
3016 #if defined( USE_UNISCRIBE )
3017     if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
3018     &&   (aUspModule || (bUspEnabled && InitUSP())) )   // CTL layout engine
3019     {
3020 #ifdef ENABLE_GRAPHITE
3021         if (rFontFace.SupportsGraphite())
3022             pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
3023         else
3024 #endif // ENABLE_GRAPHITE
3025         // script complexity is determined in upper layers
3026         pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
3027         // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
3028         // the created UniscribeLayout, otherwise the data passed into the
3029         // constructor might become invalid too early
3030     }
3031     else
3032 #endif // USE_UNISCRIBE
3033     {
3034 #ifdef GCP_KERN_HACK
3035         if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
3036         {
3037             // TODO: directly cache kerning info in the rFontInstance
3038             // TODO: get rid of kerning methods+data in WinSalGraphics object
3039             GetKernPairs( 0, NULL );
3040             rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
3041         }
3042 #endif // GCP_KERN_HACK
3043 
3044         BYTE eCharSet = ANSI_CHARSET;
3045         if( mpLogFont )
3046             eCharSet = mpLogFont->lfCharSet;
3047 #ifdef ENABLE_GRAPHITE
3048         if (rFontFace.SupportsGraphite())
3049             pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
3050         else
3051 #endif // ENABLE_GRAPHITE
3052             pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
3053     }
3054 
3055     if( mfFontScale != 1.0 )
3056         pWinLayout->SetFontScale( mfFontScale );
3057 
3058     return pWinLayout;
3059 }
3060 
3061 // -----------------------------------------------------------------------
3062 
3063 int	WinSalGraphics::GetMinKashidaWidth()
3064 {
3065 	if( !mpWinFontEntry[0] )
3066 		return 0;
3067 	mpWinFontEntry[0]->InitKashidaHandling( mhDC );
3068 	int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
3069 	return nMinKashida;
3070 }
3071 
3072 // =======================================================================
3073 
3074 ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
3075 :   ImplFontEntry( rFSD )
3076 ,   maWidthMap( 512 )
3077 ,   mpKerningPairs( NULL )
3078 ,   mnKerningPairs( -1 )
3079 ,	mnMinKashidaWidth( -1 )
3080 ,	mnMinKashidaGlyph( -1 )
3081 {
3082 #ifdef USE_UNISCRIBE
3083     maScriptCache = NULL;
3084 #endif // USE_UNISCRIBE
3085 }
3086 
3087 // -----------------------------------------------------------------------
3088 
3089 ImplWinFontEntry::~ImplWinFontEntry()
3090 {
3091 #ifdef USE_UNISCRIBE
3092     if( maScriptCache != NULL )
3093         (*pScriptFreeCache)( &maScriptCache );
3094 #endif // USE_UNISCRIBE
3095 #ifdef GCP_KERN_HACK
3096     delete[] mpKerningPairs;
3097 #endif // GCP_KERN_HACK
3098 }
3099 
3100 // -----------------------------------------------------------------------
3101 
3102 bool ImplWinFontEntry::HasKernData() const
3103 {
3104     return (mnKerningPairs >= 0);
3105 }
3106 
3107 // -----------------------------------------------------------------------
3108 
3109 void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
3110 {
3111     mnKerningPairs = nPairCount;
3112     mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
3113     ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) );
3114 }
3115 
3116 // -----------------------------------------------------------------------
3117 
3118 int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
3119 {
3120     int nKernAmount = 0;
3121     if( mpKerningPairs )
3122     {
3123         const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
3124         const KERNINGPAIR* pFirstPair = mpKerningPairs;
3125         const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
3126         const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
3127             pEndPair, aRefPair, ImplCmpKernData );
3128         if( (pPair != pEndPair)
3129         &&  (pPair->wFirst == aRefPair.wFirst)
3130         &&  (pPair->wSecond == aRefPair.wSecond) )
3131             nKernAmount = pPair->iKernAmount;
3132     }
3133 
3134     return nKernAmount;
3135 }
3136 
3137 // -----------------------------------------------------------------------
3138 
3139 bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
3140 {
3141 	if( mnMinKashidaWidth >= 0 )	// already cached?
3142 		return mnMinKashidaWidth;
3143 
3144 	// initialize the kashida width
3145 	mnMinKashidaWidth = 0;
3146 	mnMinKashidaGlyph = 0;
3147 #ifdef USE_UNISCRIBE
3148 	if (aUspModule || (bUspEnabled && InitUSP()))
3149 	{
3150 		SCRIPT_FONTPROPERTIES aFontProperties;
3151 		aFontProperties.cBytes = sizeof (aFontProperties);
3152 		SCRIPT_CACHE& rScriptCache = GetScriptCache();
3153 		HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
3154 		if( nRC != 0 )
3155 			return false;
3156 		mnMinKashidaWidth = aFontProperties.iKashidaWidth;
3157 		mnMinKashidaGlyph = aFontProperties.wgKashida;
3158     }
3159 #endif // USE_UNISCRIBE
3160 
3161 	return true;
3162 }
3163 
3164 // =======================================================================
3165 
3166 ImplFontData* ImplWinFontData::Clone() const
3167 {
3168     if( mpUnicodeMap )
3169         mpUnicodeMap->AddReference();
3170     ImplFontData* pClone = new ImplWinFontData( *this );
3171     return pClone;
3172 }
3173 
3174 // -----------------------------------------------------------------------
3175 
3176 ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
3177 {
3178     ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD );
3179     return pEntry;
3180 }
3181 
3182 // =======================================================================
3183