LCOV - code coverage report
Current view: top level - vcl/generic/glyphs - gcach_layout.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 209 247 84.6 %
Date: 2015-06-13 12:38:46 Functions: 25 31 80.6 %
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 <i18nlangtag/mslangid.hxx>
      26             : 
      27             : #include <vcl/svapp.hxx>
      28             : #include <vcl/unohelp.hxx>
      29             : 
      30             : #include <sal/alloca.h>
      31             : #include <rtl/instance.hxx>
      32             : 
      33             : #include <hb-icu.h>
      34             : #include <hb-ot.h>
      35             : 
      36             : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
      37             : 
      38             : // layout implementation for ServerFont
      39     1586176 : ServerFontLayout::ServerFontLayout( ServerFont& rFont )
      40     1586176 : :   mrServerFont( rFont )
      41             : {
      42     1586176 : }
      43             : 
      44      246022 : void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
      45             : {
      46      246022 :     rSalGraphics.DrawServerFontLayout( *this );
      47      246022 : }
      48             : 
      49     1531565 : bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
      50             : {
      51     1531565 :     return mrServerFont.GetLayoutEngine()->Layout(*this, rArgs);
      52             : }
      53             : 
      54     1534125 : void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
      55             : {
      56     1534125 :     GenericSalLayout::AdjustLayout( rArgs );
      57             : 
      58             :     // apply asian kerning if the glyphs are not already formatted
      59     4602375 :     if( (rArgs.mnFlags & SalLayoutFlags::KerningAsian)
      60     4602375 :     && !(rArgs.mnFlags & SalLayoutFlags::Vertical) )
      61         522 :         if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
      62          50 :             ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
      63             : 
      64             :     // insert kashidas where requested by the formatting array
      65     1534125 :     if( (rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray )
      66             :     {
      67           0 :         int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
      68           0 :         if( nKashidaIndex != 0 )
      69             :         {
      70           0 :             const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
      71           0 :             KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
      72             :             // TODO: kashida-GSUB/GPOS
      73             :         }
      74             :     }
      75     1534125 : }
      76             : 
      77       63946 : void ServerFontLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos,
      78             :     bool bRightToLeft)
      79             : {
      80       63946 :     if (nCharPos < 0)
      81       63946 :         return;
      82             : 
      83             :     using namespace ::com::sun::star;
      84             : 
      85       63946 :     if (!mxBreak.is())
      86        3640 :         mxBreak = vcl::unohelper::CreateBreakIterator();
      87             : 
      88       63946 :     lang::Locale aLocale(rArgs.maLanguageTag.getLocale());
      89             : 
      90             :     //if position nCharPos is missing in the font, grab the entire grapheme and
      91             :     //mark all glyphs as missing so the whole thing is rendered with the same
      92             :     //font
      93      127892 :     OUString aRun(rArgs.mpStr);
      94             :     sal_Int32 nDone;
      95             :     sal_Int32 nGraphemeStartPos =
      96       63946 :         mxBreak->previousCharacters(aRun, nCharPos+1, aLocale,
      97       63946 :             i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
      98             :     sal_Int32 nGraphemeEndPos =
      99       63946 :         mxBreak->nextCharacters(aRun, nCharPos, aLocale,
     100       63946 :             i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
     101             : 
     102      127892 :     rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft);
     103             : }
     104             : 
     105           0 : std::ostream &operator <<(std::ostream& s, ServerFont* pFont)
     106             : {
     107             : #ifndef SAL_LOG_INFO
     108             :     (void) pFont;
     109             : #else
     110             :     FT_Face aFace = pFont->GetFtFace();
     111             :     const char* pName = FT_Get_Postscript_Name(aFace);
     112             :     if (pName)
     113             :         s << pName;
     114             :     else
     115             :         s << pFont->GetFontFileName();
     116             : #endif
     117           0 :     return s;
     118             : }
     119             : 
     120       14115 : static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData)
     121             : {
     122             :     char pTagName[5];
     123       14115 :     pTagName[0] = (char)(nTableTag >> 24);
     124       14115 :     pTagName[1] = (char)(nTableTag >> 16);
     125       14115 :     pTagName[2] = (char)(nTableTag >>  8);
     126       14115 :     pTagName[3] = (char)(nTableTag);
     127       14115 :     pTagName[4] = 0;
     128             : 
     129       14115 :     ServerFont* pFont = static_cast<ServerFont*>(pUserData);
     130             : 
     131             :     SAL_INFO("vcl.harfbuzz", "getFontTable(" << pFont << ", " << pTagName << ")");
     132             : 
     133             :     sal_uLong nLength;
     134       14115 :     const unsigned char* pBuffer = pFont->GetTable(pTagName, &nLength);
     135             : 
     136       14115 :     hb_blob_t* pBlob = NULL;
     137       14115 :     if (pBuffer != NULL)
     138       13497 :         pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, const_cast<unsigned char *>(pBuffer), NULL);
     139             : 
     140       14115 :     return pBlob;
     141             : }
     142             : 
     143    24837657 : static hb_bool_t getFontGlyph(hb_font_t* /*font*/, void* pFontData,
     144             :         hb_codepoint_t ch, hb_codepoint_t vs,
     145             :         hb_codepoint_t* nGlyphIndex,
     146             :         void* /*pUserData*/)
     147             : {
     148    24837657 :     ServerFont* pFont = static_cast<ServerFont*>(pFontData);
     149    24837657 :     *nGlyphIndex = pFont->GetRawGlyphIndex(ch, vs);
     150             : 
     151    24837657 :     return *nGlyphIndex != 0;
     152             : }
     153             : 
     154    24816818 : static hb_position_t getGlyphAdvanceH(hb_font_t* /*font*/, void* pFontData,
     155             :         hb_codepoint_t nGlyphIndex,
     156             :         void* /*pUserData*/)
     157             : {
     158    24816818 :     ServerFont* pFont = static_cast<ServerFont*>(pFontData);
     159    24816818 :     const GlyphMetric& rGM = pFont->GetGlyphMetric(nGlyphIndex);
     160    24816818 :     return rGM.GetCharWidth() << 6;
     161             : }
     162             : 
     163           0 : static hb_position_t getGlyphAdvanceV(hb_font_t* /*font*/, void* /*pFontData*/,
     164             :         hb_codepoint_t /*nGlyphIndex*/,
     165             :         void* /*pUserData*/)
     166             : {
     167             :     // XXX: vertical metrics
     168           0 :     return 0;
     169             : }
     170             : 
     171    74368216 : static hb_bool_t getGlyphOriginH(hb_font_t* /*font*/, void* /*pFontData*/,
     172             :         hb_codepoint_t /*nGlyphIndex*/,
     173             :         hb_position_t* /*x*/, hb_position_t* /*y*/,
     174             :         void* /*pUserData*/)
     175             : {
     176             :     // the horizontal origin is always (0, 0)
     177    74368216 :     return true;
     178             : }
     179             : 
     180           0 : static hb_bool_t getGlyphOriginV(hb_font_t* /*font*/, void* /*pFontData*/,
     181             :         hb_codepoint_t /*nGlyphIndex*/,
     182             :         hb_position_t* /*x*/, hb_position_t* /*y*/,
     183             :         void* /*pUserData*/)
     184             : {
     185             :     // XXX: vertical origin
     186           0 :     return true;
     187             : }
     188             : 
     189       34267 : static hb_position_t getGlyphKerningH(hb_font_t* /*font*/, void* pFontData,
     190             :         hb_codepoint_t nGlyphIndex1, hb_codepoint_t nGlyphIndex2,
     191             :         void* /*pUserData*/)
     192             : {
     193             :     // This callback is for old style 'kern' table, GPOS kerning is handled by HarfBuzz directly
     194             : 
     195       34267 :     ServerFont* pFont = static_cast<ServerFont*>(pFontData);
     196       34267 :     FT_Face aFace = pFont->GetFtFace();
     197             : 
     198             :     SAL_INFO("vcl.harfbuzz", "getGlyphKerningH(" << pFont << ", " << nGlyphIndex1 << ", " << nGlyphIndex2 << ")");
     199             : 
     200             :     FT_Error error;
     201             :     FT_Vector kerning;
     202             :     hb_position_t ret;
     203             : 
     204       34267 :     error = FT_Get_Kerning(aFace, nGlyphIndex1, nGlyphIndex2, FT_KERNING_DEFAULT, &kerning);
     205       34267 :     if (error)
     206           0 :         ret = 0;
     207             :     else
     208       34267 :         ret = kerning.x;
     209             : 
     210       34267 :     return ret;
     211             : }
     212             : 
     213           0 : static hb_position_t getGlyphKerningV(hb_font_t* /*font*/, void* /*pFontData*/,
     214             :         hb_codepoint_t /*nGlyphIndex1*/, hb_codepoint_t /*nGlyphIndex2*/,
     215             :         void* /*pUserData*/)
     216             : {
     217             :     // XXX vertical kerning
     218           0 :     return 0;
     219             : }
     220             : 
     221           0 : static hb_bool_t getGlyphExtents(hb_font_t* /*font*/, void* pFontData,
     222             :         hb_codepoint_t nGlyphIndex,
     223             :         hb_glyph_extents_t* pExtents,
     224             :         void* /*pUserData*/)
     225             : {
     226           0 :     ServerFont* pFont = static_cast<ServerFont*>(pFontData);
     227           0 :     FT_Face aFace = pFont->GetFtFace();
     228             : 
     229             :     SAL_INFO("vcl.harfbuzz", "getGlyphExtents(" << pFont << ", " << nGlyphIndex << ")");
     230             : 
     231             :     FT_Error error;
     232           0 :     error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
     233           0 :     if (!error)
     234             :     {
     235           0 :         pExtents->x_bearing = aFace->glyph->metrics.horiBearingX;
     236           0 :         pExtents->y_bearing = aFace->glyph->metrics.horiBearingY;
     237           0 :         pExtents->width  =  aFace->glyph->metrics.width;
     238           0 :         pExtents->height = -aFace->glyph->metrics.height;
     239             :     }
     240             : 
     241           0 :     return !error;
     242             : }
     243             : 
     244           0 : static hb_bool_t getGlyphContourPoint(hb_font_t* /*font*/, void* pFontData,
     245             :         hb_codepoint_t nGlyphIndex, unsigned int nPointIndex,
     246             :         hb_position_t *x, hb_position_t *y,
     247             :         void* /*pUserData*/)
     248             : {
     249           0 :     bool ret = false;
     250           0 :     ServerFont* pFont = static_cast<ServerFont*>(pFontData);
     251           0 :     FT_Face aFace = pFont->GetFtFace();
     252             : 
     253             :     SAL_INFO("vcl.harfbuzz", "getGlyphContourPoint(" << pFont << ", " << nGlyphIndex << ", " << nPointIndex << ")");
     254             : 
     255             :     FT_Error error;
     256           0 :     error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
     257           0 :     if (!error)
     258             :     {
     259           0 :         if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
     260             :         {
     261           0 :             if (nPointIndex < (unsigned int) aFace->glyph->outline.n_points)
     262             :             {
     263           0 :                 *x = aFace->glyph->outline.points[nPointIndex].x;
     264           0 :                 *y = aFace->glyph->outline.points[nPointIndex].y;
     265           0 :                 ret = true;
     266             :             }
     267             :         }
     268             :     }
     269             : 
     270           0 :     return ret;
     271             : }
     272             : 
     273         198 : static hb_font_funcs_t* getFontFuncs()
     274             : {
     275         198 :     static hb_font_funcs_t* funcs = hb_font_funcs_create();
     276             : 
     277         198 :     hb_font_funcs_set_glyph_func                (funcs, getFontGlyph, NULL, NULL);
     278         198 :     hb_font_funcs_set_glyph_h_advance_func      (funcs, getGlyphAdvanceH, NULL, NULL);
     279         198 :     hb_font_funcs_set_glyph_v_advance_func      (funcs, getGlyphAdvanceV, NULL, NULL);
     280         198 :     hb_font_funcs_set_glyph_h_origin_func       (funcs, getGlyphOriginH, NULL, NULL);
     281         198 :     hb_font_funcs_set_glyph_v_origin_func       (funcs, getGlyphOriginV, NULL, NULL);
     282         198 :     hb_font_funcs_set_glyph_h_kerning_func      (funcs, getGlyphKerningH, NULL, NULL);
     283         198 :     hb_font_funcs_set_glyph_v_kerning_func      (funcs, getGlyphKerningV, NULL, NULL);
     284         198 :     hb_font_funcs_set_glyph_extents_func        (funcs, getGlyphExtents, NULL, NULL);
     285         198 :     hb_font_funcs_set_glyph_contour_point_func  (funcs, getGlyphContourPoint, NULL, NULL);
     286             : 
     287         198 :     return funcs;
     288             : }
     289             : 
     290             : // Disabled Unicode compatibility decomposition, see fdo#66715
     291       63946 : static unsigned int unicodeDecomposeCompatibility(hb_unicode_funcs_t* /*ufuncs*/,
     292             :                                                   hb_codepoint_t      /*u*/,
     293             :                                                   hb_codepoint_t*     /*decomposed*/,
     294             :                                                   void*               /*user_data*/)
     295             : {
     296       63946 :     return 0;
     297             : }
     298             : 
     299         198 : static hb_unicode_funcs_t* getUnicodeFuncs()
     300             : {
     301         198 :     static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
     302         198 :     hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, NULL, NULL);
     303         198 :     return ufuncs;
     304             : }
     305             : 
     306             : class HbLayoutEngine : public ServerFontLayoutEngine
     307             : {
     308             : private:
     309             :     hb_script_t             maHbScript;
     310             :     hb_face_t*              mpHbFace;
     311             :     int                     mnUnitsPerEM;
     312             : 
     313             : public:
     314             :     explicit                HbLayoutEngine(ServerFont&);
     315             :     virtual                 ~HbLayoutEngine();
     316             : 
     317             :     virtual bool            Layout(ServerFontLayout&, ImplLayoutArgs&) SAL_OVERRIDE;
     318             : };
     319             : 
     320        4725 : HbLayoutEngine::HbLayoutEngine(ServerFont& rServerFont)
     321             : :   maHbScript(HB_SCRIPT_INVALID),
     322             :     mpHbFace(NULL),
     323        4725 :     mnUnitsPerEM(0)
     324             : {
     325        4725 :     FT_Face aFtFace = rServerFont.GetFtFace();
     326        4725 :     mnUnitsPerEM = rServerFont.GetEmUnits();
     327             : 
     328        4725 :     mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, NULL);
     329        4725 :     hb_face_set_index(mpHbFace, aFtFace->face_index);
     330        4725 :     hb_face_set_upem(mpHbFace, mnUnitsPerEM);
     331        4725 : }
     332             : 
     333       14175 : HbLayoutEngine::~HbLayoutEngine()
     334             : {
     335        4725 :     hb_face_destroy(mpHbFace);
     336        9450 : }
     337             : 
     338             : struct HbScriptRun
     339             : {
     340             :     int32_t mnMin;
     341             :     int32_t mnEnd;
     342             :     hb_script_t maScript;
     343             : 
     344     1533807 :     HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript)
     345             :     : mnMin(nMin), mnEnd(nEnd),
     346     1533807 :       maScript(hb_icu_script_to_script(aScript))
     347     1533807 :     {}
     348             : };
     349             : 
     350             : typedef std::vector<HbScriptRun> HbScriptRuns;
     351             : 
     352             : namespace vcl {
     353             :     struct Run
     354             :     {
     355             :         int32_t nStart;
     356             :         int32_t nEnd;
     357             :         UScriptCode nCode;
     358     1470263 :         Run(int32_t nStart_, int32_t nEnd_, UScriptCode nCode_)
     359     1470263 :             : nStart(nStart_), nEnd(nEnd_), nCode(nCode_)
     360     1470263 :         {}
     361             :     };
     362             : 
     363     1513433 :     class TextLayoutCache
     364             :     {
     365             :     public:
     366             :         std::vector<vcl::Run> runs;
     367     1513433 :         TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd)
     368     1513433 :         {
     369             :             vcl::ScriptRun aScriptRun(
     370             :                 reinterpret_cast<const UChar *>(pStr),
     371     1513433 :                 nEnd);
     372     4497129 :             while (aScriptRun.next())
     373             :             {
     374             :                 runs.push_back(Run(aScriptRun.getScriptStart(),
     375     1470263 :                     aScriptRun.getScriptEnd(), aScriptRun.getScriptCode()));
     376     1513433 :             }
     377     1513433 :         }
     378             :     };
     379             : }
     380             : 
     381       54611 : std::shared_ptr<vcl::TextLayoutCache> ServerFontLayout::CreateTextLayoutCache(
     382             :         OUString const& rString) const
     383             : {
     384       54611 :     return std::make_shared<vcl::TextLayoutCache>(rString.getStr(), rString.getLength());
     385             : }
     386             : 
     387     1531565 : bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
     388             : {
     389     1531565 :     ServerFont& rFont = rLayout.GetServerFont();
     390     1531565 :     FT_Face aFtFace = rFont.GetFtFace();
     391             : 
     392             :     SAL_INFO("vcl.harfbuzz", "layout(" << this << ",rArgs=" << rArgs << ")");
     393             : 
     394     1531565 :     static hb_font_funcs_t* pHbFontFuncs = getFontFuncs();
     395             : 
     396     1531565 :     hb_font_t *pHbFont = hb_font_create(mpHbFace);
     397     1531565 :     hb_font_set_funcs(pHbFont, pHbFontFuncs, &rFont, NULL);
     398             :     hb_font_set_scale(pHbFont,
     399     1531565 :             ((uint64_t) aFtFace->size->metrics.x_scale * (uint64_t) mnUnitsPerEM) >> 16,
     400     3063130 :             ((uint64_t) aFtFace->size->metrics.y_scale * (uint64_t) mnUnitsPerEM) >> 16);
     401     1531565 :     hb_font_set_ppem(pHbFont, aFtFace->size->metrics.x_ppem, aFtFace->size->metrics.y_ppem);
     402             : 
     403             :     // allocate temporary arrays, note: round to even
     404     1531565 :     int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1;
     405             : 
     406     1531565 :     rLayout.Reserve(nGlyphCapacity);
     407             : 
     408     1531565 :     std::unique_ptr<vcl::TextLayoutCache> pNewScriptRun;
     409             :     vcl::TextLayoutCache const* pTextLayout;
     410     1531565 :     if (rArgs.m_pTextLayoutCache)
     411             :     {
     412       72743 :         pTextLayout = rArgs.m_pTextLayoutCache; // use cache!
     413             :     }
     414             :     else
     415             :     {
     416     1458822 :         pNewScriptRun.reset(new vcl::TextLayoutCache(rArgs.mpStr, rArgs.mnEndCharPos));
     417     1458822 :         pTextLayout = pNewScriptRun.get();
     418             :     }
     419             : 
     420     1531565 :     Point aCurrPos(0, 0);
     421             :     while (true)
     422             :     {
     423             :         int nBidiMinRunPos, nBidiEndRunPos;
     424             :         bool bRightToLeft;
     425     3064802 :         if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft))
     426     1531565 :             break;
     427             : 
     428             :         // Find script subruns.
     429     1533237 :         int nCurrentPos = nBidiMinRunPos;
     430     1533237 :         HbScriptRuns aScriptSubRuns;
     431     1533237 :         size_t k = 0;
     432     1695534 :         for (; k < pTextLayout->runs.size(); ++k)
     433             :         {
     434     1695534 :             vcl::Run const& rRun(pTextLayout->runs[k]);
     435     1695534 :             if (rRun.nStart <= nCurrentPos && nCurrentPos < rRun.nEnd)
     436             :             {
     437     1533237 :                 break;
     438             :             }
     439             :         }
     440             : 
     441     4600281 :         while (nCurrentPos < nBidiEndRunPos && k < pTextLayout->runs.size())
     442             :         {
     443     1533807 :             int32_t nMinRunPos = nCurrentPos;
     444     1533807 :             int32_t nEndRunPos = std::min(pTextLayout->runs[k].nEnd, nBidiEndRunPos);
     445     1533807 :             HbScriptRun aRun(nMinRunPos, nEndRunPos, pTextLayout->runs[k].nCode);
     446     1533807 :             aScriptSubRuns.push_back(aRun);
     447             : 
     448     1533807 :             nCurrentPos = nEndRunPos;
     449     1533807 :             ++k;
     450             :         }
     451             : 
     452             :         // RTL subruns should be reversed to ensure that final glyph order is
     453             :         // correct.
     454     1533237 :         if (bRightToLeft)
     455         180 :             std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end());
     456             : 
     457     3067044 :         for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it)
     458             :         {
     459     1533807 :             int nMinRunPos = it->mnMin;
     460     1533807 :             int nEndRunPos = it->mnEnd;
     461     1533807 :             int nRunLen = nEndRunPos - nMinRunPos;
     462     1533807 :             maHbScript = it->maScript;
     463             : 
     464     1533807 :             OString sLanguage = OUStringToOString(rArgs.maLanguageTag.getLanguage(), RTL_TEXTENCODING_UTF8);
     465             : 
     466     1533807 :             static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
     467             : 
     468     1533807 :             int nHbFlags = HB_BUFFER_FLAGS_DEFAULT;
     469     1533807 :             if (nMinRunPos == 0)
     470     1257956 :                 nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */
     471     1533807 :             if (nEndRunPos == rArgs.mnLength)
     472     1323269 :                 nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */
     473             : 
     474     1533807 :             hb_buffer_t *pHbBuffer = hb_buffer_create();
     475     1533807 :             hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
     476     1533807 :             hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
     477     1533807 :             hb_buffer_set_script(pHbBuffer, maHbScript);
     478     1533807 :             hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1));
     479     1533807 :             hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags);
     480     1533807 :             hb_buffer_add_utf16(pHbBuffer, rArgs.mpStr, rArgs.mnLength, nMinRunPos, nRunLen);
     481     1533807 :             hb_shape(pHbFont, pHbBuffer, NULL, 0);
     482             : 
     483     1533807 :             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
     484     1533807 :             hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, NULL);
     485     1533807 :             hb_glyph_position_t *pHbPositions = hb_buffer_get_glyph_positions(pHbBuffer, NULL);
     486             : 
     487    26350625 :             for (int i = 0; i < nRunGlyphCount; ++i) {
     488    24816818 :                 int32_t nGlyphIndex = pHbGlyphInfos[i].codepoint;
     489    24816818 :                 int32_t nCharPos = pHbGlyphInfos[i].cluster;
     490             : 
     491             :                 // tdf#89231 if it's just a missing non-breaking space, then use a normal space
     492    24816818 :                 if (!nGlyphIndex && (SalLayoutFlags::ForFallback & rArgs.mnFlags) && nCharPos >= 0 && rArgs.mpStr[nCharPos] == 0x202F)
     493             :                 {
     494           0 :                     nGlyphIndex = rFont.GetGlyphIndex(' ');
     495             :                 }
     496             : 
     497             :                 // if needed request glyph fallback by updating LayoutArgs
     498    24816818 :                 if (!nGlyphIndex)
     499             :                 {
     500       63946 :                     rLayout.SetNeedFallback(rArgs, nCharPos, bRightToLeft);
     501       63946 :                     if (SalLayoutFlags::ForFallback & rArgs.mnFlags)
     502         670 :                         continue;
     503             :                 }
     504             : 
     505             :                 // apply vertical flags and glyph substitution
     506             :                 // XXX: Use HB_DIRECTION_TTB above and apply whatever flags magic
     507             :                 // FixupGlyphIndex() is doing, minus the GSUB part.
     508    24816148 :                 if (nCharPos >= 0)
     509             :                 {
     510    24816148 :                     sal_UCS4 aChar = rArgs.mpStr[nCharPos];
     511    24816148 :                     nGlyphIndex = rFont.FixupGlyphIndex(nGlyphIndex, aChar);
     512             :                 }
     513             : 
     514    24816148 :                 bool bInCluster = false;
     515    24816148 :                 if (i > 0 && pHbGlyphInfos[i].cluster == pHbGlyphInfos[i - 1].cluster)
     516          13 :                     bInCluster = true;
     517             : 
     518    24816148 :                 long nGlyphFlags = 0;
     519    24816148 :                 if (bRightToLeft)
     520         508 :                     nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
     521             : 
     522    24816148 :                 if (bInCluster)
     523          13 :                     nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
     524             : 
     525             :                 // The whole IS_DIACRITIC concept is a stupid hack that was
     526             :                 // introduced ages ago to work around the utter brokenness of the
     527             :                 // way justification adjustments are applied (the DXArray fiasco).
     528             :                 // Since it is such a stupid hack, there is no sane way to directly
     529             :                 // map to concepts of the "outside" world, so we do some rather
     530             :                 // ugly hacks:
     531             :                 // * If the font has a GDEF table, we check for glyphs with mark
     532             :                 //   glyph class which is sensible, except that some fonts
     533             :                 //   (fdo#70968) assign mark class to spacing marks (which is wrong
     534             :                 //   but usually harmless), so we try to sniff what HarfBuzz thinks
     535             :                 //   about this glyph by checking if it gives it a zero advance
     536             :                 //   width.
     537             :                 // * If the font has no GDEF table, we just check if the glyph has
     538             :                 //   zero advance width, but this is stupid and can be wrong. A
     539             :                 //   better way would to check the character's Unicode combining
     540             :                 //   class, but unfortunately glyph gives combining marks the
     541             :                 //   cluster value of its base character, so nCharPos will be
     542             :                 //   pointing to the wrong character (but HarfBuzz might change
     543             :                 //   this in the future).
     544    24816148 :                 bool bDiacritic = false;
     545    24816148 :                 if (hb_ot_layout_has_glyph_classes(mpHbFace))
     546             :                 {
     547             :                     // the font has GDEF table
     548    24775335 :                     bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
     549    24775335 :                     if (bMark && pHbPositions[i].x_advance == 0)
     550           8 :                         bDiacritic = true;
     551             :                 }
     552             :                 else
     553             :                 {
     554             :                     // the font lacks GDEF table
     555       40813 :                     if (pHbPositions[i].x_advance == 0)
     556           0 :                         bDiacritic = true;
     557             :                 }
     558             : 
     559    24816148 :                 if (bDiacritic)
     560           8 :                     nGlyphFlags |= GlyphItem::IS_DIACRITIC;
     561             : 
     562    24816148 :                 int32_t nXOffset =  pHbPositions[i].x_offset >> 6;
     563    24816148 :                 int32_t nYOffset =  pHbPositions[i].y_offset >> 6;
     564    24816148 :                 int32_t nXAdvance = pHbPositions[i].x_advance >> 6;
     565    24816148 :                 int32_t nYAdvance = pHbPositions[i].y_advance >> 6;
     566             : 
     567    24816148 :                 Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
     568    24816148 :                 const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset, nYOffset);
     569    24816148 :                 rLayout.AppendGlyph(aGI);
     570             : 
     571    24816148 :                 aCurrPos.X() += nXAdvance;
     572    24816148 :                 aCurrPos.Y() += nYAdvance;
     573             :             }
     574             : 
     575     1533807 :             hb_buffer_destroy(pHbBuffer);
     576     1533807 :         }
     577     1533237 :     }
     578             : 
     579     1531565 :     hb_font_destroy(pHbFont);
     580             : 
     581             :     // sort glyphs in visual order
     582             :     // and then in logical order (e.g. diacritics after cluster start)
     583             :     // XXX: why?
     584     1531565 :     rLayout.SortGlyphItems();
     585             : 
     586             :     // determine need for kashida justification
     587     1531565 :     if((rArgs.mpDXArray || rArgs.mnLayoutWidth)
     588       40511 :     && ((maHbScript == HB_SCRIPT_ARABIC) || (maHbScript == HB_SCRIPT_SYRIAC)))
     589           0 :         rArgs.mnFlags |= SalLayoutFlags::KashidaJustification;
     590             : 
     591     1531565 :     return true;
     592             : }
     593             : 
     594     1531565 : ServerFontLayoutEngine* ServerFont::GetLayoutEngine()
     595             : {
     596             :     // find best layout engine for font, platform, script and language
     597     1531565 :     if (!mpLayoutEngine) {
     598        4725 :         mpLayoutEngine = new HbLayoutEngine(*this);
     599             :     }
     600     1531565 :     return mpLayoutEngine;
     601         801 : }
     602             : 
     603             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11