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