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