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 #define ENABLE_ICU_LAYOUT 32*cdf0e10cSrcweir #include <gcach_ftyp.hxx> 33*cdf0e10cSrcweir #include <sallayout.hxx> 34*cdf0e10cSrcweir #include <salgdi.hxx> 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir #include <vcl/svapp.hxx> 37*cdf0e10cSrcweir 38*cdf0e10cSrcweir #include <sal/alloca.h> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 41*cdf0e10cSrcweir #include <cstdio> 42*cdf0e10cSrcweir #endif 43*cdf0e10cSrcweir #include <rtl/instance.hxx> 44*cdf0e10cSrcweir 45*cdf0e10cSrcweir namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; } 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir // ======================================================================= 48*cdf0e10cSrcweir // layout implementation for ServerFont 49*cdf0e10cSrcweir // ======================================================================= 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir ServerFontLayout::ServerFontLayout( ServerFont& rFont ) 52*cdf0e10cSrcweir : mrServerFont( rFont ) 53*cdf0e10cSrcweir {} 54*cdf0e10cSrcweir 55*cdf0e10cSrcweir void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const 56*cdf0e10cSrcweir { 57*cdf0e10cSrcweir rSalGraphics.DrawServerFontLayout( *this ); 58*cdf0e10cSrcweir } 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir // ----------------------------------------------------------------------- 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs ) 63*cdf0e10cSrcweir { 64*cdf0e10cSrcweir ServerFontLayoutEngine* pLE = NULL; 65*cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) ) 66*cdf0e10cSrcweir pLE = mrServerFont.GetLayoutEngine(); 67*cdf0e10cSrcweir if( !pLE ) 68*cdf0e10cSrcweir pLE = &SimpleLayoutEngine::get(); 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir bool bRet = (*pLE)( *this, rArgs ); 71*cdf0e10cSrcweir return bRet; 72*cdf0e10cSrcweir } 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir // ----------------------------------------------------------------------- 75*cdf0e10cSrcweir 76*cdf0e10cSrcweir void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 77*cdf0e10cSrcweir { 78*cdf0e10cSrcweir GenericSalLayout::AdjustLayout( rArgs ); 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir // apply asian kerning if the glyphs are not already formatted 81*cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN) 82*cdf0e10cSrcweir && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) ) 83*cdf0e10cSrcweir if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) ) 84*cdf0e10cSrcweir ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength ); 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir // insert kashidas where requested by the formatting array 87*cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray ) 88*cdf0e10cSrcweir { 89*cdf0e10cSrcweir int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); 90*cdf0e10cSrcweir if( nKashidaIndex != 0 ) 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); 93*cdf0e10cSrcweir KashidaJustify( nKashidaIndex, rGM.GetCharWidth() ); 94*cdf0e10cSrcweir // TODO: kashida-GSUB/GPOS 95*cdf0e10cSrcweir } 96*cdf0e10cSrcweir } 97*cdf0e10cSrcweir } 98*cdf0e10cSrcweir 99*cdf0e10cSrcweir // ======================================================================= 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs ) 102*cdf0e10cSrcweir { 103*cdf0e10cSrcweir FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont()); 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir Point aNewPos( 0, 0 ); 106*cdf0e10cSrcweir int nOldGlyphId = -1; 107*cdf0e10cSrcweir int nGlyphWidth = 0; 108*cdf0e10cSrcweir GlyphItem aPrevItem; 109*cdf0e10cSrcweir bool bRightToLeft; 110*cdf0e10cSrcweir for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); ) 111*cdf0e10cSrcweir { 112*cdf0e10cSrcweir sal_UCS4 cChar = rArgs.mpStr[ nCharPos ]; 113*cdf0e10cSrcweir if( (cChar >= 0xD800) && (cChar <= 0xDFFF) ) 114*cdf0e10cSrcweir { 115*cdf0e10cSrcweir if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed 116*cdf0e10cSrcweir continue; 117*cdf0e10cSrcweir cChar = 0x10000 + ((cChar - 0xD800) << 10) 118*cdf0e10cSrcweir + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00); 119*cdf0e10cSrcweir } 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir if( bRightToLeft ) 122*cdf0e10cSrcweir cChar = GetMirroredChar( cChar ); 123*cdf0e10cSrcweir int nGlyphIndex = rFont.GetGlyphIndex( cChar ); 124*cdf0e10cSrcweir // when glyph fallback is needed update LayoutArgs 125*cdf0e10cSrcweir if( !nGlyphIndex ) { 126*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRightToLeft ); 127*cdf0e10cSrcweir if( cChar >= 0x10000 ) // handle surrogate pairs 128*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRightToLeft ); 129*cdf0e10cSrcweir } 130*cdf0e10cSrcweir 131*cdf0e10cSrcweir // apply pair kerning to prev glyph if requested 132*cdf0e10cSrcweir if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags ) 133*cdf0e10cSrcweir { 134*cdf0e10cSrcweir int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, nGlyphIndex ); 135*cdf0e10cSrcweir nGlyphWidth += nKernValue; 136*cdf0e10cSrcweir aPrevItem.mnNewWidth = nGlyphWidth; 137*cdf0e10cSrcweir } 138*cdf0e10cSrcweir 139*cdf0e10cSrcweir // finish previous glyph 140*cdf0e10cSrcweir if( nOldGlyphId >= 0 ) 141*cdf0e10cSrcweir rLayout.AppendGlyph( aPrevItem ); 142*cdf0e10cSrcweir aNewPos.X() += nGlyphWidth; 143*cdf0e10cSrcweir 144*cdf0e10cSrcweir // prepare GlyphItem for appending it in next round 145*cdf0e10cSrcweir nOldGlyphId = nGlyphIndex; 146*cdf0e10cSrcweir const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex ); 147*cdf0e10cSrcweir nGlyphWidth = rGM.GetCharWidth(); 148*cdf0e10cSrcweir int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0; 149*cdf0e10cSrcweir aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); 150*cdf0e10cSrcweir } 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir // append last glyph item if any 153*cdf0e10cSrcweir if( nOldGlyphId >= 0 ) 154*cdf0e10cSrcweir rLayout.AppendGlyph( aPrevItem ); 155*cdf0e10cSrcweir 156*cdf0e10cSrcweir return true; 157*cdf0e10cSrcweir } 158*cdf0e10cSrcweir 159*cdf0e10cSrcweir // ======================================================================= 160*cdf0e10cSrcweir // bridge to ICU LayoutEngine 161*cdf0e10cSrcweir // ======================================================================= 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir #ifdef ENABLE_ICU_LAYOUT 164*cdf0e10cSrcweir 165*cdf0e10cSrcweir #define bool_t signed char 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir // disable warnings in icu layout headers 168*cdf0e10cSrcweir #if defined __SUNPRO_CC 169*cdf0e10cSrcweir #pragma disable_warn 170*cdf0e10cSrcweir #endif 171*cdf0e10cSrcweir 172*cdf0e10cSrcweir #include <layout/LayoutEngine.h> 173*cdf0e10cSrcweir #include <layout/LEFontInstance.h> 174*cdf0e10cSrcweir #include <layout/LEScripts.h> 175*cdf0e10cSrcweir 176*cdf0e10cSrcweir // enable warnings again 177*cdf0e10cSrcweir #if defined __SUNPRO_CC 178*cdf0e10cSrcweir #pragma enable_warn 179*cdf0e10cSrcweir #endif 180*cdf0e10cSrcweir 181*cdf0e10cSrcweir #include <unicode/uscript.h> 182*cdf0e10cSrcweir #include <unicode/ubidi.h> 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir using namespace U_ICU_NAMESPACE; 185*cdf0e10cSrcweir 186*cdf0e10cSrcweir static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF; 187*cdf0e10cSrcweir static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE; 188*cdf0e10cSrcweir 189*cdf0e10cSrcweir // ----------------------------------------------------------------------- 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir class IcuFontFromServerFont 192*cdf0e10cSrcweir : public LEFontInstance 193*cdf0e10cSrcweir { 194*cdf0e10cSrcweir private: 195*cdf0e10cSrcweir FreetypeServerFont& mrServerFont; 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir public: 198*cdf0e10cSrcweir IcuFontFromServerFont( FreetypeServerFont& rFont ) 199*cdf0e10cSrcweir : mrServerFont( rFont ) 200*cdf0e10cSrcweir {} 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir virtual const void* getFontTable(LETag tableTag) const; 203*cdf0e10cSrcweir virtual le_int32 getUnitsPerEM() const; 204*cdf0e10cSrcweir virtual float getXPixelsPerEm() const; 205*cdf0e10cSrcweir virtual float getYPixelsPerEm() const; 206*cdf0e10cSrcweir virtual float getScaleFactorX() const; 207*cdf0e10cSrcweir virtual float getScaleFactorY() const; 208*cdf0e10cSrcweir 209*cdf0e10cSrcweir using LEFontInstance::mapCharToGlyph; 210*cdf0e10cSrcweir virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const; 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir virtual le_int32 getAscent() const; 213*cdf0e10cSrcweir virtual le_int32 getDescent() const; 214*cdf0e10cSrcweir virtual le_int32 getLeading() const; 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const; 217*cdf0e10cSrcweir virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const; 218*cdf0e10cSrcweir }; 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir // ----------------------------------------------------------------------- 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const 223*cdf0e10cSrcweir { 224*cdf0e10cSrcweir char pTagName[5]; 225*cdf0e10cSrcweir pTagName[0] = (char)(nICUTableTag >> 24); 226*cdf0e10cSrcweir pTagName[1] = (char)(nICUTableTag >> 16); 227*cdf0e10cSrcweir pTagName[2] = (char)(nICUTableTag >> 8); 228*cdf0e10cSrcweir pTagName[3] = (char)(nICUTableTag); 229*cdf0e10cSrcweir pTagName[4] = 0; 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir sal_uLong nLength; 232*cdf0e10cSrcweir const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength ); 233*cdf0e10cSrcweir #ifdef VERBOSE_DEBUG 234*cdf0e10cSrcweir fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer); 235*cdf0e10cSrcweir int mnHeight = mrServerFont.GetFontSelData().mnHeight; 236*cdf0e10cSrcweir const char* pName = mrServerFont.GetFontFileName()->getStr(); 237*cdf0e10cSrcweir fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName ); 238*cdf0e10cSrcweir #endif 239*cdf0e10cSrcweir return (const void*)pBuffer; 240*cdf0e10cSrcweir } 241*cdf0e10cSrcweir 242*cdf0e10cSrcweir // ----------------------------------------------------------------------- 243*cdf0e10cSrcweir 244*cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getUnitsPerEM() const 245*cdf0e10cSrcweir { 246*cdf0e10cSrcweir return mrServerFont.GetEmUnits(); 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir 249*cdf0e10cSrcweir // ----------------------------------------------------------------------- 250*cdf0e10cSrcweir 251*cdf0e10cSrcweir float IcuFontFromServerFont::getXPixelsPerEm() const 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir const ImplFontSelectData& r = mrServerFont.GetFontSelData(); 254*cdf0e10cSrcweir float fX = r.mnWidth ? r.mnWidth : r.mnHeight; 255*cdf0e10cSrcweir return fX; 256*cdf0e10cSrcweir } 257*cdf0e10cSrcweir 258*cdf0e10cSrcweir // ----------------------------------------------------------------------- 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir float IcuFontFromServerFont::getYPixelsPerEm() const 261*cdf0e10cSrcweir { 262*cdf0e10cSrcweir float fY = mrServerFont.GetFontSelData().mnHeight; 263*cdf0e10cSrcweir return fY; 264*cdf0e10cSrcweir } 265*cdf0e10cSrcweir 266*cdf0e10cSrcweir // ----------------------------------------------------------------------- 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir float IcuFontFromServerFont::getScaleFactorX() const 269*cdf0e10cSrcweir { 270*cdf0e10cSrcweir return 1.0; 271*cdf0e10cSrcweir } 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // ----------------------------------------------------------------------- 274*cdf0e10cSrcweir 275*cdf0e10cSrcweir float IcuFontFromServerFont::getScaleFactorY() const 276*cdf0e10cSrcweir { 277*cdf0e10cSrcweir return 1.0; 278*cdf0e10cSrcweir } 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir // ----------------------------------------------------------------------- 281*cdf0e10cSrcweir 282*cdf0e10cSrcweir LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const 283*cdf0e10cSrcweir { 284*cdf0e10cSrcweir LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch ); 285*cdf0e10cSrcweir return nGlyphIndex; 286*cdf0e10cSrcweir } 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir // ----------------------------------------------------------------------- 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getAscent() const 291*cdf0e10cSrcweir { 292*cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 293*cdf0e10cSrcweir le_int32 nAscent = (+rMetrics.ascender + 32) >> 6; 294*cdf0e10cSrcweir return nAscent; 295*cdf0e10cSrcweir } 296*cdf0e10cSrcweir 297*cdf0e10cSrcweir // ----------------------------------------------------------------------- 298*cdf0e10cSrcweir 299*cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getDescent() const 300*cdf0e10cSrcweir { 301*cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 302*cdf0e10cSrcweir le_int32 nDescent = (-rMetrics.descender + 32) >> 6; 303*cdf0e10cSrcweir return nDescent; 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir // ----------------------------------------------------------------------- 307*cdf0e10cSrcweir 308*cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getLeading() const 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 311*cdf0e10cSrcweir le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6; 312*cdf0e10cSrcweir return nLeading; 313*cdf0e10cSrcweir } 314*cdf0e10cSrcweir 315*cdf0e10cSrcweir // ----------------------------------------------------------------------- 316*cdf0e10cSrcweir 317*cdf0e10cSrcweir void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex, 318*cdf0e10cSrcweir LEPoint &advance ) const 319*cdf0e10cSrcweir { 320*cdf0e10cSrcweir if( (nGlyphIndex == ICU_MARKED_GLYPH) 321*cdf0e10cSrcweir || (nGlyphIndex == ICU_DELETED_GLYPH) ) 322*cdf0e10cSrcweir { 323*cdf0e10cSrcweir // deleted glyph or mark glyph has not advance 324*cdf0e10cSrcweir advance.fX = 0; 325*cdf0e10cSrcweir } 326*cdf0e10cSrcweir else 327*cdf0e10cSrcweir { 328*cdf0e10cSrcweir const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex ); 329*cdf0e10cSrcweir advance.fX = rGM.GetCharWidth(); 330*cdf0e10cSrcweir } 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir advance.fY = 0; 333*cdf0e10cSrcweir } 334*cdf0e10cSrcweir 335*cdf0e10cSrcweir // ----------------------------------------------------------------------- 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID, 338*cdf0e10cSrcweir le_int32 339*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 340*cdf0e10cSrcweir pointNumber 341*cdf0e10cSrcweir #endif 342*cdf0e10cSrcweir , 343*cdf0e10cSrcweir LEPoint& ) const 344*cdf0e10cSrcweir { 345*cdf0e10cSrcweir //TODO: replace dummy implementation 346*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 347*cdf0e10cSrcweir fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber ); 348*cdf0e10cSrcweir #endif 349*cdf0e10cSrcweir return false; 350*cdf0e10cSrcweir } 351*cdf0e10cSrcweir 352*cdf0e10cSrcweir // ======================================================================= 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir class IcuLayoutEngine : public ServerFontLayoutEngine 355*cdf0e10cSrcweir { 356*cdf0e10cSrcweir private: 357*cdf0e10cSrcweir IcuFontFromServerFont maIcuFont; 358*cdf0e10cSrcweir 359*cdf0e10cSrcweir le_int32 meScriptCode; 360*cdf0e10cSrcweir LayoutEngine* mpIcuLE; 361*cdf0e10cSrcweir 362*cdf0e10cSrcweir public: 363*cdf0e10cSrcweir IcuLayoutEngine( FreetypeServerFont& ); 364*cdf0e10cSrcweir virtual ~IcuLayoutEngine(); 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& ); 367*cdf0e10cSrcweir }; 368*cdf0e10cSrcweir 369*cdf0e10cSrcweir // ----------------------------------------------------------------------- 370*cdf0e10cSrcweir 371*cdf0e10cSrcweir IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont ) 372*cdf0e10cSrcweir : maIcuFont( rServerFont ), 373*cdf0e10cSrcweir meScriptCode( USCRIPT_INVALID_CODE ), 374*cdf0e10cSrcweir mpIcuLE( NULL ) 375*cdf0e10cSrcweir {} 376*cdf0e10cSrcweir 377*cdf0e10cSrcweir // ----------------------------------------------------------------------- 378*cdf0e10cSrcweir 379*cdf0e10cSrcweir IcuLayoutEngine::~IcuLayoutEngine() 380*cdf0e10cSrcweir { 381*cdf0e10cSrcweir if( mpIcuLE ) 382*cdf0e10cSrcweir delete mpIcuLE; 383*cdf0e10cSrcweir } 384*cdf0e10cSrcweir 385*cdf0e10cSrcweir // ----------------------------------------------------------------------- 386*cdf0e10cSrcweir 387*cdf0e10cSrcweir static bool lcl_CharIsJoiner(sal_Unicode cChar) 388*cdf0e10cSrcweir { 389*cdf0e10cSrcweir return ((cChar == 0x200C) || (cChar == 0x200D)); 390*cdf0e10cSrcweir } 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs ) 393*cdf0e10cSrcweir { 394*cdf0e10cSrcweir LEUnicode* pIcuChars; 395*cdf0e10cSrcweir if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) ) 396*cdf0e10cSrcweir pIcuChars = (LEUnicode*)rArgs.mpStr; 397*cdf0e10cSrcweir else 398*cdf0e10cSrcweir { 399*cdf0e10cSrcweir // this conversion will only be needed when either 400*cdf0e10cSrcweir // ICU's or OOo's unicodes stop being unsigned shorts 401*cdf0e10cSrcweir // TODO: watch out for surrogates! 402*cdf0e10cSrcweir pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) ); 403*cdf0e10cSrcweir for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic ) 404*cdf0e10cSrcweir pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] ); 405*cdf0e10cSrcweir } 406*cdf0e10cSrcweir 407*cdf0e10cSrcweir // allocate temporary arrays, note: round to even 408*cdf0e10cSrcweir int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1; 409*cdf0e10cSrcweir 410*cdf0e10cSrcweir struct IcuPosition{ float fX, fY; }; 411*cdf0e10cSrcweir const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition); 412*cdf0e10cSrcweir LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) ); 413*cdf0e10cSrcweir le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) ); 414*cdf0e10cSrcweir IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) ); 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont()); 417*cdf0e10cSrcweir 418*cdf0e10cSrcweir UErrorCode rcI18n = U_ZERO_ERROR; 419*cdf0e10cSrcweir LEErrorCode rcIcu = LE_NO_ERROR; 420*cdf0e10cSrcweir Point aNewPos( 0, 0 ); 421*cdf0e10cSrcweir for( int nGlyphCount = 0;; ) 422*cdf0e10cSrcweir { 423*cdf0e10cSrcweir int nMinRunPos, nEndRunPos; 424*cdf0e10cSrcweir bool bRightToLeft; 425*cdf0e10cSrcweir if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) ) 426*cdf0e10cSrcweir break; 427*cdf0e10cSrcweir 428*cdf0e10cSrcweir // find matching script 429*cdf0e10cSrcweir // TODO: split up bidi run into script runs 430*cdf0e10cSrcweir le_int32 eScriptCode = -1; 431*cdf0e10cSrcweir for( int i = nMinRunPos; i < nEndRunPos; ++i ) 432*cdf0e10cSrcweir { 433*cdf0e10cSrcweir eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n ); 434*cdf0e10cSrcweir if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) ) 435*cdf0e10cSrcweir break; 436*cdf0e10cSrcweir } 437*cdf0e10cSrcweir if( eScriptCode < 0 ) // TODO: handle errors better 438*cdf0e10cSrcweir eScriptCode = latnScriptCode; 439*cdf0e10cSrcweir 440*cdf0e10cSrcweir // get layout engine matching to this script 441*cdf0e10cSrcweir // no engine change necessary if script is latin 442*cdf0e10cSrcweir if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) ) 443*cdf0e10cSrcweir { 444*cdf0e10cSrcweir // TODO: cache multiple layout engines when multiple scripts are used 445*cdf0e10cSrcweir delete mpIcuLE; 446*cdf0e10cSrcweir meScriptCode = eScriptCode; 447*cdf0e10cSrcweir le_int32 eLangCode = 0; // TODO: get better value 448*cdf0e10cSrcweir mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu ); 449*cdf0e10cSrcweir if( LE_FAILURE(rcIcu) ) 450*cdf0e10cSrcweir { 451*cdf0e10cSrcweir delete mpIcuLE; 452*cdf0e10cSrcweir mpIcuLE = NULL; 453*cdf0e10cSrcweir } 454*cdf0e10cSrcweir } 455*cdf0e10cSrcweir 456*cdf0e10cSrcweir // fall back to default layout if needed 457*cdf0e10cSrcweir if( !mpIcuLE ) 458*cdf0e10cSrcweir break; 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir // run ICU layout engine 461*cdf0e10cSrcweir // TODO: get enough context, remove extra glyps below 462*cdf0e10cSrcweir int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars, 463*cdf0e10cSrcweir nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength, 464*cdf0e10cSrcweir bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu ); 465*cdf0e10cSrcweir if( LE_FAILURE(rcIcu) ) 466*cdf0e10cSrcweir return false; 467*cdf0e10cSrcweir 468*cdf0e10cSrcweir // import layout info from icu 469*cdf0e10cSrcweir mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu ); 470*cdf0e10cSrcweir mpIcuLE->getCharIndices( pCharIndices, rcIcu ); 471*cdf0e10cSrcweir mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu ); 472*cdf0e10cSrcweir mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed 473*cdf0e10cSrcweir if( LE_FAILURE(rcIcu) ) 474*cdf0e10cSrcweir return false; 475*cdf0e10cSrcweir 476*cdf0e10cSrcweir // layout bidi/script runs and export them to a ServerFontLayout 477*cdf0e10cSrcweir // convert results to GlyphItems 478*cdf0e10cSrcweir int nLastCharPos = -1; 479*cdf0e10cSrcweir int nClusterMinPos = -1; 480*cdf0e10cSrcweir int nClusterMaxPos = -1; 481*cdf0e10cSrcweir bool bClusterStart = true; 482*cdf0e10cSrcweir int nFilteredRunGlyphCount = 0; 483*cdf0e10cSrcweir const IcuPosition* pPos = pGlyphPositions; 484*cdf0e10cSrcweir for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos ) 485*cdf0e10cSrcweir { 486*cdf0e10cSrcweir LEGlyphID nGlyphIndex = pIcuGlyphs[i]; 487*cdf0e10cSrcweir // ignore glyphs which were marked or deleted by ICU 488*cdf0e10cSrcweir if( (nGlyphIndex == ICU_MARKED_GLYPH) 489*cdf0e10cSrcweir || (nGlyphIndex == ICU_DELETED_GLYPH) ) 490*cdf0e10cSrcweir continue; 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir // adjust the relative char pos 493*cdf0e10cSrcweir int nCharPos = pCharIndices[i]; 494*cdf0e10cSrcweir if( nCharPos >= 0 ) { 495*cdf0e10cSrcweir nCharPos += nMinRunPos; 496*cdf0e10cSrcweir // ICU seems to return bad pCharIndices 497*cdf0e10cSrcweir // for some combinations of ICU+font+text 498*cdf0e10cSrcweir // => better give up now than crash later 499*cdf0e10cSrcweir if( nCharPos >= nEndRunPos ) 500*cdf0e10cSrcweir continue; 501*cdf0e10cSrcweir } 502*cdf0e10cSrcweir 503*cdf0e10cSrcweir // if needed request glyph fallback by updating LayoutArgs 504*cdf0e10cSrcweir if( !nGlyphIndex ) 505*cdf0e10cSrcweir { 506*cdf0e10cSrcweir if( nCharPos >= 0 ) 507*cdf0e10cSrcweir { 508*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRightToLeft ); 509*cdf0e10cSrcweir if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) ) 510*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos-1, bRightToLeft ); 511*cdf0e10cSrcweir else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) ) 512*cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRightToLeft ); 513*cdf0e10cSrcweir } 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags ) 516*cdf0e10cSrcweir continue; 517*cdf0e10cSrcweir } 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir 520*cdf0e10cSrcweir // apply vertical flags, etc. 521*cdf0e10cSrcweir bool bDiacritic = false; 522*cdf0e10cSrcweir if( nCharPos >= 0 ) 523*cdf0e10cSrcweir { 524*cdf0e10cSrcweir sal_UCS4 aChar = rArgs.mpStr[ nCharPos ]; 525*cdf0e10cSrcweir #if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0 526*cdf0e10cSrcweir if( (aChar >= 0xD800) && (aChar <= 0xDFFF) ) 527*cdf0e10cSrcweir { 528*cdf0e10cSrcweir if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed 529*cdf0e10cSrcweir continue; 530*cdf0e10cSrcweir // calculate unicode scalar value of surrogate pair 531*cdf0e10cSrcweir aChar = 0x10000 + ((aChar - 0xD800) << 10); 532*cdf0e10cSrcweir sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ]; 533*cdf0e10cSrcweir aChar += aLow & 0x03FF; 534*cdf0e10cSrcweir } 535*cdf0e10cSrcweir #endif 536*cdf0e10cSrcweir nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar ); 537*cdf0e10cSrcweir 538*cdf0e10cSrcweir // #i99367# HACK: try to detect all diacritics 539*cdf0e10cSrcweir if( aChar>=0x0300 && aChar<0x2100 ) 540*cdf0e10cSrcweir bDiacritic = IsDiacritic( aChar ); 541*cdf0e10cSrcweir } 542*cdf0e10cSrcweir 543*cdf0e10cSrcweir // get glyph position and its metrics 544*cdf0e10cSrcweir aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); 545*cdf0e10cSrcweir const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex ); 546*cdf0e10cSrcweir int nGlyphWidth = rGM.GetCharWidth(); 547*cdf0e10cSrcweir if( nGlyphWidth <= 0 ) 548*cdf0e10cSrcweir bDiacritic |= true; 549*cdf0e10cSrcweir // #i99367# force all diacritics to zero width 550*cdf0e10cSrcweir // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth 551*cdf0e10cSrcweir else if( bDiacritic ) 552*cdf0e10cSrcweir nGlyphWidth = 0; 553*cdf0e10cSrcweir 554*cdf0e10cSrcweir // heuristic to detect glyph clusters 555*cdf0e10cSrcweir bool bInCluster = true; 556*cdf0e10cSrcweir if( nLastCharPos == -1 ) 557*cdf0e10cSrcweir { 558*cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos; 559*cdf0e10cSrcweir bInCluster = false; 560*cdf0e10cSrcweir } 561*cdf0e10cSrcweir else if( !bRightToLeft ) 562*cdf0e10cSrcweir { 563*cdf0e10cSrcweir // left-to-right case 564*cdf0e10cSrcweir if( nClusterMinPos > nCharPos ) 565*cdf0e10cSrcweir nClusterMinPos = nCharPos; // extend cluster 566*cdf0e10cSrcweir else if( nCharPos <= nClusterMaxPos ) 567*cdf0e10cSrcweir /*NOTHING*/; // inside cluster 568*cdf0e10cSrcweir else if( bDiacritic ) 569*cdf0e10cSrcweir nClusterMaxPos = nCharPos; // add diacritic to cluster 570*cdf0e10cSrcweir else { 571*cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster 572*cdf0e10cSrcweir bInCluster = false; 573*cdf0e10cSrcweir } 574*cdf0e10cSrcweir } 575*cdf0e10cSrcweir else 576*cdf0e10cSrcweir { 577*cdf0e10cSrcweir // right-to-left case 578*cdf0e10cSrcweir if( nClusterMaxPos < nCharPos ) 579*cdf0e10cSrcweir nClusterMaxPos = nCharPos; // extend cluster 580*cdf0e10cSrcweir else if( nCharPos >= nClusterMinPos ) 581*cdf0e10cSrcweir /*NOTHING*/; // inside cluster 582*cdf0e10cSrcweir else if( bDiacritic ) 583*cdf0e10cSrcweir { 584*cdf0e10cSrcweir nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*] 585*cdf0e10cSrcweir if( bClusterStart ) { 586*cdf0e10cSrcweir nClusterMaxPos = nCharPos; 587*cdf0e10cSrcweir bInCluster = false; 588*cdf0e10cSrcweir } 589*cdf0e10cSrcweir } 590*cdf0e10cSrcweir else 591*cdf0e10cSrcweir { 592*cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster 593*cdf0e10cSrcweir bInCluster = !bClusterStart; 594*cdf0e10cSrcweir } 595*cdf0e10cSrcweir } 596*cdf0e10cSrcweir 597*cdf0e10cSrcweir long nGlyphFlags = 0; 598*cdf0e10cSrcweir if( bInCluster ) 599*cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; 600*cdf0e10cSrcweir if( bRightToLeft ) 601*cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; 602*cdf0e10cSrcweir if( bDiacritic ) 603*cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_DIACRITIC; 604*cdf0e10cSrcweir 605*cdf0e10cSrcweir // add resulting glyph item to layout 606*cdf0e10cSrcweir const GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); 607*cdf0e10cSrcweir rLayout.AppendGlyph( aGI ); 608*cdf0e10cSrcweir ++nFilteredRunGlyphCount; 609*cdf0e10cSrcweir nLastCharPos = nCharPos; 610*cdf0e10cSrcweir bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath 611*cdf0e10cSrcweir } 612*cdf0e10cSrcweir aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); 613*cdf0e10cSrcweir nGlyphCount += nFilteredRunGlyphCount; 614*cdf0e10cSrcweir } 615*cdf0e10cSrcweir 616*cdf0e10cSrcweir // sort glyphs in visual order 617*cdf0e10cSrcweir // and then in logical order (e.g. diacritics after cluster start) 618*cdf0e10cSrcweir rLayout.SortGlyphItems(); 619*cdf0e10cSrcweir 620*cdf0e10cSrcweir // determine need for kashida justification 621*cdf0e10cSrcweir if( (rArgs.mpDXArray || rArgs.mnLayoutWidth) 622*cdf0e10cSrcweir && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) ) 623*cdf0e10cSrcweir rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON; 624*cdf0e10cSrcweir 625*cdf0e10cSrcweir return true; 626*cdf0e10cSrcweir } 627*cdf0e10cSrcweir 628*cdf0e10cSrcweir #endif // ENABLE_ICU_LAYOUT 629*cdf0e10cSrcweir 630*cdf0e10cSrcweir // ======================================================================= 631*cdf0e10cSrcweir 632*cdf0e10cSrcweir ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine() 633*cdf0e10cSrcweir { 634*cdf0e10cSrcweir // find best layout engine for font, platform, script and language 635*cdf0e10cSrcweir #ifdef ENABLE_ICU_LAYOUT 636*cdf0e10cSrcweir if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) ) 637*cdf0e10cSrcweir mpLayoutEngine = new IcuLayoutEngine( *this ); 638*cdf0e10cSrcweir #endif // ENABLE_ICU_LAYOUT 639*cdf0e10cSrcweir 640*cdf0e10cSrcweir return mpLayoutEngine; 641*cdf0e10cSrcweir } 642*cdf0e10cSrcweir 643*cdf0e10cSrcweir // ======================================================================= 644*cdf0e10cSrcweir 645