1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: winlayout.cxx,v $
10 * $Revision: 1.113.6.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "tools/svwin.h"
37 #include "saldata.hxx"
38 // for GetMirroredChar
41 #include "vcl/sallayout.hxx"
42 #include "vcl/svapp.hxx"
44 #include "rtl/ustring.hxx"
46 #include "osl/module.h"
53 #define alloca _alloca
58 #endif // GCP_KERN_HACK
66 #endif // USE_UNISCRIBE
71 typedef std::hash_map
<int,int> IntMap
;
72 typedef std::set
<int> IntSet
;
75 #ifdef ENABLE_GRAPHITE
76 #include <i18npool/mslangid.hxx>
77 #include <graphite/GrClient.h>
78 #include <graphite/WinFont.h>
79 #include <graphite/Segment.h>
80 #include <vcl/graphite_layout.hxx>
81 #include <vcl/graphite_cache.hxx>
82 #include <vcl/graphite_features.hxx>
85 #define DROPPED_OUTGLYPH 0xFFFF
89 // =======================================================================
91 // win32 specific physical font instance
92 class ImplWinFontEntry
: public ImplFontEntry
95 ImplWinFontEntry( ImplFontSelectData
& );
99 // TODO: also add HFONT??? Watch out for issues with too many active fonts...
103 bool HasKernData() const;
104 void SetKernData( int, const KERNINGPAIR
* );
105 int GetKerning( sal_Unicode
, sal_Unicode
) const;
107 KERNINGPAIR
* mpKerningPairs
;
109 #endif // GCP_KERN_HACK
113 SCRIPT_CACHE
& GetScriptCache() const
114 { return maScriptCache
; }
116 mutable SCRIPT_CACHE maScriptCache
;
117 #endif // USE_UNISCRIBE
120 int GetCachedGlyphWidth( int nCharCode
) const;
121 void CacheGlyphWidth( int nCharCode
, int nCharWidth
);
123 bool InitKashidaHandling( HDC
);
124 int GetMinKashidaWidth() const { return mnMinKashidaWidth
; }
125 int GetMinKashidaGlyph() const { return mnMinKashidaGlyph
; }
129 mutable int mnMinKashidaWidth
;
130 mutable int mnMinKashidaGlyph
;
133 // -----------------------------------------------------------------------
135 inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode
, int nCharWidth
)
137 maWidthMap
[ nCharCode
] = nCharWidth
;
140 inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode
) const
142 IntMap::const_iterator it
= maWidthMap
.find( nCharCode
);
143 if( it
== maWidthMap
.end() )
148 // =======================================================================
150 class WinLayout
: public SalLayout
153 WinLayout( HDC
, const ImplWinFontData
&, ImplWinFontEntry
& );
154 virtual void InitFont() const;
155 void SetFontScale( float f
) { mfFontScale
= f
; }
156 float GetFontScale() const { return mfFontScale
; }
157 HFONT
DisableFontScaling( void) const;
160 SCRIPT_CACHE
& GetScriptCache() const
161 { return mrWinFontEntry
.GetScriptCache(); }
162 #endif // USE_UNISCRIBE
165 HDC mhDC
; // WIN32 device handle
166 HFONT mhFont
; // WIN32 font handle
167 int mnBaseAdv
; // x-offset relative to Layout origin
168 float mfFontScale
; // allows metrics emulation of huge font sizes
170 const ImplWinFontData
& mrWinFontData
;
171 ImplWinFontEntry
& mrWinFontEntry
;
174 // =======================================================================
176 class SimpleWinLayout
: public WinLayout
179 SimpleWinLayout( HDC
, BYTE nCharSet
, const ImplWinFontData
&, ImplWinFontEntry
& );
180 virtual ~SimpleWinLayout();
182 virtual bool LayoutText( ImplLayoutArgs
& );
183 virtual void AdjustLayout( ImplLayoutArgs
& );
184 virtual void DrawText( SalGraphics
& ) const;
186 virtual int GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int&,
187 sal_Int32
* pGlyphAdvances
, int* pCharIndexes
) const;
189 virtual long FillDXArray( long* pDXArray
) const;
190 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const;
191 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
193 // for glyph+font+script fallback
194 virtual void MoveGlyph( int nStart
, long nNewXPos
);
195 virtual void DropGlyph( int nStart
);
196 virtual void Simplify( bool bIsBase
);
199 void Justify( long nNewWidth
);
200 void ApplyDXArray( const ImplLayoutArgs
& );
206 int* mpGlyphAdvances
; // if possible this is shared with mpGlyphAdvances[]
207 int* mpGlyphOrigAdvs
;
208 int* mpCharWidths
; // map rel char pos to char width
209 int* mpChars2Glyphs
; // map rel char pos to abs glyph pos
210 int* mpGlyphs2Chars
; // map abs glyph pos to abs char pos
211 bool* mpGlyphRTLFlags
; // BiDi status for glyphs: true=>RTL
212 mutable long mnWidth
;
213 bool mbDisableGlyphs
;
219 // =======================================================================
221 WinLayout::WinLayout( HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
)
223 mhFont( (HFONT
)::GetCurrentObject(hDC
,OBJ_FONT
) ),
226 mrWinFontData( rWFD
),
227 mrWinFontEntry( rWFE
)
230 // -----------------------------------------------------------------------
232 void WinLayout::InitFont() const
234 ::SelectObject( mhDC
, mhFont
);
237 // -----------------------------------------------------------------------
239 // Using reasonably sized fonts to emulate huge fonts works around
240 // a lot of problems in printer and display drivers. Huge fonts are
241 // mostly used by high resolution reference devices which are never
242 // painted to anyway. In the rare case that a huge font needs to be
243 // displayed somewhere then the workaround doesn't help anymore.
244 // If the drivers fail silently for huge fonts, so be it...
245 HFONT
WinLayout::DisableFontScaling() const
247 if( mfFontScale
== 1.0 )
251 if( aSalShlData
.mbWNT
)
254 ::GetObjectW( mhFont
, sizeof(LOGFONTW
), &aLogFont
);
255 aLogFont
.lfHeight
= (LONG
)(mfFontScale
* aLogFont
.lfHeight
);
256 aLogFont
.lfWidth
= (LONG
)(mfFontScale
* aLogFont
.lfWidth
);
257 hHugeFont
= ::CreateFontIndirectW( &aLogFont
);
262 ::GetObjectA( mhFont
, sizeof(LOGFONTA
), &aLogFont
);
263 aLogFont
.lfHeight
= (LONG
)(mfFontScale
* aLogFont
.lfHeight
);
264 aLogFont
.lfWidth
= (LONG
)(mfFontScale
* aLogFont
.lfWidth
);
265 hHugeFont
= ::CreateFontIndirectA( &aLogFont
);
271 return SelectFont( mhDC
, hHugeFont
);
274 // =======================================================================
276 SimpleWinLayout::SimpleWinLayout( HDC hDC
, BYTE nCharSet
,
277 const ImplWinFontData
& rWinFontData
, ImplWinFontEntry
& rWinFontEntry
)
278 : WinLayout( hDC
, rWinFontData
, rWinFontEntry
),
282 mpGlyphAdvances( NULL
),
283 mpGlyphOrigAdvs( NULL
),
284 mpCharWidths( NULL
),
285 mpChars2Glyphs( NULL
),
286 mpGlyphs2Chars( NULL
),
287 mpGlyphRTLFlags( NULL
),
290 mnCharSet( nCharSet
),
291 mbDisableGlyphs( false )
293 mbDisableGlyphs
= true;
296 // -----------------------------------------------------------------------
298 SimpleWinLayout::~SimpleWinLayout()
300 delete[] mpGlyphRTLFlags
;
301 delete[] mpGlyphs2Chars
;
302 delete[] mpChars2Glyphs
;
303 if( mpCharWidths
!= mpGlyphAdvances
)
304 delete[] mpCharWidths
;
305 delete[] mpGlyphOrigAdvs
;
306 delete[] mpGlyphAdvances
;
307 delete[] mpOutGlyphs
;
310 // -----------------------------------------------------------------------
312 bool SimpleWinLayout::LayoutText( ImplLayoutArgs
& rArgs
)
315 // TODO: fix case when recyclying old SimpleWinLayout object
316 mbDisableGlyphs
|= ((rArgs
.mnFlags
& SAL_LAYOUT_DISABLE_GLYPH_PROCESSING
) != 0);
317 mnCharCount
= rArgs
.mnEndCharPos
- rArgs
.mnMinCharPos
;
319 if( !mbDisableGlyphs
)
321 // Win32 glyph APIs have serious problems with vertical layout
322 // => workaround is to use the unicode methods then
323 if( rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
)
324 mbDisableGlyphs
= true;
326 // use cached value from font face
327 mbDisableGlyphs
= mrWinFontData
.IsGlyphApiDisabled();
330 // TODO: use a cached value for bDisableAsianKern from upper layers
331 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
333 TEXTMETRICA aTextMetricA
;
334 if( ::GetTextMetricsA( mhDC
, &aTextMetricA
)
335 && !(aTextMetricA
.tmPitchAndFamily
& TMPF_FIXED_PITCH
) && !(aTextMetricA
.tmCharSet
== 0x86) )
336 rArgs
.mnFlags
&= ~SAL_LAYOUT_KERNING_ASIAN
;
343 bool bVertical
= (rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
) != 0;
345 // count the number of chars to process if no RTL run
347 bool bHasRTL
= false;
348 while( rArgs
.GetNextRun( &i
, &j
, &bHasRTL
) && !bHasRTL
)
349 mnGlyphCount
+= j
- i
;
351 // if there are RTL runs we need room to remember individual BiDi flags
354 mpGlyphRTLFlags
= new bool[ mnCharCount
];
355 for( i
= 0; i
< mnCharCount
; ++i
)
356 mpGlyphRTLFlags
[i
] = false;
359 // rewrite the logical string if needed to prepare for the API calls
360 const sal_Unicode
* pBidiStr
= rArgs
.mpStr
+ rArgs
.mnMinCharPos
;
361 if( (mnGlyphCount
!= mnCharCount
) || bVertical
)
363 // we need to rewrite the pBidiStr when any of
364 // - BiDirectional layout
366 // - partial runs (e.g. with control chars or for glyph fallback)
368 sal_Unicode
* pRewrittenStr
= (sal_Unicode
*)alloca( mnCharCount
* sizeof(sal_Unicode
) );
369 pBidiStr
= pRewrittenStr
;
371 // note: glyph to char mapping is relative to first character
372 mpChars2Glyphs
= new int[ mnCharCount
];
373 mpGlyphs2Chars
= new int[ mnCharCount
];
374 for( i
= 0; i
< mnCharCount
; ++i
)
375 mpChars2Glyphs
[i
] = mpGlyphs2Chars
[i
] = -1;
380 while( rArgs
.GetNextRun( &i
, &j
, &bIsRTL
) )
384 // get the next leftmost character in this run
385 int nCharPos
= bIsRTL
? --j
: i
++;
386 sal_UCS4 cChar
= rArgs
.mpStr
[ nCharPos
];
388 // in the RTL case mirror the character and remember its RTL status
391 cChar
= ::GetMirroredChar( cChar
);
392 mpGlyphRTLFlags
[ mnGlyphCount
] = true;
395 // for vertical writing use vertical alternatives
398 sal_UCS4 cVert
= ::GetVerticalChar( cChar
);
403 // rewrite the original string
404 // update the mappings between original and rewritten string
405 // TODO: support surrogates in rewritten strings
406 pRewrittenStr
[ mnGlyphCount
] = static_cast<sal_Unicode
>(cChar
);
407 mpGlyphs2Chars
[ mnGlyphCount
] = nCharPos
;
408 mpChars2Glyphs
[ nCharPos
- rArgs
.mnMinCharPos
] = mnGlyphCount
;
414 mpOutGlyphs
= new WCHAR
[ mnGlyphCount
];
415 mpGlyphAdvances
= new int[ mnGlyphCount
];
417 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_PAIRS
| SAL_LAYOUT_KERNING_ASIAN
) )
418 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
420 #ifndef GCP_KERN_HACK
421 DWORD nGcpOption
= 0;
422 // enable kerning if requested
423 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
424 nGcpOption
|= GCP_USEKERNING
;
425 #endif // GCP_KERN_HACK
427 for( i
= 0; i
< mnGlyphCount
; ++i
)
428 mpOutGlyphs
[i
] = pBidiStr
[ i
];
430 for( i
= 0; i
< mnGlyphCount
; ++i
)
432 // get the current UCS-4 code point, check for surrogate pairs
433 const WCHAR
* pCodes
= reinterpret_cast<LPCWSTR
>(&pBidiStr
[i
]);
434 unsigned nCharCode
= pCodes
[0];
435 bool bSurrogate
= ((nCharCode
>= 0xD800) && (nCharCode
<= 0xDFFF));
438 if( nCharCode
>= 0xDC00 ) // this part of a surrogate pair was already processed
440 nCharCode
= 0x10000 + ((pCodes
[0] - 0xD800) << 10) + (pCodes
[1] - 0xDC00);
443 // get the advance width for the current UCS-4 code point
444 int nGlyphWidth
= mrWinFontEntry
.GetCachedGlyphWidth( nCharCode
);
445 if( nGlyphWidth
== -1 )
449 if( ::GetTextExtentPoint32W( mhDC
, &pCodes
[0], bSurrogate
? 2 : 1, &aExtent
) )
450 nGlyphWidth
= aExtent
.cx
;
451 else if( ::GetCharABCWidthsW( mhDC
, nCharCode
, nCharCode
, &aABC
) )
452 nGlyphWidth
= aABC
.abcA
+ aABC
.abcB
+ aABC
.abcC
;
453 else if( !::GetCharWidth32W( mhDC
, nCharCode
, nCharCode
, &nGlyphWidth
)
454 && !::GetCharWidthW( mhDC
, nCharCode
, nCharCode
, &nGlyphWidth
) )
456 mrWinFontEntry
.CacheGlyphWidth( nCharCode
, nGlyphWidth
);
458 mpGlyphAdvances
[ i
] = nGlyphWidth
;
459 mnWidth
+= nGlyphWidth
;
461 // remaining codes of surrogate pair get a zero width
462 if( bSurrogate
&& ((i
+1) < mnGlyphCount
) )
463 mpGlyphAdvances
[ i
+1 ] = 0;
465 // check with the font face if glyph fallback is needed
466 if( mrWinFontData
.HasChar( nCharCode
) )
469 // request glyph fallback at this position in the string
470 bool bRTL
= mpGlyphRTLFlags
? mpGlyphRTLFlags
[i
] : false;
471 int nCharPos
= mpGlyphs2Chars
? mpGlyphs2Chars
[i
]: i
+ rArgs
.mnMinCharPos
;
472 rArgs
.NeedFallback( nCharPos
, bRTL
);
473 if( bSurrogate
&& ((nCharPos
+1) < rArgs
.mnLength
) )
474 rArgs
.NeedFallback( nCharPos
+1, bRTL
);
476 // replace the current glyph shape with the NotDef glyph shape
477 if( rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
)
479 // when we already are layouting for glyph fallback
480 // then a new unresolved glyph is not interesting
482 mpOutGlyphs
[i
] = DROPPED_OUTGLYPH
;
486 if( mnNotdefWidth
< 0 )
488 // get the width of the NotDef glyph
490 WCHAR cNotDef
= rArgs
.mpStr
[ nCharPos
];
492 if( ::GetTextExtentPoint32W( mhDC
, &cNotDef
, 1, &aExtent
) )
493 mnNotdefWidth
= aExtent
.cx
;
495 // use a better NotDef glyph
496 if( !mbDisableGlyphs
&& !bSurrogate
)
499 if( bSurrogate
&& ((i
+1) < mnGlyphCount
) )
500 mpOutGlyphs
[i
+1] = DROPPED_OUTGLYPH
;
502 // adjust the current glyph width to the NotDef glyph width
503 mnWidth
+= mnNotdefWidth
- mpGlyphAdvances
[i
];
504 mpGlyphAdvances
[i
] = mnNotdefWidth
;
505 if( mpGlyphOrigAdvs
)
506 mpGlyphOrigAdvs
[i
] = mnNotdefWidth
;
510 // apply kerning if the layout engine has not yet done it
511 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_ASIAN
|SAL_LAYOUT_KERNING_PAIRS
) )
513 #else // GCP_KERN_HACK
514 // apply just asian kerning
515 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
517 if( !(rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) )
518 #endif // GCP_KERN_HACK
519 for( i
= 0; i
< mnGlyphCount
; ++i
)
520 mpGlyphOrigAdvs
[i
] = mpGlyphAdvances
[i
];
522 // #99658# also apply asian kerning on the substring border
523 int nLen
= mnGlyphCount
;
524 if( rArgs
.mnMinCharPos
+ nLen
< rArgs
.mnLength
)
526 for( i
= 1; i
< nLen
; ++i
)
529 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
531 int nKernAmount
= mrWinFontEntry
.GetKerning( pBidiStr
[i
-1], pBidiStr
[i
] );
532 mpGlyphAdvances
[ i
-1 ] += nKernAmount
;
533 mnWidth
+= nKernAmount
;
535 else if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
536 #endif // GCP_KERN_HACK
538 if( ( (0x3000 == (0xFF00 & pBidiStr
[i
-1])) || (0x2010 == (0xFFF0 & pBidiStr
[i
-1])) || (0xFF00 == (0xFF00 & pBidiStr
[i
-1])))
539 && ( (0x3000 == (0xFF00 & pBidiStr
[i
])) || (0x2010 == (0xFFF0 & pBidiStr
[i
])) || (0xFF00 == (0xFF00 & pBidiStr
[i
])) ) )
541 long nKernFirst
= +CalcAsianKerning( pBidiStr
[i
-1], true, bVertical
);
542 long nKernNext
= -CalcAsianKerning( pBidiStr
[i
], false, bVertical
);
544 long nDelta
= (nKernFirst
< nKernNext
) ? nKernFirst
: nKernNext
;
545 if( nDelta
<0 && nKernFirst
!=0 && nKernNext
!=0 )
547 nDelta
= (nDelta
* mpGlyphAdvances
[i
-1] + 2) / 4;
548 mpGlyphAdvances
[i
-1] += nDelta
;
555 // calculate virtual char widths
556 if( !mpGlyphs2Chars
)
557 mpCharWidths
= mpGlyphAdvances
;
560 mpCharWidths
= new int[ mnCharCount
];
561 for( i
= 0; i
< mnCharCount
; ++i
)
562 mpCharWidths
[ i
] = 0;
563 for( i
= 0; i
< mnGlyphCount
; ++i
)
565 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
567 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
571 // scale layout metrics if needed
572 // TODO: does it make the code more simple if the metric scaling
573 // is moved to the methods that need metric scaling (e.g. FillDXArray())?
574 if( mfFontScale
!= 1.0 )
576 mnWidth
= (long)(mnWidth
* mfFontScale
);
577 mnBaseAdv
= (int)(mnBaseAdv
* mfFontScale
);
578 for( i
= 0; i
< mnCharCount
; ++i
)
579 mpCharWidths
[i
] = (int)(mpCharWidths
[i
] * mfFontScale
);
580 if( mpGlyphAdvances
!= mpCharWidths
)
581 for( i
= 0; i
< mnGlyphCount
; ++i
)
582 mpGlyphAdvances
[i
] = (int)(mpGlyphAdvances
[i
] * mfFontScale
);
583 if( mpGlyphOrigAdvs
&& (mpGlyphOrigAdvs
!= mpGlyphAdvances
) )
584 for( i
= 0; i
< mnGlyphCount
; ++i
)
585 mpGlyphOrigAdvs
[i
] = (int)(mpGlyphOrigAdvs
[i
] * mfFontScale
);
591 // -----------------------------------------------------------------------
593 int SimpleWinLayout::GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int& nStart
,
594 long* pGlyphAdvances
, int* pCharIndexes
) const
596 // return zero if no more glyph found
597 if( nStart
>= mnGlyphCount
)
600 // calculate glyph position relative to layout base
601 // TODO: avoid for nStart!=0 case by reusing rPos
602 long nXOffset
= mnBaseAdv
;
603 for( int i
= 0; i
< nStart
; ++i
)
604 nXOffset
+= mpGlyphAdvances
[ i
];
606 // calculate absolute position in pixel units
607 Point
aRelativePos( nXOffset
, 0 );
608 rPos
= GetDrawPosition( aRelativePos
);
611 while( nCount
< nLen
)
613 // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
614 sal_GlyphId nGlyphIndex
= mpOutGlyphs
[ nStart
];
615 if( mbDisableGlyphs
)
617 if( mnLayoutFlags
& SAL_LAYOUT_VERTICAL
)
619 const sal_UCS4 cChar
= static_cast<sal_UCS4
>(nGlyphIndex
& GF_IDXMASK
);
620 if( mrWinFontData
.HasGSUBstitutions( mhDC
)
621 && mrWinFontData
.IsGSUBstituted( cChar
) )
622 nGlyphIndex
|= GF_GSUB
| GF_ROTL
;
625 nGlyphIndex
|= GetVerticalFlags( cChar
);
626 if( (nGlyphIndex
& GF_ROTMASK
) == 0 )
627 nGlyphIndex
|= GF_VERT
;
630 nGlyphIndex
|= GF_ISCHAR
;
633 *(pGlyphs
++) = nGlyphIndex
;
635 *(pGlyphAdvances
++) = mpGlyphAdvances
[ nStart
];
639 if( !mpGlyphs2Chars
)
640 nCharPos
= nStart
+ mnMinCharPos
;
642 nCharPos
= mpGlyphs2Chars
[nStart
];
643 *(pCharIndexes
++) = nCharPos
;
646 // stop at last glyph
647 if( ++nStart
>= mnGlyphCount
)
650 // stop when next x-position is unexpected
651 if( !pGlyphAdvances
&& mpGlyphOrigAdvs
)
652 if( mpGlyphAdvances
[nStart
-1] != mpGlyphOrigAdvs
[nStart
-1] )
659 // -----------------------------------------------------------------------
661 void SimpleWinLayout::DrawText( SalGraphics
& rGraphics
) const
663 if( mnGlyphCount
<= 0 )
666 WinSalGraphics
& rWinGraphics
= static_cast<WinSalGraphics
&>(rGraphics
);
667 HDC aHDC
= rWinGraphics
.mhDC
;
669 HFONT hOrigFont
= DisableFontScaling();
671 UINT mnDrawOptions
= ETO_GLYPH_INDEX
;
672 if( mbDisableGlyphs
)
675 Point aPos
= GetDrawPosition( Point( mnBaseAdv
, 0 ) );
677 // #108267#, limit the number of glyphs to avoid paint errors
678 UINT limitedGlyphCount
= Min( 8192, mnGlyphCount
);
679 if( mnDrawOptions
|| aSalShlData
.mbWNT
)
681 // #108267#, break up into glyph portions of a limited size required by Win32 API
682 const unsigned int maxGlyphCount
= 8192;
683 UINT numGlyphPortions
= mnGlyphCount
/ maxGlyphCount
;
684 UINT remainingGlyphs
= mnGlyphCount
% maxGlyphCount
;
686 if( numGlyphPortions
)
688 // #108267#,#109387# break up string into smaller chunks
689 // the output positions will be updated by windows (SetTextAlign)
692 UINT oldTa
= ::GetTextAlign( aHDC
);
693 ::SetTextAlign( aHDC
, (oldTa
& ~TA_NOUPDATECP
) | TA_UPDATECP
);
694 ::MoveToEx( aHDC
, aPos
.X(), aPos
.Y(), &oldPos
);
695 for( i
=n
=0; n
<numGlyphPortions
; n
++, i
+=maxGlyphCount
)
696 ::ExtTextOutW( aHDC
, 0, 0, mnDrawOptions
, NULL
,
697 mpOutGlyphs
+i
, maxGlyphCount
, mpGlyphAdvances
+i
);
698 ::ExtTextOutW( aHDC
, 0, 0, mnDrawOptions
, NULL
,
699 mpOutGlyphs
+i
, remainingGlyphs
, mpGlyphAdvances
+i
);
700 ::MoveToEx( aHDC
, oldPos
.x
, oldPos
.y
, (LPPOINT
) NULL
);
701 ::SetTextAlign( aHDC
, oldTa
);
704 ::ExtTextOutW( aHDC
, aPos
.X(), aPos
.Y(), mnDrawOptions
, NULL
,
705 mpOutGlyphs
, mnGlyphCount
, mpGlyphAdvances
);
709 // #108267#, On Win9x, we get paint errors when drawing huge strings, even when
710 // split into pieces (see above), seems to be a problem in the internal text clipping
711 // so we just cut off the string
712 if( !mpGlyphOrigAdvs
)
713 ::ExtTextOutW( aHDC
, aPos
.X(), aPos
.Y(), 0, NULL
,
714 mpOutGlyphs
, limitedGlyphCount
, NULL
);
717 // workaround for problem in #106259#
718 long nXPos
= mnBaseAdv
;
719 for( unsigned int i
= 0; i
< limitedGlyphCount
; ++i
)
721 ::ExtTextOutW( aHDC
, aPos
.X(), aPos
.Y(), 0, NULL
,
722 mpOutGlyphs
+i
, 1, NULL
);
723 nXPos
+= mpGlyphAdvances
[ i
];
724 aPos
= GetDrawPosition( Point( nXPos
, 0 ) );
730 DeleteFont( SelectFont( aHDC
, hOrigFont
) );
733 // -----------------------------------------------------------------------
735 long SimpleWinLayout::FillDXArray( long* pDXArray
) const
739 long mnWidth
= mnBaseAdv
;
740 for( int i
= 0; i
< mnGlyphCount
; ++i
)
741 mnWidth
+= mpGlyphAdvances
[ i
];
744 if( pDXArray
!= NULL
)
746 for( int i
= 0; i
< mnCharCount
; ++i
)
747 pDXArray
[ i
] = mpCharWidths
[ i
];
753 // -----------------------------------------------------------------------
755 int SimpleWinLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
756 // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
759 if( (mnWidth
* nFactor
+ mnCharCount
* nCharExtra
) <= nMaxWidth
)
762 long nExtraWidth
= mnBaseAdv
* nFactor
;
763 for( int n
= 0; n
< mnCharCount
; ++n
)
765 // skip unused characters
766 if( mpChars2Glyphs
&& (mpChars2Glyphs
[n
] < 0) )
768 // add char widths until max
769 nExtraWidth
+= mpCharWidths
[ n
] * nFactor
;
770 if( nExtraWidth
>= nMaxWidth
)
771 return (mnMinCharPos
+ n
);
772 nExtraWidth
+= nCharExtra
;
778 // -----------------------------------------------------------------------
780 void SimpleWinLayout::GetCaretPositions( int nMaxIdx
, long* pCaretXArray
) const
782 long nXPos
= mnBaseAdv
;
784 if( !mpGlyphs2Chars
)
786 for( int i
= 0; i
< nMaxIdx
; i
+= 2 )
788 pCaretXArray
[ i
] = nXPos
;
789 nXPos
+= mpGlyphAdvances
[ i
>>1 ];
790 pCaretXArray
[ i
+1 ] = nXPos
;
796 for( i
= 0; i
< nMaxIdx
; ++i
)
797 pCaretXArray
[ i
] = -1;
799 // assign glyph positions to character positions
800 for( i
= 0; i
< mnGlyphCount
; ++i
)
802 int nCurrIdx
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
803 long nXRight
= nXPos
+ mpCharWidths
[ nCurrIdx
];
805 if( !(mpGlyphRTLFlags
&& mpGlyphRTLFlags
[i
]) )
807 // normal positions for LTR case
808 pCaretXArray
[ nCurrIdx
] = nXPos
;
809 pCaretXArray
[ nCurrIdx
+1 ] = nXRight
;
813 // reverse positions for RTL case
814 pCaretXArray
[ nCurrIdx
] = nXRight
;
815 pCaretXArray
[ nCurrIdx
+1 ] = nXPos
;
817 nXPos
+= mpGlyphAdvances
[ i
];
822 // -----------------------------------------------------------------------
824 void SimpleWinLayout::Justify( long nNewWidth
)
826 long nOldWidth
= mnWidth
;
829 if( mnGlyphCount
<= 0 )
832 if( nNewWidth
== nOldWidth
)
835 // the rightmost glyph cannot be stretched
836 const int nRight
= mnGlyphCount
- 1;
837 nOldWidth
-= mpGlyphAdvances
[ nRight
];
838 nNewWidth
-= mpGlyphAdvances
[ nRight
];
840 // count stretchable glyphs
841 int nStretchable
= 0, i
;
842 for( i
= 0; i
< nRight
; ++i
)
843 if( mpGlyphAdvances
[i
] >= 0 )
846 // stretch these glyphs
847 int nDiffWidth
= nNewWidth
- nOldWidth
;
848 for( i
= 0; (i
< nRight
) && (nStretchable
> 0); ++i
)
850 if( mpGlyphAdvances
[i
] <= 0 )
852 int nDeltaWidth
= nDiffWidth
/ nStretchable
;
853 mpGlyphAdvances
[i
] += nDeltaWidth
;
855 nDiffWidth
-= nDeltaWidth
;
859 // -----------------------------------------------------------------------
861 void SimpleWinLayout::AdjustLayout( ImplLayoutArgs
& rArgs
)
863 SalLayout::AdjustLayout( rArgs
);
865 // adjust positions if requested
866 if( rArgs
.mpDXArray
)
867 ApplyDXArray( rArgs
);
868 else if( rArgs
.mnLayoutWidth
)
869 Justify( rArgs
.mnLayoutWidth
);
873 // recalculate virtual char widths if they were changed
874 if( mpCharWidths
!= mpGlyphAdvances
)
877 if( !mpGlyphs2Chars
)
880 for( i
= 0; i
< mnGlyphCount
; ++i
)
881 mpCharWidths
[ i
] = mpGlyphAdvances
[ i
];
885 // BiDi or complex case
886 for( i
= 0; i
< mnCharCount
; ++i
)
887 mpCharWidths
[ i
] = 0;
888 for( i
= 0; i
< mnGlyphCount
; ++i
)
890 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
892 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
898 // -----------------------------------------------------------------------
900 void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs
& rArgs
)
902 // try to avoid disturbance of text flow for LSB rounding case;
903 const long* pDXArray
= rArgs
.mpDXArray
;
906 long nOldWidth
= mnBaseAdv
;
907 for(; i
< mnCharCount
; ++i
)
909 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
912 nOldWidth
+= mpGlyphAdvances
[ j
];
913 int nDiff
= nOldWidth
- pDXArray
[ i
];
915 // disabled because of #104768#
916 // works great for static text, but problems when typing
917 // if( nDiff>+1 || nDiff<-1 )
918 // only bother with changing anything when something moved
923 if( i
>= mnCharCount
)
926 if( !mpGlyphOrigAdvs
)
928 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
929 for( i
= 0; i
< mnGlyphCount
; ++i
)
930 mpGlyphOrigAdvs
[ i
] = mpGlyphAdvances
[ i
];
934 for( i
= 0; i
< mnCharCount
; ++i
)
936 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
938 mpGlyphAdvances
[j
] = pDXArray
[i
] - mnWidth
;
939 mnWidth
= pDXArray
[i
];
943 // -----------------------------------------------------------------------
945 void SimpleWinLayout::MoveGlyph( int nStart
, long nNewXPos
)
947 if( nStart
> mnGlyphCount
)
950 // calculate the current x-position of the requested glyph
951 // TODO: cache absolute positions
952 int nXPos
= mnBaseAdv
;
953 for( int i
= 0; i
< nStart
; ++i
)
954 nXPos
+= mpGlyphAdvances
[i
];
956 // calculate the difference to the current glyph position
957 int nDelta
= nNewXPos
- nXPos
;
959 // adjust the width of the layout if it was already cached
963 // depending on whether the requested glyph is leftmost in the layout
964 // adjust either the layout's or the requested glyph's relative position
966 mpGlyphAdvances
[ nStart
-1 ] += nDelta
;
971 // -----------------------------------------------------------------------
973 void SimpleWinLayout::DropGlyph( int nStart
)
975 mpOutGlyphs
[ nStart
] = DROPPED_OUTGLYPH
;
978 // -----------------------------------------------------------------------
980 void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
982 // return early if no glyph has been dropped
983 int i
= mnGlyphCount
;
984 while( (--i
>= 0) && (mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
) );
988 // convert the layout to a sparse layout if it is not already
989 if( !mpGlyphs2Chars
)
991 mpGlyphs2Chars
= new int[ mnGlyphCount
];
992 mpCharWidths
= new int[ mnCharCount
];
993 // assertion: mnGlyphCount == mnCharCount
994 for( int k
= 0; k
< mnGlyphCount
; ++k
)
996 mpGlyphs2Chars
[ k
] = mnMinCharPos
+ k
;
997 mpCharWidths
[ k
] = mpGlyphAdvances
[ k
];
1001 // remove dropped glyphs that are rightmost in the layout
1002 for( i
= mnGlyphCount
; --i
>= 0; )
1004 if( mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
)
1007 mnWidth
-= mpGlyphAdvances
[ i
];
1008 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
1009 if( nRelCharPos
>= 0 )
1010 mpCharWidths
[ nRelCharPos
] = 0;
1012 mnGlyphCount
= i
+ 1;
1014 // keep original glyph widths around
1015 if( !mpGlyphOrigAdvs
)
1017 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
1018 for( int k
= 0; k
< mnGlyphCount
; ++k
)
1019 mpGlyphOrigAdvs
[ k
] = mpGlyphAdvances
[ k
];
1022 // remove dropped glyphs inside the layout
1024 for( i
= 0; i
< mnGlyphCount
; ++i
)
1026 if( mpOutGlyphs
[ i
] == DROPPED_OUTGLYPH
)
1028 // adjust relative position to last valid glyph
1029 int nDroppedWidth
= mpGlyphAdvances
[ i
];
1030 mpGlyphAdvances
[ i
] = 0;
1032 mpGlyphAdvances
[ nNewGC
-1 ] += nDroppedWidth
;
1034 mnBaseAdv
+= nDroppedWidth
;
1036 // zero the virtual char width for the char that has a fallback
1037 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
1038 if( nRelCharPos
>= 0 )
1039 mpCharWidths
[ nRelCharPos
] = 0;
1045 // rearrange the glyph array to get rid of the dropped glyph
1046 mpOutGlyphs
[ nNewGC
] = mpOutGlyphs
[ i
];
1047 mpGlyphAdvances
[ nNewGC
] = mpGlyphAdvances
[ i
];
1048 mpGlyphOrigAdvs
[ nNewGC
] = mpGlyphOrigAdvs
[ i
];
1049 mpGlyphs2Chars
[ nNewGC
] = mpGlyphs2Chars
[ i
];
1055 mnGlyphCount
= nNewGC
;
1056 if( mnGlyphCount
<= 0 )
1057 mnWidth
= mnBaseAdv
= 0;
1060 // =======================================================================
1062 #ifdef USE_UNISCRIBE
1067 SCRIPT_ITEM
* mpScriptItem
;
1072 //long mnPixelWidth;
1078 bool IsEmpty() const { return (mnEndGlyphPos
<= 0); }
1079 bool IsRTL() const { return mpScriptItem
->a
.fRTL
; }
1080 bool HasKashidas() const { return mbHasKashidas
; }
1083 // -----------------------------------------------------------------------
1085 class UniscribeLayout
: public WinLayout
1088 UniscribeLayout( HDC
, const ImplWinFontData
&, ImplWinFontEntry
& );
1090 virtual bool LayoutText( ImplLayoutArgs
& );
1091 virtual void AdjustLayout( ImplLayoutArgs
& );
1092 virtual void DrawText( SalGraphics
& ) const;
1093 virtual int GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int&,
1094 sal_Int32
* pGlyphAdvances
, int* pCharPosAry
) const;
1096 virtual long FillDXArray( long* pDXArray
) const;
1097 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const;
1098 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
1099 virtual bool IsKashidaPosValid ( int nCharPos
) const;
1101 // for glyph+font+script fallback
1102 virtual void MoveGlyph( int nStart
, long nNewXPos
);
1103 virtual void DropGlyph( int nStart
);
1104 virtual void Simplify( bool bIsBase
);
1105 virtual void DisableGlyphInjection( bool bDisable
) { mbDisableGlyphInjection
= bDisable
; }
1108 virtual ~UniscribeLayout();
1110 void Justify( long nNewWidth
);
1111 void ApplyDXArray( const ImplLayoutArgs
& );
1113 bool GetItemSubrange( const VisualItem
&,
1114 int& rMinIndex
, int& rEndIndex
) const;
1117 // item specific info
1118 SCRIPT_ITEM
* mpScriptItems
; // in logical order
1119 VisualItem
* mpVisualItems
; // in visual order
1120 int mnItemCount
; // number of visual items
1122 // string specific info
1123 // everything is in logical order
1125 WORD
* mpLogClusters
; // map from absolute_char_pos to relative_glyph_pos
1126 int* mpCharWidths
; // map from absolute_char_pos to char_width
1127 int mnSubStringMin
; // char_pos of first char in context
1129 // glyph specific info
1130 // everything is in visual order
1132 int mnGlyphCapacity
;
1133 int* mpGlyphAdvances
; // glyph advance width before justification
1134 int* mpJustifications
; // glyph advance width after justification
1135 WORD
* mpOutGlyphs
; // glyphids in visual order
1136 GOFFSET
* mpGlyphOffsets
; // glyph offsets to the "naive" layout
1137 SCRIPT_VISATTR
* mpVisualAttrs
; // glyph visual attributes
1138 mutable int* mpGlyphs2Chars
; // map from absolute_glyph_pos to absolute_char_pos
1141 void InitKashidaHandling();
1142 void KashidaItemFix( int nMinGlyphPos
, int nEndGlyphPos
);
1143 bool KashidaWordFix( int nMinGlyphPos
, int nEndGlyphPos
, int* pnCurrentPos
);
1145 int mnMinKashidaWidth
;
1146 int mnMinKashidaGlyph
;
1147 bool mbDisableGlyphInjection
;
1150 // -----------------------------------------------------------------------
1151 // dynamic loading of usp library
1153 static oslModule aUspModule
= NULL
;
1154 static bool bUspEnabled
= true;
1156 static HRESULT ((WINAPI
*pScriptIsComplex
)( const WCHAR
*, int, DWORD
));
1157 static HRESULT ((WINAPI
*pScriptItemize
)( const WCHAR
*, int, int,
1158 const SCRIPT_CONTROL
*, const SCRIPT_STATE
*, SCRIPT_ITEM
*, int* ));
1159 static HRESULT ((WINAPI
*pScriptShape
)( HDC
, SCRIPT_CACHE
*, const WCHAR
*,
1160 int, int, SCRIPT_ANALYSIS
*, WORD
*, WORD
*, SCRIPT_VISATTR
*, int* ));
1161 static HRESULT ((WINAPI
*pScriptPlace
)( HDC
, SCRIPT_CACHE
*, const WORD
*, int,
1162 const SCRIPT_VISATTR
*, SCRIPT_ANALYSIS
*, int*, GOFFSET
*, ABC
* ));
1163 static HRESULT ((WINAPI
*pScriptGetLogicalWidths
)( const SCRIPT_ANALYSIS
*,
1164 int, int, const int*, const WORD
*, const SCRIPT_VISATTR
*, int* ));
1165 static HRESULT ((WINAPI
*pScriptApplyLogicalWidth
)( const int*, int, int, const WORD
*,
1166 const SCRIPT_VISATTR
*, const int*, const SCRIPT_ANALYSIS
*, ABC
*, int* ));
1167 static HRESULT ((WINAPI
*pScriptJustify
)( const SCRIPT_VISATTR
*,
1168 const int*, int, int, int, int* ));
1169 static HRESULT ((WINAPI
*pScriptTextOut
)( const HDC
, SCRIPT_CACHE
*,
1170 int, int, UINT
, const RECT
*, const SCRIPT_ANALYSIS
*, const WCHAR
*,
1171 int, const WORD
*, int, const int*, const int*, const GOFFSET
* ));
1172 static HRESULT ((WINAPI
*pScriptGetFontProperties
)( HDC
, SCRIPT_CACHE
*, SCRIPT_FONTPROPERTIES
* ));
1173 static HRESULT ((WINAPI
*pScriptFreeCache
)( SCRIPT_CACHE
* ));
1175 static bool bManualCellAlign
= true;
1177 // -----------------------------------------------------------------------
1179 static bool InitUSP()
1181 OUString
aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
1182 aUspModule
= osl_loadModule( aLibraryName
.pData
, SAL_LOADMODULE_DEFAULT
);
1184 return (bUspEnabled
= false);
1186 pScriptIsComplex
= (HRESULT (WINAPI
*)(const WCHAR
*,int,DWORD
))
1187 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptIsComplex" );
1188 bUspEnabled
&= (NULL
!= pScriptIsComplex
);
1190 pScriptItemize
= (HRESULT (WINAPI
*)(const WCHAR
*,int,int,
1191 const SCRIPT_CONTROL
*,const SCRIPT_STATE
*,SCRIPT_ITEM
*,int*))
1192 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptItemize" );
1193 bUspEnabled
&= (NULL
!= pScriptItemize
);
1195 pScriptShape
= (HRESULT (WINAPI
*)(HDC
,SCRIPT_CACHE
*,const WCHAR
*,
1196 int,int,SCRIPT_ANALYSIS
*,WORD
*,WORD
*,SCRIPT_VISATTR
*,int*))
1197 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptShape" );
1198 bUspEnabled
&= (NULL
!= pScriptShape
);
1200 pScriptPlace
= (HRESULT (WINAPI
*)(HDC
, SCRIPT_CACHE
*, const WORD
*, int,
1201 const SCRIPT_VISATTR
*,SCRIPT_ANALYSIS
*,int*,GOFFSET
*,ABC
*))
1202 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptPlace" );
1203 bUspEnabled
&= (NULL
!= pScriptPlace
);
1205 pScriptGetLogicalWidths
= (HRESULT (WINAPI
*)(const SCRIPT_ANALYSIS
*,
1206 int,int,const int*,const WORD
*,const SCRIPT_VISATTR
*,int*))
1207 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptGetLogicalWidths" );
1208 bUspEnabled
&= (NULL
!= pScriptGetLogicalWidths
);
1210 pScriptApplyLogicalWidth
= (HRESULT (WINAPI
*)(const int*,int,int,const WORD
*,
1211 const SCRIPT_VISATTR
*,const int*,const SCRIPT_ANALYSIS
*,ABC
*,int*))
1212 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptApplyLogicalWidth" );
1213 bUspEnabled
&= (NULL
!= pScriptApplyLogicalWidth
);
1215 pScriptJustify
= (HRESULT (WINAPI
*)(const SCRIPT_VISATTR
*,const int*,
1217 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptJustify" );
1218 bUspEnabled
&= (NULL
!= pScriptJustify
);
1220 pScriptGetFontProperties
= (HRESULT (WINAPI
*)( HDC
,SCRIPT_CACHE
*,SCRIPT_FONTPROPERTIES
*))
1221 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptGetFontProperties" );
1222 bUspEnabled
&= (NULL
!= pScriptGetFontProperties
);
1224 pScriptTextOut
= (HRESULT (WINAPI
*)(const HDC
,SCRIPT_CACHE
*,
1225 int,int,UINT
,const RECT
*,const SCRIPT_ANALYSIS
*,const WCHAR
*,
1226 int,const WORD
*,int,const int*,const int*,const GOFFSET
*))
1227 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptTextOut" );
1228 bUspEnabled
&= (NULL
!= pScriptTextOut
);
1230 pScriptFreeCache
= (HRESULT (WINAPI
*)(SCRIPT_CACHE
*))
1231 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptFreeCache" );
1232 bUspEnabled
&= (NULL
!= pScriptFreeCache
);
1236 osl_unloadModule( aUspModule
);
1240 // get the DLL version info
1241 int nUspVersion
= 0;
1242 // TODO: there must be a simpler way to get the friggin version info from OSL?
1243 rtl_uString
* pModuleURL
= NULL
;
1244 osl_getModuleURLFromAddress( (void*)pScriptIsComplex
, &pModuleURL
);
1245 rtl_uString
* pModuleFileName
= NULL
;
1247 osl_getSystemPathFromFileURL( pModuleURL
, &pModuleFileName
);
1248 const sal_Unicode
* pModuleFileCStr
= NULL
;
1249 if( pModuleFileName
)
1250 pModuleFileCStr
= rtl_uString_getStr( pModuleFileName
);
1251 if( pModuleFileCStr
)
1254 DWORD nBufSize
= ::GetFileVersionInfoSizeW( const_cast<LPWSTR
>(reinterpret_cast<LPCWSTR
>(pModuleFileCStr
)), &nHandle
);
1255 char* pBuffer
= (char*)alloca( nBufSize
);
1256 WIN_BOOL bRC
= ::GetFileVersionInfoW( const_cast<LPWSTR
>(reinterpret_cast<LPCWSTR
>(pModuleFileCStr
)), nHandle
, nBufSize
, pBuffer
);
1257 VS_FIXEDFILEINFO
* pFixedFileInfo
= NULL
;
1258 UINT nFixedFileSize
= 0;
1260 ::VerQueryValueW( pBuffer
, const_cast<LPWSTR
>(L
"\\"), (void**)&pFixedFileInfo
, &nFixedFileSize
);
1261 if( pFixedFileInfo
&& pFixedFileInfo
->dwSignature
== 0xFEEF04BD )
1262 nUspVersion
= HIWORD(pFixedFileInfo
->dwProductVersionMS
) * 10000
1263 + LOWORD(pFixedFileInfo
->dwProductVersionMS
);
1266 // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
1267 if( nUspVersion
>= 10600 )
1268 bManualCellAlign
= false;
1273 // -----------------------------------------------------------------------
1275 UniscribeLayout::UniscribeLayout( HDC hDC
,
1276 const ImplWinFontData
& rWinFontData
, ImplWinFontEntry
& rWinFontEntry
)
1277 : WinLayout( hDC
, rWinFontData
, rWinFontEntry
),
1279 mpScriptItems( NULL
),
1280 mpVisualItems( NULL
),
1281 mpLogClusters( NULL
),
1282 mpCharWidths( NULL
),
1283 mnCharCapacity( 0 ),
1284 mnSubStringMin( 0 ),
1285 mnGlyphCapacity( 0 ),
1287 mpOutGlyphs( NULL
),
1288 mpGlyphAdvances( NULL
),
1289 mpJustifications( NULL
),
1290 mpGlyphOffsets( NULL
),
1291 mpVisualAttrs( NULL
),
1292 mpGlyphs2Chars( NULL
),
1293 mnMinKashidaGlyph( 0 ),
1294 mbDisableGlyphInjection( false )
1297 // -----------------------------------------------------------------------
1299 UniscribeLayout::~UniscribeLayout()
1301 delete[] mpScriptItems
;
1302 delete[] mpVisualItems
;
1303 delete[] mpLogClusters
;
1304 delete[] mpCharWidths
;
1305 delete[] mpOutGlyphs
;
1306 delete[] mpGlyphAdvances
;
1307 delete[] mpJustifications
;
1308 delete[] mpGlyphOffsets
;
1309 delete[] mpVisualAttrs
;
1310 delete[] mpGlyphs2Chars
;
1313 // -----------------------------------------------------------------------
1315 bool UniscribeLayout::LayoutText( ImplLayoutArgs
& rArgs
)
1317 // for a base layout only the context glyphs have to be dropped
1318 // => when the whole string is involved there is no extra context
1319 typedef std::vector
<int> TIntVector
;
1320 TIntVector aDropChars
;
1321 if( rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
)
1323 // calculate superfluous context char positions
1324 aDropChars
.push_back( 0 );
1325 aDropChars
.push_back( rArgs
.mnLength
);
1328 for( rArgs
.ResetPos(); rArgs
.GetNextRun( &nMin
, &nEnd
, &bRTL
); )
1330 aDropChars
.push_back( nMin
);
1331 aDropChars
.push_back( nEnd
);
1333 // prepare aDropChars for binary search which will allow to
1334 // not bother with visual items that will be dropped anyway
1335 std::sort( aDropChars
.begin(), aDropChars
.end() );
1339 // TODO: fix case when recyclying old UniscribeLayout object
1340 mnMinCharPos
= rArgs
.mnMinCharPos
;
1341 mnEndCharPos
= rArgs
.mnEndCharPos
;
1343 // determine script items from string
1345 // prepare itemization
1346 // TODO: try to avoid itemization since it costs a lot of performance
1347 SCRIPT_STATE aScriptState
= {0,false,false,false,false,false,false,false,false,0,0};
1348 aScriptState
.uBidiLevel
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
));
1349 aScriptState
.fOverrideDirection
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
));
1350 aScriptState
.fDigitSubstitute
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_SUBSTITUTE_DIGITS
));
1351 aScriptState
.fArabicNumContext
= aScriptState
.fDigitSubstitute
& aScriptState
.uBidiLevel
;
1352 DWORD nLangId
= 0; // TODO: get language from font
1353 SCRIPT_CONTROL aScriptControl
= {nLangId
,false,false,false,false,false,false,false,false,0};
1354 aScriptControl
.fNeutralOverride
= aScriptState
.fOverrideDirection
;
1355 aScriptControl
.fContextDigits
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_SUBSTITUTE_DIGITS
));
1356 // determine relevant substring and work only on it
1357 // when Bidi status is unknown we need to look at the whole string though
1359 int nSubStringEnd
= rArgs
.mnLength
;
1360 if( aScriptState
.fOverrideDirection
)
1362 // TODO: limit substring to portion limits
1363 mnSubStringMin
= rArgs
.mnMinCharPos
- 8;
1364 if( mnSubStringMin
< 0 )
1366 nSubStringEnd
= rArgs
.mnEndCharPos
+ 8;
1367 if( nSubStringEnd
> rArgs
.mnLength
)
1368 nSubStringEnd
= rArgs
.mnLength
;
1372 // now itemize the substring with its context
1373 for( int nItemCapacity
= 16;; nItemCapacity
*= 8 )
1375 mpScriptItems
= new SCRIPT_ITEM
[ nItemCapacity
];
1376 HRESULT nRC
= (*pScriptItemize
)(
1377 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ mnSubStringMin
), nSubStringEnd
- mnSubStringMin
,
1378 nItemCapacity
- 1, &aScriptControl
, &aScriptState
,
1379 mpScriptItems
, &mnItemCount
);
1380 if( !nRC
) // break loop when everything is correctly itemized
1383 // prepare bigger buffers for another itemization round
1384 delete[] mpScriptItems
;
1385 mpScriptItems
= NULL
;
1386 if( nRC
!= E_OUTOFMEMORY
)
1388 if( nItemCapacity
> (nSubStringEnd
- mnSubStringMin
) )
1392 // calculate the order of visual items
1395 // adjust char positions by substring offset
1396 for( nItem
= 0; nItem
<= mnItemCount
; ++nItem
)
1397 mpScriptItems
[ nItem
].iCharPos
+= mnSubStringMin
;
1398 // default visual item ordering
1399 mpVisualItems
= new VisualItem
[ mnItemCount
];
1400 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1402 // initialize char specific item info
1403 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
1404 SCRIPT_ITEM
* pScriptItem
= &mpScriptItems
[ nItem
];
1405 rVisualItem
.mpScriptItem
= pScriptItem
;
1406 rVisualItem
.mnMinCharPos
= pScriptItem
[0].iCharPos
;
1407 rVisualItem
.mnEndCharPos
= pScriptItem
[1].iCharPos
;
1410 // reorder visual item order if needed
1411 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
)
1413 // force RTL item ordering if requested
1414 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
)
1416 VisualItem
* pVI0
= &mpVisualItems
[ 0 ];
1417 VisualItem
* pVI1
= &mpVisualItems
[ mnItemCount
];
1418 while( pVI0
< --pVI1
)
1420 VisualItem aVtmp
= *pVI0
;
1426 else if( mnItemCount
> 1 )
1428 // apply bidi algorithm's rule L2 on item level
1429 // TODO: use faster L2 algorithm
1430 int nMaxBidiLevel
= 0;
1431 VisualItem
* pVI
= &mpVisualItems
[0];
1432 VisualItem
* const pVIend
= pVI
+ mnItemCount
;
1433 for(; pVI
< pVIend
; ++pVI
)
1434 if( nMaxBidiLevel
< pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1435 nMaxBidiLevel
= pVI
->mpScriptItem
->a
.s
.uBidiLevel
;
1437 while( --nMaxBidiLevel
>= 0 )
1439 for( pVI
= &mpVisualItems
[0]; pVI
< pVIend
; )
1441 // find item range that needs reordering
1442 for(; pVI
< pVIend
; ++pVI
)
1443 if( nMaxBidiLevel
< pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1445 VisualItem
* pVImin
= pVI
++;
1446 for(; pVI
< pVIend
; ++pVI
)
1447 if( nMaxBidiLevel
>= pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1449 VisualItem
* pVImax
= pVI
++;
1451 // reverse order of items in this range
1452 while( pVImin
< --pVImax
)
1454 VisualItem aVtmp
= *pVImin
;
1455 *(pVImin
++) = *pVImax
;
1463 // TODO: when reusing object reuse old allocations or delete them
1464 // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
1465 mnCharCapacity
= nSubStringEnd
;
1466 mpLogClusters
= new WORD
[ mnCharCapacity
];
1467 mpCharWidths
= new int[ mnCharCapacity
];
1470 mnGlyphCapacity
= 16 + 4 * (nSubStringEnd
- mnSubStringMin
); // worst case assumption
1471 mpGlyphAdvances
= new int[ mnGlyphCapacity
];
1472 mpOutGlyphs
= new WORD
[ mnGlyphCapacity
];
1473 mpGlyphOffsets
= new GOFFSET
[ mnGlyphCapacity
];
1474 mpVisualAttrs
= new SCRIPT_VISATTR
[ mnGlyphCapacity
];
1477 for( int j
= mnSubStringMin
; j
< nSubStringEnd
; ++j
)
1478 mpCharWidths
[j
] = 0;
1480 // layout script items
1481 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
1482 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1484 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
1486 // initialize glyph specific item info
1487 rVisualItem
.mnMinGlyphPos
= mnGlyphCount
;
1488 rVisualItem
.mnEndGlyphPos
= 0;
1489 rVisualItem
.mnXOffset
= nXOffset
;
1490 //rVisualItem.mnPixelWidth = 0;
1492 // shortcut ignorable items
1493 if( (rArgs
.mnEndCharPos
<= rVisualItem
.mnMinCharPos
)
1494 || (rArgs
.mnMinCharPos
>= rVisualItem
.mnEndCharPos
) )
1496 for( int i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; ++i
)
1497 mpLogClusters
[i
] = sal::static_int_cast
<WORD
>(~0U);
1501 // override bidi analysis if requested
1502 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
)
1504 // FIXME: is this intended ?
1505 rVisualItem
.mpScriptItem
->a
.fRTL
= (aScriptState
.uBidiLevel
& 1);
1506 rVisualItem
.mpScriptItem
->a
.s
.uBidiLevel
= aScriptState
.uBidiLevel
;
1507 rVisualItem
.mpScriptItem
->a
.s
.fOverrideDirection
= aScriptState
.fOverrideDirection
;
1510 // convert the unicodes to glyphs
1511 int nGlyphCount
= 0;
1512 int nCharCount
= rVisualItem
.mnEndCharPos
- rVisualItem
.mnMinCharPos
;
1513 HRESULT nRC
= (*pScriptShape
)( mhDC
, &rScriptCache
,
1514 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ rVisualItem
.mnMinCharPos
),
1516 mnGlyphCapacity
- rVisualItem
.mnMinGlyphPos
, // problem when >0xFFFF
1517 &rVisualItem
.mpScriptItem
->a
,
1518 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1519 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1520 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1523 // find and handle problems in the unicode to glyph conversion
1524 if( nRC
== USP_E_SCRIPT_NOT_IN_FONT
)
1526 // the whole visual item needs a fallback, but make sure that the next
1527 // fallback request is limited to the characters in the original request
1528 // => this is handled in ImplLayoutArgs::PrepareFallback()
1529 rArgs
.NeedFallback( rVisualItem
.mnMinCharPos
, rVisualItem
.mnEndCharPos
,
1530 rVisualItem
.IsRTL() );
1532 // don't bother to do a default layout in a fallback level
1533 if( 0 != (rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
) )
1536 // the primitive layout engine is good enough for the default layout
1537 rVisualItem
.mpScriptItem
->a
.eScript
= SCRIPT_UNDEFINED
;
1538 nRC
= (*pScriptShape
)( mhDC
, &rScriptCache
,
1539 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ rVisualItem
.mnMinCharPos
),
1541 mnGlyphCapacity
- rVisualItem
.mnMinGlyphPos
,
1542 &rVisualItem
.mpScriptItem
->a
,
1543 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1544 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1545 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1551 #if 0 // keep the glyphs for now because they are better than nothing
1552 // mark as NotDef glyphs
1553 for( i
= 0; i
< nGlyphCount
; ++i
)
1554 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 0;
1558 // something undefined happened => give up for this visual item
1560 else // if( nRC == 0 )
1562 // check if there are any NotDef glyphs
1563 for( i
= 0; i
< nGlyphCount
; ++i
)
1564 if( 0 == mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] )
1566 if( i
< nGlyphCount
)
1568 // clip charpos limits to the layout string without context
1569 int nMinCharPos
= rVisualItem
.mnMinCharPos
;
1570 if( nMinCharPos
< rArgs
.mnMinCharPos
)
1571 nMinCharPos
= rArgs
.mnMinCharPos
;
1572 int nEndCharPos
= rVisualItem
.mnEndCharPos
;
1573 if( nEndCharPos
> rArgs
.mnEndCharPos
)
1574 nEndCharPos
= rArgs
.mnEndCharPos
;
1575 // request fallback for individual NotDef glyphs
1578 // ignore non-NotDef glyphs
1579 if( 0 != mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] )
1581 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = DROPPED_OUTGLYPH
;
1582 // request fallback for the whole cell that resulted in a NotDef glyph
1583 // TODO: optimize algorithm
1584 const bool bRTL
= rVisualItem
.IsRTL();
1587 // request fallback for the left-to-right cell
1588 for( int c
= nMinCharPos
; c
< nEndCharPos
; ++c
)
1590 if( mpLogClusters
[ c
] == i
)
1592 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1593 if( rArgs
.mpStr
[ c
] == 0x2060 )
1594 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 1;
1597 rArgs
.NeedFallback( c
, false );
1603 // request fallback for the right to left cell
1604 for( int c
= nEndCharPos
; --c
>= nMinCharPos
; )
1606 if( mpLogClusters
[ c
] == i
)
1608 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1609 if( rArgs
.mpStr
[ c
] == 0x2060 )
1610 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 1;
1613 rArgs
.NeedFallback( c
, true );
1617 } while( ++i
< nGlyphCount
);
1621 // now place the glyphs
1622 nRC
= (*pScriptPlace
)( mhDC
, &rScriptCache
,
1623 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1625 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1626 &rVisualItem
.mpScriptItem
->a
,
1627 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
1628 mpGlyphOffsets
+ rVisualItem
.mnMinGlyphPos
,
1629 &rVisualItem
.maABCWidths
);
1634 // calculate the logical char widths from the glyph layout
1635 nRC
= (*pScriptGetLogicalWidths
)(
1636 &rVisualItem
.mpScriptItem
->a
,
1637 nCharCount
, nGlyphCount
,
1638 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
1639 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1640 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1641 mpCharWidths
+ rVisualItem
.mnMinCharPos
);
1643 // update the glyph counters
1644 mnGlyphCount
+= nGlyphCount
;
1645 rVisualItem
.mnEndGlyphPos
= mnGlyphCount
;
1649 if( GetItemSubrange( rVisualItem
, i
, nEndGlyphPos
) )
1650 for(; i
< nEndGlyphPos
; ++i
)
1651 nXOffset
+= mpGlyphAdvances
[ i
];
1653 // TODO: shrink glyphpos limits to match charpos/fallback limits
1654 //pVI->mnMinGlyphPos = nMinGlyphPos;
1655 //pVI->mnEndGlyphPos = nEndGlyphPos;
1657 // drop the superfluous context glyphs
1658 TIntVector::const_iterator it
= aDropChars
.begin();
1659 while( it
!= aDropChars
.end() )
1661 // find matching "drop range"
1662 int nMinDropPos
= *(it
++); // begin of drop range
1663 if( nMinDropPos
>= rVisualItem
.mnEndCharPos
)
1665 int nEndDropPos
= *(it
++); // end of drop range
1666 if( nEndDropPos
<= rVisualItem
.mnMinCharPos
)
1668 // clip "drop range" to visual item's char range
1669 if( nMinDropPos
<= rVisualItem
.mnMinCharPos
)
1671 nMinDropPos
= rVisualItem
.mnMinCharPos
;
1672 // drop the whole visual item if possible
1673 if( nEndDropPos
>= rVisualItem
.mnEndCharPos
)
1675 rVisualItem
.mnEndGlyphPos
= 0;
1679 if( nEndDropPos
> rVisualItem
.mnEndCharPos
)
1680 nEndDropPos
= rVisualItem
.mnEndCharPos
;
1682 // drop the glyphs which correspond to the charpos range
1683 // drop the corresponding glyphs in the cluster
1684 for( int c
= nMinDropPos
; c
< nEndDropPos
; ++c
)
1686 int nGlyphPos
= mpLogClusters
[c
] + rVisualItem
.mnMinGlyphPos
;
1687 // no need to bother when the cluster was already dropped
1688 if( mpOutGlyphs
[ nGlyphPos
] != DROPPED_OUTGLYPH
)
1692 mpOutGlyphs
[ nGlyphPos
] = DROPPED_OUTGLYPH
;
1693 // until the end of visual item
1694 if( ++nGlyphPos
>= rVisualItem
.mnEndGlyphPos
)
1696 // until the next cluster start
1697 if( mpVisualAttrs
[ nGlyphPos
].fClusterStart
)
1705 // scale layout metrics if needed
1706 // TODO: does it make the code more simple if the metric scaling
1707 // is moved to the methods that need metric scaling (e.g. FillDXArray())?
1708 if( mfFontScale
!= 1.0 )
1710 mnBaseAdv
= (int)((double)mnBaseAdv
*mfFontScale
);
1712 for( i
= 0; i
< mnItemCount
; ++i
)
1713 mpVisualItems
[i
].mnXOffset
= (int)((double)mpVisualItems
[i
].mnXOffset
*mfFontScale
);
1715 mnBaseAdv
= (int)((double)mnBaseAdv
*mfFontScale
);
1716 for( i
= 0; i
< mnGlyphCount
; ++i
)
1718 mpGlyphAdvances
[i
] = (int)(mpGlyphAdvances
[i
] * mfFontScale
);
1719 mpGlyphOffsets
[i
].du
= (LONG
)(mpGlyphOffsets
[i
].du
* mfFontScale
);
1720 mpGlyphOffsets
[i
].dv
= (LONG
)(mpGlyphOffsets
[i
].dv
* mfFontScale
);
1721 // mpJustifications are still NULL
1724 for( i
= mnSubStringMin
; i
< nSubStringEnd
; ++i
)
1725 mpCharWidths
[i
] = (int)(mpCharWidths
[i
] * mfFontScale
);
1731 // -----------------------------------------------------------------------
1733 // calculate the range of relevant glyphs for this visual item
1734 bool UniscribeLayout::GetItemSubrange( const VisualItem
& rVisualItem
,
1735 int& rMinGlyphPos
, int& rEndGlyphPos
) const
1737 // return early when nothing of interest in this item
1738 if( rVisualItem
.IsEmpty()
1739 || (rVisualItem
.mnEndCharPos
<= mnMinCharPos
)
1740 || (mnEndCharPos
<= rVisualItem
.mnMinCharPos
) )
1743 // default: subrange is complete range
1744 rMinGlyphPos
= rVisualItem
.mnMinGlyphPos
;
1745 rEndGlyphPos
= rVisualItem
.mnEndGlyphPos
;
1747 // return early when the whole item is of interest
1748 if( (mnMinCharPos
<= rVisualItem
.mnMinCharPos
)
1749 && (rVisualItem
.mnEndCharPos
<= mnEndCharPos
) )
1752 // get glyph range from char range by looking at cluster boundries
1753 // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
1754 rMinGlyphPos
= rVisualItem
.mnEndGlyphPos
;
1755 int nMaxGlyphPos
= 0;
1757 int i
= mnMinCharPos
;
1758 if( i
< rVisualItem
.mnMinCharPos
)
1759 i
= rVisualItem
.mnMinCharPos
;
1760 int nCharPosLimit
= rVisualItem
.mnEndCharPos
;
1761 if( nCharPosLimit
> mnEndCharPos
)
1762 nCharPosLimit
= mnEndCharPos
;
1763 for(; i
< nCharPosLimit
; ++i
)
1765 int n
= mpLogClusters
[ i
] + rVisualItem
.mnMinGlyphPos
;
1766 if( rMinGlyphPos
> n
)
1768 if( nMaxGlyphPos
< n
)
1771 if (nMaxGlyphPos
> rVisualItem
.mnEndGlyphPos
)
1772 nMaxGlyphPos
= rVisualItem
.mnEndGlyphPos
- 1;
1774 // extend the glyph range to account for all glyphs in referenced clusters
1775 if( !rVisualItem
.IsRTL() ) // LTR-item
1777 // extend to rightmost glyph of rightmost referenced cluster
1778 for( i
= nMaxGlyphPos
; ++i
< rVisualItem
.mnEndGlyphPos
; nMaxGlyphPos
= i
)
1779 if( mpVisualAttrs
[i
].fClusterStart
)
1784 // extend to leftmost glyph of leftmost referenced cluster
1785 for( i
= rMinGlyphPos
; --i
>= rVisualItem
.mnMinGlyphPos
; rMinGlyphPos
= i
)
1786 if( mpVisualAttrs
[i
].fClusterStart
)
1789 rEndGlyphPos
= nMaxGlyphPos
+ 1;
1794 // -----------------------------------------------------------------------
1796 int UniscribeLayout::GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
,
1797 int& nStartx8
, sal_Int32
* pGlyphAdvances
, int* pCharPosAry
) const
1799 // HACK to allow fake-glyph insertion (e.g. for kashidas)
1800 // TODO: use iterator idiom instead of GetNextGlyphs(...)
1801 // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
1802 int nSubIter
= nStartx8
& 0xff;
1803 int nStart
= nStartx8
>> 8;
1805 // check the glyph iterator
1806 if( nStart
> mnGlyphCount
) // nStart>MAX means no more glyphs
1809 // find the visual item for the nStart glyph position
1811 const VisualItem
* pVI
= mpVisualItems
;
1812 if( nStart
<= 0 ) // nStart<=0 requests the first visible glyph
1814 // find first visible item
1815 for(; nItem
< mnItemCount
; ++nItem
, ++pVI
)
1816 if( !pVI
->IsEmpty() )
1818 // it is possible that there are glyphs but no valid visual item
1819 // TODO: get rid of these visual items more early
1820 if( nItem
< mnItemCount
)
1821 nStart
= pVI
->mnMinGlyphPos
;
1823 else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1
1827 // find matching item
1828 for(; nItem
< mnItemCount
; ++nItem
, ++pVI
)
1829 if( (nStart
>= pVI
->mnMinGlyphPos
)
1830 && (nStart
< pVI
->mnEndGlyphPos
) )
1834 // after the last visual item there are no more glyphs
1835 if( (nItem
>= mnItemCount
) || (nStart
< 0) )
1837 nStartx8
= (mnGlyphCount
+ 1) << 8;
1841 // calculate the first glyph in the next visual item
1842 int nNextItemStart
= mnGlyphCount
;
1843 while( ++nItem
< mnItemCount
)
1845 if( mpVisualItems
[nItem
].IsEmpty() )
1847 nNextItemStart
= mpVisualItems
[nItem
].mnMinGlyphPos
;
1851 // get the range of relevant glyphs in this visual item
1852 int nMinGlyphPos
, nEndGlyphPos
;
1853 bool bRC
= GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
);
1854 DBG_ASSERT( bRC
, "USPLayout::GNG GISR() returned false" );
1857 nStartx8
= (mnGlyphCount
+ 1) << 8;
1861 // make sure nStart is inside the range of relevant glyphs
1862 if( nStart
< nMinGlyphPos
)
1863 nStart
= nMinGlyphPos
;
1865 // calculate the start glyph xoffset relative to layout's base position,
1866 // advance to next visual glyph position by using adjusted glyph widths
1867 // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
1868 long nXOffset
= pVI
->mnXOffset
;
1869 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
1870 for( int i
= nMinGlyphPos
; i
< nStart
; ++i
)
1871 nXOffset
+= pGlyphWidths
[ i
];
1873 // adjust the nXOffset relative to glyph cluster start
1874 int c
= mnMinCharPos
;
1875 if( !pVI
->IsRTL() ) // LTR-case
1877 // LTR case: subtract the remainder of the cell from xoffset
1878 int nTmpIndex
= mpLogClusters
[c
];
1879 while( (--c
>= pVI
->mnMinCharPos
)
1880 && (nTmpIndex
== mpLogClusters
[c
]) )
1881 nXOffset
-= mpCharWidths
[c
];
1885 // RTL case: add the remainder of the cell from xoffset
1886 int nTmpIndex
= mpLogClusters
[ pVI
->mnEndCharPos
- 1 ];
1887 while( (--c
>= pVI
->mnMinCharPos
)
1888 && (nTmpIndex
== mpLogClusters
[c
]) )
1889 nXOffset
+= mpCharWidths
[c
];
1891 // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
1892 if( mpJustifications
&& !bManualCellAlign
)
1893 nXOffset
+= mpJustifications
[ nStart
] - mpGlyphAdvances
[ nStart
];
1896 // create mpGlyphs2Chars[] if it is needed later
1897 if( pCharPosAry
&& !mpGlyphs2Chars
)
1899 // create and reset the new array
1900 mpGlyphs2Chars
= new int[ mnGlyphCapacity
];
1901 for( int i
= 0; i
< mnGlyphCount
; ++i
)
1902 mpGlyphs2Chars
[i
] = -1;
1903 // calculate the char->glyph mapping
1904 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1906 // ignore invisible visual items
1907 const VisualItem
& rVI
= mpVisualItems
[ nItem
];
1910 // calculate the mapping by using mpLogClusters[]
1911 // mpGlyphs2Chars[] should obey the logical order
1912 // => reversing the loop does this by overwriting higher logicals
1913 for( c
= rVI
.mnEndCharPos
; --c
>= rVI
.mnMinCharPos
; )
1915 int i
= mpLogClusters
[c
] + rVI
.mnMinGlyphPos
;
1916 mpGlyphs2Chars
[i
] = c
;
1921 // calculate the absolute position of the first result glyph in pixel units
1922 const GOFFSET aGOffset
= mpGlyphOffsets
[ nStart
];
1923 Point
aRelativePos( nXOffset
+ aGOffset
.du
, -aGOffset
.dv
);
1924 rPos
= GetDrawPosition( aRelativePos
);
1926 // fill the result arrays
1928 while( nCount
< nLen
)
1930 // prepare return values
1931 sal_GlyphId aGlyphId
= mpOutGlyphs
[ nStart
];
1932 int nGlyphWidth
= pGlyphWidths
[ nStart
];
1933 int nCharPos
= -1; // no need to determine charpos
1934 if( mpGlyphs2Chars
) // unless explicitly requested+provided
1935 nCharPos
= mpGlyphs2Chars
[ nStart
];
1937 // inject kashida glyphs if needed
1938 if( !mbDisableGlyphInjection
1940 && mnMinKashidaWidth
1941 && mpVisualAttrs
[nStart
].uJustification
>= SCRIPT_JUSTIFY_ARABIC_NORMAL
)
1943 // prepare draw position adjustment
1944 int nExtraOfs
= (nSubIter
++) * mnMinKashidaWidth
;
1945 // calculate space available for the injected glyphs
1946 nGlyphWidth
= mpGlyphAdvances
[ nStart
];
1947 const int nExtraWidth
= mpJustifications
[ nStart
] - nGlyphWidth
;
1948 const int nToFillWidth
= nExtraWidth
- nExtraOfs
;
1949 if( (4*nToFillWidth
>= mnMinKashidaWidth
) // prevent glyph-injection if there is no room
1950 || ((nSubIter
> 1) && (nToFillWidth
> 0)) ) // unless they can overlap with others
1952 // handle if there is not sufficient room for a full glyph
1953 if( nToFillWidth
< mnMinKashidaWidth
)
1955 // overlap it with the previously injected glyph if possible
1956 int nOverlap
= mnMinKashidaWidth
- nToFillWidth
;
1957 // else overlap it with both neighboring glyphs
1960 nExtraOfs
-= nOverlap
;
1962 nGlyphWidth
= mnMinKashidaWidth
;
1963 aGlyphId
= mnMinKashidaGlyph
;
1968 nExtraOfs
+= nToFillWidth
; // at right of cell
1969 nSubIter
= 0; // done with glyph injection
1971 if( !bManualCellAlign
)
1972 nExtraOfs
-= nExtraWidth
; // adjust for right-aligned cells
1974 // adjust the draw position for the injected-glyphs case
1977 aRelativePos
.X() += nExtraOfs
;
1978 rPos
= GetDrawPosition( aRelativePos
);
1982 // update return values
1983 *(pGlyphs
++) = aGlyphId
;
1984 if( pGlyphAdvances
)
1985 *(pGlyphAdvances
++) = nGlyphWidth
;
1987 *(pCharPosAry
++) = nCharPos
;
1989 // increment counter of returned glyphs
1992 // reduce code complexity by returning early in glyph-injection case
1996 // stop after the last visible glyph in this visual item
1997 if( ++nStart
>= nEndGlyphPos
)
1999 nStart
= nNextItemStart
;
2003 // RTL-justified glyph positioning is not easy
2004 // simplify the code by just returning only one glyph at a time
2005 if( mpJustifications
&& pVI
->IsRTL() )
2008 // stop when the x-position of the next glyph is unexpected
2009 if( !pGlyphAdvances
)
2010 if( (mpGlyphOffsets
&& (mpGlyphOffsets
[nStart
].du
!= aGOffset
.du
) )
2011 || (mpJustifications
&& (mpJustifications
[nStart
] != mpGlyphAdvances
[nStart
]) ) )
2014 // stop when the y-position of the next glyph is unexpected
2015 if( mpGlyphOffsets
&& (mpGlyphOffsets
[nStart
].dv
!= aGOffset
.dv
) )
2020 nStartx8
= (nStart
<< 8) + nSubIter
;
2024 // -----------------------------------------------------------------------
2026 void UniscribeLayout::MoveGlyph( int nStartx8
, long nNewXPos
)
2028 DBG_ASSERT( !(nStartx8
& 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
2029 int nStart
= nStartx8
>> 8;
2030 if( nStart
> mnGlyphCount
)
2033 VisualItem
* pVI
= mpVisualItems
;
2034 int nMinGlyphPos
= 0, nEndGlyphPos
;
2035 if( nStart
== 0 ) // nStart==0 for first visible glyph
2037 for( int i
= mnItemCount
; --i
>= 0; ++pVI
)
2038 if( GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
) )
2040 nStart
= nMinGlyphPos
;
2041 DBG_ASSERT( nStart
<= mnGlyphCount
, "USPLayout::MoveG overflow" );
2043 else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1
2046 for( int i
= mnItemCount
; --i
>= 0; ++pVI
)
2047 if( (nStart
>= pVI
->mnMinGlyphPos
) && (nStart
< pVI
->mnEndGlyphPos
) )
2049 bool bRC
= GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
);
2050 (void)bRC
; // avoid var-not-used warning
2051 DBG_ASSERT( bRC
, "USPLayout::MoveG GISR() returned false" );
2054 long nDelta
= nNewXPos
- pVI
->mnXOffset
;
2055 if( nStart
> nMinGlyphPos
)
2057 // move the glyph by expanding its left glyph but ignore dropped glyphs
2058 int i
, nLastUndropped
= nMinGlyphPos
- 1;
2059 for( i
= nMinGlyphPos
; i
< nStart
; ++i
)
2061 if (mpOutGlyphs
[i
] != DROPPED_OUTGLYPH
)
2063 nDelta
-= (mpJustifications
)? mpJustifications
[ i
] : mpGlyphAdvances
[ i
];
2067 if (nLastUndropped
>= nMinGlyphPos
)
2069 mpGlyphAdvances
[ nLastUndropped
] += nDelta
;
2070 if (mpJustifications
) mpJustifications
[ nLastUndropped
] += nDelta
;
2074 pVI
->mnXOffset
+= nDelta
;
2079 // move the visual item by having an offset
2080 pVI
->mnXOffset
+= nDelta
;
2084 // -----------------------------------------------------------------------
2086 void UniscribeLayout::DropGlyph( int nStartx8
)
2088 DBG_ASSERT( !(nStartx8
& 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
2089 int nStart
= nStartx8
>> 8;
2090 DBG_ASSERT( nStart
<=mnGlyphCount
, "USPLayout::MoveG nStart overflow" );
2092 if( nStart
> 0 ) // nStart>0 means absolute glyph pos + 1
2094 else // nStart<=0 for first visible glyph
2096 VisualItem
* pVI
= mpVisualItems
;
2097 for( int i
= mnItemCount
, nDummy
; --i
>= 0; ++pVI
)
2098 if( GetItemSubrange( *pVI
, nStart
, nDummy
) )
2100 DBG_ASSERT( nStart
<= mnGlyphCount
, "USPLayout::DropG overflow" );
2102 int j
= pVI
->mnMinGlyphPos
;
2103 while (mpOutGlyphs
[j
] == DROPPED_OUTGLYPH
) j
++;
2106 pVI
->mnXOffset
+= ((mpJustifications
)? mpJustifications
[nStart
] : mpGlyphAdvances
[nStart
]);
2110 mpOutGlyphs
[ nStart
] = DROPPED_OUTGLYPH
;
2113 // -----------------------------------------------------------------------
2115 void UniscribeLayout::Simplify( bool /*bIsBase*/ )
2117 static const WCHAR cDroppedGlyph
= DROPPED_OUTGLYPH
;
2119 // if there are no dropped glyphs don't bother
2120 for( i
= 0; i
< mnGlyphCount
; ++i
)
2121 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2123 if( i
>= mnGlyphCount
)
2126 // prepare for sparse layout
2127 // => make sure mpGlyphs2Chars[] exists
2128 if( !mpGlyphs2Chars
)
2130 mpGlyphs2Chars
= new int[ mnGlyphCapacity
];
2131 for( i
= 0; i
< mnGlyphCount
; ++i
)
2132 mpGlyphs2Chars
[ i
] = -1;
2133 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2135 // skip invisible items
2136 VisualItem
& rVI
= mpVisualItems
[ nItem
];
2139 for( i
= rVI
.mnEndCharPos
; --i
>= rVI
.mnMinCharPos
; )
2141 int j
= mpLogClusters
[ i
] + rVI
.mnMinGlyphPos
;
2142 mpGlyphs2Chars
[ j
] = i
;
2147 // remove the dropped glyphs
2148 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
2149 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2151 VisualItem
& rVI
= mpVisualItems
[ nItem
];
2155 // mark replaced character widths
2156 for( i
= rVI
.mnMinCharPos
; i
< rVI
.mnEndCharPos
; ++i
)
2158 int j
= mpLogClusters
[ i
] + rVI
.mnMinGlyphPos
;
2159 if( mpOutGlyphs
[ j
] == cDroppedGlyph
)
2160 mpCharWidths
[ i
] = 0;
2163 // handle dropped glyphs at start of visual item
2164 int nMinGlyphPos
, nEndGlyphPos
, nOrigMinGlyphPos
= rVI
.mnMinGlyphPos
;
2165 GetItemSubrange( rVI
, nMinGlyphPos
, nEndGlyphPos
);
2167 while( (mpOutGlyphs
[i
] == cDroppedGlyph
) && (i
< nEndGlyphPos
) )
2169 //rVI.mnXOffset += pGlyphWidths[ i ];
2170 rVI
.mnMinGlyphPos
= ++i
;
2173 // when all glyphs in item got dropped mark it as empty
2174 if( i
>= nEndGlyphPos
)
2176 rVI
.mnEndGlyphPos
= 0;
2179 // If there are still glyphs in the cluster and mnMinGlyphPos
2180 // has changed then we need to remove the dropped glyphs at start
2181 // to correct logClusters, which is unsigned and relative to the
2183 if (rVI
.mnMinGlyphPos
!= nOrigMinGlyphPos
)
2185 // drop any glyphs in the visual item outside the range
2186 for (i
= nOrigMinGlyphPos
; i
< nMinGlyphPos
; i
++)
2187 mpOutGlyphs
[ i
] = cDroppedGlyph
;
2188 rVI
.mnMinGlyphPos
= i
= nOrigMinGlyphPos
;
2191 // handle dropped glyphs in the middle of visual item
2192 for(; i
< nEndGlyphPos
; ++i
)
2193 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2196 while( ++i
< nEndGlyphPos
)
2198 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2200 mpOutGlyphs
[ j
] = mpOutGlyphs
[ i
];
2201 mpGlyphOffsets
[ j
] = mpGlyphOffsets
[ i
];
2202 mpVisualAttrs
[ j
] = mpVisualAttrs
[ i
];
2203 mpGlyphAdvances
[ j
] = mpGlyphAdvances
[ i
];
2204 if( mpJustifications
)
2205 mpJustifications
[ j
] = mpJustifications
[ i
];
2206 const int k
= mpGlyphs2Chars
[ i
];
2207 mpGlyphs2Chars
[ j
] = k
;
2208 const int nRelGlyphPos
= (j
++) - rVI
.mnMinGlyphPos
;
2209 mpLogClusters
[ k
] = static_cast<WORD
>(nRelGlyphPos
);
2212 rVI
.mnEndGlyphPos
= j
;
2216 // -----------------------------------------------------------------------
2218 void UniscribeLayout::DrawText( SalGraphics
& ) const
2220 HFONT hOrigFont
= DisableFontScaling();
2222 int nBaseClusterOffset
= 0;
2223 int nBaseGlyphPos
= -1;
2224 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2226 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2228 // skip if there is nothing to display
2229 int nMinGlyphPos
, nEndGlyphPos
;
2230 if( !GetItemSubrange( rVisualItem
, nMinGlyphPos
, nEndGlyphPos
) )
2233 if( nBaseGlyphPos
< 0 )
2235 // adjust draw position relative to cluster start
2236 if( rVisualItem
.IsRTL() )
2237 nBaseGlyphPos
= nEndGlyphPos
- 1;
2239 nBaseGlyphPos
= nMinGlyphPos
;
2241 const int* pGlyphWidths
;
2242 if( mpJustifications
)
2243 pGlyphWidths
= mpJustifications
;
2245 pGlyphWidths
= mpGlyphAdvances
;
2247 int i
= mnMinCharPos
;
2248 while( (--i
>= rVisualItem
.mnMinCharPos
)
2249 && (nBaseGlyphPos
== mpLogClusters
[i
]) )
2250 nBaseClusterOffset
+= mpCharWidths
[i
];
2252 if( !rVisualItem
.IsRTL() )
2253 nBaseClusterOffset
= -nBaseClusterOffset
;
2256 // now draw the matching glyphs in this item
2257 Point
aRelPos( rVisualItem
.mnXOffset
+ nBaseClusterOffset
, 0 );
2258 Point aPos
= GetDrawPosition( aRelPos
);
2259 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
2260 (*pScriptTextOut
)( mhDC
, &rScriptCache
,
2261 aPos
.X(), aPos
.Y(), 0, NULL
,
2262 &rVisualItem
.mpScriptItem
->a
, NULL
, 0,
2263 mpOutGlyphs
+ nMinGlyphPos
,
2264 nEndGlyphPos
- nMinGlyphPos
,
2265 mpGlyphAdvances
+ nMinGlyphPos
,
2266 mpJustifications
? mpJustifications
+ nMinGlyphPos
: NULL
,
2267 mpGlyphOffsets
+ nMinGlyphPos
);
2271 DeleteFont( SelectFont( mhDC
, hOrigFont
) );
2274 // -----------------------------------------------------------------------
2276 long UniscribeLayout::FillDXArray( long* pDXArray
) const
2278 // calculate width of the complete layout
2279 long nWidth
= mnBaseAdv
;
2280 for( int nItem
= mnItemCount
; --nItem
>= 0; )
2282 const VisualItem
& rVI
= mpVisualItems
[ nItem
];
2284 // skip if there is nothing to display
2285 int nMinGlyphPos
, nEndGlyphPos
;
2286 if( !GetItemSubrange( rVI
, nMinGlyphPos
, nEndGlyphPos
) )
2289 // width = xoffset + width of last item
2290 nWidth
= rVI
.mnXOffset
;
2291 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
2292 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2293 nWidth
+= pGlyphWidths
[i
];
2297 // copy the virtual char widths into pDXArray[]
2299 for( int i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2300 pDXArray
[ i
- mnMinCharPos
] = mpCharWidths
[ i
];
2305 // -----------------------------------------------------------------------
2307 int UniscribeLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
2310 for( int i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2312 nWidth
+= mpCharWidths
[ i
] * nFactor
;
2314 // check if the nMaxWidth still fits the current sub-layout
2315 if( nWidth
>= nMaxWidth
)
2317 // go back to cluster start
2318 // we have to find the visual item first since the mpLogClusters[]
2319 // needed to find the cluster start is relative to to the visual item
2320 int nMinGlyphIndex
= 0;
2321 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2323 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2324 nMinGlyphIndex
= rVisualItem
.mnMinGlyphPos
;
2325 if( (i
>= rVisualItem
.mnMinCharPos
)
2326 && (i
< rVisualItem
.mnEndCharPos
) )
2329 // now go back to the matching cluster start
2332 int nGlyphPos
= mpLogClusters
[i
] + nMinGlyphIndex
;
2333 if( 0 != mpVisualAttrs
[ nGlyphPos
].fClusterStart
)
2335 } while( --i
>= mnMinCharPos
);
2337 // if the cluster starts before the start of the visual item
2338 // then set the visual breakpoint before this item
2339 return mnMinCharPos
;
2342 // the visual break also depends on the nCharExtra between the characters
2343 nWidth
+= nCharExtra
;
2346 // the whole layout did fit inside the nMaxWidth
2350 // -----------------------------------------------------------------------
2352 void UniscribeLayout::GetCaretPositions( int nMaxIdx
, long* pCaretXArray
) const
2355 for( i
= 0; i
< nMaxIdx
; ++i
)
2356 pCaretXArray
[ i
] = -1;
2357 long* const pGlyphPos
= (long*)alloca( (mnGlyphCount
+1) * sizeof(long) );
2358 for( i
= 0; i
<= mnGlyphCount
; ++i
)
2359 pGlyphPos
[ i
] = -1;
2362 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2364 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2365 if( rVisualItem
.IsEmpty() )
2368 // get glyph positions
2369 // TODO: handle when rVisualItem's glyph range is only partially used
2370 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2372 pGlyphPos
[ i
] = nXPos
;
2373 nXPos
+= mpGlyphAdvances
[ i
];
2375 // rightmost position of this visualitem
2376 pGlyphPos
[ i
] = nXPos
;
2378 // convert glyph positions to character positions
2379 i
= rVisualItem
.mnMinCharPos
;
2380 if( i
< mnMinCharPos
)
2382 for(; (i
< rVisualItem
.mnEndCharPos
) && (i
< mnEndCharPos
); ++i
)
2384 int j
= mpLogClusters
[ i
] + rVisualItem
.mnMinGlyphPos
;
2385 int nCurrIdx
= i
* 2;
2386 if( !rVisualItem
.IsRTL() )
2388 // normal positions for LTR case
2389 pCaretXArray
[ nCurrIdx
] = pGlyphPos
[ j
];
2390 pCaretXArray
[ nCurrIdx
+1 ] = pGlyphPos
[ j
+1 ];
2394 // reverse positions for RTL case
2395 pCaretXArray
[ nCurrIdx
] = pGlyphPos
[ j
+1 ];
2396 pCaretXArray
[ nCurrIdx
+1 ] = pGlyphPos
[ j
];
2401 // fixup unknown character positions to neighbor
2402 for( i
= 0; i
< nMaxIdx
; ++i
)
2404 if( pCaretXArray
[ i
] >= 0 )
2405 nXPos
= pCaretXArray
[ i
];
2407 pCaretXArray
[ i
] = nXPos
;
2411 // -----------------------------------------------------------------------
2413 void UniscribeLayout::AdjustLayout( ImplLayoutArgs
& rArgs
)
2415 SalLayout::AdjustLayout( rArgs
);
2417 // adjust positions if requested
2418 if( rArgs
.mpDXArray
)
2419 ApplyDXArray( rArgs
);
2420 else if( rArgs
.mnLayoutWidth
)
2421 Justify( rArgs
.mnLayoutWidth
);
2424 // -----------------------------------------------------------------------
2426 void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs
& rArgs
)
2428 const long* pDXArray
= rArgs
.mpDXArray
;
2430 // increase char widths in string range to desired values
2431 bool bModified
= false;
2433 DBG_ASSERT( mnUnitsPerPixel
==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
2435 for( i
= mnMinCharPos
, j
= 0; i
< mnEndCharPos
; ++i
, ++j
)
2437 int nNewCharWidth
= (pDXArray
[j
] - nOldWidth
);
2438 // TODO: nNewCharWidth *= mnUnitsPerPixel;
2439 if( mpCharWidths
[i
] != nNewCharWidth
)
2441 mpCharWidths
[i
] = nNewCharWidth
;
2444 nOldWidth
= pDXArray
[j
];
2450 // initialize justifications array
2451 mpJustifications
= new int[ mnGlyphCapacity
];
2452 for( i
= 0; i
< mnGlyphCount
; ++i
)
2453 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2455 // apply new widths to script items
2457 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2459 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2461 // set the position of this visual item
2462 rVisualItem
.mnXOffset
= nXOffset
;
2464 // ignore empty visual items
2465 if( rVisualItem
.IsEmpty() )
2467 for (i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; i
++)
2468 nXOffset
+= mpCharWidths
[i
];
2471 // ignore irrelevant visual items
2472 if( (rVisualItem
.mnMinCharPos
>= mnEndCharPos
)
2473 || (rVisualItem
.mnEndCharPos
<= mnMinCharPos
) )
2476 // if needed prepare special handling for arabic justification
2477 rVisualItem
.mbHasKashidas
= false;
2478 if( rVisualItem
.IsRTL() )
2480 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2481 if ( (1U << mpVisualAttrs
[i
].uJustification
) & 0xFF82 ) // any Arabic justification
2482 { // excluding SCRIPT_JUSTIFY_NONE
2484 rVisualItem
.mbHasKashidas
= true;
2485 // so prepare for kashida handling
2486 InitKashidaHandling();
2490 if( rVisualItem
.HasKashidas() )
2491 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2493 // TODO: check if we still need this hack after correction of kashida placing?
2494 // (i87688): apparently yes, we still need it!
2495 if ( mpVisualAttrs
[i
].uJustification
== SCRIPT_JUSTIFY_NONE
)
2496 // usp decided that justification can't be applied here
2497 // but maybe our Kashida algorithm thinks differently.
2498 // To avoid trouble (gaps within words, last character of
2499 // a word gets a Kashida appended) override this.
2501 // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
2502 // just because this previous hack (which I haven't understand, sorry) used
2503 // the same value to replace. Don't know if this is really the best
2504 // thing to do, but it seems to fix things
2505 mpVisualAttrs
[i
].uJustification
= SCRIPT_JUSTIFY_ARABIC_KASHIDA
;
2509 // convert virtual charwidths to glyph justification values
2510 HRESULT nRC
= (*pScriptApplyLogicalWidth
)(
2511 mpCharWidths
+ rVisualItem
.mnMinCharPos
,
2512 rVisualItem
.mnEndCharPos
- rVisualItem
.mnMinCharPos
,
2513 rVisualItem
.mnEndGlyphPos
- rVisualItem
.mnMinGlyphPos
,
2514 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
2515 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
2516 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
2517 &rVisualItem
.mpScriptItem
->a
,
2518 &rVisualItem
.maABCWidths
,
2519 mpJustifications
+ rVisualItem
.mnMinGlyphPos
);
2523 delete[] mpJustifications
;
2524 mpJustifications
= NULL
;
2528 // to prepare for the next visual item
2529 // update nXOffset to the next items position
2530 // before the mpJustifications[] array gets modified
2531 int nMinGlyphPos
, nEndGlyphPos
;
2532 if( GetItemSubrange( rVisualItem
, nMinGlyphPos
, nEndGlyphPos
) )
2534 for( i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2535 nXOffset
+= mpJustifications
[ i
];
2537 if( rVisualItem
.mbHasKashidas
)
2538 KashidaItemFix( nMinGlyphPos
, nEndGlyphPos
);
2541 // workaround needed for older USP versions:
2542 // right align the justification-adjusted glyphs in their cells for RTL-items
2543 // unless the right alignment is done by inserting kashidas
2544 if( bManualCellAlign
&& rVisualItem
.IsRTL() && !rVisualItem
.HasKashidas() )
2546 for( i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2548 const int nXOffsetAdjust
= mpJustifications
[i
] - mpGlyphAdvances
[i
];
2549 // #i99862# skip diacritics, we mustn't add extra justification to diacritics
2550 int nIdxAdd
= i
- 1;
2551 while( (nIdxAdd
>= nMinGlyphPos
) && !mpGlyphAdvances
[nIdxAdd
] )
2553 if( nIdxAdd
< nMinGlyphPos
)
2554 rVisualItem
.mnXOffset
+= nXOffsetAdjust
;
2556 mpJustifications
[nIdxAdd
] += nXOffsetAdjust
;
2557 mpJustifications
[i
] -= nXOffsetAdjust
;
2563 // -----------------------------------------------------------------------
2565 void UniscribeLayout::InitKashidaHandling()
2567 if( mnMinKashidaGlyph
!= 0 ) // already initialized
2570 mrWinFontEntry
.InitKashidaHandling( mhDC
);
2571 mnMinKashidaWidth
= static_cast<int>(mfFontScale
* mrWinFontEntry
.GetMinKashidaWidth());
2572 mnMinKashidaGlyph
= mrWinFontEntry
.GetMinKashidaGlyph();
2575 // adjust the kashida placement matching to the WriterEngine
2576 void UniscribeLayout::KashidaItemFix( int nMinGlyphPos
, int nEndGlyphPos
)
2578 // workaround needed for all known USP versions:
2579 // ApplyLogicalWidth does not match ScriptJustify behaviour
2580 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2583 if( (i
> nMinGlyphPos
&& !mpGlyphAdvances
[ i
-1 ])
2584 && (1U << mpVisualAttrs
[i
].uJustification
) & 0xFF83 ) // all Arabic justifiction types
2585 { // including SCRIPT_JUSTIFY_NONE
2586 // vowel, we do it like ScriptJustify does
2587 // the vowel gets the extra width
2588 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2589 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2590 mpJustifications
[ i
- 1 ] += nSpaceAdded
;
2594 // redistribute the widths for kashidas
2595 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; )
2596 KashidaWordFix ( nMinGlyphPos
, nEndGlyphPos
, &i
);
2599 bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos
, int nEndGlyphPos
, int* pnCurrentPos
)
2601 // doing pixel work within a word.
2602 // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
2604 // find the next kashida
2605 int nMinPos
= *pnCurrentPos
;
2606 int nMaxPos
= *pnCurrentPos
;
2607 for( int i
= nMaxPos
; i
< nEndGlyphPos
; ++i
)
2609 if( (mpVisualAttrs
[ i
].uJustification
>= SCRIPT_JUSTIFY_ARABIC_BLANK
)
2610 && (mpVisualAttrs
[ i
].uJustification
< SCRIPT_JUSTIFY_ARABIC_NORMAL
) )
2614 *pnCurrentPos
= nMaxPos
+ 1;
2615 if( nMinPos
== nMaxPos
)
2618 // calculate the available space for an extra kashida
2621 for( int i
= nMaxPos
; i
>= nMinPos
; --i
)
2623 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2624 if( nSpaceAdded
> nMaxAdded
)
2627 nMaxAdded
= nSpaceAdded
;
2631 // return early if there is no need for an extra kashida
2632 if ( nMaxAdded
<= 0 )
2634 // return early if there is not enough space for an extra kashida
2635 if( 2*nMaxAdded
< mnMinKashidaWidth
)
2638 // redistribute the extra spacing to the kashida position
2639 for( int i
= nMinPos
; i
<= nMaxPos
; ++i
)
2643 // everything else should not have extra spacing
2644 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2645 if( nSpaceAdded
> 0 )
2647 mpJustifications
[ i
] -= nSpaceAdded
;
2648 mpJustifications
[ nKashPos
] += nSpaceAdded
;
2652 // check if we fulfill minimal kashida width
2653 long nSpaceAdded
= mpJustifications
[ nKashPos
] - mpGlyphAdvances
[ nKashPos
];
2654 if( nSpaceAdded
< mnMinKashidaWidth
)
2656 // ugly: steal some pixels
2658 if ( nMaxPos
- nMinPos
> 0 && ((mnMinKashidaWidth
- nSpaceAdded
) > (nMaxPos
- nMinPos
)))
2659 nSteal
= (mnMinKashidaWidth
- nSpaceAdded
) / (nMaxPos
- nMinPos
);
2660 for( int i
= nMinPos
; i
<= nMaxPos
; ++i
)
2664 nSteal
= Min( mnMinKashidaWidth
- nSpaceAdded
, nSteal
);
2667 mpJustifications
[ i
] -= nSteal
;
2668 mpJustifications
[ nKashPos
] += nSteal
;
2669 nSpaceAdded
+= nSteal
;
2671 if( nSpaceAdded
>= mnMinKashidaWidth
)
2677 long nSpaceMissing
= mnMinKashidaWidth
- nSpaceAdded
;
2678 if( nSpaceMissing
> 0 )
2680 // inner glyph: distribute extra space evenly
2681 if( (nMinPos
> nMinGlyphPos
) && (nMaxPos
< nEndGlyphPos
- 1) )
2683 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2684 long nHalfSpace
= nSpaceMissing
/ 2;
2685 mpJustifications
[ nMinPos
- 1 ] -= nHalfSpace
;
2686 mpJustifications
[ nMaxPos
+ 1 ] -= nSpaceMissing
- nHalfSpace
;
2688 // rightmost: left glyph gets extra space
2689 else if( nMinPos
> nMinGlyphPos
)
2691 mpJustifications
[ nMinPos
- 1 ] -= nSpaceMissing
;
2692 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2694 // leftmost: right glyph gets extra space
2695 else if( nMaxPos
< nEndGlyphPos
- 1 )
2697 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2698 mpJustifications
[ nMaxPos
+ 1 ] -= nSpaceMissing
;
2707 // -----------------------------------------------------------------------
2709 void UniscribeLayout::Justify( long nNewWidth
)
2713 for( i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2714 nOldWidth
+= mpCharWidths
[ i
];
2715 if( nOldWidth
<= 0 )
2718 nNewWidth
*= mnUnitsPerPixel
; // convert into font units
2719 if( nNewWidth
== nOldWidth
)
2721 // prepare to distribute the extra width evenly among the visual items
2722 const double fStretch
= (double)nNewWidth
/ nOldWidth
;
2724 // initialize justifications array
2725 mpJustifications
= new int[ mnGlyphCapacity
];
2726 for( i
= 0; i
< mnGlyphCapacity
; ++i
)
2727 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2729 // justify stretched script items
2731 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
2732 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2734 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2735 if( rVisualItem
.IsEmpty() )
2738 if( (rVisualItem
.mnMinCharPos
< mnEndCharPos
)
2739 && (rVisualItem
.mnEndCharPos
> mnMinCharPos
) )
2741 long nItemWidth
= 0;
2742 for( i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; ++i
)
2743 nItemWidth
+= mpCharWidths
[ i
];
2744 nItemWidth
= (int)((fStretch
- 1.0) * nItemWidth
+ 0.5);
2746 HRESULT nRC
= (*pScriptJustify
) (
2747 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
2748 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
2749 rVisualItem
.mnEndGlyphPos
- rVisualItem
.mnMinGlyphPos
,
2752 mpJustifications
+ rVisualItem
.mnMinGlyphPos
);
2754 rVisualItem
.mnXOffset
= nXOffset
;
2755 nXOffset
+= nItemWidth
;
2760 // -----------------------------------------------------------------------
2762 bool UniscribeLayout::IsKashidaPosValid ( int nCharPos
) const
2764 // we have to find the visual item first since the mpLogClusters[]
2765 // needed to find the cluster start is relative to to the visual item
2766 int nMinGlyphIndex
= -1;
2767 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2769 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2770 if( (nCharPos
>= rVisualItem
.mnMinCharPos
)
2771 && (nCharPos
< rVisualItem
.mnEndCharPos
) )
2773 nMinGlyphIndex
= rVisualItem
.mnMinGlyphPos
;
2777 // Invalid char pos or leftmost glyph in visual item
2778 if ( nMinGlyphIndex
== -1 || !mpLogClusters
[ nCharPos
] )
2781 // This test didn't give the expected results
2782 /* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
2783 // two chars, one glyph
2786 const int nGlyphPos
= mpLogClusters
[ nCharPos
] + nMinGlyphIndex
;
2787 if( nGlyphPos
<= 0 )
2789 // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
2790 // and not SCRIPT_JUSTIFY_ARABIC_BLANK
2791 // special case: glyph to the left is vowel (no advance width)
2792 if ( mpVisualAttrs
[ nGlyphPos
-1 ].uJustification
== SCRIPT_JUSTIFY_ARABIC_BLANK
2793 || ( mpVisualAttrs
[ nGlyphPos
-1 ].uJustification
== SCRIPT_JUSTIFY_NONE
2794 && mpGlyphAdvances
[ nGlyphPos
-1 ] ))
2799 #endif // USE_UNISCRIBE
2801 #ifdef ENABLE_GRAPHITE
2803 class GraphiteLayoutWinImpl
: public GraphiteLayout
2806 GraphiteLayoutWinImpl(const gr::Font
& font
, ImplWinFontEntry
& rFont
)
2808 : GraphiteLayout(font
), mrFont(rFont
) {};
2809 virtual ~GraphiteLayoutWinImpl() throw() {};
2810 virtual sal_GlyphId
getKashidaGlyph(int & rWidth
);
2812 ImplWinFontEntry
& mrFont
;
2815 sal_GlyphId
GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth
)
2817 rWidth
= mrFont
.GetMinKashidaWidth();
2818 return mrFont
.GetMinKashidaGlyph();
2821 // This class uses the SIL Graphite engine to provide complex text layout services to the VCL
2824 class GraphiteWinLayout
: public WinLayout
2827 mutable gr::WinFont mpFont
;
2828 grutils::GrFeatureParser
* mpFeatures
;
2829 mutable GraphiteLayoutWinImpl maImpl
;
2831 GraphiteWinLayout(HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
);
2833 static bool IsGraphiteEnabledFont(HDC hDC
) throw();
2835 // used by upper layers
2836 virtual bool LayoutText( ImplLayoutArgs
& ); // first step of layout
2837 virtual void AdjustLayout( ImplLayoutArgs
& ); // adjusting after fallback etc.
2838 // virtual void InitFont() const;
2839 virtual void DrawText( SalGraphics
& ) const;
2841 // methods using string indexing
2842 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
=0, int nFactor
=1 ) const;
2843 virtual long FillDXArray( long* pDXArray
) const;
2845 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
2847 // methods using glyph indexing
2848 virtual int GetNextGlyphs(int nLen
, sal_GlyphId
* pGlyphIdxAry
, ::Point
& rPos
, int&,
2849 long* pGlyphAdvAry
= 0, int* pCharPosAry
= 0 ) const;
2851 // used by glyph+font+script fallback
2852 virtual void MoveGlyph( int nStart
, long nNewXPos
);
2853 virtual void DropGlyph( int nStart
);
2854 virtual void Simplify( bool bIsBase
);
2855 ~GraphiteWinLayout() { delete mpFeatures
; mpFeatures
= NULL
; };
2857 virtual void ReplaceDC(gr::Segment
& segment
) const;
2858 virtual void RestoreDC(gr::Segment
& segment
) const;
2861 bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC
) throw()
2863 return gr::WinFont::FontHasGraphiteTables(hDC
);
2866 GraphiteWinLayout::GraphiteWinLayout(HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
) throw()
2867 : WinLayout(hDC
, rWFD
, rWFE
), mpFont(hDC
),
2868 maImpl(mpFont
, rWFE
)
2870 const rtl::OString aLang
= MsLangId::convertLanguageToIsoByteString( rWFE
.maFontSelData
.meLanguage
);
2871 rtl::OString name
= rtl::OUStringToOString(
2872 rWFE
.maFontSelData
.maTargetName
, RTL_TEXTENCODING_UTF8
);
2873 sal_Int32 nFeat
= name
.indexOf(grutils::GrFeatureParser::FEAT_PREFIX
) + 1;
2876 rtl::OString aFeat
= name
.copy(nFeat
, name
.getLength() - nFeat
);
2877 mpFeatures
= new grutils::GrFeatureParser(mpFont
, aFeat
.getStr(), aLang
.getStr());
2881 mpFeatures
= new grutils::GrFeatureParser(mpFont
, aLang
.getStr());
2883 maImpl
.SetFeatures(mpFeatures
);
2886 void GraphiteWinLayout::ReplaceDC(gr::Segment
& segment
) const
2888 COLORREF color
= GetTextColor(mhDC
);
2889 dynamic_cast<gr::WinFont
&>(segment
.getFont()).replaceDC(mhDC
);
2890 SetTextColor(mhDC
, color
);
2893 void GraphiteWinLayout::RestoreDC(gr::Segment
& segment
) const
2895 dynamic_cast<gr::WinFont
&>(segment
.getFont()).restoreDC();
2898 bool GraphiteWinLayout::LayoutText( ImplLayoutArgs
& args
)
2900 HFONT hUnRotatedFont
;
2901 if (args
.mnOrientation
)
2903 // Graphite gets very confused if the font is rotated
2905 ::GetObjectW( mhFont
, sizeof(LOGFONTW
), &aLogFont
);
2906 aLogFont
.lfEscapement
= 0;
2907 aLogFont
.lfOrientation
= 0;
2908 hUnRotatedFont
= ::CreateFontIndirectW( &aLogFont
);
2909 ::SelectFont(mhDC
, hUnRotatedFont
);
2911 WinLayout::AdjustLayout(args
);
2912 mpFont
.replaceDC(mhDC
);
2913 maImpl
.SetFontScale(WinLayout::mfFontScale
);
2914 //bool succeeded = maImpl.LayoutText(args);
2916 GrSegRecord
* pSegRecord
= NULL
;
2917 gr::Segment
* pSegment
= maImpl
.CreateSegment(args
, &pSegRecord
);
2919 gr::Segment
* pSegment
= maImpl
.CreateSegment(args
);
2921 bool bSucceeded
= false;
2924 // replace the DC on the font within the segment
2925 ReplaceDC(*pSegment
);
2926 // create glyph vectors
2928 bSucceeded
= maImpl
.LayoutGlyphs(args
, pSegment
, pSegRecord
);
2930 bSucceeded
= maImpl
.LayoutGlyphs(args
, pSegment
);
2932 // restore original DC
2933 RestoreDC(*pSegment
);
2935 if (pSegRecord
) pSegRecord
->unlock();
2936 else delete pSegment
;
2942 if (args
.mnOrientation
)
2944 // restore the rotated font
2945 ::SelectFont(mhDC
, mhFont
);
2946 ::DeleteObject(hUnRotatedFont
);
2951 void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs
& rArgs
)
2953 WinLayout::AdjustLayout(rArgs
);
2954 maImpl
.DrawBase() = WinLayout::maDrawBase
;
2955 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
2956 if ( (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
) && rArgs
.mpDXArray
)
2958 mrWinFontEntry
.InitKashidaHandling(mhDC
);
2960 maImpl
.AdjustLayout(rArgs
);
2963 void GraphiteWinLayout::DrawText(SalGraphics
&sal_graphics
) const
2965 HFONT hOrigFont
= DisableFontScaling();
2966 HDC aHDC
= static_cast<WinSalGraphics
&>(sal_graphics
).mhDC
;
2967 maImpl
.DrawBase() = WinLayout::maDrawBase
;
2968 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
2969 const int MAX_GLYPHS
= 2;
2970 sal_GlyphId glyphIntStr
[MAX_GLYPHS
];
2971 WORD glyphWStr
[MAX_GLYPHS
];
2977 nGlyphs
= maImpl
.GetNextGlyphs(1, glyphIntStr
, aPos
, glyphIndex
);
2980 std::copy(glyphIntStr
, glyphIntStr
+ nGlyphs
, glyphWStr
);
2981 ::ExtTextOutW(aHDC
, aPos
.X(), aPos
.Y(), ETO_GLYPH_INDEX
,
2982 NULL
, (LPCWSTR
)&(glyphWStr
), nGlyphs
, NULL
);
2985 DeleteFont( SelectFont( mhDC
, hOrigFont
) );
2988 int GraphiteWinLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
2990 mpFont
.replaceDC(mhDC
);
2991 int nBreak
= maImpl
.GetTextBreak(nMaxWidth
, nCharExtra
, nFactor
);
2996 long GraphiteWinLayout::FillDXArray( long* pDXArray
) const
2998 return maImpl
.FillDXArray(pDXArray
);
3001 void GraphiteWinLayout::GetCaretPositions( int nArraySize
, long* pCaretXArray
) const
3003 maImpl
.GetCaretPositions(nArraySize
, pCaretXArray
);
3006 int GraphiteWinLayout::GetNextGlyphs( int length
, sal_GlyphId
* glyph_out
,
3007 ::Point
& pos_out
, int &glyph_slot
, long * glyph_adv
, int *char_index
) const
3009 maImpl
.DrawBase() = WinLayout::maDrawBase
;
3010 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
3011 return maImpl
.GetNextGlyphs(length
, glyph_out
, pos_out
, glyph_slot
, glyph_adv
, char_index
);
3014 void GraphiteWinLayout::MoveGlyph( int glyph_idx
, long new_x_pos
)
3016 maImpl
.MoveGlyph(glyph_idx
, new_x_pos
);
3019 void GraphiteWinLayout::DropGlyph( int glyph_idx
)
3021 maImpl
.DropGlyph(glyph_idx
);
3024 void GraphiteWinLayout::Simplify( bool is_base
)
3026 maImpl
.Simplify(is_base
);
3028 #endif // ENABLE_GRAPHITE
3029 // =======================================================================
3031 SalLayout
* WinSalGraphics::GetTextLayout( ImplLayoutArgs
& rArgs
, int nFallbackLevel
)
3033 DBG_ASSERT( mpWinFontEntry
[nFallbackLevel
], "WinSalGraphics mpWinFontEntry==NULL");
3035 WinLayout
* pWinLayout
= NULL
;
3037 const ImplWinFontData
& rFontFace
= *mpWinFontData
[ nFallbackLevel
];
3038 ImplWinFontEntry
& rFontInstance
= *mpWinFontEntry
[ nFallbackLevel
];
3040 #if defined( USE_UNISCRIBE )
3041 if( !(rArgs
.mnFlags
& SAL_LAYOUT_COMPLEX_DISABLED
)
3042 && (aUspModule
|| (bUspEnabled
&& InitUSP())) ) // CTL layout engine
3044 #ifdef ENABLE_GRAPHITE
3045 if (rFontFace
.SupportsGraphite())
3046 pWinLayout
= new GraphiteWinLayout(mhDC
, rFontFace
, rFontInstance
);
3048 #endif // ENABLE_GRAPHITE
3049 // script complexity is determined in upper layers
3050 pWinLayout
= new UniscribeLayout( mhDC
, rFontFace
, rFontInstance
);
3051 // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
3052 // the created UniscribeLayout, otherwise the data passed into the
3053 // constructor might become invalid too early
3056 #endif // USE_UNISCRIBE
3058 #ifdef GCP_KERN_HACK
3059 if( (rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) && !rFontInstance
.HasKernData() )
3061 // TODO: directly cache kerning info in the rFontInstance
3062 // TODO: get rid of kerning methods+data in WinSalGraphics object
3063 GetKernPairs( 0, NULL
);
3064 rFontInstance
.SetKernData( mnFontKernPairCount
, mpFontKernPairs
);
3066 #endif // GCP_KERN_HACK
3068 BYTE eCharSet
= ANSI_CHARSET
;
3070 eCharSet
= mpLogFont
->lfCharSet
;
3071 #ifdef ENABLE_GRAPHITE
3072 if (rFontFace
.SupportsGraphite())
3073 pWinLayout
= new GraphiteWinLayout(mhDC
, rFontFace
, rFontInstance
);
3075 #endif // ENABLE_GRAPHITE
3076 pWinLayout
= new SimpleWinLayout( mhDC
, eCharSet
, rFontFace
, rFontInstance
);
3079 if( mfFontScale
!= 1.0 )
3080 pWinLayout
->SetFontScale( mfFontScale
);
3085 // -----------------------------------------------------------------------
3087 int WinSalGraphics::GetMinKashidaWidth()
3089 if( !mpWinFontEntry
[0] )
3091 mpWinFontEntry
[0]->InitKashidaHandling( mhDC
);
3092 int nMinKashida
= static_cast<int>(mfFontScale
* mpWinFontEntry
[0]->GetMinKashidaWidth());
3096 // =======================================================================
3098 ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData
& rFSD
)
3099 : ImplFontEntry( rFSD
)
3101 , mpKerningPairs( NULL
)
3102 , mnKerningPairs( -1 )
3103 , mnMinKashidaWidth( -1 )
3104 , mnMinKashidaGlyph( -1 )
3106 #ifdef USE_UNISCRIBE
3107 maScriptCache
= NULL
;
3108 #endif // USE_UNISCRIBE
3111 // -----------------------------------------------------------------------
3113 ImplWinFontEntry::~ImplWinFontEntry()
3115 #ifdef USE_UNISCRIBE
3116 if( maScriptCache
!= NULL
)
3117 (*pScriptFreeCache
)( &maScriptCache
);
3118 #endif // USE_UNISCRIBE
3119 #ifdef GCP_KERN_HACK
3120 delete[] mpKerningPairs
;
3121 #endif // GCP_KERN_HACK
3124 // -----------------------------------------------------------------------
3126 bool ImplWinFontEntry::HasKernData() const
3128 return (mnKerningPairs
>= 0);
3131 // -----------------------------------------------------------------------
3133 void ImplWinFontEntry::SetKernData( int nPairCount
, const KERNINGPAIR
* pPairData
)
3135 mnKerningPairs
= nPairCount
;
3136 mpKerningPairs
= new KERNINGPAIR
[ mnKerningPairs
];
3137 ::memcpy( mpKerningPairs
, (const void*)pPairData
, nPairCount
*sizeof(KERNINGPAIR
) );
3140 // -----------------------------------------------------------------------
3142 int ImplWinFontEntry::GetKerning( sal_Unicode cLeft
, sal_Unicode cRight
) const
3144 int nKernAmount
= 0;
3145 if( mpKerningPairs
)
3147 const KERNINGPAIR aRefPair
= { cLeft
, cRight
, 0 };
3148 const KERNINGPAIR
* pFirstPair
= mpKerningPairs
;
3149 const KERNINGPAIR
* pEndPair
= mpKerningPairs
+ mnKerningPairs
;
3150 const KERNINGPAIR
* pPair
= std::lower_bound( pFirstPair
,
3151 pEndPair
, aRefPair
, ImplCmpKernData
);
3152 if( (pPair
!= pEndPair
)
3153 && (pPair
->wFirst
== aRefPair
.wFirst
)
3154 && (pPair
->wSecond
== aRefPair
.wSecond
) )
3155 nKernAmount
= pPair
->iKernAmount
;
3161 // -----------------------------------------------------------------------
3163 bool ImplWinFontEntry::InitKashidaHandling( HDC hDC
)
3165 if( mnMinKashidaWidth
>= 0 ) // already cached?
3166 return mnMinKashidaWidth
;
3168 // initialize the kashida width
3169 mnMinKashidaWidth
= 0;
3170 mnMinKashidaGlyph
= 0;
3171 #ifdef USE_UNISCRIBE
3172 if (aUspModule
|| (bUspEnabled
&& InitUSP()))
3174 SCRIPT_FONTPROPERTIES aFontProperties
;
3175 aFontProperties
.cBytes
= sizeof (aFontProperties
);
3176 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
3177 HRESULT nRC
= (*pScriptGetFontProperties
)( hDC
, &rScriptCache
, &aFontProperties
);
3180 mnMinKashidaWidth
= aFontProperties
.iKashidaWidth
;
3181 mnMinKashidaGlyph
= aFontProperties
.wgKashida
;
3183 #endif // USE_UNISCRIBE
3188 // =======================================================================
3190 ImplFontData
* ImplWinFontData::Clone() const
3193 mpUnicodeMap
->AddReference();
3194 ImplFontData
* pClone
= new ImplWinFontData( *this );
3198 // -----------------------------------------------------------------------
3200 ImplFontEntry
* ImplWinFontData::CreateFontInstance( ImplFontSelectData
& rFSD
) const
3202 ImplFontEntry
* pEntry
= new ImplWinFontEntry( rFSD
);
3206 // =======================================================================