LCOV - code coverage report
Current view: top level - vcl/generic/glyphs - gcach_layout.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 189 229 82.5 %
Date: 2014-04-11 Functions: 21 27 77.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <gcach_ftyp.hxx>
      21             : #include <sallayout.hxx>
      22             : #include <salgdi.hxx>
      23             : #include <scrptrun.h>
      24             : 
      25             : #include <boost/static_assert.hpp>
      26             : 
      27             : #include <i18nlangtag/mslangid.hxx>
      28             : 
      29             : #include <vcl/svapp.hxx>
      30             : 
      31             : #include <sal/alloca.h>
      32             : #include <rtl/instance.hxx>
      33             : 
      34             : #include <hb-icu.h>
      35             : #include <hb-ot.h>
      36             : 
      37             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      38             : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
      39             : #include <comphelper/processfactory.hxx>
      40             : 
      41             : // layout implementation for ServerFont
      42             : 
      43      937518 : ServerFontLayout::ServerFontLayout( ServerFont& rFont )
      44      937518 : :   mrServerFont( rFont )
      45      937518 : { }
      46             : 
      47      144873 : void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
      48             : {
      49      144873 :     rSalGraphics.DrawServerFontLayout( *this );
      50      144873 : }
      51             : 
      52      937518 : bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
      53             : {
      54      937518 :     return mrServerFont.GetLayoutEngine()->layout(*this, rArgs);
      55             : }
      56             : 
      57      938650 : void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
      58             : {
      59      938650 :     GenericSalLayout::AdjustLayout( rArgs );
      60             : 
      61             :     // apply asian kerning if the glyphs are not already formatted
      62      938650 :     if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
      63           0 :     && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
      64           0 :         if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
      65           0 :             ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
      66             : 
      67             :     // insert kashidas where requested by the formatting array
      68      938650 :     if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
      69             :     {
      70           0 :         int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
      71           0 :         if( nKashidaIndex != 0 )
      72             :         {
      73           0 :             const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
      74           0 :             KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
      75             :             // TODO: kashida-GSUB/GPOS
      76             :         }
      77             :     }
      78      938650 : }
      79             : 
      80        1839 : void ServerFontLayout::setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos,
      81             :     bool bRightToLeft)
      82             : {
      83        1839 :     if (nCharPos < 0)
      84        1839 :         return;
      85             : 
      86             :     using namespace ::com::sun::star;
      87             : 
      88        1839 :     if (!mxBreak.is())
      89             :     {
      90             :         uno::Reference< lang::XMultiServiceFactory > xFactory =
      91        1722 :             comphelper::getProcessServiceFactory();
      92        5166 :         mxBreak = uno::Reference< i18n::XBreakIterator >(xFactory->createInstance(
      93        5166 :             "com.sun.star.i18n.BreakIterator"), uno::UNO_QUERY);
      94             :     }
      95             : 
      96        1839 :     lang::Locale aLocale(rArgs.maLanguageTag.getLocale());
      97             : 
      98             :     //if position nCharPos is missing in the font, grab the entire grapheme and
      99             :     //mark all glyphs as missing so the whole thing is rendered with the same
     100             :     //font
     101        3678 :     OUString aRun(rArgs.mpStr);
     102             :     sal_Int32 nDone;
     103             :     sal_Int32 nGraphemeStartPos =
     104        1839 :         mxBreak->previousCharacters(aRun, nCharPos+1, aLocale,
     105        1839 :             i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
     106             :     sal_Int32 nGraphemeEndPos =
     107        1839 :         mxBreak->nextCharacters(aRun, nCharPos, aLocale,
     108        1839 :             i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
     109             : 
     110        3678 :     rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft);
     111             : }
     112             : 
     113           0 : std::ostream &operator <<(std::ostream& s, ServerFont* pFont)
     114             : {
     115             : #ifndef SAL_LOG_INFO
     116             :     (void) pFont;
     117             : #else
     118             :     FT_Face aFace = pFont->GetFtFace();
     119             :     const char* pName = FT_Get_Postscript_Name(aFace);
     120             :     if (pName)
     121             :         s << pName;
     122             :     else
     123             :         s << pFont->GetFontFileName();
     124             : #endif
     125           0 :     return s;
     126             : }
     127             : 
     128       11312 : static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData)
     129             : {
     130             :     char pTagName[5];
     131       11312 :     pTagName[0] = (char)(nTableTag >> 24);
     132       11312 :     pTagName[1] = (char)(nTableTag >> 16);
     133       11312 :     pTagName[2] = (char)(nTableTag >>  8);
     134       11312 :     pTagName[3] = (char)(nTableTag);
     135       11312 :     pTagName[4] = 0;
     136             : 
     137       11312 :     ServerFont* pFont = (ServerFont*) pUserData;
     138             : 
     139             :     SAL_INFO("vcl.harfbuzz", "getFontTable(" << pFont << ", " << pTagName << ")");
     140             : 
     141             :     sal_uLong nLength;
     142       11312 :     const unsigned char* pBuffer = pFont->GetTable(pTagName, &nLength);
     143             : 
     144       11312 :     hb_blob_t* pBlob = NULL;
     145       11312 :     if (pBuffer != NULL)
     146        8165 :         pBlob = hb_blob_create((const char*) pBuffer, nLength, HB_MEMORY_MODE_READONLY, (void*) pBuffer, NULL);
     147             : 
     148       11312 :     return pBlob;
     149             : }
     150             : 
     151    15105959 : static hb_bool_t getFontGlyph(hb_font_t* /*font*/, void* pFontData,
     152             :         hb_codepoint_t ch, hb_codepoint_t vs,
     153             :         hb_codepoint_t* nGlyphIndex,
     154             :         void* /*pUserData*/)
     155             : {
     156    15105959 :     ServerFont* pFont = (ServerFont*) pFontData;
     157    15105959 :     *nGlyphIndex = pFont->GetRawGlyphIndex(ch, vs);
     158             : 
     159    15105959 :     return *nGlyphIndex != 0;
     160             : }
     161             : 
     162    15089817 : static hb_position_t getGlyphAdvanceH(hb_font_t* /*font*/, void* pFontData,
     163             :         hb_codepoint_t nGlyphIndex,
     164             :         void* /*pUserData*/)
     165             : {
     166    15089817 :     ServerFont* pFont = (ServerFont*) pFontData;
     167    15089817 :     const GlyphMetric& rGM = pFont->GetGlyphMetric(nGlyphIndex);
     168    15089817 :     return rGM.GetCharWidth() << 6;
     169             : }
     170             : 
     171           0 : static hb_position_t getGlyphAdvanceV(hb_font_t* /*font*/, void* /*pFontData*/,
     172             :         hb_codepoint_t /*nGlyphIndex*/,
     173             :         void* /*pUserData*/)
     174             : {
     175             :     // XXX: vertical metrics
     176           0 :     return 0;
     177             : }
     178             : 
     179    44879197 : static hb_bool_t getGlyphOriginH(hb_font_t* /*font*/, void* /*pFontData*/,
     180             :         hb_codepoint_t /*nGlyphIndex*/,
     181             :         hb_position_t* /*x*/, hb_position_t* /*y*/,
     182             :         void* /*pUserData*/)
     183             : {
     184             :     // the horizontal origin is always (0, 0)
     185    44879197 :     return true;
     186             : }
     187             : 
     188           0 : static hb_bool_t getGlyphOriginV(hb_font_t* /*font*/, void* /*pFontData*/,
     189             :         hb_codepoint_t /*nGlyphIndex*/,
     190             :         hb_position_t* /*x*/, hb_position_t* /*y*/,
     191             :         void* /*pUserData*/)
     192             : {
     193             :     // XXX: vertical origin
     194           0 :     return true;
     195             : }
     196             : 
     197      187660 : static hb_position_t getGlyphKerningH(hb_font_t* /*font*/, void* pFontData,
     198             :         hb_codepoint_t nGlyphIndex1, hb_codepoint_t nGlyphIndex2,
     199             :         void* /*pUserData*/)
     200             : {
     201             :     // This callback is for old style 'kern' table, GPOS kerning is handled by HarfBuzz directly
     202             : 
     203      187660 :     ServerFont* pFont = (ServerFont*) pFontData;
     204      187660 :     FT_Face aFace = pFont->GetFtFace();
     205             : 
     206             :     SAL_INFO("vcl.harfbuzz", "getGlyphKerningH(" << pFont << ", " << nGlyphIndex1 << ", " << nGlyphIndex2 << ")");
     207             : 
     208             :     FT_Error error;
     209             :     FT_Vector kerning;
     210             :     hb_position_t ret;
     211             : 
     212      187660 :     error = FT_Get_Kerning(aFace, nGlyphIndex1, nGlyphIndex2, FT_KERNING_DEFAULT, &kerning);
     213      187660 :     if (error)
     214           0 :         ret = 0;
     215             :     else
     216      187660 :         ret = kerning.x;
     217             : 
     218      187660 :     return ret;
     219             : }
     220             : 
     221           0 : static hb_position_t getGlyphKerningV(hb_font_t* /*font*/, void* /*pFontData*/,
     222             :         hb_codepoint_t /*nGlyphIndex1*/, hb_codepoint_t /*nGlyphIndex2*/,
     223             :         void* /*pUserData*/)
     224             : {
     225             :     // XXX vertical kerning
     226           0 :     return 0;
     227             : }
     228             : 
     229           0 : static hb_bool_t getGlyphExtents(hb_font_t* /*font*/, void* pFontData,
     230             :         hb_codepoint_t nGlyphIndex,
     231             :         hb_glyph_extents_t* pExtents,
     232             :         void* /*pUserData*/)
     233             : {
     234           0 :     ServerFont* pFont = (ServerFont*) pFontData;
     235           0 :     FT_Face aFace = pFont->GetFtFace();
     236             : 
     237             :     SAL_INFO("vcl.harfbuzz", "getGlyphExtents(" << pFont << ", " << nGlyphIndex << ")");
     238             : 
     239             :     FT_Error error;
     240           0 :     error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
     241           0 :     if (!error)
     242             :     {
     243           0 :         pExtents->x_bearing = aFace->glyph->metrics.horiBearingX;
     244           0 :         pExtents->y_bearing = aFace->glyph->metrics.horiBearingY;
     245           0 :         pExtents->width  =  aFace->glyph->metrics.width;
     246           0 :         pExtents->height = -aFace->glyph->metrics.height;
     247             :     }
     248             : 
     249           0 :     return !error;
     250             : }
     251             : 
     252           0 : static hb_bool_t getGlyphContourPoint(hb_font_t* /*font*/, void* pFontData,
     253             :         hb_codepoint_t nGlyphIndex, unsigned int nPointIndex,
     254             :         hb_position_t *x, hb_position_t *y,
     255             :         void* /*pUserData*/)
     256             : {
     257           0 :     bool ret = false;
     258           0 :     ServerFont* pFont = (ServerFont*) pFontData;
     259           0 :     FT_Face aFace = pFont->GetFtFace();
     260             : 
     261             :     SAL_INFO("vcl.harfbuzz", "getGlyphContourPoint(" << pFont << ", " << nGlyphIndex << ", " << nPointIndex << ")");
     262             : 
     263             :     FT_Error error;
     264           0 :     error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
     265           0 :     if (!error)
     266             :     {
     267           0 :         if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
     268             :         {
     269           0 :             if (nPointIndex < (unsigned int) aFace->glyph->outline.n_points)
     270             :             {
     271           0 :                 *x = aFace->glyph->outline.points[nPointIndex].x;
     272           0 :                 *y = aFace->glyph->outline.points[nPointIndex].y;
     273           0 :                 ret = true;
     274             :             }
     275             :         }
     276             :     }
     277             : 
     278           0 :     return ret;
     279             : }
     280             : 
     281          82 : static hb_font_funcs_t* getFontFuncs(void)
     282             : {
     283          82 :     static hb_font_funcs_t* funcs = hb_font_funcs_create();
     284             : 
     285          82 :     hb_font_funcs_set_glyph_func                (funcs, getFontGlyph, NULL, NULL);
     286          82 :     hb_font_funcs_set_glyph_h_advance_func      (funcs, getGlyphAdvanceH, NULL, NULL);
     287          82 :     hb_font_funcs_set_glyph_v_advance_func      (funcs, getGlyphAdvanceV, NULL, NULL);
     288          82 :     hb_font_funcs_set_glyph_h_origin_func       (funcs, getGlyphOriginH, NULL, NULL);
     289          82 :     hb_font_funcs_set_glyph_v_origin_func       (funcs, getGlyphOriginV, NULL, NULL);
     290          82 :     hb_font_funcs_set_glyph_h_kerning_func      (funcs, getGlyphKerningH, NULL, NULL);
     291          82 :     hb_font_funcs_set_glyph_v_kerning_func      (funcs, getGlyphKerningV, NULL, NULL);
     292          82 :     hb_font_funcs_set_glyph_extents_func        (funcs, getGlyphExtents, NULL, NULL);
     293          82 :     hb_font_funcs_set_glyph_contour_point_func  (funcs, getGlyphContourPoint, NULL, NULL);
     294             : 
     295          82 :     return funcs;
     296             : }
     297             : 
     298             : // Disabled Unicode compatibility decomposition, see fdo#66715
     299        1839 : static unsigned int unicodeDecomposeCompatibility(hb_unicode_funcs_t* /*ufuncs*/,
     300             :                                                   hb_codepoint_t      /*u*/,
     301             :                                                   hb_codepoint_t*     /*decomposed*/,
     302             :                                                   void*               /*user_data*/)
     303             : {
     304        1839 :     return 0;
     305             : }
     306             : 
     307          82 : static hb_unicode_funcs_t* getUnicodeFuncs(void)
     308             : {
     309          82 :     static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
     310          82 :     hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, NULL, NULL);
     311          82 :     return ufuncs;
     312             : }
     313             : 
     314             : class HbLayoutEngine : public ServerFontLayoutEngine
     315             : {
     316             : private:
     317             :     hb_script_t             maHbScript;
     318             :     hb_face_t*              mpHbFace;
     319             :     int                     mnUnitsPerEM;
     320             : 
     321             : public:
     322             :                             HbLayoutEngine(ServerFont&);
     323             :     virtual                 ~HbLayoutEngine();
     324             : 
     325             :     virtual bool            layout(ServerFontLayout&, ImplLayoutArgs&) SAL_OVERRIDE;
     326             : };
     327             : 
     328        2833 : HbLayoutEngine::HbLayoutEngine(ServerFont& rServerFont)
     329             : :   maHbScript(HB_SCRIPT_INVALID),
     330             :     mpHbFace(NULL),
     331        2833 :     mnUnitsPerEM(0)
     332             : {
     333        2833 :     FT_Face aFtFace = rServerFont.GetFtFace();
     334        2833 :     mnUnitsPerEM = rServerFont.GetEmUnits();
     335             : 
     336        2833 :     mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, NULL);
     337        2833 :     hb_face_set_index(mpHbFace, aFtFace->face_index);
     338        2833 :     hb_face_set_upem(mpHbFace, mnUnitsPerEM);
     339        2833 : }
     340             : 
     341        8499 : HbLayoutEngine::~HbLayoutEngine()
     342             : {
     343        2833 :     hb_face_destroy(mpHbFace);
     344        5666 : }
     345             : 
     346             : struct HbScriptRun
     347             : {
     348             :     int32_t mnMin;
     349             :     int32_t mnEnd;
     350             :     hb_script_t maScript;
     351             : 
     352      925263 :     HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript)
     353             :     : mnMin(nMin), mnEnd(nEnd),
     354      925263 :       maScript(hb_icu_script_to_script(aScript))
     355      925263 :     {}
     356             : };
     357             : 
     358             : typedef std::vector<HbScriptRun> HbScriptRuns;
     359             : 
     360      937518 : bool HbLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
     361             : {
     362      937518 :     ServerFont& rFont = rLayout.GetServerFont();
     363      937518 :     FT_Face aFtFace = rFont.GetFtFace();
     364             : 
     365             :     SAL_INFO("vcl.harfbuzz", "layout(" << this << ",rArgs=" << rArgs << ")");
     366             : 
     367      937518 :     static hb_font_funcs_t* pHbFontFuncs = getFontFuncs();
     368             : 
     369      937518 :     hb_font_t *pHbFont = hb_font_create(mpHbFace);
     370      937518 :     hb_font_set_funcs(pHbFont, pHbFontFuncs, &rFont, NULL);
     371             :     hb_font_set_scale(pHbFont,
     372      937518 :             ((uint64_t) aFtFace->size->metrics.x_scale * (uint64_t) mnUnitsPerEM) >> 16,
     373     1875036 :             ((uint64_t) aFtFace->size->metrics.y_scale * (uint64_t) mnUnitsPerEM) >> 16);
     374      937518 :     hb_font_set_ppem(pHbFont, aFtFace->size->metrics.x_ppem, aFtFace->size->metrics.y_ppem);
     375             : 
     376             :     // allocate temporary arrays, note: round to even
     377      937518 :     int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1;
     378             : 
     379      937518 :     rLayout.Reserve(nGlyphCapacity);
     380             : 
     381      937518 :     ScriptRun aScriptRun(reinterpret_cast<const UChar *>(rArgs.mpStr), rArgs.mnLength);
     382             : 
     383      937518 :     Point aCurrPos(0, 0);
     384             :     while (true)
     385             :     {
     386             :         int nBidiMinRunPos, nBidiEndRunPos;
     387             :         bool bRightToLeft;
     388     1862526 :         if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft))
     389      937518 :             break;
     390             : 
     391             :         // Find script subruns.
     392      925008 :         int nCurrentPos = nBidiMinRunPos;
     393      925008 :         HbScriptRuns aScriptSubRuns;
     394     1850372 :         while (aScriptRun.next())
     395             :         {
     396      925364 :             if (aScriptRun.getScriptStart() <= nCurrentPos && aScriptRun.getScriptEnd() > nCurrentPos)
     397      925008 :                 break;
     398             :         }
     399             : 
     400     2775279 :         while (nCurrentPos < nBidiEndRunPos)
     401             :         {
     402      925263 :             int32_t nMinRunPos = nCurrentPos;
     403      925263 :             int32_t nEndRunPos = std::min(aScriptRun.getScriptEnd(), nBidiEndRunPos);
     404      925263 :             HbScriptRun aRun(nMinRunPos, nEndRunPos, aScriptRun.getScriptCode());
     405      925263 :             aScriptSubRuns.push_back(aRun);
     406             : 
     407      925263 :             nCurrentPos = nEndRunPos;
     408      925263 :             aScriptRun.next();
     409             :         }
     410             : 
     411             :         // RTL subruns should be reversed to ensure that final glyph order is
     412             :         // correct.
     413      925008 :         if (bRightToLeft)
     414          54 :             std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end());
     415             : 
     416      925008 :         aScriptRun.reset();
     417             : 
     418     1850271 :         for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it)
     419             :         {
     420      925263 :             int nMinRunPos = it->mnMin;
     421      925263 :             int nEndRunPos = it->mnEnd;
     422      925263 :             int nRunLen = nEndRunPos - nMinRunPos;
     423      925263 :             maHbScript = it->maScript;
     424             : 
     425      925263 :             OString sLanguage = OUStringToOString(rArgs.maLanguageTag.getLanguage(), RTL_TEXTENCODING_UTF8);
     426             : 
     427      925263 :             static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
     428             : 
     429      925263 :             int nHbFlags = HB_BUFFER_FLAG_DEFAULT;
     430      925263 :             if (nMinRunPos == 0)
     431      758747 :                 nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */
     432      925263 :             if (nEndRunPos == rArgs.mnLength)
     433      804918 :                 nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */
     434             : 
     435      925263 :             hb_buffer_t *pHbBuffer = hb_buffer_create();
     436      925263 :             hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
     437      925263 :             hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
     438      925263 :             hb_buffer_set_script(pHbBuffer, maHbScript);
     439      925263 :             hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1));
     440      925263 :             hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags);
     441      925263 :             hb_buffer_add_utf16(pHbBuffer, rArgs.mpStr, rArgs.mnLength, nMinRunPos, nRunLen);
     442      925263 :             hb_shape(pHbFont, pHbBuffer, NULL, 0);
     443             : 
     444      925263 :             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
     445      925263 :             hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, NULL);
     446      925263 :             hb_glyph_position_t *pHbPositions = hb_buffer_get_glyph_positions(pHbBuffer, NULL);
     447             : 
     448    16015119 :             for (int i = 0; i < nRunGlyphCount; ++i) {
     449    15089856 :                 int32_t nGlyphIndex = pHbGlyphInfos[i].codepoint;
     450    15089856 :                 int32_t nCharPos = pHbGlyphInfos[i].cluster;
     451             : 
     452             :                 // if needed request glyph fallback by updating LayoutArgs
     453    15089856 :                 if (!nGlyphIndex)
     454             :                 {
     455        1839 :                     rLayout.setNeedFallback(rArgs, nCharPos, bRightToLeft);
     456        1839 :                     if (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)
     457        1026 :                         continue;
     458             :                 }
     459             : 
     460             :                 // apply vertical flags and glyph substitution
     461             :                 // XXX: Use HB_DIRECTION_TTB above and apply whatever flags magic
     462             :                 // FixupGlyphIndex() is doing, minus the GSUB part.
     463    15088830 :                 if (nCharPos >= 0)
     464             :                 {
     465    15088830 :                     sal_UCS4 aChar = rArgs.mpStr[nCharPos];
     466    15088830 :                     nGlyphIndex = rFont.FixupGlyphIndex(nGlyphIndex, aChar);
     467             :                 }
     468             : 
     469    15088830 :                 bool bInCluster = false;
     470    15088830 :                 if (i > 0 && pHbGlyphInfos[i].cluster == pHbGlyphInfos[i - 1].cluster)
     471           8 :                     bInCluster = true;
     472             : 
     473    15088830 :                 long nGlyphFlags = 0;
     474    15088830 :                 if (bRightToLeft)
     475         174 :                     nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
     476             : 
     477    15088830 :                 if (bInCluster)
     478           8 :                     nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
     479             : 
     480             :                 // The whole IS_DIACRITIC concept is a stupid hack that was
     481             :                 // introduced ages ago to work around the utter brokenness of the
     482             :                 // way justification adjustments are applied (the DXArray fiasco).
     483             :                 // Since it is such a stupid hack, there is no sane way to directly
     484             :                 // map to concepts of the "outside" world, so we do some rather
     485             :                 // ugly hacks:
     486             :                 // * If the font has a GDEF table, we check for glyphs with mark
     487             :                 //   glyph class which is sensible, except that some fonts
     488             :                 //   (fdo#70968) assign mark class to spacing marks (which is wrong
     489             :                 //   but usually harmless), so we try to sniff what HarfBuzz thinks
     490             :                 //   about this glyph by checking if it gives it a zero advance
     491             :                 //   width.
     492             :                 // * If the font has no GDEF table, we just check if the glyph has
     493             :                 //   zero advance width, but this is stupid and can be wrong. A
     494             :                 //   better way would to check the character's Unicode combining
     495             :                 //   class, but unfortunately glyph gives combining marks the
     496             :                 //   cluster value of its base character, so nCharPos will be
     497             :                 //   pointing to the wrong character (but HarfBuzz might change
     498             :                 //   this in the future).
     499    15088830 :                 bool bDiacritic = false;
     500    15088830 :                 if (hb_ot_layout_has_glyph_classes(mpHbFace))
     501             :                 {
     502             :                     // the font has GDEF table
     503    14893990 :                     bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
     504    14893990 :                     if (bMark && pHbPositions[i].x_advance == 0)
     505           8 :                         bDiacritic = true;
     506             :                 }
     507             :                 else
     508             :                 {
     509             :                     // the font lacks GDEF table
     510      194840 :                     if (pHbPositions[i].x_advance == 0)
     511           0 :                         bDiacritic = true;
     512             :                 }
     513             : 
     514    15088830 :                 if (bDiacritic)
     515           8 :                     nGlyphFlags |= GlyphItem::IS_DIACRITIC;
     516             : 
     517    15088830 :                 int32_t nXOffset =  pHbPositions[i].x_offset >> 6;
     518    15088830 :                 int32_t nYOffset =  pHbPositions[i].y_offset >> 6;
     519    15088830 :                 int32_t nXAdvance = pHbPositions[i].x_advance >> 6;
     520    15088830 :                 int32_t nYAdvance = pHbPositions[i].y_advance >> 6;
     521             : 
     522    15088830 :                 Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
     523    15088830 :                 const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset);
     524    15088830 :                 rLayout.AppendGlyph(aGI);
     525             : 
     526    15088830 :                 aCurrPos.X() += nXAdvance;
     527    15088830 :                 aCurrPos.Y() += nYAdvance;
     528             :             }
     529             : 
     530      925263 :             hb_buffer_destroy(pHbBuffer);
     531      925263 :         }
     532      925008 :     }
     533             : 
     534      937518 :     hb_font_destroy(pHbFont);
     535             : 
     536             :     // sort glyphs in visual order
     537             :     // and then in logical order (e.g. diacritics after cluster start)
     538             :     // XXX: why?
     539      937518 :     rLayout.SortGlyphItems();
     540             : 
     541             :     // determine need for kashida justification
     542      937518 :     if((rArgs.mpDXArray || rArgs.mnLayoutWidth)
     543       26062 :     && ((maHbScript == HB_SCRIPT_ARABIC) || (maHbScript == HB_SCRIPT_SYRIAC)))
     544           0 :         rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
     545             : 
     546      937518 :     return true;
     547             : }
     548             : 
     549      937518 : ServerFontLayoutEngine* ServerFont::GetLayoutEngine()
     550             : {
     551             :     // find best layout engine for font, platform, script and language
     552      937518 :     if (!mpLayoutEngine) {
     553        2833 :         mpLayoutEngine = new HbLayoutEngine(*this);
     554             :     }
     555      937518 :     return mpLayoutEngine;
     556         516 : }
     557             : 
     558             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10