From 09a1566bf18cdf98b111d4979e4f4ad52ce65b07 Mon Sep 17 00:00:00 2001 From: Chris Sherlock Date: Mon, 11 Jan 2016 13:41:05 +1100 Subject: vcl: move all glyph files from generic to unx All the files in glyph are only used by Unix based systems, with the exception of OS X. Therefore, it's not really "generic" as in "used across all platforms" but is generic as in "used in all Unix-based systems". Change-Id: Id89c09df74f0ddafee5c88c55bac4c35f9b23ef8 Reviewed-on: https://gerrit.libreoffice.org/21312 Tested-by: Jenkins Reviewed-by: Chris Sherlock --- vcl/Library_vcl.mk | 8 +- vcl/generic/fontmanager/fontsubst.cxx | 2 +- vcl/generic/glyphs/gcach_layout.cxx | 621 ------------------------- vcl/generic/glyphs/glyphcache.cxx | 379 --------------- vcl/generic/glyphs/graphite_serverfont.cxx | 135 ------ vcl/generic/glyphs/scrptrun.cxx | 234 ---------- vcl/generic/glyphs/scrptrun.h | 173 ------- vcl/generic/print/genpspgraphics.cxx | 2 +- vcl/headless/svpglyphcache.cxx | 2 +- vcl/inc/generic/glyphcache.hxx | 300 ------------ vcl/inc/graphite_serverfont.hxx | 2 +- vcl/inc/unx/freetype_glyphcache.hxx | 2 +- vcl/inc/unx/glyphcache.hxx | 300 ++++++++++++ vcl/unx/generic/gdi/cairotextrender.cxx | 2 +- vcl/unx/generic/gdi/gcach_xpeer.hxx | 2 +- vcl/unx/generic/glyphs/gcach_layout.cxx | 621 +++++++++++++++++++++++++ vcl/unx/generic/glyphs/glyphcache.cxx | 379 +++++++++++++++ vcl/unx/generic/glyphs/graphite_serverfont.cxx | 135 ++++++ vcl/unx/generic/glyphs/scrptrun.cxx | 234 ++++++++++ vcl/unx/generic/glyphs/scrptrun.h | 173 +++++++ 20 files changed, 1853 insertions(+), 1853 deletions(-) delete mode 100644 vcl/generic/glyphs/gcach_layout.cxx delete mode 100644 vcl/generic/glyphs/glyphcache.cxx delete mode 100644 vcl/generic/glyphs/graphite_serverfont.cxx delete mode 100644 vcl/generic/glyphs/scrptrun.cxx delete mode 100644 vcl/generic/glyphs/scrptrun.h delete mode 100644 vcl/inc/generic/glyphcache.hxx create mode 100644 vcl/inc/unx/glyphcache.hxx create mode 100644 vcl/unx/generic/glyphs/gcach_layout.cxx create mode 100644 vcl/unx/generic/glyphs/glyphcache.cxx create mode 100644 vcl/unx/generic/glyphs/graphite_serverfont.cxx create mode 100644 vcl/unx/generic/glyphs/scrptrun.cxx create mode 100644 vcl/unx/generic/glyphs/scrptrun.h diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index b3dfd097de0d..94ee4c35e964 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -423,7 +423,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ # handle X11 platforms, which have additional files and possibly system graphite ifneq (,$(or $(USING_X11),$(ENABLE_HEADLESS))) $(eval $(call gb_Library_add_exception_objects,vcl,\ - vcl/generic/glyphs/graphite_serverfont \ + vcl/unx/generic/glyphs/graphite_serverfont \ )) endif @@ -555,9 +555,6 @@ vcl_generic_code= \ vcl/generic/print/prtsetup \ vcl/generic/print/text_gfx \ vcl/generic/fontmanager/fontsubst \ - vcl/generic/glyphs/gcach_layout \ - vcl/generic/glyphs/glyphcache \ - vcl/generic/glyphs/scrptrun \ vcl/generic/fontmanager/fontcache \ vcl/generic/fontmanager/fontconfig \ vcl/generic/fontmanager/fontmanager \ @@ -579,6 +576,9 @@ vcl_headless_freetype_code=\ vcl/headless/svpglyphcache \ vcl/unx/generic/gdi/cairotextrender \ vcl/unx/generic/glyphs/freetype_glyphcache \ + vcl/unx/generic/glyphs/gcach_layout \ + vcl/unx/generic/glyphs/glyphcache \ + vcl/unx/generic/glyphs/scrptrun \ vcl/headless/svpcairotextrender \ ifeq ($(USING_X11),TRUE) diff --git a/vcl/generic/fontmanager/fontsubst.cxx b/vcl/generic/fontmanager/fontsubst.cxx index 5f7bfb361d46..f88944504764 100644 --- a/vcl/generic/fontmanager/fontsubst.cxx +++ b/vcl/generic/fontmanager/fontsubst.cxx @@ -19,7 +19,7 @@ #include "generic/geninst.h" #include "generic/genpspgraphics.h" -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" #include "vcl/sysdata.hxx" #include "fontinstance.hxx" diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx deleted file mode 100644 index 70ac1901f09d..000000000000 --- a/vcl/generic/glyphs/gcach_layout.cxx +++ /dev/null @@ -1,621 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include "unx/freetype_glyphcache.hxx" -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include - -#include - -#ifndef HB_VERSION_ATLEAST -#define HB_VERSION_ATLEAST(a,b,c) 0 -#endif - -// layout implementation for ServerFont -ServerFontLayout::ServerFontLayout( ServerFont& rFont ) -: mrServerFont( rFont ) -{ -} - -void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const -{ - rSalGraphics.DrawServerFontLayout( *this ); -} - -bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs ) -{ - return mrServerFont.GetLayoutEngine()->Layout(*this, rArgs); -} - -void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs ) -{ - GenericSalLayout::AdjustLayout( rArgs ); - - // apply asian kerning if the glyphs are not already formatted - if( (rArgs.mnFlags & SalLayoutFlags::KerningAsian) - && !(rArgs.mnFlags & SalLayoutFlags::Vertical) ) - if( (rArgs.mpDXArray != nullptr) || (rArgs.mnLayoutWidth != 0) ) - ApplyAsianKerning(rArgs.mrStr); - - // insert kashidas where requested by the formatting array - if( (rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray ) - { - int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); - if( nKashidaIndex != 0 ) - { - const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); - KashidaJustify( nKashidaIndex, rGM.GetCharWidth() ); - // TODO: kashida-GSUB/GPOS - } - } -} - -void ServerFontLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos, - bool bRightToLeft) -{ - if (nCharPos < 0) - return; - - using namespace ::com::sun::star; - - if (!mxBreak.is()) - mxBreak = vcl::unohelper::CreateBreakIterator(); - - lang::Locale aLocale(rArgs.maLanguageTag.getLocale()); - - //if position nCharPos is missing in the font, grab the entire grapheme and - //mark all glyphs as missing so the whole thing is rendered with the same - //font - sal_Int32 nDone; - sal_Int32 nGraphemeStartPos = - mxBreak->previousCharacters(rArgs.mrStr, nCharPos+1, aLocale, - i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); - sal_Int32 nGraphemeEndPos = - mxBreak->nextCharacters(rArgs.mrStr, nCharPos, aLocale, - i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); - - rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft); -} - -std::ostream &operator <<(std::ostream& s, ServerFont* pFont) -{ -#ifndef SAL_LOG_INFO - (void) pFont; -#else - FT_Face aFace = pFont->GetFtFace(); - const char* pName = FT_Get_Postscript_Name(aFace); - if (pName) - s << pName; - else - s << pFont->GetFontFileName(); -#endif - return s; -} - -static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) -{ - char pTagName[5]; - pTagName[0] = (char)(nTableTag >> 24); - pTagName[1] = (char)(nTableTag >> 16); - pTagName[2] = (char)(nTableTag >> 8); - pTagName[3] = (char)(nTableTag); - pTagName[4] = 0; - - ServerFont* pFont = static_cast(pUserData); - - SAL_INFO("vcl.harfbuzz", "getFontTable(" << pFont << ", " << pTagName << ")"); - - sal_uLong nLength; - const unsigned char* pBuffer = pFont->GetTable(pTagName, &nLength); - - hb_blob_t* pBlob = nullptr; - if (pBuffer != nullptr) - pBlob = hb_blob_create(reinterpret_cast(pBuffer), nLength, HB_MEMORY_MODE_READONLY, const_cast(pBuffer), nullptr); - - return pBlob; -} - -static hb_bool_t getFontGlyph(hb_font_t* /*font*/, void* pFontData, - hb_codepoint_t ch, hb_codepoint_t vs, - hb_codepoint_t* nGlyphIndex, - void* /*pUserData*/) -{ - ServerFont* pFont = static_cast(pFontData); - *nGlyphIndex = pFont->GetRawGlyphIndex(ch, vs); - - // tdf#89231 if the font is missing non-breaking space, then use a normal space - if (*nGlyphIndex == 0 && ch == 0x202F && !vs) - *nGlyphIndex = pFont->GetRawGlyphIndex(' '); - - return *nGlyphIndex != 0; -} - -static hb_position_t getGlyphAdvanceH(hb_font_t* /*font*/, void* pFontData, - hb_codepoint_t nGlyphIndex, - void* /*pUserData*/) -{ - ServerFont* pFont = static_cast(pFontData); - const GlyphMetric& rGM = pFont->GetGlyphMetric(nGlyphIndex); - return rGM.GetCharWidth() << 6; -} - -#if !HB_VERSION_ATLEAST(1, 1, 2) -static hb_position_t getGlyphAdvanceV(hb_font_t* /*font*/, void* /*pFontData*/, - hb_codepoint_t /*nGlyphIndex*/, - void* /*pUserData*/) -{ - // XXX: vertical metrics - return 0; -} - -static hb_bool_t getGlyphOriginH(hb_font_t* /*font*/, void* /*pFontData*/, - hb_codepoint_t /*nGlyphIndex*/, - hb_position_t* /*x*/, hb_position_t* /*y*/, - void* /*pUserData*/) -{ - // the horizontal origin is always (0, 0) - return true; -} - -static hb_bool_t getGlyphOriginV(hb_font_t* /*font*/, void* /*pFontData*/, - hb_codepoint_t /*nGlyphIndex*/, - hb_position_t* /*x*/, hb_position_t* /*y*/, - void* /*pUserData*/) -{ - // XXX: vertical origin - return true; -} -#endif - -static hb_position_t getGlyphKerningH(hb_font_t* /*font*/, void* pFontData, - hb_codepoint_t nGlyphIndex1, hb_codepoint_t nGlyphIndex2, - void* /*pUserData*/) -{ - // This callback is for old style 'kern' table, GPOS kerning is handled by HarfBuzz directly - - ServerFont* pFont = static_cast(pFontData); - FT_Face aFace = pFont->GetFtFace(); - - SAL_INFO("vcl.harfbuzz", "getGlyphKerningH(" << pFont << ", " << nGlyphIndex1 << ", " << nGlyphIndex2 << ")"); - - FT_Error error; - FT_Vector kerning; - hb_position_t ret; - - error = FT_Get_Kerning(aFace, nGlyphIndex1, nGlyphIndex2, FT_KERNING_DEFAULT, &kerning); - if (error) - ret = 0; - else - ret = kerning.x; - - return ret; -} - -#if !HB_VERSION_ATLEAST(1, 1, 2) -static hb_position_t getGlyphKerningV(hb_font_t* /*font*/, void* /*pFontData*/, - hb_codepoint_t /*nGlyphIndex1*/, hb_codepoint_t /*nGlyphIndex2*/, - void* /*pUserData*/) -{ - // XXX vertical kerning - return 0; -} -#endif - -static hb_bool_t getGlyphExtents(hb_font_t* /*font*/, void* pFontData, - hb_codepoint_t nGlyphIndex, - hb_glyph_extents_t* pExtents, - void* /*pUserData*/) -{ - ServerFont* pFont = static_cast(pFontData); - FT_Face aFace = pFont->GetFtFace(); - - SAL_INFO("vcl.harfbuzz", "getGlyphExtents(" << pFont << ", " << nGlyphIndex << ")"); - - FT_Error error; - error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT); - if (!error) - { - pExtents->x_bearing = aFace->glyph->metrics.horiBearingX; - pExtents->y_bearing = aFace->glyph->metrics.horiBearingY; - pExtents->width = aFace->glyph->metrics.width; - pExtents->height = -aFace->glyph->metrics.height; - } - - return !error; -} - -static hb_bool_t getGlyphContourPoint(hb_font_t* /*font*/, void* pFontData, - hb_codepoint_t nGlyphIndex, unsigned int nPointIndex, - hb_position_t *x, hb_position_t *y, - void* /*pUserData*/) -{ - bool ret = false; - ServerFont* pFont = static_cast(pFontData); - FT_Face aFace = pFont->GetFtFace(); - - SAL_INFO("vcl.harfbuzz", "getGlyphContourPoint(" << pFont << ", " << nGlyphIndex << ", " << nPointIndex << ")"); - - FT_Error error; - error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT); - if (!error) - { - if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) - { - if (nPointIndex < (unsigned int) aFace->glyph->outline.n_points) - { - *x = aFace->glyph->outline.points[nPointIndex].x; - *y = aFace->glyph->outline.points[nPointIndex].y; - ret = true; - } - } - } - - return ret; -} - -static hb_font_funcs_t* getFontFuncs() -{ - static hb_font_funcs_t* funcs = hb_font_funcs_create(); - - hb_font_funcs_set_glyph_func (funcs, getFontGlyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func (funcs, getGlyphAdvanceH, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func (funcs, getGlyphKerningH, nullptr, nullptr); - hb_font_funcs_set_glyph_extents_func (funcs, getGlyphExtents, nullptr, nullptr); - hb_font_funcs_set_glyph_contour_point_func (funcs, getGlyphContourPoint, nullptr, nullptr); -#if !HB_VERSION_ATLEAST(1, 1, 2) - hb_font_funcs_set_glyph_v_advance_func (funcs, getGlyphAdvanceV, nullptr, nullptr); - hb_font_funcs_set_glyph_h_origin_func (funcs, getGlyphOriginH, nullptr, nullptr); - hb_font_funcs_set_glyph_v_origin_func (funcs, getGlyphOriginV, nullptr, nullptr); - hb_font_funcs_set_glyph_v_kerning_func (funcs, getGlyphKerningV, nullptr, nullptr); -#endif - - return funcs; -} - -#if !HB_VERSION_ATLEAST(1, 1, 0) -// Disabled Unicode compatibility decomposition, see fdo#66715 -static unsigned int unicodeDecomposeCompatibility(hb_unicode_funcs_t* /*ufuncs*/, - hb_codepoint_t /*u*/, - hb_codepoint_t* /*decomposed*/, - void* /*user_data*/) -{ - return 0; -} - -static hb_unicode_funcs_t* getUnicodeFuncs() -{ - static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs()); - hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, nullptr, nullptr); - return ufuncs; -} -#endif - -class HbLayoutEngine : public ServerFontLayoutEngine -{ -private: - hb_script_t maHbScript; - hb_face_t* mpHbFace; - int mnUnitsPerEM; - -public: - explicit HbLayoutEngine(ServerFont&); - virtual ~HbLayoutEngine(); - - virtual bool Layout(ServerFontLayout&, ImplLayoutArgs&) override; -}; - -HbLayoutEngine::HbLayoutEngine(ServerFont& rServerFont) -: maHbScript(HB_SCRIPT_INVALID), - mpHbFace(nullptr), - mnUnitsPerEM(0) -{ - FT_Face aFtFace = rServerFont.GetFtFace(); - mnUnitsPerEM = rServerFont.GetEmUnits(); - - mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); - hb_face_set_index(mpHbFace, aFtFace->face_index); - hb_face_set_upem(mpHbFace, mnUnitsPerEM); -} - -HbLayoutEngine::~HbLayoutEngine() -{ - hb_face_destroy(mpHbFace); -} - -struct HbScriptRun -{ - int32_t mnMin; - int32_t mnEnd; - hb_script_t maScript; - - HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript) - : mnMin(nMin), mnEnd(nEnd), - maScript(hb_icu_script_to_script(aScript)) - {} -}; - -typedef std::vector HbScriptRuns; - -namespace vcl { - struct Run - { - int32_t nStart; - int32_t nEnd; - UScriptCode nCode; - Run(int32_t nStart_, int32_t nEnd_, UScriptCode nCode_) - : nStart(nStart_), nEnd(nEnd_), nCode(nCode_) - {} - }; - - class TextLayoutCache - { - public: - std::vector runs; - TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd) - { - vcl::ScriptRun aScriptRun( - reinterpret_cast(pStr), - nEnd); - while (aScriptRun.next()) - { - runs.push_back(Run(aScriptRun.getScriptStart(), - aScriptRun.getScriptEnd(), aScriptRun.getScriptCode())); - } - } - }; -} - -std::shared_ptr ServerFontLayout::CreateTextLayoutCache( - OUString const& rString) const -{ - return std::make_shared(rString.getStr(), rString.getLength()); -} - -bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs) -{ - ServerFont& rFont = rLayout.GetServerFont(); - FT_Face aFtFace = rFont.GetFtFace(); - - SAL_INFO("vcl.harfbuzz", "layout(" << this << ",rArgs=" << rArgs << ")"); - - static hb_font_funcs_t* pHbFontFuncs = getFontFuncs(); - - hb_font_t *pHbFont = hb_font_create(mpHbFace); - hb_font_set_funcs(pHbFont, pHbFontFuncs, &rFont, nullptr); - hb_font_set_scale(pHbFont, - ((uint64_t) aFtFace->size->metrics.x_scale * (uint64_t) mnUnitsPerEM) >> 16, - ((uint64_t) aFtFace->size->metrics.y_scale * (uint64_t) mnUnitsPerEM) >> 16); - hb_font_set_ppem(pHbFont, aFtFace->size->metrics.x_ppem, aFtFace->size->metrics.y_ppem); - - // allocate temporary arrays, note: round to even - int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1; - int32_t nVirtAdv = int32_t(aFtFace->size->metrics.height*rFont.GetStretch())>>6; - - rLayout.Reserve(nGlyphCapacity); - - const int nLength = rArgs.mrStr.getLength(); - const sal_Unicode *pStr = rArgs.mrStr.getStr(); - - std::unique_ptr pNewScriptRun; - vcl::TextLayoutCache const* pTextLayout; - if (rArgs.m_pTextLayoutCache) - { - pTextLayout = rArgs.m_pTextLayoutCache; // use cache! - } - else - { - pNewScriptRun.reset(new vcl::TextLayoutCache(pStr, rArgs.mnEndCharPos)); - pTextLayout = pNewScriptRun.get(); - } - - Point aCurrPos(0, 0); - while (true) - { - int nBidiMinRunPos, nBidiEndRunPos; - bool bRightToLeft; - if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft)) - break; - - // Find script subruns. - int nCurrentPos = nBidiMinRunPos; - HbScriptRuns aScriptSubRuns; - size_t k = 0; - for (; k < pTextLayout->runs.size(); ++k) - { - vcl::Run const& rRun(pTextLayout->runs[k]); - if (rRun.nStart <= nCurrentPos && nCurrentPos < rRun.nEnd) - { - break; - } - } - - while (nCurrentPos < nBidiEndRunPos && k < pTextLayout->runs.size()) - { - int32_t nMinRunPos = nCurrentPos; - int32_t nEndRunPos = std::min(pTextLayout->runs[k].nEnd, nBidiEndRunPos); - HbScriptRun aRun(nMinRunPos, nEndRunPos, pTextLayout->runs[k].nCode); - aScriptSubRuns.push_back(aRun); - - nCurrentPos = nEndRunPos; - ++k; - } - - // RTL subruns should be reversed to ensure that final glyph order is - // correct. - if (bRightToLeft) - std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end()); - - for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it) - { - int nMinRunPos = it->mnMin; - int nEndRunPos = it->mnEnd; - int nRunLen = nEndRunPos - nMinRunPos; - maHbScript = it->maScript; - // hb_language_from_string() accept ISO639-3 language tag except for Chinese. - LanguageTag &rTag = rArgs.maLanguageTag; - OString sLanguage = OUStringToOString( MsLangId::isChinese(rTag.getLanguageType()) ? rTag.getBcp47():rTag.getLanguage() , RTL_TEXTENCODING_UTF8 ); - - int nHbFlags = HB_BUFFER_FLAGS_DEFAULT; - if (nMinRunPos == 0) - nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */ - if (nEndRunPos == nLength) - nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */ - - hb_buffer_t *pHbBuffer = hb_buffer_create(); -#if !HB_VERSION_ATLEAST(1, 1, 0) - static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); - hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); -#endif - hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); - hb_buffer_set_script(pHbBuffer, maHbScript); - hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1)); - hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags); - hb_buffer_add_utf16( - pHbBuffer, reinterpret_cast(pStr), nLength, - nMinRunPos, nRunLen); - hb_shape(pHbFont, pHbBuffer, nullptr, 0); - - int nRunGlyphCount = hb_buffer_get_length(pHbBuffer); - hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr); - hb_glyph_position_t *pHbPositions = hb_buffer_get_glyph_positions(pHbBuffer, nullptr); - - for (int i = 0; i < nRunGlyphCount; ++i) { - int32_t nGlyphIndex = pHbGlyphInfos[i].codepoint; - int32_t nCharPos = pHbGlyphInfos[i].cluster; - - // if needed request glyph fallback by updating LayoutArgs - if (!nGlyphIndex) - { - rLayout.SetNeedFallback(rArgs, nCharPos, bRightToLeft); - if (SalLayoutFlags::ForFallback & rArgs.mnFlags) - continue; - } - - // apply vertical flags and glyph substitution - // XXX: Use HB_DIRECTION_TTB above and apply whatever flags magic - // FixupGlyphIndex() is doing, minus the GSUB part. - if (nCharPos >= 0) - { - sal_UCS4 aChar = rArgs.mrStr[nCharPos]; - nGlyphIndex = rFont.FixupGlyphIndex(nGlyphIndex, aChar); - } - - bool bInCluster = false; - if (i > 0 && pHbGlyphInfos[i].cluster == pHbGlyphInfos[i - 1].cluster) - bInCluster = true; - - long nGlyphFlags = 0; - if (bRightToLeft) - nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; - - if (bInCluster) - nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; - - // The whole IS_DIACRITIC concept is a stupid hack that was - // introduced ages ago to work around the utter brokenness of the - // way justification adjustments are applied (the DXArray fiasco). - // Since it is such a stupid hack, there is no sane way to directly - // map to concepts of the "outside" world, so we do some rather - // ugly hacks: - // * If the font has a GDEF table, we check for glyphs with mark - // glyph class which is sensible, except that some fonts - // (fdo#70968) assign mark class to spacing marks (which is wrong - // but usually harmless), so we try to sniff what HarfBuzz thinks - // about this glyph by checking if it gives it a zero advance - // width. - // * If the font has no GDEF table, we just check if the glyph has - // zero advance width, but this is stupid and can be wrong. A - // better way would to check the character's Unicode combining - // class, but unfortunately glyph gives combining marks the - // cluster value of its base character, so nCharPos will be - // pointing to the wrong character (but HarfBuzz might change - // this in the future). - bool bDiacritic = false; - if (hb_ot_layout_has_glyph_classes(mpHbFace)) - { - // the font has GDEF table - bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; - if (bMark && pHbPositions[i].x_advance == 0) - bDiacritic = true; - } - else - { - // the font lacks GDEF table - if (pHbPositions[i].x_advance == 0) - bDiacritic = true; - } - - if (bDiacritic) - nGlyphFlags |= GlyphItem::IS_DIACRITIC; - - int32_t nXOffset = pHbPositions[i].x_offset >> 6; - int32_t nYOffset = pHbPositions[i].y_offset >> 6; - int32_t nXAdvance = pHbPositions[i].x_advance >> 6; - int32_t nYAdvance = pHbPositions[i].y_advance >> 6; - if ( nGlyphIndex & GF_ROTMASK ) - nXAdvance = nVirtAdv; - - Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset)); - const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset, nYOffset); - rLayout.AppendGlyph(aGI); - - aCurrPos.X() += nXAdvance; - aCurrPos.Y() += nYAdvance; - } - - hb_buffer_destroy(pHbBuffer); - } - } - - hb_font_destroy(pHbFont); - - // sort glyphs in visual order - // and then in logical order (e.g. diacritics after cluster start) - // XXX: why? - rLayout.SortGlyphItems(); - - // determine need for kashida justification - if((rArgs.mpDXArray || rArgs.mnLayoutWidth) - && ((maHbScript == HB_SCRIPT_ARABIC) || (maHbScript == HB_SCRIPT_SYRIAC))) - rArgs.mnFlags |= SalLayoutFlags::KashidaJustification; - - return true; -} - -ServerFontLayoutEngine* ServerFont::GetLayoutEngine() -{ - // find best layout engine for font, platform, script and language - if (!mpLayoutEngine) { - mpLayoutEngine = new HbLayoutEngine(*this); - } - return mpLayoutEngine; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/generic/glyphs/glyphcache.cxx b/vcl/generic/glyphs/glyphcache.cxx deleted file mode 100644 index 33f06df2faab..000000000000 --- a/vcl/generic/glyphs/glyphcache.cxx +++ /dev/null @@ -1,379 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include -#include -#include "unx/freetype_glyphcache.hxx" - -#include -#include -#include -#include - -#include -#if ENABLE_GRAPHITE -#include -#endif - -#include -#include -#include - -static GlyphCache* pInstance = nullptr; - -GlyphCache::GlyphCache() -: mnMaxSize( 1500000 ), - mnBytesUsed(sizeof(GlyphCache)), - mnLruIndex(0), - mnGlyphCount(0), - mpCurrentGCFont(nullptr), - mpFtManager(nullptr) -{ - pInstance = this; - mpFtManager = new FreetypeManager; -} - -GlyphCache::~GlyphCache() -{ - InvalidateAllGlyphs(); - delete mpFtManager; -} - -void GlyphCache::InvalidateAllGlyphs() -{ - for( FontList::iterator it = maFontList.begin(), end = maFontList.end(); it != end; ++it ) - { - ServerFont* pServerFont = it->second; - // free all pServerFont related data - pServerFont->GarbageCollect( mnLruIndex+0x10000000 ); - delete pServerFont; - } - - maFontList.clear(); - mpCurrentGCFont = nullptr; -} - -inline -size_t GlyphCache::IFSD_Hash::operator()( const FontSelectPattern& rFontSelData ) const -{ - // TODO: is it worth to improve this hash function? - sal_IntPtr nFontId = reinterpret_cast( rFontSelData.mpFontData ); -#if ENABLE_GRAPHITE - if (rFontSelData.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1) - { - OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 ); - nFontId ^= aFeatName.hashCode(); - } -#endif - size_t nHash = nFontId << 8; - nHash += rFontSelData.mnHeight; - nHash += rFontSelData.mnOrientation; - nHash += size_t(rFontSelData.mbVertical); - nHash += rFontSelData.GetSlantType(); - nHash += rFontSelData.GetWeight(); -#if ENABLE_GRAPHITE - nHash += rFontSelData.meLanguage; -#endif - return nHash; -} - -bool GlyphCache::IFSD_Equal::operator()( const FontSelectPattern& rA, const FontSelectPattern& rB) const -{ - // check font ids - sal_IntPtr nFontIdA = reinterpret_cast( rA.mpFontData ); - sal_IntPtr nFontIdB = reinterpret_cast( rB.mpFontData ); - if( nFontIdA != nFontIdB ) - return false; - - // compare with the requested metrics - if( (rA.mnHeight != rB.mnHeight) - || (rA.mnOrientation != rB.mnOrientation) - || (rA.mbVertical != rB.mbVertical) - || (rA.mbNonAntialiased != rB.mbNonAntialiased) ) - return false; - - if( (rA.GetSlantType() != rB.GetSlantType()) - || (rA.GetWeight() != rB.GetWeight()) ) - return false; - - // NOTE: ignoring meFamily deliberately - - // compare with the requested width, allow default width - int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight; - int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight; - if( nAWidth != nBWidth ) - return false; - -#if ENABLE_GRAPHITE - if (rA.meLanguage != rB.meLanguage) - return false; - // check for features - if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1 || - rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1) && rA.maTargetName != rB.maTargetName) - return false; -#endif - - if (rA.mbEmbolden != rB.mbEmbolden) - return false; - - if (rA.maItalicMatrix != rB.maItalicMatrix) - return false; - - return true; -} - -GlyphCache& GlyphCache::GetInstance() -{ - return *pInstance; -} - -void GlyphCache::AddFontFile( const OString& rNormalizedName, int nFaceNum, - sal_IntPtr nFontId, const FontAttributes& rDFA) -{ - if( mpFtManager ) - mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA); -} - -void GlyphCache::AnnounceFonts( PhysicalFontCollection* pFontCollection ) const -{ - if( mpFtManager ) - mpFtManager->AnnounceFonts( pFontCollection ); -} - -void GlyphCache::ClearFontCache() -{ - InvalidateAllGlyphs(); - if (mpFtManager) - mpFtManager->ClearFontList(); -} - -ServerFont* GlyphCache::CacheFont( const FontSelectPattern& rFontSelData ) -{ - // a serverfont request has pFontData - if( rFontSelData.mpFontData == nullptr ) - return nullptr; - // a serverfont request has a fontid > 0 - sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId(); - if( nFontId <= 0 ) - return nullptr; - - // the FontList's key mpFontData member is reinterpreted as font id - FontSelectPattern aFontSelData = rFontSelData; - aFontSelData.mpFontData = reinterpret_cast( nFontId ); - FontList::iterator it = maFontList.find( aFontSelData ); - if( it != maFontList.end() ) - { - ServerFont* pFound = it->second; - if( pFound ) - pFound->AddRef(); - return pFound; - } - - // font not cached yet => create new font item - ServerFont* pNew = nullptr; - if( mpFtManager ) - pNew = mpFtManager->CreateFont( aFontSelData ); - - if( pNew ) - { - maFontList[ aFontSelData ] = pNew; - mnBytesUsed += pNew->GetByteCount(); - - // enable garbage collection for new font - if( !mpCurrentGCFont ) - { - mpCurrentGCFont = pNew; - pNew->mpNextGCFont = pNew; - pNew->mpPrevGCFont = pNew; - } - else - { - pNew->mpNextGCFont = mpCurrentGCFont; - pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont; - pNew->mpPrevGCFont->mpNextGCFont = pNew; - mpCurrentGCFont->mpPrevGCFont = pNew; - } - } - - return pNew; -} - -void GlyphCache::UncacheFont( ServerFont& rServerFont ) -{ - if( (rServerFont.Release() <= 0) && (mnMaxSize <= mnBytesUsed) ) - { - mpCurrentGCFont = &rServerFont; - GarbageCollect(); - } -} - -void GlyphCache::GarbageCollect() -{ - // when current GC font has been destroyed get another one - if( !mpCurrentGCFont ) - { - FontList::iterator it = maFontList.begin(); - if( it != maFontList.end() ) - mpCurrentGCFont = it->second; - } - - // unless there is no other font to collect - if( !mpCurrentGCFont ) - return; - - // prepare advance to next font for garbage collection - ServerFont* const pServerFont = mpCurrentGCFont; - mpCurrentGCFont = pServerFont->mpNextGCFont; - - if( (pServerFont == mpCurrentGCFont) // no other fonts - || (pServerFont->GetRefCount() > 0) ) // font still used - { - // try to garbage collect at least a few bytes - pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 ); - } - else // current GC font is unreferenced - { - DBG_ASSERT( (pServerFont->GetRefCount() == 0), - "GlyphCache::GC detected RefCount underflow" ); - - // free all pServerFont related data - pServerFont->GarbageCollect( mnLruIndex+0x10000000 ); - if( pServerFont == mpCurrentGCFont ) - mpCurrentGCFont = nullptr; - const FontSelectPattern& rIFSD = pServerFont->GetFontSelData(); - maFontList.erase( rIFSD ); - mnBytesUsed -= pServerFont->GetByteCount(); - - // remove font from list of garbage collected fonts - if( pServerFont->mpPrevGCFont ) - pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont; - if( pServerFont->mpNextGCFont ) - pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont; - if( pServerFont == mpCurrentGCFont ) - mpCurrentGCFont = nullptr; - - delete pServerFont; - } -} - -inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData ) -{ - rGlyphData.SetLruValue( mnLruIndex++ ); -} - -inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData ) -{ - ++mnGlyphCount; - mnBytesUsed += sizeof( rGlyphData ); - UsingGlyph( rServerFont, rGlyphData ); - GrowNotify(); -} - -void GlyphCache::GrowNotify() -{ - if( mnBytesUsed > mnMaxSize ) - GarbageCollect(); -} - -inline void GlyphCache::RemovingGlyph() -{ - mnBytesUsed -= sizeof( GlyphData ); - --mnGlyphCount; -} - -void ServerFont::ReleaseFromGarbageCollect() -{ - // remove from GC list - ServerFont* pPrev = mpPrevGCFont; - ServerFont* pNext = mpNextGCFont; - if( pPrev ) pPrev->mpNextGCFont = pNext; - if( pNext ) pNext->mpPrevGCFont = pPrev; - mpPrevGCFont = nullptr; - mpNextGCFont = nullptr; -} - -long ServerFont::Release() const -{ - DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" ); - return --mnRefCount; -} - -GlyphData& ServerFont::GetGlyphData( sal_GlyphId aGlyphId ) -{ - // usually the GlyphData is cached - GlyphList::iterator it = maGlyphList.find( aGlyphId ); - if( it != maGlyphList.end() ) { - GlyphData& rGlyphData = it->second; - GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData ); - return rGlyphData; - } - - // sometimes not => we need to create and initialize it ourselves - GlyphData& rGlyphData = maGlyphList[ aGlyphId ]; - mnBytesUsed += sizeof( GlyphData ); - InitGlyphData( aGlyphId, rGlyphData ); - GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData ); - return rGlyphData; -} - -void ServerFont::GarbageCollect( long nMinLruIndex ) -{ - GlyphList::iterator it = maGlyphList.begin(); - while( it != maGlyphList.end() ) - { - GlyphData& rGD = it->second; - if( (nMinLruIndex - rGD.GetLruValue()) > 0 ) - { - OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) ); - mnBytesUsed -= sizeof( GlyphData ); - GlyphCache::GetInstance().RemovingGlyph(); - it = maGlyphList.erase( it ); - } - else - ++it; - } -} - -ServerFontInstance::ServerFontInstance( FontSelectPattern& rFSD ) -: LogicalFontInstance( rFSD ) -, mpServerFont( nullptr ) -, mbGotFontOptions( false ) -{} - -void ServerFontInstance::SetServerFont(ServerFont* p) -{ - if (p == mpServerFont) - return; - if (mpServerFont) - mpServerFont->Release(); - mpServerFont = p; - if (mpServerFont) - mpServerFont->AddRef(); -} - -ServerFontInstance::~ServerFontInstance() -{ - // TODO: remove the ServerFont here instead of in the GlyphCache - if (mpServerFont) - mpServerFont->Release(); -} -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/generic/glyphs/graphite_serverfont.cxx b/vcl/generic/glyphs/graphite_serverfont.cxx deleted file mode 100644 index 623df7b3fb8d..000000000000 --- a/vcl/generic/glyphs/graphite_serverfont.cxx +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -// Header files - -// Platform -#include -#include -// Module -#include "unx/freetype_glyphcache.hxx" -#include "generic/glyphcache.hxx" -#include -#include - -float freetypeServerFontAdvance(const void* appFontHandle, gr_uint16 glyphId) -{ - ServerFont * pServerFont = - const_cast - (static_cast(appFontHandle)); - if (pServerFont) - { - return static_cast(pServerFont->GetGlyphMetric(glyphId).GetCharWidth()); - } - return .0f; -} - -// An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used. - -GraphiteServerFontLayout::GraphiteServerFontLayout(ServerFont& rServerFont) throw() - : ServerFontLayout(rServerFont), - maImpl(rServerFont.GetGraphiteFace()->face(), rServerFont) - , mpFeatures(nullptr) -{ - gr_font * pFont = rServerFont.GetGraphiteFace()->font(rServerFont.GetFontSelData().mnHeight, rServerFont.NeedsArtificialBold(), rServerFont.NeedsArtificialItalic()); - if (!pFont) - { - pFont = gr_make_font_with_advance_fn( - // need to use mnHeight here, mfExactHeight can give wrong values - static_cast(rServerFont.GetFontSelData().mnHeight), - &rServerFont, - freetypeServerFontAdvance, - rServerFont.GetGraphiteFace()->face()); - rServerFont.GetGraphiteFace()->addFont(rServerFont.GetFontSelData().mnHeight, pFont, rServerFont.NeedsArtificialBold(), rServerFont.NeedsArtificialItalic()); - } - maImpl.SetFont(pFont); - OString aLang(""); - if (rServerFont.GetFontSelData().meLanguage != LANGUAGE_DONTKNOW) - { - aLang = OUStringToOString( LanguageTag( rServerFont.GetFontSelData().meLanguage ).getBcp47(), - RTL_TEXTENCODING_UTF8 ); - } - OString name = OUStringToOString( - rServerFont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 ); -#ifdef DEBUG - printf("GraphiteServerFontLayout %lx %s size %d %f\n", (long unsigned int)this, name.getStr(), - rServerFont.GetMetricsFT().x_ppem, - rServerFont.GetFontSelData().mfExactHeight); -#endif - sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1; - if (nFeat > 0) - { - OString aFeat = name.copy(nFeat, name.getLength() - nFeat); - mpFeatures = new grutils::GrFeatureParser( - rServerFont.GetGraphiteFace()->face(), aFeat, aLang); -#ifdef DEBUG - if (mpFeatures) - printf("GraphiteServerFontLayout %s/%s/%s %x language %d features %d errors\n", - OUStringToOString( rServerFont.GetFontSelData().GetFamilyName(), - RTL_TEXTENCODING_UTF8 ).getStr(), - OUStringToOString( rServerFont.GetFontSelData().maTargetName, - RTL_TEXTENCODING_UTF8 ).getStr(), - OUStringToOString( rServerFont.GetFontSelData().maSearchName, - RTL_TEXTENCODING_UTF8 ).getStr(), - rServerFont.GetFontSelData().meLanguage, - (int)mpFeatures->numFeatures(), mpFeatures->parseErrors()); -#endif - } - else - { - mpFeatures = new grutils::GrFeatureParser( - rServerFont.GetGraphiteFace()->face(), aLang); - } - maImpl.SetFeatures(mpFeatures); -} - -GraphiteServerFontLayout::~GraphiteServerFontLayout() throw() -{ - delete mpFeatures; - mpFeatures = nullptr; -} - -bool GraphiteServerFontLayout::IsGraphiteEnabledFont(ServerFont& rServerFont) -{ - if (rServerFont.GetGraphiteFace()) - { -#ifdef DEBUG - printf("IsGraphiteEnabledFont\n"); -#endif - return true; - } - return false; -} - -sal_GlyphId GraphiteLayoutImpl::getKashidaGlyph(int & width) -{ - int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); - if( nKashidaIndex != 0 ) - { - const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); - width = rGM.GetCharWidth(); - } - else - { - width = 0; - } - return nKashidaIndex; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/generic/glyphs/scrptrun.cxx b/vcl/generic/glyphs/scrptrun.cxx deleted file mode 100644 index d6557d79a894..000000000000 --- a/vcl/generic/glyphs/scrptrun.cxx +++ /dev/null @@ -1,234 +0,0 @@ -/* - ******************************************************************************* - * - * Copyright (c) 1995-2013 International Business Machines Corporation and others - * - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * provided that the above copyright notice(s) and this permission notice appear - * in all copies of the Software and that both the above copyright notice(s) and - * this permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN - * NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE - * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY - * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall not be - * used in advertising or otherwise to promote the sale, use or other dealings in - * this Software without prior written authorization of the copyright holder. - * - ******************************************************************************* - * file name: scrptrun.cpp - * - * created on: 10/17/2001 - * created by: Eric R. Mader - */ -/** - * This file is largely copied from the ICU project, - * under folder source/extra/scrptrun/scrptrun.cpp - */ -#include "unicode/utypes.h" -#include "unicode/uscript.h" - -#include "scrptrun.h" -#include - -namespace { - -struct PairIndices -{ - int8_t ma00[0xff]; - int8_t ma20[0x7f]; - int8_t ma30[0x7f]; - - PairIndices() - { - std::fill_n(ma00, 0xff, -1); - std::fill_n(ma20, 0x7f, -1); - std::fill_n(ma30, 0x7f, -1); - - // characters in the range 0x0000 - 0x007e (inclusive) - // ascii paired punctuation - ma00[0x28] = 0; - ma00[0x29] = 1; - ma00[0x3c] = 2; - ma00[0x3e] = 3; - ma00[0x5b] = 4; - ma00[0x5d] = 5; - ma00[0x7b] = 6; - ma00[0x7d] = 7; - // guillemets - ma00[0xab] = 8; - ma00[0xbb] = 9; - - // characters in the range 0x2000 - 0x207e (inclusive) - // general punctuation - ma20[0x18] = 10; - ma20[0x19] = 11; - ma20[0x1c] = 12; - ma20[0x1d] = 13; - ma20[0x39] = 14; - ma20[0x3a] = 15; - - // characters in the range 0x3000 - 0x307e (inclusive) - // chinese paired punctuation - ma30[0x08] = 16; - ma30[0x09] = 17; - ma30[0x0a] = 18; - ma30[0x0b] = 19; - ma30[0x0c] = 20; - ma30[0x0d] = 21; - ma30[0x0e] = 22; - ma30[0x0f] = 23; - ma30[0x10] = 24; - ma30[0x11] = 25; - ma30[0x14] = 26; - ma30[0x15] = 27; - ma30[0x16] = 28; - ma30[0x17] = 29; - ma30[0x18] = 30; - ma30[0x19] = 31; - ma30[0x1a] = 32; - ma30[0x1b] = 33; - } - - inline int32_t getPairIndex(UChar32 ch) const - { - if (ch < 0xff) - return ma00[ch]; - if (ch >= 0x2000 && ch < 0x207f) - return ma20[ch - 0x2000]; - if (ch >= 0x3000 && ch < 0x307f) - return ma30[ch - 0x3000]; - return -1; - } - -}; - -} - -static const PairIndices gPairIndices; - - -namespace vcl { - -const char ScriptRun::fgClassID=0; - -static inline UBool sameScript(int32_t scriptOne, int32_t scriptTwo) -{ - return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo; -} - -UBool ScriptRun::next() -{ - int32_t startSP = parenSP; // used to find the first new open character - UErrorCode error = U_ZERO_ERROR; - - // if we've fallen off the end of the text, we're done - if (scriptEnd >= charLimit) { - return false; - } - - scriptCode = USCRIPT_COMMON; - - for (scriptStart = scriptEnd; scriptEnd < charLimit; scriptEnd += 1) { - UChar high = charArray[scriptEnd]; - UChar32 ch = high; - - // if the character is a high surrogate and it's not the last one - // in the text, see if it's followed by a low surrogate - if (high >= 0xD800 && high <= 0xDBFF && scriptEnd < charLimit - 1) - { - UChar low = charArray[scriptEnd + 1]; - - // if it is followed by a low surrogate, - // consume it and form the full character - if (low >= 0xDC00 && low <= 0xDFFF) { - ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000; - scriptEnd += 1; - } - } - - UScriptCode sc = uscript_getScript(ch, &error); - int32_t pairIndex = gPairIndices.getPairIndex(ch); - - // Paired character handling: - - // if it's an open character, push it onto the stack. - // if it's a close character, find the matching open on the - // stack, and use that script code. Any non-matching open - // characters above it on the stack will be poped. - if (pairIndex >= 0) { - if ((pairIndex & 1) == 0) { - ++parenSP; - int32_t nVecSize = parenStack.size(); - if (parenSP == nVecSize) - parenStack.resize(nVecSize + 128); - parenStack[parenSP].pairIndex = pairIndex; - parenStack[parenSP].scriptCode = scriptCode; - } else if (parenSP >= 0) { - int32_t pi = pairIndex & ~1; - - while (parenSP >= 0 && parenStack[parenSP].pairIndex != pi) { - parenSP -= 1; - } - - if (parenSP < startSP) { - startSP = parenSP; - } - - if (parenSP >= 0) { - sc = parenStack[parenSP].scriptCode; - } - } - } - - if (sameScript(scriptCode, sc)) { - if (scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) { - scriptCode = sc; - - // now that we have a final script code, fix any open - // characters we pushed before we knew the script code. - while (startSP < parenSP) { - parenStack[++startSP].scriptCode = scriptCode; - } - } - - // if this character is a close paired character, - // pop it from the stack - if (pairIndex >= 0 && (pairIndex & 1) != 0 && parenSP >= 0) { - parenSP -= 1; - /* decrement startSP only if it is >= 0, - decrementing it unnecessarily will lead to memory corruption - while processing the above while block. - e.g. startSP = -4 , parenSP = -1 - */ - if (startSP >= 0) { - startSP -= 1; - } - } - } else { - // if the run broke on a surrogate pair, - // end it before the high surrogate - if (ch >= 0x10000) { - scriptEnd -= 1; - } - - break; - } - } - - return true; -} - -} diff --git a/vcl/generic/glyphs/scrptrun.h b/vcl/generic/glyphs/scrptrun.h deleted file mode 100644 index 2efcff4110ba..000000000000 --- a/vcl/generic/glyphs/scrptrun.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - ******************************************************************************* - * - * Copyright (c) 1995-2013 International Business Machines Corporation and others - * - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * provided that the above copyright notice(s) and this permission notice appear - * in all copies of the Software and that both the above copyright notice(s) and - * this permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN - * NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE - * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY - * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall not be - * used in advertising or otherwise to promote the sale, use or other dealings in - * this Software without prior written authorization of the copyright holder. - * - ******************************************************************************* - * file name: scrptrun.h - * - * created on: 10/17/2001 - * created by: Eric R. Mader - */ - -#ifndef INCLUDED_VCL_GENERIC_GLYPHS_SCRPTRUN_H -#define INCLUDED_VCL_GENERIC_GLYPHS_SCRPTRUN_H - -#include - -#include -#include "unicode/utypes.h" -#include "unicode/uobject.h" -#include "unicode/uscript.h" -#include - -namespace vcl { - -struct ParenStackEntry -{ - int32_t pairIndex; - UScriptCode scriptCode; - ParenStackEntry() - : pairIndex(0) - , scriptCode(USCRIPT_INVALID_CODE) - { - } -}; - -class ScriptRun : public UObject { -public: - ScriptRun(); - - ScriptRun(const UChar chars[], int32_t length); - - ScriptRun(const UChar chars[], int32_t start, int32_t length); - - void reset(); - - void reset(int32_t start, int32_t count); - - void reset(const UChar chars[], int32_t start, int32_t length); - - int32_t getScriptStart(); - - int32_t getScriptEnd(); - - UScriptCode getScriptCode(); - - UBool next(); - - /** -s * ICU "poor man's RTTI", returns a UClassID for the actual class. - * - * @stable ICU 2.2 - */ - virtual inline UClassID getDynamicClassID() const override { return getStaticClassID(); } - - /** - * ICU "poor man's RTTI", returns a UClassID for this class. - * - * @stable ICU 2.2 - */ - static inline UClassID getStaticClassID() { return static_cast(const_cast(&fgClassID)); } - -private: - - int32_t charStart; - int32_t charLimit; - const UChar *charArray; - - int32_t scriptStart; - int32_t scriptEnd; - UScriptCode scriptCode; - - std::vector parenStack; - int32_t parenSP; - - /** - * The address of this static class variable serves as this class's ID - * for ICU "poor man's RTTI". - */ - static const char fgClassID; -}; - -inline ScriptRun::ScriptRun() -{ - reset(NULL, 0, 0); -} - -inline ScriptRun::ScriptRun(const UChar chars[], int32_t length) -{ - reset(chars, 0, length); -} - -inline ScriptRun::ScriptRun(const UChar chars[], int32_t start, int32_t length) -{ - reset(chars, start, length); -} - -inline int32_t ScriptRun::getScriptStart() -{ - return scriptStart; -} - -inline int32_t ScriptRun::getScriptEnd() -{ - return scriptEnd; -} - -inline UScriptCode ScriptRun::getScriptCode() -{ - return scriptCode; -} - -inline void ScriptRun::reset() -{ - scriptStart = charStart; - scriptEnd = charStart; - scriptCode = USCRIPT_INVALID_CODE; - parenSP = -1; - parenStack.resize(128); -} - -inline void ScriptRun::reset(int32_t start, int32_t length) -{ - charStart = start; - charLimit = start + length; - - reset(); -} - -inline void ScriptRun::reset(const UChar chars[], int32_t start, int32_t length) -{ - charArray = chars; - - reset(start, length); -} - -} - -#endif diff --git a/vcl/generic/print/genpspgraphics.cxx b/vcl/generic/print/genpspgraphics.cxx index 145bf7dc18e6..d3cc75c1466b 100644 --- a/vcl/generic/print/genpspgraphics.cxx +++ b/vcl/generic/print/genpspgraphics.cxx @@ -46,7 +46,7 @@ #include "fontsubset.hxx" #include "generic/geninst.h" #include "generic/genpspgraphics.h" -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" #include "generic/printergfx.hxx" #include "impfont.hxx" #include "langboost.hxx" diff --git a/vcl/headless/svpglyphcache.cxx b/vcl/headless/svpglyphcache.cxx index a94ea85ea76f..e5c56751b9dc 100644 --- a/vcl/headless/svpglyphcache.cxx +++ b/vcl/headless/svpglyphcache.cxx @@ -25,7 +25,7 @@ #include #include "generic/geninst.h" -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" #include "headless/svpgdi.hxx" namespace diff --git a/vcl/inc/generic/glyphcache.hxx b/vcl/inc/generic/glyphcache.hxx deleted file mode 100644 index da8f29c57608..000000000000 --- a/vcl/inc/generic/glyphcache.hxx +++ /dev/null @@ -1,300 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX -#define INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX - -#include - -#include -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#include -#include -#include -#include -#include - -#include -#include -#include "fontattributes.hxx" - -#include - -class FreetypeManager; -class FreetypeFontInfo; -class GlyphData; -class GraphiteFaceWrapper; -class FontConfigFontOptions; -class PhysicalFontCollection; -class ServerFont; -class ServerFontLayout; -class ServerFontLayoutEngine; -class SvpGcpHelper; - -namespace basegfx { class B2DPolyPolygon; } -namespace vcl { struct FontCapabilities; } - -class VCL_DLLPUBLIC GlyphCache -{ -public: - explicit GlyphCache(); - virtual ~GlyphCache(); - - static GlyphCache& GetInstance(); - - void AddFontFile( - const OString& rNormalizedName, - int nFaceNum, sal_IntPtr nFontId, - const FontAttributes&); - - void AnnounceFonts( PhysicalFontCollection* ) const; - - ServerFont* CacheFont( const FontSelectPattern& ); - void UncacheFont( ServerFont& ); - void ClearFontCache(); - void InvalidateAllGlyphs(); - -private: - friend class ServerFont; - // used by ServerFont class only - void AddedGlyph( ServerFont&, GlyphData& ); - void RemovingGlyph(); - void UsingGlyph( ServerFont&, GlyphData& ); - void GrowNotify(); - -private: - void GarbageCollect(); - - // the GlyphCache's FontList matches a font request to a serverfont instance - // the FontList key's mpFontData member is reinterpreted as integer font id - struct IFSD_Equal{ bool operator()( const FontSelectPattern&, const FontSelectPattern& ) const; }; - struct IFSD_Hash{ size_t operator()( const FontSelectPattern& ) const; }; - typedef std::unordered_map FontList; - - FontList maFontList; - sal_uLong mnMaxSize; // max overall cache size in bytes - mutable sal_uLong mnBytesUsed; - mutable long mnLruIndex; - mutable int mnGlyphCount; - ServerFont* mpCurrentGCFont; - - FreetypeManager* mpFtManager; -}; - -class GlyphMetric -{ -public: - GlyphMetric() : mnAdvanceWidth(0) {} - - Point GetOffset() const { return maOffset; } - Size GetSize() const { return maSize; } - long GetCharWidth() const { return mnAdvanceWidth; } - -protected: - friend class GlyphData; - void SetOffset( int nX, int nY ) { maOffset = Point( nX, nY); } - void SetDelta( int nX, int nY ) { maDelta = Point( nX, nY); } - void SetSize( const Size& s ) { maSize = s; } - void SetCharWidth( long nW ) { mnAdvanceWidth = nW; } - -private: - long mnAdvanceWidth; - Point maDelta; - Point maOffset; - Size maSize; -}; - -class GlyphData -{ -public: - GlyphData() : mnLruValue(0) {} - - const GlyphMetric& GetMetric() const { return maFontAttributes; } - - void SetSize( const Size& s) { maFontAttributes.SetSize( s ); } - void SetOffset( int nX, int nY ) { maFontAttributes.SetOffset( nX, nY ); } - void SetDelta( int nX, int nY ) { maFontAttributes.SetDelta( nX, nY ); } - void SetCharWidth( long nW ) { maFontAttributes.SetCharWidth( nW ); } - - void SetLruValue( int n ) const { mnLruValue = n; } - long GetLruValue() const { return mnLruValue;} - -private: - GlyphMetric maFontAttributes; - - // used by GlyphCache for cache LRU algorithm - mutable long mnLruValue; -}; - -class VCL_DLLPUBLIC ServerFont -{ -public: - ServerFont( const FontSelectPattern&, FreetypeFontInfo* ); - virtual ~ServerFont(); - - const OString& GetFontFileName() const; - bool TestFont() const { return mbFaceOk;} - FT_Face GetFtFace() const; - int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); } - void SetFontOptions(std::shared_ptr); - std::shared_ptr GetFontOptions() const; - bool NeedsArtificialBold() const { return mbArtBold; } - bool NeedsArtificialItalic() const { return mbArtItalic; } - - const FontSelectPattern& GetFontSelData() const { return maFontSelData; } - - void FetchFontAttributes( FontAttributes&, long& rFactor ) const; - const unsigned char* GetTable( const char* pName, sal_uLong* pLength ); - int GetEmUnits() const { return maFaceFT->units_per_EM;} - double GetStretch() { return mfStretch; } - const FontCharMapPtr GetFontCharMap() const; - bool GetFontCapabilities(vcl::FontCapabilities &) const; - - GlyphData& GetGlyphData( sal_GlyphId ); - const GlyphMetric& GetGlyphMetric( sal_GlyphId aGlyphId ) - { return GetGlyphData( aGlyphId ).GetMetric(); } - -#if ENABLE_GRAPHITE - GraphiteFaceWrapper* GetGraphiteFace() const; -#endif - - sal_GlyphId GetGlyphIndex( sal_UCS4 ) const; - sal_GlyphId GetRawGlyphIndex( sal_UCS4, sal_UCS4 = 0 ) const; - sal_GlyphId FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const; - bool GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const; - bool GetAntialiasAdvice() const; - -private: - friend class GlyphCache; - friend class ServerFontLayout; - friend class ServerFontInstance; - friend class X11SalGraphics; - friend class CairoTextRender; - - void AddRef() const { ++mnRefCount; } - long GetRefCount() const { return mnRefCount; } - long Release() const; - sal_uLong GetByteCount() const { return mnBytesUsed; } - - void InitGlyphData( sal_GlyphId, GlyphData& ) const; - void GarbageCollect( long ); - void ReleaseFromGarbageCollect(); - - int ApplyGlyphTransform( int nGlyphFlags, FT_GlyphRec_*, bool ) const; - bool ApplyGSUB( const FontSelectPattern& ); - - ServerFontLayoutEngine* GetLayoutEngine(); - - typedef std::unordered_map GlyphList; - mutable GlyphList maGlyphList; - - const FontSelectPattern maFontSelData; - - // used by GlyphCache for cache LRU algorithm - mutable long mnRefCount; - mutable sal_uLong mnBytesUsed; - - ServerFont* mpPrevGCFont; - ServerFont* mpNextGCFont; - - // 16.16 fixed point values used for a rotated font - long mnCos; - long mnSin; - - int mnWidth; - int mnPrioEmbedded; - int mnPrioAntiAlias; - int mnPrioAutoHint; - FreetypeFontInfo* mpFontInfo; - FT_Int mnLoadFlags; - double mfStretch; - FT_FaceRec_* maFaceFT; - FT_SizeRec_* maSizeFT; - - std::shared_ptr mxFontOptions; - - bool mbFaceOk; - bool mbArtItalic; - bool mbArtBold; - bool mbUseGamma; - - typedef std::unordered_map GlyphSubstitution; - GlyphSubstitution maGlyphSubstitution; - - ServerFontLayoutEngine* mpLayoutEngine; -}; - -// a class for cache entries for physical font instances that are based on serverfonts -class VCL_DLLPUBLIC ServerFontInstance : public LogicalFontInstance -{ -public: - ServerFontInstance( FontSelectPattern& ); - virtual ~ServerFontInstance(); - - void SetServerFont(ServerFont* p); - void HandleFontOptions(); - -private: - ServerFont* mpServerFont; - std::shared_ptr mxFontOptions; - bool mbGotFontOptions; - -}; - -class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout -{ -public: - ServerFontLayout( ServerFont& ); - - virtual bool LayoutText( ImplLayoutArgs& ) override; - virtual void AdjustLayout( ImplLayoutArgs& ) override; - virtual void DrawText( SalGraphics& ) const override; - - void SetNeedFallback( - ImplLayoutArgs& rArgs, - sal_Int32 nIndex, - bool bRightToLeft); - - ServerFont& GetServerFont() const { return mrServerFont; } - - virtual std::shared_ptr - CreateTextLayoutCache(OUString const&) const override; - -private: - ServerFont& mrServerFont; - css::uno::Reference mxBreak; - - ServerFontLayout( const ServerFontLayout& ) = delete; - ServerFontLayout& operator=( const ServerFontLayout& ) = delete; - -}; - -class ServerFontLayoutEngine -{ -public: - virtual ~ServerFontLayoutEngine() {} - - virtual bool Layout(ServerFontLayout&, ImplLayoutArgs&) = 0; -}; - -#endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphite_serverfont.hxx b/vcl/inc/graphite_serverfont.hxx index 0a5b9133acf7..137cb14ba5e7 100644 --- a/vcl/inc/graphite_serverfont.hxx +++ b/vcl/inc/graphite_serverfont.hxx @@ -26,7 +26,7 @@ #ifndef _MSC_VER #include -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" class PhysicalFontFace; diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx index cf3c66b5aa10..3b8d315e5a5c 100644 --- a/vcl/inc/unx/freetype_glyphcache.hxx +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -20,7 +20,7 @@ #ifndef INCLUDED_VCL_GENERIC_GLYPHS_GCACH_FTYP_HXX #define INCLUDED_VCL_GENERIC_GLYPHS_GCACH_FTYP_HXX -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" #include "PhysicalFontFace.hxx" #include diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx new file mode 100644 index 000000000000..da8f29c57608 --- /dev/null +++ b/vcl/inc/unx/glyphcache.hxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX +#define INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX + +#include + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include +#include +#include +#include +#include + +#include +#include +#include "fontattributes.hxx" + +#include + +class FreetypeManager; +class FreetypeFontInfo; +class GlyphData; +class GraphiteFaceWrapper; +class FontConfigFontOptions; +class PhysicalFontCollection; +class ServerFont; +class ServerFontLayout; +class ServerFontLayoutEngine; +class SvpGcpHelper; + +namespace basegfx { class B2DPolyPolygon; } +namespace vcl { struct FontCapabilities; } + +class VCL_DLLPUBLIC GlyphCache +{ +public: + explicit GlyphCache(); + virtual ~GlyphCache(); + + static GlyphCache& GetInstance(); + + void AddFontFile( + const OString& rNormalizedName, + int nFaceNum, sal_IntPtr nFontId, + const FontAttributes&); + + void AnnounceFonts( PhysicalFontCollection* ) const; + + ServerFont* CacheFont( const FontSelectPattern& ); + void UncacheFont( ServerFont& ); + void ClearFontCache(); + void InvalidateAllGlyphs(); + +private: + friend class ServerFont; + // used by ServerFont class only + void AddedGlyph( ServerFont&, GlyphData& ); + void RemovingGlyph(); + void UsingGlyph( ServerFont&, GlyphData& ); + void GrowNotify(); + +private: + void GarbageCollect(); + + // the GlyphCache's FontList matches a font request to a serverfont instance + // the FontList key's mpFontData member is reinterpreted as integer font id + struct IFSD_Equal{ bool operator()( const FontSelectPattern&, const FontSelectPattern& ) const; }; + struct IFSD_Hash{ size_t operator()( const FontSelectPattern& ) const; }; + typedef std::unordered_map FontList; + + FontList maFontList; + sal_uLong mnMaxSize; // max overall cache size in bytes + mutable sal_uLong mnBytesUsed; + mutable long mnLruIndex; + mutable int mnGlyphCount; + ServerFont* mpCurrentGCFont; + + FreetypeManager* mpFtManager; +}; + +class GlyphMetric +{ +public: + GlyphMetric() : mnAdvanceWidth(0) {} + + Point GetOffset() const { return maOffset; } + Size GetSize() const { return maSize; } + long GetCharWidth() const { return mnAdvanceWidth; } + +protected: + friend class GlyphData; + void SetOffset( int nX, int nY ) { maOffset = Point( nX, nY); } + void SetDelta( int nX, int nY ) { maDelta = Point( nX, nY); } + void SetSize( const Size& s ) { maSize = s; } + void SetCharWidth( long nW ) { mnAdvanceWidth = nW; } + +private: + long mnAdvanceWidth; + Point maDelta; + Point maOffset; + Size maSize; +}; + +class GlyphData +{ +public: + GlyphData() : mnLruValue(0) {} + + const GlyphMetric& GetMetric() const { return maFontAttributes; } + + void SetSize( const Size& s) { maFontAttributes.SetSize( s ); } + void SetOffset( int nX, int nY ) { maFontAttributes.SetOffset( nX, nY ); } + void SetDelta( int nX, int nY ) { maFontAttributes.SetDelta( nX, nY ); } + void SetCharWidth( long nW ) { maFontAttributes.SetCharWidth( nW ); } + + void SetLruValue( int n ) const { mnLruValue = n; } + long GetLruValue() const { return mnLruValue;} + +private: + GlyphMetric maFontAttributes; + + // used by GlyphCache for cache LRU algorithm + mutable long mnLruValue; +}; + +class VCL_DLLPUBLIC ServerFont +{ +public: + ServerFont( const FontSelectPattern&, FreetypeFontInfo* ); + virtual ~ServerFont(); + + const OString& GetFontFileName() const; + bool TestFont() const { return mbFaceOk;} + FT_Face GetFtFace() const; + int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); } + void SetFontOptions(std::shared_ptr); + std::shared_ptr GetFontOptions() const; + bool NeedsArtificialBold() const { return mbArtBold; } + bool NeedsArtificialItalic() const { return mbArtItalic; } + + const FontSelectPattern& GetFontSelData() const { return maFontSelData; } + + void FetchFontAttributes( FontAttributes&, long& rFactor ) const; + const unsigned char* GetTable( const char* pName, sal_uLong* pLength ); + int GetEmUnits() const { return maFaceFT->units_per_EM;} + double GetStretch() { return mfStretch; } + const FontCharMapPtr GetFontCharMap() const; + bool GetFontCapabilities(vcl::FontCapabilities &) const; + + GlyphData& GetGlyphData( sal_GlyphId ); + const GlyphMetric& GetGlyphMetric( sal_GlyphId aGlyphId ) + { return GetGlyphData( aGlyphId ).GetMetric(); } + +#if ENABLE_GRAPHITE + GraphiteFaceWrapper* GetGraphiteFace() const; +#endif + + sal_GlyphId GetGlyphIndex( sal_UCS4 ) const; + sal_GlyphId GetRawGlyphIndex( sal_UCS4, sal_UCS4 = 0 ) const; + sal_GlyphId FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const; + bool GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const; + bool GetAntialiasAdvice() const; + +private: + friend class GlyphCache; + friend class ServerFontLayout; + friend class ServerFontInstance; + friend class X11SalGraphics; + friend class CairoTextRender; + + void AddRef() const { ++mnRefCount; } + long GetRefCount() const { return mnRefCount; } + long Release() const; + sal_uLong GetByteCount() const { return mnBytesUsed; } + + void InitGlyphData( sal_GlyphId, GlyphData& ) const; + void GarbageCollect( long ); + void ReleaseFromGarbageCollect(); + + int ApplyGlyphTransform( int nGlyphFlags, FT_GlyphRec_*, bool ) const; + bool ApplyGSUB( const FontSelectPattern& ); + + ServerFontLayoutEngine* GetLayoutEngine(); + + typedef std::unordered_map GlyphList; + mutable GlyphList maGlyphList; + + const FontSelectPattern maFontSelData; + + // used by GlyphCache for cache LRU algorithm + mutable long mnRefCount; + mutable sal_uLong mnBytesUsed; + + ServerFont* mpPrevGCFont; + ServerFont* mpNextGCFont; + + // 16.16 fixed point values used for a rotated font + long mnCos; + long mnSin; + + int mnWidth; + int mnPrioEmbedded; + int mnPrioAntiAlias; + int mnPrioAutoHint; + FreetypeFontInfo* mpFontInfo; + FT_Int mnLoadFlags; + double mfStretch; + FT_FaceRec_* maFaceFT; + FT_SizeRec_* maSizeFT; + + std::shared_ptr mxFontOptions; + + bool mbFaceOk; + bool mbArtItalic; + bool mbArtBold; + bool mbUseGamma; + + typedef std::unordered_map GlyphSubstitution; + GlyphSubstitution maGlyphSubstitution; + + ServerFontLayoutEngine* mpLayoutEngine; +}; + +// a class for cache entries for physical font instances that are based on serverfonts +class VCL_DLLPUBLIC ServerFontInstance : public LogicalFontInstance +{ +public: + ServerFontInstance( FontSelectPattern& ); + virtual ~ServerFontInstance(); + + void SetServerFont(ServerFont* p); + void HandleFontOptions(); + +private: + ServerFont* mpServerFont; + std::shared_ptr mxFontOptions; + bool mbGotFontOptions; + +}; + +class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout +{ +public: + ServerFontLayout( ServerFont& ); + + virtual bool LayoutText( ImplLayoutArgs& ) override; + virtual void AdjustLayout( ImplLayoutArgs& ) override; + virtual void DrawText( SalGraphics& ) const override; + + void SetNeedFallback( + ImplLayoutArgs& rArgs, + sal_Int32 nIndex, + bool bRightToLeft); + + ServerFont& GetServerFont() const { return mrServerFont; } + + virtual std::shared_ptr + CreateTextLayoutCache(OUString const&) const override; + +private: + ServerFont& mrServerFont; + css::uno::Reference mxBreak; + + ServerFontLayout( const ServerFontLayout& ) = delete; + ServerFontLayout& operator=( const ServerFontLayout& ) = delete; + +}; + +class ServerFontLayoutEngine +{ +public: + virtual ~ServerFontLayoutEngine() {} + + virtual bool Layout(ServerFontLayout&, ImplLayoutArgs&) = 0; +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 97af78fc5800..5e39d0e162c5 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -28,7 +28,7 @@ #include "generic/printergfx.hxx" #include "generic/genpspgraphics.h" #include "generic/geninst.h" -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" #include "PhysicalFontFace.hxx" #include "impfont.hxx" diff --git a/vcl/unx/generic/gdi/gcach_xpeer.hxx b/vcl/unx/generic/gdi/gcach_xpeer.hxx index 5d3b89ffe3f4..d933c8b61490 100644 --- a/vcl/unx/generic/gdi/gcach_xpeer.hxx +++ b/vcl/unx/generic/gdi/gcach_xpeer.hxx @@ -20,7 +20,7 @@ #ifndef INCLUDED_VCL_UNX_GENERIC_GDI_GCACH_XPEER_HXX #define INCLUDED_VCL_UNX_GENERIC_GDI_GCACH_XPEER_HXX -#include "generic/glyphcache.hxx" +#include "unx/glyphcache.hxx" class X11GlyphCache : public GlyphCache { diff --git a/vcl/unx/generic/glyphs/gcach_layout.cxx b/vcl/unx/generic/glyphs/gcach_layout.cxx new file mode 100644 index 000000000000..70ac1901f09d --- /dev/null +++ b/vcl/unx/generic/glyphs/gcach_layout.cxx @@ -0,0 +1,621 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "unx/freetype_glyphcache.hxx" +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include + +#ifndef HB_VERSION_ATLEAST +#define HB_VERSION_ATLEAST(a,b,c) 0 +#endif + +// layout implementation for ServerFont +ServerFontLayout::ServerFontLayout( ServerFont& rFont ) +: mrServerFont( rFont ) +{ +} + +void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const +{ + rSalGraphics.DrawServerFontLayout( *this ); +} + +bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs ) +{ + return mrServerFont.GetLayoutEngine()->Layout(*this, rArgs); +} + +void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs ) +{ + GenericSalLayout::AdjustLayout( rArgs ); + + // apply asian kerning if the glyphs are not already formatted + if( (rArgs.mnFlags & SalLayoutFlags::KerningAsian) + && !(rArgs.mnFlags & SalLayoutFlags::Vertical) ) + if( (rArgs.mpDXArray != nullptr) || (rArgs.mnLayoutWidth != 0) ) + ApplyAsianKerning(rArgs.mrStr); + + // insert kashidas where requested by the formatting array + if( (rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray ) + { + int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); + if( nKashidaIndex != 0 ) + { + const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); + KashidaJustify( nKashidaIndex, rGM.GetCharWidth() ); + // TODO: kashida-GSUB/GPOS + } + } +} + +void ServerFontLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos, + bool bRightToLeft) +{ + if (nCharPos < 0) + return; + + using namespace ::com::sun::star; + + if (!mxBreak.is()) + mxBreak = vcl::unohelper::CreateBreakIterator(); + + lang::Locale aLocale(rArgs.maLanguageTag.getLocale()); + + //if position nCharPos is missing in the font, grab the entire grapheme and + //mark all glyphs as missing so the whole thing is rendered with the same + //font + sal_Int32 nDone; + sal_Int32 nGraphemeStartPos = + mxBreak->previousCharacters(rArgs.mrStr, nCharPos+1, aLocale, + i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + sal_Int32 nGraphemeEndPos = + mxBreak->nextCharacters(rArgs.mrStr, nCharPos, aLocale, + i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + + rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft); +} + +std::ostream &operator <<(std::ostream& s, ServerFont* pFont) +{ +#ifndef SAL_LOG_INFO + (void) pFont; +#else + FT_Face aFace = pFont->GetFtFace(); + const char* pName = FT_Get_Postscript_Name(aFace); + if (pName) + s << pName; + else + s << pFont->GetFontFileName(); +#endif + return s; +} + +static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) +{ + char pTagName[5]; + pTagName[0] = (char)(nTableTag >> 24); + pTagName[1] = (char)(nTableTag >> 16); + pTagName[2] = (char)(nTableTag >> 8); + pTagName[3] = (char)(nTableTag); + pTagName[4] = 0; + + ServerFont* pFont = static_cast(pUserData); + + SAL_INFO("vcl.harfbuzz", "getFontTable(" << pFont << ", " << pTagName << ")"); + + sal_uLong nLength; + const unsigned char* pBuffer = pFont->GetTable(pTagName, &nLength); + + hb_blob_t* pBlob = nullptr; + if (pBuffer != nullptr) + pBlob = hb_blob_create(reinterpret_cast(pBuffer), nLength, HB_MEMORY_MODE_READONLY, const_cast(pBuffer), nullptr); + + return pBlob; +} + +static hb_bool_t getFontGlyph(hb_font_t* /*font*/, void* pFontData, + hb_codepoint_t ch, hb_codepoint_t vs, + hb_codepoint_t* nGlyphIndex, + void* /*pUserData*/) +{ + ServerFont* pFont = static_cast(pFontData); + *nGlyphIndex = pFont->GetRawGlyphIndex(ch, vs); + + // tdf#89231 if the font is missing non-breaking space, then use a normal space + if (*nGlyphIndex == 0 && ch == 0x202F && !vs) + *nGlyphIndex = pFont->GetRawGlyphIndex(' '); + + return *nGlyphIndex != 0; +} + +static hb_position_t getGlyphAdvanceH(hb_font_t* /*font*/, void* pFontData, + hb_codepoint_t nGlyphIndex, + void* /*pUserData*/) +{ + ServerFont* pFont = static_cast(pFontData); + const GlyphMetric& rGM = pFont->GetGlyphMetric(nGlyphIndex); + return rGM.GetCharWidth() << 6; +} + +#if !HB_VERSION_ATLEAST(1, 1, 2) +static hb_position_t getGlyphAdvanceV(hb_font_t* /*font*/, void* /*pFontData*/, + hb_codepoint_t /*nGlyphIndex*/, + void* /*pUserData*/) +{ + // XXX: vertical metrics + return 0; +} + +static hb_bool_t getGlyphOriginH(hb_font_t* /*font*/, void* /*pFontData*/, + hb_codepoint_t /*nGlyphIndex*/, + hb_position_t* /*x*/, hb_position_t* /*y*/, + void* /*pUserData*/) +{ + // the horizontal origin is always (0, 0) + return true; +} + +static hb_bool_t getGlyphOriginV(hb_font_t* /*font*/, void* /*pFontData*/, + hb_codepoint_t /*nGlyphIndex*/, + hb_position_t* /*x*/, hb_position_t* /*y*/, + void* /*pUserData*/) +{ + // XXX: vertical origin + return true; +} +#endif + +static hb_position_t getGlyphKerningH(hb_font_t* /*font*/, void* pFontData, + hb_codepoint_t nGlyphIndex1, hb_codepoint_t nGlyphIndex2, + void* /*pUserData*/) +{ + // This callback is for old style 'kern' table, GPOS kerning is handled by HarfBuzz directly + + ServerFont* pFont = static_cast(pFontData); + FT_Face aFace = pFont->GetFtFace(); + + SAL_INFO("vcl.harfbuzz", "getGlyphKerningH(" << pFont << ", " << nGlyphIndex1 << ", " << nGlyphIndex2 << ")"); + + FT_Error error; + FT_Vector kerning; + hb_position_t ret; + + error = FT_Get_Kerning(aFace, nGlyphIndex1, nGlyphIndex2, FT_KERNING_DEFAULT, &kerning); + if (error) + ret = 0; + else + ret = kerning.x; + + return ret; +} + +#if !HB_VERSION_ATLEAST(1, 1, 2) +static hb_position_t getGlyphKerningV(hb_font_t* /*font*/, void* /*pFontData*/, + hb_codepoint_t /*nGlyphIndex1*/, hb_codepoint_t /*nGlyphIndex2*/, + void* /*pUserData*/) +{ + // XXX vertical kerning + return 0; +} +#endif + +static hb_bool_t getGlyphExtents(hb_font_t* /*font*/, void* pFontData, + hb_codepoint_t nGlyphIndex, + hb_glyph_extents_t* pExtents, + void* /*pUserData*/) +{ + ServerFont* pFont = static_cast(pFontData); + FT_Face aFace = pFont->GetFtFace(); + + SAL_INFO("vcl.harfbuzz", "getGlyphExtents(" << pFont << ", " << nGlyphIndex << ")"); + + FT_Error error; + error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT); + if (!error) + { + pExtents->x_bearing = aFace->glyph->metrics.horiBearingX; + pExtents->y_bearing = aFace->glyph->metrics.horiBearingY; + pExtents->width = aFace->glyph->metrics.width; + pExtents->height = -aFace->glyph->metrics.height; + } + + return !error; +} + +static hb_bool_t getGlyphContourPoint(hb_font_t* /*font*/, void* pFontData, + hb_codepoint_t nGlyphIndex, unsigned int nPointIndex, + hb_position_t *x, hb_position_t *y, + void* /*pUserData*/) +{ + bool ret = false; + ServerFont* pFont = static_cast(pFontData); + FT_Face aFace = pFont->GetFtFace(); + + SAL_INFO("vcl.harfbuzz", "getGlyphContourPoint(" << pFont << ", " << nGlyphIndex << ", " << nPointIndex << ")"); + + FT_Error error; + error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT); + if (!error) + { + if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + if (nPointIndex < (unsigned int) aFace->glyph->outline.n_points) + { + *x = aFace->glyph->outline.points[nPointIndex].x; + *y = aFace->glyph->outline.points[nPointIndex].y; + ret = true; + } + } + } + + return ret; +} + +static hb_font_funcs_t* getFontFuncs() +{ + static hb_font_funcs_t* funcs = hb_font_funcs_create(); + + hb_font_funcs_set_glyph_func (funcs, getFontGlyph, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advance_func (funcs, getGlyphAdvanceH, nullptr, nullptr); + hb_font_funcs_set_glyph_h_kerning_func (funcs, getGlyphKerningH, nullptr, nullptr); + hb_font_funcs_set_glyph_extents_func (funcs, getGlyphExtents, nullptr, nullptr); + hb_font_funcs_set_glyph_contour_point_func (funcs, getGlyphContourPoint, nullptr, nullptr); +#if !HB_VERSION_ATLEAST(1, 1, 2) + hb_font_funcs_set_glyph_v_advance_func (funcs, getGlyphAdvanceV, nullptr, nullptr); + hb_font_funcs_set_glyph_h_origin_func (funcs, getGlyphOriginH, nullptr, nullptr); + hb_font_funcs_set_glyph_v_origin_func (funcs, getGlyphOriginV, nullptr, nullptr); + hb_font_funcs_set_glyph_v_kerning_func (funcs, getGlyphKerningV, nullptr, nullptr); +#endif + + return funcs; +} + +#if !HB_VERSION_ATLEAST(1, 1, 0) +// Disabled Unicode compatibility decomposition, see fdo#66715 +static unsigned int unicodeDecomposeCompatibility(hb_unicode_funcs_t* /*ufuncs*/, + hb_codepoint_t /*u*/, + hb_codepoint_t* /*decomposed*/, + void* /*user_data*/) +{ + return 0; +} + +static hb_unicode_funcs_t* getUnicodeFuncs() +{ + static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs()); + hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, nullptr, nullptr); + return ufuncs; +} +#endif + +class HbLayoutEngine : public ServerFontLayoutEngine +{ +private: + hb_script_t maHbScript; + hb_face_t* mpHbFace; + int mnUnitsPerEM; + +public: + explicit HbLayoutEngine(ServerFont&); + virtual ~HbLayoutEngine(); + + virtual bool Layout(ServerFontLayout&, ImplLayoutArgs&) override; +}; + +HbLayoutEngine::HbLayoutEngine(ServerFont& rServerFont) +: maHbScript(HB_SCRIPT_INVALID), + mpHbFace(nullptr), + mnUnitsPerEM(0) +{ + FT_Face aFtFace = rServerFont.GetFtFace(); + mnUnitsPerEM = rServerFont.GetEmUnits(); + + mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); + hb_face_set_index(mpHbFace, aFtFace->face_index); + hb_face_set_upem(mpHbFace, mnUnitsPerEM); +} + +HbLayoutEngine::~HbLayoutEngine() +{ + hb_face_destroy(mpHbFace); +} + +struct HbScriptRun +{ + int32_t mnMin; + int32_t mnEnd; + hb_script_t maScript; + + HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript) + : mnMin(nMin), mnEnd(nEnd), + maScript(hb_icu_script_to_script(aScript)) + {} +}; + +typedef std::vector HbScriptRuns; + +namespace vcl { + struct Run + { + int32_t nStart; + int32_t nEnd; + UScriptCode nCode; + Run(int32_t nStart_, int32_t nEnd_, UScriptCode nCode_) + : nStart(nStart_), nEnd(nEnd_), nCode(nCode_) + {} + }; + + class TextLayoutCache + { + public: + std::vector runs; + TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd) + { + vcl::ScriptRun aScriptRun( + reinterpret_cast(pStr), + nEnd); + while (aScriptRun.next()) + { + runs.push_back(Run(aScriptRun.getScriptStart(), + aScriptRun.getScriptEnd(), aScriptRun.getScriptCode())); + } + } + }; +} + +std::shared_ptr ServerFontLayout::CreateTextLayoutCache( + OUString const& rString) const +{ + return std::make_shared(rString.getStr(), rString.getLength()); +} + +bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs) +{ + ServerFont& rFont = rLayout.GetServerFont(); + FT_Face aFtFace = rFont.GetFtFace(); + + SAL_INFO("vcl.harfbuzz", "layout(" << this << ",rArgs=" << rArgs << ")"); + + static hb_font_funcs_t* pHbFontFuncs = getFontFuncs(); + + hb_font_t *pHbFont = hb_font_create(mpHbFace); + hb_font_set_funcs(pHbFont, pHbFontFuncs, &rFont, nullptr); + hb_font_set_scale(pHbFont, + ((uint64_t) aFtFace->size->metrics.x_scale * (uint64_t) mnUnitsPerEM) >> 16, + ((uint64_t) aFtFace->size->metrics.y_scale * (uint64_t) mnUnitsPerEM) >> 16); + hb_font_set_ppem(pHbFont, aFtFace->size->metrics.x_ppem, aFtFace->size->metrics.y_ppem); + + // allocate temporary arrays, note: round to even + int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1; + int32_t nVirtAdv = int32_t(aFtFace->size->metrics.height*rFont.GetStretch())>>6; + + rLayout.Reserve(nGlyphCapacity); + + const int nLength = rArgs.mrStr.getLength(); + const sal_Unicode *pStr = rArgs.mrStr.getStr(); + + std::unique_ptr pNewScriptRun; + vcl::TextLayoutCache const* pTextLayout; + if (rArgs.m_pTextLayoutCache) + { + pTextLayout = rArgs.m_pTextLayoutCache; // use cache! + } + else + { + pNewScriptRun.reset(new vcl::TextLayoutCache(pStr, rArgs.mnEndCharPos)); + pTextLayout = pNewScriptRun.get(); + } + + Point aCurrPos(0, 0); + while (true) + { + int nBidiMinRunPos, nBidiEndRunPos; + bool bRightToLeft; + if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft)) + break; + + // Find script subruns. + int nCurrentPos = nBidiMinRunPos; + HbScriptRuns aScriptSubRuns; + size_t k = 0; + for (; k < pTextLayout->runs.size(); ++k) + { + vcl::Run const& rRun(pTextLayout->runs[k]); + if (rRun.nStart <= nCurrentPos && nCurrentPos < rRun.nEnd) + { + break; + } + } + + while (nCurrentPos < nBidiEndRunPos && k < pTextLayout->runs.size()) + { + int32_t nMinRunPos = nCurrentPos; + int32_t nEndRunPos = std::min(pTextLayout->runs[k].nEnd, nBidiEndRunPos); + HbScriptRun aRun(nMinRunPos, nEndRunPos, pTextLayout->runs[k].nCode); + aScriptSubRuns.push_back(aRun); + + nCurrentPos = nEndRunPos; + ++k; + } + + // RTL subruns should be reversed to ensure that final glyph order is + // correct. + if (bRightToLeft) + std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end()); + + for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it) + { + int nMinRunPos = it->mnMin; + int nEndRunPos = it->mnEnd; + int nRunLen = nEndRunPos - nMinRunPos; + maHbScript = it->maScript; + // hb_language_from_string() accept ISO639-3 language tag except for Chinese. + LanguageTag &rTag = rArgs.maLanguageTag; + OString sLanguage = OUStringToOString( MsLangId::isChinese(rTag.getLanguageType()) ? rTag.getBcp47():rTag.getLanguage() , RTL_TEXTENCODING_UTF8 ); + + int nHbFlags = HB_BUFFER_FLAGS_DEFAULT; + if (nMinRunPos == 0) + nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */ + if (nEndRunPos == nLength) + nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */ + + hb_buffer_t *pHbBuffer = hb_buffer_create(); +#if !HB_VERSION_ATLEAST(1, 1, 0) + static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); + hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); +#endif + hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); + hb_buffer_set_script(pHbBuffer, maHbScript); + hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1)); + hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags); + hb_buffer_add_utf16( + pHbBuffer, reinterpret_cast(pStr), nLength, + nMinRunPos, nRunLen); + hb_shape(pHbFont, pHbBuffer, nullptr, 0); + + int nRunGlyphCount = hb_buffer_get_length(pHbBuffer); + hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr); + hb_glyph_position_t *pHbPositions = hb_buffer_get_glyph_positions(pHbBuffer, nullptr); + + for (int i = 0; i < nRunGlyphCount; ++i) { + int32_t nGlyphIndex = pHbGlyphInfos[i].codepoint; + int32_t nCharPos = pHbGlyphInfos[i].cluster; + + // if needed request glyph fallback by updating LayoutArgs + if (!nGlyphIndex) + { + rLayout.SetNeedFallback(rArgs, nCharPos, bRightToLeft); + if (SalLayoutFlags::ForFallback & rArgs.mnFlags) + continue; + } + + // apply vertical flags and glyph substitution + // XXX: Use HB_DIRECTION_TTB above and apply whatever flags magic + // FixupGlyphIndex() is doing, minus the GSUB part. + if (nCharPos >= 0) + { + sal_UCS4 aChar = rArgs.mrStr[nCharPos]; + nGlyphIndex = rFont.FixupGlyphIndex(nGlyphIndex, aChar); + } + + bool bInCluster = false; + if (i > 0 && pHbGlyphInfos[i].cluster == pHbGlyphInfos[i - 1].cluster) + bInCluster = true; + + long nGlyphFlags = 0; + if (bRightToLeft) + nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; + + if (bInCluster) + nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; + + // The whole IS_DIACRITIC concept is a stupid hack that was + // introduced ages ago to work around the utter brokenness of the + // way justification adjustments are applied (the DXArray fiasco). + // Since it is such a stupid hack, there is no sane way to directly + // map to concepts of the "outside" world, so we do some rather + // ugly hacks: + // * If the font has a GDEF table, we check for glyphs with mark + // glyph class which is sensible, except that some fonts + // (fdo#70968) assign mark class to spacing marks (which is wrong + // but usually harmless), so we try to sniff what HarfBuzz thinks + // about this glyph by checking if it gives it a zero advance + // width. + // * If the font has no GDEF table, we just check if the glyph has + // zero advance width, but this is stupid and can be wrong. A + // better way would to check the character's Unicode combining + // class, but unfortunately glyph gives combining marks the + // cluster value of its base character, so nCharPos will be + // pointing to the wrong character (but HarfBuzz might change + // this in the future). + bool bDiacritic = false; + if (hb_ot_layout_has_glyph_classes(mpHbFace)) + { + // the font has GDEF table + bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; + if (bMark && pHbPositions[i].x_advance == 0) + bDiacritic = true; + } + else + { + // the font lacks GDEF table + if (pHbPositions[i].x_advance == 0) + bDiacritic = true; + } + + if (bDiacritic) + nGlyphFlags |= GlyphItem::IS_DIACRITIC; + + int32_t nXOffset = pHbPositions[i].x_offset >> 6; + int32_t nYOffset = pHbPositions[i].y_offset >> 6; + int32_t nXAdvance = pHbPositions[i].x_advance >> 6; + int32_t nYAdvance = pHbPositions[i].y_advance >> 6; + if ( nGlyphIndex & GF_ROTMASK ) + nXAdvance = nVirtAdv; + + Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset)); + const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset, nYOffset); + rLayout.AppendGlyph(aGI); + + aCurrPos.X() += nXAdvance; + aCurrPos.Y() += nYAdvance; + } + + hb_buffer_destroy(pHbBuffer); + } + } + + hb_font_destroy(pHbFont); + + // sort glyphs in visual order + // and then in logical order (e.g. diacritics after cluster start) + // XXX: why? + rLayout.SortGlyphItems(); + + // determine need for kashida justification + if((rArgs.mpDXArray || rArgs.mnLayoutWidth) + && ((maHbScript == HB_SCRIPT_ARABIC) || (maHbScript == HB_SCRIPT_SYRIAC))) + rArgs.mnFlags |= SalLayoutFlags::KashidaJustification; + + return true; +} + +ServerFontLayoutEngine* ServerFont::GetLayoutEngine() +{ + // find best layout engine for font, platform, script and language + if (!mpLayoutEngine) { + mpLayoutEngine = new HbLayoutEngine(*this); + } + return mpLayoutEngine; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx b/vcl/unx/generic/glyphs/glyphcache.cxx new file mode 100644 index 000000000000..33f06df2faab --- /dev/null +++ b/vcl/unx/generic/glyphs/glyphcache.cxx @@ -0,0 +1,379 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "unx/freetype_glyphcache.hxx" + +#include +#include +#include +#include + +#include +#if ENABLE_GRAPHITE +#include +#endif + +#include +#include +#include + +static GlyphCache* pInstance = nullptr; + +GlyphCache::GlyphCache() +: mnMaxSize( 1500000 ), + mnBytesUsed(sizeof(GlyphCache)), + mnLruIndex(0), + mnGlyphCount(0), + mpCurrentGCFont(nullptr), + mpFtManager(nullptr) +{ + pInstance = this; + mpFtManager = new FreetypeManager; +} + +GlyphCache::~GlyphCache() +{ + InvalidateAllGlyphs(); + delete mpFtManager; +} + +void GlyphCache::InvalidateAllGlyphs() +{ + for( FontList::iterator it = maFontList.begin(), end = maFontList.end(); it != end; ++it ) + { + ServerFont* pServerFont = it->second; + // free all pServerFont related data + pServerFont->GarbageCollect( mnLruIndex+0x10000000 ); + delete pServerFont; + } + + maFontList.clear(); + mpCurrentGCFont = nullptr; +} + +inline +size_t GlyphCache::IFSD_Hash::operator()( const FontSelectPattern& rFontSelData ) const +{ + // TODO: is it worth to improve this hash function? + sal_IntPtr nFontId = reinterpret_cast( rFontSelData.mpFontData ); +#if ENABLE_GRAPHITE + if (rFontSelData.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1) + { + OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 ); + nFontId ^= aFeatName.hashCode(); + } +#endif + size_t nHash = nFontId << 8; + nHash += rFontSelData.mnHeight; + nHash += rFontSelData.mnOrientation; + nHash += size_t(rFontSelData.mbVertical); + nHash += rFontSelData.GetSlantType(); + nHash += rFontSelData.GetWeight(); +#if ENABLE_GRAPHITE + nHash += rFontSelData.meLanguage; +#endif + return nHash; +} + +bool GlyphCache::IFSD_Equal::operator()( const FontSelectPattern& rA, const FontSelectPattern& rB) const +{ + // check font ids + sal_IntPtr nFontIdA = reinterpret_cast( rA.mpFontData ); + sal_IntPtr nFontIdB = reinterpret_cast( rB.mpFontData ); + if( nFontIdA != nFontIdB ) + return false; + + // compare with the requested metrics + if( (rA.mnHeight != rB.mnHeight) + || (rA.mnOrientation != rB.mnOrientation) + || (rA.mbVertical != rB.mbVertical) + || (rA.mbNonAntialiased != rB.mbNonAntialiased) ) + return false; + + if( (rA.GetSlantType() != rB.GetSlantType()) + || (rA.GetWeight() != rB.GetWeight()) ) + return false; + + // NOTE: ignoring meFamily deliberately + + // compare with the requested width, allow default width + int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight; + int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight; + if( nAWidth != nBWidth ) + return false; + +#if ENABLE_GRAPHITE + if (rA.meLanguage != rB.meLanguage) + return false; + // check for features + if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1 || + rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1) && rA.maTargetName != rB.maTargetName) + return false; +#endif + + if (rA.mbEmbolden != rB.mbEmbolden) + return false; + + if (rA.maItalicMatrix != rB.maItalicMatrix) + return false; + + return true; +} + +GlyphCache& GlyphCache::GetInstance() +{ + return *pInstance; +} + +void GlyphCache::AddFontFile( const OString& rNormalizedName, int nFaceNum, + sal_IntPtr nFontId, const FontAttributes& rDFA) +{ + if( mpFtManager ) + mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA); +} + +void GlyphCache::AnnounceFonts( PhysicalFontCollection* pFontCollection ) const +{ + if( mpFtManager ) + mpFtManager->AnnounceFonts( pFontCollection ); +} + +void GlyphCache::ClearFontCache() +{ + InvalidateAllGlyphs(); + if (mpFtManager) + mpFtManager->ClearFontList(); +} + +ServerFont* GlyphCache::CacheFont( const FontSelectPattern& rFontSelData ) +{ + // a serverfont request has pFontData + if( rFontSelData.mpFontData == nullptr ) + return nullptr; + // a serverfont request has a fontid > 0 + sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId(); + if( nFontId <= 0 ) + return nullptr; + + // the FontList's key mpFontData member is reinterpreted as font id + FontSelectPattern aFontSelData = rFontSelData; + aFontSelData.mpFontData = reinterpret_cast( nFontId ); + FontList::iterator it = maFontList.find( aFontSelData ); + if( it != maFontList.end() ) + { + ServerFont* pFound = it->second; + if( pFound ) + pFound->AddRef(); + return pFound; + } + + // font not cached yet => create new font item + ServerFont* pNew = nullptr; + if( mpFtManager ) + pNew = mpFtManager->CreateFont( aFontSelData ); + + if( pNew ) + { + maFontList[ aFontSelData ] = pNew; + mnBytesUsed += pNew->GetByteCount(); + + // enable garbage collection for new font + if( !mpCurrentGCFont ) + { + mpCurrentGCFont = pNew; + pNew->mpNextGCFont = pNew; + pNew->mpPrevGCFont = pNew; + } + else + { + pNew->mpNextGCFont = mpCurrentGCFont; + pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont; + pNew->mpPrevGCFont->mpNextGCFont = pNew; + mpCurrentGCFont->mpPrevGCFont = pNew; + } + } + + return pNew; +} + +void GlyphCache::UncacheFont( ServerFont& rServerFont ) +{ + if( (rServerFont.Release() <= 0) && (mnMaxSize <= mnBytesUsed) ) + { + mpCurrentGCFont = &rServerFont; + GarbageCollect(); + } +} + +void GlyphCache::GarbageCollect() +{ + // when current GC font has been destroyed get another one + if( !mpCurrentGCFont ) + { + FontList::iterator it = maFontList.begin(); + if( it != maFontList.end() ) + mpCurrentGCFont = it->second; + } + + // unless there is no other font to collect + if( !mpCurrentGCFont ) + return; + + // prepare advance to next font for garbage collection + ServerFont* const pServerFont = mpCurrentGCFont; + mpCurrentGCFont = pServerFont->mpNextGCFont; + + if( (pServerFont == mpCurrentGCFont) // no other fonts + || (pServerFont->GetRefCount() > 0) ) // font still used + { + // try to garbage collect at least a few bytes + pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 ); + } + else // current GC font is unreferenced + { + DBG_ASSERT( (pServerFont->GetRefCount() == 0), + "GlyphCache::GC detected RefCount underflow" ); + + // free all pServerFont related data + pServerFont->GarbageCollect( mnLruIndex+0x10000000 ); + if( pServerFont == mpCurrentGCFont ) + mpCurrentGCFont = nullptr; + const FontSelectPattern& rIFSD = pServerFont->GetFontSelData(); + maFontList.erase( rIFSD ); + mnBytesUsed -= pServerFont->GetByteCount(); + + // remove font from list of garbage collected fonts + if( pServerFont->mpPrevGCFont ) + pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont; + if( pServerFont->mpNextGCFont ) + pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont; + if( pServerFont == mpCurrentGCFont ) + mpCurrentGCFont = nullptr; + + delete pServerFont; + } +} + +inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData ) +{ + rGlyphData.SetLruValue( mnLruIndex++ ); +} + +inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData ) +{ + ++mnGlyphCount; + mnBytesUsed += sizeof( rGlyphData ); + UsingGlyph( rServerFont, rGlyphData ); + GrowNotify(); +} + +void GlyphCache::GrowNotify() +{ + if( mnBytesUsed > mnMaxSize ) + GarbageCollect(); +} + +inline void GlyphCache::RemovingGlyph() +{ + mnBytesUsed -= sizeof( GlyphData ); + --mnGlyphCount; +} + +void ServerFont::ReleaseFromGarbageCollect() +{ + // remove from GC list + ServerFont* pPrev = mpPrevGCFont; + ServerFont* pNext = mpNextGCFont; + if( pPrev ) pPrev->mpNextGCFont = pNext; + if( pNext ) pNext->mpPrevGCFont = pPrev; + mpPrevGCFont = nullptr; + mpNextGCFont = nullptr; +} + +long ServerFont::Release() const +{ + DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" ); + return --mnRefCount; +} + +GlyphData& ServerFont::GetGlyphData( sal_GlyphId aGlyphId ) +{ + // usually the GlyphData is cached + GlyphList::iterator it = maGlyphList.find( aGlyphId ); + if( it != maGlyphList.end() ) { + GlyphData& rGlyphData = it->second; + GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData ); + return rGlyphData; + } + + // sometimes not => we need to create and initialize it ourselves + GlyphData& rGlyphData = maGlyphList[ aGlyphId ]; + mnBytesUsed += sizeof( GlyphData ); + InitGlyphData( aGlyphId, rGlyphData ); + GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData ); + return rGlyphData; +} + +void ServerFont::GarbageCollect( long nMinLruIndex ) +{ + GlyphList::iterator it = maGlyphList.begin(); + while( it != maGlyphList.end() ) + { + GlyphData& rGD = it->second; + if( (nMinLruIndex - rGD.GetLruValue()) > 0 ) + { + OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) ); + mnBytesUsed -= sizeof( GlyphData ); + GlyphCache::GetInstance().RemovingGlyph(); + it = maGlyphList.erase( it ); + } + else + ++it; + } +} + +ServerFontInstance::ServerFontInstance( FontSelectPattern& rFSD ) +: LogicalFontInstance( rFSD ) +, mpServerFont( nullptr ) +, mbGotFontOptions( false ) +{} + +void ServerFontInstance::SetServerFont(ServerFont* p) +{ + if (p == mpServerFont) + return; + if (mpServerFont) + mpServerFont->Release(); + mpServerFont = p; + if (mpServerFont) + mpServerFont->AddRef(); +} + +ServerFontInstance::~ServerFontInstance() +{ + // TODO: remove the ServerFont here instead of in the GlyphCache + if (mpServerFont) + mpServerFont->Release(); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/glyphs/graphite_serverfont.cxx b/vcl/unx/generic/glyphs/graphite_serverfont.cxx new file mode 100644 index 000000000000..d2126b05f377 --- /dev/null +++ b/vcl/unx/generic/glyphs/graphite_serverfont.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// Header files + +// Platform +#include +#include +// Module +#include "unx/freetype_glyphcache.hxx" +#include "unx/glyphcache.hxx" +#include +#include + +float freetypeServerFontAdvance(const void* appFontHandle, gr_uint16 glyphId) +{ + ServerFont * pServerFont = + const_cast + (static_cast(appFontHandle)); + if (pServerFont) + { + return static_cast(pServerFont->GetGlyphMetric(glyphId).GetCharWidth()); + } + return .0f; +} + +// An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used. + +GraphiteServerFontLayout::GraphiteServerFontLayout(ServerFont& rServerFont) throw() + : ServerFontLayout(rServerFont), + maImpl(rServerFont.GetGraphiteFace()->face(), rServerFont) + , mpFeatures(nullptr) +{ + gr_font * pFont = rServerFont.GetGraphiteFace()->font(rServerFont.GetFontSelData().mnHeight, rServerFont.NeedsArtificialBold(), rServerFont.NeedsArtificialItalic()); + if (!pFont) + { + pFont = gr_make_font_with_advance_fn( + // need to use mnHeight here, mfExactHeight can give wrong values + static_cast(rServerFont.GetFontSelData().mnHeight), + &rServerFont, + freetypeServerFontAdvance, + rServerFont.GetGraphiteFace()->face()); + rServerFont.GetGraphiteFace()->addFont(rServerFont.GetFontSelData().mnHeight, pFont, rServerFont.NeedsArtificialBold(), rServerFont.NeedsArtificialItalic()); + } + maImpl.SetFont(pFont); + OString aLang(""); + if (rServerFont.GetFontSelData().meLanguage != LANGUAGE_DONTKNOW) + { + aLang = OUStringToOString( LanguageTag( rServerFont.GetFontSelData().meLanguage ).getBcp47(), + RTL_TEXTENCODING_UTF8 ); + } + OString name = OUStringToOString( + rServerFont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 ); +#ifdef DEBUG + printf("GraphiteServerFontLayout %lx %s size %d %f\n", (long unsigned int)this, name.getStr(), + rServerFont.GetMetricsFT().x_ppem, + rServerFont.GetFontSelData().mfExactHeight); +#endif + sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1; + if (nFeat > 0) + { + OString aFeat = name.copy(nFeat, name.getLength() - nFeat); + mpFeatures = new grutils::GrFeatureParser( + rServerFont.GetGraphiteFace()->face(), aFeat, aLang); +#ifdef DEBUG + if (mpFeatures) + printf("GraphiteServerFontLayout %s/%s/%s %x language %d features %d errors\n", + OUStringToOString( rServerFont.GetFontSelData().GetFamilyName(), + RTL_TEXTENCODING_UTF8 ).getStr(), + OUStringToOString( rServerFont.GetFontSelData().maTargetName, + RTL_TEXTENCODING_UTF8 ).getStr(), + OUStringToOString( rServerFont.GetFontSelData().maSearchName, + RTL_TEXTENCODING_UTF8 ).getStr(), + rServerFont.GetFontSelData().meLanguage, + (int)mpFeatures->numFeatures(), mpFeatures->parseErrors()); +#endif + } + else + { + mpFeatures = new grutils::GrFeatureParser( + rServerFont.GetGraphiteFace()->face(), aLang); + } + maImpl.SetFeatures(mpFeatures); +} + +GraphiteServerFontLayout::~GraphiteServerFontLayout() throw() +{ + delete mpFeatures; + mpFeatures = nullptr; +} + +bool GraphiteServerFontLayout::IsGraphiteEnabledFont(ServerFont& rServerFont) +{ + if (rServerFont.GetGraphiteFace()) + { +#ifdef DEBUG + printf("IsGraphiteEnabledFont\n"); +#endif + return true; + } + return false; +} + +sal_GlyphId GraphiteLayoutImpl::getKashidaGlyph(int & width) +{ + int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); + if( nKashidaIndex != 0 ) + { + const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); + width = rGM.GetCharWidth(); + } + else + { + width = 0; + } + return nKashidaIndex; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/glyphs/scrptrun.cxx b/vcl/unx/generic/glyphs/scrptrun.cxx new file mode 100644 index 000000000000..d6557d79a894 --- /dev/null +++ b/vcl/unx/generic/glyphs/scrptrun.cxx @@ -0,0 +1,234 @@ +/* + ******************************************************************************* + * + * Copyright (c) 1995-2013 International Business Machines Corporation and others + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * provided that the above copyright notice(s) and this permission notice appear + * in all copies of the Software and that both the above copyright notice(s) and + * this permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN + * NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE + * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not be + * used in advertising or otherwise to promote the sale, use or other dealings in + * this Software without prior written authorization of the copyright holder. + * + ******************************************************************************* + * file name: scrptrun.cpp + * + * created on: 10/17/2001 + * created by: Eric R. Mader + */ +/** + * This file is largely copied from the ICU project, + * under folder source/extra/scrptrun/scrptrun.cpp + */ +#include "unicode/utypes.h" +#include "unicode/uscript.h" + +#include "scrptrun.h" +#include + +namespace { + +struct PairIndices +{ + int8_t ma00[0xff]; + int8_t ma20[0x7f]; + int8_t ma30[0x7f]; + + PairIndices() + { + std::fill_n(ma00, 0xff, -1); + std::fill_n(ma20, 0x7f, -1); + std::fill_n(ma30, 0x7f, -1); + + // characters in the range 0x0000 - 0x007e (inclusive) + // ascii paired punctuation + ma00[0x28] = 0; + ma00[0x29] = 1; + ma00[0x3c] = 2; + ma00[0x3e] = 3; + ma00[0x5b] = 4; + ma00[0x5d] = 5; + ma00[0x7b] = 6; + ma00[0x7d] = 7; + // guillemets + ma00[0xab] = 8; + ma00[0xbb] = 9; + + // characters in the range 0x2000 - 0x207e (inclusive) + // general punctuation + ma20[0x18] = 10; + ma20[0x19] = 11; + ma20[0x1c] = 12; + ma20[0x1d] = 13; + ma20[0x39] = 14; + ma20[0x3a] = 15; + + // characters in the range 0x3000 - 0x307e (inclusive) + // chinese paired punctuation + ma30[0x08] = 16; + ma30[0x09] = 17; + ma30[0x0a] = 18; + ma30[0x0b] = 19; + ma30[0x0c] = 20; + ma30[0x0d] = 21; + ma30[0x0e] = 22; + ma30[0x0f] = 23; + ma30[0x10] = 24; + ma30[0x11] = 25; + ma30[0x14] = 26; + ma30[0x15] = 27; + ma30[0x16] = 28; + ma30[0x17] = 29; + ma30[0x18] = 30; + ma30[0x19] = 31; + ma30[0x1a] = 32; + ma30[0x1b] = 33; + } + + inline int32_t getPairIndex(UChar32 ch) const + { + if (ch < 0xff) + return ma00[ch]; + if (ch >= 0x2000 && ch < 0x207f) + return ma20[ch - 0x2000]; + if (ch >= 0x3000 && ch < 0x307f) + return ma30[ch - 0x3000]; + return -1; + } + +}; + +} + +static const PairIndices gPairIndices; + + +namespace vcl { + +const char ScriptRun::fgClassID=0; + +static inline UBool sameScript(int32_t scriptOne, int32_t scriptTwo) +{ + return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo; +} + +UBool ScriptRun::next() +{ + int32_t startSP = parenSP; // used to find the first new open character + UErrorCode error = U_ZERO_ERROR; + + // if we've fallen off the end of the text, we're done + if (scriptEnd >= charLimit) { + return false; + } + + scriptCode = USCRIPT_COMMON; + + for (scriptStart = scriptEnd; scriptEnd < charLimit; scriptEnd += 1) { + UChar high = charArray[scriptEnd]; + UChar32 ch = high; + + // if the character is a high surrogate and it's not the last one + // in the text, see if it's followed by a low surrogate + if (high >= 0xD800 && high <= 0xDBFF && scriptEnd < charLimit - 1) + { + UChar low = charArray[scriptEnd + 1]; + + // if it is followed by a low surrogate, + // consume it and form the full character + if (low >= 0xDC00 && low <= 0xDFFF) { + ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000; + scriptEnd += 1; + } + } + + UScriptCode sc = uscript_getScript(ch, &error); + int32_t pairIndex = gPairIndices.getPairIndex(ch); + + // Paired character handling: + + // if it's an open character, push it onto the stack. + // if it's a close character, find the matching open on the + // stack, and use that script code. Any non-matching open + // characters above it on the stack will be poped. + if (pairIndex >= 0) { + if ((pairIndex & 1) == 0) { + ++parenSP; + int32_t nVecSize = parenStack.size(); + if (parenSP == nVecSize) + parenStack.resize(nVecSize + 128); + parenStack[parenSP].pairIndex = pairIndex; + parenStack[parenSP].scriptCode = scriptCode; + } else if (parenSP >= 0) { + int32_t pi = pairIndex & ~1; + + while (parenSP >= 0 && parenStack[parenSP].pairIndex != pi) { + parenSP -= 1; + } + + if (parenSP < startSP) { + startSP = parenSP; + } + + if (parenSP >= 0) { + sc = parenStack[parenSP].scriptCode; + } + } + } + + if (sameScript(scriptCode, sc)) { + if (scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) { + scriptCode = sc; + + // now that we have a final script code, fix any open + // characters we pushed before we knew the script code. + while (startSP < parenSP) { + parenStack[++startSP].scriptCode = scriptCode; + } + } + + // if this character is a close paired character, + // pop it from the stack + if (pairIndex >= 0 && (pairIndex & 1) != 0 && parenSP >= 0) { + parenSP -= 1; + /* decrement startSP only if it is >= 0, + decrementing it unnecessarily will lead to memory corruption + while processing the above while block. + e.g. startSP = -4 , parenSP = -1 + */ + if (startSP >= 0) { + startSP -= 1; + } + } + } else { + // if the run broke on a surrogate pair, + // end it before the high surrogate + if (ch >= 0x10000) { + scriptEnd -= 1; + } + + break; + } + } + + return true; +} + +} diff --git a/vcl/unx/generic/glyphs/scrptrun.h b/vcl/unx/generic/glyphs/scrptrun.h new file mode 100644 index 000000000000..2efcff4110ba --- /dev/null +++ b/vcl/unx/generic/glyphs/scrptrun.h @@ -0,0 +1,173 @@ +/* + ******************************************************************************* + * + * Copyright (c) 1995-2013 International Business Machines Corporation and others + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * provided that the above copyright notice(s) and this permission notice appear + * in all copies of the Software and that both the above copyright notice(s) and + * this permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN + * NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE + * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not be + * used in advertising or otherwise to promote the sale, use or other dealings in + * this Software without prior written authorization of the copyright holder. + * + ******************************************************************************* + * file name: scrptrun.h + * + * created on: 10/17/2001 + * created by: Eric R. Mader + */ + +#ifndef INCLUDED_VCL_GENERIC_GLYPHS_SCRPTRUN_H +#define INCLUDED_VCL_GENERIC_GLYPHS_SCRPTRUN_H + +#include + +#include +#include "unicode/utypes.h" +#include "unicode/uobject.h" +#include "unicode/uscript.h" +#include + +namespace vcl { + +struct ParenStackEntry +{ + int32_t pairIndex; + UScriptCode scriptCode; + ParenStackEntry() + : pairIndex(0) + , scriptCode(USCRIPT_INVALID_CODE) + { + } +}; + +class ScriptRun : public UObject { +public: + ScriptRun(); + + ScriptRun(const UChar chars[], int32_t length); + + ScriptRun(const UChar chars[], int32_t start, int32_t length); + + void reset(); + + void reset(int32_t start, int32_t count); + + void reset(const UChar chars[], int32_t start, int32_t length); + + int32_t getScriptStart(); + + int32_t getScriptEnd(); + + UScriptCode getScriptCode(); + + UBool next(); + + /** +s * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.2 + */ + virtual inline UClassID getDynamicClassID() const override { return getStaticClassID(); } + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.2 + */ + static inline UClassID getStaticClassID() { return static_cast(const_cast(&fgClassID)); } + +private: + + int32_t charStart; + int32_t charLimit; + const UChar *charArray; + + int32_t scriptStart; + int32_t scriptEnd; + UScriptCode scriptCode; + + std::vector parenStack; + int32_t parenSP; + + /** + * The address of this static class variable serves as this class's ID + * for ICU "poor man's RTTI". + */ + static const char fgClassID; +}; + +inline ScriptRun::ScriptRun() +{ + reset(NULL, 0, 0); +} + +inline ScriptRun::ScriptRun(const UChar chars[], int32_t length) +{ + reset(chars, 0, length); +} + +inline ScriptRun::ScriptRun(const UChar chars[], int32_t start, int32_t length) +{ + reset(chars, start, length); +} + +inline int32_t ScriptRun::getScriptStart() +{ + return scriptStart; +} + +inline int32_t ScriptRun::getScriptEnd() +{ + return scriptEnd; +} + +inline UScriptCode ScriptRun::getScriptCode() +{ + return scriptCode; +} + +inline void ScriptRun::reset() +{ + scriptStart = charStart; + scriptEnd = charStart; + scriptCode = USCRIPT_INVALID_CODE; + parenSP = -1; + parenStack.resize(128); +} + +inline void ScriptRun::reset(int32_t start, int32_t length) +{ + charStart = start; + charLimit = start + length; + + reset(); +} + +inline void ScriptRun::reset(const UChar chars[], int32_t start, int32_t length) +{ + charArray = chars; + + reset(start, length); +} + +} + +#endif -- cgit