1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include "tools/svwin.h"
34 #include "saldata.hxx"
35 // for GetMirroredChar
38 #include "vcl/sallayout.hxx"
39 #include "vcl/svapp.hxx"
41 #include "rtl/ustring.hxx"
43 #include "osl/module.h"
50 #define alloca _alloca
55 #endif // GCP_KERN_HACK
63 #endif // USE_UNISCRIBE
68 typedef std::hash_map
<int,int> IntMap
;
69 typedef std::set
<int> IntSet
;
72 #ifdef ENABLE_GRAPHITE
73 #include <i18npool/mslangid.hxx>
74 #include <graphite/GrClient.h>
75 #include <graphite/WinFont.h>
76 #include <graphite/Segment.h>
77 #include <vcl/graphite_layout.hxx>
78 #include <vcl/graphite_cache.hxx>
79 #include <vcl/graphite_features.hxx>
82 #define DROPPED_OUTGLYPH 0xFFFF
86 // =======================================================================
88 // win32 specific physical font instance
89 class ImplWinFontEntry
: public ImplFontEntry
92 ImplWinFontEntry( ImplFontSelectData
& );
96 // TODO: also add HFONT??? Watch out for issues with too many active fonts...
100 bool HasKernData() const;
101 void SetKernData( int, const KERNINGPAIR
* );
102 int GetKerning( sal_Unicode
, sal_Unicode
) const;
104 KERNINGPAIR
* mpKerningPairs
;
106 #endif // GCP_KERN_HACK
110 SCRIPT_CACHE
& GetScriptCache() const
111 { return maScriptCache
; }
113 mutable SCRIPT_CACHE maScriptCache
;
114 #endif // USE_UNISCRIBE
117 int GetCachedGlyphWidth( int nCharCode
) const;
118 void CacheGlyphWidth( int nCharCode
, int nCharWidth
);
120 bool InitKashidaHandling( HDC
);
121 int GetMinKashidaWidth() const { return mnMinKashidaWidth
; }
122 int GetMinKashidaGlyph() const { return mnMinKashidaGlyph
; }
126 mutable int mnMinKashidaWidth
;
127 mutable int mnMinKashidaGlyph
;
130 // -----------------------------------------------------------------------
132 inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode
, int nCharWidth
)
134 maWidthMap
[ nCharCode
] = nCharWidth
;
137 inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode
) const
139 IntMap::const_iterator it
= maWidthMap
.find( nCharCode
);
140 if( it
== maWidthMap
.end() )
145 // =======================================================================
147 class WinLayout
: public SalLayout
150 WinLayout( HDC
, const ImplWinFontData
&, ImplWinFontEntry
& );
151 virtual void InitFont() const;
152 void SetFontScale( float f
) { mfFontScale
= f
; }
153 float GetFontScale() const { return mfFontScale
; }
154 HFONT
DisableFontScaling( void) const;
157 SCRIPT_CACHE
& GetScriptCache() const
158 { return mrWinFontEntry
.GetScriptCache(); }
159 #endif // USE_UNISCRIBE
162 HDC mhDC
; // WIN32 device handle
163 HFONT mhFont
; // WIN32 font handle
164 int mnBaseAdv
; // x-offset relative to Layout origin
165 float mfFontScale
; // allows metrics emulation of huge font sizes
167 const ImplWinFontData
& mrWinFontData
;
168 ImplWinFontEntry
& mrWinFontEntry
;
171 // =======================================================================
173 class SimpleWinLayout
: public WinLayout
176 SimpleWinLayout( HDC
, BYTE nCharSet
, const ImplWinFontData
&, ImplWinFontEntry
& );
177 virtual ~SimpleWinLayout();
179 virtual bool LayoutText( ImplLayoutArgs
& );
180 virtual void AdjustLayout( ImplLayoutArgs
& );
181 virtual void DrawText( SalGraphics
& ) const;
183 virtual int GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int&,
184 sal_Int32
* pGlyphAdvances
, int* pCharIndexes
) const;
186 virtual long FillDXArray( long* pDXArray
) const;
187 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const;
188 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
190 // for glyph+font+script fallback
191 virtual void MoveGlyph( int nStart
, long nNewXPos
);
192 virtual void DropGlyph( int nStart
);
193 virtual void Simplify( bool bIsBase
);
196 void Justify( long nNewWidth
);
197 void ApplyDXArray( const ImplLayoutArgs
& );
203 int* mpGlyphAdvances
; // if possible this is shared with mpGlyphAdvances[]
204 int* mpGlyphOrigAdvs
;
205 int* mpCharWidths
; // map rel char pos to char width
206 int* mpChars2Glyphs
; // map rel char pos to abs glyph pos
207 int* mpGlyphs2Chars
; // map abs glyph pos to abs char pos
208 bool* mpGlyphRTLFlags
; // BiDi status for glyphs: true=>RTL
209 mutable long mnWidth
;
210 bool mbDisableGlyphs
;
216 // =======================================================================
218 WinLayout::WinLayout( HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
)
220 mhFont( (HFONT
)::GetCurrentObject(hDC
,OBJ_FONT
) ),
223 mrWinFontData( rWFD
),
224 mrWinFontEntry( rWFE
)
227 // -----------------------------------------------------------------------
229 void WinLayout::InitFont() const
231 ::SelectObject( mhDC
, mhFont
);
234 // -----------------------------------------------------------------------
236 // Using reasonably sized fonts to emulate huge fonts works around
237 // a lot of problems in printer and display drivers. Huge fonts are
238 // mostly used by high resolution reference devices which are never
239 // painted to anyway. In the rare case that a huge font needs to be
240 // displayed somewhere then the workaround doesn't help anymore.
241 // If the drivers fail silently for huge fonts, so be it...
242 HFONT
WinLayout::DisableFontScaling() const
244 if( mfFontScale
== 1.0 )
248 ::GetObjectW( mhFont
, sizeof(LOGFONTW
), &aLogFont
);
249 aLogFont
.lfHeight
= (LONG
)(mfFontScale
* aLogFont
.lfHeight
);
250 aLogFont
.lfWidth
= (LONG
)(mfFontScale
* aLogFont
.lfWidth
);
251 HFONT hHugeFont
= ::CreateFontIndirectW( &aLogFont
);
255 return SelectFont( mhDC
, hHugeFont
);
258 // =======================================================================
260 SimpleWinLayout::SimpleWinLayout( HDC hDC
, BYTE nCharSet
,
261 const ImplWinFontData
& rWinFontData
, ImplWinFontEntry
& rWinFontEntry
)
262 : WinLayout( hDC
, rWinFontData
, rWinFontEntry
),
266 mpGlyphAdvances( NULL
),
267 mpGlyphOrigAdvs( NULL
),
268 mpCharWidths( NULL
),
269 mpChars2Glyphs( NULL
),
270 mpGlyphs2Chars( NULL
),
271 mpGlyphRTLFlags( NULL
),
274 mnCharSet( nCharSet
),
275 mbDisableGlyphs( false )
277 mbDisableGlyphs
= true;
280 // -----------------------------------------------------------------------
282 SimpleWinLayout::~SimpleWinLayout()
284 delete[] mpGlyphRTLFlags
;
285 delete[] mpGlyphs2Chars
;
286 delete[] mpChars2Glyphs
;
287 if( mpCharWidths
!= mpGlyphAdvances
)
288 delete[] mpCharWidths
;
289 delete[] mpGlyphOrigAdvs
;
290 delete[] mpGlyphAdvances
;
291 delete[] mpOutGlyphs
;
294 // -----------------------------------------------------------------------
296 bool SimpleWinLayout::LayoutText( ImplLayoutArgs
& rArgs
)
299 // TODO: fix case when recyclying old SimpleWinLayout object
300 mbDisableGlyphs
|= ((rArgs
.mnFlags
& SAL_LAYOUT_DISABLE_GLYPH_PROCESSING
) != 0);
301 mnCharCount
= rArgs
.mnEndCharPos
- rArgs
.mnMinCharPos
;
303 if( !mbDisableGlyphs
)
305 // Win32 glyph APIs have serious problems with vertical layout
306 // => workaround is to use the unicode methods then
307 if( rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
)
308 mbDisableGlyphs
= true;
310 // use cached value from font face
311 mbDisableGlyphs
= mrWinFontData
.IsGlyphApiDisabled();
314 // TODO: use a cached value for bDisableAsianKern from upper layers
315 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
317 TEXTMETRICA aTextMetricA
;
318 if( ::GetTextMetricsA( mhDC
, &aTextMetricA
)
319 && !(aTextMetricA
.tmPitchAndFamily
& TMPF_FIXED_PITCH
) && !(aTextMetricA
.tmCharSet
== 0x86) )
320 rArgs
.mnFlags
&= ~SAL_LAYOUT_KERNING_ASIAN
;
327 bool bVertical
= (rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
) != 0;
329 // count the number of chars to process if no RTL run
331 bool bHasRTL
= false;
332 while( rArgs
.GetNextRun( &i
, &j
, &bHasRTL
) && !bHasRTL
)
333 mnGlyphCount
+= j
- i
;
335 // if there are RTL runs we need room to remember individual BiDi flags
338 mpGlyphRTLFlags
= new bool[ mnCharCount
];
339 for( i
= 0; i
< mnCharCount
; ++i
)
340 mpGlyphRTLFlags
[i
] = false;
343 // rewrite the logical string if needed to prepare for the API calls
344 const sal_Unicode
* pBidiStr
= rArgs
.mpStr
+ rArgs
.mnMinCharPos
;
345 if( (mnGlyphCount
!= mnCharCount
) || bVertical
)
347 // we need to rewrite the pBidiStr when any of
348 // - BiDirectional layout
350 // - partial runs (e.g. with control chars or for glyph fallback)
352 sal_Unicode
* pRewrittenStr
= (sal_Unicode
*)alloca( mnCharCount
* sizeof(sal_Unicode
) );
353 pBidiStr
= pRewrittenStr
;
355 // note: glyph to char mapping is relative to first character
356 mpChars2Glyphs
= new int[ mnCharCount
];
357 mpGlyphs2Chars
= new int[ mnCharCount
];
358 for( i
= 0; i
< mnCharCount
; ++i
)
359 mpChars2Glyphs
[i
] = mpGlyphs2Chars
[i
] = -1;
364 while( rArgs
.GetNextRun( &i
, &j
, &bIsRTL
) )
368 // get the next leftmost character in this run
369 int nCharPos
= bIsRTL
? --j
: i
++;
370 sal_UCS4 cChar
= rArgs
.mpStr
[ nCharPos
];
372 // in the RTL case mirror the character and remember its RTL status
375 cChar
= ::GetMirroredChar( cChar
);
376 mpGlyphRTLFlags
[ mnGlyphCount
] = true;
379 // for vertical writing use vertical alternatives
382 sal_UCS4 cVert
= ::GetVerticalChar( cChar
);
387 // rewrite the original string
388 // update the mappings between original and rewritten string
389 // TODO: support surrogates in rewritten strings
390 pRewrittenStr
[ mnGlyphCount
] = static_cast<sal_Unicode
>(cChar
);
391 mpGlyphs2Chars
[ mnGlyphCount
] = nCharPos
;
392 mpChars2Glyphs
[ nCharPos
- rArgs
.mnMinCharPos
] = mnGlyphCount
;
398 mpOutGlyphs
= new WCHAR
[ mnGlyphCount
];
399 mpGlyphAdvances
= new int[ mnGlyphCount
];
401 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_PAIRS
| SAL_LAYOUT_KERNING_ASIAN
) )
402 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
404 #ifndef GCP_KERN_HACK
405 DWORD nGcpOption
= 0;
406 // enable kerning if requested
407 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
408 nGcpOption
|= GCP_USEKERNING
;
409 #endif // GCP_KERN_HACK
411 for( i
= 0; i
< mnGlyphCount
; ++i
)
412 mpOutGlyphs
[i
] = pBidiStr
[ i
];
414 for( i
= 0; i
< mnGlyphCount
; ++i
)
416 // get the current UCS-4 code point, check for surrogate pairs
417 const WCHAR
* pCodes
= reinterpret_cast<LPCWSTR
>(&pBidiStr
[i
]);
418 unsigned nCharCode
= pCodes
[0];
419 bool bSurrogate
= ((nCharCode
>= 0xD800) && (nCharCode
<= 0xDFFF));
422 if( nCharCode
>= 0xDC00 ) // this part of a surrogate pair was already processed
424 nCharCode
= 0x10000 + ((pCodes
[0] - 0xD800) << 10) + (pCodes
[1] - 0xDC00);
427 // get the advance width for the current UCS-4 code point
428 int nGlyphWidth
= mrWinFontEntry
.GetCachedGlyphWidth( nCharCode
);
429 if( nGlyphWidth
== -1 )
433 if( ::GetTextExtentPoint32W( mhDC
, &pCodes
[0], bSurrogate
? 2 : 1, &aExtent
) )
434 nGlyphWidth
= aExtent
.cx
;
435 else if( ::GetCharABCWidthsW( mhDC
, nCharCode
, nCharCode
, &aABC
) )
436 nGlyphWidth
= aABC
.abcA
+ aABC
.abcB
+ aABC
.abcC
;
437 else if( !::GetCharWidth32W( mhDC
, nCharCode
, nCharCode
, &nGlyphWidth
)
438 && !::GetCharWidthW( mhDC
, nCharCode
, nCharCode
, &nGlyphWidth
) )
440 mrWinFontEntry
.CacheGlyphWidth( nCharCode
, nGlyphWidth
);
442 mpGlyphAdvances
[ i
] = nGlyphWidth
;
443 mnWidth
+= nGlyphWidth
;
445 // remaining codes of surrogate pair get a zero width
446 if( bSurrogate
&& ((i
+1) < mnGlyphCount
) )
447 mpGlyphAdvances
[ i
+1 ] = 0;
449 // check with the font face if glyph fallback is needed
450 if( mrWinFontData
.HasChar( nCharCode
) )
453 // request glyph fallback at this position in the string
454 bool bRTL
= mpGlyphRTLFlags
? mpGlyphRTLFlags
[i
] : false;
455 int nCharPos
= mpGlyphs2Chars
? mpGlyphs2Chars
[i
]: i
+ rArgs
.mnMinCharPos
;
456 rArgs
.NeedFallback( nCharPos
, bRTL
);
457 if( bSurrogate
&& ((nCharPos
+1) < rArgs
.mnLength
) )
458 rArgs
.NeedFallback( nCharPos
+1, bRTL
);
460 // replace the current glyph shape with the NotDef glyph shape
461 if( rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
)
463 // when we already are layouting for glyph fallback
464 // then a new unresolved glyph is not interesting
466 mpOutGlyphs
[i
] = DROPPED_OUTGLYPH
;
470 if( mnNotdefWidth
< 0 )
472 // get the width of the NotDef glyph
474 WCHAR cNotDef
= rArgs
.mpStr
[ nCharPos
];
476 if( ::GetTextExtentPoint32W( mhDC
, &cNotDef
, 1, &aExtent
) )
477 mnNotdefWidth
= aExtent
.cx
;
479 // use a better NotDef glyph
480 if( !mbDisableGlyphs
&& !bSurrogate
)
483 if( bSurrogate
&& ((i
+1) < mnGlyphCount
) )
484 mpOutGlyphs
[i
+1] = DROPPED_OUTGLYPH
;
486 // adjust the current glyph width to the NotDef glyph width
487 mnWidth
+= mnNotdefWidth
- mpGlyphAdvances
[i
];
488 mpGlyphAdvances
[i
] = mnNotdefWidth
;
489 if( mpGlyphOrigAdvs
)
490 mpGlyphOrigAdvs
[i
] = mnNotdefWidth
;
494 // apply kerning if the layout engine has not yet done it
495 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_ASIAN
|SAL_LAYOUT_KERNING_PAIRS
) )
497 #else // GCP_KERN_HACK
498 // apply just asian kerning
499 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
501 if( !(rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) )
502 #endif // GCP_KERN_HACK
503 for( i
= 0; i
< mnGlyphCount
; ++i
)
504 mpGlyphOrigAdvs
[i
] = mpGlyphAdvances
[i
];
506 // #99658# also apply asian kerning on the substring border
507 int nLen
= mnGlyphCount
;
508 if( rArgs
.mnMinCharPos
+ nLen
< rArgs
.mnLength
)
510 for( i
= 1; i
< nLen
; ++i
)
513 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
515 int nKernAmount
= mrWinFontEntry
.GetKerning( pBidiStr
[i
-1], pBidiStr
[i
] );
516 mpGlyphAdvances
[ i
-1 ] += nKernAmount
;
517 mnWidth
+= nKernAmount
;
519 else if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
520 #endif // GCP_KERN_HACK
522 if( ( (0x3000 == (0xFF00 & pBidiStr
[i
-1])) || (0x2010 == (0xFFF0 & pBidiStr
[i
-1])) || (0xFF00 == (0xFF00 & pBidiStr
[i
-1])))
523 && ( (0x3000 == (0xFF00 & pBidiStr
[i
])) || (0x2010 == (0xFFF0 & pBidiStr
[i
])) || (0xFF00 == (0xFF00 & pBidiStr
[i
])) ) )
525 long nKernFirst
= +CalcAsianKerning( pBidiStr
[i
-1], true, bVertical
);
526 long nKernNext
= -CalcAsianKerning( pBidiStr
[i
], false, bVertical
);
528 long nDelta
= (nKernFirst
< nKernNext
) ? nKernFirst
: nKernNext
;
529 if( nDelta
<0 && nKernFirst
!=0 && nKernNext
!=0 )
531 nDelta
= (nDelta
* mpGlyphAdvances
[i
-1] + 2) / 4;
532 mpGlyphAdvances
[i
-1] += nDelta
;
539 // calculate virtual char widths
540 if( !mpGlyphs2Chars
)
541 mpCharWidths
= mpGlyphAdvances
;
544 mpCharWidths
= new int[ mnCharCount
];
545 for( i
= 0; i
< mnCharCount
; ++i
)
546 mpCharWidths
[ i
] = 0;
547 for( i
= 0; i
< mnGlyphCount
; ++i
)
549 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
551 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
555 // scale layout metrics if needed
556 // TODO: does it make the code more simple if the metric scaling
557 // is moved to the methods that need metric scaling (e.g. FillDXArray())?
558 if( mfFontScale
!= 1.0 )
560 mnWidth
= (long)(mnWidth
* mfFontScale
);
561 mnBaseAdv
= (int)(mnBaseAdv
* mfFontScale
);
562 for( i
= 0; i
< mnCharCount
; ++i
)
563 mpCharWidths
[i
] = (int)(mpCharWidths
[i
] * mfFontScale
);
564 if( mpGlyphAdvances
!= mpCharWidths
)
565 for( i
= 0; i
< mnGlyphCount
; ++i
)
566 mpGlyphAdvances
[i
] = (int)(mpGlyphAdvances
[i
] * mfFontScale
);
567 if( mpGlyphOrigAdvs
&& (mpGlyphOrigAdvs
!= mpGlyphAdvances
) )
568 for( i
= 0; i
< mnGlyphCount
; ++i
)
569 mpGlyphOrigAdvs
[i
] = (int)(mpGlyphOrigAdvs
[i
] * mfFontScale
);
575 // -----------------------------------------------------------------------
577 int SimpleWinLayout::GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int& nStart
,
578 long* pGlyphAdvances
, int* pCharIndexes
) const
580 // return zero if no more glyph found
581 if( nStart
>= mnGlyphCount
)
584 // calculate glyph position relative to layout base
585 // TODO: avoid for nStart!=0 case by reusing rPos
586 long nXOffset
= mnBaseAdv
;
587 for( int i
= 0; i
< nStart
; ++i
)
588 nXOffset
+= mpGlyphAdvances
[ i
];
590 // calculate absolute position in pixel units
591 Point
aRelativePos( nXOffset
, 0 );
592 rPos
= GetDrawPosition( aRelativePos
);
595 while( nCount
< nLen
)
597 // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
598 sal_GlyphId nGlyphIndex
= mpOutGlyphs
[ nStart
];
599 if( mbDisableGlyphs
)
601 if( mnLayoutFlags
& SAL_LAYOUT_VERTICAL
)
603 const sal_UCS4 cChar
= static_cast<sal_UCS4
>(nGlyphIndex
& GF_IDXMASK
);
604 if( mrWinFontData
.HasGSUBstitutions( mhDC
)
605 && mrWinFontData
.IsGSUBstituted( cChar
) )
606 nGlyphIndex
|= GF_GSUB
| GF_ROTL
;
609 nGlyphIndex
|= GetVerticalFlags( cChar
);
610 if( (nGlyphIndex
& GF_ROTMASK
) == 0 )
611 nGlyphIndex
|= GF_VERT
;
614 nGlyphIndex
|= GF_ISCHAR
;
617 *(pGlyphs
++) = nGlyphIndex
;
619 *(pGlyphAdvances
++) = mpGlyphAdvances
[ nStart
];
623 if( !mpGlyphs2Chars
)
624 nCharPos
= nStart
+ mnMinCharPos
;
626 nCharPos
= mpGlyphs2Chars
[nStart
];
627 *(pCharIndexes
++) = nCharPos
;
630 // stop at last glyph
631 if( ++nStart
>= mnGlyphCount
)
634 // stop when next x-position is unexpected
635 if( !pGlyphAdvances
&& mpGlyphOrigAdvs
)
636 if( mpGlyphAdvances
[nStart
-1] != mpGlyphOrigAdvs
[nStart
-1] )
643 // -----------------------------------------------------------------------
645 void SimpleWinLayout::DrawText( SalGraphics
& rGraphics
) const
647 if( mnGlyphCount
<= 0 )
650 WinSalGraphics
& rWinGraphics
= static_cast<WinSalGraphics
&>(rGraphics
);
651 HDC aHDC
= rWinGraphics
.mhDC
;
653 HFONT hOrigFont
= DisableFontScaling();
655 UINT mnDrawOptions
= ETO_GLYPH_INDEX
;
656 if( mbDisableGlyphs
)
659 Point aPos
= GetDrawPosition( Point( mnBaseAdv
, 0 ) );
661 // #108267#, break up into glyph portions of a limited size required by Win32 API
662 const unsigned int maxGlyphCount
= 8192;
663 UINT numGlyphPortions
= mnGlyphCount
/ maxGlyphCount
;
664 UINT remainingGlyphs
= mnGlyphCount
% maxGlyphCount
;
666 if( numGlyphPortions
)
668 // #108267#,#109387# break up string into smaller chunks
669 // the output positions will be updated by windows (SetTextAlign)
671 UINT oldTa
= ::GetTextAlign( aHDC
);
672 ::SetTextAlign( aHDC
, (oldTa
& ~TA_NOUPDATECP
) | TA_UPDATECP
);
673 ::MoveToEx( aHDC
, aPos
.X(), aPos
.Y(), &oldPos
);
675 for( unsigned int n
= 0; n
< numGlyphPortions
; ++n
, i
+=maxGlyphCount
)
676 ::ExtTextOutW( aHDC
, 0, 0, mnDrawOptions
, NULL
,
677 mpOutGlyphs
+i
, maxGlyphCount
, mpGlyphAdvances
+i
);
678 ::ExtTextOutW( aHDC
, 0, 0, mnDrawOptions
, NULL
,
679 mpOutGlyphs
+i
, remainingGlyphs
, mpGlyphAdvances
+i
);
680 ::MoveToEx( aHDC
, oldPos
.x
, oldPos
.y
, (LPPOINT
) NULL
);
681 ::SetTextAlign( aHDC
, oldTa
);
684 ::ExtTextOutW( aHDC
, aPos
.X(), aPos
.Y(), mnDrawOptions
, NULL
,
685 mpOutGlyphs
, mnGlyphCount
, mpGlyphAdvances
);
688 DeleteFont( SelectFont( aHDC
, hOrigFont
) );
691 // -----------------------------------------------------------------------
693 long SimpleWinLayout::FillDXArray( long* pDXArray
) const
697 long mnWidth
= mnBaseAdv
;
698 for( int i
= 0; i
< mnGlyphCount
; ++i
)
699 mnWidth
+= mpGlyphAdvances
[ i
];
702 if( pDXArray
!= NULL
)
704 for( int i
= 0; i
< mnCharCount
; ++i
)
705 pDXArray
[ i
] = mpCharWidths
[ i
];
711 // -----------------------------------------------------------------------
713 int SimpleWinLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
714 // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
717 if( (mnWidth
* nFactor
+ mnCharCount
* nCharExtra
) <= nMaxWidth
)
720 long nExtraWidth
= mnBaseAdv
* nFactor
;
721 for( int n
= 0; n
< mnCharCount
; ++n
)
723 // skip unused characters
724 if( mpChars2Glyphs
&& (mpChars2Glyphs
[n
] < 0) )
726 // add char widths until max
727 nExtraWidth
+= mpCharWidths
[ n
] * nFactor
;
728 if( nExtraWidth
>= nMaxWidth
)
729 return (mnMinCharPos
+ n
);
730 nExtraWidth
+= nCharExtra
;
736 // -----------------------------------------------------------------------
738 void SimpleWinLayout::GetCaretPositions( int nMaxIdx
, long* pCaretXArray
) const
740 long nXPos
= mnBaseAdv
;
742 if( !mpGlyphs2Chars
)
744 for( int i
= 0; i
< nMaxIdx
; i
+= 2 )
746 pCaretXArray
[ i
] = nXPos
;
747 nXPos
+= mpGlyphAdvances
[ i
>>1 ];
748 pCaretXArray
[ i
+1 ] = nXPos
;
754 for( i
= 0; i
< nMaxIdx
; ++i
)
755 pCaretXArray
[ i
] = -1;
757 // assign glyph positions to character positions
758 for( i
= 0; i
< mnGlyphCount
; ++i
)
760 int nCurrIdx
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
761 long nXRight
= nXPos
+ mpCharWidths
[ nCurrIdx
];
763 if( !(mpGlyphRTLFlags
&& mpGlyphRTLFlags
[i
]) )
765 // normal positions for LTR case
766 pCaretXArray
[ nCurrIdx
] = nXPos
;
767 pCaretXArray
[ nCurrIdx
+1 ] = nXRight
;
771 // reverse positions for RTL case
772 pCaretXArray
[ nCurrIdx
] = nXRight
;
773 pCaretXArray
[ nCurrIdx
+1 ] = nXPos
;
775 nXPos
+= mpGlyphAdvances
[ i
];
780 // -----------------------------------------------------------------------
782 void SimpleWinLayout::Justify( long nNewWidth
)
784 long nOldWidth
= mnWidth
;
787 if( mnGlyphCount
<= 0 )
790 if( nNewWidth
== nOldWidth
)
793 // the rightmost glyph cannot be stretched
794 const int nRight
= mnGlyphCount
- 1;
795 nOldWidth
-= mpGlyphAdvances
[ nRight
];
796 nNewWidth
-= mpGlyphAdvances
[ nRight
];
798 // count stretchable glyphs
799 int nStretchable
= 0, i
;
800 for( i
= 0; i
< nRight
; ++i
)
801 if( mpGlyphAdvances
[i
] >= 0 )
804 // stretch these glyphs
805 int nDiffWidth
= nNewWidth
- nOldWidth
;
806 for( i
= 0; (i
< nRight
) && (nStretchable
> 0); ++i
)
808 if( mpGlyphAdvances
[i
] <= 0 )
810 int nDeltaWidth
= nDiffWidth
/ nStretchable
;
811 mpGlyphAdvances
[i
] += nDeltaWidth
;
813 nDiffWidth
-= nDeltaWidth
;
817 // -----------------------------------------------------------------------
819 void SimpleWinLayout::AdjustLayout( ImplLayoutArgs
& rArgs
)
821 SalLayout::AdjustLayout( rArgs
);
823 // adjust positions if requested
824 if( rArgs
.mpDXArray
)
825 ApplyDXArray( rArgs
);
826 else if( rArgs
.mnLayoutWidth
)
827 Justify( rArgs
.mnLayoutWidth
);
831 // recalculate virtual char widths if they were changed
832 if( mpCharWidths
!= mpGlyphAdvances
)
835 if( !mpGlyphs2Chars
)
838 for( i
= 0; i
< mnGlyphCount
; ++i
)
839 mpCharWidths
[ i
] = mpGlyphAdvances
[ i
];
843 // BiDi or complex case
844 for( i
= 0; i
< mnCharCount
; ++i
)
845 mpCharWidths
[ i
] = 0;
846 for( i
= 0; i
< mnGlyphCount
; ++i
)
848 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
850 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
856 // -----------------------------------------------------------------------
858 void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs
& rArgs
)
860 // try to avoid disturbance of text flow for LSB rounding case;
861 const long* pDXArray
= rArgs
.mpDXArray
;
864 long nOldWidth
= mnBaseAdv
;
865 for(; i
< mnCharCount
; ++i
)
867 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
870 nOldWidth
+= mpGlyphAdvances
[ j
];
871 int nDiff
= nOldWidth
- pDXArray
[ i
];
873 // disabled because of #104768#
874 // works great for static text, but problems when typing
875 // if( nDiff>+1 || nDiff<-1 )
876 // only bother with changing anything when something moved
881 if( i
>= mnCharCount
)
884 if( !mpGlyphOrigAdvs
)
886 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
887 for( i
= 0; i
< mnGlyphCount
; ++i
)
888 mpGlyphOrigAdvs
[ i
] = mpGlyphAdvances
[ i
];
892 for( i
= 0; i
< mnCharCount
; ++i
)
894 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
896 mpGlyphAdvances
[j
] = pDXArray
[i
] - mnWidth
;
897 mnWidth
= pDXArray
[i
];
901 // -----------------------------------------------------------------------
903 void SimpleWinLayout::MoveGlyph( int nStart
, long nNewXPos
)
905 if( nStart
> mnGlyphCount
)
908 // calculate the current x-position of the requested glyph
909 // TODO: cache absolute positions
910 int nXPos
= mnBaseAdv
;
911 for( int i
= 0; i
< nStart
; ++i
)
912 nXPos
+= mpGlyphAdvances
[i
];
914 // calculate the difference to the current glyph position
915 int nDelta
= nNewXPos
- nXPos
;
917 // adjust the width of the layout if it was already cached
921 // depending on whether the requested glyph is leftmost in the layout
922 // adjust either the layout's or the requested glyph's relative position
924 mpGlyphAdvances
[ nStart
-1 ] += nDelta
;
929 // -----------------------------------------------------------------------
931 void SimpleWinLayout::DropGlyph( int nStart
)
933 mpOutGlyphs
[ nStart
] = DROPPED_OUTGLYPH
;
936 // -----------------------------------------------------------------------
938 void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
940 // return early if no glyph has been dropped
941 int i
= mnGlyphCount
;
942 while( (--i
>= 0) && (mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
) );
946 // convert the layout to a sparse layout if it is not already
947 if( !mpGlyphs2Chars
)
949 mpGlyphs2Chars
= new int[ mnGlyphCount
];
950 mpCharWidths
= new int[ mnCharCount
];
951 // assertion: mnGlyphCount == mnCharCount
952 for( int k
= 0; k
< mnGlyphCount
; ++k
)
954 mpGlyphs2Chars
[ k
] = mnMinCharPos
+ k
;
955 mpCharWidths
[ k
] = mpGlyphAdvances
[ k
];
959 // remove dropped glyphs that are rightmost in the layout
960 for( i
= mnGlyphCount
; --i
>= 0; )
962 if( mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
)
965 mnWidth
-= mpGlyphAdvances
[ i
];
966 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
967 if( nRelCharPos
>= 0 )
968 mpCharWidths
[ nRelCharPos
] = 0;
970 mnGlyphCount
= i
+ 1;
972 // keep original glyph widths around
973 if( !mpGlyphOrigAdvs
)
975 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
976 for( int k
= 0; k
< mnGlyphCount
; ++k
)
977 mpGlyphOrigAdvs
[ k
] = mpGlyphAdvances
[ k
];
980 // remove dropped glyphs inside the layout
982 for( i
= 0; i
< mnGlyphCount
; ++i
)
984 if( mpOutGlyphs
[ i
] == DROPPED_OUTGLYPH
)
986 // adjust relative position to last valid glyph
987 int nDroppedWidth
= mpGlyphAdvances
[ i
];
988 mpGlyphAdvances
[ i
] = 0;
990 mpGlyphAdvances
[ nNewGC
-1 ] += nDroppedWidth
;
992 mnBaseAdv
+= nDroppedWidth
;
994 // zero the virtual char width for the char that has a fallback
995 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
996 if( nRelCharPos
>= 0 )
997 mpCharWidths
[ nRelCharPos
] = 0;
1003 // rearrange the glyph array to get rid of the dropped glyph
1004 mpOutGlyphs
[ nNewGC
] = mpOutGlyphs
[ i
];
1005 mpGlyphAdvances
[ nNewGC
] = mpGlyphAdvances
[ i
];
1006 mpGlyphOrigAdvs
[ nNewGC
] = mpGlyphOrigAdvs
[ i
];
1007 mpGlyphs2Chars
[ nNewGC
] = mpGlyphs2Chars
[ i
];
1013 mnGlyphCount
= nNewGC
;
1014 if( mnGlyphCount
<= 0 )
1015 mnWidth
= mnBaseAdv
= 0;
1018 // =======================================================================
1020 #ifdef USE_UNISCRIBE
1025 SCRIPT_ITEM
* mpScriptItem
;
1030 //long mnPixelWidth;
1036 bool IsEmpty() const { return (mnEndGlyphPos
<= 0); }
1037 bool IsRTL() const { return mpScriptItem
->a
.fRTL
; }
1038 bool HasKashidas() const { return mbHasKashidas
; }
1041 // -----------------------------------------------------------------------
1043 class UniscribeLayout
: public WinLayout
1046 UniscribeLayout( HDC
, const ImplWinFontData
&, ImplWinFontEntry
& );
1048 virtual bool LayoutText( ImplLayoutArgs
& );
1049 virtual void AdjustLayout( ImplLayoutArgs
& );
1050 virtual void DrawText( SalGraphics
& ) const;
1051 virtual int GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int&,
1052 sal_Int32
* pGlyphAdvances
, int* pCharPosAry
) const;
1054 virtual long FillDXArray( long* pDXArray
) const;
1055 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const;
1056 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
1057 virtual bool IsKashidaPosValid ( int nCharPos
) const;
1059 // for glyph+font+script fallback
1060 virtual void MoveGlyph( int nStart
, long nNewXPos
);
1061 virtual void DropGlyph( int nStart
);
1062 virtual void Simplify( bool bIsBase
);
1063 virtual void DisableGlyphInjection( bool bDisable
) { mbDisableGlyphInjection
= bDisable
; }
1066 virtual ~UniscribeLayout();
1068 void Justify( long nNewWidth
);
1069 void ApplyDXArray( const ImplLayoutArgs
& );
1071 bool GetItemSubrange( const VisualItem
&,
1072 int& rMinIndex
, int& rEndIndex
) const;
1075 // item specific info
1076 SCRIPT_ITEM
* mpScriptItems
; // in logical order
1077 VisualItem
* mpVisualItems
; // in visual order
1078 int mnItemCount
; // number of visual items
1080 // string specific info
1081 // everything is in logical order
1083 WORD
* mpLogClusters
; // map from absolute_char_pos to relative_glyph_pos
1084 int* mpCharWidths
; // map from absolute_char_pos to char_width
1085 int mnSubStringMin
; // char_pos of first char in context
1087 // glyph specific info
1088 // everything is in visual order
1090 int mnGlyphCapacity
;
1091 int* mpGlyphAdvances
; // glyph advance width before justification
1092 int* mpJustifications
; // glyph advance width after justification
1093 WORD
* mpOutGlyphs
; // glyphids in visual order
1094 GOFFSET
* mpGlyphOffsets
; // glyph offsets to the "naive" layout
1095 SCRIPT_VISATTR
* mpVisualAttrs
; // glyph visual attributes
1096 mutable int* mpGlyphs2Chars
; // map from absolute_glyph_pos to absolute_char_pos
1099 void InitKashidaHandling();
1100 void KashidaItemFix( int nMinGlyphPos
, int nEndGlyphPos
);
1101 bool KashidaWordFix( int nMinGlyphPos
, int nEndGlyphPos
, int* pnCurrentPos
);
1103 int mnMinKashidaWidth
;
1104 int mnMinKashidaGlyph
;
1105 bool mbDisableGlyphInjection
;
1108 // -----------------------------------------------------------------------
1109 // dynamic loading of usp library
1111 static oslModule aUspModule
= NULL
;
1112 static bool bUspEnabled
= true;
1114 static HRESULT ((WINAPI
*pScriptIsComplex
)( const WCHAR
*, int, DWORD
));
1115 static HRESULT ((WINAPI
*pScriptItemize
)( const WCHAR
*, int, int,
1116 const SCRIPT_CONTROL
*, const SCRIPT_STATE
*, SCRIPT_ITEM
*, int* ));
1117 static HRESULT ((WINAPI
*pScriptShape
)( HDC
, SCRIPT_CACHE
*, const WCHAR
*,
1118 int, int, SCRIPT_ANALYSIS
*, WORD
*, WORD
*, SCRIPT_VISATTR
*, int* ));
1119 static HRESULT ((WINAPI
*pScriptPlace
)( HDC
, SCRIPT_CACHE
*, const WORD
*, int,
1120 const SCRIPT_VISATTR
*, SCRIPT_ANALYSIS
*, int*, GOFFSET
*, ABC
* ));
1121 static HRESULT ((WINAPI
*pScriptGetLogicalWidths
)( const SCRIPT_ANALYSIS
*,
1122 int, int, const int*, const WORD
*, const SCRIPT_VISATTR
*, int* ));
1123 static HRESULT ((WINAPI
*pScriptApplyLogicalWidth
)( const int*, int, int, const WORD
*,
1124 const SCRIPT_VISATTR
*, const int*, const SCRIPT_ANALYSIS
*, ABC
*, int* ));
1125 static HRESULT ((WINAPI
*pScriptJustify
)( const SCRIPT_VISATTR
*,
1126 const int*, int, int, int, int* ));
1127 static HRESULT ((WINAPI
*pScriptTextOut
)( const HDC
, SCRIPT_CACHE
*,
1128 int, int, UINT
, const RECT
*, const SCRIPT_ANALYSIS
*, const WCHAR
*,
1129 int, const WORD
*, int, const int*, const int*, const GOFFSET
* ));
1130 static HRESULT ((WINAPI
*pScriptGetFontProperties
)( HDC
, SCRIPT_CACHE
*, SCRIPT_FONTPROPERTIES
* ));
1131 static HRESULT ((WINAPI
*pScriptFreeCache
)( SCRIPT_CACHE
* ));
1133 static bool bManualCellAlign
= true;
1135 // -----------------------------------------------------------------------
1137 static bool InitUSP()
1139 OUString
aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
1140 aUspModule
= osl_loadModule( aLibraryName
.pData
, SAL_LOADMODULE_DEFAULT
);
1142 return (bUspEnabled
= false);
1144 pScriptIsComplex
= (HRESULT (WINAPI
*)(const WCHAR
*,int,DWORD
))
1145 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptIsComplex" );
1146 bUspEnabled
&= (NULL
!= pScriptIsComplex
);
1148 pScriptItemize
= (HRESULT (WINAPI
*)(const WCHAR
*,int,int,
1149 const SCRIPT_CONTROL
*,const SCRIPT_STATE
*,SCRIPT_ITEM
*,int*))
1150 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptItemize" );
1151 bUspEnabled
&= (NULL
!= pScriptItemize
);
1153 pScriptShape
= (HRESULT (WINAPI
*)(HDC
,SCRIPT_CACHE
*,const WCHAR
*,
1154 int,int,SCRIPT_ANALYSIS
*,WORD
*,WORD
*,SCRIPT_VISATTR
*,int*))
1155 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptShape" );
1156 bUspEnabled
&= (NULL
!= pScriptShape
);
1158 pScriptPlace
= (HRESULT (WINAPI
*)(HDC
, SCRIPT_CACHE
*, const WORD
*, int,
1159 const SCRIPT_VISATTR
*,SCRIPT_ANALYSIS
*,int*,GOFFSET
*,ABC
*))
1160 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptPlace" );
1161 bUspEnabled
&= (NULL
!= pScriptPlace
);
1163 pScriptGetLogicalWidths
= (HRESULT (WINAPI
*)(const SCRIPT_ANALYSIS
*,
1164 int,int,const int*,const WORD
*,const SCRIPT_VISATTR
*,int*))
1165 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptGetLogicalWidths" );
1166 bUspEnabled
&= (NULL
!= pScriptGetLogicalWidths
);
1168 pScriptApplyLogicalWidth
= (HRESULT (WINAPI
*)(const int*,int,int,const WORD
*,
1169 const SCRIPT_VISATTR
*,const int*,const SCRIPT_ANALYSIS
*,ABC
*,int*))
1170 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptApplyLogicalWidth" );
1171 bUspEnabled
&= (NULL
!= pScriptApplyLogicalWidth
);
1173 pScriptJustify
= (HRESULT (WINAPI
*)(const SCRIPT_VISATTR
*,const int*,
1175 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptJustify" );
1176 bUspEnabled
&= (NULL
!= pScriptJustify
);
1178 pScriptGetFontProperties
= (HRESULT (WINAPI
*)( HDC
,SCRIPT_CACHE
*,SCRIPT_FONTPROPERTIES
*))
1179 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptGetFontProperties" );
1180 bUspEnabled
&= (NULL
!= pScriptGetFontProperties
);
1182 pScriptTextOut
= (HRESULT (WINAPI
*)(const HDC
,SCRIPT_CACHE
*,
1183 int,int,UINT
,const RECT
*,const SCRIPT_ANALYSIS
*,const WCHAR
*,
1184 int,const WORD
*,int,const int*,const int*,const GOFFSET
*))
1185 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptTextOut" );
1186 bUspEnabled
&= (NULL
!= pScriptTextOut
);
1188 pScriptFreeCache
= (HRESULT (WINAPI
*)(SCRIPT_CACHE
*))
1189 osl_getAsciiFunctionSymbol( aUspModule
, "ScriptFreeCache" );
1190 bUspEnabled
&= (NULL
!= pScriptFreeCache
);
1194 osl_unloadModule( aUspModule
);
1198 // get the DLL version info
1199 int nUspVersion
= 0;
1200 // TODO: there must be a simpler way to get the friggin version info from OSL?
1201 rtl_uString
* pModuleURL
= NULL
;
1202 osl_getModuleURLFromAddress( (void*)pScriptIsComplex
, &pModuleURL
);
1203 rtl_uString
* pModuleFileName
= NULL
;
1205 osl_getSystemPathFromFileURL( pModuleURL
, &pModuleFileName
);
1206 const sal_Unicode
* pModuleFileCStr
= NULL
;
1207 if( pModuleFileName
)
1208 pModuleFileCStr
= rtl_uString_getStr( pModuleFileName
);
1209 if( pModuleFileCStr
)
1212 DWORD nBufSize
= ::GetFileVersionInfoSizeW( const_cast<LPWSTR
>(reinterpret_cast<LPCWSTR
>(pModuleFileCStr
)), &nHandle
);
1213 char* pBuffer
= (char*)alloca( nBufSize
);
1214 BOOL bRC
= ::GetFileVersionInfoW( const_cast<LPWSTR
>(reinterpret_cast<LPCWSTR
>(pModuleFileCStr
)), nHandle
, nBufSize
, pBuffer
);
1215 VS_FIXEDFILEINFO
* pFixedFileInfo
= NULL
;
1216 UINT nFixedFileSize
= 0;
1218 ::VerQueryValueW( pBuffer
, const_cast<LPWSTR
>(L
"\\"), (void**)&pFixedFileInfo
, &nFixedFileSize
);
1219 if( pFixedFileInfo
&& pFixedFileInfo
->dwSignature
== 0xFEEF04BD )
1220 nUspVersion
= HIWORD(pFixedFileInfo
->dwProductVersionMS
) * 10000
1221 + LOWORD(pFixedFileInfo
->dwProductVersionMS
);
1224 // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
1225 if( nUspVersion
>= 10600 )
1226 bManualCellAlign
= false;
1231 // -----------------------------------------------------------------------
1233 UniscribeLayout::UniscribeLayout( HDC hDC
,
1234 const ImplWinFontData
& rWinFontData
, ImplWinFontEntry
& rWinFontEntry
)
1235 : WinLayout( hDC
, rWinFontData
, rWinFontEntry
),
1237 mpScriptItems( NULL
),
1238 mpVisualItems( NULL
),
1239 mpLogClusters( NULL
),
1240 mpCharWidths( NULL
),
1241 mnCharCapacity( 0 ),
1242 mnSubStringMin( 0 ),
1243 mnGlyphCapacity( 0 ),
1245 mpOutGlyphs( NULL
),
1246 mpGlyphAdvances( NULL
),
1247 mpJustifications( NULL
),
1248 mpGlyphOffsets( NULL
),
1249 mpVisualAttrs( NULL
),
1250 mpGlyphs2Chars( NULL
),
1251 mnMinKashidaGlyph( 0 ),
1252 mbDisableGlyphInjection( false )
1255 // -----------------------------------------------------------------------
1257 UniscribeLayout::~UniscribeLayout()
1259 delete[] mpScriptItems
;
1260 delete[] mpVisualItems
;
1261 delete[] mpLogClusters
;
1262 delete[] mpCharWidths
;
1263 delete[] mpOutGlyphs
;
1264 delete[] mpGlyphAdvances
;
1265 delete[] mpJustifications
;
1266 delete[] mpGlyphOffsets
;
1267 delete[] mpVisualAttrs
;
1268 delete[] mpGlyphs2Chars
;
1271 // -----------------------------------------------------------------------
1273 bool UniscribeLayout::LayoutText( ImplLayoutArgs
& rArgs
)
1275 // for a base layout only the context glyphs have to be dropped
1276 // => when the whole string is involved there is no extra context
1277 typedef std::vector
<int> TIntVector
;
1278 TIntVector aDropChars
;
1279 if( rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
)
1281 // calculate superfluous context char positions
1282 aDropChars
.push_back( 0 );
1283 aDropChars
.push_back( rArgs
.mnLength
);
1286 for( rArgs
.ResetPos(); rArgs
.GetNextRun( &nMin
, &nEnd
, &bRTL
); )
1288 aDropChars
.push_back( nMin
);
1289 aDropChars
.push_back( nEnd
);
1291 // prepare aDropChars for binary search which will allow to
1292 // not bother with visual items that will be dropped anyway
1293 std::sort( aDropChars
.begin(), aDropChars
.end() );
1297 // TODO: fix case when recyclying old UniscribeLayout object
1298 mnMinCharPos
= rArgs
.mnMinCharPos
;
1299 mnEndCharPos
= rArgs
.mnEndCharPos
;
1301 // determine script items from string
1303 // prepare itemization
1304 // TODO: try to avoid itemization since it costs a lot of performance
1305 SCRIPT_STATE aScriptState
= {0,false,false,false,false,false,false,false,false,0,0};
1306 aScriptState
.uBidiLevel
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
));
1307 aScriptState
.fOverrideDirection
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
));
1308 aScriptState
.fDigitSubstitute
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_SUBSTITUTE_DIGITS
));
1309 aScriptState
.fArabicNumContext
= aScriptState
.fDigitSubstitute
& aScriptState
.uBidiLevel
;
1310 DWORD nLangId
= 0; // TODO: get language from font
1311 SCRIPT_CONTROL aScriptControl
= {nLangId
,false,false,false,false,false,false,false,false,0};
1312 aScriptControl
.fNeutralOverride
= aScriptState
.fOverrideDirection
;
1313 aScriptControl
.fContextDigits
= (0 != (rArgs
.mnFlags
& SAL_LAYOUT_SUBSTITUTE_DIGITS
));
1314 // determine relevant substring and work only on it
1315 // when Bidi status is unknown we need to look at the whole string though
1317 int nSubStringEnd
= rArgs
.mnLength
;
1318 if( aScriptState
.fOverrideDirection
)
1320 // TODO: limit substring to portion limits
1321 mnSubStringMin
= rArgs
.mnMinCharPos
- 8;
1322 if( mnSubStringMin
< 0 )
1324 nSubStringEnd
= rArgs
.mnEndCharPos
+ 8;
1325 if( nSubStringEnd
> rArgs
.mnLength
)
1326 nSubStringEnd
= rArgs
.mnLength
;
1330 // now itemize the substring with its context
1331 for( int nItemCapacity
= 16;; nItemCapacity
*= 8 )
1333 mpScriptItems
= new SCRIPT_ITEM
[ nItemCapacity
];
1334 HRESULT nRC
= (*pScriptItemize
)(
1335 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ mnSubStringMin
), nSubStringEnd
- mnSubStringMin
,
1336 nItemCapacity
- 1, &aScriptControl
, &aScriptState
,
1337 mpScriptItems
, &mnItemCount
);
1338 if( !nRC
) // break loop when everything is correctly itemized
1341 // prepare bigger buffers for another itemization round
1342 delete[] mpScriptItems
;
1343 mpScriptItems
= NULL
;
1344 if( nRC
!= E_OUTOFMEMORY
)
1346 if( nItemCapacity
> (nSubStringEnd
- mnSubStringMin
) + 16 )
1350 // calculate the order of visual items
1353 // adjust char positions by substring offset
1354 for( nItem
= 0; nItem
<= mnItemCount
; ++nItem
)
1355 mpScriptItems
[ nItem
].iCharPos
+= mnSubStringMin
;
1356 // default visual item ordering
1357 mpVisualItems
= new VisualItem
[ mnItemCount
];
1358 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1360 // initialize char specific item info
1361 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
1362 SCRIPT_ITEM
* pScriptItem
= &mpScriptItems
[ nItem
];
1363 rVisualItem
.mpScriptItem
= pScriptItem
;
1364 rVisualItem
.mnMinCharPos
= pScriptItem
[0].iCharPos
;
1365 rVisualItem
.mnEndCharPos
= pScriptItem
[1].iCharPos
;
1368 // reorder visual item order if needed
1369 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
)
1371 // force RTL item ordering if requested
1372 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
)
1374 VisualItem
* pVI0
= &mpVisualItems
[ 0 ];
1375 VisualItem
* pVI1
= &mpVisualItems
[ mnItemCount
];
1376 while( pVI0
< --pVI1
)
1378 VisualItem aVtmp
= *pVI0
;
1384 else if( mnItemCount
> 1 )
1386 // apply bidi algorithm's rule L2 on item level
1387 // TODO: use faster L2 algorithm
1388 int nMaxBidiLevel
= 0;
1389 VisualItem
* pVI
= &mpVisualItems
[0];
1390 VisualItem
* const pVIend
= pVI
+ mnItemCount
;
1391 for(; pVI
< pVIend
; ++pVI
)
1392 if( nMaxBidiLevel
< pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1393 nMaxBidiLevel
= pVI
->mpScriptItem
->a
.s
.uBidiLevel
;
1395 while( --nMaxBidiLevel
>= 0 )
1397 for( pVI
= &mpVisualItems
[0]; pVI
< pVIend
; )
1399 // find item range that needs reordering
1400 for(; pVI
< pVIend
; ++pVI
)
1401 if( nMaxBidiLevel
< pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1403 VisualItem
* pVImin
= pVI
++;
1404 for(; pVI
< pVIend
; ++pVI
)
1405 if( nMaxBidiLevel
>= pVI
->mpScriptItem
->a
.s
.uBidiLevel
)
1407 VisualItem
* pVImax
= pVI
++;
1409 // reverse order of items in this range
1410 while( pVImin
< --pVImax
)
1412 VisualItem aVtmp
= *pVImin
;
1413 *(pVImin
++) = *pVImax
;
1421 // TODO: when reusing object reuse old allocations or delete them
1422 // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
1423 mnCharCapacity
= nSubStringEnd
;
1424 mpLogClusters
= new WORD
[ mnCharCapacity
];
1425 mpCharWidths
= new int[ mnCharCapacity
];
1428 mnGlyphCapacity
= 16 + 4 * (nSubStringEnd
- mnSubStringMin
); // worst case assumption
1429 mpGlyphAdvances
= new int[ mnGlyphCapacity
];
1430 mpOutGlyphs
= new WORD
[ mnGlyphCapacity
];
1431 mpGlyphOffsets
= new GOFFSET
[ mnGlyphCapacity
];
1432 mpVisualAttrs
= new SCRIPT_VISATTR
[ mnGlyphCapacity
];
1435 for( int j
= mnSubStringMin
; j
< nSubStringEnd
; ++j
)
1436 mpCharWidths
[j
] = 0;
1438 // layout script items
1439 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
1440 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1442 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
1444 // initialize glyph specific item info
1445 rVisualItem
.mnMinGlyphPos
= mnGlyphCount
;
1446 rVisualItem
.mnEndGlyphPos
= 0;
1447 rVisualItem
.mnXOffset
= nXOffset
;
1448 //rVisualItem.mnPixelWidth = 0;
1450 // shortcut ignorable items
1451 if( (rArgs
.mnEndCharPos
<= rVisualItem
.mnMinCharPos
)
1452 || (rArgs
.mnMinCharPos
>= rVisualItem
.mnEndCharPos
) )
1454 for( int i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; ++i
)
1455 mpLogClusters
[i
] = sal::static_int_cast
<WORD
>(~0U);
1459 // override bidi analysis if requested
1460 if( rArgs
.mnFlags
& SAL_LAYOUT_BIDI_STRONG
)
1462 // FIXME: is this intended ?
1463 rVisualItem
.mpScriptItem
->a
.fRTL
= (aScriptState
.uBidiLevel
& 1);
1464 rVisualItem
.mpScriptItem
->a
.s
.uBidiLevel
= aScriptState
.uBidiLevel
;
1465 rVisualItem
.mpScriptItem
->a
.s
.fOverrideDirection
= aScriptState
.fOverrideDirection
;
1468 // convert the unicodes to glyphs
1469 int nGlyphCount
= 0;
1470 int nCharCount
= rVisualItem
.mnEndCharPos
- rVisualItem
.mnMinCharPos
;
1471 HRESULT nRC
= (*pScriptShape
)( mhDC
, &rScriptCache
,
1472 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ rVisualItem
.mnMinCharPos
),
1474 mnGlyphCapacity
- rVisualItem
.mnMinGlyphPos
, // problem when >0xFFFF
1475 &rVisualItem
.mpScriptItem
->a
,
1476 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1477 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1478 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1481 // find and handle problems in the unicode to glyph conversion
1482 if( nRC
== USP_E_SCRIPT_NOT_IN_FONT
)
1484 // the whole visual item needs a fallback, but make sure that the next
1485 // fallback request is limited to the characters in the original request
1486 // => this is handled in ImplLayoutArgs::PrepareFallback()
1487 rArgs
.NeedFallback( rVisualItem
.mnMinCharPos
, rVisualItem
.mnEndCharPos
,
1488 rVisualItem
.IsRTL() );
1490 // don't bother to do a default layout in a fallback level
1491 if( 0 != (rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
) )
1494 // the primitive layout engine is good enough for the default layout
1495 rVisualItem
.mpScriptItem
->a
.eScript
= SCRIPT_UNDEFINED
;
1496 nRC
= (*pScriptShape
)( mhDC
, &rScriptCache
,
1497 reinterpret_cast<LPCWSTR
>(rArgs
.mpStr
+ rVisualItem
.mnMinCharPos
),
1499 mnGlyphCapacity
- rVisualItem
.mnMinGlyphPos
,
1500 &rVisualItem
.mpScriptItem
->a
,
1501 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1502 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1503 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1509 #if 0 // keep the glyphs for now because they are better than nothing
1510 // mark as NotDef glyphs
1511 for( i
= 0; i
< nGlyphCount
; ++i
)
1512 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 0;
1516 // something undefined happened => give up for this visual item
1518 else // if( nRC == 0 )
1520 // check if there are any NotDef glyphs
1521 for( i
= 0; i
< nGlyphCount
; ++i
)
1522 if( 0 == mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] )
1524 if( i
< nGlyphCount
)
1526 // clip charpos limits to the layout string without context
1527 int nMinCharPos
= rVisualItem
.mnMinCharPos
;
1528 if( nMinCharPos
< rArgs
.mnMinCharPos
)
1529 nMinCharPos
= rArgs
.mnMinCharPos
;
1530 int nEndCharPos
= rVisualItem
.mnEndCharPos
;
1531 if( nEndCharPos
> rArgs
.mnEndCharPos
)
1532 nEndCharPos
= rArgs
.mnEndCharPos
;
1533 // request fallback for individual NotDef glyphs
1536 // ignore non-NotDef glyphs
1537 if( 0 != mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] )
1539 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = DROPPED_OUTGLYPH
;
1540 // request fallback for the whole cell that resulted in a NotDef glyph
1541 // TODO: optimize algorithm
1542 const bool bRTL
= rVisualItem
.IsRTL();
1545 // request fallback for the left-to-right cell
1546 for( int c
= nMinCharPos
; c
< nEndCharPos
; ++c
)
1548 if( mpLogClusters
[ c
] == i
)
1550 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1551 if( rArgs
.mpStr
[ c
] == 0x2060 )
1552 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 1;
1555 rArgs
.NeedFallback( c
, false );
1561 // request fallback for the right to left cell
1562 for( int c
= nEndCharPos
; --c
>= nMinCharPos
; )
1564 if( mpLogClusters
[ c
] == i
)
1566 // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
1567 if( rArgs
.mpStr
[ c
] == 0x2060 )
1568 mpOutGlyphs
[ i
+ rVisualItem
.mnMinGlyphPos
] = 1;
1571 rArgs
.NeedFallback( c
, true );
1575 } while( ++i
< nGlyphCount
);
1579 // now place the glyphs
1580 nRC
= (*pScriptPlace
)( mhDC
, &rScriptCache
,
1581 mpOutGlyphs
+ rVisualItem
.mnMinGlyphPos
,
1583 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1584 &rVisualItem
.mpScriptItem
->a
,
1585 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
1586 mpGlyphOffsets
+ rVisualItem
.mnMinGlyphPos
,
1587 &rVisualItem
.maABCWidths
);
1592 // calculate the logical char widths from the glyph layout
1593 nRC
= (*pScriptGetLogicalWidths
)(
1594 &rVisualItem
.mpScriptItem
->a
,
1595 nCharCount
, nGlyphCount
,
1596 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
1597 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
1598 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
1599 mpCharWidths
+ rVisualItem
.mnMinCharPos
);
1601 // update the glyph counters
1602 mnGlyphCount
+= nGlyphCount
;
1603 rVisualItem
.mnEndGlyphPos
= mnGlyphCount
;
1607 if( GetItemSubrange( rVisualItem
, i
, nEndGlyphPos
) )
1608 for(; i
< nEndGlyphPos
; ++i
)
1609 nXOffset
+= mpGlyphAdvances
[ i
];
1611 // TODO: shrink glyphpos limits to match charpos/fallback limits
1612 //pVI->mnMinGlyphPos = nMinGlyphPos;
1613 //pVI->mnEndGlyphPos = nEndGlyphPos;
1615 // drop the superfluous context glyphs
1616 TIntVector::const_iterator it
= aDropChars
.begin();
1617 while( it
!= aDropChars
.end() )
1619 // find matching "drop range"
1620 int nMinDropPos
= *(it
++); // begin of drop range
1621 if( nMinDropPos
>= rVisualItem
.mnEndCharPos
)
1623 int nEndDropPos
= *(it
++); // end of drop range
1624 if( nEndDropPos
<= rVisualItem
.mnMinCharPos
)
1626 // clip "drop range" to visual item's char range
1627 if( nMinDropPos
<= rVisualItem
.mnMinCharPos
)
1629 nMinDropPos
= rVisualItem
.mnMinCharPos
;
1630 // drop the whole visual item if possible
1631 if( nEndDropPos
>= rVisualItem
.mnEndCharPos
)
1633 rVisualItem
.mnEndGlyphPos
= 0;
1637 if( nEndDropPos
> rVisualItem
.mnEndCharPos
)
1638 nEndDropPos
= rVisualItem
.mnEndCharPos
;
1640 // drop the glyphs which correspond to the charpos range
1641 // drop the corresponding glyphs in the cluster
1642 for( int c
= nMinDropPos
; c
< nEndDropPos
; ++c
)
1644 int nGlyphPos
= mpLogClusters
[c
] + rVisualItem
.mnMinGlyphPos
;
1645 // no need to bother when the cluster was already dropped
1646 if( mpOutGlyphs
[ nGlyphPos
] != DROPPED_OUTGLYPH
)
1650 mpOutGlyphs
[ nGlyphPos
] = DROPPED_OUTGLYPH
;
1651 // until the end of visual item
1652 if( ++nGlyphPos
>= rVisualItem
.mnEndGlyphPos
)
1654 // until the next cluster start
1655 if( mpVisualAttrs
[ nGlyphPos
].fClusterStart
)
1663 // scale layout metrics if needed
1664 // TODO: does it make the code more simple if the metric scaling
1665 // is moved to the methods that need metric scaling (e.g. FillDXArray())?
1666 if( mfFontScale
!= 1.0 )
1668 mnBaseAdv
= (int)((double)mnBaseAdv
*mfFontScale
);
1670 for( i
= 0; i
< mnItemCount
; ++i
)
1671 mpVisualItems
[i
].mnXOffset
= (int)((double)mpVisualItems
[i
].mnXOffset
*mfFontScale
);
1673 mnBaseAdv
= (int)((double)mnBaseAdv
*mfFontScale
);
1674 for( i
= 0; i
< mnGlyphCount
; ++i
)
1676 mpGlyphAdvances
[i
] = (int)(mpGlyphAdvances
[i
] * mfFontScale
);
1677 mpGlyphOffsets
[i
].du
= (LONG
)(mpGlyphOffsets
[i
].du
* mfFontScale
);
1678 mpGlyphOffsets
[i
].dv
= (LONG
)(mpGlyphOffsets
[i
].dv
* mfFontScale
);
1679 // mpJustifications are still NULL
1682 for( i
= mnSubStringMin
; i
< nSubStringEnd
; ++i
)
1683 mpCharWidths
[i
] = (int)(mpCharWidths
[i
] * mfFontScale
);
1689 // -----------------------------------------------------------------------
1691 // calculate the range of relevant glyphs for this visual item
1692 bool UniscribeLayout::GetItemSubrange( const VisualItem
& rVisualItem
,
1693 int& rMinGlyphPos
, int& rEndGlyphPos
) const
1695 // return early when nothing of interest in this item
1696 if( rVisualItem
.IsEmpty()
1697 || (rVisualItem
.mnEndCharPos
<= mnMinCharPos
)
1698 || (mnEndCharPos
<= rVisualItem
.mnMinCharPos
) )
1701 // default: subrange is complete range
1702 rMinGlyphPos
= rVisualItem
.mnMinGlyphPos
;
1703 rEndGlyphPos
= rVisualItem
.mnEndGlyphPos
;
1705 // return early when the whole item is of interest
1706 if( (mnMinCharPos
<= rVisualItem
.mnMinCharPos
)
1707 && (rVisualItem
.mnEndCharPos
<= mnEndCharPos
) )
1710 // get glyph range from char range by looking at cluster boundries
1711 // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
1712 rMinGlyphPos
= rVisualItem
.mnEndGlyphPos
;
1713 int nMaxGlyphPos
= 0;
1715 int i
= mnMinCharPos
;
1716 if( i
< rVisualItem
.mnMinCharPos
)
1717 i
= rVisualItem
.mnMinCharPos
;
1718 int nCharPosLimit
= rVisualItem
.mnEndCharPos
;
1719 if( nCharPosLimit
> mnEndCharPos
)
1720 nCharPosLimit
= mnEndCharPos
;
1721 for(; i
< nCharPosLimit
; ++i
)
1723 int n
= mpLogClusters
[ i
] + rVisualItem
.mnMinGlyphPos
;
1724 if( rMinGlyphPos
> n
)
1726 if( nMaxGlyphPos
< n
)
1729 if (nMaxGlyphPos
> rVisualItem
.mnEndGlyphPos
)
1730 nMaxGlyphPos
= rVisualItem
.mnEndGlyphPos
- 1;
1732 // extend the glyph range to account for all glyphs in referenced clusters
1733 if( !rVisualItem
.IsRTL() ) // LTR-item
1735 // extend to rightmost glyph of rightmost referenced cluster
1736 for( i
= nMaxGlyphPos
; ++i
< rVisualItem
.mnEndGlyphPos
; nMaxGlyphPos
= i
)
1737 if( mpVisualAttrs
[i
].fClusterStart
)
1742 // extend to leftmost glyph of leftmost referenced cluster
1743 for( i
= rMinGlyphPos
; --i
>= rVisualItem
.mnMinGlyphPos
; rMinGlyphPos
= i
)
1744 if( mpVisualAttrs
[i
].fClusterStart
)
1747 rEndGlyphPos
= nMaxGlyphPos
+ 1;
1752 // -----------------------------------------------------------------------
1754 int UniscribeLayout::GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
,
1755 int& nStartx8
, sal_Int32
* pGlyphAdvances
, int* pCharPosAry
) const
1757 // HACK to allow fake-glyph insertion (e.g. for kashidas)
1758 // TODO: use iterator idiom instead of GetNextGlyphs(...)
1759 // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
1760 int nSubIter
= nStartx8
& 0xff;
1761 int nStart
= nStartx8
>> 8;
1763 // check the glyph iterator
1764 if( nStart
> mnGlyphCount
) // nStart>MAX means no more glyphs
1767 // find the visual item for the nStart glyph position
1769 const VisualItem
* pVI
= mpVisualItems
;
1770 if( nStart
<= 0 ) // nStart<=0 requests the first visible glyph
1772 // find first visible item
1773 for(; nItem
< mnItemCount
; ++nItem
, ++pVI
)
1774 if( !pVI
->IsEmpty() )
1776 // it is possible that there are glyphs but no valid visual item
1777 // TODO: get rid of these visual items more early
1778 if( nItem
< mnItemCount
)
1779 nStart
= pVI
->mnMinGlyphPos
;
1781 else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1
1785 // find matching item
1786 for(; nItem
< mnItemCount
; ++nItem
, ++pVI
)
1787 if( (nStart
>= pVI
->mnMinGlyphPos
)
1788 && (nStart
< pVI
->mnEndGlyphPos
) )
1792 // after the last visual item there are no more glyphs
1793 if( (nItem
>= mnItemCount
) || (nStart
< 0) )
1795 nStartx8
= (mnGlyphCount
+ 1) << 8;
1799 // calculate the first glyph in the next visual item
1800 int nNextItemStart
= mnGlyphCount
;
1801 while( ++nItem
< mnItemCount
)
1803 if( mpVisualItems
[nItem
].IsEmpty() )
1805 nNextItemStart
= mpVisualItems
[nItem
].mnMinGlyphPos
;
1809 // get the range of relevant glyphs in this visual item
1810 int nMinGlyphPos
, nEndGlyphPos
;
1811 bool bRC
= GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
);
1812 DBG_ASSERT( bRC
, "USPLayout::GNG GISR() returned false" );
1815 nStartx8
= (mnGlyphCount
+ 1) << 8;
1819 // make sure nStart is inside the range of relevant glyphs
1820 if( nStart
< nMinGlyphPos
)
1821 nStart
= nMinGlyphPos
;
1823 // calculate the start glyph xoffset relative to layout's base position,
1824 // advance to next visual glyph position by using adjusted glyph widths
1825 // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
1826 long nXOffset
= pVI
->mnXOffset
;
1827 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
1828 for( int i
= nMinGlyphPos
; i
< nStart
; ++i
)
1829 nXOffset
+= pGlyphWidths
[ i
];
1831 // adjust the nXOffset relative to glyph cluster start
1832 int c
= mnMinCharPos
;
1833 if( !pVI
->IsRTL() ) // LTR-case
1835 // LTR case: subtract the remainder of the cell from xoffset
1836 int nTmpIndex
= mpLogClusters
[c
];
1837 while( (--c
>= pVI
->mnMinCharPos
)
1838 && (nTmpIndex
== mpLogClusters
[c
]) )
1839 nXOffset
-= mpCharWidths
[c
];
1843 // RTL case: add the remainder of the cell from xoffset
1844 int nTmpIndex
= mpLogClusters
[ pVI
->mnEndCharPos
- 1 ];
1845 while( (--c
>= pVI
->mnMinCharPos
)
1846 && (nTmpIndex
== mpLogClusters
[c
]) )
1847 nXOffset
+= mpCharWidths
[c
];
1849 // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
1850 if( mpJustifications
&& !bManualCellAlign
)
1851 nXOffset
+= mpJustifications
[ nStart
] - mpGlyphAdvances
[ nStart
];
1854 // create mpGlyphs2Chars[] if it is needed later
1855 if( pCharPosAry
&& !mpGlyphs2Chars
)
1857 // create and reset the new array
1858 mpGlyphs2Chars
= new int[ mnGlyphCapacity
];
1859 for( int i
= 0; i
< mnGlyphCount
; ++i
)
1860 mpGlyphs2Chars
[i
] = -1;
1861 // calculate the char->glyph mapping
1862 for( nItem
= 0; nItem
< mnItemCount
; ++nItem
)
1864 // ignore invisible visual items
1865 const VisualItem
& rVI
= mpVisualItems
[ nItem
];
1868 // calculate the mapping by using mpLogClusters[]
1869 // mpGlyphs2Chars[] should obey the logical order
1870 // => reversing the loop does this by overwriting higher logicals
1871 for( c
= rVI
.mnEndCharPos
; --c
>= rVI
.mnMinCharPos
; )
1873 int i
= mpLogClusters
[c
] + rVI
.mnMinGlyphPos
;
1874 mpGlyphs2Chars
[i
] = c
;
1879 // calculate the absolute position of the first result glyph in pixel units
1880 const GOFFSET aGOffset
= mpGlyphOffsets
[ nStart
];
1881 Point
aRelativePos( nXOffset
+ aGOffset
.du
, -aGOffset
.dv
);
1882 rPos
= GetDrawPosition( aRelativePos
);
1884 // fill the result arrays
1886 while( nCount
< nLen
)
1888 // prepare return values
1889 sal_GlyphId aGlyphId
= mpOutGlyphs
[ nStart
];
1890 int nGlyphWidth
= pGlyphWidths
[ nStart
];
1891 int nCharPos
= -1; // no need to determine charpos
1892 if( mpGlyphs2Chars
) // unless explicitly requested+provided
1893 nCharPos
= mpGlyphs2Chars
[ nStart
];
1895 // inject kashida glyphs if needed
1896 if( !mbDisableGlyphInjection
1898 && mnMinKashidaWidth
1899 && mpVisualAttrs
[nStart
].uJustification
>= SCRIPT_JUSTIFY_ARABIC_NORMAL
)
1901 // prepare draw position adjustment
1902 int nExtraOfs
= (nSubIter
++) * mnMinKashidaWidth
;
1903 // calculate space available for the injected glyphs
1904 nGlyphWidth
= mpGlyphAdvances
[ nStart
];
1905 const int nExtraWidth
= mpJustifications
[ nStart
] - nGlyphWidth
;
1906 const int nToFillWidth
= nExtraWidth
- nExtraOfs
;
1907 if( (4*nToFillWidth
>= mnMinKashidaWidth
) // prevent glyph-injection if there is no room
1908 || ((nSubIter
> 1) && (nToFillWidth
> 0)) ) // unless they can overlap with others
1910 // handle if there is not sufficient room for a full glyph
1911 if( nToFillWidth
< mnMinKashidaWidth
)
1913 // overlap it with the previously injected glyph if possible
1914 int nOverlap
= mnMinKashidaWidth
- nToFillWidth
;
1915 // else overlap it with both neighboring glyphs
1918 nExtraOfs
-= nOverlap
;
1920 nGlyphWidth
= mnMinKashidaWidth
;
1921 aGlyphId
= mnMinKashidaGlyph
;
1926 nExtraOfs
+= nToFillWidth
; // at right of cell
1927 nSubIter
= 0; // done with glyph injection
1929 if( !bManualCellAlign
)
1930 nExtraOfs
-= nExtraWidth
; // adjust for right-aligned cells
1932 // adjust the draw position for the injected-glyphs case
1935 aRelativePos
.X() += nExtraOfs
;
1936 rPos
= GetDrawPosition( aRelativePos
);
1940 // update return values
1941 *(pGlyphs
++) = aGlyphId
;
1942 if( pGlyphAdvances
)
1943 *(pGlyphAdvances
++) = nGlyphWidth
;
1945 *(pCharPosAry
++) = nCharPos
;
1947 // increment counter of returned glyphs
1950 // reduce code complexity by returning early in glyph-injection case
1954 // stop after the last visible glyph in this visual item
1955 if( ++nStart
>= nEndGlyphPos
)
1957 nStart
= nNextItemStart
;
1961 // RTL-justified glyph positioning is not easy
1962 // simplify the code by just returning only one glyph at a time
1963 if( mpJustifications
&& pVI
->IsRTL() )
1966 // stop when the x-position of the next glyph is unexpected
1967 if( !pGlyphAdvances
)
1968 if( (mpGlyphOffsets
&& (mpGlyphOffsets
[nStart
].du
!= aGOffset
.du
) )
1969 || (mpJustifications
&& (mpJustifications
[nStart
] != mpGlyphAdvances
[nStart
]) ) )
1972 // stop when the y-position of the next glyph is unexpected
1973 if( mpGlyphOffsets
&& (mpGlyphOffsets
[nStart
].dv
!= aGOffset
.dv
) )
1978 nStartx8
= (nStart
<< 8) + nSubIter
;
1982 // -----------------------------------------------------------------------
1984 void UniscribeLayout::MoveGlyph( int nStartx8
, long nNewXPos
)
1986 DBG_ASSERT( !(nStartx8
& 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
1987 int nStart
= nStartx8
>> 8;
1988 if( nStart
> mnGlyphCount
)
1991 VisualItem
* pVI
= mpVisualItems
;
1992 int nMinGlyphPos
= 0, nEndGlyphPos
;
1993 if( nStart
== 0 ) // nStart==0 for first visible glyph
1995 for( int i
= mnItemCount
; --i
>= 0; ++pVI
)
1996 if( GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
) )
1998 nStart
= nMinGlyphPos
;
1999 DBG_ASSERT( nStart
<= mnGlyphCount
, "USPLayout::MoveG overflow" );
2001 else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1
2004 for( int i
= mnItemCount
; --i
>= 0; ++pVI
)
2005 if( (nStart
>= pVI
->mnMinGlyphPos
) && (nStart
< pVI
->mnEndGlyphPos
) )
2007 bool bRC
= GetItemSubrange( *pVI
, nMinGlyphPos
, nEndGlyphPos
);
2008 (void)bRC
; // avoid var-not-used warning
2009 DBG_ASSERT( bRC
, "USPLayout::MoveG GISR() returned false" );
2012 long nDelta
= nNewXPos
- pVI
->mnXOffset
;
2013 if( nStart
> nMinGlyphPos
)
2015 // move the glyph by expanding its left glyph but ignore dropped glyphs
2016 int i
, nLastUndropped
= nMinGlyphPos
- 1;
2017 for( i
= nMinGlyphPos
; i
< nStart
; ++i
)
2019 if (mpOutGlyphs
[i
] != DROPPED_OUTGLYPH
)
2021 nDelta
-= (mpJustifications
)? mpJustifications
[ i
] : mpGlyphAdvances
[ i
];
2025 if (nLastUndropped
>= nMinGlyphPos
)
2027 mpGlyphAdvances
[ nLastUndropped
] += nDelta
;
2028 if (mpJustifications
) mpJustifications
[ nLastUndropped
] += nDelta
;
2032 pVI
->mnXOffset
+= nDelta
;
2037 // move the visual item by having an offset
2038 pVI
->mnXOffset
+= nDelta
;
2040 // move subsequent items - this often isn't necessary because subsequent
2041 // moves will correct subsequent items. However, if there is a contiguous
2042 // range not involving fallback which spans items, this will be needed
2043 while (++pVI
- mpVisualItems
< mnItemCount
)
2045 pVI
->mnXOffset
+= nDelta
;
2049 // -----------------------------------------------------------------------
2051 void UniscribeLayout::DropGlyph( int nStartx8
)
2053 DBG_ASSERT( !(nStartx8
& 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
2054 int nStart
= nStartx8
>> 8;
2055 DBG_ASSERT( nStart
<=mnGlyphCount
, "USPLayout::MoveG nStart overflow" );
2057 if( nStart
> 0 ) // nStart>0 means absolute glyph pos + 1
2059 else // nStart<=0 for first visible glyph
2061 VisualItem
* pVI
= mpVisualItems
;
2062 for( int i
= mnItemCount
, nDummy
; --i
>= 0; ++pVI
)
2063 if( GetItemSubrange( *pVI
, nStart
, nDummy
) )
2065 DBG_ASSERT( nStart
<= mnGlyphCount
, "USPLayout::DropG overflow" );
2067 int j
= pVI
->mnMinGlyphPos
;
2068 while (mpOutGlyphs
[j
] == DROPPED_OUTGLYPH
) j
++;
2071 pVI
->mnXOffset
+= ((mpJustifications
)? mpJustifications
[nStart
] : mpGlyphAdvances
[nStart
]);
2075 mpOutGlyphs
[ nStart
] = DROPPED_OUTGLYPH
;
2078 // -----------------------------------------------------------------------
2080 void UniscribeLayout::Simplify( bool /*bIsBase*/ )
2082 static const WCHAR cDroppedGlyph
= DROPPED_OUTGLYPH
;
2084 // if there are no dropped glyphs don't bother
2085 for( i
= 0; i
< mnGlyphCount
; ++i
)
2086 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2088 if( i
>= mnGlyphCount
)
2091 // prepare for sparse layout
2092 // => make sure mpGlyphs2Chars[] exists
2093 if( !mpGlyphs2Chars
)
2095 mpGlyphs2Chars
= new int[ mnGlyphCapacity
];
2096 for( i
= 0; i
< mnGlyphCount
; ++i
)
2097 mpGlyphs2Chars
[ i
] = -1;
2098 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2100 // skip invisible items
2101 VisualItem
& rVI
= mpVisualItems
[ nItem
];
2104 for( i
= rVI
.mnEndCharPos
; --i
>= rVI
.mnMinCharPos
; )
2106 int j
= mpLogClusters
[ i
] + rVI
.mnMinGlyphPos
;
2107 mpGlyphs2Chars
[ j
] = i
;
2112 // remove the dropped glyphs
2113 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
2114 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2116 VisualItem
& rVI
= mpVisualItems
[ nItem
];
2120 // mark replaced character widths
2121 for( i
= rVI
.mnMinCharPos
; i
< rVI
.mnEndCharPos
; ++i
)
2123 int j
= mpLogClusters
[ i
] + rVI
.mnMinGlyphPos
;
2124 if( mpOutGlyphs
[ j
] == cDroppedGlyph
)
2125 mpCharWidths
[ i
] = 0;
2128 // handle dropped glyphs at start of visual item
2129 int nMinGlyphPos
, nEndGlyphPos
, nOrigMinGlyphPos
= rVI
.mnMinGlyphPos
;
2130 GetItemSubrange( rVI
, nMinGlyphPos
, nEndGlyphPos
);
2132 while( (mpOutGlyphs
[i
] == cDroppedGlyph
) && (i
< nEndGlyphPos
) )
2134 //rVI.mnXOffset += pGlyphWidths[ i ];
2135 rVI
.mnMinGlyphPos
= ++i
;
2138 // when all glyphs in item got dropped mark it as empty
2139 if( i
>= nEndGlyphPos
)
2141 rVI
.mnEndGlyphPos
= 0;
2144 // If there are still glyphs in the cluster and mnMinGlyphPos
2145 // has changed then we need to remove the dropped glyphs at start
2146 // to correct logClusters, which is unsigned and relative to the
2148 if (rVI
.mnMinGlyphPos
!= nOrigMinGlyphPos
)
2150 // drop any glyphs in the visual item outside the range
2151 for (i
= nOrigMinGlyphPos
; i
< nMinGlyphPos
; i
++)
2152 mpOutGlyphs
[ i
] = cDroppedGlyph
;
2153 rVI
.mnMinGlyphPos
= i
= nOrigMinGlyphPos
;
2156 // handle dropped glyphs in the middle of visual item
2157 for(; i
< nEndGlyphPos
; ++i
)
2158 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2161 while( ++i
< nEndGlyphPos
)
2163 if( mpOutGlyphs
[ i
] == cDroppedGlyph
)
2165 mpOutGlyphs
[ j
] = mpOutGlyphs
[ i
];
2166 mpGlyphOffsets
[ j
] = mpGlyphOffsets
[ i
];
2167 mpVisualAttrs
[ j
] = mpVisualAttrs
[ i
];
2168 mpGlyphAdvances
[ j
] = mpGlyphAdvances
[ i
];
2169 if( mpJustifications
)
2170 mpJustifications
[ j
] = mpJustifications
[ i
];
2171 const int k
= mpGlyphs2Chars
[ i
];
2172 mpGlyphs2Chars
[ j
] = k
;
2173 const int nRelGlyphPos
= (j
++) - rVI
.mnMinGlyphPos
;
2174 if( k
< 0) // extra glyphs are already mapped
2176 mpLogClusters
[ k
] = static_cast<WORD
>(nRelGlyphPos
);
2179 rVI
.mnEndGlyphPos
= j
;
2183 // -----------------------------------------------------------------------
2185 void UniscribeLayout::DrawText( SalGraphics
& ) const
2187 HFONT hOrigFont
= DisableFontScaling();
2189 int nBaseClusterOffset
= 0;
2190 int nBaseGlyphPos
= -1;
2191 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2193 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2195 // skip if there is nothing to display
2196 int nMinGlyphPos
, nEndGlyphPos
;
2197 if( !GetItemSubrange( rVisualItem
, nMinGlyphPos
, nEndGlyphPos
) )
2200 if( nBaseGlyphPos
< 0 )
2202 // adjust draw position relative to cluster start
2203 if( rVisualItem
.IsRTL() )
2204 nBaseGlyphPos
= nEndGlyphPos
- 1;
2206 nBaseGlyphPos
= nMinGlyphPos
;
2208 const int* pGlyphWidths
;
2209 if( mpJustifications
)
2210 pGlyphWidths
= mpJustifications
;
2212 pGlyphWidths
= mpGlyphAdvances
;
2214 int i
= mnMinCharPos
;
2215 while( (--i
>= rVisualItem
.mnMinCharPos
)
2216 && (nBaseGlyphPos
== mpLogClusters
[i
]) )
2217 nBaseClusterOffset
+= mpCharWidths
[i
];
2219 if( !rVisualItem
.IsRTL() )
2220 nBaseClusterOffset
= -nBaseClusterOffset
;
2223 // now draw the matching glyphs in this item
2224 Point
aRelPos( rVisualItem
.mnXOffset
+ nBaseClusterOffset
, 0 );
2225 Point aPos
= GetDrawPosition( aRelPos
);
2226 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
2227 (*pScriptTextOut
)( mhDC
, &rScriptCache
,
2228 aPos
.X(), aPos
.Y(), 0, NULL
,
2229 &rVisualItem
.mpScriptItem
->a
, NULL
, 0,
2230 mpOutGlyphs
+ nMinGlyphPos
,
2231 nEndGlyphPos
- nMinGlyphPos
,
2232 mpGlyphAdvances
+ nMinGlyphPos
,
2233 mpJustifications
? mpJustifications
+ nMinGlyphPos
: NULL
,
2234 mpGlyphOffsets
+ nMinGlyphPos
);
2238 DeleteFont( SelectFont( mhDC
, hOrigFont
) );
2241 // -----------------------------------------------------------------------
2243 long UniscribeLayout::FillDXArray( long* pDXArray
) const
2245 // calculate width of the complete layout
2246 long nWidth
= mnBaseAdv
;
2247 for( int nItem
= mnItemCount
; --nItem
>= 0; )
2249 const VisualItem
& rVI
= mpVisualItems
[ nItem
];
2251 // skip if there is nothing to display
2252 int nMinGlyphPos
, nEndGlyphPos
;
2253 if( !GetItemSubrange( rVI
, nMinGlyphPos
, nEndGlyphPos
) )
2256 // width = xoffset + width of last item
2257 nWidth
= rVI
.mnXOffset
;
2258 const int* pGlyphWidths
= mpJustifications
? mpJustifications
: mpGlyphAdvances
;
2259 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2260 nWidth
+= pGlyphWidths
[i
];
2264 // copy the virtual char widths into pDXArray[]
2266 for( int i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2267 pDXArray
[ i
- mnMinCharPos
] = mpCharWidths
[ i
];
2272 // -----------------------------------------------------------------------
2274 int UniscribeLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
2277 for( int i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2279 nWidth
+= mpCharWidths
[ i
] * nFactor
;
2281 // check if the nMaxWidth still fits the current sub-layout
2282 if( nWidth
>= nMaxWidth
)
2284 // go back to cluster start
2285 // we have to find the visual item first since the mpLogClusters[]
2286 // needed to find the cluster start is relative to to the visual item
2287 int nMinGlyphIndex
= 0;
2288 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2290 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2291 nMinGlyphIndex
= rVisualItem
.mnMinGlyphPos
;
2292 if( (i
>= rVisualItem
.mnMinCharPos
)
2293 && (i
< rVisualItem
.mnEndCharPos
) )
2296 // now go back to the matching cluster start
2299 int nGlyphPos
= mpLogClusters
[i
] + nMinGlyphIndex
;
2300 if( 0 != mpVisualAttrs
[ nGlyphPos
].fClusterStart
)
2302 } while( --i
>= mnMinCharPos
);
2304 // if the cluster starts before the start of the visual item
2305 // then set the visual breakpoint before this item
2306 return mnMinCharPos
;
2309 // the visual break also depends on the nCharExtra between the characters
2310 nWidth
+= nCharExtra
;
2313 // the whole layout did fit inside the nMaxWidth
2317 // -----------------------------------------------------------------------
2319 void UniscribeLayout::GetCaretPositions( int nMaxIdx
, long* pCaretXArray
) const
2322 for( i
= 0; i
< nMaxIdx
; ++i
)
2323 pCaretXArray
[ i
] = -1;
2324 long* const pGlyphPos
= (long*)alloca( (mnGlyphCount
+1) * sizeof(long) );
2325 for( i
= 0; i
<= mnGlyphCount
; ++i
)
2326 pGlyphPos
[ i
] = -1;
2329 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2331 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2332 if( rVisualItem
.IsEmpty() )
2335 if (mnLayoutFlags
& SAL_LAYOUT_FOR_FALLBACK
)
2337 nXPos
= rVisualItem
.mnXOffset
;
2339 // get glyph positions
2340 // TODO: handle when rVisualItem's glyph range is only partially used
2341 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2343 pGlyphPos
[ i
] = nXPos
;
2344 nXPos
+= mpGlyphAdvances
[ i
];
2346 // rightmost position of this visualitem
2347 pGlyphPos
[ i
] = nXPos
;
2349 // convert glyph positions to character positions
2350 i
= rVisualItem
.mnMinCharPos
;
2351 if( i
< mnMinCharPos
)
2353 for(; (i
< rVisualItem
.mnEndCharPos
) && (i
< mnEndCharPos
); ++i
)
2355 int j
= mpLogClusters
[ i
] + rVisualItem
.mnMinGlyphPos
;
2356 int nCurrIdx
= i
* 2;
2357 if( !rVisualItem
.IsRTL() )
2359 // normal positions for LTR case
2360 pCaretXArray
[ nCurrIdx
] = pGlyphPos
[ j
];
2361 pCaretXArray
[ nCurrIdx
+1 ] = pGlyphPos
[ j
+1 ];
2365 // reverse positions for RTL case
2366 pCaretXArray
[ nCurrIdx
] = pGlyphPos
[ j
+1 ];
2367 pCaretXArray
[ nCurrIdx
+1 ] = pGlyphPos
[ j
];
2372 if (!(mnLayoutFlags
& SAL_LAYOUT_FOR_FALLBACK
))
2375 // fixup unknown character positions to neighbor
2376 for( i
= 0; i
< nMaxIdx
; ++i
)
2378 if( pCaretXArray
[ i
] >= 0 )
2379 nXPos
= pCaretXArray
[ i
];
2381 pCaretXArray
[ i
] = nXPos
;
2386 // -----------------------------------------------------------------------
2388 void UniscribeLayout::AdjustLayout( ImplLayoutArgs
& rArgs
)
2390 SalLayout::AdjustLayout( rArgs
);
2392 // adjust positions if requested
2393 if( rArgs
.mpDXArray
)
2394 ApplyDXArray( rArgs
);
2395 else if( rArgs
.mnLayoutWidth
)
2396 Justify( rArgs
.mnLayoutWidth
);
2399 // -----------------------------------------------------------------------
2401 void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs
& rArgs
)
2403 const long* pDXArray
= rArgs
.mpDXArray
;
2405 // increase char widths in string range to desired values
2406 bool bModified
= false;
2408 DBG_ASSERT( mnUnitsPerPixel
==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
2410 for( i
= mnMinCharPos
, j
= 0; i
< mnEndCharPos
; ++i
, ++j
)
2412 int nNewCharWidth
= (pDXArray
[j
] - nOldWidth
);
2413 // TODO: nNewCharWidth *= mnUnitsPerPixel;
2414 if( mpCharWidths
[i
] != nNewCharWidth
)
2416 mpCharWidths
[i
] = nNewCharWidth
;
2419 nOldWidth
= pDXArray
[j
];
2425 // initialize justifications array
2426 mpJustifications
= new int[ mnGlyphCapacity
];
2427 for( i
= 0; i
< mnGlyphCount
; ++i
)
2428 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2430 // apply new widths to script items
2432 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2434 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2436 // set the position of this visual item
2437 rVisualItem
.mnXOffset
= nXOffset
;
2439 // ignore empty visual items
2440 if( rVisualItem
.IsEmpty() )
2442 for (i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; i
++)
2443 nXOffset
+= mpCharWidths
[i
];
2446 // ignore irrelevant visual items
2447 if( (rVisualItem
.mnMinCharPos
>= mnEndCharPos
)
2448 || (rVisualItem
.mnEndCharPos
<= mnMinCharPos
) )
2451 // if needed prepare special handling for arabic justification
2452 rVisualItem
.mbHasKashidas
= false;
2453 if( rVisualItem
.IsRTL() )
2455 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2456 if ( (1U << mpVisualAttrs
[i
].uJustification
) & 0xFF82 ) // any Arabic justification
2457 { // excluding SCRIPT_JUSTIFY_NONE
2459 rVisualItem
.mbHasKashidas
= true;
2460 // so prepare for kashida handling
2461 InitKashidaHandling();
2465 if( rVisualItem
.HasKashidas() )
2466 for( i
= rVisualItem
.mnMinGlyphPos
; i
< rVisualItem
.mnEndGlyphPos
; ++i
)
2468 // TODO: check if we still need this hack after correction of kashida placing?
2469 // (i87688): apparently yes, we still need it!
2470 if ( mpVisualAttrs
[i
].uJustification
== SCRIPT_JUSTIFY_NONE
)
2471 // usp decided that justification can't be applied here
2472 // but maybe our Kashida algorithm thinks differently.
2473 // To avoid trouble (gaps within words, last character of
2474 // a word gets a Kashida appended) override this.
2476 // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
2477 // just because this previous hack (which I haven't understand, sorry) used
2478 // the same value to replace. Don't know if this is really the best
2479 // thing to do, but it seems to fix things
2480 mpVisualAttrs
[i
].uJustification
= SCRIPT_JUSTIFY_ARABIC_KASHIDA
;
2484 // convert virtual charwidths to glyph justification values
2485 HRESULT nRC
= (*pScriptApplyLogicalWidth
)(
2486 mpCharWidths
+ rVisualItem
.mnMinCharPos
,
2487 rVisualItem
.mnEndCharPos
- rVisualItem
.mnMinCharPos
,
2488 rVisualItem
.mnEndGlyphPos
- rVisualItem
.mnMinGlyphPos
,
2489 mpLogClusters
+ rVisualItem
.mnMinCharPos
,
2490 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
2491 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
2492 &rVisualItem
.mpScriptItem
->a
,
2493 &rVisualItem
.maABCWidths
,
2494 mpJustifications
+ rVisualItem
.mnMinGlyphPos
);
2498 delete[] mpJustifications
;
2499 mpJustifications
= NULL
;
2503 // to prepare for the next visual item
2504 // update nXOffset to the next items position
2505 // before the mpJustifications[] array gets modified
2506 int nMinGlyphPos
, nEndGlyphPos
;
2507 if( GetItemSubrange( rVisualItem
, nMinGlyphPos
, nEndGlyphPos
) )
2509 for( i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2510 nXOffset
+= mpJustifications
[ i
];
2512 if( rVisualItem
.mbHasKashidas
)
2513 KashidaItemFix( nMinGlyphPos
, nEndGlyphPos
);
2516 // workaround needed for older USP versions:
2517 // right align the justification-adjusted glyphs in their cells for RTL-items
2518 // unless the right alignment is done by inserting kashidas
2519 if( bManualCellAlign
&& rVisualItem
.IsRTL() && !rVisualItem
.HasKashidas() )
2521 for( i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2523 const int nXOffsetAdjust
= mpJustifications
[i
] - mpGlyphAdvances
[i
];
2524 // #i99862# skip diacritics, we mustn't add extra justification to diacritics
2525 int nIdxAdd
= i
- 1;
2526 while( (nIdxAdd
>= nMinGlyphPos
) && !mpGlyphAdvances
[nIdxAdd
] )
2528 if( nIdxAdd
< nMinGlyphPos
)
2529 rVisualItem
.mnXOffset
+= nXOffsetAdjust
;
2531 mpJustifications
[nIdxAdd
] += nXOffsetAdjust
;
2532 mpJustifications
[i
] -= nXOffsetAdjust
;
2538 // -----------------------------------------------------------------------
2540 void UniscribeLayout::InitKashidaHandling()
2542 if( mnMinKashidaGlyph
!= 0 ) // already initialized
2545 mrWinFontEntry
.InitKashidaHandling( mhDC
);
2546 mnMinKashidaWidth
= static_cast<int>(mfFontScale
* mrWinFontEntry
.GetMinKashidaWidth());
2547 mnMinKashidaGlyph
= mrWinFontEntry
.GetMinKashidaGlyph();
2550 // adjust the kashida placement matching to the WriterEngine
2551 void UniscribeLayout::KashidaItemFix( int nMinGlyphPos
, int nEndGlyphPos
)
2553 // workaround needed for all known USP versions:
2554 // ApplyLogicalWidth does not match ScriptJustify behaviour
2555 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; ++i
)
2558 if( (i
> nMinGlyphPos
&& !mpGlyphAdvances
[ i
-1 ])
2559 && (1U << mpVisualAttrs
[i
].uJustification
) & 0xFF83 ) // all Arabic justifiction types
2560 { // including SCRIPT_JUSTIFY_NONE
2561 // vowel, we do it like ScriptJustify does
2562 // the vowel gets the extra width
2563 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2564 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2565 mpJustifications
[ i
- 1 ] += nSpaceAdded
;
2569 // redistribute the widths for kashidas
2570 for( int i
= nMinGlyphPos
; i
< nEndGlyphPos
; )
2571 KashidaWordFix ( nMinGlyphPos
, nEndGlyphPos
, &i
);
2574 bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos
, int nEndGlyphPos
, int* pnCurrentPos
)
2576 // doing pixel work within a word.
2577 // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
2579 // find the next kashida
2580 int nMinPos
= *pnCurrentPos
;
2581 int nMaxPos
= *pnCurrentPos
;
2582 for( int i
= nMaxPos
; i
< nEndGlyphPos
; ++i
)
2584 if( (mpVisualAttrs
[ i
].uJustification
>= SCRIPT_JUSTIFY_ARABIC_BLANK
)
2585 && (mpVisualAttrs
[ i
].uJustification
< SCRIPT_JUSTIFY_ARABIC_NORMAL
) )
2589 *pnCurrentPos
= nMaxPos
+ 1;
2590 if( nMinPos
== nMaxPos
)
2593 // calculate the available space for an extra kashida
2596 for( int i
= nMaxPos
; i
>= nMinPos
; --i
)
2598 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2599 if( nSpaceAdded
> nMaxAdded
)
2602 nMaxAdded
= nSpaceAdded
;
2606 // return early if there is no need for an extra kashida
2607 if ( nMaxAdded
<= 0 )
2609 // return early if there is not enough space for an extra kashida
2610 if( 2*nMaxAdded
< mnMinKashidaWidth
)
2613 // redistribute the extra spacing to the kashida position
2614 for( int i
= nMinPos
; i
<= nMaxPos
; ++i
)
2618 // everything else should not have extra spacing
2619 long nSpaceAdded
= mpJustifications
[ i
] - mpGlyphAdvances
[ i
];
2620 if( nSpaceAdded
> 0 )
2622 mpJustifications
[ i
] -= nSpaceAdded
;
2623 mpJustifications
[ nKashPos
] += nSpaceAdded
;
2627 // check if we fulfill minimal kashida width
2628 long nSpaceAdded
= mpJustifications
[ nKashPos
] - mpGlyphAdvances
[ nKashPos
];
2629 if( nSpaceAdded
< mnMinKashidaWidth
)
2631 // ugly: steal some pixels
2633 if ( nMaxPos
- nMinPos
> 0 && ((mnMinKashidaWidth
- nSpaceAdded
) > (nMaxPos
- nMinPos
)))
2634 nSteal
= (mnMinKashidaWidth
- nSpaceAdded
) / (nMaxPos
- nMinPos
);
2635 for( int i
= nMinPos
; i
<= nMaxPos
; ++i
)
2639 nSteal
= Min( mnMinKashidaWidth
- nSpaceAdded
, nSteal
);
2642 mpJustifications
[ i
] -= nSteal
;
2643 mpJustifications
[ nKashPos
] += nSteal
;
2644 nSpaceAdded
+= nSteal
;
2646 if( nSpaceAdded
>= mnMinKashidaWidth
)
2652 long nSpaceMissing
= mnMinKashidaWidth
- nSpaceAdded
;
2653 if( nSpaceMissing
> 0 )
2655 // inner glyph: distribute extra space evenly
2656 if( (nMinPos
> nMinGlyphPos
) && (nMaxPos
< nEndGlyphPos
- 1) )
2658 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2659 long nHalfSpace
= nSpaceMissing
/ 2;
2660 mpJustifications
[ nMinPos
- 1 ] -= nHalfSpace
;
2661 mpJustifications
[ nMaxPos
+ 1 ] -= nSpaceMissing
- nHalfSpace
;
2663 // rightmost: left glyph gets extra space
2664 else if( nMinPos
> nMinGlyphPos
)
2666 mpJustifications
[ nMinPos
- 1 ] -= nSpaceMissing
;
2667 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2669 // leftmost: right glyph gets extra space
2670 else if( nMaxPos
< nEndGlyphPos
- 1 )
2672 mpJustifications
[ nKashPos
] += nSpaceMissing
;
2673 mpJustifications
[ nMaxPos
+ 1 ] -= nSpaceMissing
;
2682 // -----------------------------------------------------------------------
2684 void UniscribeLayout::Justify( long nNewWidth
)
2688 for( i
= mnMinCharPos
; i
< mnEndCharPos
; ++i
)
2689 nOldWidth
+= mpCharWidths
[ i
];
2690 if( nOldWidth
<= 0 )
2693 nNewWidth
*= mnUnitsPerPixel
; // convert into font units
2694 if( nNewWidth
== nOldWidth
)
2696 // prepare to distribute the extra width evenly among the visual items
2697 const double fStretch
= (double)nNewWidth
/ nOldWidth
;
2699 // initialize justifications array
2700 mpJustifications
= new int[ mnGlyphCapacity
];
2701 for( i
= 0; i
< mnGlyphCapacity
; ++i
)
2702 mpJustifications
[ i
] = mpGlyphAdvances
[ i
];
2704 // justify stretched script items
2706 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
2707 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2709 VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2710 if( rVisualItem
.IsEmpty() )
2713 if( (rVisualItem
.mnMinCharPos
< mnEndCharPos
)
2714 && (rVisualItem
.mnEndCharPos
> mnMinCharPos
) )
2716 long nItemWidth
= 0;
2717 for( i
= rVisualItem
.mnMinCharPos
; i
< rVisualItem
.mnEndCharPos
; ++i
)
2718 nItemWidth
+= mpCharWidths
[ i
];
2719 nItemWidth
= (int)((fStretch
- 1.0) * nItemWidth
+ 0.5);
2721 HRESULT nRC
= (*pScriptJustify
) (
2722 mpVisualAttrs
+ rVisualItem
.mnMinGlyphPos
,
2723 mpGlyphAdvances
+ rVisualItem
.mnMinGlyphPos
,
2724 rVisualItem
.mnEndGlyphPos
- rVisualItem
.mnMinGlyphPos
,
2727 mpJustifications
+ rVisualItem
.mnMinGlyphPos
);
2729 rVisualItem
.mnXOffset
= nXOffset
;
2730 nXOffset
+= nItemWidth
;
2735 // -----------------------------------------------------------------------
2737 bool UniscribeLayout::IsKashidaPosValid ( int nCharPos
) const
2739 // we have to find the visual item first since the mpLogClusters[]
2740 // needed to find the cluster start is relative to to the visual item
2741 int nMinGlyphIndex
= -1;
2742 for( int nItem
= 0; nItem
< mnItemCount
; ++nItem
)
2744 const VisualItem
& rVisualItem
= mpVisualItems
[ nItem
];
2745 if( (nCharPos
>= rVisualItem
.mnMinCharPos
)
2746 && (nCharPos
< rVisualItem
.mnEndCharPos
) )
2748 nMinGlyphIndex
= rVisualItem
.mnMinGlyphPos
;
2752 // Invalid char pos or leftmost glyph in visual item
2753 if ( nMinGlyphIndex
== -1 || !mpLogClusters
[ nCharPos
] )
2756 // This test didn't give the expected results
2757 /* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
2758 // two chars, one glyph
2761 const int nGlyphPos
= mpLogClusters
[ nCharPos
] + nMinGlyphIndex
;
2762 if( nGlyphPos
<= 0 )
2764 // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
2765 // and not SCRIPT_JUSTIFY_ARABIC_BLANK
2766 // special case: glyph to the left is vowel (no advance width)
2767 if ( mpVisualAttrs
[ nGlyphPos
-1 ].uJustification
== SCRIPT_JUSTIFY_ARABIC_BLANK
2768 || ( mpVisualAttrs
[ nGlyphPos
-1 ].uJustification
== SCRIPT_JUSTIFY_NONE
2769 && mpGlyphAdvances
[ nGlyphPos
-1 ] ))
2774 #endif // USE_UNISCRIBE
2776 #ifdef ENABLE_GRAPHITE
2778 class GraphiteLayoutWinImpl
: public GraphiteLayout
2781 GraphiteLayoutWinImpl(const gr::Font
& font
, ImplWinFontEntry
& rFont
)
2783 : GraphiteLayout(font
), mrFont(rFont
) {};
2784 virtual ~GraphiteLayoutWinImpl() throw() {};
2785 virtual sal_GlyphId
getKashidaGlyph(int & rWidth
);
2787 ImplWinFontEntry
& mrFont
;
2790 sal_GlyphId
GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth
)
2792 rWidth
= mrFont
.GetMinKashidaWidth();
2793 return mrFont
.GetMinKashidaGlyph();
2796 // This class uses the SIL Graphite engine to provide complex text layout services to the VCL
2799 class GraphiteWinLayout
: public WinLayout
2802 mutable GraphiteWinFont mpFont
;
2803 grutils::GrFeatureParser
* mpFeatures
;
2804 mutable GraphiteLayoutWinImpl maImpl
;
2806 GraphiteWinLayout(HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
);
2808 static bool IsGraphiteEnabledFont(HDC hDC
) throw();
2810 // used by upper layers
2811 virtual bool LayoutText( ImplLayoutArgs
& ); // first step of layout
2812 virtual void AdjustLayout( ImplLayoutArgs
& ); // adjusting after fallback etc.
2813 // virtual void InitFont() const;
2814 virtual void DrawText( SalGraphics
& ) const;
2816 // methods using string indexing
2817 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
=0, int nFactor
=1 ) const;
2818 virtual long FillDXArray( long* pDXArray
) const;
2820 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
2822 // methods using glyph indexing
2823 virtual int GetNextGlyphs(int nLen
, sal_GlyphId
* pGlyphIdxAry
, ::Point
& rPos
, int&,
2824 long* pGlyphAdvAry
= 0, int* pCharPosAry
= 0 ) const;
2826 // used by glyph+font+script fallback
2827 virtual void MoveGlyph( int nStart
, long nNewXPos
);
2828 virtual void DropGlyph( int nStart
);
2829 virtual void Simplify( bool bIsBase
);
2830 ~GraphiteWinLayout() { delete mpFeatures
; mpFeatures
= NULL
; };
2832 virtual void ReplaceDC(gr::Segment
& segment
) const;
2833 virtual void RestoreDC(gr::Segment
& segment
) const;
2836 bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC
) throw()
2838 return gr::WinFont::FontHasGraphiteTables(hDC
);
2841 GraphiteWinLayout::GraphiteWinLayout(HDC hDC
, const ImplWinFontData
& rWFD
, ImplWinFontEntry
& rWFE
) throw()
2842 : WinLayout(hDC
, rWFD
, rWFE
), mpFont(hDC
),
2843 maImpl(mpFont
, rWFE
)
2845 const rtl::OString aLang
= MsLangId::convertLanguageToIsoByteString( rWFE
.maFontSelData
.meLanguage
);
2846 rtl::OString name
= rtl::OUStringToOString(
2847 rWFE
.maFontSelData
.maTargetName
, RTL_TEXTENCODING_UTF8
);
2848 sal_Int32 nFeat
= name
.indexOf(grutils::GrFeatureParser::FEAT_PREFIX
) + 1;
2851 rtl::OString aFeat
= name
.copy(nFeat
, name
.getLength() - nFeat
);
2852 mpFeatures
= new grutils::GrFeatureParser(mpFont
, aFeat
.getStr(), aLang
.getStr());
2856 mpFeatures
= new grutils::GrFeatureParser(mpFont
, aLang
.getStr());
2858 maImpl
.SetFeatures(mpFeatures
);
2861 void GraphiteWinLayout::ReplaceDC(gr::Segment
& segment
) const
2863 COLORREF color
= GetTextColor(mhDC
);
2864 dynamic_cast<gr::WinFont
&>(segment
.getFont()).replaceDC(mhDC
);
2865 SetTextColor(mhDC
, color
);
2868 void GraphiteWinLayout::RestoreDC(gr::Segment
& segment
) const
2870 dynamic_cast<gr::WinFont
&>(segment
.getFont()).restoreDC();
2873 bool GraphiteWinLayout::LayoutText( ImplLayoutArgs
& args
)
2875 if (args
.mnMinCharPos
>= args
.mnEndCharPos
)
2880 HFONT hUnRotatedFont
;
2881 if (args
.mnOrientation
)
2883 // Graphite gets very confused if the font is rotated
2885 ::GetObjectW( mhFont
, sizeof(LOGFONTW
), &aLogFont
);
2886 aLogFont
.lfEscapement
= 0;
2887 aLogFont
.lfOrientation
= 0;
2888 hUnRotatedFont
= ::CreateFontIndirectW( &aLogFont
);
2889 ::SelectFont(mhDC
, hUnRotatedFont
);
2891 WinLayout::AdjustLayout(args
);
2892 mpFont
.replaceDC(mhDC
);
2893 maImpl
.SetFontScale(WinLayout::mfFontScale
);
2894 //bool succeeded = maImpl.LayoutText(args);
2896 GrSegRecord
* pSegRecord
= NULL
;
2897 gr::Segment
* pSegment
= maImpl
.CreateSegment(args
, &pSegRecord
);
2899 gr::Segment
* pSegment
= maImpl
.CreateSegment(args
);
2901 bool bSucceeded
= false;
2904 // replace the DC on the font within the segment
2905 ReplaceDC(*pSegment
);
2906 // create glyph vectors
2908 bSucceeded
= maImpl
.LayoutGlyphs(args
, pSegment
, pSegRecord
);
2910 bSucceeded
= maImpl
.LayoutGlyphs(args
, pSegment
);
2912 // restore original DC
2913 RestoreDC(*pSegment
);
2915 if (pSegRecord
) pSegRecord
->unlock();
2916 else delete pSegment
;
2922 if (args
.mnOrientation
)
2924 // restore the rotated font
2925 ::SelectFont(mhDC
, mhFont
);
2926 ::DeleteObject(hUnRotatedFont
);
2931 void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs
& rArgs
)
2933 WinLayout::AdjustLayout(rArgs
);
2934 maImpl
.DrawBase() = WinLayout::maDrawBase
;
2935 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
2936 if ( (rArgs
.mnFlags
& SAL_LAYOUT_BIDI_RTL
) && rArgs
.mpDXArray
)
2938 mrWinFontEntry
.InitKashidaHandling(mhDC
);
2940 maImpl
.AdjustLayout(rArgs
);
2943 void GraphiteWinLayout::DrawText(SalGraphics
&sal_graphics
) const
2945 HFONT hOrigFont
= DisableFontScaling();
2946 HDC aHDC
= static_cast<WinSalGraphics
&>(sal_graphics
).mhDC
;
2947 maImpl
.DrawBase() = WinLayout::maDrawBase
;
2948 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
2949 const int MAX_GLYPHS
= 2;
2950 sal_GlyphId glyphIntStr
[MAX_GLYPHS
];
2951 WORD glyphWStr
[MAX_GLYPHS
];
2957 nGlyphs
= maImpl
.GetNextGlyphs(1, glyphIntStr
, aPos
, glyphIndex
);
2960 std::copy(glyphIntStr
, glyphIntStr
+ nGlyphs
, glyphWStr
);
2961 ::ExtTextOutW(aHDC
, aPos
.X(), aPos
.Y(), ETO_GLYPH_INDEX
,
2962 NULL
, (LPCWSTR
)&(glyphWStr
), nGlyphs
, NULL
);
2965 DeleteFont( SelectFont( mhDC
, hOrigFont
) );
2968 int GraphiteWinLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
2970 mpFont
.replaceDC(mhDC
);
2971 int nBreak
= maImpl
.GetTextBreak(nMaxWidth
, nCharExtra
, nFactor
);
2976 long GraphiteWinLayout::FillDXArray( long* pDXArray
) const
2978 return maImpl
.FillDXArray(pDXArray
);
2981 void GraphiteWinLayout::GetCaretPositions( int nArraySize
, long* pCaretXArray
) const
2983 maImpl
.GetCaretPositions(nArraySize
, pCaretXArray
);
2986 int GraphiteWinLayout::GetNextGlyphs( int length
, sal_GlyphId
* glyph_out
,
2987 ::Point
& pos_out
, int &glyph_slot
, long * glyph_adv
, int *char_index
) const
2989 maImpl
.DrawBase() = WinLayout::maDrawBase
;
2990 maImpl
.DrawOffset() = WinLayout::maDrawOffset
;
2991 return maImpl
.GetNextGlyphs(length
, glyph_out
, pos_out
, glyph_slot
, glyph_adv
, char_index
);
2994 void GraphiteWinLayout::MoveGlyph( int glyph_idx
, long new_x_pos
)
2996 maImpl
.MoveGlyph(glyph_idx
, new_x_pos
);
2999 void GraphiteWinLayout::DropGlyph( int glyph_idx
)
3001 maImpl
.DropGlyph(glyph_idx
);
3004 void GraphiteWinLayout::Simplify( bool is_base
)
3006 maImpl
.Simplify(is_base
);
3008 #endif // ENABLE_GRAPHITE
3009 // =======================================================================
3011 SalLayout
* WinSalGraphics::GetTextLayout( ImplLayoutArgs
& rArgs
, int nFallbackLevel
)
3013 DBG_ASSERT( mpWinFontEntry
[nFallbackLevel
], "WinSalGraphics mpWinFontEntry==NULL");
3015 WinLayout
* pWinLayout
= NULL
;
3017 const ImplWinFontData
& rFontFace
= *mpWinFontData
[ nFallbackLevel
];
3018 ImplWinFontEntry
& rFontInstance
= *mpWinFontEntry
[ nFallbackLevel
];
3020 #if defined( USE_UNISCRIBE )
3021 if( !(rArgs
.mnFlags
& SAL_LAYOUT_COMPLEX_DISABLED
)
3022 && (aUspModule
|| (bUspEnabled
&& InitUSP())) ) // CTL layout engine
3024 #ifdef ENABLE_GRAPHITE
3025 if (rFontFace
.SupportsGraphite())
3026 pWinLayout
= new GraphiteWinLayout(mhDC
, rFontFace
, rFontInstance
);
3028 #endif // ENABLE_GRAPHITE
3029 // script complexity is determined in upper layers
3030 pWinLayout
= new UniscribeLayout( mhDC
, rFontFace
, rFontInstance
);
3031 // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
3032 // the created UniscribeLayout, otherwise the data passed into the
3033 // constructor might become invalid too early
3036 #endif // USE_UNISCRIBE
3038 #ifdef GCP_KERN_HACK
3039 if( (rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) && !rFontInstance
.HasKernData() )
3041 // TODO: directly cache kerning info in the rFontInstance
3042 // TODO: get rid of kerning methods+data in WinSalGraphics object
3043 GetKernPairs( 0, NULL
);
3044 rFontInstance
.SetKernData( mnFontKernPairCount
, mpFontKernPairs
);
3046 #endif // GCP_KERN_HACK
3048 BYTE eCharSet
= ANSI_CHARSET
;
3050 eCharSet
= mpLogFont
->lfCharSet
;
3051 #ifdef ENABLE_GRAPHITE
3052 if (rFontFace
.SupportsGraphite())
3053 pWinLayout
= new GraphiteWinLayout(mhDC
, rFontFace
, rFontInstance
);
3055 #endif // ENABLE_GRAPHITE
3056 pWinLayout
= new SimpleWinLayout( mhDC
, eCharSet
, rFontFace
, rFontInstance
);
3059 if( mfFontScale
!= 1.0 )
3060 pWinLayout
->SetFontScale( mfFontScale
);
3065 // -----------------------------------------------------------------------
3067 int WinSalGraphics::GetMinKashidaWidth()
3069 if( !mpWinFontEntry
[0] )
3071 mpWinFontEntry
[0]->InitKashidaHandling( mhDC
);
3072 int nMinKashida
= static_cast<int>(mfFontScale
* mpWinFontEntry
[0]->GetMinKashidaWidth());
3076 // =======================================================================
3078 ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData
& rFSD
)
3079 : ImplFontEntry( rFSD
)
3081 , mpKerningPairs( NULL
)
3082 , mnKerningPairs( -1 )
3083 , mnMinKashidaWidth( -1 )
3084 , mnMinKashidaGlyph( -1 )
3086 #ifdef USE_UNISCRIBE
3087 maScriptCache
= NULL
;
3088 #endif // USE_UNISCRIBE
3091 // -----------------------------------------------------------------------
3093 ImplWinFontEntry::~ImplWinFontEntry()
3095 #ifdef USE_UNISCRIBE
3096 if( maScriptCache
!= NULL
)
3097 (*pScriptFreeCache
)( &maScriptCache
);
3098 #endif // USE_UNISCRIBE
3099 #ifdef GCP_KERN_HACK
3100 delete[] mpKerningPairs
;
3101 #endif // GCP_KERN_HACK
3104 // -----------------------------------------------------------------------
3106 bool ImplWinFontEntry::HasKernData() const
3108 return (mnKerningPairs
>= 0);
3111 // -----------------------------------------------------------------------
3113 void ImplWinFontEntry::SetKernData( int nPairCount
, const KERNINGPAIR
* pPairData
)
3115 mnKerningPairs
= nPairCount
;
3116 mpKerningPairs
= new KERNINGPAIR
[ mnKerningPairs
];
3117 ::memcpy( mpKerningPairs
, (const void*)pPairData
, nPairCount
*sizeof(KERNINGPAIR
) );
3120 // -----------------------------------------------------------------------
3122 int ImplWinFontEntry::GetKerning( sal_Unicode cLeft
, sal_Unicode cRight
) const
3124 int nKernAmount
= 0;
3125 if( mpKerningPairs
)
3127 const KERNINGPAIR aRefPair
= { cLeft
, cRight
, 0 };
3128 const KERNINGPAIR
* pFirstPair
= mpKerningPairs
;
3129 const KERNINGPAIR
* pEndPair
= mpKerningPairs
+ mnKerningPairs
;
3130 const KERNINGPAIR
* pPair
= std::lower_bound( pFirstPair
,
3131 pEndPair
, aRefPair
, ImplCmpKernData
);
3132 if( (pPair
!= pEndPair
)
3133 && (pPair
->wFirst
== aRefPair
.wFirst
)
3134 && (pPair
->wSecond
== aRefPair
.wSecond
) )
3135 nKernAmount
= pPair
->iKernAmount
;
3141 // -----------------------------------------------------------------------
3143 bool ImplWinFontEntry::InitKashidaHandling( HDC hDC
)
3145 if( mnMinKashidaWidth
>= 0 ) // already cached?
3146 return mnMinKashidaWidth
;
3148 // initialize the kashida width
3149 mnMinKashidaWidth
= 0;
3150 mnMinKashidaGlyph
= 0;
3151 #ifdef USE_UNISCRIBE
3152 if (aUspModule
|| (bUspEnabled
&& InitUSP()))
3154 SCRIPT_FONTPROPERTIES aFontProperties
;
3155 aFontProperties
.cBytes
= sizeof (aFontProperties
);
3156 SCRIPT_CACHE
& rScriptCache
= GetScriptCache();
3157 HRESULT nRC
= (*pScriptGetFontProperties
)( hDC
, &rScriptCache
, &aFontProperties
);
3160 mnMinKashidaWidth
= aFontProperties
.iKashidaWidth
;
3161 mnMinKashidaGlyph
= aFontProperties
.wgKashida
;
3163 #endif // USE_UNISCRIBE
3168 // =======================================================================
3170 ImplFontData
* ImplWinFontData::Clone() const
3173 mpUnicodeMap
->AddReference();
3174 ImplFontData
* pClone
= new ImplWinFontData( *this );
3178 // -----------------------------------------------------------------------
3180 ImplFontEntry
* ImplWinFontData::CreateFontInstance( ImplFontSelectData
& rFSD
) const
3182 ImplFontEntry
* pEntry
= new ImplWinFontEntry( rFSD
);
3186 // =======================================================================