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