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