LCOV - code coverage report
Current view: top level - vcl/generic/glyphs - gcach_layout.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 218 256 85.2 %
Date: 2012-08-25 Functions: 23 27 85.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 147 238 61.8 %

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

Generated by: LCOV version 1.10