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