1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir #include <tools/svwin.h> 29*cdf0e10cSrcweir 30*cdf0e10cSrcweir #include <rtl/ustring.hxx> 31*cdf0e10cSrcweir #include <osl/module.h> 32*cdf0e10cSrcweir #include <salgdi.h> 33*cdf0e10cSrcweir #include <saldata.hxx> 34*cdf0e10cSrcweir #include <vcl/sallayout.hxx> 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir #ifndef __H_FT2LIB 37*cdf0e10cSrcweir #include <wingdi.h> 38*cdf0e10cSrcweir #include <ft2lib.h> 39*cdf0e10cSrcweir #endif 40*cdf0e10cSrcweir 41*cdf0e10cSrcweir #include <cstdio> 42*cdf0e10cSrcweir #include <malloc.h> 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 45*cdf0e10cSrcweir #include <algorithm> 46*cdf0e10cSrcweir #endif // GCP_KERN_HACK 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir // for GetMirroredChar 49*cdf0e10cSrcweir #include <vcl/svapp.hxx> 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir #include <hash_map> 52*cdf0e10cSrcweir typedef std::hash_map<int,int> IntMap; 53*cdf0e10cSrcweir 54*cdf0e10cSrcweir #define DROPPED_OUTGLYPH 0xFFFF 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir using namespace rtl; 57*cdf0e10cSrcweir 58*cdf0e10cSrcweir // ======================================================================= 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir // OS/2 specific physical font instance 61*cdf0e10cSrcweir class ImplOs2FontEntry : public ImplFontEntry 62*cdf0e10cSrcweir { 63*cdf0e10cSrcweir public: 64*cdf0e10cSrcweir ImplOs2FontEntry( ImplFontSelectData& ); 65*cdf0e10cSrcweir ~ImplOs2FontEntry(); 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir private: 68*cdf0e10cSrcweir // TODO: also add HFONT??? Watch out for issues with too many active fonts... 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 71*cdf0e10cSrcweir public: 72*cdf0e10cSrcweir bool HasKernData() const; 73*cdf0e10cSrcweir void SetKernData( int, const KERNINGPAIRS* ); 74*cdf0e10cSrcweir int GetKerning( sal_Unicode, sal_Unicode ) const; 75*cdf0e10cSrcweir private: 76*cdf0e10cSrcweir KERNINGPAIRS* mpKerningPairs; 77*cdf0e10cSrcweir int mnKerningPairs; 78*cdf0e10cSrcweir #endif // GCP_KERN_HACK 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir public: 81*cdf0e10cSrcweir int GetCachedGlyphWidth( int nCharCode ) const; 82*cdf0e10cSrcweir void CacheGlyphWidth( int nCharCode, int nCharWidth ); 83*cdf0e10cSrcweir private: 84*cdf0e10cSrcweir IntMap maWidthMap; 85*cdf0e10cSrcweir }; 86*cdf0e10cSrcweir 87*cdf0e10cSrcweir // ----------------------------------------------------------------------- 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) 90*cdf0e10cSrcweir { 91*cdf0e10cSrcweir maWidthMap[ nCharCode ] = nCharWidth; 92*cdf0e10cSrcweir } 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir inline int ImplOs2FontEntry::GetCachedGlyphWidth( int nCharCode ) const 95*cdf0e10cSrcweir { 96*cdf0e10cSrcweir IntMap::const_iterator it = maWidthMap.find( nCharCode ); 97*cdf0e10cSrcweir if( it == maWidthMap.end() ) 98*cdf0e10cSrcweir return -1; 99*cdf0e10cSrcweir return it->second; 100*cdf0e10cSrcweir } 101*cdf0e10cSrcweir 102*cdf0e10cSrcweir // ======================================================================= 103*cdf0e10cSrcweir 104*cdf0e10cSrcweir class Os2Layout : public SalLayout 105*cdf0e10cSrcweir { 106*cdf0e10cSrcweir public: 107*cdf0e10cSrcweir Os2Layout( HDC, const ImplOs2FontData&, ImplOs2FontEntry& ); 108*cdf0e10cSrcweir virtual void InitFont() const; 109*cdf0e10cSrcweir void SetFontScale( float f ) { mfFontScale = f; } 110*cdf0e10cSrcweir float GetFontScale() const { return mfFontScale; } 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir protected: 113*cdf0e10cSrcweir HPS mhPS; // OS2 device handle 114*cdf0e10cSrcweir FATTRS mhFont; 115*cdf0e10cSrcweir int mnBaseAdv; // x-offset relative to Layout origin 116*cdf0e10cSrcweir float mfFontScale; // allows metrics emulation of huge font sizes 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir const ImplOs2FontData& mrOs2FontData; 119*cdf0e10cSrcweir ImplOs2FontEntry& mrOs2FontEntry; 120*cdf0e10cSrcweir }; 121*cdf0e10cSrcweir 122*cdf0e10cSrcweir // ======================================================================= 123*cdf0e10cSrcweir 124*cdf0e10cSrcweir class Os2SalLayout : public Os2Layout 125*cdf0e10cSrcweir { 126*cdf0e10cSrcweir public: 127*cdf0e10cSrcweir Os2SalLayout( HPS, BYTE nCharSet, const ImplOs2FontData&, ImplOs2FontEntry& ); 128*cdf0e10cSrcweir virtual ~Os2SalLayout(); 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& ); 131*cdf0e10cSrcweir virtual void AdjustLayout( ImplLayoutArgs& ); 132*cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const; 133*cdf0e10cSrcweir 134*cdf0e10cSrcweir virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, 135*cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharIndexes ) const; 136*cdf0e10cSrcweir 137*cdf0e10cSrcweir virtual long FillDXArray( long* pDXArray ) const; 138*cdf0e10cSrcweir virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; 139*cdf0e10cSrcweir virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir // for glyph+font+script fallback 142*cdf0e10cSrcweir virtual void MoveGlyph( int nStart, long nNewXPos ); 143*cdf0e10cSrcweir virtual void DropGlyph( int nStart ); 144*cdf0e10cSrcweir virtual void Simplify( bool bIsBase ); 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir protected: 147*cdf0e10cSrcweir void Justify( long nNewWidth ); 148*cdf0e10cSrcweir void ApplyDXArray( const ImplLayoutArgs& ); 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir protected: 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir private: 153*cdf0e10cSrcweir int mnGlyphCount; 154*cdf0e10cSrcweir int mnCharCount; 155*cdf0e10cSrcweir sal_Unicode* mpOutGlyphs; 156*cdf0e10cSrcweir int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[] 157*cdf0e10cSrcweir int* mpGlyphOrigAdvs; 158*cdf0e10cSrcweir int* mpCharWidths; // map rel char pos to char width 159*cdf0e10cSrcweir int* mpChars2Glyphs; // map rel char pos to abs glyph pos 160*cdf0e10cSrcweir int* mpGlyphs2Chars; // map abs glyph pos to abs char pos 161*cdf0e10cSrcweir bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL 162*cdf0e10cSrcweir mutable long mnWidth; 163*cdf0e10cSrcweir bool mbDisableGlyphs; 164*cdf0e10cSrcweir 165*cdf0e10cSrcweir int mnNotdefWidth; 166*cdf0e10cSrcweir BYTE mnCharSet; 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir }; 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir // ======================================================================= 171*cdf0e10cSrcweir 172*cdf0e10cSrcweir Os2Layout::Os2Layout( HPS hPS, const ImplOs2FontData& rWFD, ImplOs2FontEntry& rWFE ) 173*cdf0e10cSrcweir : mhPS( hPS ), 174*cdf0e10cSrcweir mnBaseAdv( 0 ), 175*cdf0e10cSrcweir mfFontScale( 1.0 ), 176*cdf0e10cSrcweir mrOs2FontData( rWFD ), 177*cdf0e10cSrcweir mrOs2FontEntry( rWFE ) 178*cdf0e10cSrcweir { 179*cdf0e10cSrcweir BOOL fSuccess; 180*cdf0e10cSrcweir fSuccess = Ft2QueryLogicalFont( mhPS, LCID_BASE, NULL, &mhFont, sizeof(FATTRS)); 181*cdf0e10cSrcweir } 182*cdf0e10cSrcweir 183*cdf0e10cSrcweir // ----------------------------------------------------------------------- 184*cdf0e10cSrcweir 185*cdf0e10cSrcweir void Os2Layout::InitFont() const 186*cdf0e10cSrcweir { 187*cdf0e10cSrcweir // select fallback level 0 font 188*cdf0e10cSrcweir APIRET rc = Ft2CreateLogFont( mhPS, NULL, LCID_BASE, (PFATTRS)&mhFont); 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir // ======================================================================= 192*cdf0e10cSrcweir 193*cdf0e10cSrcweir Os2SalLayout::Os2SalLayout( HPS hPS, BYTE nCharSet, 194*cdf0e10cSrcweir const ImplOs2FontData& rOs2FontData, ImplOs2FontEntry& rOs2FontEntry ) 195*cdf0e10cSrcweir : Os2Layout( hPS, rOs2FontData, rOs2FontEntry ), 196*cdf0e10cSrcweir mnGlyphCount( 0 ), 197*cdf0e10cSrcweir mnCharCount( 0 ), 198*cdf0e10cSrcweir mpOutGlyphs( NULL ), 199*cdf0e10cSrcweir mpGlyphAdvances( NULL ), 200*cdf0e10cSrcweir mpGlyphOrigAdvs( NULL ), 201*cdf0e10cSrcweir mpCharWidths( NULL ), 202*cdf0e10cSrcweir mpChars2Glyphs( NULL ), 203*cdf0e10cSrcweir mpGlyphs2Chars( NULL ), 204*cdf0e10cSrcweir mpGlyphRTLFlags( NULL ), 205*cdf0e10cSrcweir mnWidth( 0 ), 206*cdf0e10cSrcweir mnNotdefWidth( -1 ), 207*cdf0e10cSrcweir mnCharSet( nCharSet ), 208*cdf0e10cSrcweir mbDisableGlyphs( false ) 209*cdf0e10cSrcweir { 210*cdf0e10cSrcweir mbDisableGlyphs = true; 211*cdf0e10cSrcweir } 212*cdf0e10cSrcweir 213*cdf0e10cSrcweir // ----------------------------------------------------------------------- 214*cdf0e10cSrcweir 215*cdf0e10cSrcweir Os2SalLayout::~Os2SalLayout() 216*cdf0e10cSrcweir { 217*cdf0e10cSrcweir delete[] mpGlyphRTLFlags; 218*cdf0e10cSrcweir delete[] mpGlyphs2Chars; 219*cdf0e10cSrcweir delete[] mpChars2Glyphs; 220*cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances ) 221*cdf0e10cSrcweir delete[] mpCharWidths; 222*cdf0e10cSrcweir delete[] mpGlyphOrigAdvs; 223*cdf0e10cSrcweir delete[] mpGlyphAdvances; 224*cdf0e10cSrcweir delete[] mpOutGlyphs; 225*cdf0e10cSrcweir } 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir // ----------------------------------------------------------------------- 228*cdf0e10cSrcweir 229*cdf0e10cSrcweir bool Os2SalLayout::LayoutText( ImplLayoutArgs& rArgs ) 230*cdf0e10cSrcweir { 231*cdf0e10cSrcweir // prepare layout 232*cdf0e10cSrcweir // TODO: fix case when recyclying old Os2SalLayout object 233*cdf0e10cSrcweir mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0); 234*cdf0e10cSrcweir mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos; 235*cdf0e10cSrcweir 236*cdf0e10cSrcweir if( !mbDisableGlyphs ) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir // Win32 glyph APIs have serious problems with vertical layout 239*cdf0e10cSrcweir // => workaround is to use the unicode methods then 240*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL ) 241*cdf0e10cSrcweir mbDisableGlyphs = true; 242*cdf0e10cSrcweir else 243*cdf0e10cSrcweir // use cached value from font face 244*cdf0e10cSrcweir mbDisableGlyphs = mrOs2FontData.IsGlyphApiDisabled(); 245*cdf0e10cSrcweir } 246*cdf0e10cSrcweir 247*cdf0e10cSrcweir // TODO: use a cached value for bDisableAsianKern from upper layers 248*cdf0e10cSrcweir #if 0 249*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 250*cdf0e10cSrcweir { 251*cdf0e10cSrcweir TEXTMETRICA aTextMetricA; 252*cdf0e10cSrcweir if( ::GetTextMetricsA( mhDC, &aTextMetricA ) 253*cdf0e10cSrcweir && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) ) 254*cdf0e10cSrcweir rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN; 255*cdf0e10cSrcweir } 256*cdf0e10cSrcweir #endif 257*cdf0e10cSrcweir 258*cdf0e10cSrcweir // layout text 259*cdf0e10cSrcweir int i, j; 260*cdf0e10cSrcweir 261*cdf0e10cSrcweir mnGlyphCount = 0; 262*cdf0e10cSrcweir bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0; 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir // count the number of chars to process if no RTL run 265*cdf0e10cSrcweir rArgs.ResetPos(); 266*cdf0e10cSrcweir bool bHasRTL = false; 267*cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL ) 268*cdf0e10cSrcweir mnGlyphCount += j - i; 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir // if there are RTL runs we need room to remember individual BiDi flags 271*cdf0e10cSrcweir if( bHasRTL ) 272*cdf0e10cSrcweir { 273*cdf0e10cSrcweir mpGlyphRTLFlags = new bool[ mnCharCount ]; 274*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 275*cdf0e10cSrcweir mpGlyphRTLFlags[i] = false; 276*cdf0e10cSrcweir } 277*cdf0e10cSrcweir 278*cdf0e10cSrcweir // rewrite the logical string if needed to prepare for the API calls 279*cdf0e10cSrcweir const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos; 280*cdf0e10cSrcweir if( (mnGlyphCount != mnCharCount) || bVertical ) 281*cdf0e10cSrcweir { 282*cdf0e10cSrcweir // we need to rewrite the pBidiStr when any of 283*cdf0e10cSrcweir // - BiDirectional layout 284*cdf0e10cSrcweir // - vertical layout 285*cdf0e10cSrcweir // - partial runs (e.g. with control chars or for glyph fallback) 286*cdf0e10cSrcweir // are involved 287*cdf0e10cSrcweir sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) ); 288*cdf0e10cSrcweir pBidiStr = pRewrittenStr; 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir // note: glyph to char mapping is relative to first character 291*cdf0e10cSrcweir mpChars2Glyphs = new int[ mnCharCount ]; 292*cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnCharCount ]; 293*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 294*cdf0e10cSrcweir mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1; 295*cdf0e10cSrcweir 296*cdf0e10cSrcweir mnGlyphCount = 0; 297*cdf0e10cSrcweir rArgs.ResetPos(); 298*cdf0e10cSrcweir bool bIsRTL = false; 299*cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bIsRTL ) ) 300*cdf0e10cSrcweir { 301*cdf0e10cSrcweir do 302*cdf0e10cSrcweir { 303*cdf0e10cSrcweir // get the next leftmost character in this run 304*cdf0e10cSrcweir int nCharPos = bIsRTL ? --j : i++; 305*cdf0e10cSrcweir sal_Unicode cChar = rArgs.mpStr[ nCharPos ]; 306*cdf0e10cSrcweir 307*cdf0e10cSrcweir // in the RTL case mirror the character and remember its RTL status 308*cdf0e10cSrcweir if( bIsRTL ) 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir cChar = ::GetMirroredChar( cChar ); 311*cdf0e10cSrcweir mpGlyphRTLFlags[ mnGlyphCount ] = true; 312*cdf0e10cSrcweir } 313*cdf0e10cSrcweir 314*cdf0e10cSrcweir // for vertical writing use vertical alternatives 315*cdf0e10cSrcweir if( bVertical ) 316*cdf0e10cSrcweir { 317*cdf0e10cSrcweir sal_Unicode cVert = ::GetVerticalChar( cChar ); 318*cdf0e10cSrcweir if( cVert ) 319*cdf0e10cSrcweir cChar = cVert; 320*cdf0e10cSrcweir } 321*cdf0e10cSrcweir 322*cdf0e10cSrcweir // rewrite the original string 323*cdf0e10cSrcweir // update the mappings between original and rewritten string 324*cdf0e10cSrcweir pRewrittenStr[ mnGlyphCount ] = cChar; 325*cdf0e10cSrcweir mpGlyphs2Chars[ mnGlyphCount ] = nCharPos; 326*cdf0e10cSrcweir mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount; 327*cdf0e10cSrcweir ++mnGlyphCount; 328*cdf0e10cSrcweir } while( i < j ); 329*cdf0e10cSrcweir } 330*cdf0e10cSrcweir } 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir mpOutGlyphs = new sal_Unicode[ mnGlyphCount ]; 333*cdf0e10cSrcweir mpGlyphAdvances = new int[ mnGlyphCount ]; 334*cdf0e10cSrcweir 335*cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) ) 336*cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 337*cdf0e10cSrcweir 338*cdf0e10cSrcweir #ifndef GCP_KERN_HACK 339*cdf0e10cSrcweir DWORD nGcpOption = 0; 340*cdf0e10cSrcweir // enable kerning if requested 341*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS ) 342*cdf0e10cSrcweir nGcpOption |= GCP_USEKERNING; 343*cdf0e10cSrcweir #endif // GCP_KERN_HACK 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir LONG lLcid = Ft2QueryCharSet( mhPS); 346*cdf0e10cSrcweir 347*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 348*cdf0e10cSrcweir mpOutGlyphs[i] = pBidiStr[ i ]; 349*cdf0e10cSrcweir mnWidth = 0; 350*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 351*cdf0e10cSrcweir { 352*cdf0e10cSrcweir const sal_Unicode* pCodes = &pBidiStr[i]; 353*cdf0e10cSrcweir // check for surrogate pairs 354*cdf0e10cSrcweir if( (pCodes[0] & 0xFC00) == 0xDC00 ) 355*cdf0e10cSrcweir continue; 356*cdf0e10cSrcweir bool bSurrogate = ((pCodes[0] & 0xFC00) == 0xD800); 357*cdf0e10cSrcweir 358*cdf0e10cSrcweir // get the width of the corresponding code point 359*cdf0e10cSrcweir int nCharCode = pCodes[0]; 360*cdf0e10cSrcweir if( bSurrogate ) 361*cdf0e10cSrcweir nCharCode = 0x10000 + ((pCodes[0] & 0x03FF) << 10) + (pCodes[1] & 0x03FF); 362*cdf0e10cSrcweir int nGlyphWidth = mrOs2FontEntry.GetCachedGlyphWidth( nCharCode ); 363*cdf0e10cSrcweir if( nGlyphWidth == -1 ) 364*cdf0e10cSrcweir { 365*cdf0e10cSrcweir if (!Ft2QueryStringWidthW( mhPS, (LPWSTR)&pCodes[0], 1, (LONG*)&nGlyphWidth)) 366*cdf0e10cSrcweir nGlyphWidth = 0; 367*cdf0e10cSrcweir mrOs2FontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth ); 368*cdf0e10cSrcweir } 369*cdf0e10cSrcweir mpGlyphAdvances[ i ] = nGlyphWidth; 370*cdf0e10cSrcweir mnWidth += nGlyphWidth; 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir // remaining codes of surrogate pair get a zero width 373*cdf0e10cSrcweir if( bSurrogate ) 374*cdf0e10cSrcweir mpGlyphAdvances[ i+1 ] = 0; 375*cdf0e10cSrcweir 376*cdf0e10cSrcweir // check with the font face if glyph fallback is needed 377*cdf0e10cSrcweir if( mrOs2FontData.HasChar( nCharCode ) ) 378*cdf0e10cSrcweir continue; 379*cdf0e10cSrcweir // Type1 charmaps are not complete (or buggy), use FT2 to check again 380*cdf0e10cSrcweir if (Ft2FontSupportsUnicodeChar( mhPS, lLcid, TRUE, nCharCode)) 381*cdf0e10cSrcweir continue; 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0 384*cdf0e10cSrcweir debug_printf("Os2SalLayout::LayoutText font does not support unicode char\n"); 385*cdf0e10cSrcweir #endif 386*cdf0e10cSrcweir // request glyph fallback at this position in the string 387*cdf0e10cSrcweir bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false; 388*cdf0e10cSrcweir int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos; 389*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRTL ); 390*cdf0e10cSrcweir if( bSurrogate ) 391*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRTL ); 392*cdf0e10cSrcweir 393*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK ) 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir // when we already are layouting for glyph fallback 396*cdf0e10cSrcweir // then a new unresolved glyph is not interesting 397*cdf0e10cSrcweir mnNotdefWidth = 0; 398*cdf0e10cSrcweir mpOutGlyphs[i] = DROPPED_OUTGLYPH; 399*cdf0e10cSrcweir if( mbDisableGlyphs && bSurrogate ) 400*cdf0e10cSrcweir mpOutGlyphs[i+1] = DROPPED_OUTGLYPH; 401*cdf0e10cSrcweir } 402*cdf0e10cSrcweir else 403*cdf0e10cSrcweir { 404*cdf0e10cSrcweir if( mnNotdefWidth < 0 ) 405*cdf0e10cSrcweir { 406*cdf0e10cSrcweir // get the width of the NotDef glyph 407*cdf0e10cSrcweir LONG aExtent; 408*cdf0e10cSrcweir mnNotdefWidth = 0; 409*cdf0e10cSrcweir if (Ft2QueryStringWidthW( mhPS, (LPWSTR)&rArgs.mpStr[ nCharPos ], 1, &aExtent)) 410*cdf0e10cSrcweir mnNotdefWidth = aExtent; 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir // use a better NotDef glyph 413*cdf0e10cSrcweir if( !mbDisableGlyphs ) 414*cdf0e10cSrcweir mpOutGlyphs[i] = 0; 415*cdf0e10cSrcweir } 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir // replace the current glyph with the NotDef glyph 418*cdf0e10cSrcweir mnWidth += mnNotdefWidth - mpGlyphAdvances[i]; 419*cdf0e10cSrcweir mpGlyphAdvances[i] = mnNotdefWidth; 420*cdf0e10cSrcweir if( mpGlyphOrigAdvs ) 421*cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mnNotdefWidth; 422*cdf0e10cSrcweir } 423*cdf0e10cSrcweir 424*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 425*cdf0e10cSrcweir // apply kerning if the layout engine has not yet done it 426*cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) ) 427*cdf0e10cSrcweir { 428*cdf0e10cSrcweir #else // GCP_KERN_HACK 429*cdf0e10cSrcweir // apply just asian kerning 430*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 431*cdf0e10cSrcweir { 432*cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) ) 433*cdf0e10cSrcweir #endif // GCP_KERN_HACK 434*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 435*cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mpGlyphAdvances[i]; 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir // #99658# also apply asian kerning on the substring border 438*cdf0e10cSrcweir int nLen = mnGlyphCount; 439*cdf0e10cSrcweir if( rArgs.mnMinCharPos + nLen < rArgs.mnLength ) 440*cdf0e10cSrcweir ++nLen; 441*cdf0e10cSrcweir for( i = 1; i < nLen; ++i ) 442*cdf0e10cSrcweir { 443*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 444*cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS ) 445*cdf0e10cSrcweir { 446*cdf0e10cSrcweir int nKernAmount = mrOs2FontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] ); 447*cdf0e10cSrcweir mpGlyphAdvances[ i-1 ] += nKernAmount; 448*cdf0e10cSrcweir mnWidth += nKernAmount; 449*cdf0e10cSrcweir } 450*cdf0e10cSrcweir else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 451*cdf0e10cSrcweir #endif // GCP_KERN_HACK 452*cdf0e10cSrcweir 453*cdf0e10cSrcweir if( (0x3000 == (0xFF00 & pBidiStr[i-1])) 454*cdf0e10cSrcweir && (0x3000 == (0xFF00 & pBidiStr[i])) ) 455*cdf0e10cSrcweir { 456*cdf0e10cSrcweir long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical ); 457*cdf0e10cSrcweir long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical ); 458*cdf0e10cSrcweir 459*cdf0e10cSrcweir long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext; 460*cdf0e10cSrcweir if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 ) 461*cdf0e10cSrcweir { 462*cdf0e10cSrcweir nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4; 463*cdf0e10cSrcweir mpGlyphAdvances[i-1] += nDelta; 464*cdf0e10cSrcweir mnWidth += nDelta; 465*cdf0e10cSrcweir } 466*cdf0e10cSrcweir } 467*cdf0e10cSrcweir } 468*cdf0e10cSrcweir } 469*cdf0e10cSrcweir 470*cdf0e10cSrcweir // calculate virtual char widths 471*cdf0e10cSrcweir if( !mpGlyphs2Chars ) 472*cdf0e10cSrcweir mpCharWidths = mpGlyphAdvances; 473*cdf0e10cSrcweir else 474*cdf0e10cSrcweir { 475*cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ]; 476*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 477*cdf0e10cSrcweir mpCharWidths[ i ] = 0; 478*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 479*cdf0e10cSrcweir { 480*cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos; 481*cdf0e10cSrcweir if( j >= 0 ) 482*cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ]; 483*cdf0e10cSrcweir } 484*cdf0e10cSrcweir } 485*cdf0e10cSrcweir 486*cdf0e10cSrcweir // scale layout metrics if needed 487*cdf0e10cSrcweir if( mfFontScale != 1.0 ) 488*cdf0e10cSrcweir { 489*cdf0e10cSrcweir mnWidth *= mfFontScale; 490*cdf0e10cSrcweir mnBaseAdv *= mfFontScale; 491*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 492*cdf0e10cSrcweir mpCharWidths[ i ] *= mfFontScale; 493*cdf0e10cSrcweir if( mpGlyphAdvances != mpCharWidths ) 494*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 495*cdf0e10cSrcweir mpGlyphAdvances[ i ] *= mfFontScale; 496*cdf0e10cSrcweir if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) ) 497*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 498*cdf0e10cSrcweir mpGlyphOrigAdvs[ i ] *= mfFontScale; 499*cdf0e10cSrcweir } 500*cdf0e10cSrcweir 501*cdf0e10cSrcweir return true; 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir // ----------------------------------------------------------------------- 505*cdf0e10cSrcweir 506*cdf0e10cSrcweir int Os2SalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart, 507*cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharIndexes ) const 508*cdf0e10cSrcweir { 509*cdf0e10cSrcweir // return zero if no more glyph found 510*cdf0e10cSrcweir if( nStart >= mnGlyphCount ) 511*cdf0e10cSrcweir return 0; 512*cdf0e10cSrcweir 513*cdf0e10cSrcweir // calculate glyph position relative to layout base 514*cdf0e10cSrcweir // TODO: avoid for nStart!=0 case by reusing rPos 515*cdf0e10cSrcweir long nXOffset = mnBaseAdv; 516*cdf0e10cSrcweir for( int i = 0; i < nStart; ++i ) 517*cdf0e10cSrcweir nXOffset += mpGlyphAdvances[ i ]; 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir // calculate absolute position in pixel units 520*cdf0e10cSrcweir Point aRelativePos( nXOffset, 0 ); 521*cdf0e10cSrcweir rPos = GetDrawPosition( aRelativePos ); 522*cdf0e10cSrcweir 523*cdf0e10cSrcweir int nCount = 0; 524*cdf0e10cSrcweir while( nCount < nLen ) 525*cdf0e10cSrcweir { 526*cdf0e10cSrcweir // update return values {nGlyphIndex,nCharPos,nGlyphAdvance} 527*cdf0e10cSrcweir long nGlyphIndex = mpOutGlyphs[ nStart ]; 528*cdf0e10cSrcweir if( mbDisableGlyphs ) 529*cdf0e10cSrcweir { 530*cdf0e10cSrcweir if( mnLayoutFlags & SAL_LAYOUT_VERTICAL ) 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir sal_Unicode cChar = (sal_Unicode)(nGlyphIndex & GF_IDXMASK); 533*cdf0e10cSrcweir #ifdef GNG_VERT_HACK 534*cdf0e10cSrcweir if( mrOs2FontData.HasGSUBstitutions( mhPS ) 535*cdf0e10cSrcweir && mrOs2FontData.IsGSUBstituted( cChar ) ) 536*cdf0e10cSrcweir nGlyphIndex |= GF_ROTL | GF_GSUB; 537*cdf0e10cSrcweir else 538*cdf0e10cSrcweir #endif // GNG_VERT_HACK 539*cdf0e10cSrcweir { 540*cdf0e10cSrcweir nGlyphIndex |= GetVerticalFlags( cChar ); 541*cdf0e10cSrcweir if( !(nGlyphIndex & GF_ROTMASK) ) 542*cdf0e10cSrcweir nGlyphIndex |= GF_VERT; 543*cdf0e10cSrcweir } 544*cdf0e10cSrcweir } 545*cdf0e10cSrcweir nGlyphIndex |= GF_ISCHAR; 546*cdf0e10cSrcweir } 547*cdf0e10cSrcweir ++nCount; 548*cdf0e10cSrcweir *(pGlyphs++) = nGlyphIndex; 549*cdf0e10cSrcweir if( pGlyphAdvances ) 550*cdf0e10cSrcweir *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ]; 551*cdf0e10cSrcweir if( pCharIndexes ) 552*cdf0e10cSrcweir { 553*cdf0e10cSrcweir int nCharPos; 554*cdf0e10cSrcweir if( !mpGlyphs2Chars ) 555*cdf0e10cSrcweir nCharPos = nStart + mnMinCharPos; 556*cdf0e10cSrcweir else 557*cdf0e10cSrcweir nCharPos = mpGlyphs2Chars[nStart]; 558*cdf0e10cSrcweir *(pCharIndexes++) = nCharPos; 559*cdf0e10cSrcweir } 560*cdf0e10cSrcweir 561*cdf0e10cSrcweir // stop at last glyph 562*cdf0e10cSrcweir if( ++nStart >= mnGlyphCount ) 563*cdf0e10cSrcweir break; 564*cdf0e10cSrcweir 565*cdf0e10cSrcweir // stop when next x-position is unexpected 566*cdf0e10cSrcweir if( !pGlyphAdvances && mpGlyphOrigAdvs ) 567*cdf0e10cSrcweir if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] ) 568*cdf0e10cSrcweir break; 569*cdf0e10cSrcweir } 570*cdf0e10cSrcweir 571*cdf0e10cSrcweir return nCount; 572*cdf0e10cSrcweir } 573*cdf0e10cSrcweir 574*cdf0e10cSrcweir // ----------------------------------------------------------------------- 575*cdf0e10cSrcweir 576*cdf0e10cSrcweir void Os2SalLayout::DrawText( SalGraphics& rGraphics ) const 577*cdf0e10cSrcweir { 578*cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 579*cdf0e10cSrcweir return; 580*cdf0e10cSrcweir 581*cdf0e10cSrcweir Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) ); 582*cdf0e10cSrcweir POINTL aPt; 583*cdf0e10cSrcweir APIRET rc; 584*cdf0e10cSrcweir 585*cdf0e10cSrcweir aPt.x = aPos.X(); 586*cdf0e10cSrcweir aPt.y = static_cast<Os2SalGraphics&>(rGraphics).mnHeight - aPos.Y(); 587*cdf0e10cSrcweir 588*cdf0e10cSrcweir // ft2lib doesn't work with printer hps, so we fallback to codepage printing 589*cdf0e10cSrcweir // until cp1200 support will work. 590*cdf0e10cSrcweir if (static_cast<Os2SalGraphics&>(rGraphics).mbPrinter) { 591*cdf0e10cSrcweir // convert to codepage 592*cdf0e10cSrcweir ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() ); 593*cdf0e10cSrcweir // gliph size is not recalculated, so it could be wrong! 594*cdf0e10cSrcweir rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS, 595*cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(), 596*cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0); 597*cdf0e10cSrcweir } else { 598*cdf0e10cSrcweir // try unicode rendering to screen 599*cdf0e10cSrcweir rc = Ft2CharStringPosAtW( static_cast<Os2SalGraphics&>(rGraphics).mhPS, 600*cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (LPWSTR)mpOutGlyphs, 601*cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0); 602*cdf0e10cSrcweir if (rc == GPI_ERROR) { 603*cdf0e10cSrcweir // if *W fails, convert to codepage and use *A (fallback to GPI into ft2) 604*cdf0e10cSrcweir ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() ); 605*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>10 606*cdf0e10cSrcweir debug_printf("Os2SalLayout::DrawText HPS %08x PosAtW failed '%s'!\n",static_cast<Os2SalGraphics&>(rGraphics).mhPS,str.GetBuffer()); 607*cdf0e10cSrcweir #endif 608*cdf0e10cSrcweir // gliph size is not recalculated, so it could be wrong! 609*cdf0e10cSrcweir rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS, 610*cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(), 611*cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0); 612*cdf0e10cSrcweir } 613*cdf0e10cSrcweir } 614*cdf0e10cSrcweir } 615*cdf0e10cSrcweir 616*cdf0e10cSrcweir // ----------------------------------------------------------------------- 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir long Os2SalLayout::FillDXArray( long* pDXArray ) const 619*cdf0e10cSrcweir { 620*cdf0e10cSrcweir if( !mnWidth ) 621*cdf0e10cSrcweir { 622*cdf0e10cSrcweir long mnWidth = mnBaseAdv; 623*cdf0e10cSrcweir for( int i = 0; i < mnGlyphCount; ++i ) 624*cdf0e10cSrcweir mnWidth += mpGlyphAdvances[ i ]; 625*cdf0e10cSrcweir } 626*cdf0e10cSrcweir 627*cdf0e10cSrcweir if( pDXArray != NULL ) 628*cdf0e10cSrcweir { 629*cdf0e10cSrcweir for( int i = 0; i < mnCharCount; ++i ) 630*cdf0e10cSrcweir pDXArray[ i ] = mpCharWidths[ i ]; 631*cdf0e10cSrcweir } 632*cdf0e10cSrcweir 633*cdf0e10cSrcweir return mnWidth; 634*cdf0e10cSrcweir } 635*cdf0e10cSrcweir 636*cdf0e10cSrcweir // ----------------------------------------------------------------------- 637*cdf0e10cSrcweir 638*cdf0e10cSrcweir int Os2SalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const 639*cdf0e10cSrcweir // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values 640*cdf0e10cSrcweir { 641*cdf0e10cSrcweir if( mnWidth ) 642*cdf0e10cSrcweir if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth ) 643*cdf0e10cSrcweir return STRING_LEN; 644*cdf0e10cSrcweir 645*cdf0e10cSrcweir long nExtraWidth = mnBaseAdv * nFactor; 646*cdf0e10cSrcweir for( int n = 0; n < mnCharCount; ++n ) 647*cdf0e10cSrcweir { 648*cdf0e10cSrcweir // skip unused characters 649*cdf0e10cSrcweir if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) ) 650*cdf0e10cSrcweir continue; 651*cdf0e10cSrcweir // add char widths until max 652*cdf0e10cSrcweir nExtraWidth += mpCharWidths[ n ] * nFactor; 653*cdf0e10cSrcweir if( nExtraWidth >= nMaxWidth ) 654*cdf0e10cSrcweir return (mnMinCharPos + n); 655*cdf0e10cSrcweir nExtraWidth += nCharExtra; 656*cdf0e10cSrcweir } 657*cdf0e10cSrcweir 658*cdf0e10cSrcweir return STRING_LEN; 659*cdf0e10cSrcweir } 660*cdf0e10cSrcweir 661*cdf0e10cSrcweir // ----------------------------------------------------------------------- 662*cdf0e10cSrcweir 663*cdf0e10cSrcweir void Os2SalLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const 664*cdf0e10cSrcweir { 665*cdf0e10cSrcweir long nXPos = mnBaseAdv; 666*cdf0e10cSrcweir 667*cdf0e10cSrcweir if( !mpGlyphs2Chars ) 668*cdf0e10cSrcweir { 669*cdf0e10cSrcweir for( int i = 0; i < nMaxIdx; i += 2 ) 670*cdf0e10cSrcweir { 671*cdf0e10cSrcweir pCaretXArray[ i ] = nXPos; 672*cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i>>1 ]; 673*cdf0e10cSrcweir pCaretXArray[ i+1 ] = nXPos; 674*cdf0e10cSrcweir } 675*cdf0e10cSrcweir } 676*cdf0e10cSrcweir else 677*cdf0e10cSrcweir { 678*cdf0e10cSrcweir int i; 679*cdf0e10cSrcweir for( i = 0; i < nMaxIdx; ++i ) 680*cdf0e10cSrcweir pCaretXArray[ i ] = -1; 681*cdf0e10cSrcweir 682*cdf0e10cSrcweir // assign glyph positions to character positions 683*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos; 686*cdf0e10cSrcweir long nXRight = nXPos + mpCharWidths[ nCurrIdx ]; 687*cdf0e10cSrcweir nCurrIdx *= 2; 688*cdf0e10cSrcweir if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) ) 689*cdf0e10cSrcweir { 690*cdf0e10cSrcweir // normal positions for LTR case 691*cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXPos; 692*cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXRight; 693*cdf0e10cSrcweir } 694*cdf0e10cSrcweir else 695*cdf0e10cSrcweir { 696*cdf0e10cSrcweir // reverse positions for RTL case 697*cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXRight; 698*cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXPos; 699*cdf0e10cSrcweir } 700*cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i ]; 701*cdf0e10cSrcweir } 702*cdf0e10cSrcweir } 703*cdf0e10cSrcweir } 704*cdf0e10cSrcweir 705*cdf0e10cSrcweir // ----------------------------------------------------------------------- 706*cdf0e10cSrcweir 707*cdf0e10cSrcweir void Os2SalLayout::Justify( long nNewWidth ) 708*cdf0e10cSrcweir { 709*cdf0e10cSrcweir long nOldWidth = mnWidth; 710*cdf0e10cSrcweir mnWidth = nNewWidth; 711*cdf0e10cSrcweir 712*cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 713*cdf0e10cSrcweir return; 714*cdf0e10cSrcweir 715*cdf0e10cSrcweir if( nNewWidth == nOldWidth ) 716*cdf0e10cSrcweir return; 717*cdf0e10cSrcweir 718*cdf0e10cSrcweir // the rightmost glyph cannot be stretched 719*cdf0e10cSrcweir const int nRight = mnGlyphCount - 1; 720*cdf0e10cSrcweir nOldWidth -= mpGlyphAdvances[ nRight ]; 721*cdf0e10cSrcweir nNewWidth -= mpGlyphAdvances[ nRight ]; 722*cdf0e10cSrcweir 723*cdf0e10cSrcweir // count stretchable glyphs 724*cdf0e10cSrcweir int nStretchable = 0, i; 725*cdf0e10cSrcweir for( i = 0; i < nRight; ++i ) 726*cdf0e10cSrcweir if( mpGlyphAdvances[i] >= 0 ) 727*cdf0e10cSrcweir ++nStretchable; 728*cdf0e10cSrcweir 729*cdf0e10cSrcweir // stretch these glyphs 730*cdf0e10cSrcweir int nDiffWidth = nNewWidth - nOldWidth; 731*cdf0e10cSrcweir for( i = 0; (i < nRight) && (nStretchable > 0); ++i ) 732*cdf0e10cSrcweir { 733*cdf0e10cSrcweir if( mpGlyphAdvances[i] <= 0 ) 734*cdf0e10cSrcweir continue; 735*cdf0e10cSrcweir int nDeltaWidth = nDiffWidth / nStretchable; 736*cdf0e10cSrcweir mpGlyphAdvances[i] += nDeltaWidth; 737*cdf0e10cSrcweir --nStretchable; 738*cdf0e10cSrcweir nDiffWidth -= nDeltaWidth; 739*cdf0e10cSrcweir } 740*cdf0e10cSrcweir } 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir // ----------------------------------------------------------------------- 743*cdf0e10cSrcweir 744*cdf0e10cSrcweir void Os2SalLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 745*cdf0e10cSrcweir { 746*cdf0e10cSrcweir SalLayout::AdjustLayout( rArgs ); 747*cdf0e10cSrcweir 748*cdf0e10cSrcweir // adjust positions if requested 749*cdf0e10cSrcweir if( rArgs.mpDXArray ) 750*cdf0e10cSrcweir ApplyDXArray( rArgs ); 751*cdf0e10cSrcweir else if( rArgs.mnLayoutWidth ) 752*cdf0e10cSrcweir Justify( rArgs.mnLayoutWidth ); 753*cdf0e10cSrcweir else 754*cdf0e10cSrcweir return; 755*cdf0e10cSrcweir 756*cdf0e10cSrcweir // recalculate virtual char widths if they were changed 757*cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances ) 758*cdf0e10cSrcweir { 759*cdf0e10cSrcweir int i; 760*cdf0e10cSrcweir if( !mpGlyphs2Chars ) 761*cdf0e10cSrcweir { 762*cdf0e10cSrcweir // standard LTR case 763*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 764*cdf0e10cSrcweir mpCharWidths[ i ] = mpGlyphAdvances[ i ]; 765*cdf0e10cSrcweir } 766*cdf0e10cSrcweir else 767*cdf0e10cSrcweir { 768*cdf0e10cSrcweir // BiDi or complex case 769*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 770*cdf0e10cSrcweir mpCharWidths[ i ] = 0; 771*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 772*cdf0e10cSrcweir { 773*cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos; 774*cdf0e10cSrcweir if( j >= 0 ) 775*cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ]; 776*cdf0e10cSrcweir } 777*cdf0e10cSrcweir } 778*cdf0e10cSrcweir } 779*cdf0e10cSrcweir } 780*cdf0e10cSrcweir 781*cdf0e10cSrcweir // ----------------------------------------------------------------------- 782*cdf0e10cSrcweir 783*cdf0e10cSrcweir void Os2SalLayout::ApplyDXArray( const ImplLayoutArgs& rArgs ) 784*cdf0e10cSrcweir { 785*cdf0e10cSrcweir // try to avoid disturbance of text flow for LSB rounding case; 786*cdf0e10cSrcweir const long* pDXArray = rArgs.mpDXArray; 787*cdf0e10cSrcweir 788*cdf0e10cSrcweir int i = 0; 789*cdf0e10cSrcweir long nOldWidth = mnBaseAdv; 790*cdf0e10cSrcweir for(; i < mnCharCount; ++i ) 791*cdf0e10cSrcweir { 792*cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i]; 793*cdf0e10cSrcweir if( j >= 0 ) 794*cdf0e10cSrcweir { 795*cdf0e10cSrcweir nOldWidth += mpGlyphAdvances[ j ]; 796*cdf0e10cSrcweir int nDiff = nOldWidth - pDXArray[ i ]; 797*cdf0e10cSrcweir 798*cdf0e10cSrcweir // disabled because of #104768# 799*cdf0e10cSrcweir // works great for static text, but problems when typing 800*cdf0e10cSrcweir // if( nDiff>+1 || nDiff<-1 ) 801*cdf0e10cSrcweir // only bother with changing anything when something moved 802*cdf0e10cSrcweir if( nDiff != 0 ) 803*cdf0e10cSrcweir break; 804*cdf0e10cSrcweir } 805*cdf0e10cSrcweir } 806*cdf0e10cSrcweir if( i >= mnCharCount ) 807*cdf0e10cSrcweir return; 808*cdf0e10cSrcweir 809*cdf0e10cSrcweir if( !mpGlyphOrigAdvs ) 810*cdf0e10cSrcweir { 811*cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 812*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 813*cdf0e10cSrcweir mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ]; 814*cdf0e10cSrcweir } 815*cdf0e10cSrcweir 816*cdf0e10cSrcweir mnWidth = mnBaseAdv; 817*cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 818*cdf0e10cSrcweir { 819*cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i]; 820*cdf0e10cSrcweir if( j >= 0 ) 821*cdf0e10cSrcweir mpGlyphAdvances[j] = pDXArray[i] - mnWidth; 822*cdf0e10cSrcweir mnWidth = pDXArray[i]; 823*cdf0e10cSrcweir } 824*cdf0e10cSrcweir } 825*cdf0e10cSrcweir 826*cdf0e10cSrcweir // ----------------------------------------------------------------------- 827*cdf0e10cSrcweir 828*cdf0e10cSrcweir void Os2SalLayout::MoveGlyph( int nStart, long nNewXPos ) 829*cdf0e10cSrcweir { 830*cdf0e10cSrcweir if( nStart > mnGlyphCount ) 831*cdf0e10cSrcweir return; 832*cdf0e10cSrcweir 833*cdf0e10cSrcweir // calculate the current x-position of the requested glyph 834*cdf0e10cSrcweir // TODO: cache absolute positions 835*cdf0e10cSrcweir int nXPos = mnBaseAdv; 836*cdf0e10cSrcweir for( int i = 0; i < nStart; ++i ) 837*cdf0e10cSrcweir nXPos += mpGlyphAdvances[i]; 838*cdf0e10cSrcweir 839*cdf0e10cSrcweir // calculate the difference to the current glyph position 840*cdf0e10cSrcweir int nDelta = nNewXPos - nXPos; 841*cdf0e10cSrcweir 842*cdf0e10cSrcweir // adjust the width of the layout if it was already cached 843*cdf0e10cSrcweir if( mnWidth ) 844*cdf0e10cSrcweir mnWidth += nDelta; 845*cdf0e10cSrcweir 846*cdf0e10cSrcweir // depending on whether the requested glyph is leftmost in the layout 847*cdf0e10cSrcweir // adjust either the layout's or the requested glyph's relative position 848*cdf0e10cSrcweir if( nStart > 0 ) 849*cdf0e10cSrcweir mpGlyphAdvances[ nStart-1 ] += nDelta; 850*cdf0e10cSrcweir else 851*cdf0e10cSrcweir mnBaseAdv += nDelta; 852*cdf0e10cSrcweir } 853*cdf0e10cSrcweir 854*cdf0e10cSrcweir // ----------------------------------------------------------------------- 855*cdf0e10cSrcweir 856*cdf0e10cSrcweir void Os2SalLayout::DropGlyph( int nStart ) 857*cdf0e10cSrcweir { 858*cdf0e10cSrcweir mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH; 859*cdf0e10cSrcweir } 860*cdf0e10cSrcweir 861*cdf0e10cSrcweir // ----------------------------------------------------------------------- 862*cdf0e10cSrcweir 863*cdf0e10cSrcweir void Os2SalLayout::Simplify( bool bIsBase ) 864*cdf0e10cSrcweir { 865*cdf0e10cSrcweir // return early if no glyph has been dropped 866*cdf0e10cSrcweir int i = mnGlyphCount; 867*cdf0e10cSrcweir while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) ); 868*cdf0e10cSrcweir if( i < 0 ) 869*cdf0e10cSrcweir return; 870*cdf0e10cSrcweir 871*cdf0e10cSrcweir // convert the layout to a sparse layout if it is not already 872*cdf0e10cSrcweir if( !mpGlyphs2Chars ) 873*cdf0e10cSrcweir { 874*cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnGlyphCount ]; 875*cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ]; 876*cdf0e10cSrcweir // assertion: mnGlyphCount == mnCharCount 877*cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k ) 878*cdf0e10cSrcweir { 879*cdf0e10cSrcweir mpGlyphs2Chars[ k ] = mnMinCharPos + k; 880*cdf0e10cSrcweir mpCharWidths[ k ] = mpGlyphAdvances[ k ]; 881*cdf0e10cSrcweir } 882*cdf0e10cSrcweir } 883*cdf0e10cSrcweir 884*cdf0e10cSrcweir // remove dropped glyphs that are rightmost in the layout 885*cdf0e10cSrcweir for( i = mnGlyphCount; --i >= 0; ) 886*cdf0e10cSrcweir { 887*cdf0e10cSrcweir if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH ) 888*cdf0e10cSrcweir break; 889*cdf0e10cSrcweir if( mnWidth ) 890*cdf0e10cSrcweir mnWidth -= mpGlyphAdvances[ i ]; 891*cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos; 892*cdf0e10cSrcweir if( nRelCharPos >= 0 ) 893*cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0; 894*cdf0e10cSrcweir } 895*cdf0e10cSrcweir mnGlyphCount = i + 1; 896*cdf0e10cSrcweir 897*cdf0e10cSrcweir // keep original glyph widths around 898*cdf0e10cSrcweir if( !mpGlyphOrigAdvs ) 899*cdf0e10cSrcweir { 900*cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 901*cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k ) 902*cdf0e10cSrcweir mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ]; 903*cdf0e10cSrcweir } 904*cdf0e10cSrcweir 905*cdf0e10cSrcweir // remove dropped glyphs inside the layout 906*cdf0e10cSrcweir int nNewGC = 0; 907*cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 908*cdf0e10cSrcweir { 909*cdf0e10cSrcweir if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH ) 910*cdf0e10cSrcweir { 911*cdf0e10cSrcweir // adjust relative position to last valid glyph 912*cdf0e10cSrcweir int nDroppedWidth = mpGlyphAdvances[ i ]; 913*cdf0e10cSrcweir mpGlyphAdvances[ i ] = 0; 914*cdf0e10cSrcweir if( nNewGC > 0 ) 915*cdf0e10cSrcweir mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth; 916*cdf0e10cSrcweir else 917*cdf0e10cSrcweir mnBaseAdv += nDroppedWidth; 918*cdf0e10cSrcweir 919*cdf0e10cSrcweir // zero the virtual char width for the char that has a fallback 920*cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos; 921*cdf0e10cSrcweir if( nRelCharPos >= 0 ) 922*cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0; 923*cdf0e10cSrcweir } 924*cdf0e10cSrcweir else 925*cdf0e10cSrcweir { 926*cdf0e10cSrcweir if( nNewGC != i ) 927*cdf0e10cSrcweir { 928*cdf0e10cSrcweir // rearrange the glyph array to get rid of the dropped glyph 929*cdf0e10cSrcweir mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ]; 930*cdf0e10cSrcweir mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ]; 931*cdf0e10cSrcweir mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ]; 932*cdf0e10cSrcweir mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ]; 933*cdf0e10cSrcweir } 934*cdf0e10cSrcweir ++nNewGC; 935*cdf0e10cSrcweir } 936*cdf0e10cSrcweir } 937*cdf0e10cSrcweir 938*cdf0e10cSrcweir mnGlyphCount = nNewGC; 939*cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 940*cdf0e10cSrcweir mnWidth = mnBaseAdv = 0; 941*cdf0e10cSrcweir } 942*cdf0e10cSrcweir 943*cdf0e10cSrcweir // ======================================================================= 944*cdf0e10cSrcweir 945*cdf0e10cSrcweir SalLayout* Os2SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel ) 946*cdf0e10cSrcweir { 947*cdf0e10cSrcweir Os2SalLayout* pLayout = NULL; 948*cdf0e10cSrcweir DBG_ASSERT( mpOs2FontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL"); 949*cdf0e10cSrcweir 950*cdf0e10cSrcweir const ImplOs2FontData& rFontFace = *mpOs2FontData[ nFallbackLevel ]; 951*cdf0e10cSrcweir ImplOs2FontEntry& rFontInstance = *mpOs2FontEntry[ nFallbackLevel ]; 952*cdf0e10cSrcweir 953*cdf0e10cSrcweir { 954*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 955*cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() ) 956*cdf0e10cSrcweir { 957*cdf0e10cSrcweir // TODO: directly cache kerning info in the rFontInstance 958*cdf0e10cSrcweir // TODO: get rid of kerning methods+data in WinSalGraphics object 959*cdf0e10cSrcweir GetKernPairs( 0, NULL ); 960*cdf0e10cSrcweir rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs ); 961*cdf0e10cSrcweir } 962*cdf0e10cSrcweir #endif // GCP_KERN_HACK 963*cdf0e10cSrcweir 964*cdf0e10cSrcweir //BYTE eCharSet = ANSI_CHARSET; 965*cdf0e10cSrcweir //if( mpLogFont ) 966*cdf0e10cSrcweir // eCharSet = mpLogFont->lfCharSet; 967*cdf0e10cSrcweir pLayout = new Os2SalLayout( mhPS, 0, rFontFace, rFontInstance ); 968*cdf0e10cSrcweir } 969*cdf0e10cSrcweir 970*cdf0e10cSrcweir if( mfFontScale != 1.0 ) 971*cdf0e10cSrcweir pLayout->SetFontScale( mfFontScale ); 972*cdf0e10cSrcweir 973*cdf0e10cSrcweir return pLayout; 974*cdf0e10cSrcweir } 975*cdf0e10cSrcweir 976*cdf0e10cSrcweir // ======================================================================= 977*cdf0e10cSrcweir 978*cdf0e10cSrcweir ImplOs2FontEntry::ImplOs2FontEntry( ImplFontSelectData& rFSD ) 979*cdf0e10cSrcweir : ImplFontEntry( rFSD ), 980*cdf0e10cSrcweir maWidthMap( 512 ) 981*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 982*cdf0e10cSrcweir ,mpKerningPairs( NULL ) 983*cdf0e10cSrcweir ,mnKerningPairs( -1 ) 984*cdf0e10cSrcweir #endif // GCP_KERN_HACK 985*cdf0e10cSrcweir { 986*cdf0e10cSrcweir } 987*cdf0e10cSrcweir 988*cdf0e10cSrcweir // ----------------------------------------------------------------------- 989*cdf0e10cSrcweir 990*cdf0e10cSrcweir ImplOs2FontEntry::~ImplOs2FontEntry() 991*cdf0e10cSrcweir { 992*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 993*cdf0e10cSrcweir delete[] mpKerningPairs; 994*cdf0e10cSrcweir #endif // GCP_KERN_HACK 995*cdf0e10cSrcweir } 996*cdf0e10cSrcweir 997*cdf0e10cSrcweir // ----------------------------------------------------------------------- 998*cdf0e10cSrcweir 999*cdf0e10cSrcweir #ifdef GCP_KERN_HACK 1000*cdf0e10cSrcweir bool ImplOs2FontEntry::HasKernData() const 1001*cdf0e10cSrcweir { 1002*cdf0e10cSrcweir return (mnKerningPairs >= 0); 1003*cdf0e10cSrcweir } 1004*cdf0e10cSrcweir 1005*cdf0e10cSrcweir // ----------------------------------------------------------------------- 1006*cdf0e10cSrcweir 1007*cdf0e10cSrcweir void ImplOs2FontEntry::SetKernData( int nPairCount, const KERNINGPAIRS* pPairData ) 1008*cdf0e10cSrcweir { 1009*cdf0e10cSrcweir mnKerningPairs = nPairCount; 1010*cdf0e10cSrcweir mpKerningPairs = new KERNINGPAIRS[ mnKerningPairs ]; 1011*cdf0e10cSrcweir ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIRS) ); 1012*cdf0e10cSrcweir } 1013*cdf0e10cSrcweir 1014*cdf0e10cSrcweir // ----------------------------------------------------------------------- 1015*cdf0e10cSrcweir 1016*cdf0e10cSrcweir int ImplOs2FontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const 1017*cdf0e10cSrcweir { 1018*cdf0e10cSrcweir int nKernAmount = 0; 1019*cdf0e10cSrcweir if( mpKerningPairs ) 1020*cdf0e10cSrcweir { 1021*cdf0e10cSrcweir const KERNINGPAIRS aRefPair = { cLeft, cRight, 0 }; 1022*cdf0e10cSrcweir const KERNINGPAIRS* pFirstPair = mpKerningPairs; 1023*cdf0e10cSrcweir const KERNINGPAIRS* pEndPair = mpKerningPairs + mnKerningPairs; 1024*cdf0e10cSrcweir const KERNINGPAIRS* pPair = std::lower_bound( pFirstPair, 1025*cdf0e10cSrcweir pEndPair, aRefPair, ImplCmpKernData ); 1026*cdf0e10cSrcweir if( (pPair != pEndPair) 1027*cdf0e10cSrcweir && (pPair->sFirstChar == aRefPair.sFirstChar) 1028*cdf0e10cSrcweir && (pPair->sSecondChar == aRefPair.sSecondChar) ) 1029*cdf0e10cSrcweir nKernAmount = pPair->lKerningAmount; 1030*cdf0e10cSrcweir } 1031*cdf0e10cSrcweir 1032*cdf0e10cSrcweir return nKernAmount; 1033*cdf0e10cSrcweir } 1034*cdf0e10cSrcweir #endif // GCP_KERN_HACK 1035*cdf0e10cSrcweir 1036*cdf0e10cSrcweir // ======================================================================= 1037*cdf0e10cSrcweir 1038*cdf0e10cSrcweir ImplFontData* ImplOs2FontData::Clone() const 1039*cdf0e10cSrcweir { 1040*cdf0e10cSrcweir if( mpUnicodeMap ) 1041*cdf0e10cSrcweir mpUnicodeMap->AddReference(); 1042*cdf0e10cSrcweir ImplFontData* pClone = new ImplOs2FontData( *this ); 1043*cdf0e10cSrcweir return pClone; 1044*cdf0e10cSrcweir } 1045*cdf0e10cSrcweir 1046*cdf0e10cSrcweir // ----------------------------------------------------------------------- 1047*cdf0e10cSrcweir 1048*cdf0e10cSrcweir ImplFontEntry* ImplOs2FontData::CreateFontInstance( ImplFontSelectData& rFSD ) const 1049*cdf0e10cSrcweir { 1050*cdf0e10cSrcweir //debug_printf("ImplOs2FontData::CreateFontInstance\n"); 1051*cdf0e10cSrcweir ImplFontEntry* pEntry = new ImplOs2FontEntry( rFSD ); 1052*cdf0e10cSrcweir return pEntry; 1053*cdf0e10cSrcweir } 1054*cdf0e10cSrcweir 1055*cdf0e10cSrcweir // ======================================================================= 1056*cdf0e10cSrcweir 1057