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 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include "rtl/ustring.hxx" 28cdf0e10cSrcweir 29cdf0e10cSrcweir #include "osl/module.h" 30cdf0e10cSrcweir #include "osl/file.h" 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include "tools/svwin.h" 33cdf0e10cSrcweir 34cdf0e10cSrcweir #include "vcl/svapp.hxx" 35cdf0e10cSrcweir 36cdf0e10cSrcweir #include "win/salgdi.h" 37cdf0e10cSrcweir #include "win/saldata.hxx" 38cdf0e10cSrcweir 39cdf0e10cSrcweir // for GetMirroredChar 40cdf0e10cSrcweir #include "sft.hxx" 41cdf0e10cSrcweir #include "sallayout.hxx" 42cdf0e10cSrcweir 43cdf0e10cSrcweir #include <cstdio> 44cdf0e10cSrcweir #include <malloc.h> 45cdf0e10cSrcweir #ifndef __MINGW32__ 46cdf0e10cSrcweir #define alloca _alloca 47cdf0e10cSrcweir #endif 48cdf0e10cSrcweir 49cdf0e10cSrcweir #ifdef GCP_KERN_HACK 50cdf0e10cSrcweir #include <algorithm> 51cdf0e10cSrcweir #endif // GCP_KERN_HACK 52cdf0e10cSrcweir 53cdf0e10cSrcweir 54cdf0e10cSrcweir #define USE_UNISCRIBE 55cdf0e10cSrcweir #ifdef USE_UNISCRIBE 56cdf0e10cSrcweir #include <Usp10.h> 57cdf0e10cSrcweir #include <ShLwApi.h> 58cdf0e10cSrcweir #include <winver.h> 59cdf0e10cSrcweir #endif // USE_UNISCRIBE 60cdf0e10cSrcweir 61cdf0e10cSrcweir #include <hash_map> 62cdf0e10cSrcweir #include <set> 63cdf0e10cSrcweir 64cdf0e10cSrcweir typedef std::hash_map<int,int> IntMap; 65cdf0e10cSrcweir typedef std::set<int> IntSet; 66cdf0e10cSrcweir 67cdf0e10cSrcweir // Graphite headers 68cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 69cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 70cdf0e10cSrcweir #include <graphite/GrClient.h> 71cdf0e10cSrcweir #include <graphite/WinFont.h> 72cdf0e10cSrcweir #include <graphite/Segment.h> 73cdf0e10cSrcweir #include <graphite_layout.hxx> 74cdf0e10cSrcweir #include <graphite_cache.hxx> 75cdf0e10cSrcweir #include <graphite_features.hxx> 76cdf0e10cSrcweir #endif 77cdf0e10cSrcweir 78cdf0e10cSrcweir #define DROPPED_OUTGLYPH 0xFFFF 79cdf0e10cSrcweir 80cdf0e10cSrcweir using namespace rtl; 81cdf0e10cSrcweir 82cdf0e10cSrcweir // ======================================================================= 83cdf0e10cSrcweir 84cdf0e10cSrcweir // win32 specific physical font instance 85cdf0e10cSrcweir class ImplWinFontEntry : public ImplFontEntry 86cdf0e10cSrcweir { 87cdf0e10cSrcweir public: 88fed8d294SHerbert Dürr explicit ImplWinFontEntry( ImplFontSelectData& ); 89fed8d294SHerbert Dürr virtual ~ImplWinFontEntry(); 90cdf0e10cSrcweir 91cdf0e10cSrcweir private: 92cdf0e10cSrcweir // TODO: also add HFONT??? Watch out for issues with too many active fonts... 93cdf0e10cSrcweir 94cdf0e10cSrcweir #ifdef GCP_KERN_HACK 95cdf0e10cSrcweir public: 96cdf0e10cSrcweir bool HasKernData() const; 97cdf0e10cSrcweir void SetKernData( int, const KERNINGPAIR* ); 98cdf0e10cSrcweir int GetKerning( sal_Unicode, sal_Unicode ) const; 99cdf0e10cSrcweir private: 100cdf0e10cSrcweir KERNINGPAIR* mpKerningPairs; 101cdf0e10cSrcweir int mnKerningPairs; 102cdf0e10cSrcweir #endif // GCP_KERN_HACK 103cdf0e10cSrcweir 104cdf0e10cSrcweir #ifdef USE_UNISCRIBE 105cdf0e10cSrcweir public: 106cdf0e10cSrcweir SCRIPT_CACHE& GetScriptCache() const 107cdf0e10cSrcweir { return maScriptCache; } 108cdf0e10cSrcweir private: 109cdf0e10cSrcweir mutable SCRIPT_CACHE maScriptCache; 110cdf0e10cSrcweir #endif // USE_UNISCRIBE 111cdf0e10cSrcweir 112cdf0e10cSrcweir public: 113cdf0e10cSrcweir int GetCachedGlyphWidth( int nCharCode ) const; 114cdf0e10cSrcweir void CacheGlyphWidth( int nCharCode, int nCharWidth ); 115cdf0e10cSrcweir 116cdf0e10cSrcweir bool InitKashidaHandling( HDC ); 117cdf0e10cSrcweir int GetMinKashidaWidth() const { return mnMinKashidaWidth; } 118cdf0e10cSrcweir int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; } 119cdf0e10cSrcweir 120cdf0e10cSrcweir private: 121cdf0e10cSrcweir IntMap maWidthMap; 122cdf0e10cSrcweir mutable int mnMinKashidaWidth; 123cdf0e10cSrcweir mutable int mnMinKashidaGlyph; 124cdf0e10cSrcweir }; 125cdf0e10cSrcweir 126cdf0e10cSrcweir // ----------------------------------------------------------------------- 127cdf0e10cSrcweir 128cdf0e10cSrcweir inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) 129cdf0e10cSrcweir { 130cdf0e10cSrcweir maWidthMap[ nCharCode ] = nCharWidth; 131cdf0e10cSrcweir } 132cdf0e10cSrcweir 133cdf0e10cSrcweir inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const 134cdf0e10cSrcweir { 135cdf0e10cSrcweir IntMap::const_iterator it = maWidthMap.find( nCharCode ); 136cdf0e10cSrcweir if( it == maWidthMap.end() ) 137cdf0e10cSrcweir return -1; 138cdf0e10cSrcweir return it->second; 139cdf0e10cSrcweir } 140cdf0e10cSrcweir 141cdf0e10cSrcweir // ======================================================================= 142cdf0e10cSrcweir 143cdf0e10cSrcweir class WinLayout : public SalLayout 144cdf0e10cSrcweir { 145cdf0e10cSrcweir public: 146cdf0e10cSrcweir WinLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& ); 147cdf0e10cSrcweir virtual void InitFont() const; 148cdf0e10cSrcweir void SetFontScale( float f ) { mfFontScale = f; } 149cdf0e10cSrcweir float GetFontScale() const { return mfFontScale; } 150cdf0e10cSrcweir HFONT DisableFontScaling( void) const; 151cdf0e10cSrcweir 152cdf0e10cSrcweir #ifdef USE_UNISCRIBE 153cdf0e10cSrcweir SCRIPT_CACHE& GetScriptCache() const 154cdf0e10cSrcweir { return mrWinFontEntry.GetScriptCache(); } 155cdf0e10cSrcweir #endif // USE_UNISCRIBE 156cdf0e10cSrcweir 157cdf0e10cSrcweir protected: 158cdf0e10cSrcweir HDC mhDC; // WIN32 device handle 159cdf0e10cSrcweir HFONT mhFont; // WIN32 font handle 160cdf0e10cSrcweir int mnBaseAdv; // x-offset relative to Layout origin 161cdf0e10cSrcweir float mfFontScale; // allows metrics emulation of huge font sizes 162cdf0e10cSrcweir 163cdf0e10cSrcweir const ImplWinFontData& mrWinFontData; 164cdf0e10cSrcweir ImplWinFontEntry& mrWinFontEntry; 165cdf0e10cSrcweir }; 166cdf0e10cSrcweir 167cdf0e10cSrcweir // ======================================================================= 168cdf0e10cSrcweir 169cdf0e10cSrcweir class SimpleWinLayout : public WinLayout 170cdf0e10cSrcweir { 171cdf0e10cSrcweir public: 172cdf0e10cSrcweir SimpleWinLayout( HDC, BYTE nCharSet, const ImplWinFontData&, ImplWinFontEntry& ); 173cdf0e10cSrcweir virtual ~SimpleWinLayout(); 174cdf0e10cSrcweir 175cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& ); 176cdf0e10cSrcweir virtual void AdjustLayout( ImplLayoutArgs& ); 177cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const; 178cdf0e10cSrcweir 179cdf0e10cSrcweir virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, 180cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharIndexes ) const; 181cdf0e10cSrcweir 182cdf0e10cSrcweir virtual long FillDXArray( long* pDXArray ) const; 183cdf0e10cSrcweir virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; 184cdf0e10cSrcweir virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; 185cdf0e10cSrcweir 186cdf0e10cSrcweir // for glyph+font+script fallback 187cdf0e10cSrcweir virtual void MoveGlyph( int nStart, long nNewXPos ); 188cdf0e10cSrcweir virtual void DropGlyph( int nStart ); 189cdf0e10cSrcweir virtual void Simplify( bool bIsBase ); 190cdf0e10cSrcweir 191cdf0e10cSrcweir protected: 192cdf0e10cSrcweir void Justify( long nNewWidth ); 193cdf0e10cSrcweir void ApplyDXArray( const ImplLayoutArgs& ); 194cdf0e10cSrcweir 195cdf0e10cSrcweir private: 196cdf0e10cSrcweir int mnGlyphCount; 197cdf0e10cSrcweir int mnCharCount; 198cdf0e10cSrcweir WCHAR* mpOutGlyphs; 199cdf0e10cSrcweir int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[] 200cdf0e10cSrcweir int* mpGlyphOrigAdvs; 201cdf0e10cSrcweir int* mpCharWidths; // map rel char pos to char width 202cdf0e10cSrcweir int* mpChars2Glyphs; // map rel char pos to abs glyph pos 203cdf0e10cSrcweir int* mpGlyphs2Chars; // map abs glyph pos to abs char pos 204cdf0e10cSrcweir bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL 205cdf0e10cSrcweir mutable long mnWidth; 206cdf0e10cSrcweir bool mbDisableGlyphs; 207cdf0e10cSrcweir 208cdf0e10cSrcweir int mnNotdefWidth; 209cdf0e10cSrcweir BYTE mnCharSet; 210cdf0e10cSrcweir }; 211cdf0e10cSrcweir 212cdf0e10cSrcweir // ======================================================================= 213cdf0e10cSrcweir 214cdf0e10cSrcweir WinLayout::WinLayout( HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE ) 215cdf0e10cSrcweir : mhDC( hDC ), 216cdf0e10cSrcweir mhFont( (HFONT)::GetCurrentObject(hDC,OBJ_FONT) ), 217cdf0e10cSrcweir mnBaseAdv( 0 ), 218cdf0e10cSrcweir mfFontScale( 1.0 ), 219cdf0e10cSrcweir mrWinFontData( rWFD ), 220cdf0e10cSrcweir mrWinFontEntry( rWFE ) 221cdf0e10cSrcweir {} 222cdf0e10cSrcweir 223cdf0e10cSrcweir // ----------------------------------------------------------------------- 224cdf0e10cSrcweir 225cdf0e10cSrcweir void WinLayout::InitFont() const 226cdf0e10cSrcweir { 227cdf0e10cSrcweir ::SelectObject( mhDC, mhFont ); 228cdf0e10cSrcweir } 229cdf0e10cSrcweir 230cdf0e10cSrcweir // ----------------------------------------------------------------------- 231cdf0e10cSrcweir 232cdf0e10cSrcweir // Using reasonably sized fonts to emulate huge fonts works around 233cdf0e10cSrcweir // a lot of problems in printer and display drivers. Huge fonts are 234cdf0e10cSrcweir // mostly used by high resolution reference devices which are never 235cdf0e10cSrcweir // painted to anyway. In the rare case that a huge font needs to be 236cdf0e10cSrcweir // displayed somewhere then the workaround doesn't help anymore. 237cdf0e10cSrcweir // If the drivers fail silently for huge fonts, so be it... 238cdf0e10cSrcweir HFONT WinLayout::DisableFontScaling() const 239cdf0e10cSrcweir { 240cdf0e10cSrcweir if( mfFontScale == 1.0 ) 241cdf0e10cSrcweir return 0; 242cdf0e10cSrcweir 243cdf0e10cSrcweir LOGFONTW aLogFont; 244cdf0e10cSrcweir ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont); 245cdf0e10cSrcweir aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight); 246cdf0e10cSrcweir aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth); 247cdf0e10cSrcweir HFONT hHugeFont = ::CreateFontIndirectW( &aLogFont); 248cdf0e10cSrcweir if( !hHugeFont ) 249cdf0e10cSrcweir return 0; 250cdf0e10cSrcweir 251cdf0e10cSrcweir return SelectFont( mhDC, hHugeFont ); 252cdf0e10cSrcweir } 253cdf0e10cSrcweir 254cdf0e10cSrcweir // ======================================================================= 255cdf0e10cSrcweir 256cdf0e10cSrcweir SimpleWinLayout::SimpleWinLayout( HDC hDC, BYTE nCharSet, 257cdf0e10cSrcweir const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry ) 258cdf0e10cSrcweir : WinLayout( hDC, rWinFontData, rWinFontEntry ), 259cdf0e10cSrcweir mnGlyphCount( 0 ), 260cdf0e10cSrcweir mnCharCount( 0 ), 261cdf0e10cSrcweir mpOutGlyphs( NULL ), 262cdf0e10cSrcweir mpGlyphAdvances( NULL ), 263cdf0e10cSrcweir mpGlyphOrigAdvs( NULL ), 264cdf0e10cSrcweir mpCharWidths( NULL ), 265cdf0e10cSrcweir mpChars2Glyphs( NULL ), 266cdf0e10cSrcweir mpGlyphs2Chars( NULL ), 267cdf0e10cSrcweir mpGlyphRTLFlags( NULL ), 268cdf0e10cSrcweir mnWidth( 0 ), 269cdf0e10cSrcweir mnNotdefWidth( -1 ), 270cdf0e10cSrcweir mnCharSet( nCharSet ), 271cdf0e10cSrcweir mbDisableGlyphs( false ) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir mbDisableGlyphs = true; 274cdf0e10cSrcweir } 275cdf0e10cSrcweir 276cdf0e10cSrcweir // ----------------------------------------------------------------------- 277cdf0e10cSrcweir 278cdf0e10cSrcweir SimpleWinLayout::~SimpleWinLayout() 279cdf0e10cSrcweir { 280cdf0e10cSrcweir delete[] mpGlyphRTLFlags; 281cdf0e10cSrcweir delete[] mpGlyphs2Chars; 282cdf0e10cSrcweir delete[] mpChars2Glyphs; 283cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances ) 284cdf0e10cSrcweir delete[] mpCharWidths; 285cdf0e10cSrcweir delete[] mpGlyphOrigAdvs; 286cdf0e10cSrcweir delete[] mpGlyphAdvances; 287cdf0e10cSrcweir delete[] mpOutGlyphs; 288cdf0e10cSrcweir } 289cdf0e10cSrcweir 290cdf0e10cSrcweir // ----------------------------------------------------------------------- 291cdf0e10cSrcweir 292cdf0e10cSrcweir bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs ) 293cdf0e10cSrcweir { 294cdf0e10cSrcweir // prepare layout 295cdf0e10cSrcweir // TODO: fix case when recyclying old SimpleWinLayout object 296cdf0e10cSrcweir mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0); 297cdf0e10cSrcweir mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos; 298cdf0e10cSrcweir 299cdf0e10cSrcweir if( !mbDisableGlyphs ) 300cdf0e10cSrcweir { 301cdf0e10cSrcweir // Win32 glyph APIs have serious problems with vertical layout 302cdf0e10cSrcweir // => workaround is to use the unicode methods then 303cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL ) 304cdf0e10cSrcweir mbDisableGlyphs = true; 305cdf0e10cSrcweir else 306cdf0e10cSrcweir // use cached value from font face 307cdf0e10cSrcweir mbDisableGlyphs = mrWinFontData.IsGlyphApiDisabled(); 308cdf0e10cSrcweir } 309cdf0e10cSrcweir 310cdf0e10cSrcweir // TODO: use a cached value for bDisableAsianKern from upper layers 311cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 312cdf0e10cSrcweir { 313cdf0e10cSrcweir TEXTMETRICA aTextMetricA; 314cdf0e10cSrcweir if( ::GetTextMetricsA( mhDC, &aTextMetricA ) 315cdf0e10cSrcweir && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) ) 316cdf0e10cSrcweir rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN; 317cdf0e10cSrcweir } 318cdf0e10cSrcweir 319cdf0e10cSrcweir // layout text 320cdf0e10cSrcweir int i, j; 321cdf0e10cSrcweir 322cdf0e10cSrcweir mnGlyphCount = 0; 323cdf0e10cSrcweir bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0; 324cdf0e10cSrcweir 325cdf0e10cSrcweir // count the number of chars to process if no RTL run 326cdf0e10cSrcweir rArgs.ResetPos(); 327cdf0e10cSrcweir bool bHasRTL = false; 328cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL ) 329cdf0e10cSrcweir mnGlyphCount += j - i; 330cdf0e10cSrcweir 331cdf0e10cSrcweir // if there are RTL runs we need room to remember individual BiDi flags 332cdf0e10cSrcweir if( bHasRTL ) 333cdf0e10cSrcweir { 334cdf0e10cSrcweir mpGlyphRTLFlags = new bool[ mnCharCount ]; 335cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 336cdf0e10cSrcweir mpGlyphRTLFlags[i] = false; 337cdf0e10cSrcweir } 338cdf0e10cSrcweir 339cdf0e10cSrcweir // rewrite the logical string if needed to prepare for the API calls 340cdf0e10cSrcweir const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos; 341cdf0e10cSrcweir if( (mnGlyphCount != mnCharCount) || bVertical ) 342cdf0e10cSrcweir { 343cdf0e10cSrcweir // we need to rewrite the pBidiStr when any of 344cdf0e10cSrcweir // - BiDirectional layout 345cdf0e10cSrcweir // - vertical layout 346cdf0e10cSrcweir // - partial runs (e.g. with control chars or for glyph fallback) 347cdf0e10cSrcweir // are involved 348cdf0e10cSrcweir sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) ); 349cdf0e10cSrcweir pBidiStr = pRewrittenStr; 350cdf0e10cSrcweir 351cdf0e10cSrcweir // note: glyph to char mapping is relative to first character 352cdf0e10cSrcweir mpChars2Glyphs = new int[ mnCharCount ]; 353cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnCharCount ]; 354cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 355cdf0e10cSrcweir mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1; 356cdf0e10cSrcweir 357cdf0e10cSrcweir mnGlyphCount = 0; 358cdf0e10cSrcweir rArgs.ResetPos(); 359cdf0e10cSrcweir bool bIsRTL = false; 360cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bIsRTL ) ) 361cdf0e10cSrcweir { 362cdf0e10cSrcweir do 363cdf0e10cSrcweir { 364cdf0e10cSrcweir // get the next leftmost character in this run 365cdf0e10cSrcweir int nCharPos = bIsRTL ? --j : i++; 366cdf0e10cSrcweir sal_UCS4 cChar = rArgs.mpStr[ nCharPos ]; 367cdf0e10cSrcweir 368cdf0e10cSrcweir // in the RTL case mirror the character and remember its RTL status 369cdf0e10cSrcweir if( bIsRTL ) 370cdf0e10cSrcweir { 371cdf0e10cSrcweir cChar = ::GetMirroredChar( cChar ); 372cdf0e10cSrcweir mpGlyphRTLFlags[ mnGlyphCount ] = true; 373cdf0e10cSrcweir } 374cdf0e10cSrcweir 375cdf0e10cSrcweir // for vertical writing use vertical alternatives 376cdf0e10cSrcweir if( bVertical ) 377cdf0e10cSrcweir { 378cdf0e10cSrcweir sal_UCS4 cVert = ::GetVerticalChar( cChar ); 379cdf0e10cSrcweir if( cVert ) 380cdf0e10cSrcweir cChar = cVert; 381cdf0e10cSrcweir } 382cdf0e10cSrcweir 383cdf0e10cSrcweir // rewrite the original string 384cdf0e10cSrcweir // update the mappings between original and rewritten string 385cdf0e10cSrcweir // TODO: support surrogates in rewritten strings 386cdf0e10cSrcweir pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar); 387cdf0e10cSrcweir mpGlyphs2Chars[ mnGlyphCount ] = nCharPos; 388cdf0e10cSrcweir mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount; 389cdf0e10cSrcweir ++mnGlyphCount; 390cdf0e10cSrcweir } while( i < j ); 391cdf0e10cSrcweir } 392cdf0e10cSrcweir } 393cdf0e10cSrcweir 394cdf0e10cSrcweir mpOutGlyphs = new WCHAR[ mnGlyphCount ]; 395cdf0e10cSrcweir mpGlyphAdvances = new int[ mnGlyphCount ]; 396cdf0e10cSrcweir 397cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) ) 398cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 399cdf0e10cSrcweir 400cdf0e10cSrcweir #ifndef GCP_KERN_HACK 401cdf0e10cSrcweir DWORD nGcpOption = 0; 402cdf0e10cSrcweir // enable kerning if requested 403cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS ) 404cdf0e10cSrcweir nGcpOption |= GCP_USEKERNING; 405cdf0e10cSrcweir #endif // GCP_KERN_HACK 406cdf0e10cSrcweir 407cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 408cdf0e10cSrcweir mpOutGlyphs[i] = pBidiStr[ i ]; 409cdf0e10cSrcweir mnWidth = 0; 410cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 411cdf0e10cSrcweir { 412cdf0e10cSrcweir // get the current UCS-4 code point, check for surrogate pairs 413cdf0e10cSrcweir const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]); 414cdf0e10cSrcweir unsigned nCharCode = pCodes[0]; 415cdf0e10cSrcweir bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF)); 416cdf0e10cSrcweir if( bSurrogate ) 417cdf0e10cSrcweir { 418cdf0e10cSrcweir if( nCharCode >= 0xDC00 ) // this part of a surrogate pair was already processed 419cdf0e10cSrcweir continue; 420cdf0e10cSrcweir nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00); 421cdf0e10cSrcweir } 422cdf0e10cSrcweir 423cdf0e10cSrcweir // get the advance width for the current UCS-4 code point 424cdf0e10cSrcweir int nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode ); 425cdf0e10cSrcweir if( nGlyphWidth == -1 ) 426cdf0e10cSrcweir { 427cdf0e10cSrcweir ABC aABC; 428cdf0e10cSrcweir SIZE aExtent; 429cdf0e10cSrcweir if( ::GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) ) 430cdf0e10cSrcweir nGlyphWidth = aExtent.cx; 431cdf0e10cSrcweir else if( ::GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) ) 432cdf0e10cSrcweir nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC; 433cdf0e10cSrcweir else if( !::GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth ) 434cdf0e10cSrcweir && !::GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) ) 435cdf0e10cSrcweir nGlyphWidth = 0; 436cdf0e10cSrcweir mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth ); 437cdf0e10cSrcweir } 438cdf0e10cSrcweir mpGlyphAdvances[ i ] = nGlyphWidth; 439cdf0e10cSrcweir mnWidth += nGlyphWidth; 440cdf0e10cSrcweir 441cdf0e10cSrcweir // remaining codes of surrogate pair get a zero width 442cdf0e10cSrcweir if( bSurrogate && ((i+1) < mnGlyphCount) ) 443cdf0e10cSrcweir mpGlyphAdvances[ i+1 ] = 0; 444cdf0e10cSrcweir 445cdf0e10cSrcweir // check with the font face if glyph fallback is needed 446cdf0e10cSrcweir if( mrWinFontData.HasChar( nCharCode ) ) 447cdf0e10cSrcweir continue; 448cdf0e10cSrcweir 449cdf0e10cSrcweir // request glyph fallback at this position in the string 450cdf0e10cSrcweir bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false; 451cdf0e10cSrcweir int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos; 452cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRTL ); 453cdf0e10cSrcweir if( bSurrogate && ((nCharPos+1) < rArgs.mnLength) ) 454cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRTL ); 455cdf0e10cSrcweir 456cdf0e10cSrcweir // replace the current glyph shape with the NotDef glyph shape 457cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK ) 458cdf0e10cSrcweir { 459cdf0e10cSrcweir // when we already are layouting for glyph fallback 460cdf0e10cSrcweir // then a new unresolved glyph is not interesting 461cdf0e10cSrcweir mnNotdefWidth = 0; 462cdf0e10cSrcweir mpOutGlyphs[i] = DROPPED_OUTGLYPH; 463cdf0e10cSrcweir } 464cdf0e10cSrcweir else 465cdf0e10cSrcweir { 466cdf0e10cSrcweir if( mnNotdefWidth < 0 ) 467cdf0e10cSrcweir { 468cdf0e10cSrcweir // get the width of the NotDef glyph 469cdf0e10cSrcweir SIZE aExtent; 470cdf0e10cSrcweir WCHAR cNotDef = rArgs.mpStr[ nCharPos ]; 471cdf0e10cSrcweir mnNotdefWidth = 0; 472cdf0e10cSrcweir if( ::GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) ) 473cdf0e10cSrcweir mnNotdefWidth = aExtent.cx; 474cdf0e10cSrcweir } 475cdf0e10cSrcweir // use a better NotDef glyph 476cdf0e10cSrcweir if( !mbDisableGlyphs && !bSurrogate ) 477cdf0e10cSrcweir mpOutGlyphs[i] = 0; 478cdf0e10cSrcweir } 479cdf0e10cSrcweir if( bSurrogate && ((i+1) < mnGlyphCount) ) 480cdf0e10cSrcweir mpOutGlyphs[i+1] = DROPPED_OUTGLYPH; 481cdf0e10cSrcweir 482cdf0e10cSrcweir // adjust the current glyph width to the NotDef glyph width 483cdf0e10cSrcweir mnWidth += mnNotdefWidth - mpGlyphAdvances[i]; 484cdf0e10cSrcweir mpGlyphAdvances[i] = mnNotdefWidth; 485cdf0e10cSrcweir if( mpGlyphOrigAdvs ) 486cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mnNotdefWidth; 487cdf0e10cSrcweir } 488cdf0e10cSrcweir 489cdf0e10cSrcweir #ifdef GCP_KERN_HACK 490cdf0e10cSrcweir // apply kerning if the layout engine has not yet done it 491cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) ) 492cdf0e10cSrcweir { 493cdf0e10cSrcweir #else // GCP_KERN_HACK 494cdf0e10cSrcweir // apply just asian kerning 495cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 496cdf0e10cSrcweir { 497cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) ) 498cdf0e10cSrcweir #endif // GCP_KERN_HACK 499cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 500cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mpGlyphAdvances[i]; 501cdf0e10cSrcweir 502cdf0e10cSrcweir // #99658# also apply asian kerning on the substring border 503cdf0e10cSrcweir int nLen = mnGlyphCount; 504cdf0e10cSrcweir if( rArgs.mnMinCharPos + nLen < rArgs.mnLength ) 505cdf0e10cSrcweir ++nLen; 506cdf0e10cSrcweir for( i = 1; i < nLen; ++i ) 507cdf0e10cSrcweir { 508cdf0e10cSrcweir #ifdef GCP_KERN_HACK 509cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS ) 510cdf0e10cSrcweir { 511cdf0e10cSrcweir int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] ); 512cdf0e10cSrcweir mpGlyphAdvances[ i-1 ] += nKernAmount; 513cdf0e10cSrcweir mnWidth += nKernAmount; 514cdf0e10cSrcweir } 515cdf0e10cSrcweir else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN ) 516cdf0e10cSrcweir #endif // GCP_KERN_HACK 517cdf0e10cSrcweir 518cdf0e10cSrcweir if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1]))) 519cdf0e10cSrcweir && ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) ) 520cdf0e10cSrcweir { 521cdf0e10cSrcweir long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical ); 522cdf0e10cSrcweir long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical ); 523cdf0e10cSrcweir 524cdf0e10cSrcweir long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext; 525cdf0e10cSrcweir if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 ) 526cdf0e10cSrcweir { 527cdf0e10cSrcweir nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4; 528cdf0e10cSrcweir mpGlyphAdvances[i-1] += nDelta; 529cdf0e10cSrcweir mnWidth += nDelta; 530cdf0e10cSrcweir } 531cdf0e10cSrcweir } 532cdf0e10cSrcweir } 533cdf0e10cSrcweir } 534cdf0e10cSrcweir 535cdf0e10cSrcweir // calculate virtual char widths 536cdf0e10cSrcweir if( !mpGlyphs2Chars ) 537cdf0e10cSrcweir mpCharWidths = mpGlyphAdvances; 538cdf0e10cSrcweir else 539cdf0e10cSrcweir { 540cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ]; 541cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 542cdf0e10cSrcweir mpCharWidths[ i ] = 0; 543cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 544cdf0e10cSrcweir { 545cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos; 546cdf0e10cSrcweir if( j >= 0 ) 547cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ]; 548cdf0e10cSrcweir } 549cdf0e10cSrcweir } 550cdf0e10cSrcweir 551cdf0e10cSrcweir // scale layout metrics if needed 552cdf0e10cSrcweir // TODO: does it make the code more simple if the metric scaling 553cdf0e10cSrcweir // is moved to the methods that need metric scaling (e.g. FillDXArray())? 554cdf0e10cSrcweir if( mfFontScale != 1.0 ) 555cdf0e10cSrcweir { 556cdf0e10cSrcweir mnWidth = (long)(mnWidth * mfFontScale); 557cdf0e10cSrcweir mnBaseAdv = (int)(mnBaseAdv * mfFontScale); 558cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 559cdf0e10cSrcweir mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale); 560cdf0e10cSrcweir if( mpGlyphAdvances != mpCharWidths ) 561cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 562cdf0e10cSrcweir mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale); 563cdf0e10cSrcweir if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) ) 564cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 565cdf0e10cSrcweir mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale); 566cdf0e10cSrcweir } 567cdf0e10cSrcweir 568cdf0e10cSrcweir return true; 569cdf0e10cSrcweir } 570cdf0e10cSrcweir 571cdf0e10cSrcweir // ----------------------------------------------------------------------- 572cdf0e10cSrcweir 573*248a599fSHerbert Dürr int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIds, Point& rPos, int& nStart, 574cdf0e10cSrcweir long* pGlyphAdvances, int* pCharIndexes ) const 575cdf0e10cSrcweir { 576cdf0e10cSrcweir // return zero if no more glyph found 577cdf0e10cSrcweir if( nStart >= mnGlyphCount ) 578cdf0e10cSrcweir return 0; 579cdf0e10cSrcweir 580cdf0e10cSrcweir // calculate glyph position relative to layout base 581cdf0e10cSrcweir // TODO: avoid for nStart!=0 case by reusing rPos 582cdf0e10cSrcweir long nXOffset = mnBaseAdv; 583cdf0e10cSrcweir for( int i = 0; i < nStart; ++i ) 584cdf0e10cSrcweir nXOffset += mpGlyphAdvances[ i ]; 585cdf0e10cSrcweir 586cdf0e10cSrcweir // calculate absolute position in pixel units 587cdf0e10cSrcweir Point aRelativePos( nXOffset, 0 ); 588cdf0e10cSrcweir rPos = GetDrawPosition( aRelativePos ); 589cdf0e10cSrcweir 590cdf0e10cSrcweir int nCount = 0; 591cdf0e10cSrcweir while( nCount < nLen ) 592cdf0e10cSrcweir { 593*248a599fSHerbert Dürr // update return values {aGlyphId,nCharPos,nGlyphAdvance} 594*248a599fSHerbert Dürr sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ]; 595cdf0e10cSrcweir if( mbDisableGlyphs ) 596cdf0e10cSrcweir { 597cdf0e10cSrcweir if( mnLayoutFlags & SAL_LAYOUT_VERTICAL ) 598cdf0e10cSrcweir { 599*248a599fSHerbert Dürr const sal_UCS4 cChar = static_cast<sal_UCS4>(aGlyphId & GF_IDXMASK); 600cdf0e10cSrcweir if( mrWinFontData.HasGSUBstitutions( mhDC ) 601cdf0e10cSrcweir && mrWinFontData.IsGSUBstituted( cChar ) ) 602*248a599fSHerbert Dürr aGlyphId |= GF_GSUB | GF_ROTL; 603cdf0e10cSrcweir else 604cdf0e10cSrcweir { 605*248a599fSHerbert Dürr aGlyphId |= GetVerticalFlags( cChar ); 606*248a599fSHerbert Dürr if( (aGlyphId & GF_ROTMASK) == 0 ) 607*248a599fSHerbert Dürr aGlyphId |= GF_VERT; 608cdf0e10cSrcweir } 609cdf0e10cSrcweir } 610*248a599fSHerbert Dürr aGlyphId |= GF_ISCHAR; 611cdf0e10cSrcweir } 612cdf0e10cSrcweir ++nCount; 613*248a599fSHerbert Dürr *(pGlyphIds++) = aGlyphId; 614cdf0e10cSrcweir if( pGlyphAdvances ) 615cdf0e10cSrcweir *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ]; 616cdf0e10cSrcweir if( pCharIndexes ) 617cdf0e10cSrcweir { 618cdf0e10cSrcweir int nCharPos; 619cdf0e10cSrcweir if( !mpGlyphs2Chars ) 620cdf0e10cSrcweir nCharPos = nStart + mnMinCharPos; 621cdf0e10cSrcweir else 622cdf0e10cSrcweir nCharPos = mpGlyphs2Chars[nStart]; 623cdf0e10cSrcweir *(pCharIndexes++) = nCharPos; 624cdf0e10cSrcweir } 625cdf0e10cSrcweir 626cdf0e10cSrcweir // stop at last glyph 627cdf0e10cSrcweir if( ++nStart >= mnGlyphCount ) 628cdf0e10cSrcweir break; 629cdf0e10cSrcweir 630cdf0e10cSrcweir // stop when next x-position is unexpected 631cdf0e10cSrcweir if( !pGlyphAdvances && mpGlyphOrigAdvs ) 632cdf0e10cSrcweir if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] ) 633cdf0e10cSrcweir break; 634cdf0e10cSrcweir } 635cdf0e10cSrcweir 636cdf0e10cSrcweir return nCount; 637cdf0e10cSrcweir } 638cdf0e10cSrcweir 639cdf0e10cSrcweir // ----------------------------------------------------------------------- 640cdf0e10cSrcweir 641cdf0e10cSrcweir void SimpleWinLayout::DrawText( SalGraphics& rGraphics ) const 642cdf0e10cSrcweir { 643cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 644cdf0e10cSrcweir return; 645cdf0e10cSrcweir 646cdf0e10cSrcweir WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics); 6475f27b83cSArmin Le Grand HDC aHDC = rWinGraphics.getHDC(); 648cdf0e10cSrcweir 649cdf0e10cSrcweir HFONT hOrigFont = DisableFontScaling(); 650cdf0e10cSrcweir 651cdf0e10cSrcweir UINT mnDrawOptions = ETO_GLYPH_INDEX; 652cdf0e10cSrcweir if( mbDisableGlyphs ) 653cdf0e10cSrcweir mnDrawOptions = 0; 654cdf0e10cSrcweir 655cdf0e10cSrcweir Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) ); 656cdf0e10cSrcweir 657cdf0e10cSrcweir // #108267#, break up into glyph portions of a limited size required by Win32 API 658cdf0e10cSrcweir const unsigned int maxGlyphCount = 8192; 659cdf0e10cSrcweir UINT numGlyphPortions = mnGlyphCount / maxGlyphCount; 660cdf0e10cSrcweir UINT remainingGlyphs = mnGlyphCount % maxGlyphCount; 661cdf0e10cSrcweir 662cdf0e10cSrcweir if( numGlyphPortions ) 663cdf0e10cSrcweir { 664cdf0e10cSrcweir // #108267#,#109387# break up string into smaller chunks 665cdf0e10cSrcweir // the output positions will be updated by windows (SetTextAlign) 666cdf0e10cSrcweir POINT oldPos; 667cdf0e10cSrcweir UINT oldTa = ::GetTextAlign( aHDC ); 668cdf0e10cSrcweir ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP ); 669cdf0e10cSrcweir ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos ); 670cdf0e10cSrcweir unsigned int i = 0; 671cdf0e10cSrcweir for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount ) 672cdf0e10cSrcweir ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL, 673cdf0e10cSrcweir mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i ); 674cdf0e10cSrcweir ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL, 675cdf0e10cSrcweir mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i ); 676cdf0e10cSrcweir ::MoveToEx( aHDC, oldPos.x, oldPos.y, (LPPOINT) NULL); 677cdf0e10cSrcweir ::SetTextAlign( aHDC, oldTa ); 678cdf0e10cSrcweir } 679cdf0e10cSrcweir else 680cdf0e10cSrcweir ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), mnDrawOptions, NULL, 681cdf0e10cSrcweir mpOutGlyphs, mnGlyphCount, mpGlyphAdvances ); 682cdf0e10cSrcweir 683cdf0e10cSrcweir if( hOrigFont ) 684cdf0e10cSrcweir DeleteFont( SelectFont( aHDC, hOrigFont ) ); 685cdf0e10cSrcweir } 686cdf0e10cSrcweir 687cdf0e10cSrcweir // ----------------------------------------------------------------------- 688cdf0e10cSrcweir 689cdf0e10cSrcweir long SimpleWinLayout::FillDXArray( long* pDXArray ) const 690cdf0e10cSrcweir { 691cdf0e10cSrcweir if( !mnWidth ) 692cdf0e10cSrcweir { 693cdf0e10cSrcweir long mnWidth = mnBaseAdv; 694cdf0e10cSrcweir for( int i = 0; i < mnGlyphCount; ++i ) 695cdf0e10cSrcweir mnWidth += mpGlyphAdvances[ i ]; 696cdf0e10cSrcweir } 697cdf0e10cSrcweir 698cdf0e10cSrcweir if( pDXArray != NULL ) 699cdf0e10cSrcweir { 700cdf0e10cSrcweir for( int i = 0; i < mnCharCount; ++i ) 701cdf0e10cSrcweir pDXArray[ i ] = mpCharWidths[ i ]; 702cdf0e10cSrcweir } 703cdf0e10cSrcweir 704cdf0e10cSrcweir return mnWidth; 705cdf0e10cSrcweir } 706cdf0e10cSrcweir 707cdf0e10cSrcweir // ----------------------------------------------------------------------- 708cdf0e10cSrcweir 709cdf0e10cSrcweir int SimpleWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const 710cdf0e10cSrcweir // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values 711cdf0e10cSrcweir { 712cdf0e10cSrcweir if( mnWidth ) 713cdf0e10cSrcweir if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth ) 714cdf0e10cSrcweir return STRING_LEN; 715cdf0e10cSrcweir 716cdf0e10cSrcweir long nExtraWidth = mnBaseAdv * nFactor; 717cdf0e10cSrcweir for( int n = 0; n < mnCharCount; ++n ) 718cdf0e10cSrcweir { 719cdf0e10cSrcweir // skip unused characters 720cdf0e10cSrcweir if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) ) 721cdf0e10cSrcweir continue; 722cdf0e10cSrcweir // add char widths until max 723cdf0e10cSrcweir nExtraWidth += mpCharWidths[ n ] * nFactor; 724cdf0e10cSrcweir if( nExtraWidth >= nMaxWidth ) 725cdf0e10cSrcweir return (mnMinCharPos + n); 726cdf0e10cSrcweir nExtraWidth += nCharExtra; 727cdf0e10cSrcweir } 728cdf0e10cSrcweir 729cdf0e10cSrcweir return STRING_LEN; 730cdf0e10cSrcweir } 731cdf0e10cSrcweir 732cdf0e10cSrcweir // ----------------------------------------------------------------------- 733cdf0e10cSrcweir 734cdf0e10cSrcweir void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const 735cdf0e10cSrcweir { 736cdf0e10cSrcweir long nXPos = mnBaseAdv; 737cdf0e10cSrcweir 738cdf0e10cSrcweir if( !mpGlyphs2Chars ) 739cdf0e10cSrcweir { 740cdf0e10cSrcweir for( int i = 0; i < nMaxIdx; i += 2 ) 741cdf0e10cSrcweir { 742cdf0e10cSrcweir pCaretXArray[ i ] = nXPos; 743cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i>>1 ]; 744cdf0e10cSrcweir pCaretXArray[ i+1 ] = nXPos; 745cdf0e10cSrcweir } 746cdf0e10cSrcweir } 747cdf0e10cSrcweir else 748cdf0e10cSrcweir { 749cdf0e10cSrcweir int i; 750cdf0e10cSrcweir for( i = 0; i < nMaxIdx; ++i ) 751cdf0e10cSrcweir pCaretXArray[ i ] = -1; 752cdf0e10cSrcweir 753cdf0e10cSrcweir // assign glyph positions to character positions 754cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 755cdf0e10cSrcweir { 756cdf0e10cSrcweir int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos; 757cdf0e10cSrcweir long nXRight = nXPos + mpCharWidths[ nCurrIdx ]; 758cdf0e10cSrcweir nCurrIdx *= 2; 759cdf0e10cSrcweir if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) ) 760cdf0e10cSrcweir { 761cdf0e10cSrcweir // normal positions for LTR case 762cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXPos; 763cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXRight; 764cdf0e10cSrcweir } 765cdf0e10cSrcweir else 766cdf0e10cSrcweir { 767cdf0e10cSrcweir // reverse positions for RTL case 768cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXRight; 769cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXPos; 770cdf0e10cSrcweir } 771cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i ]; 772cdf0e10cSrcweir } 773cdf0e10cSrcweir } 774cdf0e10cSrcweir } 775cdf0e10cSrcweir 776cdf0e10cSrcweir // ----------------------------------------------------------------------- 777cdf0e10cSrcweir 778cdf0e10cSrcweir void SimpleWinLayout::Justify( long nNewWidth ) 779cdf0e10cSrcweir { 780cdf0e10cSrcweir long nOldWidth = mnWidth; 781cdf0e10cSrcweir mnWidth = nNewWidth; 782cdf0e10cSrcweir 783cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 784cdf0e10cSrcweir return; 785cdf0e10cSrcweir 786cdf0e10cSrcweir if( nNewWidth == nOldWidth ) 787cdf0e10cSrcweir return; 788cdf0e10cSrcweir 789cdf0e10cSrcweir // the rightmost glyph cannot be stretched 790cdf0e10cSrcweir const int nRight = mnGlyphCount - 1; 791cdf0e10cSrcweir nOldWidth -= mpGlyphAdvances[ nRight ]; 792cdf0e10cSrcweir nNewWidth -= mpGlyphAdvances[ nRight ]; 793cdf0e10cSrcweir 794cdf0e10cSrcweir // count stretchable glyphs 795cdf0e10cSrcweir int nStretchable = 0, i; 796cdf0e10cSrcweir for( i = 0; i < nRight; ++i ) 797cdf0e10cSrcweir if( mpGlyphAdvances[i] >= 0 ) 798cdf0e10cSrcweir ++nStretchable; 799cdf0e10cSrcweir 800cdf0e10cSrcweir // stretch these glyphs 801cdf0e10cSrcweir int nDiffWidth = nNewWidth - nOldWidth; 802cdf0e10cSrcweir for( i = 0; (i < nRight) && (nStretchable > 0); ++i ) 803cdf0e10cSrcweir { 804cdf0e10cSrcweir if( mpGlyphAdvances[i] <= 0 ) 805cdf0e10cSrcweir continue; 806cdf0e10cSrcweir int nDeltaWidth = nDiffWidth / nStretchable; 807cdf0e10cSrcweir mpGlyphAdvances[i] += nDeltaWidth; 808cdf0e10cSrcweir --nStretchable; 809cdf0e10cSrcweir nDiffWidth -= nDeltaWidth; 810cdf0e10cSrcweir } 811cdf0e10cSrcweir } 812cdf0e10cSrcweir 813cdf0e10cSrcweir // ----------------------------------------------------------------------- 814cdf0e10cSrcweir 815cdf0e10cSrcweir void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 816cdf0e10cSrcweir { 817cdf0e10cSrcweir SalLayout::AdjustLayout( rArgs ); 818cdf0e10cSrcweir 819cdf0e10cSrcweir // adjust positions if requested 820cdf0e10cSrcweir if( rArgs.mpDXArray ) 821cdf0e10cSrcweir ApplyDXArray( rArgs ); 822cdf0e10cSrcweir else if( rArgs.mnLayoutWidth ) 823cdf0e10cSrcweir Justify( rArgs.mnLayoutWidth ); 824cdf0e10cSrcweir else 825cdf0e10cSrcweir return; 826cdf0e10cSrcweir 827cdf0e10cSrcweir // recalculate virtual char widths if they were changed 828cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances ) 829cdf0e10cSrcweir { 830cdf0e10cSrcweir int i; 831cdf0e10cSrcweir if( !mpGlyphs2Chars ) 832cdf0e10cSrcweir { 833cdf0e10cSrcweir // standard LTR case 834cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 835cdf0e10cSrcweir mpCharWidths[ i ] = mpGlyphAdvances[ i ]; 836cdf0e10cSrcweir } 837cdf0e10cSrcweir else 838cdf0e10cSrcweir { 839cdf0e10cSrcweir // BiDi or complex case 840cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 841cdf0e10cSrcweir mpCharWidths[ i ] = 0; 842cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 843cdf0e10cSrcweir { 844cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos; 845cdf0e10cSrcweir if( j >= 0 ) 846cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ]; 847cdf0e10cSrcweir } 848cdf0e10cSrcweir } 849cdf0e10cSrcweir } 850cdf0e10cSrcweir } 851cdf0e10cSrcweir 852cdf0e10cSrcweir // ----------------------------------------------------------------------- 853cdf0e10cSrcweir 854cdf0e10cSrcweir void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs ) 855cdf0e10cSrcweir { 856cdf0e10cSrcweir // try to avoid disturbance of text flow for LSB rounding case; 857cdf0e10cSrcweir const long* pDXArray = rArgs.mpDXArray; 858cdf0e10cSrcweir 859cdf0e10cSrcweir int i = 0; 860cdf0e10cSrcweir long nOldWidth = mnBaseAdv; 861cdf0e10cSrcweir for(; i < mnCharCount; ++i ) 862cdf0e10cSrcweir { 863cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i]; 864cdf0e10cSrcweir if( j >= 0 ) 865cdf0e10cSrcweir { 866cdf0e10cSrcweir nOldWidth += mpGlyphAdvances[ j ]; 867cdf0e10cSrcweir int nDiff = nOldWidth - pDXArray[ i ]; 868cdf0e10cSrcweir 869cdf0e10cSrcweir // disabled because of #104768# 870cdf0e10cSrcweir // works great for static text, but problems when typing 871cdf0e10cSrcweir // if( nDiff>+1 || nDiff<-1 ) 872cdf0e10cSrcweir // only bother with changing anything when something moved 873cdf0e10cSrcweir if( nDiff != 0 ) 874cdf0e10cSrcweir break; 875cdf0e10cSrcweir } 876cdf0e10cSrcweir } 877cdf0e10cSrcweir if( i >= mnCharCount ) 878cdf0e10cSrcweir return; 879cdf0e10cSrcweir 880cdf0e10cSrcweir if( !mpGlyphOrigAdvs ) 881cdf0e10cSrcweir { 882cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 883cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 884cdf0e10cSrcweir mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ]; 885cdf0e10cSrcweir } 886cdf0e10cSrcweir 887cdf0e10cSrcweir mnWidth = mnBaseAdv; 888cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i ) 889cdf0e10cSrcweir { 890cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i]; 891cdf0e10cSrcweir if( j >= 0 ) 892cdf0e10cSrcweir mpGlyphAdvances[j] = pDXArray[i] - mnWidth; 893cdf0e10cSrcweir mnWidth = pDXArray[i]; 894cdf0e10cSrcweir } 895cdf0e10cSrcweir } 896cdf0e10cSrcweir 897cdf0e10cSrcweir // ----------------------------------------------------------------------- 898cdf0e10cSrcweir 899cdf0e10cSrcweir void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos ) 900cdf0e10cSrcweir { 901cdf0e10cSrcweir if( nStart > mnGlyphCount ) 902cdf0e10cSrcweir return; 903cdf0e10cSrcweir 904cdf0e10cSrcweir // calculate the current x-position of the requested glyph 905cdf0e10cSrcweir // TODO: cache absolute positions 906cdf0e10cSrcweir int nXPos = mnBaseAdv; 907cdf0e10cSrcweir for( int i = 0; i < nStart; ++i ) 908cdf0e10cSrcweir nXPos += mpGlyphAdvances[i]; 909cdf0e10cSrcweir 910cdf0e10cSrcweir // calculate the difference to the current glyph position 911cdf0e10cSrcweir int nDelta = nNewXPos - nXPos; 912cdf0e10cSrcweir 913cdf0e10cSrcweir // adjust the width of the layout if it was already cached 914cdf0e10cSrcweir if( mnWidth ) 915cdf0e10cSrcweir mnWidth += nDelta; 916cdf0e10cSrcweir 917cdf0e10cSrcweir // depending on whether the requested glyph is leftmost in the layout 918cdf0e10cSrcweir // adjust either the layout's or the requested glyph's relative position 919cdf0e10cSrcweir if( nStart > 0 ) 920cdf0e10cSrcweir mpGlyphAdvances[ nStart-1 ] += nDelta; 921cdf0e10cSrcweir else 922cdf0e10cSrcweir mnBaseAdv += nDelta; 923cdf0e10cSrcweir } 924cdf0e10cSrcweir 925cdf0e10cSrcweir // ----------------------------------------------------------------------- 926cdf0e10cSrcweir 927cdf0e10cSrcweir void SimpleWinLayout::DropGlyph( int nStart ) 928cdf0e10cSrcweir { 929cdf0e10cSrcweir mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH; 930cdf0e10cSrcweir } 931cdf0e10cSrcweir 932cdf0e10cSrcweir // ----------------------------------------------------------------------- 933cdf0e10cSrcweir 934cdf0e10cSrcweir void SimpleWinLayout::Simplify( bool /*bIsBase*/ ) 935cdf0e10cSrcweir { 936cdf0e10cSrcweir // return early if no glyph has been dropped 937cdf0e10cSrcweir int i = mnGlyphCount; 938cdf0e10cSrcweir while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) ); 939cdf0e10cSrcweir if( i < 0 ) 940cdf0e10cSrcweir return; 941cdf0e10cSrcweir 942cdf0e10cSrcweir // convert the layout to a sparse layout if it is not already 943cdf0e10cSrcweir if( !mpGlyphs2Chars ) 944cdf0e10cSrcweir { 945cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnGlyphCount ]; 946cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ]; 947cdf0e10cSrcweir // assertion: mnGlyphCount == mnCharCount 948cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k ) 949cdf0e10cSrcweir { 950cdf0e10cSrcweir mpGlyphs2Chars[ k ] = mnMinCharPos + k; 951cdf0e10cSrcweir mpCharWidths[ k ] = mpGlyphAdvances[ k ]; 952cdf0e10cSrcweir } 953cdf0e10cSrcweir } 954cdf0e10cSrcweir 955cdf0e10cSrcweir // remove dropped glyphs that are rightmost in the layout 956cdf0e10cSrcweir for( i = mnGlyphCount; --i >= 0; ) 957cdf0e10cSrcweir { 958cdf0e10cSrcweir if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH ) 959cdf0e10cSrcweir break; 960cdf0e10cSrcweir if( mnWidth ) 961cdf0e10cSrcweir mnWidth -= mpGlyphAdvances[ i ]; 962cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos; 963cdf0e10cSrcweir if( nRelCharPos >= 0 ) 964cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0; 965cdf0e10cSrcweir } 966cdf0e10cSrcweir mnGlyphCount = i + 1; 967cdf0e10cSrcweir 968cdf0e10cSrcweir // keep original glyph widths around 969cdf0e10cSrcweir if( !mpGlyphOrigAdvs ) 970cdf0e10cSrcweir { 971cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ]; 972cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k ) 973cdf0e10cSrcweir mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ]; 974cdf0e10cSrcweir } 975cdf0e10cSrcweir 976cdf0e10cSrcweir // remove dropped glyphs inside the layout 977cdf0e10cSrcweir int nNewGC = 0; 978cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 979cdf0e10cSrcweir { 980cdf0e10cSrcweir if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH ) 981cdf0e10cSrcweir { 982cdf0e10cSrcweir // adjust relative position to last valid glyph 983cdf0e10cSrcweir int nDroppedWidth = mpGlyphAdvances[ i ]; 984cdf0e10cSrcweir mpGlyphAdvances[ i ] = 0; 985cdf0e10cSrcweir if( nNewGC > 0 ) 986cdf0e10cSrcweir mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth; 987cdf0e10cSrcweir else 988cdf0e10cSrcweir mnBaseAdv += nDroppedWidth; 989cdf0e10cSrcweir 990cdf0e10cSrcweir // zero the virtual char width for the char that has a fallback 991cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos; 992cdf0e10cSrcweir if( nRelCharPos >= 0 ) 993cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0; 994cdf0e10cSrcweir } 995cdf0e10cSrcweir else 996cdf0e10cSrcweir { 997cdf0e10cSrcweir if( nNewGC != i ) 998cdf0e10cSrcweir { 999cdf0e10cSrcweir // rearrange the glyph array to get rid of the dropped glyph 1000cdf0e10cSrcweir mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ]; 1001cdf0e10cSrcweir mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ]; 1002cdf0e10cSrcweir mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ]; 1003cdf0e10cSrcweir mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ]; 1004cdf0e10cSrcweir } 1005cdf0e10cSrcweir ++nNewGC; 1006cdf0e10cSrcweir } 1007cdf0e10cSrcweir } 1008cdf0e10cSrcweir 1009cdf0e10cSrcweir mnGlyphCount = nNewGC; 1010cdf0e10cSrcweir if( mnGlyphCount <= 0 ) 1011cdf0e10cSrcweir mnWidth = mnBaseAdv = 0; 1012cdf0e10cSrcweir } 1013cdf0e10cSrcweir 1014cdf0e10cSrcweir // ======================================================================= 1015cdf0e10cSrcweir 1016cdf0e10cSrcweir #ifdef USE_UNISCRIBE 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir struct VisualItem 1019cdf0e10cSrcweir { 1020cdf0e10cSrcweir public: 1021cdf0e10cSrcweir SCRIPT_ITEM* mpScriptItem; 1022cdf0e10cSrcweir int mnMinGlyphPos; 1023cdf0e10cSrcweir int mnEndGlyphPos; 1024cdf0e10cSrcweir int mnMinCharPos; 1025cdf0e10cSrcweir int mnEndCharPos; 1026cdf0e10cSrcweir //long mnPixelWidth; 1027cdf0e10cSrcweir int mnXOffset; 1028cdf0e10cSrcweir ABC maABCWidths; 1029cdf0e10cSrcweir bool mbHasKashidas; 1030cdf0e10cSrcweir 1031cdf0e10cSrcweir public: 1032cdf0e10cSrcweir bool IsEmpty() const { return (mnEndGlyphPos <= 0); } 1033cdf0e10cSrcweir bool IsRTL() const { return mpScriptItem->a.fRTL; } 1034cdf0e10cSrcweir bool HasKashidas() const { return mbHasKashidas; } 1035cdf0e10cSrcweir }; 1036cdf0e10cSrcweir 1037cdf0e10cSrcweir // ----------------------------------------------------------------------- 1038cdf0e10cSrcweir 1039cdf0e10cSrcweir class UniscribeLayout : public WinLayout 1040cdf0e10cSrcweir { 1041cdf0e10cSrcweir public: 1042cdf0e10cSrcweir UniscribeLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& ); 1043cdf0e10cSrcweir 1044cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& ); 1045cdf0e10cSrcweir virtual void AdjustLayout( ImplLayoutArgs& ); 1046cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const; 1047cdf0e10cSrcweir virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, 1048cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharPosAry ) const; 1049cdf0e10cSrcweir 1050cdf0e10cSrcweir virtual long FillDXArray( long* pDXArray ) const; 1051cdf0e10cSrcweir virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; 1052cdf0e10cSrcweir virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; 1053cdf0e10cSrcweir virtual bool IsKashidaPosValid ( int nCharPos ) const; 1054cdf0e10cSrcweir 1055cdf0e10cSrcweir // for glyph+font+script fallback 1056cdf0e10cSrcweir virtual void MoveGlyph( int nStart, long nNewXPos ); 1057cdf0e10cSrcweir virtual void DropGlyph( int nStart ); 1058cdf0e10cSrcweir virtual void Simplify( bool bIsBase ); 1059cdf0e10cSrcweir virtual void DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; } 1060cdf0e10cSrcweir 1061cdf0e10cSrcweir protected: 1062cdf0e10cSrcweir virtual ~UniscribeLayout(); 1063cdf0e10cSrcweir 1064cdf0e10cSrcweir void Justify( long nNewWidth ); 1065cdf0e10cSrcweir void ApplyDXArray( const ImplLayoutArgs& ); 1066cdf0e10cSrcweir 1067cdf0e10cSrcweir bool GetItemSubrange( const VisualItem&, 1068cdf0e10cSrcweir int& rMinIndex, int& rEndIndex ) const; 1069cdf0e10cSrcweir 1070cdf0e10cSrcweir private: 1071cdf0e10cSrcweir // item specific info 1072cdf0e10cSrcweir SCRIPT_ITEM* mpScriptItems; // in logical order 1073cdf0e10cSrcweir VisualItem* mpVisualItems; // in visual order 1074cdf0e10cSrcweir int mnItemCount; // number of visual items 1075cdf0e10cSrcweir 1076cdf0e10cSrcweir // string specific info 1077cdf0e10cSrcweir // everything is in logical order 1078cdf0e10cSrcweir int mnCharCapacity; 1079cdf0e10cSrcweir WORD* mpLogClusters; // map from absolute_char_pos to relative_glyph_pos 1080cdf0e10cSrcweir int* mpCharWidths; // map from absolute_char_pos to char_width 1081cdf0e10cSrcweir int mnSubStringMin; // char_pos of first char in context 1082cdf0e10cSrcweir 1083cdf0e10cSrcweir // glyph specific info 1084cdf0e10cSrcweir // everything is in visual order 1085cdf0e10cSrcweir int mnGlyphCount; 1086cdf0e10cSrcweir int mnGlyphCapacity; 1087cdf0e10cSrcweir int* mpGlyphAdvances; // glyph advance width before justification 1088cdf0e10cSrcweir int* mpJustifications; // glyph advance width after justification 1089cdf0e10cSrcweir WORD* mpOutGlyphs; // glyphids in visual order 1090cdf0e10cSrcweir GOFFSET* mpGlyphOffsets; // glyph offsets to the "naive" layout 1091cdf0e10cSrcweir SCRIPT_VISATTR* mpVisualAttrs; // glyph visual attributes 1092cdf0e10cSrcweir mutable int* mpGlyphs2Chars; // map from absolute_glyph_pos to absolute_char_pos 1093cdf0e10cSrcweir 1094cdf0e10cSrcweir // kashida stuff 1095cdf0e10cSrcweir void InitKashidaHandling(); 1096cdf0e10cSrcweir void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos ); 1097cdf0e10cSrcweir bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos ); 1098cdf0e10cSrcweir 1099cdf0e10cSrcweir int mnMinKashidaWidth; 1100cdf0e10cSrcweir int mnMinKashidaGlyph; 1101cdf0e10cSrcweir bool mbDisableGlyphInjection; 1102cdf0e10cSrcweir }; 1103cdf0e10cSrcweir 1104cdf0e10cSrcweir // ----------------------------------------------------------------------- 1105cdf0e10cSrcweir // dynamic loading of usp library 1106cdf0e10cSrcweir 1107cdf0e10cSrcweir static oslModule aUspModule = NULL; 1108cdf0e10cSrcweir static bool bUspEnabled = true; 1109cdf0e10cSrcweir 1110cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptIsComplex)( const WCHAR*, int, DWORD )); 1111cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptItemize)( const WCHAR*, int, int, 1112cdf0e10cSrcweir const SCRIPT_CONTROL*, const SCRIPT_STATE*, SCRIPT_ITEM*, int* )); 1113cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptShape)( HDC, SCRIPT_CACHE*, const WCHAR*, 1114cdf0e10cSrcweir int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*, int* )); 1115cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptPlace)( HDC, SCRIPT_CACHE*, const WORD*, int, 1116cdf0e10cSrcweir const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*, int*, GOFFSET*, ABC* )); 1117cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptGetLogicalWidths)( const SCRIPT_ANALYSIS*, 1118cdf0e10cSrcweir int, int, const int*, const WORD*, const SCRIPT_VISATTR*, int* )); 1119cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptApplyLogicalWidth)( const int*, int, int, const WORD*, 1120cdf0e10cSrcweir const SCRIPT_VISATTR*, const int*, const SCRIPT_ANALYSIS*, ABC*, int* )); 1121cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptJustify)( const SCRIPT_VISATTR*, 1122cdf0e10cSrcweir const int*, int, int, int, int* )); 1123cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptTextOut)( const HDC, SCRIPT_CACHE*, 1124cdf0e10cSrcweir int, int, UINT, const RECT*, const SCRIPT_ANALYSIS*, const WCHAR*, 1125cdf0e10cSrcweir int, const WORD*, int, const int*, const int*, const GOFFSET* )); 1126cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptGetFontProperties)( HDC, SCRIPT_CACHE*, SCRIPT_FONTPROPERTIES* )); 1127cdf0e10cSrcweir static HRESULT ((WINAPI *pScriptFreeCache)( SCRIPT_CACHE* )); 1128cdf0e10cSrcweir 1129cdf0e10cSrcweir static bool bManualCellAlign = true; 1130cdf0e10cSrcweir 1131cdf0e10cSrcweir // ----------------------------------------------------------------------- 1132cdf0e10cSrcweir 1133cdf0e10cSrcweir static bool InitUSP() 1134cdf0e10cSrcweir { 1135aa150a94SHerbert Dürr aUspModule = osl_loadAsciiModule( "usp10", SAL_LOADMODULE_DEFAULT ); 1136cdf0e10cSrcweir if( !aUspModule ) 1137cdf0e10cSrcweir return (bUspEnabled = false); 1138cdf0e10cSrcweir 1139cdf0e10cSrcweir pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD)) 1140cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" ); 1141cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptIsComplex); 1142cdf0e10cSrcweir 1143cdf0e10cSrcweir pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int, 1144cdf0e10cSrcweir const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*)) 1145cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" ); 1146cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptItemize); 1147cdf0e10cSrcweir 1148cdf0e10cSrcweir pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*, 1149cdf0e10cSrcweir int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*)) 1150cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" ); 1151cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptShape); 1152cdf0e10cSrcweir 1153cdf0e10cSrcweir pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int, 1154cdf0e10cSrcweir const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*)) 1155cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" ); 1156cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptPlace); 1157cdf0e10cSrcweir 1158cdf0e10cSrcweir pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*, 1159cdf0e10cSrcweir int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*)) 1160cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" ); 1161cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptGetLogicalWidths); 1162cdf0e10cSrcweir 1163cdf0e10cSrcweir pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*, 1164cdf0e10cSrcweir const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*)) 1165cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" ); 1166cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptApplyLogicalWidth); 1167cdf0e10cSrcweir 1168cdf0e10cSrcweir pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*, 1169cdf0e10cSrcweir int,int,int,int*)) 1170cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" ); 1171cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptJustify); 1172cdf0e10cSrcweir 1173cdf0e10cSrcweir pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*)) 1174cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" ); 1175cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptGetFontProperties); 1176cdf0e10cSrcweir 1177cdf0e10cSrcweir pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*, 1178cdf0e10cSrcweir int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*, 1179cdf0e10cSrcweir int,const WORD*,int,const int*,const int*,const GOFFSET*)) 1180cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" ); 1181cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptTextOut); 1182cdf0e10cSrcweir 1183cdf0e10cSrcweir pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*)) 1184cdf0e10cSrcweir osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" ); 1185cdf0e10cSrcweir bUspEnabled &= (NULL != pScriptFreeCache); 1186cdf0e10cSrcweir 1187cdf0e10cSrcweir if( !bUspEnabled ) 1188cdf0e10cSrcweir { 1189cdf0e10cSrcweir osl_unloadModule( aUspModule ); 1190cdf0e10cSrcweir aUspModule = NULL; 1191cdf0e10cSrcweir } 1192cdf0e10cSrcweir 1193cdf0e10cSrcweir // get the DLL version info 1194cdf0e10cSrcweir int nUspVersion = 0; 1195cdf0e10cSrcweir // TODO: there must be a simpler way to get the friggin version info from OSL? 1196cdf0e10cSrcweir rtl_uString* pModuleURL = NULL; 1197cdf0e10cSrcweir osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL ); 1198cdf0e10cSrcweir rtl_uString* pModuleFileName = NULL; 1199cdf0e10cSrcweir if( pModuleURL ) 1200cdf0e10cSrcweir osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName ); 1201cdf0e10cSrcweir const sal_Unicode* pModuleFileCStr = NULL; 1202cdf0e10cSrcweir if( pModuleFileName ) 1203cdf0e10cSrcweir pModuleFileCStr = rtl_uString_getStr( pModuleFileName ); 1204cdf0e10cSrcweir if( pModuleFileCStr ) 1205cdf0e10cSrcweir { 1206cdf0e10cSrcweir DWORD nHandle; 1207cdf0e10cSrcweir DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle ); 1208cdf0e10cSrcweir char* pBuffer = (char*)alloca( nBufSize ); 1209cdf0e10cSrcweir BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer ); 1210cdf0e10cSrcweir VS_FIXEDFILEINFO* pFixedFileInfo = NULL; 1211cdf0e10cSrcweir UINT nFixedFileSize = 0; 1212cdf0e10cSrcweir if( bRC ) 1213cdf0e10cSrcweir ::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize ); 1214cdf0e10cSrcweir if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD ) 1215cdf0e10cSrcweir nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000 1216cdf0e10cSrcweir + LOWORD(pFixedFileInfo->dwProductVersionMS); 1217cdf0e10cSrcweir } 1218cdf0e10cSrcweir 1219cdf0e10cSrcweir // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells 1220cdf0e10cSrcweir if( nUspVersion >= 10600 ) 1221cdf0e10cSrcweir bManualCellAlign = false; 1222cdf0e10cSrcweir 1223cdf0e10cSrcweir return bUspEnabled; 1224cdf0e10cSrcweir } 1225cdf0e10cSrcweir 1226cdf0e10cSrcweir // ----------------------------------------------------------------------- 1227cdf0e10cSrcweir 1228cdf0e10cSrcweir UniscribeLayout::UniscribeLayout( HDC hDC, 1229cdf0e10cSrcweir const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry ) 1230cdf0e10cSrcweir : WinLayout( hDC, rWinFontData, rWinFontEntry ), 1231cdf0e10cSrcweir mnItemCount( 0 ), 1232cdf0e10cSrcweir mpScriptItems( NULL ), 1233cdf0e10cSrcweir mpVisualItems( NULL ), 1234cdf0e10cSrcweir mpLogClusters( NULL ), 1235cdf0e10cSrcweir mpCharWidths( NULL ), 1236cdf0e10cSrcweir mnCharCapacity( 0 ), 1237cdf0e10cSrcweir mnSubStringMin( 0 ), 1238cdf0e10cSrcweir mnGlyphCapacity( 0 ), 1239cdf0e10cSrcweir mnGlyphCount( 0 ), 1240cdf0e10cSrcweir mpOutGlyphs( NULL ), 1241cdf0e10cSrcweir mpGlyphAdvances( NULL ), 1242cdf0e10cSrcweir mpJustifications( NULL ), 1243cdf0e10cSrcweir mpGlyphOffsets( NULL ), 1244cdf0e10cSrcweir mpVisualAttrs( NULL ), 1245cdf0e10cSrcweir mpGlyphs2Chars( NULL ), 1246cdf0e10cSrcweir mnMinKashidaGlyph( 0 ), 1247cdf0e10cSrcweir mbDisableGlyphInjection( false ) 1248cdf0e10cSrcweir {} 1249cdf0e10cSrcweir 1250cdf0e10cSrcweir // ----------------------------------------------------------------------- 1251cdf0e10cSrcweir 1252cdf0e10cSrcweir UniscribeLayout::~UniscribeLayout() 1253cdf0e10cSrcweir { 1254cdf0e10cSrcweir delete[] mpScriptItems; 1255cdf0e10cSrcweir delete[] mpVisualItems; 1256cdf0e10cSrcweir delete[] mpLogClusters; 1257cdf0e10cSrcweir delete[] mpCharWidths; 1258cdf0e10cSrcweir delete[] mpOutGlyphs; 1259cdf0e10cSrcweir delete[] mpGlyphAdvances; 1260cdf0e10cSrcweir delete[] mpJustifications; 1261cdf0e10cSrcweir delete[] mpGlyphOffsets; 1262cdf0e10cSrcweir delete[] mpVisualAttrs; 1263cdf0e10cSrcweir delete[] mpGlyphs2Chars; 1264cdf0e10cSrcweir } 1265cdf0e10cSrcweir 1266cdf0e10cSrcweir // ----------------------------------------------------------------------- 1267cdf0e10cSrcweir 1268cdf0e10cSrcweir bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs ) 1269cdf0e10cSrcweir { 1270cdf0e10cSrcweir // for a base layout only the context glyphs have to be dropped 1271cdf0e10cSrcweir // => when the whole string is involved there is no extra context 1272cdf0e10cSrcweir typedef std::vector<int> TIntVector; 1273cdf0e10cSrcweir TIntVector aDropChars; 1274cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK ) 1275cdf0e10cSrcweir { 1276cdf0e10cSrcweir // calculate superfluous context char positions 1277cdf0e10cSrcweir aDropChars.push_back( 0 ); 1278cdf0e10cSrcweir aDropChars.push_back( rArgs.mnLength ); 1279cdf0e10cSrcweir int nMin, nEnd; 1280cdf0e10cSrcweir bool bRTL; 1281cdf0e10cSrcweir for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); ) 1282cdf0e10cSrcweir { 1283cdf0e10cSrcweir aDropChars.push_back( nMin ); 1284cdf0e10cSrcweir aDropChars.push_back( nEnd ); 1285cdf0e10cSrcweir } 1286cdf0e10cSrcweir // prepare aDropChars for binary search which will allow to 1287cdf0e10cSrcweir // not bother with visual items that will be dropped anyway 1288cdf0e10cSrcweir std::sort( aDropChars.begin(), aDropChars.end() ); 1289cdf0e10cSrcweir } 1290cdf0e10cSrcweir 1291cdf0e10cSrcweir // prepare layout 1292cdf0e10cSrcweir // TODO: fix case when recyclying old UniscribeLayout object 1293cdf0e10cSrcweir mnMinCharPos = rArgs.mnMinCharPos; 1294cdf0e10cSrcweir mnEndCharPos = rArgs.mnEndCharPos; 1295cdf0e10cSrcweir 1296cdf0e10cSrcweir // determine script items from string 1297cdf0e10cSrcweir 1298cdf0e10cSrcweir // prepare itemization 1299cdf0e10cSrcweir // TODO: try to avoid itemization since it costs a lot of performance 1300cdf0e10cSrcweir SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0}; 1301cdf0e10cSrcweir aScriptState.uBidiLevel = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)); 1302cdf0e10cSrcweir aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG)); 1303cdf0e10cSrcweir aScriptState.fDigitSubstitute = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS)); 1304cdf0e10cSrcweir aScriptState.fArabicNumContext = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel; 1305cdf0e10cSrcweir DWORD nLangId = 0; // TODO: get language from font 1306cdf0e10cSrcweir SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0}; 1307cdf0e10cSrcweir aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection; 1308cdf0e10cSrcweir aScriptControl.fContextDigits = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS)); 1309fed8d294SHerbert Dürr aScriptControl.fMergeNeutralItems = true; 1310cdf0e10cSrcweir // determine relevant substring and work only on it 1311cdf0e10cSrcweir // when Bidi status is unknown we need to look at the whole string though 1312cdf0e10cSrcweir mnSubStringMin = 0; 1313cdf0e10cSrcweir int nSubStringEnd = rArgs.mnLength; 1314cdf0e10cSrcweir if( aScriptState.fOverrideDirection ) 1315cdf0e10cSrcweir { 1316cdf0e10cSrcweir // TODO: limit substring to portion limits 1317cdf0e10cSrcweir mnSubStringMin = rArgs.mnMinCharPos - 8; 1318cdf0e10cSrcweir if( mnSubStringMin < 0 ) 1319cdf0e10cSrcweir mnSubStringMin = 0; 1320cdf0e10cSrcweir nSubStringEnd = rArgs.mnEndCharPos + 8; 1321cdf0e10cSrcweir if( nSubStringEnd > rArgs.mnLength ) 1322cdf0e10cSrcweir nSubStringEnd = rArgs.mnLength; 1323cdf0e10cSrcweir 1324cdf0e10cSrcweir } 1325cdf0e10cSrcweir 1326cdf0e10cSrcweir // now itemize the substring with its context 1327cdf0e10cSrcweir for( int nItemCapacity = 16;; nItemCapacity *= 8 ) 1328cdf0e10cSrcweir { 1329cdf0e10cSrcweir mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ]; 1330cdf0e10cSrcweir HRESULT nRC = (*pScriptItemize)( 1331cdf0e10cSrcweir reinterpret_cast<LPCWSTR>(rArgs.mpStr + mnSubStringMin), nSubStringEnd - mnSubStringMin, 1332cdf0e10cSrcweir nItemCapacity - 1, &aScriptControl, &aScriptState, 1333cdf0e10cSrcweir mpScriptItems, &mnItemCount ); 1334cdf0e10cSrcweir if( !nRC ) // break loop when everything is correctly itemized 1335cdf0e10cSrcweir break; 1336cdf0e10cSrcweir 1337cdf0e10cSrcweir // prepare bigger buffers for another itemization round 1338cdf0e10cSrcweir delete[] mpScriptItems; 1339cdf0e10cSrcweir mpScriptItems = NULL; 1340cdf0e10cSrcweir if( nRC != E_OUTOFMEMORY ) 1341cdf0e10cSrcweir return false; 1342cdf0e10cSrcweir if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 ) 1343cdf0e10cSrcweir return false; 1344cdf0e10cSrcweir } 1345cdf0e10cSrcweir 1346cdf0e10cSrcweir // calculate the order of visual items 1347cdf0e10cSrcweir int nItem, i; 1348cdf0e10cSrcweir 1349cdf0e10cSrcweir // adjust char positions by substring offset 1350cdf0e10cSrcweir for( nItem = 0; nItem <= mnItemCount; ++nItem ) 1351cdf0e10cSrcweir mpScriptItems[ nItem ].iCharPos += mnSubStringMin; 1352cdf0e10cSrcweir // default visual item ordering 1353cdf0e10cSrcweir mpVisualItems = new VisualItem[ mnItemCount ]; 1354cdf0e10cSrcweir for( nItem = 0; nItem < mnItemCount; ++nItem ) 1355cdf0e10cSrcweir { 1356cdf0e10cSrcweir // initialize char specific item info 1357cdf0e10cSrcweir VisualItem& rVisualItem = mpVisualItems[ nItem ]; 1358cdf0e10cSrcweir SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ]; 1359cdf0e10cSrcweir rVisualItem.mpScriptItem = pScriptItem; 1360cdf0e10cSrcweir rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos; 1361cdf0e10cSrcweir rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos; 1362cdf0e10cSrcweir } 1363cdf0e10cSrcweir 1364cdf0e10cSrcweir // reorder visual item order if needed 1365cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG ) 1366cdf0e10cSrcweir { 1367cdf0e10cSrcweir // force RTL item ordering if requested 1368cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL ) 1369cdf0e10cSrcweir { 1370cdf0e10cSrcweir VisualItem* pVI0 = &mpVisualItems[ 0 ]; 1371cdf0e10cSrcweir VisualItem* pVI1 = &mpVisualItems[ mnItemCount ]; 1372cdf0e10cSrcweir while( pVI0 < --pVI1 ) 1373cdf0e10cSrcweir { 1374cdf0e10cSrcweir VisualItem aVtmp = *pVI0; 1375cdf0e10cSrcweir *(pVI0++) = *pVI1; 1376cdf0e10cSrcweir *pVI1 = aVtmp; 1377cdf0e10cSrcweir } 1378cdf0e10cSrcweir } 1379cdf0e10cSrcweir } 1380cdf0e10cSrcweir else if( mnItemCount > 1 ) 1381cdf0e10cSrcweir { 1382cdf0e10cSrcweir // apply bidi algorithm's rule L2 on item level 1383cdf0e10cSrcweir // TODO: use faster L2 algorithm 1384cdf0e10cSrcweir int nMaxBidiLevel = 0; 1385cdf0e10cSrcweir VisualItem* pVI = &mpVisualItems[0]; 1386cdf0e10cSrcweir VisualItem* const pVIend = pVI + mnItemCount; 1387cdf0e10cSrcweir for(; pVI < pVIend; ++pVI ) 1388cdf0e10cSrcweir if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel ) 1389cdf0e10cSrcweir nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel; 1390cdf0e10cSrcweir 1391cdf0e10cSrcweir while( --nMaxBidiLevel >= 0 ) 1392cdf0e10cSrcweir { 1393cdf0e10cSrcweir for( pVI = &mpVisualItems[0]; pVI < pVIend; ) 1394cdf0e10cSrcweir { 1395cdf0e10cSrcweir // find item range that needs reordering 1396cdf0e10cSrcweir for(; pVI < pVIend; ++pVI ) 1397cdf0e10cSrcweir if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel ) 1398cdf0e10cSrcweir break; 1399cdf0e10cSrcweir VisualItem* pVImin = pVI++; 1400cdf0e10cSrcweir for(; pVI < pVIend; ++pVI ) 1401cdf0e10cSrcweir if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel ) 1402cdf0e10cSrcweir break; 1403cdf0e10cSrcweir VisualItem* pVImax = pVI++; 1404cdf0e10cSrcweir 1405cdf0e10cSrcweir // reverse order of items in this range 1406cdf0e10cSrcweir while( pVImin < --pVImax ) 1407cdf0e10cSrcweir { 1408cdf0e10cSrcweir VisualItem aVtmp = *pVImin; 1409cdf0e10cSrcweir *(pVImin++) = *pVImax; 1410cdf0e10cSrcweir *pVImax = aVtmp; 1411cdf0e10cSrcweir } 1412cdf0e10cSrcweir } 1413cdf0e10cSrcweir } 1414cdf0e10cSrcweir } 1415cdf0e10cSrcweir 1416cdf0e10cSrcweir // allocate arrays 1417cdf0e10cSrcweir // TODO: when reusing object reuse old allocations or delete them 1418cdf0e10cSrcweir // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd) 1419cdf0e10cSrcweir mnCharCapacity = nSubStringEnd; 1420cdf0e10cSrcweir mpLogClusters = new WORD[ mnCharCapacity ]; 1421cdf0e10cSrcweir mpCharWidths = new int[ mnCharCapacity ]; 1422cdf0e10cSrcweir 1423cdf0e10cSrcweir mnGlyphCount = 0; 1424cdf0e10cSrcweir mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption 1425cdf0e10cSrcweir mpGlyphAdvances = new int[ mnGlyphCapacity ]; 1426cdf0e10cSrcweir mpOutGlyphs = new WORD[ mnGlyphCapacity ]; 1427cdf0e10cSrcweir mpGlyphOffsets = new GOFFSET[ mnGlyphCapacity ]; 1428cdf0e10cSrcweir mpVisualAttrs = new SCRIPT_VISATTR[ mnGlyphCapacity ]; 1429cdf0e10cSrcweir 1430cdf0e10cSrcweir long nXOffset = 0; 1431cdf0e10cSrcweir for( int j = mnSubStringMin; j < nSubStringEnd; ++j ) 1432cdf0e10cSrcweir mpCharWidths[j] = 0; 1433cdf0e10cSrcweir 1434cdf0e10cSrcweir // layout script items 1435cdf0e10cSrcweir SCRIPT_CACHE& rScriptCache = GetScriptCache(); 1436cdf0e10cSrcweir for( nItem = 0; nItem < mnItemCount; ++nItem ) 1437cdf0e10cSrcweir { 1438cdf0e10cSrcweir VisualItem& rVisualItem = mpVisualItems[ nItem ]; 1439cdf0e10cSrcweir 1440cdf0e10cSrcweir // initialize glyph specific item info 1441cdf0e10cSrcweir rVisualItem.mnMinGlyphPos = mnGlyphCount; 1442cdf0e10cSrcweir rVisualItem.mnEndGlyphPos = 0; 1443cdf0e10cSrcweir rVisualItem.mnXOffset = nXOffset; 1444cdf0e10cSrcweir //rVisualItem.mnPixelWidth = 0; 1445cdf0e10cSrcweir 1446cdf0e10cSrcweir // shortcut ignorable items 1447cdf0e10cSrcweir if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos) 1448cdf0e10cSrcweir || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) ) 1449cdf0e10cSrcweir { 1450cdf0e10cSrcweir for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i ) 1451cdf0e10cSrcweir mpLogClusters[i] = sal::static_int_cast<WORD>(~0U); 1452cdf0e10cSrcweir continue; 1453cdf0e10cSrcweir } 1454cdf0e10cSrcweir 1455cdf0e10cSrcweir // override bidi analysis if requested 1456cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG ) 1457cdf0e10cSrcweir { 1458cdf0e10cSrcweir // FIXME: is this intended ? 1459cdf0e10cSrcweir rVisualItem.mpScriptItem->a.fRTL = (aScriptState.uBidiLevel & 1); 1460cdf0e10cSrcweir rVisualItem.mpScriptItem->a.s.uBidiLevel = aScriptState.uBidiLevel; 1461cdf0e10cSrcweir rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection; 1462cdf0e10cSrcweir } 1463cdf0e10cSrcweir 1464cdf0e10cSrcweir // convert the unicodes to glyphs 1465cdf0e10cSrcweir int nGlyphCount = 0; 1466cdf0e10cSrcweir int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos; 1467cdf0e10cSrcweir HRESULT nRC = (*pScriptShape)( mhDC, &rScriptCache, 1468cdf0e10cSrcweir reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos), 1469cdf0e10cSrcweir nCharCount, 1470cdf0e10cSrcweir mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF 1471cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, 1472cdf0e10cSrcweir mpOutGlyphs + rVisualItem.mnMinGlyphPos, 1473cdf0e10cSrcweir mpLogClusters + rVisualItem.mnMinCharPos, 1474cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 1475cdf0e10cSrcweir &nGlyphCount ); 1476cdf0e10cSrcweir 1477cdf0e10cSrcweir // find and handle problems in the unicode to glyph conversion 1478cdf0e10cSrcweir if( nRC == USP_E_SCRIPT_NOT_IN_FONT ) 1479cdf0e10cSrcweir { 1480cdf0e10cSrcweir // the whole visual item needs a fallback, but make sure that the next 1481cdf0e10cSrcweir // fallback request is limited to the characters in the original request 1482cdf0e10cSrcweir // => this is handled in ImplLayoutArgs::PrepareFallback() 1483cdf0e10cSrcweir rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos, 1484cdf0e10cSrcweir rVisualItem.IsRTL() ); 1485cdf0e10cSrcweir 1486cdf0e10cSrcweir // don't bother to do a default layout in a fallback level 1487cdf0e10cSrcweir if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) ) 1488cdf0e10cSrcweir continue; 1489cdf0e10cSrcweir 1490cdf0e10cSrcweir // the primitive layout engine is good enough for the default layout 1491cdf0e10cSrcweir rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED; 1492cdf0e10cSrcweir nRC = (*pScriptShape)( mhDC, &rScriptCache, 1493cdf0e10cSrcweir reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos), 1494cdf0e10cSrcweir nCharCount, 1495cdf0e10cSrcweir mnGlyphCapacity - rVisualItem.mnMinGlyphPos, 1496cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, 1497cdf0e10cSrcweir mpOutGlyphs + rVisualItem.mnMinGlyphPos, 1498cdf0e10cSrcweir mpLogClusters + rVisualItem.mnMinCharPos, 1499cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 1500cdf0e10cSrcweir &nGlyphCount ); 1501cdf0e10cSrcweir 1502cdf0e10cSrcweir if( nRC != 0 ) 1503cdf0e10cSrcweir continue; 1504cdf0e10cSrcweir 1505cdf0e10cSrcweir #if 0 // keep the glyphs for now because they are better than nothing 1506cdf0e10cSrcweir // mark as NotDef glyphs 1507cdf0e10cSrcweir for( i = 0; i < nGlyphCount; ++i ) 1508cdf0e10cSrcweir mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 0; 1509cdf0e10cSrcweir #endif 1510cdf0e10cSrcweir } 1511cdf0e10cSrcweir else if( nRC != 0 ) 1512cdf0e10cSrcweir // something undefined happened => give up for this visual item 1513cdf0e10cSrcweir continue; 1514cdf0e10cSrcweir else // if( nRC == 0 ) 1515cdf0e10cSrcweir { 1516cdf0e10cSrcweir // check if there are any NotDef glyphs 1517cdf0e10cSrcweir for( i = 0; i < nGlyphCount; ++i ) 1518cdf0e10cSrcweir if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] ) 1519cdf0e10cSrcweir break; 1520cdf0e10cSrcweir if( i < nGlyphCount ) 1521cdf0e10cSrcweir { 1522cdf0e10cSrcweir // clip charpos limits to the layout string without context 1523cdf0e10cSrcweir int nMinCharPos = rVisualItem.mnMinCharPos; 1524cdf0e10cSrcweir if( nMinCharPos < rArgs.mnMinCharPos ) 1525cdf0e10cSrcweir nMinCharPos = rArgs.mnMinCharPos; 1526cdf0e10cSrcweir int nEndCharPos = rVisualItem.mnEndCharPos; 1527cdf0e10cSrcweir if( nEndCharPos > rArgs.mnEndCharPos ) 1528cdf0e10cSrcweir nEndCharPos = rArgs.mnEndCharPos; 1529cdf0e10cSrcweir // request fallback for individual NotDef glyphs 1530cdf0e10cSrcweir do 1531cdf0e10cSrcweir { 1532cdf0e10cSrcweir // ignore non-NotDef glyphs 1533cdf0e10cSrcweir if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] ) 1534cdf0e10cSrcweir continue; 1535cdf0e10cSrcweir mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH; 1536cdf0e10cSrcweir // request fallback for the whole cell that resulted in a NotDef glyph 1537cdf0e10cSrcweir // TODO: optimize algorithm 1538cdf0e10cSrcweir const bool bRTL = rVisualItem.IsRTL(); 1539cdf0e10cSrcweir if( !bRTL ) 1540cdf0e10cSrcweir { 1541cdf0e10cSrcweir // request fallback for the left-to-right cell 1542cdf0e10cSrcweir for( int c = nMinCharPos; c < nEndCharPos; ++c ) 1543cdf0e10cSrcweir { 1544cdf0e10cSrcweir if( mpLogClusters[ c ] == i ) 1545cdf0e10cSrcweir { 1546fed8d294SHerbert Dürr // #i55716# skip WORDJOINER 1547cdf0e10cSrcweir if( rArgs.mpStr[ c ] == 0x2060 ) 1548cdf0e10cSrcweir mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1; 1549cdf0e10cSrcweir else 1550cdf0e10cSrcweir rArgs.NeedFallback( c, false ); 1551cdf0e10cSrcweir } 1552cdf0e10cSrcweir } 1553cdf0e10cSrcweir } 1554cdf0e10cSrcweir else 1555cdf0e10cSrcweir { 1556cdf0e10cSrcweir // request fallback for the right to left cell 1557cdf0e10cSrcweir for( int c = nEndCharPos; --c >= nMinCharPos; ) 1558cdf0e10cSrcweir { 1559cdf0e10cSrcweir if( mpLogClusters[ c ] == i ) 1560cdf0e10cSrcweir { 1561fed8d294SHerbert Dürr // #i55716# skip WORDJOINER 1562cdf0e10cSrcweir if( rArgs.mpStr[ c ] == 0x2060 ) 1563cdf0e10cSrcweir mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1; 1564cdf0e10cSrcweir else 1565cdf0e10cSrcweir rArgs.NeedFallback( c, true ); 1566cdf0e10cSrcweir } 1567cdf0e10cSrcweir } 1568cdf0e10cSrcweir } 1569cdf0e10cSrcweir } while( ++i < nGlyphCount ); 1570cdf0e10cSrcweir } 1571cdf0e10cSrcweir } 1572cdf0e10cSrcweir 1573cdf0e10cSrcweir // now place the glyphs 1574cdf0e10cSrcweir nRC = (*pScriptPlace)( mhDC, &rScriptCache, 1575cdf0e10cSrcweir mpOutGlyphs + rVisualItem.mnMinGlyphPos, 1576cdf0e10cSrcweir nGlyphCount, 1577cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 1578cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, 1579cdf0e10cSrcweir mpGlyphAdvances + rVisualItem.mnMinGlyphPos, 1580cdf0e10cSrcweir mpGlyphOffsets + rVisualItem.mnMinGlyphPos, 1581cdf0e10cSrcweir &rVisualItem.maABCWidths ); 1582cdf0e10cSrcweir 1583cdf0e10cSrcweir if( nRC != 0 ) 1584cdf0e10cSrcweir continue; 1585cdf0e10cSrcweir 1586cdf0e10cSrcweir // calculate the logical char widths from the glyph layout 1587cdf0e10cSrcweir nRC = (*pScriptGetLogicalWidths)( 1588cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, 1589cdf0e10cSrcweir nCharCount, nGlyphCount, 1590cdf0e10cSrcweir mpGlyphAdvances + rVisualItem.mnMinGlyphPos, 1591cdf0e10cSrcweir mpLogClusters + rVisualItem.mnMinCharPos, 1592cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 1593cdf0e10cSrcweir mpCharWidths + rVisualItem.mnMinCharPos ); 1594cdf0e10cSrcweir 1595cdf0e10cSrcweir // update the glyph counters 1596cdf0e10cSrcweir mnGlyphCount += nGlyphCount; 1597cdf0e10cSrcweir rVisualItem.mnEndGlyphPos = mnGlyphCount; 1598cdf0e10cSrcweir 1599cdf0e10cSrcweir // update nXOffset 1600cdf0e10cSrcweir int nEndGlyphPos; 1601cdf0e10cSrcweir if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) ) 1602cdf0e10cSrcweir for(; i < nEndGlyphPos; ++i ) 1603cdf0e10cSrcweir nXOffset += mpGlyphAdvances[ i ]; 1604cdf0e10cSrcweir 1605cdf0e10cSrcweir // TODO: shrink glyphpos limits to match charpos/fallback limits 1606cdf0e10cSrcweir //pVI->mnMinGlyphPos = nMinGlyphPos; 1607cdf0e10cSrcweir //pVI->mnEndGlyphPos = nEndGlyphPos; 1608cdf0e10cSrcweir 1609cdf0e10cSrcweir // drop the superfluous context glyphs 1610cdf0e10cSrcweir TIntVector::const_iterator it = aDropChars.begin(); 1611cdf0e10cSrcweir while( it != aDropChars.end() ) 1612cdf0e10cSrcweir { 1613cdf0e10cSrcweir // find matching "drop range" 1614cdf0e10cSrcweir int nMinDropPos = *(it++); // begin of drop range 1615cdf0e10cSrcweir if( nMinDropPos >= rVisualItem.mnEndCharPos ) 1616cdf0e10cSrcweir break; 1617cdf0e10cSrcweir int nEndDropPos = *(it++); // end of drop range 1618cdf0e10cSrcweir if( nEndDropPos <= rVisualItem.mnMinCharPos ) 1619cdf0e10cSrcweir continue; 1620cdf0e10cSrcweir // clip "drop range" to visual item's char range 1621cdf0e10cSrcweir if( nMinDropPos <= rVisualItem.mnMinCharPos ) 1622cdf0e10cSrcweir { 1623cdf0e10cSrcweir nMinDropPos = rVisualItem.mnMinCharPos; 1624cdf0e10cSrcweir // drop the whole visual item if possible 1625cdf0e10cSrcweir if( nEndDropPos >= rVisualItem.mnEndCharPos ) 1626cdf0e10cSrcweir { 1627cdf0e10cSrcweir rVisualItem.mnEndGlyphPos = 0; 1628cdf0e10cSrcweir break; 1629cdf0e10cSrcweir } 1630cdf0e10cSrcweir } 1631cdf0e10cSrcweir if( nEndDropPos > rVisualItem.mnEndCharPos ) 1632cdf0e10cSrcweir nEndDropPos = rVisualItem.mnEndCharPos; 1633cdf0e10cSrcweir 1634cdf0e10cSrcweir // drop the glyphs which correspond to the charpos range 1635cdf0e10cSrcweir // drop the corresponding glyphs in the cluster 1636cdf0e10cSrcweir for( int c = nMinDropPos; c < nEndDropPos; ++c ) 1637cdf0e10cSrcweir { 1638cdf0e10cSrcweir int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos; 1639cdf0e10cSrcweir // no need to bother when the cluster was already dropped 1640cdf0e10cSrcweir if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH ) 1641cdf0e10cSrcweir { 1642cdf0e10cSrcweir for(;;) 1643cdf0e10cSrcweir { 1644cdf0e10cSrcweir mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH; 1645cdf0e10cSrcweir // until the end of visual item 1646cdf0e10cSrcweir if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos ) 1647cdf0e10cSrcweir break; 1648cdf0e10cSrcweir // until the next cluster start 1649cdf0e10cSrcweir if( mpVisualAttrs[ nGlyphPos ].fClusterStart ) 1650cdf0e10cSrcweir break; 1651cdf0e10cSrcweir } 1652cdf0e10cSrcweir } 1653cdf0e10cSrcweir } 1654cdf0e10cSrcweir } 1655cdf0e10cSrcweir } 1656cdf0e10cSrcweir 1657cdf0e10cSrcweir // scale layout metrics if needed 1658cdf0e10cSrcweir // TODO: does it make the code more simple if the metric scaling 1659cdf0e10cSrcweir // is moved to the methods that need metric scaling (e.g. FillDXArray())? 1660cdf0e10cSrcweir if( mfFontScale != 1.0 ) 1661cdf0e10cSrcweir { 1662cdf0e10cSrcweir mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale); 1663cdf0e10cSrcweir 1664cdf0e10cSrcweir for( i = 0; i < mnItemCount; ++i ) 1665cdf0e10cSrcweir mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale); 1666cdf0e10cSrcweir 1667cdf0e10cSrcweir mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale); 1668cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 1669cdf0e10cSrcweir { 1670cdf0e10cSrcweir mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale); 1671cdf0e10cSrcweir mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale); 1672cdf0e10cSrcweir mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale); 1673cdf0e10cSrcweir // mpJustifications are still NULL 1674cdf0e10cSrcweir } 1675cdf0e10cSrcweir 1676cdf0e10cSrcweir for( i = mnSubStringMin; i < nSubStringEnd; ++i ) 1677cdf0e10cSrcweir mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale); 1678cdf0e10cSrcweir } 1679cdf0e10cSrcweir 1680cdf0e10cSrcweir return true; 1681cdf0e10cSrcweir } 1682cdf0e10cSrcweir 1683cdf0e10cSrcweir // ----------------------------------------------------------------------- 1684cdf0e10cSrcweir 1685cdf0e10cSrcweir // calculate the range of relevant glyphs for this visual item 1686cdf0e10cSrcweir bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem, 1687cdf0e10cSrcweir int& rMinGlyphPos, int& rEndGlyphPos ) const 1688cdf0e10cSrcweir { 1689cdf0e10cSrcweir // return early when nothing of interest in this item 1690cdf0e10cSrcweir if( rVisualItem.IsEmpty() 1691cdf0e10cSrcweir || (rVisualItem.mnEndCharPos <= mnMinCharPos) 1692cdf0e10cSrcweir || (mnEndCharPos <= rVisualItem.mnMinCharPos) ) 1693cdf0e10cSrcweir return false; 1694cdf0e10cSrcweir 1695cdf0e10cSrcweir // default: subrange is complete range 1696cdf0e10cSrcweir rMinGlyphPos = rVisualItem.mnMinGlyphPos; 1697cdf0e10cSrcweir rEndGlyphPos = rVisualItem.mnEndGlyphPos; 1698cdf0e10cSrcweir 1699cdf0e10cSrcweir // return early when the whole item is of interest 1700cdf0e10cSrcweir if( (mnMinCharPos <= rVisualItem.mnMinCharPos) 1701cdf0e10cSrcweir && (rVisualItem.mnEndCharPos <= mnEndCharPos ) ) 1702cdf0e10cSrcweir return true; 1703cdf0e10cSrcweir 1704cdf0e10cSrcweir // get glyph range from char range by looking at cluster boundries 1705cdf0e10cSrcweir // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes 1706cdf0e10cSrcweir rMinGlyphPos = rVisualItem.mnEndGlyphPos; 1707cdf0e10cSrcweir int nMaxGlyphPos = 0; 1708cdf0e10cSrcweir 1709cdf0e10cSrcweir int i = mnMinCharPos; 1710cdf0e10cSrcweir if( i < rVisualItem.mnMinCharPos ) 1711cdf0e10cSrcweir i = rVisualItem.mnMinCharPos; 1712cdf0e10cSrcweir int nCharPosLimit = rVisualItem.mnEndCharPos; 1713cdf0e10cSrcweir if( nCharPosLimit > mnEndCharPos ) 1714cdf0e10cSrcweir nCharPosLimit = mnEndCharPos; 1715cdf0e10cSrcweir for(; i < nCharPosLimit; ++i ) 1716cdf0e10cSrcweir { 1717cdf0e10cSrcweir int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos; 1718cdf0e10cSrcweir if( rMinGlyphPos > n ) 1719cdf0e10cSrcweir rMinGlyphPos = n; 1720cdf0e10cSrcweir if( nMaxGlyphPos < n ) 1721cdf0e10cSrcweir nMaxGlyphPos = n; 1722cdf0e10cSrcweir } 1723cdf0e10cSrcweir if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos) 1724cdf0e10cSrcweir nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1; 1725cdf0e10cSrcweir 1726cdf0e10cSrcweir // extend the glyph range to account for all glyphs in referenced clusters 1727cdf0e10cSrcweir if( !rVisualItem.IsRTL() ) // LTR-item 1728cdf0e10cSrcweir { 1729cdf0e10cSrcweir // extend to rightmost glyph of rightmost referenced cluster 1730cdf0e10cSrcweir for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i ) 1731cdf0e10cSrcweir if( mpVisualAttrs[i].fClusterStart ) 1732cdf0e10cSrcweir break; 1733cdf0e10cSrcweir } 1734cdf0e10cSrcweir else // RTL-item 1735cdf0e10cSrcweir { 1736cdf0e10cSrcweir // extend to leftmost glyph of leftmost referenced cluster 1737cdf0e10cSrcweir for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i ) 1738cdf0e10cSrcweir if( mpVisualAttrs[i].fClusterStart ) 1739cdf0e10cSrcweir break; 1740cdf0e10cSrcweir } 1741cdf0e10cSrcweir rEndGlyphPos = nMaxGlyphPos + 1; 1742cdf0e10cSrcweir 1743cdf0e10cSrcweir return true; 1744cdf0e10cSrcweir } 1745cdf0e10cSrcweir 1746cdf0e10cSrcweir // ----------------------------------------------------------------------- 1747cdf0e10cSrcweir 1748cdf0e10cSrcweir int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, 1749cdf0e10cSrcweir int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const 1750cdf0e10cSrcweir { 1751cdf0e10cSrcweir // HACK to allow fake-glyph insertion (e.g. for kashidas) 1752cdf0e10cSrcweir // TODO: use iterator idiom instead of GetNextGlyphs(...) 1753cdf0e10cSrcweir // TODO: else make sure that the limit for glyph injection is sufficient (currently 256) 1754cdf0e10cSrcweir int nSubIter = nStartx8 & 0xff; 1755cdf0e10cSrcweir int nStart = nStartx8 >> 8; 1756cdf0e10cSrcweir 1757cdf0e10cSrcweir // check the glyph iterator 1758cdf0e10cSrcweir if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs 1759cdf0e10cSrcweir return 0; 1760cdf0e10cSrcweir 1761cdf0e10cSrcweir // find the visual item for the nStart glyph position 1762cdf0e10cSrcweir int nItem = 0; 1763cdf0e10cSrcweir const VisualItem* pVI = mpVisualItems; 1764cdf0e10cSrcweir if( nStart <= 0 ) // nStart<=0 requests the first visible glyph 1765cdf0e10cSrcweir { 1766cdf0e10cSrcweir // find first visible item 1767cdf0e10cSrcweir for(; nItem < mnItemCount; ++nItem, ++pVI ) 1768cdf0e10cSrcweir if( !pVI->IsEmpty() ) 1769cdf0e10cSrcweir break; 1770cdf0e10cSrcweir // it is possible that there are glyphs but no valid visual item 1771cdf0e10cSrcweir // TODO: get rid of these visual items more early 1772cdf0e10cSrcweir if( nItem < mnItemCount ) 1773cdf0e10cSrcweir nStart = pVI->mnMinGlyphPos; 1774cdf0e10cSrcweir } 1775cdf0e10cSrcweir else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1 1776cdf0e10cSrcweir { 1777cdf0e10cSrcweir --nStart; 1778cdf0e10cSrcweir 1779cdf0e10cSrcweir // find matching item 1780cdf0e10cSrcweir for(; nItem < mnItemCount; ++nItem, ++pVI ) 1781cdf0e10cSrcweir if( (nStart >= pVI->mnMinGlyphPos) 1782cdf0e10cSrcweir && (nStart < pVI->mnEndGlyphPos) ) 1783cdf0e10cSrcweir break; 1784cdf0e10cSrcweir } 1785cdf0e10cSrcweir 1786cdf0e10cSrcweir // after the last visual item there are no more glyphs 1787cdf0e10cSrcweir if( (nItem >= mnItemCount) || (nStart < 0) ) 1788cdf0e10cSrcweir { 1789cdf0e10cSrcweir nStartx8 = (mnGlyphCount + 1) << 8; 1790cdf0e10cSrcweir return 0; 1791cdf0e10cSrcweir } 1792cdf0e10cSrcweir 1793cdf0e10cSrcweir // calculate the first glyph in the next visual item 1794cdf0e10cSrcweir int nNextItemStart = mnGlyphCount; 1795cdf0e10cSrcweir while( ++nItem < mnItemCount ) 1796cdf0e10cSrcweir { 1797cdf0e10cSrcweir if( mpVisualItems[nItem].IsEmpty() ) 1798cdf0e10cSrcweir continue; 1799cdf0e10cSrcweir nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos; 1800cdf0e10cSrcweir break; 1801cdf0e10cSrcweir } 1802cdf0e10cSrcweir 1803cdf0e10cSrcweir // get the range of relevant glyphs in this visual item 1804cdf0e10cSrcweir int nMinGlyphPos, nEndGlyphPos; 1805cdf0e10cSrcweir bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ); 1806cdf0e10cSrcweir DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" ); 1807cdf0e10cSrcweir if( !bRC ) 1808cdf0e10cSrcweir { 1809cdf0e10cSrcweir nStartx8 = (mnGlyphCount + 1) << 8; 1810cdf0e10cSrcweir return 0; 1811cdf0e10cSrcweir } 1812cdf0e10cSrcweir 1813cdf0e10cSrcweir // make sure nStart is inside the range of relevant glyphs 1814cdf0e10cSrcweir if( nStart < nMinGlyphPos ) 1815cdf0e10cSrcweir nStart = nMinGlyphPos; 1816cdf0e10cSrcweir 1817cdf0e10cSrcweir // calculate the start glyph xoffset relative to layout's base position, 1818cdf0e10cSrcweir // advance to next visual glyph position by using adjusted glyph widths 1819cdf0e10cSrcweir // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache 1820cdf0e10cSrcweir long nXOffset = pVI->mnXOffset; 1821cdf0e10cSrcweir const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances; 1822cdf0e10cSrcweir for( int i = nMinGlyphPos; i < nStart; ++i ) 1823cdf0e10cSrcweir nXOffset += pGlyphWidths[ i ]; 1824cdf0e10cSrcweir 1825cdf0e10cSrcweir // adjust the nXOffset relative to glyph cluster start 1826cdf0e10cSrcweir int c = mnMinCharPos; 1827cdf0e10cSrcweir if( !pVI->IsRTL() ) // LTR-case 1828cdf0e10cSrcweir { 1829cdf0e10cSrcweir // LTR case: subtract the remainder of the cell from xoffset 1830cdf0e10cSrcweir int nTmpIndex = mpLogClusters[c]; 1831cdf0e10cSrcweir while( (--c >= pVI->mnMinCharPos) 1832cdf0e10cSrcweir && (nTmpIndex == mpLogClusters[c]) ) 1833cdf0e10cSrcweir nXOffset -= mpCharWidths[c]; 1834cdf0e10cSrcweir } 1835cdf0e10cSrcweir else // RTL-case 1836cdf0e10cSrcweir { 1837cdf0e10cSrcweir // RTL case: add the remainder of the cell from xoffset 1838cdf0e10cSrcweir int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ]; 1839cdf0e10cSrcweir while( (--c >= pVI->mnMinCharPos) 1840cdf0e10cSrcweir && (nTmpIndex == mpLogClusters[c]) ) 1841cdf0e10cSrcweir nXOffset += mpCharWidths[c]; 1842cdf0e10cSrcweir 1843cdf0e10cSrcweir // adjust the xoffset if justified glyphs are not positioned at their justified positions yet 1844cdf0e10cSrcweir if( mpJustifications && !bManualCellAlign ) 1845cdf0e10cSrcweir nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ]; 1846cdf0e10cSrcweir } 1847cdf0e10cSrcweir 18488ff75a7eSHerbert Dürr // create mpGlyphs2Chars[] if it is needed later 18498ff75a7eSHerbert Dürr if( pCharPosAry && !mpGlyphs2Chars ) 18508ff75a7eSHerbert Dürr { 18518ff75a7eSHerbert Dürr // create and reset the new array 18528ff75a7eSHerbert Dürr mpGlyphs2Chars = new int[ mnGlyphCapacity ]; 18538ff75a7eSHerbert Dürr static const int CHARPOS_NONE = -1; 18548ff75a7eSHerbert Dürr for( int i = 0; i < mnGlyphCount; ++i ) 18558ff75a7eSHerbert Dürr mpGlyphs2Chars[i] = CHARPOS_NONE; 18568ff75a7eSHerbert Dürr // calculate the char->glyph mapping 18578ff75a7eSHerbert Dürr for( nItem = 0; nItem < mnItemCount; ++nItem ) 18588ff75a7eSHerbert Dürr { 18598ff75a7eSHerbert Dürr // ignore invisible visual items 18608ff75a7eSHerbert Dürr const VisualItem& rVI = mpVisualItems[ nItem ]; 18618ff75a7eSHerbert Dürr if( rVI.IsEmpty() ) 18628ff75a7eSHerbert Dürr continue; 18638ff75a7eSHerbert Dürr // calculate the mapping by using mpLogClusters[] 18648ff75a7eSHerbert Dürr // mpGlyphs2Chars[] should obey the logical order 18658ff75a7eSHerbert Dürr // => reversing the loop does this by overwriting higher logicals 18668ff75a7eSHerbert Dürr for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; ) 18678ff75a7eSHerbert Dürr { 18688ff75a7eSHerbert Dürr int i = mpLogClusters[c] + rVI.mnMinGlyphPos; 18698ff75a7eSHerbert Dürr mpGlyphs2Chars[i] = c; 18708ff75a7eSHerbert Dürr } 18718ff75a7eSHerbert Dürr // use a heuristic to fill the gaps in the glyphs2chars array 18728ff75a7eSHerbert Dürr c = !rVI.IsRTL() ? rVI.mnMinCharPos : rVI.mnEndCharPos - 1; 18738ff75a7eSHerbert Dürr for( int i = rVI.mnMinGlyphPos; i < rVI.mnEndGlyphPos; ++i ) { 18748ff75a7eSHerbert Dürr if( mpGlyphs2Chars[i] == CHARPOS_NONE ) 18758ff75a7eSHerbert Dürr mpGlyphs2Chars[i] = c; 18768ff75a7eSHerbert Dürr else 18778ff75a7eSHerbert Dürr c = mpGlyphs2Chars[i]; 18788ff75a7eSHerbert Dürr } 18798ff75a7eSHerbert Dürr } 18808ff75a7eSHerbert Dürr } 1881cdf0e10cSrcweir 1882cdf0e10cSrcweir // calculate the absolute position of the first result glyph in pixel units 1883cdf0e10cSrcweir const GOFFSET aGOffset = mpGlyphOffsets[ nStart ]; 1884cdf0e10cSrcweir Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv ); 1885cdf0e10cSrcweir rPos = GetDrawPosition( aRelativePos ); 1886cdf0e10cSrcweir 1887cdf0e10cSrcweir // fill the result arrays 1888cdf0e10cSrcweir int nCount = 0; 1889cdf0e10cSrcweir while( nCount < nLen ) 1890cdf0e10cSrcweir { 1891cdf0e10cSrcweir // prepare return values 1892cdf0e10cSrcweir sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ]; 1893cdf0e10cSrcweir int nGlyphWidth = pGlyphWidths[ nStart ]; 1894cdf0e10cSrcweir int nCharPos = -1; // no need to determine charpos 1895cdf0e10cSrcweir if( mpGlyphs2Chars ) // unless explicitly requested+provided 1896cdf0e10cSrcweir nCharPos = mpGlyphs2Chars[ nStart ]; 1897cdf0e10cSrcweir 1898cdf0e10cSrcweir // inject kashida glyphs if needed 1899cdf0e10cSrcweir if( !mbDisableGlyphInjection 1900cdf0e10cSrcweir && mpJustifications 1901cdf0e10cSrcweir && mnMinKashidaWidth 1902cdf0e10cSrcweir && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL ) 1903cdf0e10cSrcweir { 1904cdf0e10cSrcweir // prepare draw position adjustment 1905cdf0e10cSrcweir int nExtraOfs = (nSubIter++) * mnMinKashidaWidth; 1906cdf0e10cSrcweir // calculate space available for the injected glyphs 1907cdf0e10cSrcweir nGlyphWidth = mpGlyphAdvances[ nStart ]; 1908cdf0e10cSrcweir const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth; 1909cdf0e10cSrcweir const int nToFillWidth = nExtraWidth - nExtraOfs; 1910cdf0e10cSrcweir if( (4*nToFillWidth >= mnMinKashidaWidth) // prevent glyph-injection if there is no room 1911cdf0e10cSrcweir || ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others 1912cdf0e10cSrcweir { 1913cdf0e10cSrcweir // handle if there is not sufficient room for a full glyph 1914cdf0e10cSrcweir if( nToFillWidth < mnMinKashidaWidth ) 1915cdf0e10cSrcweir { 1916cdf0e10cSrcweir // overlap it with the previously injected glyph if possible 1917cdf0e10cSrcweir int nOverlap = mnMinKashidaWidth - nToFillWidth; 1918cdf0e10cSrcweir // else overlap it with both neighboring glyphs 1919cdf0e10cSrcweir if( nSubIter <= 1 ) 1920cdf0e10cSrcweir nOverlap /= 2; 1921cdf0e10cSrcweir nExtraOfs -= nOverlap; 1922cdf0e10cSrcweir } 1923cdf0e10cSrcweir nGlyphWidth = mnMinKashidaWidth; 1924cdf0e10cSrcweir aGlyphId = mnMinKashidaGlyph; 1925cdf0e10cSrcweir nCharPos = -1; 1926cdf0e10cSrcweir } 1927cdf0e10cSrcweir else 1928cdf0e10cSrcweir { 1929cdf0e10cSrcweir nExtraOfs += nToFillWidth; // at right of cell 1930cdf0e10cSrcweir nSubIter = 0; // done with glyph injection 1931cdf0e10cSrcweir } 1932cdf0e10cSrcweir if( !bManualCellAlign ) 1933cdf0e10cSrcweir nExtraOfs -= nExtraWidth; // adjust for right-aligned cells 1934cdf0e10cSrcweir 1935cdf0e10cSrcweir // adjust the draw position for the injected-glyphs case 1936cdf0e10cSrcweir if( nExtraOfs ) 1937cdf0e10cSrcweir { 1938cdf0e10cSrcweir aRelativePos.X() += nExtraOfs; 1939cdf0e10cSrcweir rPos = GetDrawPosition( aRelativePos ); 1940cdf0e10cSrcweir } 1941cdf0e10cSrcweir } 1942cdf0e10cSrcweir 1943cdf0e10cSrcweir // update return values 1944cdf0e10cSrcweir *(pGlyphs++) = aGlyphId; 1945cdf0e10cSrcweir if( pGlyphAdvances ) 1946cdf0e10cSrcweir *(pGlyphAdvances++) = nGlyphWidth; 1947cdf0e10cSrcweir if( pCharPosAry ) 1948cdf0e10cSrcweir *(pCharPosAry++) = nCharPos; 1949cdf0e10cSrcweir 1950cdf0e10cSrcweir // increment counter of returned glyphs 1951cdf0e10cSrcweir ++nCount; 1952cdf0e10cSrcweir 1953cdf0e10cSrcweir // reduce code complexity by returning early in glyph-injection case 1954cdf0e10cSrcweir if( nSubIter != 0 ) 1955cdf0e10cSrcweir break; 1956cdf0e10cSrcweir 1957cdf0e10cSrcweir // stop after the last visible glyph in this visual item 1958cdf0e10cSrcweir if( ++nStart >= nEndGlyphPos ) 1959cdf0e10cSrcweir { 1960cdf0e10cSrcweir nStart = nNextItemStart; 1961cdf0e10cSrcweir break; 1962cdf0e10cSrcweir } 1963cdf0e10cSrcweir 1964cdf0e10cSrcweir // RTL-justified glyph positioning is not easy 1965cdf0e10cSrcweir // simplify the code by just returning only one glyph at a time 1966cdf0e10cSrcweir if( mpJustifications && pVI->IsRTL() ) 1967cdf0e10cSrcweir break; 1968cdf0e10cSrcweir 1969cdf0e10cSrcweir // stop when the x-position of the next glyph is unexpected 1970cdf0e10cSrcweir if( !pGlyphAdvances ) 1971cdf0e10cSrcweir if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) ) 1972cdf0e10cSrcweir || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) ) 1973cdf0e10cSrcweir break; 1974cdf0e10cSrcweir 1975cdf0e10cSrcweir // stop when the y-position of the next glyph is unexpected 1976cdf0e10cSrcweir if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) ) 1977cdf0e10cSrcweir break; 1978cdf0e10cSrcweir } 1979cdf0e10cSrcweir 1980cdf0e10cSrcweir ++nStart; 1981cdf0e10cSrcweir nStartx8 = (nStart << 8) + nSubIter; 1982cdf0e10cSrcweir return nCount; 1983cdf0e10cSrcweir } 1984cdf0e10cSrcweir 1985cdf0e10cSrcweir // ----------------------------------------------------------------------- 1986cdf0e10cSrcweir 1987cdf0e10cSrcweir void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos ) 1988cdf0e10cSrcweir { 1989cdf0e10cSrcweir DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" ); 1990cdf0e10cSrcweir int nStart = nStartx8 >> 8; 1991cdf0e10cSrcweir if( nStart > mnGlyphCount ) 1992cdf0e10cSrcweir return; 1993cdf0e10cSrcweir 1994cdf0e10cSrcweir VisualItem* pVI = mpVisualItems; 1995cdf0e10cSrcweir int nMinGlyphPos = 0, nEndGlyphPos; 1996cdf0e10cSrcweir if( nStart == 0 ) // nStart==0 for first visible glyph 1997cdf0e10cSrcweir { 1998cdf0e10cSrcweir for( int i = mnItemCount; --i >= 0; ++pVI ) 1999cdf0e10cSrcweir if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) ) 2000cdf0e10cSrcweir break; 2001cdf0e10cSrcweir nStart = nMinGlyphPos; 2002cdf0e10cSrcweir DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" ); 2003cdf0e10cSrcweir } 2004cdf0e10cSrcweir else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1 2005cdf0e10cSrcweir { 2006cdf0e10cSrcweir --nStart; 2007cdf0e10cSrcweir for( int i = mnItemCount; --i >= 0; ++pVI ) 2008cdf0e10cSrcweir if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) ) 2009cdf0e10cSrcweir break; 2010cdf0e10cSrcweir bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ); 2011cdf0e10cSrcweir (void)bRC; // avoid var-not-used warning 2012cdf0e10cSrcweir DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" ); 2013cdf0e10cSrcweir } 2014cdf0e10cSrcweir 2015cdf0e10cSrcweir long nDelta = nNewXPos - pVI->mnXOffset; 2016cdf0e10cSrcweir if( nStart > nMinGlyphPos ) 2017cdf0e10cSrcweir { 2018cdf0e10cSrcweir // move the glyph by expanding its left glyph but ignore dropped glyphs 2019cdf0e10cSrcweir int i, nLastUndropped = nMinGlyphPos - 1; 2020cdf0e10cSrcweir for( i = nMinGlyphPos; i < nStart; ++i ) 2021cdf0e10cSrcweir { 2022cdf0e10cSrcweir if (mpOutGlyphs[i] != DROPPED_OUTGLYPH) 2023cdf0e10cSrcweir { 2024cdf0e10cSrcweir nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ]; 2025cdf0e10cSrcweir nLastUndropped = i; 2026cdf0e10cSrcweir } 2027cdf0e10cSrcweir } 2028cdf0e10cSrcweir if (nLastUndropped >= nMinGlyphPos) 2029cdf0e10cSrcweir { 2030cdf0e10cSrcweir mpGlyphAdvances[ nLastUndropped ] += nDelta; 2031cdf0e10cSrcweir if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta; 2032cdf0e10cSrcweir } 2033cdf0e10cSrcweir else 2034cdf0e10cSrcweir { 2035cdf0e10cSrcweir pVI->mnXOffset += nDelta; 2036cdf0e10cSrcweir } 2037cdf0e10cSrcweir } 2038cdf0e10cSrcweir else 2039cdf0e10cSrcweir { 2040cdf0e10cSrcweir // move the visual item by having an offset 2041cdf0e10cSrcweir pVI->mnXOffset += nDelta; 2042cdf0e10cSrcweir } 2043cdf0e10cSrcweir // move subsequent items - this often isn't necessary because subsequent 2044cdf0e10cSrcweir // moves will correct subsequent items. However, if there is a contiguous 2045cdf0e10cSrcweir // range not involving fallback which spans items, this will be needed 2046cdf0e10cSrcweir while (++pVI - mpVisualItems < mnItemCount) 2047cdf0e10cSrcweir { 2048cdf0e10cSrcweir pVI->mnXOffset += nDelta; 2049cdf0e10cSrcweir } 2050cdf0e10cSrcweir } 2051cdf0e10cSrcweir 2052cdf0e10cSrcweir // ----------------------------------------------------------------------- 2053cdf0e10cSrcweir 2054cdf0e10cSrcweir void UniscribeLayout::DropGlyph( int nStartx8 ) 2055cdf0e10cSrcweir { 2056cdf0e10cSrcweir DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" ); 2057cdf0e10cSrcweir int nStart = nStartx8 >> 8; 2058cdf0e10cSrcweir DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" ); 2059cdf0e10cSrcweir 2060cdf0e10cSrcweir if( nStart > 0 ) // nStart>0 means absolute glyph pos + 1 2061cdf0e10cSrcweir --nStart; 2062cdf0e10cSrcweir else // nStart<=0 for first visible glyph 2063cdf0e10cSrcweir { 2064cdf0e10cSrcweir VisualItem* pVI = mpVisualItems; 2065cdf0e10cSrcweir for( int i = mnItemCount, nDummy; --i >= 0; ++pVI ) 2066cdf0e10cSrcweir if( GetItemSubrange( *pVI, nStart, nDummy ) ) 2067cdf0e10cSrcweir break; 2068cdf0e10cSrcweir DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" ); 2069cdf0e10cSrcweir int nOffset = 0; 2070cdf0e10cSrcweir int j = pVI->mnMinGlyphPos; 2071cdf0e10cSrcweir while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++; 2072cdf0e10cSrcweir if (j == nStart) 2073cdf0e10cSrcweir { 2074cdf0e10cSrcweir pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]); 2075cdf0e10cSrcweir } 2076cdf0e10cSrcweir } 2077cdf0e10cSrcweir 2078cdf0e10cSrcweir mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH; 2079cdf0e10cSrcweir } 2080cdf0e10cSrcweir 2081cdf0e10cSrcweir // ----------------------------------------------------------------------- 2082cdf0e10cSrcweir 2083cdf0e10cSrcweir void UniscribeLayout::Simplify( bool /*bIsBase*/ ) 2084cdf0e10cSrcweir { 2085cdf0e10cSrcweir static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH; 2086cdf0e10cSrcweir int i; 2087cdf0e10cSrcweir // if there are no dropped glyphs don't bother 2088cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 2089cdf0e10cSrcweir if( mpOutGlyphs[ i ] == cDroppedGlyph ) 2090cdf0e10cSrcweir break; 2091cdf0e10cSrcweir if( i >= mnGlyphCount ) 2092cdf0e10cSrcweir return; 2093cdf0e10cSrcweir 2094cdf0e10cSrcweir // prepare for sparse layout 2095cdf0e10cSrcweir // => make sure mpGlyphs2Chars[] exists 2096cdf0e10cSrcweir if( !mpGlyphs2Chars ) 2097cdf0e10cSrcweir { 2098cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnGlyphCapacity ]; 2099cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 2100cdf0e10cSrcweir mpGlyphs2Chars[ i ] = -1; 2101cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2102cdf0e10cSrcweir { 2103cdf0e10cSrcweir // skip invisible items 2104cdf0e10cSrcweir VisualItem& rVI = mpVisualItems[ nItem ]; 2105cdf0e10cSrcweir if( rVI.IsEmpty() ) 2106cdf0e10cSrcweir continue; 2107cdf0e10cSrcweir for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; ) 2108cdf0e10cSrcweir { 2109cdf0e10cSrcweir int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos; 2110cdf0e10cSrcweir mpGlyphs2Chars[ j ] = i; 2111cdf0e10cSrcweir } 2112cdf0e10cSrcweir } 2113cdf0e10cSrcweir } 2114cdf0e10cSrcweir 2115cdf0e10cSrcweir // remove the dropped glyphs 2116cdf0e10cSrcweir const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances; 2117cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2118cdf0e10cSrcweir { 2119cdf0e10cSrcweir VisualItem& rVI = mpVisualItems[ nItem ]; 2120cdf0e10cSrcweir if( rVI.IsEmpty() ) 2121cdf0e10cSrcweir continue; 2122cdf0e10cSrcweir 2123cdf0e10cSrcweir // mark replaced character widths 2124cdf0e10cSrcweir for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i ) 2125cdf0e10cSrcweir { 2126cdf0e10cSrcweir int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos; 2127cdf0e10cSrcweir if( mpOutGlyphs[ j ] == cDroppedGlyph ) 2128cdf0e10cSrcweir mpCharWidths[ i ] = 0; 2129cdf0e10cSrcweir } 2130cdf0e10cSrcweir 2131cdf0e10cSrcweir // handle dropped glyphs at start of visual item 2132cdf0e10cSrcweir int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos; 2133cdf0e10cSrcweir GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ); 2134cdf0e10cSrcweir i = nMinGlyphPos; 2135cdf0e10cSrcweir while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) ) 2136cdf0e10cSrcweir { 2137cdf0e10cSrcweir //rVI.mnXOffset += pGlyphWidths[ i ]; 2138cdf0e10cSrcweir rVI.mnMinGlyphPos = ++i; 2139cdf0e10cSrcweir } 2140cdf0e10cSrcweir 2141cdf0e10cSrcweir // when all glyphs in item got dropped mark it as empty 2142cdf0e10cSrcweir if( i >= nEndGlyphPos ) 2143cdf0e10cSrcweir { 2144cdf0e10cSrcweir rVI.mnEndGlyphPos = 0; 2145cdf0e10cSrcweir continue; 2146cdf0e10cSrcweir } 2147cdf0e10cSrcweir // If there are still glyphs in the cluster and mnMinGlyphPos 2148cdf0e10cSrcweir // has changed then we need to remove the dropped glyphs at start 2149cdf0e10cSrcweir // to correct logClusters, which is unsigned and relative to the 2150cdf0e10cSrcweir // item start. 2151cdf0e10cSrcweir if (rVI.mnMinGlyphPos != nOrigMinGlyphPos) 2152cdf0e10cSrcweir { 2153cdf0e10cSrcweir // drop any glyphs in the visual item outside the range 2154cdf0e10cSrcweir for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++) 2155cdf0e10cSrcweir mpOutGlyphs[ i ] = cDroppedGlyph; 2156cdf0e10cSrcweir rVI.mnMinGlyphPos = i = nOrigMinGlyphPos; 2157cdf0e10cSrcweir } 2158cdf0e10cSrcweir 2159cdf0e10cSrcweir // handle dropped glyphs in the middle of visual item 2160cdf0e10cSrcweir for(; i < nEndGlyphPos; ++i ) 2161cdf0e10cSrcweir if( mpOutGlyphs[ i ] == cDroppedGlyph ) 2162cdf0e10cSrcweir break; 2163cdf0e10cSrcweir int j = i; 2164cdf0e10cSrcweir while( ++i < nEndGlyphPos ) 2165cdf0e10cSrcweir { 2166cdf0e10cSrcweir if( mpOutGlyphs[ i ] == cDroppedGlyph ) 2167cdf0e10cSrcweir continue; 2168cdf0e10cSrcweir mpOutGlyphs[ j ] = mpOutGlyphs[ i ]; 2169cdf0e10cSrcweir mpGlyphOffsets[ j ] = mpGlyphOffsets[ i ]; 2170cdf0e10cSrcweir mpVisualAttrs[ j ] = mpVisualAttrs[ i ]; 2171cdf0e10cSrcweir mpGlyphAdvances[ j ] = mpGlyphAdvances[ i ]; 2172cdf0e10cSrcweir if( mpJustifications ) 2173cdf0e10cSrcweir mpJustifications[ j ] = mpJustifications[ i ]; 2174cdf0e10cSrcweir const int k = mpGlyphs2Chars[ i ]; 2175cdf0e10cSrcweir mpGlyphs2Chars[ j ] = k; 2176cdf0e10cSrcweir const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos; 2177cdf0e10cSrcweir if( k < 0) // extra glyphs are already mapped 2178cdf0e10cSrcweir continue; 2179cdf0e10cSrcweir mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos); 2180cdf0e10cSrcweir } 2181cdf0e10cSrcweir 2182cdf0e10cSrcweir rVI.mnEndGlyphPos = j; 2183cdf0e10cSrcweir } 2184cdf0e10cSrcweir } 2185cdf0e10cSrcweir 2186cdf0e10cSrcweir // ----------------------------------------------------------------------- 2187cdf0e10cSrcweir 2188cdf0e10cSrcweir void UniscribeLayout::DrawText( SalGraphics& ) const 2189cdf0e10cSrcweir { 2190cdf0e10cSrcweir HFONT hOrigFont = DisableFontScaling(); 2191cdf0e10cSrcweir 2192cdf0e10cSrcweir int nBaseClusterOffset = 0; 2193cdf0e10cSrcweir int nBaseGlyphPos = -1; 2194cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2195cdf0e10cSrcweir { 2196cdf0e10cSrcweir const VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2197cdf0e10cSrcweir 2198cdf0e10cSrcweir // skip if there is nothing to display 2199cdf0e10cSrcweir int nMinGlyphPos, nEndGlyphPos; 2200cdf0e10cSrcweir if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) ) 2201cdf0e10cSrcweir continue; 2202cdf0e10cSrcweir 2203cdf0e10cSrcweir if( nBaseGlyphPos < 0 ) 2204cdf0e10cSrcweir { 2205cdf0e10cSrcweir // adjust draw position relative to cluster start 2206cdf0e10cSrcweir if( rVisualItem.IsRTL() ) 2207cdf0e10cSrcweir nBaseGlyphPos = nEndGlyphPos - 1; 2208cdf0e10cSrcweir else 2209cdf0e10cSrcweir nBaseGlyphPos = nMinGlyphPos; 2210cdf0e10cSrcweir 2211cdf0e10cSrcweir const int* pGlyphWidths; 2212cdf0e10cSrcweir if( mpJustifications ) 2213cdf0e10cSrcweir pGlyphWidths = mpJustifications; 2214cdf0e10cSrcweir else 2215cdf0e10cSrcweir pGlyphWidths = mpGlyphAdvances; 2216cdf0e10cSrcweir 2217cdf0e10cSrcweir int i = mnMinCharPos; 2218cdf0e10cSrcweir while( (--i >= rVisualItem.mnMinCharPos) 2219cdf0e10cSrcweir && (nBaseGlyphPos == mpLogClusters[i]) ) 2220cdf0e10cSrcweir nBaseClusterOffset += mpCharWidths[i]; 2221cdf0e10cSrcweir 2222cdf0e10cSrcweir if( !rVisualItem.IsRTL() ) 2223cdf0e10cSrcweir nBaseClusterOffset = -nBaseClusterOffset; 2224cdf0e10cSrcweir } 2225cdf0e10cSrcweir 2226cdf0e10cSrcweir // now draw the matching glyphs in this item 2227cdf0e10cSrcweir Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 ); 2228cdf0e10cSrcweir Point aPos = GetDrawPosition( aRelPos ); 2229cdf0e10cSrcweir SCRIPT_CACHE& rScriptCache = GetScriptCache(); 2230cdf0e10cSrcweir (*pScriptTextOut)( mhDC, &rScriptCache, 2231cdf0e10cSrcweir aPos.X(), aPos.Y(), 0, NULL, 2232cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, NULL, 0, 2233cdf0e10cSrcweir mpOutGlyphs + nMinGlyphPos, 2234cdf0e10cSrcweir nEndGlyphPos - nMinGlyphPos, 2235cdf0e10cSrcweir mpGlyphAdvances + nMinGlyphPos, 2236cdf0e10cSrcweir mpJustifications ? mpJustifications + nMinGlyphPos : NULL, 2237cdf0e10cSrcweir mpGlyphOffsets + nMinGlyphPos ); 2238cdf0e10cSrcweir } 2239cdf0e10cSrcweir 2240cdf0e10cSrcweir if( hOrigFont ) 2241cdf0e10cSrcweir DeleteFont( SelectFont( mhDC, hOrigFont ) ); 2242cdf0e10cSrcweir } 2243cdf0e10cSrcweir 2244cdf0e10cSrcweir // ----------------------------------------------------------------------- 2245cdf0e10cSrcweir 2246cdf0e10cSrcweir long UniscribeLayout::FillDXArray( long* pDXArray ) const 2247cdf0e10cSrcweir { 2248cdf0e10cSrcweir // calculate width of the complete layout 2249cdf0e10cSrcweir long nWidth = mnBaseAdv; 2250cdf0e10cSrcweir for( int nItem = mnItemCount; --nItem >= 0; ) 2251cdf0e10cSrcweir { 2252cdf0e10cSrcweir const VisualItem& rVI = mpVisualItems[ nItem ]; 2253cdf0e10cSrcweir 2254cdf0e10cSrcweir // skip if there is nothing to display 2255cdf0e10cSrcweir int nMinGlyphPos, nEndGlyphPos; 2256cdf0e10cSrcweir if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) ) 2257cdf0e10cSrcweir continue; 2258cdf0e10cSrcweir 2259cdf0e10cSrcweir // width = xoffset + width of last item 2260cdf0e10cSrcweir nWidth = rVI.mnXOffset; 2261cdf0e10cSrcweir const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances; 2262cdf0e10cSrcweir for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i ) 2263cdf0e10cSrcweir nWidth += pGlyphWidths[i]; 2264cdf0e10cSrcweir break; 2265cdf0e10cSrcweir } 2266cdf0e10cSrcweir 2267cdf0e10cSrcweir // copy the virtual char widths into pDXArray[] 2268cdf0e10cSrcweir if( pDXArray ) 2269cdf0e10cSrcweir for( int i = mnMinCharPos; i < mnEndCharPos; ++i ) 2270cdf0e10cSrcweir pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ]; 2271cdf0e10cSrcweir 2272cdf0e10cSrcweir return nWidth; 2273cdf0e10cSrcweir } 2274cdf0e10cSrcweir 2275cdf0e10cSrcweir // ----------------------------------------------------------------------- 2276cdf0e10cSrcweir 2277cdf0e10cSrcweir int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const 2278cdf0e10cSrcweir { 2279cdf0e10cSrcweir long nWidth = 0; 2280cdf0e10cSrcweir for( int i = mnMinCharPos; i < mnEndCharPos; ++i ) 2281cdf0e10cSrcweir { 2282cdf0e10cSrcweir nWidth += mpCharWidths[ i ] * nFactor; 2283cdf0e10cSrcweir 2284cdf0e10cSrcweir // check if the nMaxWidth still fits the current sub-layout 2285cdf0e10cSrcweir if( nWidth >= nMaxWidth ) 2286cdf0e10cSrcweir { 2287cdf0e10cSrcweir // go back to cluster start 2288cdf0e10cSrcweir // we have to find the visual item first since the mpLogClusters[] 2289cdf0e10cSrcweir // needed to find the cluster start is relative to to the visual item 2290cdf0e10cSrcweir int nMinGlyphIndex = 0; 2291cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2292cdf0e10cSrcweir { 2293cdf0e10cSrcweir const VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2294cdf0e10cSrcweir nMinGlyphIndex = rVisualItem.mnMinGlyphPos; 2295cdf0e10cSrcweir if( (i >= rVisualItem.mnMinCharPos) 2296cdf0e10cSrcweir && (i < rVisualItem.mnEndCharPos) ) 2297cdf0e10cSrcweir break; 2298cdf0e10cSrcweir } 2299cdf0e10cSrcweir // now go back to the matching cluster start 2300cdf0e10cSrcweir do 2301cdf0e10cSrcweir { 2302cdf0e10cSrcweir int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex; 2303cdf0e10cSrcweir if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart ) 2304cdf0e10cSrcweir return i; 2305cdf0e10cSrcweir } while( --i >= mnMinCharPos ); 2306cdf0e10cSrcweir 2307cdf0e10cSrcweir // if the cluster starts before the start of the visual item 2308cdf0e10cSrcweir // then set the visual breakpoint before this item 2309cdf0e10cSrcweir return mnMinCharPos; 2310cdf0e10cSrcweir } 2311cdf0e10cSrcweir 2312cdf0e10cSrcweir // the visual break also depends on the nCharExtra between the characters 2313cdf0e10cSrcweir nWidth += nCharExtra; 2314cdf0e10cSrcweir } 2315cdf0e10cSrcweir 2316cdf0e10cSrcweir // the whole layout did fit inside the nMaxWidth 2317cdf0e10cSrcweir return STRING_LEN; 2318cdf0e10cSrcweir } 2319cdf0e10cSrcweir 2320cdf0e10cSrcweir // ----------------------------------------------------------------------- 2321cdf0e10cSrcweir 2322cdf0e10cSrcweir void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const 2323cdf0e10cSrcweir { 2324cdf0e10cSrcweir int i; 2325cdf0e10cSrcweir for( i = 0; i < nMaxIdx; ++i ) 2326cdf0e10cSrcweir pCaretXArray[ i ] = -1; 2327cdf0e10cSrcweir long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) ); 2328cdf0e10cSrcweir for( i = 0; i <= mnGlyphCount; ++i ) 2329cdf0e10cSrcweir pGlyphPos[ i ] = -1; 2330cdf0e10cSrcweir 2331cdf0e10cSrcweir long nXPos = 0; 2332cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2333cdf0e10cSrcweir { 2334cdf0e10cSrcweir const VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2335cdf0e10cSrcweir if( rVisualItem.IsEmpty() ) 2336cdf0e10cSrcweir continue; 2337cdf0e10cSrcweir 2338cdf0e10cSrcweir if (mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK) 2339cdf0e10cSrcweir { 2340cdf0e10cSrcweir nXPos = rVisualItem.mnXOffset; 2341cdf0e10cSrcweir } 2342cdf0e10cSrcweir // get glyph positions 2343cdf0e10cSrcweir // TODO: handle when rVisualItem's glyph range is only partially used 2344cdf0e10cSrcweir for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i ) 2345cdf0e10cSrcweir { 2346cdf0e10cSrcweir pGlyphPos[ i ] = nXPos; 2347cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i ]; 2348cdf0e10cSrcweir } 2349cdf0e10cSrcweir // rightmost position of this visualitem 2350cdf0e10cSrcweir pGlyphPos[ i ] = nXPos; 2351cdf0e10cSrcweir 2352cdf0e10cSrcweir // convert glyph positions to character positions 2353cdf0e10cSrcweir i = rVisualItem.mnMinCharPos; 2354cdf0e10cSrcweir if( i < mnMinCharPos ) 2355cdf0e10cSrcweir i = mnMinCharPos; 2356cdf0e10cSrcweir for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i ) 2357cdf0e10cSrcweir { 2358cdf0e10cSrcweir int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos; 2359cdf0e10cSrcweir int nCurrIdx = i * 2; 2360cdf0e10cSrcweir if( !rVisualItem.IsRTL() ) 2361cdf0e10cSrcweir { 2362cdf0e10cSrcweir // normal positions for LTR case 2363cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = pGlyphPos[ j ]; 2364cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ]; 2365cdf0e10cSrcweir } 2366cdf0e10cSrcweir else 2367cdf0e10cSrcweir { 2368cdf0e10cSrcweir // reverse positions for RTL case 2369cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = pGlyphPos[ j+1 ]; 2370cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ]; 2371cdf0e10cSrcweir } 2372cdf0e10cSrcweir } 2373cdf0e10cSrcweir } 2374cdf0e10cSrcweir 2375cdf0e10cSrcweir if (!(mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK)) 2376cdf0e10cSrcweir { 2377cdf0e10cSrcweir nXPos = 0; 2378cdf0e10cSrcweir // fixup unknown character positions to neighbor 2379cdf0e10cSrcweir for( i = 0; i < nMaxIdx; ++i ) 2380cdf0e10cSrcweir { 2381cdf0e10cSrcweir if( pCaretXArray[ i ] >= 0 ) 2382cdf0e10cSrcweir nXPos = pCaretXArray[ i ]; 2383cdf0e10cSrcweir else 2384cdf0e10cSrcweir pCaretXArray[ i ] = nXPos; 2385cdf0e10cSrcweir } 2386cdf0e10cSrcweir } 2387cdf0e10cSrcweir } 2388cdf0e10cSrcweir 2389cdf0e10cSrcweir // ----------------------------------------------------------------------- 2390cdf0e10cSrcweir 2391cdf0e10cSrcweir void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 2392cdf0e10cSrcweir { 2393cdf0e10cSrcweir SalLayout::AdjustLayout( rArgs ); 2394cdf0e10cSrcweir 2395cdf0e10cSrcweir // adjust positions if requested 2396cdf0e10cSrcweir if( rArgs.mpDXArray ) 2397cdf0e10cSrcweir ApplyDXArray( rArgs ); 2398cdf0e10cSrcweir else if( rArgs.mnLayoutWidth ) 2399cdf0e10cSrcweir Justify( rArgs.mnLayoutWidth ); 2400cdf0e10cSrcweir } 2401cdf0e10cSrcweir 2402cdf0e10cSrcweir // ----------------------------------------------------------------------- 2403cdf0e10cSrcweir 2404cdf0e10cSrcweir void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs ) 2405cdf0e10cSrcweir { 2406cdf0e10cSrcweir const long* pDXArray = rArgs.mpDXArray; 2407cdf0e10cSrcweir 2408cdf0e10cSrcweir // increase char widths in string range to desired values 2409cdf0e10cSrcweir bool bModified = false; 2410cdf0e10cSrcweir int nOldWidth = 0; 2411cdf0e10cSrcweir DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" ); 2412cdf0e10cSrcweir int i,j; 2413cdf0e10cSrcweir for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j ) 2414cdf0e10cSrcweir { 2415cdf0e10cSrcweir int nNewCharWidth = (pDXArray[j] - nOldWidth); 2416cdf0e10cSrcweir // TODO: nNewCharWidth *= mnUnitsPerPixel; 2417cdf0e10cSrcweir if( mpCharWidths[i] != nNewCharWidth ) 2418cdf0e10cSrcweir { 2419cdf0e10cSrcweir mpCharWidths[i] = nNewCharWidth; 2420cdf0e10cSrcweir bModified = true; 2421cdf0e10cSrcweir } 2422cdf0e10cSrcweir nOldWidth = pDXArray[j]; 2423cdf0e10cSrcweir } 2424cdf0e10cSrcweir 2425cdf0e10cSrcweir if( !bModified ) 2426cdf0e10cSrcweir return; 2427cdf0e10cSrcweir 2428cdf0e10cSrcweir // initialize justifications array 2429cdf0e10cSrcweir mpJustifications = new int[ mnGlyphCapacity ]; 2430cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i ) 2431cdf0e10cSrcweir mpJustifications[ i ] = mpGlyphAdvances[ i ]; 2432cdf0e10cSrcweir 2433cdf0e10cSrcweir // apply new widths to script items 2434cdf0e10cSrcweir long nXOffset = 0; 2435cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2436cdf0e10cSrcweir { 2437cdf0e10cSrcweir VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2438cdf0e10cSrcweir 2439cdf0e10cSrcweir // set the position of this visual item 2440cdf0e10cSrcweir rVisualItem.mnXOffset = nXOffset; 2441cdf0e10cSrcweir 2442cdf0e10cSrcweir // ignore empty visual items 2443cdf0e10cSrcweir if( rVisualItem.IsEmpty() ) 2444cdf0e10cSrcweir { 2445cdf0e10cSrcweir for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++) 2446cdf0e10cSrcweir nXOffset += mpCharWidths[i]; 2447cdf0e10cSrcweir continue; 2448cdf0e10cSrcweir } 2449cdf0e10cSrcweir // ignore irrelevant visual items 2450cdf0e10cSrcweir if( (rVisualItem.mnMinCharPos >= mnEndCharPos) 2451cdf0e10cSrcweir || (rVisualItem.mnEndCharPos <= mnMinCharPos) ) 2452cdf0e10cSrcweir continue; 2453cdf0e10cSrcweir 2454cdf0e10cSrcweir // if needed prepare special handling for arabic justification 2455cdf0e10cSrcweir rVisualItem.mbHasKashidas = false; 2456cdf0e10cSrcweir if( rVisualItem.IsRTL() ) 2457cdf0e10cSrcweir { 2458cdf0e10cSrcweir for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i ) 2459cdf0e10cSrcweir if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 ) // any Arabic justification 2460cdf0e10cSrcweir { // excluding SCRIPT_JUSTIFY_NONE 2461cdf0e10cSrcweir // yes 2462cdf0e10cSrcweir rVisualItem.mbHasKashidas = true; 2463cdf0e10cSrcweir // so prepare for kashida handling 2464cdf0e10cSrcweir InitKashidaHandling(); 2465cdf0e10cSrcweir break; 2466cdf0e10cSrcweir } 2467cdf0e10cSrcweir 2468cdf0e10cSrcweir if( rVisualItem.HasKashidas() ) 2469cdf0e10cSrcweir for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i ) 2470cdf0e10cSrcweir { 2471cdf0e10cSrcweir // TODO: check if we still need this hack after correction of kashida placing? 2472cdf0e10cSrcweir // (i87688): apparently yes, we still need it! 2473cdf0e10cSrcweir if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE ) 2474cdf0e10cSrcweir // usp decided that justification can't be applied here 2475cdf0e10cSrcweir // but maybe our Kashida algorithm thinks differently. 2476cdf0e10cSrcweir // To avoid trouble (gaps within words, last character of 2477cdf0e10cSrcweir // a word gets a Kashida appended) override this. 2478cdf0e10cSrcweir 2479cdf0e10cSrcweir // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE 2480cdf0e10cSrcweir // just because this previous hack (which I haven't understand, sorry) used 2481cdf0e10cSrcweir // the same value to replace. Don't know if this is really the best 2482cdf0e10cSrcweir // thing to do, but it seems to fix things 2483cdf0e10cSrcweir mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA; 2484cdf0e10cSrcweir } 2485cdf0e10cSrcweir } 2486cdf0e10cSrcweir 2487cdf0e10cSrcweir // convert virtual charwidths to glyph justification values 2488cdf0e10cSrcweir HRESULT nRC = (*pScriptApplyLogicalWidth)( 2489cdf0e10cSrcweir mpCharWidths + rVisualItem.mnMinCharPos, 2490cdf0e10cSrcweir rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos, 2491cdf0e10cSrcweir rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos, 2492cdf0e10cSrcweir mpLogClusters + rVisualItem.mnMinCharPos, 2493cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 2494cdf0e10cSrcweir mpGlyphAdvances + rVisualItem.mnMinGlyphPos, 2495cdf0e10cSrcweir &rVisualItem.mpScriptItem->a, 2496cdf0e10cSrcweir &rVisualItem.maABCWidths, 2497cdf0e10cSrcweir mpJustifications + rVisualItem.mnMinGlyphPos ); 2498cdf0e10cSrcweir 2499cdf0e10cSrcweir if( nRC != 0 ) 2500cdf0e10cSrcweir { 2501cdf0e10cSrcweir delete[] mpJustifications; 2502cdf0e10cSrcweir mpJustifications = NULL; 2503cdf0e10cSrcweir break; 2504cdf0e10cSrcweir } 2505cdf0e10cSrcweir 2506cdf0e10cSrcweir // to prepare for the next visual item 2507cdf0e10cSrcweir // update nXOffset to the next items position 2508cdf0e10cSrcweir // before the mpJustifications[] array gets modified 2509cdf0e10cSrcweir int nMinGlyphPos, nEndGlyphPos; 2510cdf0e10cSrcweir if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) ) 2511cdf0e10cSrcweir { 2512cdf0e10cSrcweir for( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) 2513cdf0e10cSrcweir nXOffset += mpJustifications[ i ]; 2514cdf0e10cSrcweir 2515cdf0e10cSrcweir if( rVisualItem.mbHasKashidas ) 2516cdf0e10cSrcweir KashidaItemFix( nMinGlyphPos, nEndGlyphPos ); 2517cdf0e10cSrcweir } 2518cdf0e10cSrcweir 2519cdf0e10cSrcweir // workaround needed for older USP versions: 2520cdf0e10cSrcweir // right align the justification-adjusted glyphs in their cells for RTL-items 2521cdf0e10cSrcweir // unless the right alignment is done by inserting kashidas 2522cdf0e10cSrcweir if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() ) 2523cdf0e10cSrcweir { 2524cdf0e10cSrcweir for( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) 2525cdf0e10cSrcweir { 2526cdf0e10cSrcweir const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i]; 2527cdf0e10cSrcweir // #i99862# skip diacritics, we mustn't add extra justification to diacritics 2528cdf0e10cSrcweir int nIdxAdd = i - 1; 2529cdf0e10cSrcweir while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] ) 2530cdf0e10cSrcweir --nIdxAdd; 2531cdf0e10cSrcweir if( nIdxAdd < nMinGlyphPos ) 2532cdf0e10cSrcweir rVisualItem.mnXOffset += nXOffsetAdjust; 2533cdf0e10cSrcweir else 2534cdf0e10cSrcweir mpJustifications[nIdxAdd] += nXOffsetAdjust; 2535cdf0e10cSrcweir mpJustifications[i] -= nXOffsetAdjust; 2536cdf0e10cSrcweir } 2537cdf0e10cSrcweir } 2538cdf0e10cSrcweir } 2539cdf0e10cSrcweir } 2540cdf0e10cSrcweir 2541cdf0e10cSrcweir // ----------------------------------------------------------------------- 2542cdf0e10cSrcweir 2543cdf0e10cSrcweir void UniscribeLayout::InitKashidaHandling() 2544cdf0e10cSrcweir { 2545cdf0e10cSrcweir if( mnMinKashidaGlyph != 0 ) // already initialized 2546cdf0e10cSrcweir return; 2547cdf0e10cSrcweir 2548cdf0e10cSrcweir mrWinFontEntry.InitKashidaHandling( mhDC ); 2549cdf0e10cSrcweir mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth()); 2550cdf0e10cSrcweir mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph(); 2551cdf0e10cSrcweir } 2552cdf0e10cSrcweir 2553cdf0e10cSrcweir // adjust the kashida placement matching to the WriterEngine 2554cdf0e10cSrcweir void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos ) 2555cdf0e10cSrcweir { 2556cdf0e10cSrcweir // workaround needed for all known USP versions: 2557cdf0e10cSrcweir // ApplyLogicalWidth does not match ScriptJustify behaviour 2558cdf0e10cSrcweir for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i ) 2559cdf0e10cSrcweir { 2560cdf0e10cSrcweir // check for vowels 2561cdf0e10cSrcweir if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ]) 2562cdf0e10cSrcweir && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types 2563cdf0e10cSrcweir { // including SCRIPT_JUSTIFY_NONE 2564cdf0e10cSrcweir // vowel, we do it like ScriptJustify does 2565cdf0e10cSrcweir // the vowel gets the extra width 2566cdf0e10cSrcweir long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; 2567cdf0e10cSrcweir mpJustifications [ i ] = mpGlyphAdvances [ i ]; 2568cdf0e10cSrcweir mpJustifications [ i - 1 ] += nSpaceAdded; 2569cdf0e10cSrcweir } 2570cdf0e10cSrcweir } 2571cdf0e10cSrcweir 2572cdf0e10cSrcweir // redistribute the widths for kashidas 2573cdf0e10cSrcweir for( int i = nMinGlyphPos; i < nEndGlyphPos; ) 2574cdf0e10cSrcweir KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i ); 2575cdf0e10cSrcweir } 2576cdf0e10cSrcweir 2577cdf0e10cSrcweir bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos ) 2578cdf0e10cSrcweir { 2579cdf0e10cSrcweir // doing pixel work within a word. 2580cdf0e10cSrcweir // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth 2581cdf0e10cSrcweir 2582cdf0e10cSrcweir // find the next kashida 2583cdf0e10cSrcweir int nMinPos = *pnCurrentPos; 2584cdf0e10cSrcweir int nMaxPos = *pnCurrentPos; 2585cdf0e10cSrcweir for( int i = nMaxPos; i < nEndGlyphPos; ++i ) 2586cdf0e10cSrcweir { 2587cdf0e10cSrcweir if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK) 2588cdf0e10cSrcweir && (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) ) 2589cdf0e10cSrcweir break; 2590cdf0e10cSrcweir nMaxPos = i; 2591cdf0e10cSrcweir } 2592cdf0e10cSrcweir *pnCurrentPos = nMaxPos + 1; 2593cdf0e10cSrcweir if( nMinPos == nMaxPos ) 2594cdf0e10cSrcweir return false; 2595cdf0e10cSrcweir 2596cdf0e10cSrcweir // calculate the available space for an extra kashida 2597cdf0e10cSrcweir long nMaxAdded = 0; 2598cdf0e10cSrcweir int nKashPos = -1; 2599cdf0e10cSrcweir for( int i = nMaxPos; i >= nMinPos; --i ) 2600cdf0e10cSrcweir { 2601cdf0e10cSrcweir long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; 2602cdf0e10cSrcweir if( nSpaceAdded > nMaxAdded ) 2603cdf0e10cSrcweir { 2604cdf0e10cSrcweir nKashPos = i; 2605cdf0e10cSrcweir nMaxAdded = nSpaceAdded; 2606cdf0e10cSrcweir } 2607cdf0e10cSrcweir } 2608cdf0e10cSrcweir 2609cdf0e10cSrcweir // return early if there is no need for an extra kashida 2610cdf0e10cSrcweir if ( nMaxAdded <= 0 ) 2611cdf0e10cSrcweir return false; 2612cdf0e10cSrcweir // return early if there is not enough space for an extra kashida 2613cdf0e10cSrcweir if( 2*nMaxAdded < mnMinKashidaWidth ) 2614cdf0e10cSrcweir return false; 2615cdf0e10cSrcweir 2616cdf0e10cSrcweir // redistribute the extra spacing to the kashida position 2617cdf0e10cSrcweir for( int i = nMinPos; i <= nMaxPos; ++i ) 2618cdf0e10cSrcweir { 2619cdf0e10cSrcweir if( i == nKashPos ) 2620cdf0e10cSrcweir continue; 2621cdf0e10cSrcweir // everything else should not have extra spacing 2622cdf0e10cSrcweir long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; 2623cdf0e10cSrcweir if( nSpaceAdded > 0 ) 2624cdf0e10cSrcweir { 2625cdf0e10cSrcweir mpJustifications[ i ] -= nSpaceAdded; 2626cdf0e10cSrcweir mpJustifications[ nKashPos ] += nSpaceAdded; 2627cdf0e10cSrcweir } 2628cdf0e10cSrcweir } 2629cdf0e10cSrcweir 2630cdf0e10cSrcweir // check if we fulfill minimal kashida width 2631cdf0e10cSrcweir long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ]; 2632cdf0e10cSrcweir if( nSpaceAdded < mnMinKashidaWidth ) 2633cdf0e10cSrcweir { 2634cdf0e10cSrcweir // ugly: steal some pixels 2635cdf0e10cSrcweir long nSteal = 1; 2636cdf0e10cSrcweir if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos))) 2637cdf0e10cSrcweir nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos); 2638cdf0e10cSrcweir for( int i = nMinPos; i <= nMaxPos; ++i ) 2639cdf0e10cSrcweir { 2640cdf0e10cSrcweir if( i == nKashPos ) 2641cdf0e10cSrcweir continue; 2642cdf0e10cSrcweir nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal ); 2643cdf0e10cSrcweir if ( nSteal > 0 ) 2644cdf0e10cSrcweir { 2645cdf0e10cSrcweir mpJustifications [ i ] -= nSteal; 2646cdf0e10cSrcweir mpJustifications [ nKashPos ] += nSteal; 2647cdf0e10cSrcweir nSpaceAdded += nSteal; 2648cdf0e10cSrcweir } 2649cdf0e10cSrcweir if( nSpaceAdded >= mnMinKashidaWidth ) 2650cdf0e10cSrcweir return true; 2651cdf0e10cSrcweir } 2652cdf0e10cSrcweir } 2653cdf0e10cSrcweir 2654cdf0e10cSrcweir // blank padding 2655cdf0e10cSrcweir long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded; 2656cdf0e10cSrcweir if( nSpaceMissing > 0 ) 2657cdf0e10cSrcweir { 2658cdf0e10cSrcweir // inner glyph: distribute extra space evenly 2659cdf0e10cSrcweir if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) ) 2660cdf0e10cSrcweir { 2661cdf0e10cSrcweir mpJustifications [ nKashPos ] += nSpaceMissing; 2662cdf0e10cSrcweir long nHalfSpace = nSpaceMissing / 2; 2663cdf0e10cSrcweir mpJustifications [ nMinPos - 1 ] -= nHalfSpace; 2664cdf0e10cSrcweir mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace; 2665cdf0e10cSrcweir } 2666cdf0e10cSrcweir // rightmost: left glyph gets extra space 2667cdf0e10cSrcweir else if( nMinPos > nMinGlyphPos ) 2668cdf0e10cSrcweir { 2669cdf0e10cSrcweir mpJustifications [ nMinPos - 1 ] -= nSpaceMissing; 2670cdf0e10cSrcweir mpJustifications [ nKashPos ] += nSpaceMissing; 2671cdf0e10cSrcweir } 2672cdf0e10cSrcweir // leftmost: right glyph gets extra space 2673cdf0e10cSrcweir else if( nMaxPos < nEndGlyphPos - 1 ) 2674cdf0e10cSrcweir { 2675cdf0e10cSrcweir mpJustifications [ nKashPos ] += nSpaceMissing; 2676cdf0e10cSrcweir mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing; 2677cdf0e10cSrcweir } 2678cdf0e10cSrcweir else 2679cdf0e10cSrcweir return false; 2680cdf0e10cSrcweir } 2681cdf0e10cSrcweir 2682cdf0e10cSrcweir return true; 2683cdf0e10cSrcweir } 2684cdf0e10cSrcweir 2685cdf0e10cSrcweir // ----------------------------------------------------------------------- 2686cdf0e10cSrcweir 2687cdf0e10cSrcweir void UniscribeLayout::Justify( long nNewWidth ) 2688cdf0e10cSrcweir { 2689cdf0e10cSrcweir long nOldWidth = 0; 2690cdf0e10cSrcweir int i; 2691cdf0e10cSrcweir for( i = mnMinCharPos; i < mnEndCharPos; ++i ) 2692cdf0e10cSrcweir nOldWidth += mpCharWidths[ i ]; 2693cdf0e10cSrcweir if( nOldWidth <= 0 ) 2694cdf0e10cSrcweir return; 2695cdf0e10cSrcweir 2696cdf0e10cSrcweir nNewWidth *= mnUnitsPerPixel; // convert into font units 2697cdf0e10cSrcweir if( nNewWidth == nOldWidth ) 2698cdf0e10cSrcweir return; 2699cdf0e10cSrcweir // prepare to distribute the extra width evenly among the visual items 2700cdf0e10cSrcweir const double fStretch = (double)nNewWidth / nOldWidth; 2701cdf0e10cSrcweir 2702cdf0e10cSrcweir // initialize justifications array 2703cdf0e10cSrcweir mpJustifications = new int[ mnGlyphCapacity ]; 2704cdf0e10cSrcweir for( i = 0; i < mnGlyphCapacity; ++i ) 2705cdf0e10cSrcweir mpJustifications[ i ] = mpGlyphAdvances[ i ]; 2706cdf0e10cSrcweir 2707cdf0e10cSrcweir // justify stretched script items 2708cdf0e10cSrcweir long nXOffset = 0; 2709cdf0e10cSrcweir SCRIPT_CACHE& rScriptCache = GetScriptCache(); 2710cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2711cdf0e10cSrcweir { 2712cdf0e10cSrcweir VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2713cdf0e10cSrcweir if( rVisualItem.IsEmpty() ) 2714cdf0e10cSrcweir continue; 2715cdf0e10cSrcweir 2716cdf0e10cSrcweir if( (rVisualItem.mnMinCharPos < mnEndCharPos) 2717cdf0e10cSrcweir && (rVisualItem.mnEndCharPos > mnMinCharPos) ) 2718cdf0e10cSrcweir { 2719cdf0e10cSrcweir long nItemWidth = 0; 2720cdf0e10cSrcweir for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i ) 2721cdf0e10cSrcweir nItemWidth += mpCharWidths[ i ]; 2722cdf0e10cSrcweir nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5); 2723cdf0e10cSrcweir 2724cdf0e10cSrcweir HRESULT nRC = (*pScriptJustify) ( 2725cdf0e10cSrcweir mpVisualAttrs + rVisualItem.mnMinGlyphPos, 2726cdf0e10cSrcweir mpGlyphAdvances + rVisualItem.mnMinGlyphPos, 2727cdf0e10cSrcweir rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos, 2728cdf0e10cSrcweir nItemWidth, 2729cdf0e10cSrcweir mnMinKashidaWidth, 2730cdf0e10cSrcweir mpJustifications + rVisualItem.mnMinGlyphPos ); 2731cdf0e10cSrcweir 2732cdf0e10cSrcweir rVisualItem.mnXOffset = nXOffset; 2733cdf0e10cSrcweir nXOffset += nItemWidth; 2734cdf0e10cSrcweir } 2735cdf0e10cSrcweir } 2736cdf0e10cSrcweir } 2737cdf0e10cSrcweir 2738cdf0e10cSrcweir // ----------------------------------------------------------------------- 2739cdf0e10cSrcweir 2740cdf0e10cSrcweir bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const 2741cdf0e10cSrcweir { 2742cdf0e10cSrcweir // we have to find the visual item first since the mpLogClusters[] 2743cdf0e10cSrcweir // needed to find the cluster start is relative to to the visual item 2744cdf0e10cSrcweir int nMinGlyphIndex = -1; 2745cdf0e10cSrcweir for( int nItem = 0; nItem < mnItemCount; ++nItem ) 2746cdf0e10cSrcweir { 2747cdf0e10cSrcweir const VisualItem& rVisualItem = mpVisualItems[ nItem ]; 2748cdf0e10cSrcweir if( (nCharPos >= rVisualItem.mnMinCharPos) 2749cdf0e10cSrcweir && (nCharPos < rVisualItem.mnEndCharPos) ) 2750cdf0e10cSrcweir { 2751cdf0e10cSrcweir nMinGlyphIndex = rVisualItem.mnMinGlyphPos; 2752cdf0e10cSrcweir break; 2753cdf0e10cSrcweir } 2754cdf0e10cSrcweir } 2755cdf0e10cSrcweir // Invalid char pos or leftmost glyph in visual item 2756cdf0e10cSrcweir if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] ) 2757cdf0e10cSrcweir return false; 2758cdf0e10cSrcweir 2759cdf0e10cSrcweir // This test didn't give the expected results 2760cdf0e10cSrcweir /* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ]) 2761cdf0e10cSrcweir // two chars, one glyph 2762cdf0e10cSrcweir return false;*/ 2763cdf0e10cSrcweir 2764cdf0e10cSrcweir const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex; 2765cdf0e10cSrcweir if( nGlyphPos <= 0 ) 2766cdf0e10cSrcweir return true; 2767cdf0e10cSrcweir // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE 2768cdf0e10cSrcweir // and not SCRIPT_JUSTIFY_ARABIC_BLANK 2769cdf0e10cSrcweir // special case: glyph to the left is vowel (no advance width) 2770cdf0e10cSrcweir if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK 2771cdf0e10cSrcweir || ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE 2772cdf0e10cSrcweir && mpGlyphAdvances [ nGlyphPos-1 ] )) 2773cdf0e10cSrcweir return false; 2774cdf0e10cSrcweir return true; 2775cdf0e10cSrcweir } 2776cdf0e10cSrcweir 2777cdf0e10cSrcweir #endif // USE_UNISCRIBE 2778cdf0e10cSrcweir 2779cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 2780cdf0e10cSrcweir 2781cdf0e10cSrcweir class GraphiteLayoutWinImpl : public GraphiteLayout 2782cdf0e10cSrcweir { 2783cdf0e10cSrcweir public: 2784cdf0e10cSrcweir GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont) 2785cdf0e10cSrcweir throw() 2786cdf0e10cSrcweir : GraphiteLayout(font), mrFont(rFont) {}; 2787cdf0e10cSrcweir virtual ~GraphiteLayoutWinImpl() throw() {}; 2788cdf0e10cSrcweir virtual sal_GlyphId getKashidaGlyph(int & rWidth); 2789cdf0e10cSrcweir private: 2790cdf0e10cSrcweir ImplWinFontEntry & mrFont; 2791cdf0e10cSrcweir }; 2792cdf0e10cSrcweir 2793cdf0e10cSrcweir sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth) 2794cdf0e10cSrcweir { 2795cdf0e10cSrcweir rWidth = mrFont.GetMinKashidaWidth(); 2796cdf0e10cSrcweir return mrFont.GetMinKashidaGlyph(); 2797cdf0e10cSrcweir } 2798cdf0e10cSrcweir 2799cdf0e10cSrcweir // This class uses the SIL Graphite engine to provide complex text layout services to the VCL 2800cdf0e10cSrcweir // @author tse 2801cdf0e10cSrcweir // 2802cdf0e10cSrcweir class GraphiteWinLayout : public WinLayout 2803cdf0e10cSrcweir { 2804cdf0e10cSrcweir private: 2805cdf0e10cSrcweir mutable GraphiteWinFont mpFont; 2806cdf0e10cSrcweir grutils::GrFeatureParser * mpFeatures; 2807cdf0e10cSrcweir mutable GraphiteLayoutWinImpl maImpl; 2808cdf0e10cSrcweir public: 28097d9c290fSMichael Stahl GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw(); 2810cdf0e10cSrcweir 2811cdf0e10cSrcweir static bool IsGraphiteEnabledFont(HDC hDC) throw(); 2812cdf0e10cSrcweir 2813cdf0e10cSrcweir // used by upper layers 2814cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout 2815cdf0e10cSrcweir virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc. 2816cdf0e10cSrcweir // virtual void InitFont() const; 2817cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const; 2818cdf0e10cSrcweir 2819cdf0e10cSrcweir // methods using string indexing 2820cdf0e10cSrcweir virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const; 2821cdf0e10cSrcweir virtual long FillDXArray( long* pDXArray ) const; 2822cdf0e10cSrcweir 2823cdf0e10cSrcweir virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; 2824cdf0e10cSrcweir 2825cdf0e10cSrcweir // methods using glyph indexing 2826cdf0e10cSrcweir virtual int GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&, 2827cdf0e10cSrcweir long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const; 2828cdf0e10cSrcweir 2829cdf0e10cSrcweir // used by glyph+font+script fallback 2830cdf0e10cSrcweir virtual void MoveGlyph( int nStart, long nNewXPos ); 2831cdf0e10cSrcweir virtual void DropGlyph( int nStart ); 2832cdf0e10cSrcweir virtual void Simplify( bool bIsBase ); 2833cdf0e10cSrcweir ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; }; 2834cdf0e10cSrcweir protected: 2835cdf0e10cSrcweir virtual void ReplaceDC(gr::Segment & segment) const; 2836cdf0e10cSrcweir virtual void RestoreDC(gr::Segment & segment) const; 2837cdf0e10cSrcweir }; 2838cdf0e10cSrcweir 2839cdf0e10cSrcweir bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw() 2840cdf0e10cSrcweir { 2841cdf0e10cSrcweir return gr::WinFont::FontHasGraphiteTables(hDC); 2842cdf0e10cSrcweir } 2843cdf0e10cSrcweir 2844cdf0e10cSrcweir GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw() 2845cdf0e10cSrcweir : WinLayout(hDC, rWFD, rWFE), mpFont(hDC), 2846cdf0e10cSrcweir maImpl(mpFont, rWFE) 2847cdf0e10cSrcweir { 2848cdf0e10cSrcweir const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage ); 2849cdf0e10cSrcweir rtl::OString name = rtl::OUStringToOString( 2850cdf0e10cSrcweir rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 ); 2851cdf0e10cSrcweir sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1; 2852cdf0e10cSrcweir if (nFeat > 0) 2853cdf0e10cSrcweir { 2854cdf0e10cSrcweir rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat); 2855cdf0e10cSrcweir mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr()); 2856cdf0e10cSrcweir } 2857cdf0e10cSrcweir else 2858cdf0e10cSrcweir { 2859cdf0e10cSrcweir mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr()); 2860cdf0e10cSrcweir } 2861cdf0e10cSrcweir maImpl.SetFeatures(mpFeatures); 2862cdf0e10cSrcweir } 2863cdf0e10cSrcweir 2864cdf0e10cSrcweir void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const 2865cdf0e10cSrcweir { 2866cdf0e10cSrcweir COLORREF color = GetTextColor(mhDC); 2867cdf0e10cSrcweir dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC); 2868cdf0e10cSrcweir SetTextColor(mhDC, color); 2869cdf0e10cSrcweir } 2870cdf0e10cSrcweir 2871cdf0e10cSrcweir void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const 2872cdf0e10cSrcweir { 2873cdf0e10cSrcweir dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC(); 2874cdf0e10cSrcweir } 2875cdf0e10cSrcweir 2876cdf0e10cSrcweir bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) 2877cdf0e10cSrcweir { 2878cdf0e10cSrcweir if (args.mnMinCharPos >= args.mnEndCharPos) 2879cdf0e10cSrcweir { 2880cdf0e10cSrcweir maImpl.clear(); 2881cdf0e10cSrcweir return true; 2882cdf0e10cSrcweir } 2883cdf0e10cSrcweir HFONT hUnRotatedFont; 2884cdf0e10cSrcweir if (args.mnOrientation) 2885cdf0e10cSrcweir { 2886cdf0e10cSrcweir // Graphite gets very confused if the font is rotated 2887cdf0e10cSrcweir LOGFONTW aLogFont; 2888cdf0e10cSrcweir ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont); 2889cdf0e10cSrcweir aLogFont.lfEscapement = 0; 2890cdf0e10cSrcweir aLogFont.lfOrientation = 0; 2891cdf0e10cSrcweir hUnRotatedFont = ::CreateFontIndirectW( &aLogFont); 2892cdf0e10cSrcweir ::SelectFont(mhDC, hUnRotatedFont); 2893cdf0e10cSrcweir } 2894cdf0e10cSrcweir WinLayout::AdjustLayout(args); 2895cdf0e10cSrcweir mpFont.replaceDC(mhDC); 2896cdf0e10cSrcweir maImpl.SetFontScale(WinLayout::mfFontScale); 2897cdf0e10cSrcweir //bool succeeded = maImpl.LayoutText(args); 2898cdf0e10cSrcweir #ifdef GRCACHE 2899cdf0e10cSrcweir GrSegRecord * pSegRecord = NULL; 2900cdf0e10cSrcweir gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord); 2901cdf0e10cSrcweir #else 2902cdf0e10cSrcweir gr::Segment * pSegment = maImpl.CreateSegment(args); 2903cdf0e10cSrcweir #endif 2904cdf0e10cSrcweir bool bSucceeded = false; 2905cdf0e10cSrcweir if (pSegment) 2906cdf0e10cSrcweir { 2907cdf0e10cSrcweir // replace the DC on the font within the segment 2908cdf0e10cSrcweir ReplaceDC(*pSegment); 2909cdf0e10cSrcweir // create glyph vectors 2910cdf0e10cSrcweir #ifdef GRCACHE 2911cdf0e10cSrcweir bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord); 2912cdf0e10cSrcweir #else 2913cdf0e10cSrcweir bSucceeded = maImpl.LayoutGlyphs(args, pSegment); 2914cdf0e10cSrcweir #endif 2915cdf0e10cSrcweir // restore original DC 2916cdf0e10cSrcweir RestoreDC(*pSegment); 2917cdf0e10cSrcweir #ifdef GRCACHE 2918cdf0e10cSrcweir if (pSegRecord) pSegRecord->unlock(); 2919cdf0e10cSrcweir else delete pSegment; 2920cdf0e10cSrcweir #else 2921cdf0e10cSrcweir delete pSegment; 2922cdf0e10cSrcweir #endif 2923cdf0e10cSrcweir } 2924cdf0e10cSrcweir mpFont.restoreDC(); 2925cdf0e10cSrcweir if (args.mnOrientation) 2926cdf0e10cSrcweir { 2927cdf0e10cSrcweir // restore the rotated font 2928cdf0e10cSrcweir ::SelectFont(mhDC, mhFont); 2929cdf0e10cSrcweir ::DeleteObject(hUnRotatedFont); 2930cdf0e10cSrcweir } 2931cdf0e10cSrcweir return bSucceeded; 2932cdf0e10cSrcweir } 2933cdf0e10cSrcweir 2934cdf0e10cSrcweir void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs) 2935cdf0e10cSrcweir { 2936cdf0e10cSrcweir WinLayout::AdjustLayout(rArgs); 2937cdf0e10cSrcweir maImpl.DrawBase() = WinLayout::maDrawBase; 2938cdf0e10cSrcweir maImpl.DrawOffset() = WinLayout::maDrawOffset; 2939cdf0e10cSrcweir if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray) 2940cdf0e10cSrcweir { 2941cdf0e10cSrcweir mrWinFontEntry.InitKashidaHandling(mhDC); 2942cdf0e10cSrcweir } 2943cdf0e10cSrcweir maImpl.AdjustLayout(rArgs); 2944cdf0e10cSrcweir } 2945cdf0e10cSrcweir 2946cdf0e10cSrcweir void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const 2947cdf0e10cSrcweir { 2948cdf0e10cSrcweir HFONT hOrigFont = DisableFontScaling(); 29492a6d8217SHerbert Dürr const HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).getHDC(); 2950cdf0e10cSrcweir maImpl.DrawBase() = WinLayout::maDrawBase; 2951cdf0e10cSrcweir maImpl.DrawOffset() = WinLayout::maDrawOffset; 2952cdf0e10cSrcweir const int MAX_GLYPHS = 2; 2953cdf0e10cSrcweir sal_GlyphId glyphIntStr[MAX_GLYPHS]; 2954cdf0e10cSrcweir WORD glyphWStr[MAX_GLYPHS]; 2955cdf0e10cSrcweir int glyphIndex = 0; 2956cdf0e10cSrcweir Point aPos(0,0); 2957cdf0e10cSrcweir int nGlyphs = 0; 2958cdf0e10cSrcweir do 2959cdf0e10cSrcweir { 2960cdf0e10cSrcweir nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex); 2961cdf0e10cSrcweir if (nGlyphs < 1) 2962cdf0e10cSrcweir break; 2963cdf0e10cSrcweir std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr); 2964cdf0e10cSrcweir ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX, 2965cdf0e10cSrcweir NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL); 2966cdf0e10cSrcweir } while (nGlyphs); 2967cdf0e10cSrcweir if( hOrigFont ) 29682a6d8217SHerbert Dürr DeleteFont( SelectFont( aHDC, hOrigFont ) ); 2969cdf0e10cSrcweir } 2970cdf0e10cSrcweir 2971cdf0e10cSrcweir int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const 2972cdf0e10cSrcweir { 2973cdf0e10cSrcweir mpFont.replaceDC(mhDC); 2974cdf0e10cSrcweir int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor); 2975cdf0e10cSrcweir mpFont.restoreDC(); 2976cdf0e10cSrcweir return nBreak; 2977cdf0e10cSrcweir } 2978cdf0e10cSrcweir 2979cdf0e10cSrcweir long GraphiteWinLayout::FillDXArray( long* pDXArray ) const 2980cdf0e10cSrcweir { 2981cdf0e10cSrcweir return maImpl.FillDXArray(pDXArray); 2982cdf0e10cSrcweir } 2983cdf0e10cSrcweir 2984cdf0e10cSrcweir void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const 2985cdf0e10cSrcweir { 2986cdf0e10cSrcweir maImpl.GetCaretPositions(nArraySize, pCaretXArray); 2987cdf0e10cSrcweir } 2988cdf0e10cSrcweir 2989cdf0e10cSrcweir int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out, 2990cdf0e10cSrcweir ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const 2991cdf0e10cSrcweir { 2992cdf0e10cSrcweir maImpl.DrawBase() = WinLayout::maDrawBase; 2993cdf0e10cSrcweir maImpl.DrawOffset() = WinLayout::maDrawOffset; 2994cdf0e10cSrcweir return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index); 2995cdf0e10cSrcweir } 2996cdf0e10cSrcweir 2997cdf0e10cSrcweir void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos ) 2998cdf0e10cSrcweir { 2999cdf0e10cSrcweir maImpl.MoveGlyph(glyph_idx, new_x_pos); 3000cdf0e10cSrcweir } 3001cdf0e10cSrcweir 3002cdf0e10cSrcweir void GraphiteWinLayout::DropGlyph( int glyph_idx ) 3003cdf0e10cSrcweir { 3004cdf0e10cSrcweir maImpl.DropGlyph(glyph_idx); 3005cdf0e10cSrcweir } 3006cdf0e10cSrcweir 3007cdf0e10cSrcweir void GraphiteWinLayout::Simplify( bool is_base ) 3008cdf0e10cSrcweir { 3009cdf0e10cSrcweir maImpl.Simplify(is_base); 3010cdf0e10cSrcweir } 3011cdf0e10cSrcweir #endif // ENABLE_GRAPHITE 3012cdf0e10cSrcweir // ======================================================================= 3013cdf0e10cSrcweir 3014cdf0e10cSrcweir SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel ) 3015cdf0e10cSrcweir { 3016cdf0e10cSrcweir DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL"); 3017cdf0e10cSrcweir 3018cdf0e10cSrcweir WinLayout* pWinLayout = NULL; 3019cdf0e10cSrcweir 3020cdf0e10cSrcweir const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ]; 3021cdf0e10cSrcweir ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ]; 3022cdf0e10cSrcweir 3023cdf0e10cSrcweir #if defined( USE_UNISCRIBE ) 3024cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) 3025cdf0e10cSrcweir && (aUspModule || (bUspEnabled && InitUSP())) ) // CTL layout engine 3026cdf0e10cSrcweir { 3027cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 3028cdf0e10cSrcweir if (rFontFace.SupportsGraphite()) 30292a6d8217SHerbert Dürr pWinLayout = new GraphiteWinLayout( getHDC(), rFontFace, rFontInstance); 3030cdf0e10cSrcweir else 3031cdf0e10cSrcweir #endif // ENABLE_GRAPHITE 3032cdf0e10cSrcweir // script complexity is determined in upper layers 30335f27b83cSArmin Le Grand pWinLayout = new UniscribeLayout( getHDC(), rFontFace, rFontInstance ); 3034cdf0e10cSrcweir // NOTE: it must be guaranteed that the WinSalGraphics lives longer than 3035cdf0e10cSrcweir // the created UniscribeLayout, otherwise the data passed into the 3036cdf0e10cSrcweir // constructor might become invalid too early 3037cdf0e10cSrcweir } 3038cdf0e10cSrcweir else 3039cdf0e10cSrcweir #endif // USE_UNISCRIBE 3040cdf0e10cSrcweir { 3041cdf0e10cSrcweir #ifdef GCP_KERN_HACK 3042cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() ) 3043cdf0e10cSrcweir { 3044cdf0e10cSrcweir // TODO: directly cache kerning info in the rFontInstance 3045cdf0e10cSrcweir // TODO: get rid of kerning methods+data in WinSalGraphics object 3046cdf0e10cSrcweir GetKernPairs( 0, NULL ); 3047cdf0e10cSrcweir rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs ); 3048cdf0e10cSrcweir } 3049cdf0e10cSrcweir #endif // GCP_KERN_HACK 3050cdf0e10cSrcweir 3051cdf0e10cSrcweir BYTE eCharSet = ANSI_CHARSET; 3052cdf0e10cSrcweir if( mpLogFont ) 3053cdf0e10cSrcweir eCharSet = mpLogFont->lfCharSet; 3054cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 3055cdf0e10cSrcweir if (rFontFace.SupportsGraphite()) 30562a6d8217SHerbert Dürr pWinLayout = new GraphiteWinLayout( getHDC(), rFontFace, rFontInstance); 3057cdf0e10cSrcweir else 3058cdf0e10cSrcweir #endif // ENABLE_GRAPHITE 30595f27b83cSArmin Le Grand pWinLayout = new SimpleWinLayout( getHDC(), eCharSet, rFontFace, rFontInstance ); 3060cdf0e10cSrcweir } 3061cdf0e10cSrcweir 3062cdf0e10cSrcweir if( mfFontScale != 1.0 ) 3063cdf0e10cSrcweir pWinLayout->SetFontScale( mfFontScale ); 3064cdf0e10cSrcweir 3065cdf0e10cSrcweir return pWinLayout; 3066cdf0e10cSrcweir } 3067cdf0e10cSrcweir 3068cdf0e10cSrcweir // ----------------------------------------------------------------------- 3069cdf0e10cSrcweir 3070cdf0e10cSrcweir int WinSalGraphics::GetMinKashidaWidth() 3071cdf0e10cSrcweir { 3072cdf0e10cSrcweir if( !mpWinFontEntry[0] ) 3073cdf0e10cSrcweir return 0; 30745f27b83cSArmin Le Grand mpWinFontEntry[0]->InitKashidaHandling( getHDC() ); 3075cdf0e10cSrcweir int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth()); 3076cdf0e10cSrcweir return nMinKashida; 3077cdf0e10cSrcweir } 3078cdf0e10cSrcweir 3079cdf0e10cSrcweir // ======================================================================= 3080cdf0e10cSrcweir 3081cdf0e10cSrcweir ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD ) 3082cdf0e10cSrcweir : ImplFontEntry( rFSD ) 3083cdf0e10cSrcweir , maWidthMap( 512 ) 3084cdf0e10cSrcweir , mpKerningPairs( NULL ) 3085cdf0e10cSrcweir , mnKerningPairs( -1 ) 3086cdf0e10cSrcweir , mnMinKashidaWidth( -1 ) 3087cdf0e10cSrcweir , mnMinKashidaGlyph( -1 ) 3088cdf0e10cSrcweir { 3089cdf0e10cSrcweir #ifdef USE_UNISCRIBE 3090cdf0e10cSrcweir maScriptCache = NULL; 3091cdf0e10cSrcweir #endif // USE_UNISCRIBE 3092cdf0e10cSrcweir } 3093cdf0e10cSrcweir 3094cdf0e10cSrcweir // ----------------------------------------------------------------------- 3095cdf0e10cSrcweir 3096cdf0e10cSrcweir ImplWinFontEntry::~ImplWinFontEntry() 3097cdf0e10cSrcweir { 3098cdf0e10cSrcweir #ifdef USE_UNISCRIBE 3099cdf0e10cSrcweir if( maScriptCache != NULL ) 3100cdf0e10cSrcweir (*pScriptFreeCache)( &maScriptCache ); 3101cdf0e10cSrcweir #endif // USE_UNISCRIBE 3102cdf0e10cSrcweir #ifdef GCP_KERN_HACK 3103cdf0e10cSrcweir delete[] mpKerningPairs; 3104cdf0e10cSrcweir #endif // GCP_KERN_HACK 3105cdf0e10cSrcweir } 3106cdf0e10cSrcweir 3107cdf0e10cSrcweir // ----------------------------------------------------------------------- 3108cdf0e10cSrcweir 3109cdf0e10cSrcweir bool ImplWinFontEntry::HasKernData() const 3110cdf0e10cSrcweir { 3111cdf0e10cSrcweir return (mnKerningPairs >= 0); 3112cdf0e10cSrcweir } 3113cdf0e10cSrcweir 3114cdf0e10cSrcweir // ----------------------------------------------------------------------- 3115cdf0e10cSrcweir 3116cdf0e10cSrcweir void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData ) 3117cdf0e10cSrcweir { 3118cdf0e10cSrcweir mnKerningPairs = nPairCount; 3119cdf0e10cSrcweir mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ]; 3120cdf0e10cSrcweir ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) ); 3121cdf0e10cSrcweir } 3122cdf0e10cSrcweir 3123cdf0e10cSrcweir // ----------------------------------------------------------------------- 3124cdf0e10cSrcweir 3125cdf0e10cSrcweir int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const 3126cdf0e10cSrcweir { 3127cdf0e10cSrcweir int nKernAmount = 0; 3128cdf0e10cSrcweir if( mpKerningPairs ) 3129cdf0e10cSrcweir { 3130cdf0e10cSrcweir const KERNINGPAIR aRefPair = { cLeft, cRight, 0 }; 3131cdf0e10cSrcweir const KERNINGPAIR* pFirstPair = mpKerningPairs; 3132cdf0e10cSrcweir const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs; 3133cdf0e10cSrcweir const KERNINGPAIR* pPair = std::lower_bound( pFirstPair, 3134cdf0e10cSrcweir pEndPair, aRefPair, ImplCmpKernData ); 3135cdf0e10cSrcweir if( (pPair != pEndPair) 3136cdf0e10cSrcweir && (pPair->wFirst == aRefPair.wFirst) 3137cdf0e10cSrcweir && (pPair->wSecond == aRefPair.wSecond) ) 3138cdf0e10cSrcweir nKernAmount = pPair->iKernAmount; 3139cdf0e10cSrcweir } 3140cdf0e10cSrcweir 3141cdf0e10cSrcweir return nKernAmount; 3142cdf0e10cSrcweir } 3143cdf0e10cSrcweir 3144cdf0e10cSrcweir // ----------------------------------------------------------------------- 3145cdf0e10cSrcweir 3146cdf0e10cSrcweir bool ImplWinFontEntry::InitKashidaHandling( HDC hDC ) 3147cdf0e10cSrcweir { 3148cdf0e10cSrcweir if( mnMinKashidaWidth >= 0 ) // already cached? 3149cdf0e10cSrcweir return mnMinKashidaWidth; 3150cdf0e10cSrcweir 3151cdf0e10cSrcweir // initialize the kashida width 3152cdf0e10cSrcweir mnMinKashidaWidth = 0; 3153cdf0e10cSrcweir mnMinKashidaGlyph = 0; 3154cdf0e10cSrcweir #ifdef USE_UNISCRIBE 3155cdf0e10cSrcweir if (aUspModule || (bUspEnabled && InitUSP())) 3156cdf0e10cSrcweir { 3157cdf0e10cSrcweir SCRIPT_FONTPROPERTIES aFontProperties; 3158cdf0e10cSrcweir aFontProperties.cBytes = sizeof (aFontProperties); 3159cdf0e10cSrcweir SCRIPT_CACHE& rScriptCache = GetScriptCache(); 3160cdf0e10cSrcweir HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties ); 3161cdf0e10cSrcweir if( nRC != 0 ) 3162cdf0e10cSrcweir return false; 3163cdf0e10cSrcweir mnMinKashidaWidth = aFontProperties.iKashidaWidth; 3164cdf0e10cSrcweir mnMinKashidaGlyph = aFontProperties.wgKashida; 3165cdf0e10cSrcweir } 3166cdf0e10cSrcweir #endif // USE_UNISCRIBE 3167cdf0e10cSrcweir 3168cdf0e10cSrcweir return true; 3169cdf0e10cSrcweir } 3170cdf0e10cSrcweir 3171cdf0e10cSrcweir // ======================================================================= 3172cdf0e10cSrcweir 3173cdf0e10cSrcweir ImplFontData* ImplWinFontData::Clone() const 3174cdf0e10cSrcweir { 3175cdf0e10cSrcweir if( mpUnicodeMap ) 3176cdf0e10cSrcweir mpUnicodeMap->AddReference(); 3177cdf0e10cSrcweir ImplFontData* pClone = new ImplWinFontData( *this ); 3178cdf0e10cSrcweir return pClone; 3179cdf0e10cSrcweir } 3180cdf0e10cSrcweir 3181cdf0e10cSrcweir // ----------------------------------------------------------------------- 3182cdf0e10cSrcweir 3183cdf0e10cSrcweir ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const 3184cdf0e10cSrcweir { 3185cdf0e10cSrcweir ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD ); 3186cdf0e10cSrcweir return pEntry; 3187cdf0e10cSrcweir } 3188cdf0e10cSrcweir 3189cdf0e10cSrcweir // ======================================================================= 3190