xref: /trunk/main/vcl/win/source/gdi/winlayout.cxx (revision 248a599f)
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     explicit                ImplWinFontEntry( ImplFontSelectData& );
89     virtual                 ~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* pGlyphIds, 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 {aGlyphId,nCharPos,nGlyphAdvance}
594         sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
595         if( mbDisableGlyphs )
596         {
597             if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
598             {
599                 const sal_UCS4 cChar = static_cast<sal_UCS4>(aGlyphId & GF_IDXMASK);
600                 if( mrWinFontData.HasGSUBstitutions( mhDC )
601                 &&  mrWinFontData.IsGSUBstituted( cChar ) )
602                     aGlyphId |= GF_GSUB | GF_ROTL;
603                 else
604                 {
605                     aGlyphId |= GetVerticalFlags( cChar );
606                     if( (aGlyphId & GF_ROTMASK) == 0 )
607                         aGlyphId |= GF_VERT;
608                 }
609             }
610             aGlyphId |= GF_ISCHAR;
611         }
612         ++nCount;
613         *(pGlyphIds++) = aGlyphId;
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.getHDC();
648 
649     HFONT hOrigFont = DisableFontScaling();
650 
651     UINT mnDrawOptions = ETO_GLYPH_INDEX;
652     if( mbDisableGlyphs )
653         mnDrawOptions = 0;
654 
655     Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
656 
657     // #108267#, break up into glyph portions of a limited size required by Win32 API
658     const unsigned int maxGlyphCount = 8192;
659     UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
660     UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
661 
662     if( numGlyphPortions )
663     {
664         // #108267#,#109387# break up string into smaller chunks
665         // the output positions will be updated by windows (SetTextAlign)
666         POINT oldPos;
667         UINT oldTa = ::GetTextAlign( aHDC );
668         ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP );
669         ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos );
670         unsigned int i = 0;
671         for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount )
672             ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
673                 mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i );
674         ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
675             mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i );
676         ::MoveToEx( aHDC, oldPos.x, oldPos.y, (LPPOINT) NULL);
677         ::SetTextAlign( aHDC, oldTa );
678     }
679     else
680         ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), mnDrawOptions, NULL,
681             mpOutGlyphs, mnGlyphCount, mpGlyphAdvances );
682 
683     if( hOrigFont )
684         DeleteFont( SelectFont( aHDC, hOrigFont ) );
685 }
686 
687 // -----------------------------------------------------------------------
688 
689 long SimpleWinLayout::FillDXArray( long* pDXArray ) const
690 {
691     if( !mnWidth )
692     {
693         long mnWidth = mnBaseAdv;
694         for( int i = 0; i < mnGlyphCount; ++i )
695             mnWidth += mpGlyphAdvances[ i ];
696     }
697 
698     if( pDXArray != NULL )
699     {
700         for( int i = 0; i < mnCharCount; ++i )
701              pDXArray[ i ] = mpCharWidths[ i ];
702     }
703 
704     return mnWidth;
705 }
706 
707 // -----------------------------------------------------------------------
708 
709 int SimpleWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
710 // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
711 {
712     if( mnWidth )
713         if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
714             return STRING_LEN;
715 
716     long nExtraWidth = mnBaseAdv * nFactor;
717     for( int n = 0; n < mnCharCount; ++n )
718     {
719         // skip unused characters
720         if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
721             continue;
722         // add char widths until max
723         nExtraWidth += mpCharWidths[ n ] * nFactor;
724         if( nExtraWidth >= nMaxWidth )
725             return (mnMinCharPos + n);
726         nExtraWidth += nCharExtra;
727     }
728 
729     return STRING_LEN;
730 }
731 
732 // -----------------------------------------------------------------------
733 
734 void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
735 {
736     long nXPos = mnBaseAdv;
737 
738     if( !mpGlyphs2Chars )
739     {
740         for( int i = 0; i < nMaxIdx; i += 2 )
741         {
742             pCaretXArray[ i ] = nXPos;
743             nXPos += mpGlyphAdvances[ i>>1 ];
744             pCaretXArray[ i+1 ] = nXPos;
745         }
746     }
747     else
748     {
749         int  i;
750         for( i = 0; i < nMaxIdx; ++i )
751             pCaretXArray[ i ] = -1;
752 
753         // assign glyph positions to character positions
754         for( i = 0; i < mnGlyphCount; ++i )
755         {
756             int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
757             long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
758             nCurrIdx *= 2;
759             if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
760             {
761                 // normal positions for LTR case
762                 pCaretXArray[ nCurrIdx ]   = nXPos;
763                 pCaretXArray[ nCurrIdx+1 ] = nXRight;
764             }
765             else
766             {
767                 // reverse positions for RTL case
768                 pCaretXArray[ nCurrIdx ]   = nXRight;
769                 pCaretXArray[ nCurrIdx+1 ] = nXPos;
770             }
771             nXPos += mpGlyphAdvances[ i ];
772         }
773     }
774 }
775 
776 // -----------------------------------------------------------------------
777 
778 void SimpleWinLayout::Justify( long nNewWidth )
779 {
780     long nOldWidth = mnWidth;
781     mnWidth = nNewWidth;
782 
783     if( mnGlyphCount <= 0 )
784         return;
785 
786     if( nNewWidth == nOldWidth )
787         return;
788 
789     // the rightmost glyph cannot be stretched
790     const int nRight = mnGlyphCount - 1;
791     nOldWidth -= mpGlyphAdvances[ nRight ];
792     nNewWidth -= mpGlyphAdvances[ nRight ];
793 
794     // count stretchable glyphs
795     int nStretchable = 0, i;
796     for( i = 0; i < nRight; ++i )
797         if( mpGlyphAdvances[i] >= 0 )
798             ++nStretchable;
799 
800     // stretch these glyphs
801     int nDiffWidth = nNewWidth - nOldWidth;
802     for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
803     {
804         if( mpGlyphAdvances[i] <= 0 )
805             continue;
806         int nDeltaWidth = nDiffWidth / nStretchable;
807         mpGlyphAdvances[i] += nDeltaWidth;
808         --nStretchable;
809         nDiffWidth -= nDeltaWidth;
810     }
811 }
812 
813 // -----------------------------------------------------------------------
814 
815 void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
816 {
817     SalLayout::AdjustLayout( rArgs );
818 
819     // adjust positions if requested
820     if( rArgs.mpDXArray )
821         ApplyDXArray( rArgs );
822     else if( rArgs.mnLayoutWidth )
823         Justify( rArgs.mnLayoutWidth );
824     else
825         return;
826 
827     // recalculate virtual char widths if they were changed
828     if( mpCharWidths != mpGlyphAdvances )
829     {
830         int i;
831         if( !mpGlyphs2Chars )
832         {
833             // standard LTR case
834             for( i = 0; i < mnGlyphCount; ++i )
835                  mpCharWidths[ i ] = mpGlyphAdvances[ i ];
836         }
837         else
838         {
839             // BiDi or complex case
840             for( i = 0; i < mnCharCount; ++i )
841                 mpCharWidths[ i ] = 0;
842             for( i = 0; i < mnGlyphCount; ++i )
843             {
844                 int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
845                 if( j >= 0 )
846                     mpCharWidths[ j ] += mpGlyphAdvances[ i ];
847             }
848         }
849     }
850 }
851 
852 // -----------------------------------------------------------------------
853 
854 void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
855 {
856     // try to avoid disturbance of text flow for LSB rounding case;
857     const long* pDXArray = rArgs.mpDXArray;
858 
859     int i = 0;
860     long nOldWidth = mnBaseAdv;
861     for(; i < mnCharCount; ++i )
862     {
863         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
864         if( j >= 0 )
865         {
866             nOldWidth += mpGlyphAdvances[ j ];
867             int nDiff = nOldWidth - pDXArray[ i ];
868 
869             // disabled because of #104768#
870             // works great for static text, but problems when typing
871             // if( nDiff>+1 || nDiff<-1 )
872             // only bother with changing anything when something moved
873             if( nDiff != 0 )
874                 break;
875         }
876     }
877     if( i >= mnCharCount )
878         return;
879 
880     if( !mpGlyphOrigAdvs )
881     {
882         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
883         for( i = 0; i < mnGlyphCount; ++i )
884             mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
885     }
886 
887     mnWidth = mnBaseAdv;
888     for( i = 0; i < mnCharCount; ++i )
889     {
890         int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
891         if( j >= 0 )
892             mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
893         mnWidth = pDXArray[i];
894     }
895 }
896 
897 // -----------------------------------------------------------------------
898 
899 void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
900 {
901    if( nStart > mnGlyphCount )
902         return;
903 
904     // calculate the current x-position of the requested glyph
905     // TODO: cache absolute positions
906     int nXPos = mnBaseAdv;
907     for( int i = 0; i < nStart; ++i )
908         nXPos += mpGlyphAdvances[i];
909 
910     // calculate the difference to the current glyph position
911     int nDelta = nNewXPos - nXPos;
912 
913     // adjust the width of the layout if it was already cached
914     if( mnWidth )
915         mnWidth += nDelta;
916 
917     // depending on whether the requested glyph is leftmost in the layout
918     // adjust either the layout's or the requested glyph's relative position
919     if( nStart > 0 )
920         mpGlyphAdvances[ nStart-1 ] += nDelta;
921     else
922         mnBaseAdv += nDelta;
923 }
924 
925 // -----------------------------------------------------------------------
926 
927 void SimpleWinLayout::DropGlyph( int nStart )
928 {
929     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
930 }
931 
932 // -----------------------------------------------------------------------
933 
934 void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
935 {
936     // return early if no glyph has been dropped
937     int i = mnGlyphCount;
938     while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
939     if( i < 0 )
940         return;
941 
942     // convert the layout to a sparse layout if it is not already
943     if( !mpGlyphs2Chars )
944     {
945         mpGlyphs2Chars = new int[ mnGlyphCount ];
946         mpCharWidths = new int[ mnCharCount ];
947         // assertion: mnGlyphCount == mnCharCount
948         for( int k = 0; k < mnGlyphCount; ++k )
949         {
950             mpGlyphs2Chars[ k ] = mnMinCharPos + k;
951             mpCharWidths[ k ] = mpGlyphAdvances[ k ];
952         }
953     }
954 
955     // remove dropped glyphs that are rightmost in the layout
956     for( i = mnGlyphCount; --i >= 0; )
957     {
958         if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
959             break;
960         if( mnWidth )
961             mnWidth -= mpGlyphAdvances[ i ];
962         int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
963         if( nRelCharPos >= 0 )
964             mpCharWidths[ nRelCharPos ] = 0;
965     }
966     mnGlyphCount = i + 1;
967 
968     // keep original glyph widths around
969     if( !mpGlyphOrigAdvs )
970     {
971         mpGlyphOrigAdvs = new int[ mnGlyphCount ];
972         for( int k = 0; k < mnGlyphCount; ++k )
973             mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
974     }
975 
976     // remove dropped glyphs inside the layout
977     int nNewGC = 0;
978     for( i = 0; i < mnGlyphCount; ++i )
979     {
980         if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
981         {
982             // adjust relative position to last valid glyph
983             int nDroppedWidth = mpGlyphAdvances[ i ];
984             mpGlyphAdvances[ i ] = 0;
985             if( nNewGC > 0 )
986                 mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
987             else
988                 mnBaseAdv += nDroppedWidth;
989 
990             // zero the virtual char width for the char that has a fallback
991             int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
992             if( nRelCharPos >= 0 )
993                 mpCharWidths[ nRelCharPos ] = 0;
994         }
995         else
996         {
997             if( nNewGC != i )
998             {
999                 // rearrange the glyph array to get rid of the dropped glyph
1000                 mpOutGlyphs[ nNewGC ]     = mpOutGlyphs[ i ];
1001                 mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
1002                 mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
1003                 mpGlyphs2Chars[ nNewGC ]  = mpGlyphs2Chars[ i ];
1004             }
1005             ++nNewGC;
1006         }
1007     }
1008 
1009     mnGlyphCount = nNewGC;
1010     if( mnGlyphCount <= 0 )
1011         mnWidth = mnBaseAdv = 0;
1012 }
1013 
1014 // =======================================================================
1015 
1016 #ifdef USE_UNISCRIBE
1017 
1018 struct VisualItem
1019 {
1020 public:
1021     SCRIPT_ITEM*    mpScriptItem;
1022     int             mnMinGlyphPos;
1023     int             mnEndGlyphPos;
1024     int             mnMinCharPos;
1025     int             mnEndCharPos;
1026     //long          mnPixelWidth;
1027     int             mnXOffset;
1028     ABC             maABCWidths;
1029     bool            mbHasKashidas;
1030 
1031 public:
1032     bool            IsEmpty() const { return (mnEndGlyphPos <= 0); }
1033     bool            IsRTL() const { return mpScriptItem->a.fRTL; }
1034     bool            HasKashidas() const { return mbHasKashidas; }
1035 };
1036 
1037 // -----------------------------------------------------------------------
1038 
1039 class UniscribeLayout : public WinLayout
1040 {
1041 public:
1042                     UniscribeLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
1043 
1044     virtual bool    LayoutText( ImplLayoutArgs& );
1045     virtual void    AdjustLayout( ImplLayoutArgs& );
1046     virtual void    DrawText( SalGraphics& ) const;
1047     virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
1048                         sal_Int32* pGlyphAdvances, int* pCharPosAry ) const;
1049 
1050     virtual long    FillDXArray( long* pDXArray ) const;
1051     virtual int     GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
1052     virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
1053     virtual bool    IsKashidaPosValid ( int nCharPos ) const;
1054 
1055     // for glyph+font+script fallback
1056     virtual void    MoveGlyph( int nStart, long nNewXPos );
1057     virtual void    DropGlyph( int nStart );
1058     virtual void    Simplify( bool bIsBase );
1059     virtual void    DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; }
1060 
1061 protected:
1062     virtual         ~UniscribeLayout();
1063 
1064     void            Justify( long nNewWidth );
1065     void            ApplyDXArray( const ImplLayoutArgs& );
1066 
1067     bool            GetItemSubrange( const VisualItem&,
1068                         int& rMinIndex, int& rEndIndex ) const;
1069 
1070 private:
1071     // item specific info
1072     SCRIPT_ITEM*    mpScriptItems;      // in logical order
1073     VisualItem*     mpVisualItems;      // in visual order
1074     int             mnItemCount;        // number of visual items
1075 
1076     // string specific info
1077     // everything is in logical order
1078     int             mnCharCapacity;
1079     WORD*           mpLogClusters;      // map from absolute_char_pos to relative_glyph_pos
1080     int*            mpCharWidths;       // map from absolute_char_pos to char_width
1081     int             mnSubStringMin;     // char_pos of first char in context
1082 
1083     // glyph specific info
1084     // everything is in visual order
1085     int             mnGlyphCount;
1086     int             mnGlyphCapacity;
1087     int*            mpGlyphAdvances;    // glyph advance width before justification
1088     int*            mpJustifications;   // glyph advance width after justification
1089     WORD*           mpOutGlyphs;        // glyphids in visual order
1090     GOFFSET*        mpGlyphOffsets;     // glyph offsets to the "naive" layout
1091     SCRIPT_VISATTR* mpVisualAttrs;      // glyph visual attributes
1092     mutable int*    mpGlyphs2Chars;     // map from absolute_glyph_pos to absolute_char_pos
1093 
1094     // kashida stuff
1095     void InitKashidaHandling();
1096     void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
1097     bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
1098 
1099     int            mnMinKashidaWidth;
1100     int            mnMinKashidaGlyph;
1101     bool           mbDisableGlyphInjection;
1102 };
1103 
1104 // -----------------------------------------------------------------------
1105 // dynamic loading of usp library
1106 
1107 static oslModule aUspModule = NULL;
1108 static bool bUspEnabled = true;
1109 
1110 static HRESULT ((WINAPI *pScriptIsComplex)( const WCHAR*, int, DWORD ));
1111 static HRESULT ((WINAPI *pScriptItemize)( const WCHAR*, int, int,
1112     const SCRIPT_CONTROL*, const SCRIPT_STATE*, SCRIPT_ITEM*, int* ));
1113 static HRESULT ((WINAPI *pScriptShape)( HDC, SCRIPT_CACHE*, const WCHAR*,
1114     int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*, int* ));
1115 static HRESULT ((WINAPI *pScriptPlace)( HDC, SCRIPT_CACHE*, const WORD*, int,
1116     const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*, int*, GOFFSET*, ABC* ));
1117 static HRESULT ((WINAPI *pScriptGetLogicalWidths)( const SCRIPT_ANALYSIS*,
1118     int, int, const int*, const WORD*, const SCRIPT_VISATTR*, int* ));
1119 static HRESULT ((WINAPI *pScriptApplyLogicalWidth)( const int*, int, int, const WORD*,
1120     const SCRIPT_VISATTR*, const int*, const SCRIPT_ANALYSIS*, ABC*, int* ));
1121 static HRESULT ((WINAPI *pScriptJustify)( const SCRIPT_VISATTR*,
1122     const int*, int, int, int, int* ));
1123 static HRESULT ((WINAPI *pScriptTextOut)( const HDC, SCRIPT_CACHE*,
1124     int, int, UINT, const RECT*, const SCRIPT_ANALYSIS*, const WCHAR*,
1125     int, const WORD*, int, const int*, const int*, const GOFFSET* ));
1126 static HRESULT ((WINAPI *pScriptGetFontProperties)( HDC, SCRIPT_CACHE*, SCRIPT_FONTPROPERTIES* ));
1127 static HRESULT ((WINAPI *pScriptFreeCache)( SCRIPT_CACHE* ));
1128 
1129 static bool bManualCellAlign = true;
1130 
1131 // -----------------------------------------------------------------------
1132 
1133 static bool InitUSP()
1134 {
1135     aUspModule = osl_loadAsciiModule( "usp10", SAL_LOADMODULE_DEFAULT );
1136     if( !aUspModule )
1137         return (bUspEnabled = false);
1138 
1139     pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD))
1140         osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" );
1141     bUspEnabled &= (NULL != pScriptIsComplex);
1142 
1143     pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int,
1144         const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*))
1145         osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" );
1146     bUspEnabled &= (NULL != pScriptItemize);
1147 
1148     pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*,
1149         int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*))
1150         osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" );
1151     bUspEnabled &= (NULL != pScriptShape);
1152 
1153     pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int,
1154         const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*))
1155         osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" );
1156     bUspEnabled &= (NULL != pScriptPlace);
1157 
1158     pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*,
1159         int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*))
1160         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" );
1161     bUspEnabled &= (NULL != pScriptGetLogicalWidths);
1162 
1163     pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*,
1164         const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*))
1165         osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" );
1166     bUspEnabled &= (NULL != pScriptApplyLogicalWidth);
1167 
1168     pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*,
1169         int,int,int,int*))
1170         osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" );
1171     bUspEnabled &= (NULL != pScriptJustify);
1172 
1173     pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*))
1174         osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" );
1175     bUspEnabled &= (NULL != pScriptGetFontProperties);
1176 
1177     pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*,
1178         int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*,
1179         int,const WORD*,int,const int*,const int*,const GOFFSET*))
1180         osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" );
1181     bUspEnabled &= (NULL != pScriptTextOut);
1182 
1183     pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*))
1184         osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" );
1185     bUspEnabled &= (NULL != pScriptFreeCache);
1186 
1187     if( !bUspEnabled )
1188     {
1189         osl_unloadModule( aUspModule );
1190         aUspModule = NULL;
1191     }
1192 
1193 	// get the DLL version info
1194 	int nUspVersion = 0;
1195 	// TODO: there must be a simpler way to get the friggin version info from OSL?
1196 	rtl_uString* pModuleURL = NULL;
1197 	osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL );
1198 	rtl_uString* pModuleFileName = NULL;
1199 	if( pModuleURL )
1200 		osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
1201 	const sal_Unicode* pModuleFileCStr = NULL;
1202 	if( pModuleFileName )
1203 		pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
1204 	if( pModuleFileCStr )
1205 	{
1206 		DWORD nHandle;
1207 		DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
1208 		char* pBuffer = (char*)alloca( nBufSize );
1209 		BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
1210 		VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
1211 		UINT nFixedFileSize = 0;
1212 		if( bRC )
1213 			::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
1214 		if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
1215 			nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
1216 						+ LOWORD(pFixedFileInfo->dwProductVersionMS);
1217 	}
1218 
1219 	// #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
1220 	if( nUspVersion >= 10600 )
1221 		bManualCellAlign = false;
1222 
1223     return bUspEnabled;
1224 }
1225 
1226 // -----------------------------------------------------------------------
1227 
1228 UniscribeLayout::UniscribeLayout( HDC hDC,
1229     const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
1230 :   WinLayout( hDC, rWinFontData, rWinFontEntry ),
1231     mnItemCount( 0 ),
1232     mpScriptItems( NULL ),
1233     mpVisualItems( NULL ),
1234     mpLogClusters( NULL ),
1235     mpCharWidths( NULL ),
1236     mnCharCapacity( 0 ),
1237     mnSubStringMin( 0 ),
1238     mnGlyphCapacity( 0 ),
1239     mnGlyphCount( 0 ),
1240     mpOutGlyphs( NULL ),
1241     mpGlyphAdvances( NULL ),
1242     mpJustifications( NULL ),
1243     mpGlyphOffsets( NULL ),
1244     mpVisualAttrs( NULL ),
1245     mpGlyphs2Chars( NULL ),
1246     mnMinKashidaGlyph( 0 ),
1247     mbDisableGlyphInjection( false )
1248 {}
1249 
1250 // -----------------------------------------------------------------------
1251 
1252 UniscribeLayout::~UniscribeLayout()
1253 {
1254     delete[] mpScriptItems;
1255     delete[] mpVisualItems;
1256     delete[] mpLogClusters;
1257     delete[] mpCharWidths;
1258     delete[] mpOutGlyphs;
1259     delete[] mpGlyphAdvances;
1260     delete[] mpJustifications;
1261     delete[] mpGlyphOffsets;
1262     delete[] mpVisualAttrs;
1263     delete[] mpGlyphs2Chars;
1264 }
1265 
1266 // -----------------------------------------------------------------------
1267 
1268 bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
1269 {
1270     // for a base layout only the context glyphs have to be dropped
1271     // => when the whole string is involved there is no extra context
1272     typedef std::vector<int> TIntVector;
1273     TIntVector aDropChars;
1274     if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
1275     {
1276         // calculate superfluous context char positions
1277         aDropChars.push_back( 0 );
1278         aDropChars.push_back( rArgs.mnLength );
1279         int nMin, nEnd;
1280         bool bRTL;
1281         for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
1282         {
1283             aDropChars.push_back( nMin );
1284             aDropChars.push_back( nEnd );
1285         }
1286         // prepare aDropChars for binary search which will allow to
1287         // not bother with visual items that will be dropped anyway
1288         std::sort( aDropChars.begin(), aDropChars.end() );
1289     }
1290 
1291     // prepare layout
1292     // TODO: fix case when recyclying old UniscribeLayout object
1293     mnMinCharPos = rArgs.mnMinCharPos;
1294     mnEndCharPos = rArgs.mnEndCharPos;
1295 
1296     // determine script items from string
1297 
1298     // prepare itemization
1299     // TODO: try to avoid itemization since it costs a lot of performance
1300     SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0};
1301     aScriptState.uBidiLevel         = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL));
1302     aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG));
1303     aScriptState.fDigitSubstitute   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1304     aScriptState.fArabicNumContext  = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
1305     DWORD nLangId = 0;  // TODO: get language from font
1306     SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0};
1307     aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
1308     aScriptControl.fContextDigits   = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
1309     aScriptControl.fMergeNeutralItems = true;
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                                 // #i55716# skip WORDJOINER
1547                                 if( rArgs.mpStr[ c ] == 0x2060 )
1548                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1549                                 else
1550                                     rArgs.NeedFallback( c, false );
1551                            }
1552                         }
1553                     }
1554                     else
1555                     {
1556                         // request fallback for the right to left cell
1557                         for( int c = nEndCharPos; --c >= nMinCharPos; )
1558                         {
1559                             if( mpLogClusters[ c ] == i )
1560                             {
1561                                 // #i55716# skip WORDJOINER
1562                                 if( rArgs.mpStr[ c ] == 0x2060 )
1563                                     mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
1564                                 else
1565                                     rArgs.NeedFallback( c, true );
1566                             }
1567                         }
1568                     }
1569                 } while( ++i < nGlyphCount );
1570             }
1571         }
1572 
1573         // now place the glyphs
1574         nRC = (*pScriptPlace)( mhDC, &rScriptCache,
1575             mpOutGlyphs + rVisualItem.mnMinGlyphPos,
1576             nGlyphCount,
1577             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1578             &rVisualItem.mpScriptItem->a,
1579             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1580             mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
1581             &rVisualItem.maABCWidths );
1582 
1583         if( nRC != 0 )
1584             continue;
1585 
1586         // calculate the logical char widths from the glyph layout
1587         nRC = (*pScriptGetLogicalWidths)(
1588             &rVisualItem.mpScriptItem->a,
1589             nCharCount, nGlyphCount,
1590             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
1591             mpLogClusters + rVisualItem.mnMinCharPos,
1592             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
1593             mpCharWidths + rVisualItem.mnMinCharPos );
1594 
1595         // update the glyph counters
1596         mnGlyphCount += nGlyphCount;
1597         rVisualItem.mnEndGlyphPos = mnGlyphCount;
1598 
1599         // update nXOffset
1600         int nEndGlyphPos;
1601         if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
1602             for(; i < nEndGlyphPos; ++i )
1603                 nXOffset += mpGlyphAdvances[ i ];
1604 
1605         // TODO: shrink glyphpos limits to match charpos/fallback limits
1606         //pVI->mnMinGlyphPos = nMinGlyphPos;
1607         //pVI->mnEndGlyphPos = nEndGlyphPos;
1608 
1609         // drop the superfluous context glyphs
1610         TIntVector::const_iterator it = aDropChars.begin();
1611         while( it != aDropChars.end() )
1612         {
1613             // find matching "drop range"
1614             int nMinDropPos = *(it++); // begin of drop range
1615             if( nMinDropPos >= rVisualItem.mnEndCharPos )
1616                 break;
1617             int nEndDropPos = *(it++); // end of drop range
1618             if( nEndDropPos <= rVisualItem.mnMinCharPos )
1619                 continue;
1620             // clip "drop range" to visual item's char range
1621             if( nMinDropPos <= rVisualItem.mnMinCharPos )
1622             {
1623                 nMinDropPos = rVisualItem.mnMinCharPos;
1624                 // drop the whole visual item if possible
1625                 if( nEndDropPos >= rVisualItem.mnEndCharPos )
1626                 {
1627                     rVisualItem.mnEndGlyphPos = 0;
1628                     break;
1629                 }
1630             }
1631             if( nEndDropPos > rVisualItem.mnEndCharPos )
1632                 nEndDropPos = rVisualItem.mnEndCharPos;
1633 
1634             // drop the glyphs which correspond to the charpos range
1635             // drop the corresponding glyphs in the cluster
1636             for( int c = nMinDropPos; c < nEndDropPos; ++c )
1637             {
1638                 int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
1639                 // no need to bother when the cluster was already dropped
1640                 if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
1641                 {
1642                     for(;;)
1643                     {
1644                         mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
1645                         // until the end of visual item
1646                         if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
1647                             break;
1648                         // until the next cluster start
1649                         if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
1650                             break;
1651                     }
1652                 }
1653             }
1654         }
1655     }
1656 
1657     // scale layout metrics if needed
1658 	// TODO: does it make the code more simple if the metric scaling
1659 	// is moved to the methods that need metric scaling (e.g. FillDXArray())?
1660     if( mfFontScale != 1.0 )
1661     {
1662         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1663 
1664         for( i = 0; i < mnItemCount; ++i )
1665             mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
1666 
1667         mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
1668         for( i = 0; i < mnGlyphCount; ++i )
1669         {
1670             mpGlyphAdvances[i]   = (int)(mpGlyphAdvances[i] * mfFontScale);
1671             mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
1672             mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
1673             // mpJustifications are still NULL
1674         }
1675 
1676         for( i = mnSubStringMin; i < nSubStringEnd; ++i )
1677             mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
1678     }
1679 
1680     return true;
1681 }
1682 
1683 // -----------------------------------------------------------------------
1684 
1685 // calculate the range of relevant glyphs for this visual item
1686 bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
1687     int& rMinGlyphPos, int& rEndGlyphPos ) const
1688 {
1689     // return early when nothing of interest in this item
1690     if( rVisualItem.IsEmpty()
1691      || (rVisualItem.mnEndCharPos <= mnMinCharPos)
1692      || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
1693         return false;
1694 
1695     // default: subrange is complete range
1696     rMinGlyphPos = rVisualItem.mnMinGlyphPos;
1697     rEndGlyphPos = rVisualItem.mnEndGlyphPos;
1698 
1699     // return early when the whole item is of interest
1700     if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
1701      && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
1702         return true;
1703 
1704     // get glyph range from char range by looking at cluster boundries
1705     // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
1706     rMinGlyphPos = rVisualItem.mnEndGlyphPos;
1707     int nMaxGlyphPos = 0;
1708 
1709     int i = mnMinCharPos;
1710     if( i < rVisualItem.mnMinCharPos )
1711         i = rVisualItem.mnMinCharPos;
1712     int nCharPosLimit = rVisualItem.mnEndCharPos;
1713     if( nCharPosLimit > mnEndCharPos )
1714         nCharPosLimit = mnEndCharPos;
1715     for(; i < nCharPosLimit; ++i )
1716     {
1717         int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
1718         if( rMinGlyphPos > n )
1719             rMinGlyphPos = n;
1720         if( nMaxGlyphPos < n )
1721             nMaxGlyphPos = n;
1722     }
1723 	if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
1724 		nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
1725 
1726     // extend the glyph range to account for all glyphs in referenced clusters
1727     if( !rVisualItem.IsRTL() ) // LTR-item
1728     {
1729         // extend to rightmost glyph of rightmost referenced cluster
1730         for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
1731             if( mpVisualAttrs[i].fClusterStart )
1732                 break;
1733     }
1734     else // RTL-item
1735     {
1736         // extend to leftmost glyph of leftmost referenced cluster
1737         for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
1738             if( mpVisualAttrs[i].fClusterStart )
1739                 break;
1740     }
1741     rEndGlyphPos = nMaxGlyphPos + 1;
1742 
1743     return true;
1744 }
1745 
1746 // -----------------------------------------------------------------------
1747 
1748 int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
1749     int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
1750 {
1751     // HACK to allow fake-glyph insertion (e.g. for kashidas)
1752     // TODO: use iterator idiom instead of GetNextGlyphs(...)
1753     // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
1754     int nSubIter = nStartx8 & 0xff;
1755     int nStart = nStartx8 >> 8;
1756 
1757     // check the glyph iterator
1758     if( nStart > mnGlyphCount )       // nStart>MAX means no more glyphs
1759         return 0;
1760 
1761     // find the visual item for the nStart glyph position
1762     int nItem = 0;
1763     const VisualItem* pVI = mpVisualItems;
1764     if( nStart <= 0 )                 // nStart<=0 requests the first visible glyph
1765     {
1766         // find first visible item
1767         for(; nItem < mnItemCount; ++nItem, ++pVI )
1768             if( !pVI->IsEmpty() )
1769                 break;
1770         // it is possible that there are glyphs but no valid visual item
1771         // TODO: get rid of these visual items more early
1772         if( nItem < mnItemCount )
1773             nStart = pVI->mnMinGlyphPos;
1774     }
1775     else //if( nStart > 0 )           // nStart>0 means absolute glyph pos +1
1776     {
1777         --nStart;
1778 
1779         // find matching item
1780         for(; nItem < mnItemCount; ++nItem, ++pVI )
1781             if( (nStart >= pVI->mnMinGlyphPos)
1782             &&  (nStart < pVI->mnEndGlyphPos) )
1783                 break;
1784     }
1785 
1786     // after the last visual item there are no more glyphs
1787     if( (nItem >= mnItemCount) || (nStart < 0) )
1788     {
1789         nStartx8 = (mnGlyphCount + 1) << 8;
1790         return 0;
1791     }
1792 
1793     // calculate the first glyph in the next visual item
1794     int nNextItemStart = mnGlyphCount;
1795     while( ++nItem < mnItemCount )
1796     {
1797         if( mpVisualItems[nItem].IsEmpty() )
1798             continue;
1799         nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
1800         break;
1801     }
1802 
1803     // get the range of relevant glyphs in this visual item
1804     int nMinGlyphPos, nEndGlyphPos;
1805     bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
1806     DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
1807     if( !bRC )
1808     {
1809         nStartx8 = (mnGlyphCount + 1) << 8;
1810         return 0;
1811     }
1812 
1813     // make sure nStart is inside the range of relevant glyphs
1814     if( nStart < nMinGlyphPos )
1815         nStart = nMinGlyphPos;
1816 
1817     // calculate the start glyph xoffset relative to layout's base position,
1818     // advance to next visual glyph position by using adjusted glyph widths
1819     // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
1820     long nXOffset = pVI->mnXOffset;
1821     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
1822     for( int i = nMinGlyphPos; i < nStart; ++i )
1823         nXOffset += pGlyphWidths[ i ];
1824 
1825     // adjust the nXOffset relative to glyph cluster start
1826     int c = mnMinCharPos;
1827     if( !pVI->IsRTL() ) // LTR-case
1828     {
1829         // LTR case: subtract the remainder of the cell from xoffset
1830         int nTmpIndex = mpLogClusters[c];
1831         while( (--c >= pVI->mnMinCharPos)
1832             && (nTmpIndex == mpLogClusters[c]) )
1833             nXOffset -= mpCharWidths[c];
1834     }
1835     else // RTL-case
1836     {
1837         // RTL case: add the remainder of the cell from xoffset
1838         int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
1839         while( (--c >= pVI->mnMinCharPos)
1840             && (nTmpIndex == mpLogClusters[c]) )
1841             nXOffset += mpCharWidths[c];
1842 
1843         // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
1844 		if( mpJustifications && !bManualCellAlign )
1845            nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
1846     }
1847 
1848 	// create mpGlyphs2Chars[] if it is needed later
1849 	if( pCharPosAry && !mpGlyphs2Chars )
1850 	{
1851 		// create and reset the new array
1852 		mpGlyphs2Chars = new int[ mnGlyphCapacity ];
1853 		static const int CHARPOS_NONE = -1;
1854 		for( int i = 0; i < mnGlyphCount; ++i )
1855 			mpGlyphs2Chars[i] = CHARPOS_NONE;
1856 		// calculate the char->glyph mapping
1857 		for( nItem = 0; nItem < mnItemCount; ++nItem )
1858 		{
1859 			// ignore invisible visual items
1860 			const VisualItem& rVI = mpVisualItems[ nItem ];
1861 			if( rVI.IsEmpty() )
1862 				continue;
1863 			// calculate the mapping by using mpLogClusters[]
1864 			// mpGlyphs2Chars[] should obey the logical order
1865 			// => reversing the loop does this by overwriting higher logicals
1866 			for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
1867 			{
1868 				int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
1869 				mpGlyphs2Chars[i] = c;
1870 			}
1871 			// use a heuristic to fill the gaps in the glyphs2chars array
1872 			c = !rVI.IsRTL() ? rVI.mnMinCharPos : rVI.mnEndCharPos - 1;
1873 			for( int i = rVI.mnMinGlyphPos; i < rVI.mnEndGlyphPos; ++i ) {
1874 				if( mpGlyphs2Chars[i] == CHARPOS_NONE )
1875 					mpGlyphs2Chars[i] = c;
1876 				else
1877 					c = mpGlyphs2Chars[i];
1878 			}
1879 		}
1880 	}
1881 
1882     // calculate the absolute position of the first result glyph in pixel units
1883     const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
1884     Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
1885     rPos = GetDrawPosition( aRelativePos );
1886 
1887 	// fill the result arrays
1888     int nCount = 0;
1889     while( nCount < nLen )
1890     {
1891         // prepare return values
1892         sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
1893         int nGlyphWidth = pGlyphWidths[ nStart ];
1894         int nCharPos = -1;    // no need to determine charpos
1895         if( mpGlyphs2Chars )  // unless explicitly requested+provided
1896             nCharPos = mpGlyphs2Chars[ nStart ];
1897 
1898         // inject kashida glyphs if needed
1899         if( !mbDisableGlyphInjection
1900         && mpJustifications
1901         && mnMinKashidaWidth
1902         && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
1903         {
1904 			// prepare draw position adjustment
1905 			int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
1906         	// calculate space available for the injected glyphs
1907    	        nGlyphWidth = mpGlyphAdvances[ nStart ];
1908 	        const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
1909 			const int nToFillWidth = nExtraWidth - nExtraOfs;
1910 	        if( (4*nToFillWidth >= mnMinKashidaWidth)    // prevent glyph-injection if there is no room
1911 	        ||  ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
1912 	        {
1913 	        	// handle if there is not sufficient room for a full glyph
1914 	        	if( nToFillWidth < mnMinKashidaWidth )
1915 	        	{
1916 	        		// overlap it with the previously injected glyph if possible
1917 	        		int nOverlap = mnMinKashidaWidth - nToFillWidth;
1918 	        		// else overlap it with both neighboring glyphs
1919 					if( nSubIter <= 1 )
1920 						nOverlap /= 2;
1921 					nExtraOfs -= nOverlap;
1922 	        	}
1923 	        	nGlyphWidth = mnMinKashidaWidth;
1924 	        	aGlyphId = mnMinKashidaGlyph;
1925 				nCharPos = -1;
1926 	        }
1927 	        else
1928 	        {
1929 	        	nExtraOfs += nToFillWidth;	// at right of cell
1930 	        	nSubIter = 0;				// done with glyph injection
1931 	        }
1932             if( !bManualCellAlign )
1933                 nExtraOfs -= nExtraWidth;	// adjust for right-aligned cells
1934 
1935 			// adjust the draw position for the injected-glyphs case
1936 			if( nExtraOfs )
1937 			{
1938 				aRelativePos.X() += nExtraOfs;
1939 				rPos = GetDrawPosition( aRelativePos );
1940 			}
1941         }
1942 
1943         // update return values
1944         *(pGlyphs++) = aGlyphId;
1945         if( pGlyphAdvances )
1946             *(pGlyphAdvances++) = nGlyphWidth;
1947         if( pCharPosAry )
1948             *(pCharPosAry++) = nCharPos;
1949 
1950         // increment counter of returned glyphs
1951         ++nCount;
1952 
1953         // reduce code complexity by returning early in glyph-injection case
1954        	if( nSubIter != 0 )
1955        		break;
1956 
1957         // stop after the last visible glyph in this visual item
1958         if( ++nStart >= nEndGlyphPos )
1959         {
1960             nStart = nNextItemStart;
1961             break;
1962         }
1963 
1964         // RTL-justified glyph positioning is not easy
1965         // simplify the code by just returning only one glyph at a time
1966         if( mpJustifications && pVI->IsRTL() )
1967             break;
1968 
1969         // stop when the x-position of the next glyph is unexpected
1970         if( !pGlyphAdvances  )
1971             if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
1972              || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
1973                 break;
1974 
1975         // stop when the y-position of the next glyph is unexpected
1976         if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
1977             break;
1978     }
1979 
1980     ++nStart;
1981     nStartx8 = (nStart << 8) + nSubIter;
1982     return nCount;
1983 }
1984 
1985 // -----------------------------------------------------------------------
1986 
1987 void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
1988 {
1989     DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
1990     int nStart = nStartx8 >> 8;
1991     if( nStart > mnGlyphCount )
1992         return;
1993 
1994     VisualItem* pVI = mpVisualItems;
1995     int nMinGlyphPos = 0, nEndGlyphPos;
1996     if( nStart == 0 )               // nStart==0 for first visible glyph
1997     {
1998         for( int i = mnItemCount; --i >= 0; ++pVI )
1999             if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
2000                 break;
2001         nStart = nMinGlyphPos;
2002         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" );
2003     }
2004     else //if( nStart > 0 )         // nStart>0 means absolute_glyphpos+1
2005     {
2006         --nStart;
2007         for( int i = mnItemCount; --i >= 0; ++pVI )
2008             if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
2009                 break;
2010         bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
2011 	(void)bRC; // avoid var-not-used warning
2012         DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
2013     }
2014 
2015     long nDelta = nNewXPos - pVI->mnXOffset;
2016     if( nStart > nMinGlyphPos )
2017     {
2018         // move the glyph by expanding its left glyph but ignore dropped glyphs
2019         int i, nLastUndropped = nMinGlyphPos - 1;
2020         for( i = nMinGlyphPos; i < nStart; ++i )
2021 		{
2022 			if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
2023 			{
2024 	            nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
2025 				nLastUndropped = i;
2026 			}
2027 		}
2028 		if (nLastUndropped >= nMinGlyphPos)
2029 		{
2030 			mpGlyphAdvances[ nLastUndropped ] += nDelta;
2031 			if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
2032 		}
2033 		else
2034 		{
2035 			pVI->mnXOffset += nDelta;
2036 		}
2037     }
2038     else
2039     {
2040         // move the visual item by having an offset
2041         pVI->mnXOffset += nDelta;
2042     }
2043     // move subsequent items - this often isn't necessary because subsequent
2044     // moves will correct subsequent items. However, if there is a contiguous
2045     // range not involving fallback which spans items, this will be needed
2046     while (++pVI - mpVisualItems < mnItemCount)
2047     {
2048         pVI->mnXOffset += nDelta;
2049     }
2050 }
2051 
2052 // -----------------------------------------------------------------------
2053 
2054 void UniscribeLayout::DropGlyph( int nStartx8 )
2055 {
2056     DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
2057     int nStart = nStartx8 >> 8;
2058     DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
2059 
2060     if( nStart > 0 )        // nStart>0 means absolute glyph pos + 1
2061         --nStart;
2062     else                    // nStart<=0 for first visible glyph
2063     {
2064         VisualItem* pVI = mpVisualItems;
2065         for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
2066             if( GetItemSubrange( *pVI, nStart, nDummy ) )
2067                 break;
2068         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
2069 		int nOffset = 0;
2070 		int j = pVI->mnMinGlyphPos;
2071 		while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
2072 		if (j == nStart)
2073 		{
2074 			pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
2075 		}
2076     }
2077 
2078     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
2079 }
2080 
2081 // -----------------------------------------------------------------------
2082 
2083 void UniscribeLayout::Simplify( bool /*bIsBase*/ )
2084 {
2085     static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH;
2086     int i;
2087     // if there are no dropped glyphs don't bother
2088     for( i = 0; i < mnGlyphCount; ++i )
2089         if( mpOutGlyphs[ i ] == cDroppedGlyph )
2090             break;
2091     if( i >= mnGlyphCount )
2092         return;
2093 
2094     // prepare for sparse layout
2095     // => make sure mpGlyphs2Chars[] exists
2096     if( !mpGlyphs2Chars )
2097     {
2098         mpGlyphs2Chars = new int[ mnGlyphCapacity ];
2099         for( i = 0; i < mnGlyphCount; ++i )
2100             mpGlyphs2Chars[ i ] = -1;
2101         for( int nItem = 0; nItem < mnItemCount; ++nItem )
2102         {
2103             // skip invisible items
2104             VisualItem& rVI = mpVisualItems[ nItem ];
2105             if( rVI.IsEmpty() )
2106                 continue;
2107             for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
2108             {
2109                 int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2110                 mpGlyphs2Chars[ j ] = i;
2111             }
2112         }
2113     }
2114 
2115     // remove the dropped glyphs
2116     const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2117     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2118     {
2119         VisualItem& rVI = mpVisualItems[ nItem ];
2120         if( rVI.IsEmpty() )
2121             continue;
2122 
2123         // mark replaced character widths
2124         for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
2125         {
2126             int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
2127             if( mpOutGlyphs[ j ] == cDroppedGlyph )
2128                 mpCharWidths[ i ] = 0;
2129         }
2130 
2131         // handle dropped glyphs at start of visual item
2132         int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
2133         GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
2134         i = nMinGlyphPos;
2135         while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
2136         {
2137             //rVI.mnXOffset += pGlyphWidths[ i ];
2138             rVI.mnMinGlyphPos = ++i;
2139         }
2140 
2141         // when all glyphs in item got dropped mark it as empty
2142         if( i >= nEndGlyphPos )
2143         {
2144             rVI.mnEndGlyphPos = 0;
2145             continue;
2146         }
2147 		// If there are still glyphs in the cluster and mnMinGlyphPos
2148 		// has changed then we need to remove the dropped glyphs at start
2149 		// to correct logClusters, which is unsigned and relative to the
2150 		// item start.
2151 		if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
2152 		{
2153 			// drop any glyphs in the visual item outside the range
2154 			for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
2155 				mpOutGlyphs[ i ] = cDroppedGlyph;
2156 			rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
2157 		}
2158 
2159         // handle dropped glyphs in the middle of visual item
2160         for(; i < nEndGlyphPos; ++i )
2161             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2162                 break;
2163         int j = i;
2164         while( ++i < nEndGlyphPos )
2165         {
2166             if( mpOutGlyphs[ i ] == cDroppedGlyph )
2167                 continue;
2168             mpOutGlyphs[ j ]      = mpOutGlyphs[ i ];
2169             mpGlyphOffsets[ j ]   = mpGlyphOffsets[ i ];
2170             mpVisualAttrs[ j ]    = mpVisualAttrs[ i ];
2171             mpGlyphAdvances[ j ]  = mpGlyphAdvances[ i ];
2172             if( mpJustifications )
2173                 mpJustifications[ j ] = mpJustifications[ i ];
2174             const int k = mpGlyphs2Chars[ i ];
2175             mpGlyphs2Chars[ j ]   = k;
2176             const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
2177             if( k < 0) // extra glyphs are already mapped
2178                 continue;
2179             mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
2180         }
2181 
2182         rVI.mnEndGlyphPos = j;
2183     }
2184 }
2185 
2186 // -----------------------------------------------------------------------
2187 
2188 void UniscribeLayout::DrawText( SalGraphics& ) const
2189 {
2190     HFONT hOrigFont = DisableFontScaling();
2191 
2192     int nBaseClusterOffset = 0;
2193     int nBaseGlyphPos = -1;
2194     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2195     {
2196         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2197 
2198         // skip if there is nothing to display
2199         int nMinGlyphPos, nEndGlyphPos;
2200         if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2201             continue;
2202 
2203         if( nBaseGlyphPos < 0 )
2204         {
2205             // adjust draw position relative to cluster start
2206             if( rVisualItem.IsRTL() )
2207                 nBaseGlyphPos = nEndGlyphPos - 1;
2208             else
2209                 nBaseGlyphPos = nMinGlyphPos;
2210 
2211             const int* pGlyphWidths;
2212             if( mpJustifications )
2213                 pGlyphWidths = mpJustifications;
2214             else
2215                 pGlyphWidths = mpGlyphAdvances;
2216 
2217             int i = mnMinCharPos;
2218             while( (--i >= rVisualItem.mnMinCharPos)
2219                 && (nBaseGlyphPos == mpLogClusters[i]) )
2220                  nBaseClusterOffset += mpCharWidths[i];
2221 
2222             if( !rVisualItem.IsRTL() )
2223                 nBaseClusterOffset = -nBaseClusterOffset;
2224         }
2225 
2226         // now draw the matching glyphs in this item
2227         Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
2228         Point aPos = GetDrawPosition( aRelPos );
2229         SCRIPT_CACHE& rScriptCache = GetScriptCache();
2230         (*pScriptTextOut)( mhDC, &rScriptCache,
2231             aPos.X(), aPos.Y(), 0, NULL,
2232             &rVisualItem.mpScriptItem->a, NULL, 0,
2233             mpOutGlyphs + nMinGlyphPos,
2234             nEndGlyphPos - nMinGlyphPos,
2235             mpGlyphAdvances + nMinGlyphPos,
2236             mpJustifications ? mpJustifications + nMinGlyphPos : NULL,
2237             mpGlyphOffsets + nMinGlyphPos );
2238     }
2239 
2240     if( hOrigFont )
2241         DeleteFont( SelectFont( mhDC, hOrigFont ) );
2242 }
2243 
2244 // -----------------------------------------------------------------------
2245 
2246 long UniscribeLayout::FillDXArray( long* pDXArray ) const
2247 {
2248     // calculate width of the complete layout
2249     long nWidth = mnBaseAdv;
2250     for( int nItem = mnItemCount; --nItem >= 0; )
2251     {
2252         const VisualItem& rVI = mpVisualItems[ nItem ];
2253 
2254         // skip if there is nothing to display
2255         int nMinGlyphPos, nEndGlyphPos;
2256         if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
2257             continue;
2258 
2259         // width = xoffset + width of last item
2260         nWidth = rVI.mnXOffset;
2261         const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
2262         for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2263             nWidth += pGlyphWidths[i];
2264         break;
2265     }
2266 
2267     // copy the virtual char widths into pDXArray[]
2268     if( pDXArray )
2269         for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2270             pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
2271 
2272     return nWidth;
2273 }
2274 
2275 // -----------------------------------------------------------------------
2276 
2277 int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2278 {
2279     long nWidth = 0;
2280     for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
2281     {
2282         nWidth += mpCharWidths[ i ] * nFactor;
2283 
2284         // check if the nMaxWidth still fits the current sub-layout
2285         if( nWidth >= nMaxWidth )
2286         {
2287             // go back to cluster start
2288             // we have to find the visual item first since the mpLogClusters[]
2289             // needed to find the cluster start is relative to to the visual item
2290             int nMinGlyphIndex = 0;
2291             for( int nItem = 0; nItem < mnItemCount; ++nItem )
2292             {
2293                 const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2294                 nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2295                 if( (i >= rVisualItem.mnMinCharPos)
2296                 &&  (i < rVisualItem.mnEndCharPos) )
2297                     break;
2298             }
2299             // now go back to the matching cluster start
2300             do
2301             {
2302                 int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
2303                 if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
2304                     return i;
2305             } while( --i >= mnMinCharPos );
2306 
2307             // if the cluster starts before the start of the visual item
2308             // then set the visual breakpoint before this item
2309             return mnMinCharPos;
2310         }
2311 
2312         // the visual break also depends on the nCharExtra between the characters
2313         nWidth += nCharExtra;
2314     }
2315 
2316     // the whole layout did fit inside the nMaxWidth
2317     return STRING_LEN;
2318 }
2319 
2320 // -----------------------------------------------------------------------
2321 
2322 void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
2323 {
2324     int i;
2325     for( i = 0; i < nMaxIdx; ++i )
2326         pCaretXArray[ i ] = -1;
2327     long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) );
2328     for( i = 0; i <= mnGlyphCount; ++i )
2329         pGlyphPos[ i ] = -1;
2330 
2331     long nXPos = 0;
2332     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2333     {
2334         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2335         if( rVisualItem.IsEmpty() )
2336             continue;
2337 
2338         if (mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK)
2339         {
2340             nXPos = rVisualItem.mnXOffset;
2341         }
2342         // get glyph positions
2343         // TODO: handle when rVisualItem's glyph range is only partially used
2344         for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2345         {
2346             pGlyphPos[ i ] = nXPos;
2347             nXPos += mpGlyphAdvances[ i ];
2348         }
2349         // rightmost position of this visualitem
2350         pGlyphPos[ i ] = nXPos;
2351 
2352         // convert glyph positions to character positions
2353         i = rVisualItem.mnMinCharPos;
2354         if( i < mnMinCharPos )
2355             i = mnMinCharPos;
2356         for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
2357         {
2358             int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
2359             int nCurrIdx = i * 2;
2360             if( !rVisualItem.IsRTL() )
2361             {
2362                 // normal positions for LTR case
2363                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j ];
2364                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
2365             }
2366             else
2367             {
2368                 // reverse positions for RTL case
2369                 pCaretXArray[ nCurrIdx ]   = pGlyphPos[ j+1 ];
2370                 pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
2371             }
2372         }
2373     }
2374 
2375     if (!(mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK))
2376     {
2377         nXPos = 0;
2378         // fixup unknown character positions to neighbor
2379         for( i = 0; i < nMaxIdx; ++i )
2380         {
2381             if( pCaretXArray[ i ] >= 0 )
2382                 nXPos = pCaretXArray[ i ];
2383             else
2384                 pCaretXArray[ i ] = nXPos;
2385         }
2386     }
2387 }
2388 
2389 // -----------------------------------------------------------------------
2390 
2391 void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
2392 {
2393     SalLayout::AdjustLayout( rArgs );
2394 
2395     // adjust positions if requested
2396     if( rArgs.mpDXArray )
2397         ApplyDXArray( rArgs );
2398     else if( rArgs.mnLayoutWidth )
2399         Justify( rArgs.mnLayoutWidth );
2400 }
2401 
2402 // -----------------------------------------------------------------------
2403 
2404 void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
2405 {
2406     const long* pDXArray = rArgs.mpDXArray;
2407 
2408     // increase char widths in string range to desired values
2409     bool bModified = false;
2410     int nOldWidth = 0;
2411     DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
2412     int i,j;
2413     for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
2414     {
2415         int nNewCharWidth = (pDXArray[j] - nOldWidth);
2416         // TODO: nNewCharWidth *= mnUnitsPerPixel;
2417         if( mpCharWidths[i] != nNewCharWidth )
2418         {
2419             mpCharWidths[i] = nNewCharWidth;
2420             bModified = true;
2421         }
2422         nOldWidth = pDXArray[j];
2423     }
2424 
2425     if( !bModified )
2426         return;
2427 
2428     // initialize justifications array
2429     mpJustifications = new int[ mnGlyphCapacity ];
2430     for( i = 0; i < mnGlyphCount; ++i )
2431         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2432 
2433     // apply new widths to script items
2434     long nXOffset = 0;
2435     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2436     {
2437         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2438 
2439         // set the position of this visual item
2440         rVisualItem.mnXOffset = nXOffset;
2441 
2442         // ignore empty visual items
2443         if( rVisualItem.IsEmpty() )
2444         {
2445             for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
2446               nXOffset += mpCharWidths[i];
2447             continue;
2448         }
2449         // ignore irrelevant visual items
2450         if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
2451          || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
2452             continue;
2453 
2454 		// if needed prepare special handling for arabic justification
2455 		rVisualItem.mbHasKashidas = false;
2456 		if( rVisualItem.IsRTL() )
2457         {
2458 			for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2459                 if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 )  //  any Arabic justification
2460                 {                                                        //  excluding SCRIPT_JUSTIFY_NONE
2461                     // yes
2462                     rVisualItem.mbHasKashidas = true;
2463                     // so prepare for kashida handling
2464                     InitKashidaHandling();
2465 					break;
2466 				}
2467 
2468 			if( rVisualItem.HasKashidas() )
2469 				for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
2470 				{
2471                     // TODO: check if we still need this hack after correction of kashida placing?
2472                     // (i87688): apparently yes, we still need it!
2473                     if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
2474                         // usp decided that justification can't be applied here
2475 						// but maybe our Kashida algorithm thinks differently.
2476 						// To avoid trouble (gaps within words, last character of
2477 						// a word gets a Kashida appended) override this.
2478 
2479 						// I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
2480 						// just because this previous hack (which I haven't understand, sorry) used
2481 						// the same value to replace. Don't know if this is really the best
2482 						// thing to do, but it seems to fix things
2483 						mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2484 				}
2485         }
2486 
2487         // convert virtual charwidths to glyph justification values
2488         HRESULT nRC = (*pScriptApplyLogicalWidth)(
2489             mpCharWidths + rVisualItem.mnMinCharPos,
2490             rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
2491             rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2492             mpLogClusters + rVisualItem.mnMinCharPos,
2493             mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2494             mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2495             &rVisualItem.mpScriptItem->a,
2496             &rVisualItem.maABCWidths,
2497             mpJustifications + rVisualItem.mnMinGlyphPos );
2498 
2499         if( nRC != 0 )
2500         {
2501             delete[] mpJustifications;
2502             mpJustifications = NULL;
2503             break;
2504         }
2505 
2506         // to prepare for the next visual item
2507         // update nXOffset to the next items position
2508         // before the mpJustifications[] array gets modified
2509         int nMinGlyphPos, nEndGlyphPos;
2510         if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
2511         {
2512             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2513                 nXOffset += mpJustifications[ i ];
2514 
2515             if( rVisualItem.mbHasKashidas )
2516 				KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
2517         }
2518 
2519 		// workaround needed for older USP versions:
2520         // right align the justification-adjusted glyphs in their cells for RTL-items
2521 		// unless the right alignment is done by inserting kashidas
2522         if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
2523         {
2524             for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2525             {
2526                 const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
2527 				// #i99862# skip diacritics, we mustn't add extra justification to diacritics
2528 				int nIdxAdd = i - 1;
2529 				while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
2530 					--nIdxAdd;
2531                 if( nIdxAdd < nMinGlyphPos )
2532                     rVisualItem.mnXOffset += nXOffsetAdjust;
2533                 else
2534                     mpJustifications[nIdxAdd] += nXOffsetAdjust;
2535                 mpJustifications[i] -= nXOffsetAdjust;
2536             }
2537         }
2538     }
2539 }
2540 
2541 // -----------------------------------------------------------------------
2542 
2543 void UniscribeLayout::InitKashidaHandling()
2544 {
2545 	if( mnMinKashidaGlyph != 0 )	// already initialized
2546 		return;
2547 
2548 	mrWinFontEntry.InitKashidaHandling( mhDC );
2549 	mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
2550 	mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
2551 }
2552 
2553 // adjust the kashida placement matching to the WriterEngine
2554 void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
2555 {
2556 	// workaround needed for all known USP versions:
2557 	// ApplyLogicalWidth does not match ScriptJustify behaviour
2558 	for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
2559 	{
2560 		// check for vowels
2561 		if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
2562 		&&  (1U << mpVisualAttrs[i].uJustification) & 0xFF83 )	// all Arabic justifiction types
2563 		{														// including SCRIPT_JUSTIFY_NONE
2564 			// vowel, we do it like ScriptJustify does
2565 			// the vowel gets the extra width
2566 			long nSpaceAdded =  mpJustifications[ i ] - mpGlyphAdvances[ i ];
2567 			mpJustifications [ i ] = mpGlyphAdvances [ i ];
2568 			mpJustifications [ i - 1 ] += nSpaceAdded;
2569 		}
2570 	}
2571 
2572 	// redistribute the widths for kashidas
2573 	for( int i = nMinGlyphPos; i < nEndGlyphPos; )
2574 		KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
2575 }
2576 
2577 bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
2578 {
2579 	// doing pixel work within a word.
2580 	// sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
2581 
2582 	// find the next kashida
2583 	int nMinPos = *pnCurrentPos;
2584 	int nMaxPos = *pnCurrentPos;
2585 	for( int i = nMaxPos; i < nEndGlyphPos; ++i )
2586 	{
2587 		if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
2588 		&&  (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
2589 			break;
2590 		nMaxPos = i;
2591 	}
2592 	*pnCurrentPos = nMaxPos + 1;
2593 	if( nMinPos == nMaxPos )
2594 		return false;
2595 
2596 	// calculate the available space for an extra kashida
2597 	long nMaxAdded = 0;
2598 	int nKashPos = -1;
2599 	for( int i = nMaxPos; i >= nMinPos; --i )
2600 	{
2601 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2602 		if( nSpaceAdded > nMaxAdded )
2603 		{
2604 			nKashPos = i;
2605 			nMaxAdded = nSpaceAdded;
2606 		}
2607 	}
2608 
2609 	// return early if there is no need for an extra kashida
2610 	if ( nMaxAdded <= 0 )
2611 		return false;
2612 	// return early if there is not enough space for an extra kashida
2613 	if( 2*nMaxAdded < mnMinKashidaWidth )
2614 		return false;
2615 
2616 	// redistribute the extra spacing to the kashida position
2617 	for( int i = nMinPos; i <= nMaxPos; ++i )
2618 	{
2619 		if( i == nKashPos )
2620 			continue;
2621 		// everything else should not have extra spacing
2622 		long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
2623 		if( nSpaceAdded > 0 )
2624 		{
2625 			mpJustifications[ i ] -= nSpaceAdded;
2626 			mpJustifications[ nKashPos ] += nSpaceAdded;
2627 		}
2628 	}
2629 
2630 	// check if we fulfill minimal kashida width
2631 	long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
2632 	if( nSpaceAdded < mnMinKashidaWidth )
2633 	{
2634 		// ugly: steal some pixels
2635 		long nSteal = 1;
2636 		if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
2637 			nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
2638 		for( int i = nMinPos; i <= nMaxPos; ++i )
2639 		{
2640 			if( i == nKashPos )
2641 				continue;
2642 			nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
2643 			if ( nSteal > 0 )
2644 			{
2645 				mpJustifications [ i ] -= nSteal;
2646 				mpJustifications [ nKashPos ] += nSteal;
2647 				nSpaceAdded += nSteal;
2648 			}
2649 			if( nSpaceAdded >= mnMinKashidaWidth )
2650 				return true;
2651 		}
2652 	}
2653 
2654 	// blank padding
2655 	long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
2656 	if( nSpaceMissing > 0 )
2657 	{
2658 		// inner glyph: distribute extra space evenly
2659 		if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
2660 		{
2661 			mpJustifications [ nKashPos ] += nSpaceMissing;
2662 			long nHalfSpace = nSpaceMissing / 2;
2663 			mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
2664 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
2665 		}
2666 		// rightmost: left glyph gets extra space
2667 		else if( nMinPos > nMinGlyphPos )
2668 		{
2669 			mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
2670 			mpJustifications [ nKashPos ] += nSpaceMissing;
2671 		}
2672 		// leftmost: right glyph gets extra space
2673 		else if( nMaxPos < nEndGlyphPos - 1 )
2674 		{
2675 			mpJustifications [ nKashPos ] += nSpaceMissing;
2676 			mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
2677 		}
2678 		else
2679 			return false;
2680 	}
2681 
2682 	return true;
2683 }
2684 
2685 // -----------------------------------------------------------------------
2686 
2687 void UniscribeLayout::Justify( long nNewWidth )
2688 {
2689     long nOldWidth = 0;
2690     int i;
2691     for( i = mnMinCharPos; i < mnEndCharPos; ++i )
2692         nOldWidth += mpCharWidths[ i ];
2693 	if( nOldWidth <= 0 )
2694 		return;
2695 
2696     nNewWidth *= mnUnitsPerPixel;	// convert into font units
2697     if( nNewWidth == nOldWidth )
2698         return;
2699     // prepare to distribute the extra width evenly among the visual items
2700     const double fStretch = (double)nNewWidth / nOldWidth;
2701 
2702     // initialize justifications array
2703     mpJustifications = new int[ mnGlyphCapacity ];
2704     for( i = 0; i < mnGlyphCapacity; ++i )
2705         mpJustifications[ i ] = mpGlyphAdvances[ i ];
2706 
2707     // justify stretched script items
2708     long nXOffset = 0;
2709     SCRIPT_CACHE& rScriptCache = GetScriptCache();
2710     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2711     {
2712         VisualItem& rVisualItem = mpVisualItems[ nItem ];
2713         if( rVisualItem.IsEmpty() )
2714             continue;
2715 
2716         if( (rVisualItem.mnMinCharPos < mnEndCharPos)
2717          && (rVisualItem.mnEndCharPos > mnMinCharPos) )
2718         {
2719             long nItemWidth = 0;
2720             for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
2721                 nItemWidth += mpCharWidths[ i ];
2722             nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
2723 
2724             HRESULT nRC = (*pScriptJustify) (
2725                 mpVisualAttrs + rVisualItem.mnMinGlyphPos,
2726                 mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
2727                 rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
2728                 nItemWidth,
2729                 mnMinKashidaWidth,
2730                 mpJustifications + rVisualItem.mnMinGlyphPos );
2731 
2732             rVisualItem.mnXOffset = nXOffset;
2733             nXOffset += nItemWidth;
2734         }
2735     }
2736 }
2737 
2738 // -----------------------------------------------------------------------
2739 
2740 bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
2741 {
2742 	// we have to find the visual item first since the mpLogClusters[]
2743     // needed to find the cluster start is relative to to the visual item
2744     int nMinGlyphIndex = -1;
2745     for( int nItem = 0; nItem < mnItemCount; ++nItem )
2746     {
2747         const VisualItem& rVisualItem = mpVisualItems[ nItem ];
2748         if( (nCharPos >= rVisualItem.mnMinCharPos)
2749         &&  (nCharPos < rVisualItem.mnEndCharPos) )
2750 		{
2751 			nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
2752             break;
2753 		}
2754     }
2755 	// Invalid char pos or leftmost glyph in visual item
2756     if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
2757 		return false;
2758 
2759 //	This test didn't give the expected results
2760 /*	if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
2761 	// two chars, one glyph
2762 		return false;*/
2763 
2764 	const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
2765 	if( nGlyphPos <= 0 )
2766 		return true;
2767 	// justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
2768 	// and not SCRIPT_JUSTIFY_ARABIC_BLANK
2769 	// special case: glyph to the left is vowel (no advance width)
2770 	if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
2771 		|| ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
2772 			&& mpGlyphAdvances [ nGlyphPos-1 ] ))
2773 		return false;
2774 	return true;
2775 }
2776 
2777 #endif // USE_UNISCRIBE
2778 
2779 #ifdef ENABLE_GRAPHITE
2780 
2781 class GraphiteLayoutWinImpl : public GraphiteLayout
2782 {
2783 public:
2784     GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
2785         throw()
2786     : GraphiteLayout(font), mrFont(rFont) {};
2787     virtual ~GraphiteLayoutWinImpl() throw() {};
2788     virtual sal_GlyphId getKashidaGlyph(int & rWidth);
2789 private:
2790     ImplWinFontEntry & mrFont;
2791 };
2792 
2793 sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
2794 {
2795     rWidth = mrFont.GetMinKashidaWidth();
2796     return mrFont.GetMinKashidaGlyph();
2797 }
2798 
2799 // This class uses the SIL Graphite engine to provide complex text layout services to the VCL
2800 // @author tse
2801 //
2802 class GraphiteWinLayout : public WinLayout
2803 {
2804 private:
2805     mutable GraphiteWinFont mpFont;
2806     grutils::GrFeatureParser * mpFeatures;
2807     mutable GraphiteLayoutWinImpl maImpl;
2808 public:
2809     GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw();
2810 
2811     static bool IsGraphiteEnabledFont(HDC hDC) throw();
2812 
2813     // used by upper layers
2814     virtual bool  LayoutText( ImplLayoutArgs& );    // first step of layout
2815     virtual void  AdjustLayout( ImplLayoutArgs& );  // adjusting after fallback etc.
2816     //  virtual void  InitFont() const;
2817     virtual void  DrawText( SalGraphics& ) const;
2818 
2819     // methods using string indexing
2820     virtual int   GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
2821     virtual long  FillDXArray( long* pDXArray ) const;
2822 
2823     virtual void  GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
2824 
2825     // methods using glyph indexing
2826     virtual int   GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
2827                       long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
2828 
2829     // used by glyph+font+script fallback
2830     virtual void    MoveGlyph( int nStart, long nNewXPos );
2831     virtual void    DropGlyph( int nStart );
2832     virtual void    Simplify( bool bIsBase );
2833     ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
2834 protected:
2835     virtual void    ReplaceDC(gr::Segment & segment) const;
2836     virtual void    RestoreDC(gr::Segment & segment) const;
2837 };
2838 
2839 bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
2840 {
2841   return gr::WinFont::FontHasGraphiteTables(hDC);
2842 }
2843 
2844 GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
2845   : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
2846     maImpl(mpFont, rWFE)
2847 {
2848     const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
2849     rtl::OString name = rtl::OUStringToOString(
2850         rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
2851     sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
2852     if (nFeat > 0)
2853     {
2854         rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
2855         mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
2856     }
2857     else
2858     {
2859         mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
2860     }
2861     maImpl.SetFeatures(mpFeatures);
2862 }
2863 
2864 void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
2865 {
2866     COLORREF color = GetTextColor(mhDC);
2867     dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
2868     SetTextColor(mhDC, color);
2869 }
2870 
2871 void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
2872 {
2873     dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
2874 }
2875 
2876 bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
2877 {
2878     if (args.mnMinCharPos >= args.mnEndCharPos)
2879     {
2880         maImpl.clear();
2881         return true;
2882     }
2883     HFONT hUnRotatedFont;
2884     if (args.mnOrientation)
2885     {
2886         // Graphite gets very confused if the font is rotated
2887         LOGFONTW aLogFont;
2888         ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
2889         aLogFont.lfEscapement = 0;
2890         aLogFont.lfOrientation = 0;
2891         hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
2892         ::SelectFont(mhDC, hUnRotatedFont);
2893     }
2894     WinLayout::AdjustLayout(args);
2895     mpFont.replaceDC(mhDC);
2896     maImpl.SetFontScale(WinLayout::mfFontScale);
2897     //bool succeeded = maImpl.LayoutText(args);
2898 #ifdef GRCACHE
2899     GrSegRecord * pSegRecord = NULL;
2900     gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
2901 #else
2902     gr::Segment * pSegment = maImpl.CreateSegment(args);
2903 #endif
2904     bool bSucceeded = false;
2905     if (pSegment)
2906     {
2907         // replace the DC on the font within the segment
2908         ReplaceDC(*pSegment);
2909         // create glyph vectors
2910 #ifdef GRCACHE
2911         bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
2912 #else
2913         bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
2914 #endif
2915         // restore original DC
2916         RestoreDC(*pSegment);
2917 #ifdef GRCACHE
2918         if (pSegRecord) pSegRecord->unlock();
2919         else delete pSegment;
2920 #else
2921         delete pSegment;
2922 #endif
2923     }
2924     mpFont.restoreDC();
2925     if (args.mnOrientation)
2926     {
2927         // restore the rotated font
2928         ::SelectFont(mhDC, mhFont);
2929         ::DeleteObject(hUnRotatedFont);
2930     }
2931     return bSucceeded;
2932 }
2933 
2934 void  GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
2935 {
2936     WinLayout::AdjustLayout(rArgs);
2937     maImpl.DrawBase() = WinLayout::maDrawBase;
2938     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2939     if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
2940     {
2941         mrWinFontEntry.InitKashidaHandling(mhDC);
2942     }
2943     maImpl.AdjustLayout(rArgs);
2944 }
2945 
2946 void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
2947 {
2948     HFONT hOrigFont = DisableFontScaling();
2949     const HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).getHDC();
2950     maImpl.DrawBase() = WinLayout::maDrawBase;
2951     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2952     const int MAX_GLYPHS = 2;
2953     sal_GlyphId glyphIntStr[MAX_GLYPHS];
2954     WORD glyphWStr[MAX_GLYPHS];
2955     int glyphIndex = 0;
2956     Point aPos(0,0);
2957     int nGlyphs = 0;
2958     do
2959     {
2960         nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
2961         if (nGlyphs < 1)
2962           break;
2963         std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
2964         ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
2965 		              NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
2966     } while (nGlyphs);
2967     if( hOrigFont )
2968           DeleteFont( SelectFont( aHDC, hOrigFont ) );
2969 }
2970 
2971 int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
2972 {
2973     mpFont.replaceDC(mhDC);
2974     int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
2975     mpFont.restoreDC();
2976     return nBreak;
2977 }
2978 
2979 long  GraphiteWinLayout::FillDXArray( long* pDXArray ) const
2980 {
2981     return maImpl.FillDXArray(pDXArray);
2982 }
2983 
2984 void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
2985 {
2986 	maImpl.GetCaretPositions(nArraySize, pCaretXArray);
2987 }
2988 
2989 int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
2990         ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
2991 {
2992     maImpl.DrawBase() = WinLayout::maDrawBase;
2993     maImpl.DrawOffset() = WinLayout::maDrawOffset;
2994     return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
2995 }
2996 
2997 void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
2998 {
2999 	maImpl.MoveGlyph(glyph_idx, new_x_pos);
3000 }
3001 
3002 void GraphiteWinLayout::DropGlyph( int glyph_idx )
3003 {
3004 	maImpl.DropGlyph(glyph_idx);
3005 }
3006 
3007 void GraphiteWinLayout::Simplify( bool is_base )
3008 {
3009 	maImpl.Simplify(is_base);
3010 }
3011 #endif // ENABLE_GRAPHITE
3012 // =======================================================================
3013 
3014 SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
3015 {
3016     DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
3017 
3018 	WinLayout* pWinLayout = NULL;
3019 
3020     const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ];
3021     ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
3022 
3023 #if defined( USE_UNISCRIBE )
3024     if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
3025     &&   (aUspModule || (bUspEnabled && InitUSP())) )   // CTL layout engine
3026     {
3027 #ifdef ENABLE_GRAPHITE
3028         if (rFontFace.SupportsGraphite())
3029             pWinLayout = new GraphiteWinLayout( getHDC(), rFontFace, rFontInstance);
3030         else
3031 #endif // ENABLE_GRAPHITE
3032         // script complexity is determined in upper layers
3033         pWinLayout = new UniscribeLayout( getHDC(), rFontFace, rFontInstance );
3034         // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
3035         // the created UniscribeLayout, otherwise the data passed into the
3036         // constructor might become invalid too early
3037     }
3038     else
3039 #endif // USE_UNISCRIBE
3040     {
3041 #ifdef GCP_KERN_HACK
3042         if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
3043         {
3044             // TODO: directly cache kerning info in the rFontInstance
3045             // TODO: get rid of kerning methods+data in WinSalGraphics object
3046             GetKernPairs( 0, NULL );
3047             rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
3048         }
3049 #endif // GCP_KERN_HACK
3050 
3051         BYTE eCharSet = ANSI_CHARSET;
3052         if( mpLogFont )
3053             eCharSet = mpLogFont->lfCharSet;
3054 #ifdef ENABLE_GRAPHITE
3055         if (rFontFace.SupportsGraphite())
3056             pWinLayout = new GraphiteWinLayout( getHDC(), rFontFace, rFontInstance);
3057         else
3058 #endif // ENABLE_GRAPHITE
3059             pWinLayout = new SimpleWinLayout( getHDC(), eCharSet, rFontFace, rFontInstance );
3060     }
3061 
3062     if( mfFontScale != 1.0 )
3063         pWinLayout->SetFontScale( mfFontScale );
3064 
3065     return pWinLayout;
3066 }
3067 
3068 // -----------------------------------------------------------------------
3069 
3070 int	WinSalGraphics::GetMinKashidaWidth()
3071 {
3072 	if( !mpWinFontEntry[0] )
3073 		return 0;
3074 	mpWinFontEntry[0]->InitKashidaHandling( getHDC() );
3075 	int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
3076 	return nMinKashida;
3077 }
3078 
3079 // =======================================================================
3080 
3081 ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
3082 :   ImplFontEntry( rFSD )
3083 ,   maWidthMap( 512 )
3084 ,   mpKerningPairs( NULL )
3085 ,   mnKerningPairs( -1 )
3086 ,	mnMinKashidaWidth( -1 )
3087 ,	mnMinKashidaGlyph( -1 )
3088 {
3089 #ifdef USE_UNISCRIBE
3090     maScriptCache = NULL;
3091 #endif // USE_UNISCRIBE
3092 }
3093 
3094 // -----------------------------------------------------------------------
3095 
3096 ImplWinFontEntry::~ImplWinFontEntry()
3097 {
3098 #ifdef USE_UNISCRIBE
3099     if( maScriptCache != NULL )
3100         (*pScriptFreeCache)( &maScriptCache );
3101 #endif // USE_UNISCRIBE
3102 #ifdef GCP_KERN_HACK
3103     delete[] mpKerningPairs;
3104 #endif // GCP_KERN_HACK
3105 }
3106 
3107 // -----------------------------------------------------------------------
3108 
3109 bool ImplWinFontEntry::HasKernData() const
3110 {
3111     return (mnKerningPairs >= 0);
3112 }
3113 
3114 // -----------------------------------------------------------------------
3115 
3116 void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
3117 {
3118     mnKerningPairs = nPairCount;
3119     mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
3120     ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) );
3121 }
3122 
3123 // -----------------------------------------------------------------------
3124 
3125 int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
3126 {
3127     int nKernAmount = 0;
3128     if( mpKerningPairs )
3129     {
3130         const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
3131         const KERNINGPAIR* pFirstPair = mpKerningPairs;
3132         const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
3133         const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
3134             pEndPair, aRefPair, ImplCmpKernData );
3135         if( (pPair != pEndPair)
3136         &&  (pPair->wFirst == aRefPair.wFirst)
3137         &&  (pPair->wSecond == aRefPair.wSecond) )
3138             nKernAmount = pPair->iKernAmount;
3139     }
3140 
3141     return nKernAmount;
3142 }
3143 
3144 // -----------------------------------------------------------------------
3145 
3146 bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
3147 {
3148 	if( mnMinKashidaWidth >= 0 )	// already cached?
3149 		return mnMinKashidaWidth;
3150 
3151 	// initialize the kashida width
3152 	mnMinKashidaWidth = 0;
3153 	mnMinKashidaGlyph = 0;
3154 #ifdef USE_UNISCRIBE
3155 	if (aUspModule || (bUspEnabled && InitUSP()))
3156 	{
3157 		SCRIPT_FONTPROPERTIES aFontProperties;
3158 		aFontProperties.cBytes = sizeof (aFontProperties);
3159 		SCRIPT_CACHE& rScriptCache = GetScriptCache();
3160 		HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
3161 		if( nRC != 0 )
3162 			return false;
3163 		mnMinKashidaWidth = aFontProperties.iKashidaWidth;
3164 		mnMinKashidaGlyph = aFontProperties.wgKashida;
3165     }
3166 #endif // USE_UNISCRIBE
3167 
3168 	return true;
3169 }
3170 
3171 // =======================================================================
3172 
3173 ImplFontData* ImplWinFontData::Clone() const
3174 {
3175     if( mpUnicodeMap )
3176         mpUnicodeMap->AddReference();
3177     ImplFontData* pClone = new ImplWinFontData( *this );
3178     return pClone;
3179 }
3180 
3181 // -----------------------------------------------------------------------
3182 
3183 ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
3184 {
3185     ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD );
3186     return pEntry;
3187 }
3188 
3189 // =======================================================================
3190