1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: os2layout.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <tools/svwin.h>
33 #include <rtl/ustring.hxx>
34 #include <osl/module.h>
36 #include <saldata.hxx>
37 #include <vcl/sallayout.hxx>
49 #endif // GCP_KERN_HACK
51 // for GetMirroredChar
52 #include <vcl/svapp.hxx>
55 typedef std::hash_map
<int,int> IntMap
;
57 #define DROPPED_OUTGLYPH 0xFFFF
61 // =======================================================================
63 // OS/2 specific physical font instance
64 class ImplOs2FontEntry
: public ImplFontEntry
67 ImplOs2FontEntry( ImplFontSelectData
& );
71 // TODO: also add HFONT??? Watch out for issues with too many active fonts...
75 bool HasKernData() const;
76 void SetKernData( int, const KERNINGPAIRS
* );
77 int GetKerning( sal_Unicode
, sal_Unicode
) const;
79 KERNINGPAIRS
* mpKerningPairs
;
81 #endif // GCP_KERN_HACK
84 int GetCachedGlyphWidth( int nCharCode
) const;
85 void CacheGlyphWidth( int nCharCode
, int nCharWidth
);
90 // -----------------------------------------------------------------------
92 inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode
, int nCharWidth
)
94 maWidthMap
[ nCharCode
] = nCharWidth
;
97 inline int ImplOs2FontEntry::GetCachedGlyphWidth( int nCharCode
) const
99 IntMap::const_iterator it
= maWidthMap
.find( nCharCode
);
100 if( it
== maWidthMap
.end() )
105 // =======================================================================
107 class Os2Layout
: public SalLayout
110 Os2Layout( HDC
, const ImplOs2FontData
&, ImplOs2FontEntry
& );
111 virtual void InitFont() const;
112 void SetFontScale( float f
) { mfFontScale
= f
; }
113 float GetFontScale() const { return mfFontScale
; }
116 HPS mhPS
; // OS2 device handle
118 int mnBaseAdv
; // x-offset relative to Layout origin
119 float mfFontScale
; // allows metrics emulation of huge font sizes
121 const ImplOs2FontData
& mrOs2FontData
;
122 ImplOs2FontEntry
& mrOs2FontEntry
;
125 // =======================================================================
127 class Os2SalLayout
: public Os2Layout
130 Os2SalLayout( HPS
, BYTE nCharSet
, const ImplOs2FontData
&, ImplOs2FontEntry
& );
131 virtual ~Os2SalLayout();
133 virtual bool LayoutText( ImplLayoutArgs
& );
134 virtual void AdjustLayout( ImplLayoutArgs
& );
135 virtual void DrawText( SalGraphics
& ) const;
137 virtual int GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int&,
138 sal_Int32
* pGlyphAdvances
, int* pCharIndexes
) const;
140 virtual long FillDXArray( long* pDXArray
) const;
141 virtual int GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const;
142 virtual void GetCaretPositions( int nArraySize
, long* pCaretXArray
) const;
144 // for glyph+font+script fallback
145 virtual void MoveGlyph( int nStart
, long nNewXPos
);
146 virtual void DropGlyph( int nStart
);
147 virtual void Simplify( bool bIsBase
);
150 void Justify( long nNewWidth
);
151 void ApplyDXArray( const ImplLayoutArgs
& );
158 sal_Unicode
* mpOutGlyphs
;
159 int* mpGlyphAdvances
; // if possible this is shared with mpGlyphAdvances[]
160 int* mpGlyphOrigAdvs
;
161 int* mpCharWidths
; // map rel char pos to char width
162 int* mpChars2Glyphs
; // map rel char pos to abs glyph pos
163 int* mpGlyphs2Chars
; // map abs glyph pos to abs char pos
164 bool* mpGlyphRTLFlags
; // BiDi status for glyphs: true=>RTL
165 mutable long mnWidth
;
166 bool mbDisableGlyphs
;
173 // =======================================================================
175 Os2Layout::Os2Layout( HPS hPS
, const ImplOs2FontData
& rWFD
, ImplOs2FontEntry
& rWFE
)
179 mrOs2FontData( rWFD
),
180 mrOs2FontEntry( rWFE
)
183 fSuccess
= Ft2QueryLogicalFont( mhPS
, LCID_BASE
, NULL
, &mhFont
, sizeof(FATTRS
));
186 // -----------------------------------------------------------------------
188 void Os2Layout::InitFont() const
190 // select fallback level 0 font
191 APIRET rc
= Ft2CreateLogFont( mhPS
, NULL
, LCID_BASE
, (PFATTRS
)&mhFont
);
194 // =======================================================================
196 Os2SalLayout::Os2SalLayout( HPS hPS
, BYTE nCharSet
,
197 const ImplOs2FontData
& rOs2FontData
, ImplOs2FontEntry
& rOs2FontEntry
)
198 : Os2Layout( hPS
, rOs2FontData
, rOs2FontEntry
),
202 mpGlyphAdvances( NULL
),
203 mpGlyphOrigAdvs( NULL
),
204 mpCharWidths( NULL
),
205 mpChars2Glyphs( NULL
),
206 mpGlyphs2Chars( NULL
),
207 mpGlyphRTLFlags( NULL
),
210 mnCharSet( nCharSet
),
211 mbDisableGlyphs( false )
213 mbDisableGlyphs
= true;
216 // -----------------------------------------------------------------------
218 Os2SalLayout::~Os2SalLayout()
220 delete[] mpGlyphRTLFlags
;
221 delete[] mpGlyphs2Chars
;
222 delete[] mpChars2Glyphs
;
223 if( mpCharWidths
!= mpGlyphAdvances
)
224 delete[] mpCharWidths
;
225 delete[] mpGlyphOrigAdvs
;
226 delete[] mpGlyphAdvances
;
227 delete[] mpOutGlyphs
;
230 // -----------------------------------------------------------------------
232 bool Os2SalLayout::LayoutText( ImplLayoutArgs
& rArgs
)
235 // TODO: fix case when recyclying old Os2SalLayout object
236 mbDisableGlyphs
|= ((rArgs
.mnFlags
& SAL_LAYOUT_DISABLE_GLYPH_PROCESSING
) != 0);
237 mnCharCount
= rArgs
.mnEndCharPos
- rArgs
.mnMinCharPos
;
239 if( !mbDisableGlyphs
)
241 // Win32 glyph APIs have serious problems with vertical layout
242 // => workaround is to use the unicode methods then
243 if( rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
)
244 mbDisableGlyphs
= true;
246 // use cached value from font face
247 mbDisableGlyphs
= mrOs2FontData
.IsGlyphApiDisabled();
250 // TODO: use a cached value for bDisableAsianKern from upper layers
252 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
254 TEXTMETRICA aTextMetricA
;
255 if( ::GetTextMetricsA( mhDC
, &aTextMetricA
)
256 && !(aTextMetricA
.tmPitchAndFamily
& TMPF_FIXED_PITCH
) )
257 rArgs
.mnFlags
&= ~SAL_LAYOUT_KERNING_ASIAN
;
265 bool bVertical
= (rArgs
.mnFlags
& SAL_LAYOUT_VERTICAL
) != 0;
267 // count the number of chars to process if no RTL run
269 bool bHasRTL
= false;
270 while( rArgs
.GetNextRun( &i
, &j
, &bHasRTL
) && !bHasRTL
)
271 mnGlyphCount
+= j
- i
;
273 // if there are RTL runs we need room to remember individual BiDi flags
276 mpGlyphRTLFlags
= new bool[ mnCharCount
];
277 for( i
= 0; i
< mnCharCount
; ++i
)
278 mpGlyphRTLFlags
[i
] = false;
281 // rewrite the logical string if needed to prepare for the API calls
282 const sal_Unicode
* pBidiStr
= rArgs
.mpStr
+ rArgs
.mnMinCharPos
;
283 if( (mnGlyphCount
!= mnCharCount
) || bVertical
)
285 // we need to rewrite the pBidiStr when any of
286 // - BiDirectional layout
288 // - partial runs (e.g. with control chars or for glyph fallback)
290 sal_Unicode
* pRewrittenStr
= (sal_Unicode
*)alloca( mnCharCount
* sizeof(sal_Unicode
) );
291 pBidiStr
= pRewrittenStr
;
293 // note: glyph to char mapping is relative to first character
294 mpChars2Glyphs
= new int[ mnCharCount
];
295 mpGlyphs2Chars
= new int[ mnCharCount
];
296 for( i
= 0; i
< mnCharCount
; ++i
)
297 mpChars2Glyphs
[i
] = mpGlyphs2Chars
[i
] = -1;
302 while( rArgs
.GetNextRun( &i
, &j
, &bIsRTL
) )
306 // get the next leftmost character in this run
307 int nCharPos
= bIsRTL
? --j
: i
++;
308 sal_Unicode cChar
= rArgs
.mpStr
[ nCharPos
];
310 // in the RTL case mirror the character and remember its RTL status
313 cChar
= ::GetMirroredChar( cChar
);
314 mpGlyphRTLFlags
[ mnGlyphCount
] = true;
317 // for vertical writing use vertical alternatives
320 sal_Unicode cVert
= ::GetVerticalChar( cChar
);
325 // rewrite the original string
326 // update the mappings between original and rewritten string
327 pRewrittenStr
[ mnGlyphCount
] = cChar
;
328 mpGlyphs2Chars
[ mnGlyphCount
] = nCharPos
;
329 mpChars2Glyphs
[ nCharPos
- rArgs
.mnMinCharPos
] = mnGlyphCount
;
335 mpOutGlyphs
= new sal_Unicode
[ mnGlyphCount
];
336 mpGlyphAdvances
= new int[ mnGlyphCount
];
338 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_PAIRS
| SAL_LAYOUT_KERNING_ASIAN
) )
339 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
341 #ifndef GCP_KERN_HACK
342 DWORD nGcpOption
= 0;
343 // enable kerning if requested
344 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
345 nGcpOption
|= GCP_USEKERNING
;
346 #endif // GCP_KERN_HACK
348 LONG lLcid
= Ft2QueryCharSet( mhPS
);
350 for( i
= 0; i
< mnGlyphCount
; ++i
)
351 mpOutGlyphs
[i
] = pBidiStr
[ i
];
353 for( i
= 0; i
< mnGlyphCount
; ++i
)
355 const sal_Unicode
* pCodes
= &pBidiStr
[i
];
356 // check for surrogate pairs
357 if( (pCodes
[0] & 0xFC00) == 0xDC00 )
359 bool bSurrogate
= ((pCodes
[0] & 0xFC00) == 0xD800);
361 // get the width of the corresponding code point
362 int nCharCode
= pCodes
[0];
364 nCharCode
= 0x10000 + ((pCodes
[0] & 0x03FF) << 10) + (pCodes
[1] & 0x03FF);
365 int nGlyphWidth
= mrOs2FontEntry
.GetCachedGlyphWidth( nCharCode
);
366 if( nGlyphWidth
== -1 )
368 if (!Ft2QueryStringWidthW( mhPS
, (LPWSTR
)&pCodes
[0], 1, (LONG
*)&nGlyphWidth
))
370 mrOs2FontEntry
.CacheGlyphWidth( nCharCode
, nGlyphWidth
);
372 mpGlyphAdvances
[ i
] = nGlyphWidth
;
373 mnWidth
+= nGlyphWidth
;
375 // remaining codes of surrogate pair get a zero width
377 mpGlyphAdvances
[ i
+1 ] = 0;
379 // check with the font face if glyph fallback is needed
380 if( mrOs2FontData
.HasChar( nCharCode
) )
382 // Type1 charmaps are not complete (or buggy), use FT2 to check again
383 if (Ft2FontSupportsUnicodeChar( mhPS
, lLcid
, TRUE
, nCharCode
))
386 #if OSL_DEBUG_LEVEL>0
387 debug_printf("Os2SalLayout::LayoutText font does not support unicode char\n");
389 // request glyph fallback at this position in the string
390 bool bRTL
= mpGlyphRTLFlags
? mpGlyphRTLFlags
[i
] : false;
391 int nCharPos
= mpGlyphs2Chars
? mpGlyphs2Chars
[i
]: i
+ rArgs
.mnMinCharPos
;
392 rArgs
.NeedFallback( nCharPos
, bRTL
);
394 rArgs
.NeedFallback( nCharPos
+1, bRTL
);
396 if( rArgs
.mnFlags
& SAL_LAYOUT_FOR_FALLBACK
)
398 // when we already are layouting for glyph fallback
399 // then a new unresolved glyph is not interesting
401 mpOutGlyphs
[i
] = DROPPED_OUTGLYPH
;
402 if( mbDisableGlyphs
&& bSurrogate
)
403 mpOutGlyphs
[i
+1] = DROPPED_OUTGLYPH
;
407 if( mnNotdefWidth
< 0 )
409 // get the width of the NotDef glyph
412 if (Ft2QueryStringWidthW( mhPS
, (LPWSTR
)&rArgs
.mpStr
[ nCharPos
], 1, &aExtent
))
413 mnNotdefWidth
= aExtent
;
415 // use a better NotDef glyph
416 if( !mbDisableGlyphs
)
420 // replace the current glyph with the NotDef glyph
421 mnWidth
+= mnNotdefWidth
- mpGlyphAdvances
[i
];
422 mpGlyphAdvances
[i
] = mnNotdefWidth
;
423 if( mpGlyphOrigAdvs
)
424 mpGlyphOrigAdvs
[i
] = mnNotdefWidth
;
428 // apply kerning if the layout engine has not yet done it
429 if( rArgs
.mnFlags
& (SAL_LAYOUT_KERNING_ASIAN
|SAL_LAYOUT_KERNING_PAIRS
) )
431 #else // GCP_KERN_HACK
432 // apply just asian kerning
433 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
435 if( !(rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) )
436 #endif // GCP_KERN_HACK
437 for( i
= 0; i
< mnGlyphCount
; ++i
)
438 mpGlyphOrigAdvs
[i
] = mpGlyphAdvances
[i
];
440 // #99658# also apply asian kerning on the substring border
441 int nLen
= mnGlyphCount
;
442 if( rArgs
.mnMinCharPos
+ nLen
< rArgs
.mnLength
)
444 for( i
= 1; i
< nLen
; ++i
)
447 if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
)
449 int nKernAmount
= mrOs2FontEntry
.GetKerning( pBidiStr
[i
-1], pBidiStr
[i
] );
450 mpGlyphAdvances
[ i
-1 ] += nKernAmount
;
451 mnWidth
+= nKernAmount
;
453 else if( rArgs
.mnFlags
& SAL_LAYOUT_KERNING_ASIAN
)
454 #endif // GCP_KERN_HACK
456 if( (0x3000 == (0xFF00 & pBidiStr
[i
-1]))
457 && (0x3000 == (0xFF00 & pBidiStr
[i
])) )
459 long nKernFirst
= +CalcAsianKerning( pBidiStr
[i
-1], true, bVertical
);
460 long nKernNext
= -CalcAsianKerning( pBidiStr
[i
], false, bVertical
);
462 long nDelta
= (nKernFirst
< nKernNext
) ? nKernFirst
: nKernNext
;
463 if( nDelta
<0 && nKernFirst
!=0 && nKernNext
!=0 )
465 nDelta
= (nDelta
* mpGlyphAdvances
[i
-1] + 2) / 4;
466 mpGlyphAdvances
[i
-1] += nDelta
;
473 // calculate virtual char widths
474 if( !mpGlyphs2Chars
)
475 mpCharWidths
= mpGlyphAdvances
;
478 mpCharWidths
= new int[ mnCharCount
];
479 for( i
= 0; i
< mnCharCount
; ++i
)
480 mpCharWidths
[ i
] = 0;
481 for( i
= 0; i
< mnGlyphCount
; ++i
)
483 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
485 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
489 // scale layout metrics if needed
490 if( mfFontScale
!= 1.0 )
492 mnWidth
*= mfFontScale
;
493 mnBaseAdv
*= mfFontScale
;
494 for( i
= 0; i
< mnCharCount
; ++i
)
495 mpCharWidths
[ i
] *= mfFontScale
;
496 if( mpGlyphAdvances
!= mpCharWidths
)
497 for( i
= 0; i
< mnGlyphCount
; ++i
)
498 mpGlyphAdvances
[ i
] *= mfFontScale
;
499 if( mpGlyphOrigAdvs
&& (mpGlyphOrigAdvs
!= mpGlyphAdvances
) )
500 for( i
= 0; i
< mnGlyphCount
; ++i
)
501 mpGlyphOrigAdvs
[ i
] *= mfFontScale
;
507 // -----------------------------------------------------------------------
509 int Os2SalLayout::GetNextGlyphs( int nLen
, sal_GlyphId
* pGlyphs
, Point
& rPos
, int& nStart
,
510 sal_Int32
* pGlyphAdvances
, int* pCharIndexes
) const
512 // return zero if no more glyph found
513 if( nStart
>= mnGlyphCount
)
516 // calculate glyph position relative to layout base
517 // TODO: avoid for nStart!=0 case by reusing rPos
518 long nXOffset
= mnBaseAdv
;
519 for( int i
= 0; i
< nStart
; ++i
)
520 nXOffset
+= mpGlyphAdvances
[ i
];
522 // calculate absolute position in pixel units
523 Point
aRelativePos( nXOffset
, 0 );
524 rPos
= GetDrawPosition( aRelativePos
);
527 while( nCount
< nLen
)
529 // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
530 long nGlyphIndex
= mpOutGlyphs
[ nStart
];
531 if( mbDisableGlyphs
)
533 if( mnLayoutFlags
& SAL_LAYOUT_VERTICAL
)
535 sal_Unicode cChar
= (sal_Unicode
)(nGlyphIndex
& GF_IDXMASK
);
537 if( mrOs2FontData
.HasGSUBstitutions( mhPS
)
538 && mrOs2FontData
.IsGSUBstituted( cChar
) )
539 nGlyphIndex
|= GF_ROTL
| GF_GSUB
;
541 #endif // GNG_VERT_HACK
543 nGlyphIndex
|= GetVerticalFlags( cChar
);
544 if( !(nGlyphIndex
& GF_ROTMASK
) )
545 nGlyphIndex
|= GF_VERT
;
548 nGlyphIndex
|= GF_ISCHAR
;
551 *(pGlyphs
++) = nGlyphIndex
;
553 *(pGlyphAdvances
++) = mpGlyphAdvances
[ nStart
];
557 if( !mpGlyphs2Chars
)
558 nCharPos
= nStart
+ mnMinCharPos
;
560 nCharPos
= mpGlyphs2Chars
[nStart
];
561 *(pCharIndexes
++) = nCharPos
;
564 // stop at last glyph
565 if( ++nStart
>= mnGlyphCount
)
568 // stop when next x-position is unexpected
569 if( !pGlyphAdvances
&& mpGlyphOrigAdvs
)
570 if( mpGlyphAdvances
[nStart
-1] != mpGlyphOrigAdvs
[nStart
-1] )
577 // -----------------------------------------------------------------------
579 void Os2SalLayout::DrawText( SalGraphics
& rGraphics
) const
581 if( mnGlyphCount
<= 0 )
584 Point aPos
= GetDrawPosition( Point( mnBaseAdv
, 0 ) );
589 aPt
.y
= static_cast<Os2SalGraphics
&>(rGraphics
).mnHeight
- aPos
.Y();
591 // ft2lib doesn't work with printer hps, so we fallback to codepage printing
592 // until cp1200 support will work.
593 if (static_cast<Os2SalGraphics
&>(rGraphics
).mbPrinter
) {
594 // convert to codepage
595 ByteString
str( mpOutGlyphs
, gsl_getSystemTextEncoding() );
596 // gliph size is not recalculated, so it could be wrong!
597 rc
= Ft2CharStringPosAtA( static_cast<Os2SalGraphics
&>(rGraphics
).mhPS
,
598 &aPt
, NULL
, CHS_VECTOR
, mnGlyphCount
, (PSZ
)str
.GetBuffer(),
599 (LONG
*)mpGlyphAdvances
, 0);
601 // try unicode rendering to screen
602 rc
= Ft2CharStringPosAtW( static_cast<Os2SalGraphics
&>(rGraphics
).mhPS
,
603 &aPt
, NULL
, CHS_VECTOR
, mnGlyphCount
, (LPWSTR
)mpOutGlyphs
,
604 (LONG
*)mpGlyphAdvances
, 0);
605 if (rc
== GPI_ERROR
) {
606 // if *W fails, convert to codepage and use *A (fallback to GPI into ft2)
607 ByteString
str( mpOutGlyphs
, gsl_getSystemTextEncoding() );
608 #if OSL_DEBUG_LEVEL>10
609 debug_printf("Os2SalLayout::DrawText HPS %08x PosAtW failed '%s'!\n",static_cast<Os2SalGraphics
&>(rGraphics
).mhPS
,str
.GetBuffer());
611 // gliph size is not recalculated, so it could be wrong!
612 rc
= Ft2CharStringPosAtA( static_cast<Os2SalGraphics
&>(rGraphics
).mhPS
,
613 &aPt
, NULL
, CHS_VECTOR
, mnGlyphCount
, (PSZ
)str
.GetBuffer(),
614 (LONG
*)mpGlyphAdvances
, 0);
619 // -----------------------------------------------------------------------
621 long Os2SalLayout::FillDXArray( long* pDXArray
) const
625 long mnWidth
= mnBaseAdv
;
626 for( int i
= 0; i
< mnGlyphCount
; ++i
)
627 mnWidth
+= mpGlyphAdvances
[ i
];
630 if( pDXArray
!= NULL
)
632 for( int i
= 0; i
< mnCharCount
; ++i
)
633 pDXArray
[ i
] = mpCharWidths
[ i
];
639 // -----------------------------------------------------------------------
641 int Os2SalLayout::GetTextBreak( long nMaxWidth
, long nCharExtra
, int nFactor
) const
642 // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
645 if( (mnWidth
* nFactor
+ mnCharCount
* nCharExtra
) <= nMaxWidth
)
648 long nExtraWidth
= mnBaseAdv
* nFactor
;
649 for( int n
= 0; n
< mnCharCount
; ++n
)
651 // skip unused characters
652 if( mpChars2Glyphs
&& (mpChars2Glyphs
[n
] < 0) )
654 // add char widths until max
655 nExtraWidth
+= mpCharWidths
[ n
] * nFactor
;
656 if( nExtraWidth
>= nMaxWidth
)
657 return (mnMinCharPos
+ n
);
658 nExtraWidth
+= nCharExtra
;
664 // -----------------------------------------------------------------------
666 void Os2SalLayout::GetCaretPositions( int nMaxIdx
, long* pCaretXArray
) const
668 long nXPos
= mnBaseAdv
;
670 if( !mpGlyphs2Chars
)
672 for( int i
= 0; i
< nMaxIdx
; i
+= 2 )
674 pCaretXArray
[ i
] = nXPos
;
675 nXPos
+= mpGlyphAdvances
[ i
>>1 ];
676 pCaretXArray
[ i
+1 ] = nXPos
;
682 for( i
= 0; i
< nMaxIdx
; ++i
)
683 pCaretXArray
[ i
] = -1;
685 // assign glyph positions to character positions
686 for( i
= 0; i
< mnGlyphCount
; ++i
)
688 int nCurrIdx
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
689 long nXRight
= nXPos
+ mpCharWidths
[ nCurrIdx
];
691 if( !(mpGlyphRTLFlags
&& mpGlyphRTLFlags
[i
]) )
693 // normal positions for LTR case
694 pCaretXArray
[ nCurrIdx
] = nXPos
;
695 pCaretXArray
[ nCurrIdx
+1 ] = nXRight
;
699 // reverse positions for RTL case
700 pCaretXArray
[ nCurrIdx
] = nXRight
;
701 pCaretXArray
[ nCurrIdx
+1 ] = nXPos
;
703 nXPos
+= mpGlyphAdvances
[ i
];
708 // -----------------------------------------------------------------------
710 void Os2SalLayout::Justify( long nNewWidth
)
712 long nOldWidth
= mnWidth
;
715 if( mnGlyphCount
<= 0 )
718 if( nNewWidth
== nOldWidth
)
721 // the rightmost glyph cannot be stretched
722 const int nRight
= mnGlyphCount
- 1;
723 nOldWidth
-= mpGlyphAdvances
[ nRight
];
724 nNewWidth
-= mpGlyphAdvances
[ nRight
];
726 // count stretchable glyphs
727 int nStretchable
= 0, i
;
728 for( i
= 0; i
< nRight
; ++i
)
729 if( mpGlyphAdvances
[i
] >= 0 )
732 // stretch these glyphs
733 int nDiffWidth
= nNewWidth
- nOldWidth
;
734 for( i
= 0; (i
< nRight
) && (nStretchable
> 0); ++i
)
736 if( mpGlyphAdvances
[i
] <= 0 )
738 int nDeltaWidth
= nDiffWidth
/ nStretchable
;
739 mpGlyphAdvances
[i
] += nDeltaWidth
;
741 nDiffWidth
-= nDeltaWidth
;
745 // -----------------------------------------------------------------------
747 void Os2SalLayout::AdjustLayout( ImplLayoutArgs
& rArgs
)
749 SalLayout::AdjustLayout( rArgs
);
751 // adjust positions if requested
752 if( rArgs
.mpDXArray
)
753 ApplyDXArray( rArgs
);
754 else if( rArgs
.mnLayoutWidth
)
755 Justify( rArgs
.mnLayoutWidth
);
759 // recalculate virtual char widths if they were changed
760 if( mpCharWidths
!= mpGlyphAdvances
)
763 if( !mpGlyphs2Chars
)
766 for( i
= 0; i
< mnGlyphCount
; ++i
)
767 mpCharWidths
[ i
] = mpGlyphAdvances
[ i
];
771 // BiDi or complex case
772 for( i
= 0; i
< mnCharCount
; ++i
)
773 mpCharWidths
[ i
] = 0;
774 for( i
= 0; i
< mnGlyphCount
; ++i
)
776 int j
= mpGlyphs2Chars
[ i
] - rArgs
.mnMinCharPos
;
778 mpCharWidths
[ j
] += mpGlyphAdvances
[ i
];
784 // -----------------------------------------------------------------------
786 void Os2SalLayout::ApplyDXArray( const ImplLayoutArgs
& rArgs
)
788 // try to avoid disturbance of text flow for LSB rounding case;
789 const long* pDXArray
= rArgs
.mpDXArray
;
792 long nOldWidth
= mnBaseAdv
;
793 for(; i
< mnCharCount
; ++i
)
795 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
798 nOldWidth
+= mpGlyphAdvances
[ j
];
799 int nDiff
= nOldWidth
- pDXArray
[ i
];
801 // disabled because of #104768#
802 // works great for static text, but problems when typing
803 // if( nDiff>+1 || nDiff<-1 )
804 // only bother with changing anything when something moved
809 if( i
>= mnCharCount
)
812 if( !mpGlyphOrigAdvs
)
814 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
815 for( i
= 0; i
< mnGlyphCount
; ++i
)
816 mpGlyphOrigAdvs
[ i
] = mpGlyphAdvances
[ i
];
820 for( i
= 0; i
< mnCharCount
; ++i
)
822 int j
= !mpChars2Glyphs
? i
: mpChars2Glyphs
[i
];
824 mpGlyphAdvances
[j
] = pDXArray
[i
] - mnWidth
;
825 mnWidth
= pDXArray
[i
];
829 // -----------------------------------------------------------------------
831 void Os2SalLayout::MoveGlyph( int nStart
, long nNewXPos
)
833 if( nStart
> mnGlyphCount
)
836 // calculate the current x-position of the requested glyph
837 // TODO: cache absolute positions
838 int nXPos
= mnBaseAdv
;
839 for( int i
= 0; i
< nStart
; ++i
)
840 nXPos
+= mpGlyphAdvances
[i
];
842 // calculate the difference to the current glyph position
843 int nDelta
= nNewXPos
- nXPos
;
845 // adjust the width of the layout if it was already cached
849 // depending on whether the requested glyph is leftmost in the layout
850 // adjust either the layout's or the requested glyph's relative position
852 mpGlyphAdvances
[ nStart
-1 ] += nDelta
;
857 // -----------------------------------------------------------------------
859 void Os2SalLayout::DropGlyph( int nStart
)
861 mpOutGlyphs
[ nStart
] = DROPPED_OUTGLYPH
;
864 // -----------------------------------------------------------------------
866 void Os2SalLayout::Simplify( bool bIsBase
)
868 // return early if no glyph has been dropped
869 int i
= mnGlyphCount
;
870 while( (--i
>= 0) && (mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
) );
874 // convert the layout to a sparse layout if it is not already
875 if( !mpGlyphs2Chars
)
877 mpGlyphs2Chars
= new int[ mnGlyphCount
];
878 mpCharWidths
= new int[ mnCharCount
];
879 // assertion: mnGlyphCount == mnCharCount
880 for( int k
= 0; k
< mnGlyphCount
; ++k
)
882 mpGlyphs2Chars
[ k
] = mnMinCharPos
+ k
;
883 mpCharWidths
[ k
] = mpGlyphAdvances
[ k
];
887 // remove dropped glyphs that are rightmost in the layout
888 for( i
= mnGlyphCount
; --i
>= 0; )
890 if( mpOutGlyphs
[ i
] != DROPPED_OUTGLYPH
)
893 mnWidth
-= mpGlyphAdvances
[ i
];
894 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
895 if( nRelCharPos
>= 0 )
896 mpCharWidths
[ nRelCharPos
] = 0;
898 mnGlyphCount
= i
+ 1;
900 // keep original glyph widths around
901 if( !mpGlyphOrigAdvs
)
903 mpGlyphOrigAdvs
= new int[ mnGlyphCount
];
904 for( int k
= 0; k
< mnGlyphCount
; ++k
)
905 mpGlyphOrigAdvs
[ k
] = mpGlyphAdvances
[ k
];
908 // remove dropped glyphs inside the layout
910 for( i
= 0; i
< mnGlyphCount
; ++i
)
912 if( mpOutGlyphs
[ i
] == DROPPED_OUTGLYPH
)
914 // adjust relative position to last valid glyph
915 int nDroppedWidth
= mpGlyphAdvances
[ i
];
916 mpGlyphAdvances
[ i
] = 0;
918 mpGlyphAdvances
[ nNewGC
-1 ] += nDroppedWidth
;
920 mnBaseAdv
+= nDroppedWidth
;
922 // zero the virtual char width for the char that has a fallback
923 int nRelCharPos
= mpGlyphs2Chars
[ i
] - mnMinCharPos
;
924 if( nRelCharPos
>= 0 )
925 mpCharWidths
[ nRelCharPos
] = 0;
931 // rearrange the glyph array to get rid of the dropped glyph
932 mpOutGlyphs
[ nNewGC
] = mpOutGlyphs
[ i
];
933 mpGlyphAdvances
[ nNewGC
] = mpGlyphAdvances
[ i
];
934 mpGlyphOrigAdvs
[ nNewGC
] = mpGlyphOrigAdvs
[ i
];
935 mpGlyphs2Chars
[ nNewGC
] = mpGlyphs2Chars
[ i
];
941 mnGlyphCount
= nNewGC
;
942 if( mnGlyphCount
<= 0 )
943 mnWidth
= mnBaseAdv
= 0;
946 // =======================================================================
948 SalLayout
* Os2SalGraphics::GetTextLayout( ImplLayoutArgs
& rArgs
, int nFallbackLevel
)
950 Os2SalLayout
* pLayout
= NULL
;
951 DBG_ASSERT( mpOs2FontEntry
[nFallbackLevel
], "WinSalGraphics mpWinFontEntry==NULL");
953 const ImplOs2FontData
& rFontFace
= *mpOs2FontData
[ nFallbackLevel
];
954 ImplOs2FontEntry
& rFontInstance
= *mpOs2FontEntry
[ nFallbackLevel
];
958 if( (rArgs
.mnFlags
& SAL_LAYOUT_KERNING_PAIRS
) && !rFontInstance
.HasKernData() )
960 // TODO: directly cache kerning info in the rFontInstance
961 // TODO: get rid of kerning methods+data in WinSalGraphics object
962 GetKernPairs( 0, NULL
);
963 rFontInstance
.SetKernData( mnFontKernPairCount
, mpFontKernPairs
);
965 #endif // GCP_KERN_HACK
967 //BYTE eCharSet = ANSI_CHARSET;
969 // eCharSet = mpLogFont->lfCharSet;
970 pLayout
= new Os2SalLayout( mhPS
, 0, rFontFace
, rFontInstance
);
973 if( mfFontScale
!= 1.0 )
974 pLayout
->SetFontScale( mfFontScale
);
979 // =======================================================================
981 ImplOs2FontEntry::ImplOs2FontEntry( ImplFontSelectData
& rFSD
)
982 : ImplFontEntry( rFSD
),
985 ,mpKerningPairs( NULL
)
986 ,mnKerningPairs( -1 )
987 #endif // GCP_KERN_HACK
991 // -----------------------------------------------------------------------
993 ImplOs2FontEntry::~ImplOs2FontEntry()
996 delete[] mpKerningPairs
;
997 #endif // GCP_KERN_HACK
1000 // -----------------------------------------------------------------------
1002 #ifdef GCP_KERN_HACK
1003 bool ImplOs2FontEntry::HasKernData() const
1005 return (mnKerningPairs
>= 0);
1008 // -----------------------------------------------------------------------
1010 void ImplOs2FontEntry::SetKernData( int nPairCount
, const KERNINGPAIRS
* pPairData
)
1012 mnKerningPairs
= nPairCount
;
1013 mpKerningPairs
= new KERNINGPAIRS
[ mnKerningPairs
];
1014 ::memcpy( mpKerningPairs
, (const void*)pPairData
, nPairCount
*sizeof(KERNINGPAIRS
) );
1017 // -----------------------------------------------------------------------
1019 int ImplOs2FontEntry::GetKerning( sal_Unicode cLeft
, sal_Unicode cRight
) const
1021 int nKernAmount
= 0;
1022 if( mpKerningPairs
)
1024 const KERNINGPAIRS aRefPair
= { cLeft
, cRight
, 0 };
1025 const KERNINGPAIRS
* pFirstPair
= mpKerningPairs
;
1026 const KERNINGPAIRS
* pEndPair
= mpKerningPairs
+ mnKerningPairs
;
1027 const KERNINGPAIRS
* pPair
= std::lower_bound( pFirstPair
,
1028 pEndPair
, aRefPair
, ImplCmpKernData
);
1029 if( (pPair
!= pEndPair
)
1030 && (pPair
->sFirstChar
== aRefPair
.sFirstChar
)
1031 && (pPair
->sSecondChar
== aRefPair
.sSecondChar
) )
1032 nKernAmount
= pPair
->lKerningAmount
;
1037 #endif // GCP_KERN_HACK
1039 // =======================================================================
1041 ImplFontData
* ImplOs2FontData::Clone() const
1044 mpUnicodeMap
->AddReference();
1045 ImplFontData
* pClone
= new ImplOs2FontData( *this );
1049 // -----------------------------------------------------------------------
1051 ImplFontEntry
* ImplOs2FontData::CreateFontInstance( ImplFontSelectData
& rFSD
) const
1053 //debug_printf("ImplOs2FontData::CreateFontInstance\n");
1054 ImplFontEntry
* pEntry
= new ImplOs2FontEntry( rFSD
);
1058 // =======================================================================