Rebased ref, commits from common ancestor: commit 4f0fede6364bac10705a4bde325e9ab35ad5b5fd Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Oct 13 22:46:28 2016 +0200
Check SAL_USE_COMMON_LAYOUT envar in one place Makes it easier to flip the switch in the future (or even do something more fancy other than checking envvar). Change-Id: Ie42ca012c167b2108f0fca1ce9ff7beee95f1be7 diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index 1050943..364bd48 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -201,6 +201,8 @@ public: virtual std::shared_ptr<vcl::TextLayoutCache> CreateTextLayoutCache(OUString const&) const; + static bool UseCommonLayout(); + protected: // used by layout engines SalLayout(); diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx index f7fe0af..856e066 100644 --- a/vcl/quartz/ctlayout.cxx +++ b/vcl/quartz/ctlayout.cxx @@ -782,7 +782,7 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {} SalLayout* CoreTextStyle::GetTextLayout() const { - if (getenv("SAL_USE_COMMON_LAYOUT")) + if (SalLayout::UseCommonLayout()) return new CommonSalLayout(*this); else return new CTLayout(this); diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index ea16f4f..86b3ab1d 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -768,6 +768,12 @@ bool SalLayout::IsSpacingGlyph( sal_GlyphId nGlyph ) return bRet; } +bool SalLayout::UseCommonLayout() +{ + static bool bUse = getenv("SAL_USE_COMMON_LAYOUT") != nullptr; + return bUse; +} + GenericSalLayout::GenericSalLayout() {} diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 46b9326..35d086d 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -532,7 +532,7 @@ SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackL if( mpServerFont[ nFallbackLevel ] && !(rArgs.mnFlags & SalLayoutFlags::DisableGlyphProcessing) ) { - if (getenv("SAL_USE_COMMON_LAYOUT")) + if (SalLayout::UseCommonLayout()) { pLayout = new CommonSalLayout(*mpServerFont[nFallbackLevel]); } diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index de0b4bf..9681986 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -3900,7 +3900,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ]; WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ]; - if (getenv("SAL_USE_COMMON_LAYOUT")) + if (SalLayout::UseCommonLayout()) { return new CommonSalLayout(this, rFontInstance, rFontFace); } commit aba6d0bd84f8f36dcbe50eacbfd72d0d6182cc2d Author: Khaled Hosny <khaledho...@eglug.org> Date: Mon Oct 10 01:36:45 2016 +0200 Just call ICU directly and cut the middle layers Change-Id: I7603d03fef8ca227c3e6fe25239281d18801522a diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 6f24f30..3583b79 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -25,6 +25,7 @@ #include <i18nlangtag/mslangid.hxx> #include <limits> #include <salgdi.hxx> +#include <unicode/uchar.h> #if defined(_WIN32) struct WinSalGraphicsWithIDFace @@ -116,14 +117,14 @@ static void scaleHbFont(hb_font_t* pHbFont, const FontSelectPattern& aFontSelDat hb_font_set_scale(pHbFont, nXScale, nYScale); } +#if !HB_VERSION_ATLEAST(1, 1, 0) static hb_unicode_funcs_t* getUnicodeFuncs() { static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs()); -#if !HB_VERSION_ATLEAST(1, 1, 0) hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, nullptr, nullptr); -#endif return ufuncs; } +#endif #if defined(_WIN32) CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace) @@ -392,8 +393,8 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */ hb_buffer_t *pHbBuffer = hb_buffer_create(); - static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); #if !HB_VERSION_ATLEAST(1, 1, 0) + static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); #endif if (SAL_UNLIKELY(bVertical)) @@ -452,7 +453,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) else { #if HB_VERSION_ATLEAST(0, 9, 42) - if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) + if (u_getIntPropertyValue(aChar, UCHAR_GENERAL_CATEGORY) == U_NON_SPACING_MARK) bDiacritic = true; #else // the font lacks GDEF table @@ -588,8 +589,7 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) sal_Int32 indexUtf16 = pGlyphIter->mnCharPos; sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0); - static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); - if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR) + if (u_isUWhiteSpace(aChar)) continue; DeviceCoordinate nGapWidth = pKashida.second; commit 5ffb6d7691546197e9ad8ec8653107edb6fd504d Author: Khaled Hosny <khaledho...@eglug.org> Date: Mon Oct 10 00:54:00 2016 +0200 Validate Kashida positions in CommonSalLayout Currently checks only for ligatures, but that is a big improvement over al code that didnât do any validation except on Windows. Change-Id: I035248f4ccc23134ea27b40c2dd6197130749f14 diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 3115cee..513d2b9 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -71,6 +71,8 @@ public: virtual bool GetCharWidths(DeviceCoordinate* pCharWidths) const override; virtual void ApplyDXArray(ImplLayoutArgs&) override; + + virtual bool IsKashidaPosValid(int nCharPos) const override; }; #endif diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 5c89172..6f24f30 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -615,3 +615,30 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) } } } + +bool CommonSalLayout::IsKashidaPosValid(int nCharPos) const +{ + for (auto pIter = m_GlyphItems.begin(); pIter != m_GlyphItems.end(); ++pIter) + { + if (pIter->mnCharPos == nCharPos) + { + // Search backwards for previous glyph belonging to a different + // character. We are looking backwards because we are dealing with + // RTL glyphs, which will be in visual order. + for (auto pPrev = pIter - 1; pPrev != m_GlyphItems.begin(); --pPrev) + { + if (pPrev->mnCharPos != nCharPos) + { + // Check if the found glyph belongs to the next character, + // otherwise the current glyph will be a ligature which is + // invalid kashida position. + if (pPrev->mnCharPos == (nCharPos + 1)) + return true; + break; + } + } + } + } + + return false; +} commit 0762d97cfec60c54fbdb7654ed7843c5b9dfa36b Author: Khaled Hosny <khaledho...@eglug.org> Date: Sun Oct 9 23:23:45 2016 +0200 Re-enable Kashida insertion in CommonSalLayout We now do Kashida insertion in ApplyDXArray(), no need for a separate step. This simplifies the code greatly (old code is in GenericSalLayout::KashidaJustify()). Change-Id: Ie31c8969e26f1f293820f1e90f963a5ba1fc9eb1 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 9badd1d..5c89172 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -286,27 +286,18 @@ void CommonSalLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos, void CommonSalLayout::AdjustLayout(ImplLayoutArgs& rArgs) { - GenericSalLayout::AdjustLayout(rArgs); + SalLayout::AdjustLayout(rArgs); + + if (rArgs.mpDXArray) + ApplyDXArray(rArgs); + else if (rArgs.mnLayoutWidth) + Justify(rArgs.mnLayoutWidth); // 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); - - if ((rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray) - { - hb_codepoint_t nKashidaCodePoint = 0x0640; - hb_codepoint_t nKashidaGlyphIndex; - - if (hb_font_get_glyph(mpHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex)) - { - if (nKashidaGlyphIndex) - { - KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(mpHbFont, nKashidaGlyphIndex) >> 6); - } - } - } } void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const @@ -549,6 +540,16 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1]; } + DeviceCoordinate nKashidaWidth = 0; + hb_codepoint_t nKashidaIndex; + if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification) + { + if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex)) + nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, nKashidaIndex) / 64; + } + + std::map<size_t, DeviceCoordinate> pKashidas; + DeviceCoordinate nDelta = 0; size_t i = 0; while (i < m_GlyphItems.size()) @@ -556,16 +557,61 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos; DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos]; - m_GlyphItems[i].maLinearPos.X() += nDelta; + if (nKashidaWidth && nDiff) + pKashidas[i] = nDiff; + size_t j = i; - while (++j < m_GlyphItems.size()) + while (j < m_GlyphItems.size()) { if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos) break; m_GlyphItems[j].maLinearPos.X() += nDelta; + // For RTL, put all justification space to the left of the glyph. + if (m_GlyphItems[i].IsRTLGlyph()) + m_GlyphItems[j].maLinearPos.X() += nDiff; + ++j; } nDelta += nDiff; i = j; } + + if (!pKashidas.empty()) + { + size_t nInserted = 0; + for (auto const& pKashida : pKashidas) + { + auto pGlyphIter = m_GlyphItems.begin() + nInserted + pKashida.first; + + if (!pGlyphIter->IsRTLGlyph()) + continue; + + sal_Int32 indexUtf16 = pGlyphIter->mnCharPos; + sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0); + static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); + if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR) + continue; + + DeviceCoordinate nGapWidth = pKashida.second; + int nKashidaCount = ceil(nGapWidth / nKashidaWidth); + DeviceCoordinate nInsertedKashidaWidth; + if (nGapWidth < nKashidaWidth) + nInsertedKashidaWidth = nGapWidth; + else + nInsertedKashidaWidth = nGapWidth / nKashidaCount; + + Point aPos(pGlyphIter->maLinearPos.X() - nGapWidth, 0); + int nCharPos = pGlyphIter->mnCharPos; + int nFlags = GlyphItem::IS_IN_CLUSTER | GlyphItem::IS_RTL_GLYPH; + while (nKashidaCount) + { + GlyphItem aKashida(nCharPos, nKashidaIndex, aPos, nFlags, nInsertedKashidaWidth); + pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida); + aPos.X() += nInsertedKashidaWidth; + ++pGlyphIter; + ++nInserted; + --nKashidaCount; + } + } + } } commit 2e243d4459df785f0cabfbe6e64d4be6a34587ca Author: Khaled Hosny <khaledho...@eglug.org> Date: Sun Oct 9 19:08:18 2016 +0200 Revert "Use HarfBuzz shape plan for a bit more control" This reverts commit 8b32ead0b988b142cd9878f126d985d946fd4ccc. diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 7c95c39..9badd1d 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -317,7 +317,6 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) { - hb_face_t* pHbFace = hb_font_get_face(mpHbFont); hb_script_t aHbScript = HB_SCRIPT_INVALID; int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos); @@ -419,13 +418,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) #if HB_VERSION_ATLEAST(0, 9, 42) hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); #endif - const char *pHbShapers[5] = { "coretext_aat", "graphite2", "ot", "fallback", nullptr }; - hb_segment_properties_t aHbProps; - hb_buffer_get_segment_properties(pHbBuffer, &aHbProps); - hb_shape_plan_t *pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, nullptr, 0, pHbShapers); - assert(hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, nullptr, 0)); - hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); - SAL_INFO("vcl.harfbuzz", hb_shape_plan_get_shaper(pHbPlan) << " shaper used for " << rArgs); + hb_shape(mpHbFont, pHbBuffer, nullptr, 0); int nRunGlyphCount = hb_buffer_get_length(pHbBuffer); hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr); @@ -458,6 +451,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; bool bDiacritic = false; + hb_face_t* pHbFace = hb_font_get_face(mpHbFont); if (hb_ot_layout_has_glyph_classes(pHbFace)) { // the font has GDEF table commit ba5f5be11e143004575e39f8fd15e05504e0a707 Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Oct 6 04:15:41 2016 +0200 Use HarfBuzz shape plan for a bit more control This way we control exactly what shapers we use in what order, and as an extra we can now tell which shaper HarfBuzz ends up using. Change-Id: Idd303b2a557e16ac86ada0c2006d3e2a052ac489 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 9badd1d..7c95c39 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -317,6 +317,7 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) { + hb_face_t* pHbFace = hb_font_get_face(mpHbFont); hb_script_t aHbScript = HB_SCRIPT_INVALID; int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos); @@ -418,7 +419,13 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) #if HB_VERSION_ATLEAST(0, 9, 42) hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); #endif - hb_shape(mpHbFont, pHbBuffer, nullptr, 0); + const char *pHbShapers[5] = { "coretext_aat", "graphite2", "ot", "fallback", nullptr }; + hb_segment_properties_t aHbProps; + hb_buffer_get_segment_properties(pHbBuffer, &aHbProps); + hb_shape_plan_t *pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, nullptr, 0, pHbShapers); + assert(hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, nullptr, 0)); + hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); + SAL_INFO("vcl.harfbuzz", hb_shape_plan_get_shaper(pHbPlan) << " shaper used for " << rArgs); int nRunGlyphCount = hb_buffer_get_length(pHbBuffer); hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr); @@ -451,7 +458,6 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; bool bDiacritic = false; - hb_face_t* pHbFace = hb_font_get_face(mpHbFont); if (hb_ot_layout_has_glyph_classes(pHbFace)) { // the font has GDEF table commit aacf6a5cc5ec7b98f547a368b62c7393ad5f250c Author: Khaled Hosny <khaledho...@eglug.org> Date: Mon Sep 26 19:09:52 2016 +0200 First try on vertical text in CommonSalLayout Does not work quite right yet. Change-Id: I52a71c9c21ad75c7cb9c8574e5e7e3b7c1c0c0c3 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index d19506f..9badd1d 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -384,6 +384,16 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) LanguageTag &rTag = rArgs.maLanguageTag; OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US); + bool bVertical = false; + if ((rArgs.mnFlags & SalLayoutFlags::Vertical) && + (aHbScript == HB_SCRIPT_HAN || + aHbScript == HB_SCRIPT_HANGUL || + aHbScript == HB_SCRIPT_HIRAGANA || + aHbScript == HB_SCRIPT_KATAKANA)) + { + bVertical = true; + } + int nHbFlags = HB_BUFFER_FLAGS_DEFAULT; if (nMinRunPos == 0) nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */ @@ -395,7 +405,10 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) #if !HB_VERSION_ATLEAST(1, 1, 0) hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); #endif - hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); + if (SAL_UNLIKELY(bVertical)) + hb_buffer_set_direction(pHbBuffer, HB_DIRECTION_TTB); + else + hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); hb_buffer_set_script(pHbBuffer, aHbScript); hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1)); hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags); @@ -460,17 +473,31 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) 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; + int32_t nXOffset; + int32_t nYOffset; + int32_t nXAdvance; + Point aNewPos; + + if (SAL_UNLIKELY(bVertical)) + { + nXOffset = pHbPositions[i].y_offset >> 6; + nYOffset = pHbPositions[i].x_offset >> 6; + nXAdvance = pHbPositions[i].y_advance >> 6; + nGlyphIndex |= GF_ROTL; + aNewPos = Point(-(aCurrPos.X() + nXOffset), aCurrPos.Y() + nYOffset); + } + else + { + nXOffset = pHbPositions[i].x_offset >> 6; + nYOffset = pHbPositions[i].y_offset >> 6; + nXAdvance = pHbPositions[i].x_advance >> 6; + aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset)); + } - Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset)); const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset); AppendGlyph(aGI); aCurrPos.X() += nXAdvance; - aCurrPos.Y() += nYAdvance; } hb_buffer_destroy(pHbBuffer); commit 9d36823ebc2c01ea8e1529a488ce5a697ab74b0b Author: Khaled Hosny <khaledho...@eglug.org> Date: Sat Sep 24 23:13:47 2016 +0200 Use range loop Change-Id: I5ce49e57ed57378b4b9e16c8bb020048644252a9 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 92e0597..d19506f 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -374,12 +374,12 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) if (bRightToLeft) std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end()); - for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it) + for (const auto& aScriptRun : aScriptSubRuns) { - int nMinRunPos = it->mnMin; - int nEndRunPos = it->mnEnd; + int nMinRunPos = aScriptRun.mnMin; + int nEndRunPos = aScriptRun.mnEnd; int nRunLen = nEndRunPos - nMinRunPos; - aHbScript = it->maScript; + aHbScript = aScriptRun.maScript; // hb_language_from_string() accept ISO639-3 language tag except for Chinese. LanguageTag &rTag = rArgs.maLanguageTag; OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US); commit 3e3983d04b1a394437b4b3d9506cfe4e41df4b46 Author: Khaled Hosny <khaledho...@eglug.org> Date: Sat Sep 24 23:04:39 2016 +0200 Use const reference Change-Id: I0f632f3a8b480f785608aa081add1b1d2fefd312 diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index dfd58fe..3115cee 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -39,7 +39,7 @@ class CommonSalLayout : public GenericSalLayout { hb_font_t* mpHbFont; - FontSelectPattern maFontSelData; + const FontSelectPattern& mrFontSelData; css::uno::Reference<css::i18n::XBreakIterator> mxBreak; #ifdef _WIN32 HDC mhDC; diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 64f55a8..92e0597 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -129,7 +129,7 @@ static hb_unicode_funcs_t* getUnicodeFuncs() CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace) : mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)), mhDC(WSL->getHDC()), - maFontSelData(rWinFontInstance.maFontSelData), + mrFontSelData(rWinFontInstance.maFontSelData), mpD2DRenderer(nullptr) { mpHbFont = rWinFontFace.GetHbFont(); @@ -153,7 +153,7 @@ CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontI hb_face_destroy(pHbFace); } - scaleHbFont(mpHbFont, maFontSelData); + scaleHbFont(mpHbFont, mrFontSelData); } void CommonSalLayout::InitFont() const @@ -163,7 +163,7 @@ void CommonSalLayout::InitFont() const #elif defined(MACOSX) || defined(IOS) CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) -: maFontSelData(rCoreTextStyle.maFontSelData), +: mrFontSelData(rCoreTextStyle.maFontSelData), mrCoreTextStyle(rCoreTextStyle) { mpHbFont = rCoreTextStyle.GetHbFont(); @@ -184,12 +184,12 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) hb_face_destroy(pHbFace); } - scaleHbFont(mpHbFont, maFontSelData); + scaleHbFont(mpHbFont, mrFontSelData); } #else CommonSalLayout::CommonSalLayout(ServerFont& rServerFont) -: maFontSelData(rServerFont.GetFontSelData()), +: mrFontSelData(rServerFont.GetFontSelData()), mrServerFont(rServerFont) { mpHbFont = rServerFont.GetHbFont(); @@ -203,7 +203,7 @@ CommonSalLayout::CommonSalLayout(ServerFont& rServerFont) hb_face_destroy(pHbFace); } - scaleHbFont(mpHbFont, maFontSelData); + scaleHbFont(mpHbFont, mrFontSelData); } #endif commit 1c2d0c6dd8b2538151faf504bdeb80f6e1d4b1eb Author: Khaled Hosny <khaledho...@eglug.org> Date: Fri Sep 23 18:34:09 2016 +0200 Make sure HarfBuzz module depends on Graphite Change-Id: I9c1cc9c679ceebeb4e5cd898876aaa7b61c18f17 diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 64eeacf..c818136 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -1368,6 +1368,8 @@ $(call gb_LinkTarget_add_libs,$(1),$(GRAPHITE_LIBS)) endef +gb_ExternalProject__use_graphite:= + else # !SYSTEM_GRAPHITE define gb_LinkTarget__use_graphite @@ -1382,6 +1384,10 @@ $(call gb_LinkTarget_use_static_libraries,$(1),\ endef +define gb_ExternalProject__use_graphite +$(call gb_ExternalProject_use_external_project,$(1),graphite) + +endef endif # SYSTEM_GRAPHITE ifneq ($(SYSTEM_ICU),) diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk index 1be5c6f..57cfc44 100644 --- a/external/harfbuzz/ExternalProject_harfbuzz.mk +++ b/external/harfbuzz/ExternalProject_harfbuzz.mk @@ -17,6 +17,7 @@ $(eval $(call gb_ExternalProject_register_targets,harfbuzz,\ $(eval $(call gb_ExternalProject_use_externals,harfbuzz,\ icu \ + graphite \ )) $(call gb_ExternalProject_get_state_target,harfbuzz,build) : commit 1b5794eae66d0675186348bef981e70f51106300 Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Sep 22 07:57:04 2016 -0700 Build HarfBuzz with Core Text on Mac To enable support for AAT fonts. Change-Id: Ifcc7d1672e98f8c067482400b7e45226bed4dbf1 diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk index 4412815..1be5c6f 100644 --- a/external/harfbuzz/ExternalProject_harfbuzz.mk +++ b/external/harfbuzz/ExternalProject_harfbuzz.mk @@ -36,6 +36,7 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) : --with-cairo=no \ --with-glib=no \ --with-graphite2=yes \ + $(if $(filter MACOSX,$(OS)),--with-coretext=yes) \ $(if $(verbose),--disable-silent-rules,--enable-silent-rules) \ $(if $(CROSS_COMPILING),--build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM)) \ $(if $(filter LINUX,$(OS)),CXXFLAGS="$(CXXFLAGS) -fvisibility=hidden") \ commit 15971133c54d131434af80cfdf4c93c682039e2a Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Sep 22 19:48:10 2016 +0200 Always pass BCP 47 tags to HarfBuzz This is what it is expecting anyway, no need to special case it for Chinese. Change-Id: I6732412375d19816b599005d78abd796f67599ee diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 0695810..64f55a8 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -382,7 +382,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) aHbScript = 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); + OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US); int nHbFlags = HB_BUFFER_FLAGS_DEFAULT; if (nMinRunPos == 0) commit e08d5f694941cbee0d5606167cdf32e3ab36b07d Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Sep 22 19:45:23 2016 +0200 Always build Graphite everywhere It is no longer an optional feature on any platform. The --enable-graphite stuff is kept as it controls the old Graphite integration code and it should be removed without. Change-Id: Ib4d76bba782a1439f02f93411b22d237a1987ea5 diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index e0f1337..64eeacf 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -1357,8 +1357,6 @@ endef endif # SYSTEM_FONTCONFIG -ifeq ($(ENABLE_GRAPHITE),TRUE) - ifneq ($(SYSTEM_GRAPHITE),) define gb_LinkTarget__use_graphite @@ -1386,12 +1384,6 @@ endef endif # SYSTEM_GRAPHITE -else # !ENABLE_GRAPHITE - -gb_LinkTarget__use_graphite := - -endif # ENABLE_GRAPHITE - ifneq ($(SYSTEM_ICU),) gb_LinkTarget__use_icu_headers:= diff --git a/configure.ac b/configure.ac index 43cc369..4124f5c 100644 --- a/configure.ac +++ b/configure.ac @@ -9240,19 +9240,20 @@ AC_SUBST(ICU_LIBS) dnl =================================================================== dnl Graphite dnl =================================================================== +libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"]) +if test "$with_system_graphite" = "yes"; then + libo_MINGW_CHECK_DLL([libgraphite2]) +fi +if test "$COM" = "MSC"; then # override the above + GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib" +fi +# This is the old Graphite support that will eventually be removed AC_MSG_CHECKING([whether to enable graphite support]) if test $_os != Darwin -a $_os != Android -a $_os != iOS -a \( -z "$enable_graphite" -o "$enable_graphite" != no \); then AC_MSG_RESULT([yes]) ENABLE_GRAPHITE="TRUE" AC_DEFINE(ENABLE_GRAPHITE) - libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"]) - if test "$with_system_graphite" = "yes"; then - libo_MINGW_CHECK_DLL([libgraphite2]) - fi - if test "$COM" = "MSC"; then # override the above - GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib" - fi else AC_MSG_RESULT([no]) @@ -9339,6 +9340,9 @@ if test "$COM" = "MSC"; then # override the above HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib" fi if test "$with_system_harfbuzz" = "yes"; then + if test "$with_system_graphite" = "no"; then + AC_MSG_ERROR([--with-system-graphite must be used when --with-system-harfbuzz is used]) + fi AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support]) _save_libs="$LIBS" _save_cflags="$CFLAGS" @@ -9347,6 +9351,10 @@ if test "$with_system_harfbuzz" = "yes"; then AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])]) LIBS="$_save_libs" CFLAGS="$_save_cflags" +else + if test "$with_system_graphite" = "yes"; then + AC_MSG_ERROR([--without-system-graphite must be used when --without-system-harfbuzz is used]) + fi fi AC_MSG_CHECKING([whether to use X11]) diff --git a/vcl/CppunitTest_vcl_wmf_test.mk b/vcl/CppunitTest_vcl_wmf_test.mk index 51e9126..1de86d8 100644 --- a/vcl/CppunitTest_vcl_wmf_test.mk +++ b/vcl/CppunitTest_vcl_wmf_test.mk @@ -80,6 +80,7 @@ endif $(eval $(call gb_CppunitTest_use_externals,vcl_wmf_test,\ gio \ + graphite \ harfbuzz \ icuuc \ lcms2 \ @@ -90,10 +91,6 @@ $(eval $(call gb_CppunitTest_use_externals,vcl_wmf_test,\ )) endif -ifeq ($(ENABLE_GRAPHITE),TRUE) -$(eval $(call gb_CppunitTest_use_external,vcl_wmf_test,graphite)) -endif - ifeq ($(OS),MACOSX) $(eval $(call gb_CppunitTest_use_system_darwin_frameworks,vcl_wmf_test,\ ApplicationServices \ diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 67bcbe5..2b0874a 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -116,6 +116,7 @@ $(eval $(call gb_Library_use_externals,vcl,\ boost_headers \ gio \ glm_headers \ + graphite \ harfbuzz \ icu_headers \ icuuc \ @@ -434,8 +435,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ )) endif -$(eval $(call gb_Library_use_external,vcl,graphite)) - endif vcl_quartz_code= \ commit 7ea9095da39f54488e3c9e8ff90053094b305a24 Author: Khaled Hosny <khaledho...@eglug.org> Date: Thu Sep 22 19:29:04 2016 +0200 Always build HarfBuzz everywhere It is no longer an optional feature on any platform. Change-Id: I70cdcd2c0df69d961ecc5f36b4e8d035d251ef16 diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 95241ab..e0f1337 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -1490,7 +1490,6 @@ endef endif # SYSTEM_ICU -ifeq ($(ENABLE_HARFBUZZ),TRUE) ifneq ($(SYSTEM_HARFBUZZ),) define gb_LinkTarget__use_harfbuzz @@ -1515,11 +1514,6 @@ $(call gb_LinkTarget_use_external_project,$(1),harfbuzz) endef endif # SYSTEM_HARFBUZZ -else # ENABLE_HARFBUZZ != YES - -gb_LinkTarget__use_harfbuzz := - -endif # ENABLE_HARFBUZZ ifeq ($(DISABLE_OPENSSL),TRUE) diff --git a/config_host.mk.in b/config_host.mk.in index 2e6d007..90c25a6 100644 --- a/config_host.mk.in +++ b/config_host.mk.in @@ -133,7 +133,6 @@ export ENABLE_FIREBIRD_SDBC=@ENABLE_FIREBIRD_SDBC@ export ENABLE_GIO=@ENABLE_GIO@ export ENABLE_GRAPHITE=@ENABLE_GRAPHITE@ export ENABLE_ORCUS=@ENABLE_ORCUS@ -export ENABLE_HARFBUZZ=@ENABLE_HARFBUZZ@ export ENABLE_GLTF=@ENABLE_GLTF@ export SYSTEM_LIBGLTF=@SYSTEM_LIBGLTF@ export LIBGLTF_CFLAGS=@LIBGLTF_CFLAGS@ diff --git a/configure.ac b/configure.ac index 5559e8b..43cc369 100644 --- a/configure.ac +++ b/configure.ac @@ -2135,12 +2135,6 @@ AC_ARG_WITH(iwyu, Use only if you are hacking on it.]), ,) -AC_ARG_WITH(harfbuzz, - AS_HELP_STRING([--with-harfbuzz], - [Enable HarfBuzz support regardless of the platform. - Experimental only. Use only if working on it.]), -,) - dnl =================================================================== dnl Branding dnl =================================================================== @@ -9340,32 +9334,20 @@ AC_SUBST(ENABLE_ORCUS) dnl =================================================================== dnl HarfBuzz dnl =================================================================== -AC_MSG_CHECKING([whether to enable HarfBuzz support]) -if test "$with_harfbuzz" = "yes" -o \( $_os != WINNT -a $_os != Darwin -a $_os != iOS \); then - AC_MSG_RESULT([yes]) - ENABLE_HARFBUZZ="TRUE" - if $PKG_CONFIG --atleast-version 0.9.18 harfbuzz; then - libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 0.9.18],["-I${WORKDIR}/UnpackedTarball/harfbuzz/src"],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"]) - else - libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz >= 0.9.10],[-I${WORKDIR}/UnpackedTarball/harfbuzz/src],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"]) - fi - if test "$COM" = "MSC"; then # override the above - HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib" - fi - if test "$with_system_harfbuzz" = "yes"; then - AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support]) - _save_libs="$LIBS" - _save_cflags="$CFLAGS" - LIBS="$LIBS $HARFBUZZ_LIBS" - CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" - AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])]) - LIBS="$_save_libs" - CFLAGS="$_save_cflags" - fi -else - AC_MSG_RESULT([no]) +libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 0.9.18],["-I${WORKDIR}/UnpackedTarball/harfbuzz/src"],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"]) +if test "$COM" = "MSC"; then # override the above + HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib" +fi +if test "$with_system_harfbuzz" = "yes"; then + AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support]) + _save_libs="$LIBS" + _save_cflags="$CFLAGS" + LIBS="$LIBS $HARFBUZZ_LIBS" + CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" + AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])]) + LIBS="$_save_libs" + CFLAGS="$_save_cflags" fi -AC_SUBST(ENABLE_HARFBUZZ) AC_MSG_CHECKING([whether to use X11]) dnl *************************************** commit 38afd59461ed913b049b2618a8d344ef72c48874 Author: Khaled Hosny <khaledho...@eglug.org> Date: Sun Sep 11 10:25:46 2016 +0200 Override GetCharWidths and ApplyDXArray in CSL A much simpler and saner implementation. This also unbreaks Awami Nastaliq. Break kashida justification, will need to rewrite that one as well. Change-Id: I843679e937f2881e77df61f5cbd9516b6df1b3b6 diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index dbd7bc1..dfd58fe 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -68,6 +68,9 @@ public: bool LayoutText(ImplLayoutArgs&) override; void DrawText(SalGraphics&) const override; std::shared_ptr<vcl::TextLayoutCache> CreateTextLayoutCache(OUString const&) const override; + + virtual bool GetCharWidths(DeviceCoordinate* pCharWidths) const override; + virtual void ApplyDXArray(ImplLayoutArgs&) override; }; #endif diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index cfb2930..1050943 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -326,7 +326,7 @@ public: void AppendGlyph( const GlyphItem& ); void Reserve(int size) { m_GlyphItems.reserve(size + 1); } virtual void AdjustLayout( ImplLayoutArgs& ) override; - void ApplyDXArray( ImplLayoutArgs& ); + virtual void ApplyDXArray( ImplLayoutArgs& ); void Justify( DeviceCoordinate nNewWidth ); void KashidaJustify( long nIndex, int nWidth ); void ApplyAsianKerning(const OUString& rStr); @@ -352,7 +352,7 @@ protected: virtual void DropGlyph( int nStart ) override; virtual void Simplify( bool bIsBase ) override; - bool GetCharWidths( DeviceCoordinate* pCharWidths ) const; + virtual bool GetCharWidths( DeviceCoordinate* pCharWidths ) const; std::vector<GlyphItem> m_GlyphItems; diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index a303f70..0695810 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -489,3 +489,56 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) return true; } + +bool CommonSalLayout::GetCharWidths(DeviceCoordinate* pCharWidths) const +{ + int nCharCount = mnEndCharPos - mnMinCharPos; + + for (int i = 0; i < nCharCount; ++i) + pCharWidths[i] = 0; + + for (auto const& aGlyphItem : m_GlyphItems) + pCharWidths[aGlyphItem.mnCharPos - mnMinCharPos] += aGlyphItem.mnNewWidth; + + return true; +} + +void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) +{ + if (rArgs.mpDXArray == nullptr) + return; + + int nCharCount = mnEndCharPos - mnMinCharPos; + std::unique_ptr<DeviceCoordinate[]> const pOldCharWidths(new DeviceCoordinate[nCharCount]); + std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new DeviceCoordinate[nCharCount]); + + GetCharWidths(pOldCharWidths.get()); + + for (int i = 0; i < nCharCount; ++i) + { + if (i == 0) + pNewCharWidths[i] = rArgs.mpDXArray[i]; + else + pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1]; + } + + DeviceCoordinate nDelta = 0; + size_t i = 0; + while (i < m_GlyphItems.size()) + { + int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos; + DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos]; + + m_GlyphItems[i].maLinearPos.X() += nDelta; + size_t j = i; + while (++j < m_GlyphItems.size()) + { + if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos) + break; + m_GlyphItems[j].maLinearPos.X() += nDelta; + } + + nDelta += nDiff; + i = j; + } +} commit 9c1ab1595e5b29a24bd5101112ec55849b2dea15 Author: Khaled Hosny <khaledho...@eglug.org> Date: Wed Sep 7 23:26:14 2016 +0200 Donât check glyph class unnecessarily Donât call hb_ot_layout_get_glyph_class() unless the glyph advance width is zero, as we really do not use its result otherwise. Change-Id: Id02238abef91b9343931f1886d54d966d7157f25 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index b502d91..a303f70 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -442,9 +442,8 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) if (hb_ot_layout_has_glyph_classes(pHbFace)) { // the font has GDEF table - bool bMark = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; - if (bMark && pHbPositions[i].x_advance == 0) - bDiacritic = true; + if (pHbPositions[i].x_advance == 0) + bDiacritic = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; } else { commit 7fa41d046a10339c32f01ad63e254546ba4f2fa3 Author: Khaled Hosny <khaledho...@eglug.org> Date: Wed Sep 7 19:40:11 2016 +0200 Cache HarfBuzz font We now create it only once per physical font, saves us few percents from the all over time spent on layout. Change-Id: I8de582cb20a168c93d72921e539c2477fa97fb54 diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 73f680b..dbd7bc1 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -38,7 +38,7 @@ class CommonSalLayout : public GenericSalLayout { - hb_face_t* mpHbFace; + hb_font_t* mpHbFont; FontSelectPattern maFontSelData; css::uno::Reference<css::i18n::XBreakIterator> mxBreak; #ifdef _WIN32 @@ -51,7 +51,6 @@ class CommonSalLayout : public GenericSalLayout ServerFont& mrServerFont; #endif - hb_font_t* GetHbFont(); public: #if defined(_WIN32) explicit CommonSalLayout(WinSalGraphics*, WinFontInstance&, const WinFontFace&); diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 00b2d8e..f7e5156 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -99,8 +99,8 @@ public: void GetFontMetric( ImplFontMetricDataRef& ) const; bool GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const; bool GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const; - hb_face_t* GetHbFace() const { return mpHbFace; } - void SetHbFace(hb_face_t* pHbFace) const { mpHbFace = pHbFace; } + hb_font_t* GetHbFont() const { return mpHbFont; } + void SetHbFont(hb_font_t* pHbFont) const { mpHbFont = pHbFont; } const CoreTextFontFace* mpFontData; /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0 @@ -112,7 +112,7 @@ public: private: /// CoreText text style object CFMutableDictionaryRef mpStyleDict; - mutable hb_face_t* mpHbFace; + mutable hb_font_t* mpHbFont; friend class CTLayout; friend class AquaSalGraphics; diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx index 38967bf..7cb2a84 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -182,8 +182,8 @@ public: sal_GlyphId FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const; bool GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const; bool GetAntialiasAdvice() const; - hb_face_t* GetHbFace() { return mpHbFace; } - void SetHbFace( hb_face_t* pHbFace ) { mpHbFace=pHbFace; } + hb_font_t* GetHbFont() { return mpHbFont; } + void SetHbFont( hb_font_t* pHbFont ) { mpHbFont = pHbFont; } private: friend class GlyphCache; @@ -243,7 +243,7 @@ private: GlyphSubstitution maGlyphSubstitution; ServerFontLayoutEngine* mpLayoutEngine; - hb_face_t* mpHbFace; + hb_font_t* mpHbFont; }; // a class for cache entries for physical font instances that are based on serverfonts diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 5301390..3509f5a 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -142,12 +142,12 @@ private: mutable std::unordered_set<sal_UCS4> maGsubTable; mutable bool mbGsubRead; - mutable hb_face_t* mpHbFace; + mutable hb_font_t* mpHbFont; public: bool HasGSUBstitutions( HDC ) const; bool IsGSUBstituted( sal_UCS4 ) const; - hb_face_t* GetHbFace() const { return mpHbFace; } - void SetHbFace( hb_face_t* pHbFace ) const { mpHbFace = pHbFace; } + hb_font_t* GetHbFont() const { return mpHbFont; } + void SetHbFont( hb_font_t* pHbFont ) const { mpHbFont = pHbFont; } }; /** Class that creates (and destroys) a compatible Device Context. diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index f183c10..ac17abc 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -50,7 +50,7 @@ CoreTextStyle::CoreTextStyle( const FontSelectPattern& rFSD ) , mfFontRotation( 0.0 ) , maFontSelData( rFSD ) , mpStyleDict( nullptr ) - , mpHbFace( nullptr ) + , mpHbFont( nullptr ) { const FontSelectPattern* const pReqFont = &rFSD; @@ -117,8 +117,8 @@ CoreTextStyle::~CoreTextStyle() { if( mpStyleDict ) CFRelease( mpStyleDict ); - if( mpHbFace ) - hb_face_destroy( mpHbFace ); + if( mpHbFont ) + hb_font_destroy( mpHbFont ); } void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef& rxFontMetric ) const diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 2e012f3..b502d91 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -90,6 +90,32 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU return pBlob; } +static hb_font_t* createHbFont(hb_face_t* pHbFace) +{ + hb_font_t* pHbFont = hb_font_create(pHbFace); + hb_ot_font_set_funcs(pHbFont); + + return pHbFont; +} + +static void scaleHbFont(hb_font_t* pHbFont, const FontSelectPattern& aFontSelData) +{ + uint64_t nXScale = aFontSelData.mnWidth << 6; + uint64_t nYScale = aFontSelData.mnHeight << 6; + +#if defined(_WIN32) + // HACK to get stretched/shrunken text. TODO: Get rid of HACK + if (nXScale) + nXScale = double(nXScale) * 1.812; +#endif + + if (!nXScale) + nXScale = nYScale; + + hb_font_set_ppem(pHbFont, nXScale, nYScale); + hb_font_set_scale(pHbFont, nXScale, nYScale); +} + static hb_unicode_funcs_t* getUnicodeFuncs() { static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs()); @@ -103,16 +129,15 @@ static hb_unicode_funcs_t* getUnicodeFuncs() CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace) : mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)), mhDC(WSL->getHDC()), - mpHbFace(nullptr), maFontSelData(rWinFontInstance.maFontSelData), mpD2DRenderer(nullptr) { - mpHbFace = rWinFontFace.GetHbFace(); - if(!mpHbFace) + mpHbFont = rWinFontFace.GetHbFont(); + if (!mpHbFont) { mpD2DRenderer = dynamic_cast<D2DWriteTextOutRenderer*>(&TextOutRenderer::get()); WinSalGraphicsWithIDFace* pWSLWithIDFace = new WinSalGraphicsWithIDFace(WSL, mpD2DRenderer->GetDWriteFontFace(mhDC)); - mpHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace, + hb_face_t* pHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace, [](void* pUserData) { WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>( pUserData ); @@ -121,8 +146,14 @@ CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontI delete pUData; } ); - rWinFontFace.SetHbFace(mpHbFace); + + mpHbFont = createHbFont(pHbFace); + rWinFontFace.SetHbFont(mpHbFont); + + hb_face_destroy(pHbFace); } + + scaleHbFont(mpHbFont, maFontSelData); } void CommonSalLayout::InitFont() const @@ -132,54 +163,49 @@ void CommonSalLayout::InitFont() const #elif defined(MACOSX) || defined(IOS) CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) -: mpHbFace(nullptr), - maFontSelData(rCoreTextStyle.maFontSelData), +: maFontSelData(rCoreTextStyle.maFontSelData), mrCoreTextStyle(rCoreTextStyle) { - mpHbFace = rCoreTextStyle.GetHbFace(); - if(!mpHbFace) + mpHbFont = rCoreTextStyle.GetHbFont(); + if (!mpHbFont) { + hb_face_t* pHbFace; CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName)); CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL); if (pCGFont) - mpHbFace = hb_coretext_face_create(pCGFont); + pHbFace = hb_coretext_face_create(pCGFont); else - mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); + pHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); CGFontRelease(pCGFont); - rCoreTextStyle.SetHbFace(mpHbFace); + + mpHbFont = createHbFont(pHbFace); + rCoreTextStyle.SetHbFont(mpHbFont); + + hb_face_destroy(pHbFace); } + + scaleHbFont(mpHbFont, maFontSelData); } #else CommonSalLayout::CommonSalLayout(ServerFont& rServerFont) -: mpHbFace(nullptr), - maFontSelData(rServerFont.GetFontSelData()), +: maFontSelData(rServerFont.GetFontSelData()), mrServerFont(rServerFont) { - mpHbFace = rServerFont.GetHbFace(); - if(!mpHbFace) + mpHbFont = rServerFont.GetHbFont(); + if (!mpHbFont) { - mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); - mrServerFont.SetHbFace(mpHbFace); - } -} -#endif + hb_face_t* pHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); -hb_font_t* CommonSalLayout::GetHbFont() -{ - // HACK. TODO: Get rid of HACK -#if defined(_WIN32) - if (maFontSelData.mnWidth) - maFontSelData.mnWidth = (double)maFontSelData.mnWidth*1.812; -#endif + mpHbFont = createHbFont(pHbFace); + mrServerFont.SetHbFont(mpHbFont); - hb_font_t* pHbFont = hb_font_create(mpHbFace); - hb_font_set_ppem(pHbFont, maFontSelData.mnWidth? maFontSelData.mnWidth:maFontSelData.mnHeight , maFontSelData.mnHeight); - hb_font_set_scale(pHbFont, (uint64_t)(maFontSelData.mnWidth? maFontSelData.mnWidth:maFontSelData.mnHeight) << 6, - (uint64_t)maFontSelData.mnHeight << 6); - hb_ot_font_set_funcs(pHbFont); - return pHbFont; + hb_face_destroy(pHbFace); + } + + scaleHbFont(mpHbFont, maFontSelData); } +#endif struct HbScriptRun { @@ -270,18 +296,16 @@ void CommonSalLayout::AdjustLayout(ImplLayoutArgs& rArgs) if ((rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray) { - hb_font_t* pHbFont = GetHbFont(); hb_codepoint_t nKashidaCodePoint = 0x0640; hb_codepoint_t nKashidaGlyphIndex; - if (hb_font_get_glyph(pHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex)) + if (hb_font_get_glyph(mpHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex)) { if (nKashidaGlyphIndex) { - KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(pHbFont, nKashidaGlyphIndex) >> 6); + KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(mpHbFont, nKashidaGlyphIndex) >> 6); } } - hb_font_destroy(pHbFont); } } @@ -293,7 +317,6 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) { - hb_font_t* pHbFont = GetHbFont(); hb_script_t aHbScript = HB_SCRIPT_INVALID; int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos); @@ -382,7 +405,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) #if HB_VERSION_ATLEAST(0, 9, 42) hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); #endif - hb_shape(pHbFont, pHbBuffer, nullptr, 0); + hb_shape(mpHbFont, pHbBuffer, nullptr, 0); int nRunGlyphCount = hb_buffer_get_length(pHbBuffer); hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr); @@ -415,10 +438,11 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; bool bDiacritic = false; - if (hb_ot_layout_has_glyph_classes(mpHbFace)) + hb_face_t* pHbFace = hb_font_get_face(mpHbFont); + if (hb_ot_layout_has_glyph_classes(pHbFace)) { // the font has GDEF table - bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; + bool bMark = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK; if (bMark && pHbPositions[i].x_advance == 0) bDiacritic = true; } @@ -454,8 +478,6 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) } } - hb_font_destroy(pHbFont); - // sort glyphs in visual order // and then in logical order (e.g. diacritics after cluster start) // XXX: why? diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 8cf7198..fbeb95e 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -462,7 +462,7 @@ ServerFont::ServerFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI ) mbArtBold( false ), mbUseGamma( false ), mpLayoutEngine( nullptr ), - mpHbFace( nullptr ) + mpHbFont( nullptr ) { // TODO: move update of mpFontInstance into FontEntry class when // it becomes responsible for the ServerFont instantiation @@ -611,8 +611,8 @@ ServerFont::~ServerFont() mpFontInfo->ReleaseFaceFT(); - if( mpHbFace ) - hb_face_destroy( mpHbFace ); + if( mpHbFont ) + hb_font_destroy( mpHbFont ); ReleaseFromGarbageCollect(); } diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 3977cee..379b8cc 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -869,7 +869,7 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, mbAliasSymbolsHigh( false ), mbAliasSymbolsLow( false ), mbGsubRead( false ), - mpHbFace( nullptr ) + mpHbFont( nullptr ) { SetBitmapSize( 0, nHeight ); @@ -911,8 +911,8 @@ WinFontFace::~WinFontFace() #endif // ENABLE_GRAPHITE delete mpEncodingVector; - if( mpHbFace ) - hb_face_destroy( mpHbFace ); + if( mpHbFont ) + hb_font_destroy( mpHbFont ); } sal_IntPtr WinFontFace::GetFontId() const diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 5e183fc..de0b4bf 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -4065,8 +4065,8 @@ PhysicalFontFace* WinFontFace::Clone() const if ( mpGraphiteData ) mpGraphiteData->AddReference(); #endif - if( mpHbFace ) - hb_face_reference( mpHbFace ); + if( mpHbFont ) + hb_font_reference( mpHbFont ); PhysicalFontFace* pClone = new WinFontFace( *this ); return pClone; commit fd55441e565e9da38b99a95252d49c0714616da6 Author: Akash Jain <akash...@gmail.com> Date: Wed Aug 17 21:31:22 2016 +0530 GSoC: Speed up CommonSalLayout by caching hb_face Cache hb_face so it is not created again and again. Switch from GDI to DirectWrite on Windows to obtain SFNT table data. Change-Id: I9c532cd72e1f6b57313f3b7d42a6b9b0633eb0ef diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 1fe3a6e..73f680b 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -44,6 +44,7 @@ class CommonSalLayout : public GenericSalLayout #ifdef _WIN32 HDC mhDC; HFONT mhFont; + D2DWriteTextOutRenderer* mpD2DRenderer; #elif defined(MACOSX) || defined(IOS) const CoreTextStyle& mrCoreTextStyle; #else @@ -53,7 +54,7 @@ class CommonSalLayout : public GenericSalLayout hb_font_t* GetHbFont(); public: #if defined(_WIN32) - explicit CommonSalLayout(HDC, WinFontInstance&); + explicit CommonSalLayout(WinSalGraphics*, WinFontInstance&, const WinFontFace&); void InitFont() const override; #elif defined(MACOSX) || defined(IOS) explicit CommonSalLayout(const CoreTextStyle&); @@ -63,7 +64,6 @@ public: const ServerFont& getFontData() const { return mrServerFont; }; #endif - ~CommonSalLayout(); void SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool); void AdjustLayout(ImplLayoutArgs&) override; bool LayoutText(ImplLayoutArgs&) override; diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 104699b..00b2d8e 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -45,6 +45,7 @@ #include "quartz/salgdicommon.hxx" #include <unordered_map> +#include <hb-ot.h> class AquaSalFrame; class FontAttributes; @@ -98,6 +99,8 @@ public: void GetFontMetric( ImplFontMetricDataRef& ) const; bool GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const; bool GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const; + hb_face_t* GetHbFace() const { return mpHbFace; } + void SetHbFace(hb_face_t* pHbFace) const { mpHbFace = pHbFace; } const CoreTextFontFace* mpFontData; /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0 @@ -109,6 +112,7 @@ public: private: /// CoreText text style object CFMutableDictionaryRef mpStyleDict; + mutable hb_face_t* mpHbFace; friend class CTLayout; friend class AquaSalGraphics; diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx index 944ffff..38967bf 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -35,6 +35,7 @@ #include <sallayout.hxx> #include "fontattributes.hxx" #include "impfontmetricdata.hxx" +#include "hb-ot.h" #include <unordered_map> @@ -181,6 +182,8 @@ public: sal_GlyphId FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const; bool GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const; bool GetAntialiasAdvice() const; + hb_face_t* GetHbFace() { return mpHbFace; } + void SetHbFace( hb_face_t* pHbFace ) { mpHbFace=pHbFace; } private: friend class GlyphCache; @@ -240,6 +243,7 @@ private: GlyphSubstitution maGlyphSubstitution; ServerFontLayoutEngine* mpLayoutEngine; + hb_face_t* mpHbFace; }; // a class for cache entries for physical font instances that are based on serverfonts diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index dba23bb..5301390 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -44,6 +44,9 @@ # include "postwin.h" #endif +#include <hb-ot.h> +#include <dwrite.h> + class FontSelectPattern; class WinFontInstance; class ImplFontAttrCache; @@ -139,10 +142,12 @@ private: mutable std::unordered_set<sal_UCS4> maGsubTable; mutable bool mbGsubRead; + mutable hb_face_t* mpHbFace; public: bool HasGSUBstitutions( HDC ) const; bool IsGSUBstituted( sal_UCS4 ) const; - static int GetTable( const char pTagName[5], const unsigned char*&, HDC ); + hb_face_t* GetHbFace() const { return mpHbFace; } + void SetHbFace( hb_face_t* pHbFace ) const { mpHbFace = pHbFace; } }; /** Class that creates (and destroys) a compatible Device Context. @@ -353,6 +358,7 @@ private: sal_uLong GetKernPairs(); public: + sal_uLong GetTable( const char pTagName[5], const unsigned char*&, void*&, IDWriteFontFace*& ); // public SalGraphics methods, the interface to the independent vcl part // get device resolution diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index 28be80b..f183c10 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -50,6 +50,7 @@ CoreTextStyle::CoreTextStyle( const FontSelectPattern& rFSD ) , mfFontRotation( 0.0 ) , maFontSelData( rFSD ) , mpStyleDict( nullptr ) + , mpHbFace( nullptr ) { const FontSelectPattern* const pReqFont = &rFSD; @@ -116,6 +117,8 @@ CoreTextStyle::~CoreTextStyle() { if( mpStyleDict ) CFRelease( mpStyleDict ); + if( mpHbFace ) + hb_face_destroy( mpHbFace ); } void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef& rxFontMetric ) const diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 89acdb7..2e012f3 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -26,6 +26,21 @@ #include <limits> #include <salgdi.hxx> +#if defined(_WIN32) +struct WinSalGraphicsWithIDFace +{ + WinSalGraphics* mpWSL; + IDWriteFontFace* mpIDFace; + void* mpTableContext; + + WinSalGraphicsWithIDFace( WinSalGraphics* pWSL, IDWriteFontFace* pIDFace ) + : mpWSL( pWSL ), + mpIDFace( pIDFace ), + mpTableContext( nullptr ) + {} +}; +#endif + static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) { char pTagName[5]; @@ -38,8 +53,8 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU sal_uLong nLength = 0; #if defined(_WIN32) const unsigned char* pBuffer = nullptr; - HDC* phDC = static_cast<HDC*>(pUserData); - nLength = WinFontFace::GetTable(pTagName, pBuffer, *phDC); + WinSalGraphicsWithIDFace* pWSLWithIDFace = static_cast<WinSalGraphicsWithIDFace*>(pUserData); + nLength = (pWSLWithIDFace->mpWSL)->GetTable(pTagName, pBuffer, pWSLWithIDFace->mpTableContext, pWSLWithIDFace->mpIDFace); #elif defined(MACOSX) || defined(IOS) unsigned char* pBuffer = nullptr; CoreTextFontFace* pFont = static_cast<CoreTextFontFace*>(pUserData); @@ -57,7 +72,15 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU hb_blob_t* pBlob = nullptr; if (pBuffer != nullptr) -#if defined(_WIN32) || defined(MACOSX) || defined(IOS) +#if defined(_WIN32) + pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, pWSLWithIDFace, + [](void* pUserData) + { + WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>(pUserData); + pUData->mpIDFace->ReleaseFontTable(pUData->mpTableContext); + } + ); +#elif defined(MACOSX) || defined(IOS) pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); }); #else @@ -77,13 +100,29 @@ static hb_unicode_funcs_t* getUnicodeFuncs() } #if defined(_WIN32) -CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance) -: mhDC(hDC), - mhFont((HFONT)GetCurrentObject(hDC, OBJ_FONT)), +CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace) +: mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)), + mhDC(WSL->getHDC()), mpHbFace(nullptr), - maFontSelData(rWinFontInstance.maFontSelData) + maFontSelData(rWinFontInstance.maFontSelData), + mpD2DRenderer(nullptr) { - mpHbFace = hb_face_create_for_tables(getFontTable, &hDC, nullptr); + mpHbFace = rWinFontFace.GetHbFace(); + if(!mpHbFace) + { + mpD2DRenderer = dynamic_cast<D2DWriteTextOutRenderer*>(&TextOutRenderer::get()); + WinSalGraphicsWithIDFace* pWSLWithIDFace = new WinSalGraphicsWithIDFace(WSL, mpD2DRenderer->GetDWriteFontFace(mhDC)); + mpHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace, + [](void* pUserData) + { + WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>( pUserData ); + if(pUData->mpIDFace) + pUData->mpIDFace->Release(); + delete pUData; + } + ); + rWinFontFace.SetHbFace(mpHbFace); + } } void CommonSalLayout::InitFont() const @@ -97,13 +136,18 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) maFontSelData(rCoreTextStyle.maFontSelData), mrCoreTextStyle(rCoreTextStyle) { - CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName)); - CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL); - if (pCGFont) - mpHbFace = hb_coretext_face_create(pCGFont); - else - mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); - CGFontRelease(pCGFont); + mpHbFace = rCoreTextStyle.GetHbFace(); + if(!mpHbFace) + { + CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName)); + CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL); + if (pCGFont) + mpHbFace = hb_coretext_face_create(pCGFont); + else + mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); + CGFontRelease(pCGFont); + rCoreTextStyle.SetHbFace(mpHbFace); + } } #else @@ -112,15 +156,15 @@ CommonSalLayout::CommonSalLayout(ServerFont& rServerFont) maFontSelData(rServerFont.GetFontSelData()), mrServerFont(rServerFont) { - mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); + mpHbFace = rServerFont.GetHbFace(); + if(!mpHbFace) + { + mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr); + mrServerFont.SetHbFace(mpHbFace); + } } #endif -CommonSalLayout::~CommonSalLayout() -{ - hb_face_destroy(mpHbFace); -} - hb_font_t* CommonSalLayout::GetHbFont() { // HACK. TODO: Get rid of HACK diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 55df59e..8cf7198 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -461,7 +461,8 @@ ServerFont::ServerFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI ) mbArtItalic( false ), mbArtBold( false ), mbUseGamma( false ), - mpLayoutEngine( nullptr ) + mpLayoutEngine( nullptr ), + mpHbFace( nullptr ) { // TODO: move update of mpFontInstance into FontEntry class when // it becomes responsible for the ServerFont instantiation @@ -610,6 +611,9 @@ ServerFont::~ServerFont() mpFontInfo->ReleaseFaceFT(); + if( mpHbFace ) + hb_face_destroy( mpHbFace ); + ReleaseFromGarbageCollect(); } diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index d86d881..3977cee 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -868,7 +868,8 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, mnPitchAndFamily( nPitchAndFamily ), mbAliasSymbolsHigh( false ), mbAliasSymbolsLow( false ), - mbGsubRead( false ) + mbGsubRead( false ), + mpHbFace( nullptr ) { SetBitmapSize( 0, nHeight ); @@ -909,6 +910,9 @@ WinFontFace::~WinFontFace() #endif #endif // ENABLE_GRAPHITE delete mpEncodingVector; + + if( mpHbFace ) + hb_face_destroy( mpHbFace ); } sal_IntPtr WinFontFace::GetFontId() const @@ -1061,16 +1065,22 @@ void WinFontFace::ReadCmapTable( HDC hDC ) const } } -int WinFontFace::GetTable(const char pTagName[5], const unsigned char*& pResBuffer, HDC hDC) +sal_uLong WinSalGraphics::GetTable( const char pTagName[5], const unsigned char*& pResBuffer, void*& pTableContext, IDWriteFontFace*& pIDFace ) { - const DWORD nTableTag = CalcTag( pTagName ); - RawFontData aRawFontData( hDC, nTableTag ); - - if( !aRawFontData.get() ) + if( !pIDFace ) return 0; - - pResBuffer = aRawFontData.steal(); - return aRawFontData.size(); + const void* pResBuf; + UINT32 nSize; + BOOL bExists; + HRESULT hr = S_OK; + const DWORD nTableTag = DWRITE_MAKE_OPENTYPE_TAG( pTagName[0], pTagName[1], pTagName[2], pTagName[3] ); + hr = pIDFace->TryGetFontTable( nTableTag, &pResBuf, &nSize, &pTableContext, &bExists ); + if( SUCCEEDED( hr ) && ( bExists ) ) + { + pResBuffer = static_cast<const unsigned char*>(pResBuf); + return static_cast<sal_uLong>(nSize); + } + return 0; } void WinFontFace::GetFontCapabilities( HDC hDC ) const diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 3740383..5e183fc 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -3518,6 +3518,24 @@ bool D2DWriteTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC, return (succeeded && nGlyphs >= 1 && pRectToErase); } +IDWriteFontFace* D2DWriteTextOutRenderer::GetDWriteFontFace(HDC hDC) const +{ + IDWriteFontFace* pFontFace; + bool succeeded = false; + try + { + succeeded = SUCCEEDED(mpGdiInterop->CreateFontFaceFromHdc(hDC, &pFontFace)); + } + catch (const std::exception& e) + { + SAL_WARN("vcl.gdi.opengl", "Error in dwrite while creating font face: " << e.what()); + return nullptr; + } + if(succeeded) + return pFontFace; + else return nullptr; +} + bool D2DWriteTextOutRenderer::BindFont(HDC hDC) { // A TextOutRender can only be bound to one font at a time, so the @@ -3884,7 +3902,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe if (getenv("SAL_USE_COMMON_LAYOUT")) { - return new CommonSalLayout(getHDC(), rFontInstance); + return new CommonSalLayout(this, rFontInstance, rFontFace); } else { @@ -4047,6 +4065,9 @@ PhysicalFontFace* WinFontFace::Clone() const if ( mpGraphiteData ) mpGraphiteData->AddReference(); #endif + if( mpHbFace ) + hb_face_reference( mpHbFace ); + PhysicalFontFace* pClone = new WinFontFace( *this ); return pClone; } commit e40b6926e7114bc3a960b271576517755ec899fd Author: Akash Jain <akash...@gmail.com> Date: Thu Aug 18 20:51:25 2016 +0530 GSoC: Move TextOutRenderer definition to winlayout.hxx Change-Id: I705f92d5ad55d7612c6413436c801de13f5352a6 diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 7f2f342..3221b4c 100755 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -417,4 +417,105 @@ public: #endif +class TextOutRenderer +{ +protected: + explicit TextOutRenderer() = default; + TextOutRenderer(const TextOutRenderer &) = delete; + TextOutRenderer & operator = (const TextOutRenderer &) = delete; + +public: + static TextOutRenderer & get(); + + virtual ~TextOutRenderer() = default; + + virtual bool operator ()(SalLayout const &rLayout, HDC hDC, + const Rectangle* pRectToErase, + Point* pPos, int* pGetNextGlypInfo) = 0; +}; + +class ExTextOutRenderer : public TextOutRenderer +{ + ExTextOutRenderer(const ExTextOutRenderer &) = delete; + ExTextOutRenderer & operator = (const ExTextOutRenderer &) = delete; + +public: + explicit ExTextOutRenderer() = default; + virtual ~ExTextOutRenderer() override = default; + + bool operator ()(SalLayout const &rLayout, HDC hDC, + const Rectangle* pRectToErase, + Point* pPos, int* pGetNextGlypInfo) override; +}; + +#if ENABLE_GRAPHITE_DWRITE + +class D2DWriteTextOutRenderer : public TextOutRenderer +{ + typedef HRESULT(WINAPI *pD2D1CreateFactory_t)(D2D1_FACTORY_TYPE, + REFIID, const D2D1_FACTORY_OPTIONS *, void **); + typedef HRESULT(WINAPI *pDWriteCreateFactory_t)(DWRITE_FACTORY_TYPE, + REFIID, IUnknown **); + + static HINSTANCE mmD2d1, mmDWrite; + static pD2D1CreateFactory_t D2D1CreateFactory; + static pDWriteCreateFactory_t DWriteCreateFactory; + +public: + static bool InitModules(); + + explicit D2DWriteTextOutRenderer(); + virtual ~D2DWriteTextOutRenderer() override; + + bool operator ()(SalLayout const &rLayout, HDC hDC, + const Rectangle* pRectToErase, + Point* pPos, int* pGetNextGlypInfo) override; + + inline bool BindDC(HDC hDC, Rectangle const & rRect = Rectangle(0, 0, 0, 0)) { + RECT const rc = { rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() }; + HRESULT ok= mpRT->BindDC(hDC, &rc); + return SUCCEEDED(ok); + } + + bool BindFont(HDC hDC) /*override*/; + bool ReleaseFont() /*override*/; + + std::vector<Rectangle> GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const /*override*/; + ID2D1RenderTarget * GetRenderTarget() const { return mpRT; } + IDWriteFontFace* GetDWriteFontFace(HDC) const; + IDWriteFontFace * GetFontFace() const { return mpFontFace; } + float GetEmHeight() const { return mlfEmHeight; } + + inline HRESULT CreateRenderTarget() { + if (mpRT) mpRT->Release(); mpRT = nullptr; + return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT); + } + + inline bool Ready() const { return mpGdiInterop && mpRT; } + +private: + static void CleanupModules(); + + // This is a singleton object disable copy ctor and assignemnt operator + D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete; + D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; + + bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; + bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const; + bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd, + float * pAdvances, Point * pOffsets) /*override*/; + + ID2D1Factory * mpD2DFactory; + IDWriteFactory * mpDWriteFactory; + IDWriteGdiInterop * mpGdiInterop; + ID2D1DCRenderTarget * mpRT; + const D2D1_RENDER_TARGET_PROPERTIES mRTProps; + + IDWriteFontFace * mpFontFace; + float mlfEmHeight; + HDC mhDC; +}; + +#endif + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 10af89e..3740383 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -17,8 +17,6 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include "win/winlayout.hxx" - #include "osl/module.h" #include "osl/file.h" @@ -56,104 +54,8 @@ std::unique_ptr<GlobalGlyphCache> GlyphCache::gGlobalGlyphCache(new GlobalGlyphCache); GLuint WinFontInstance::mnGLyphyProgram = 0; -class TextOutRenderer -{ -protected: - explicit TextOutRenderer() = default; - TextOutRenderer(const TextOutRenderer &) = delete; - TextOutRenderer & operator = (const TextOutRenderer &) = delete; - -public: - static TextOutRenderer & get(); - - virtual ~TextOutRenderer() = default; - - virtual bool operator ()(SalLayout const &rLayout, HDC hDC, - const Rectangle* pRectToErase, - Point* pPos, int* pGetNextGlypInfo) = 0; -}; - -class ExTextOutRenderer : public TextOutRenderer -{ - ExTextOutRenderer(const ExTextOutRenderer &) = delete; - ExTextOutRenderer & operator = (const ExTextOutRenderer &) = delete; - -public: - explicit ExTextOutRenderer() = default; - virtual ~ExTextOutRenderer() override = default; - - bool operator ()(SalLayout const &rLayout, HDC hDC, - const Rectangle* pRectToErase, - Point* pPos, int* pGetNextGlypInfo) override; -}; - #if ENABLE_GRAPHITE_DWRITE -class D2DWriteTextOutRenderer : public TextOutRenderer -{ - typedef HRESULT(WINAPI *pD2D1CreateFactory_t)(D2D1_FACTORY_TYPE, - REFIID, const D2D1_FACTORY_OPTIONS *, void **); - - typedef HRESULT(WINAPI *pDWriteCreateFactory_t)(DWRITE_FACTORY_TYPE, - REFIID, IUnknown **); - - static HINSTANCE mmD2d1, mmDWrite; - static pD2D1CreateFactory_t D2D1CreateFactory; - static pDWriteCreateFactory_t DWriteCreateFactory; - -public: - static bool InitModules(); - - explicit D2DWriteTextOutRenderer(); - virtual ~D2DWriteTextOutRenderer() override; - - bool operator ()(SalLayout const &rLayout, HDC hDC, - const Rectangle* pRectToErase, - Point* pPos, int* pGetNextGlypInfo) override; - - inline bool BindDC(HDC hDC, Rectangle const & rRect = Rectangle(0, 0, 0, 0)) { - RECT const rc = { rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() }; - return SUCCEEDED(mpRT->BindDC(hDC, &rc)); - } - - bool BindFont(HDC hDC) /*override*/; - bool ReleaseFont() /*override*/; - - std::vector<Rectangle> GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const /*override*/; - ID2D1RenderTarget * GetRenderTarget() const { return mpRT; } - IDWriteFontFace * GetFontFace() const { return mpFontFace; } - float GetEmHeight() const { return mlfEmHeight; } - - inline HRESULT CreateRenderTarget() { - if (mpRT) mpRT->Release(); mpRT = nullptr; - return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT); - } - - inline bool Ready() const { return mpGdiInterop && mpRT; } - -private: - static void CleanupModules(); - - // This is a singleton object disable copy ctor and assignemnt operator - D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete; - D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; - - bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; - bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const; - bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd, - float * pAdvances, Point * pOffsets) /*override*/; - - ID2D1Factory * mpD2DFactory; - IDWriteFactory * mpDWriteFactory; - IDWriteGdiInterop * mpGdiInterop; - ID2D1DCRenderTarget * mpRT; - const D2D1_RENDER_TARGET_PROPERTIES mRTProps; - - IDWriteFontFace * mpFontFace; - float mlfEmHeight; - HDC mhDC; -}; - inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth ) { maWidthMap[ nCharCode ] = nCharWidth; commit 7de392a375396ee82c9d9a99659a10410cb6d891 Author: Akash Jain <akash...@gmail.com> Date: Sat Jul 23 21:41:40 2016 +0530 GSoC: Add Graphite support for CommonSalLayout Enable Graphite font rendering in CommonSalLayout through Harfbuzz Change-Id: Ia6a00a1bb6ea1a7bd705ed91d4f4f6cb9803e062 diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 01f82db..46b9326 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -532,19 +532,23 @@ SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackL if( mpServerFont[ nFallbackLevel ] && !(rArgs.mnFlags & SalLayoutFlags::DisableGlyphProcessing) ) { -#if ENABLE_GRAPHITE - // Is this a Graphite font? - if (!bDisableGraphite_ && - GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel])) + if (getenv("SAL_USE_COMMON_LAYOUT")) { - pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]); + pLayout = new CommonSalLayout(*mpServerFont[nFallbackLevel]); } else -#endif - if (getenv("SAL_USE_COMMON_LAYOUT")) - pLayout = new CommonSalLayout(*mpServerFont[nFallbackLevel]); + { +#if ENABLE_GRAPHITE + // Is this a Graphite font? + if (!bDisableGraphite_ && + GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel])) + { + pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]); + } else - pLayout = new ServerFontLayout(*mpServerFont[nFallbackLevel]); +#endif + pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] ); + } } return pLayout; commit b0aaa26f09b4b77b39b20f34dd68feab28c29e48 Author: Akash Jain <akash...@gmail.com> Date: Sat Jul 23 21:21:46 2016 +0530 GSoC: Enable building Harfbuzz with Graphite Harfbuzz will now need to be built with Graphite support. This allows Harfbuzz to handle Graphite fonts. In case we all building with system Harfbuzz, then it should be built with Graphite support else we error out. Change-Id: I156ec08b9e5ad7ce87cc15e4b5852d9c57c98f7f diff --git a/configure.ac b/configure.ac index 6cc455a..5559e8b 100644 --- a/configure.ac +++ b/configure.ac @@ -9252,10 +9252,14 @@ if test $_os != Darwin -a $_os != Android -a $_os != iOS -a \( -z "$enable_graph AC_MSG_RESULT([yes]) ENABLE_GRAPHITE="TRUE" AC_DEFINE(ENABLE_GRAPHITE) - libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3]) + libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"]) if test "$with_system_graphite" = "yes"; then libo_MINGW_CHECK_DLL([libgraphite2]) fi + if test "$COM" = "MSC"; then # override the above + GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib" + fi + else AC_MSG_RESULT([no]) fi @@ -9348,6 +9352,16 @@ if test "$with_harfbuzz" = "yes" -o \( $_os != WINNT -a $_os != Darwin -a $_os ! if test "$COM" = "MSC"; then # override the above HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib" fi + if test "$with_system_harfbuzz" = "yes"; then + AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support]) + _save_libs="$LIBS" + _save_cflags="$CFLAGS" + LIBS="$LIBS $HARFBUZZ_LIBS" + CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" + AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])]) + LIBS="$_save_libs" + CFLAGS="$_save_cflags" + fi else AC_MSG_RESULT([no]) fi diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk index 1bee5bb..4412815 100644 --- a/external/harfbuzz/ExternalProject_harfbuzz.mk +++ b/external/harfbuzz/ExternalProject_harfbuzz.mk @@ -23,6 +23,8 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) : $(call gb_ExternalProject_run,build,\ $(if $(CROSS_COMPILING),ICU_CONFIG=$(SRCDIR)/external/icu/cross-bin/icu-config) \ $(if $(SYSTEM_ICU),,ICU_CONFIG=$(SRCDIR)/external/icu/cross-bin/icu-config) \ + GRAPHITE2_CFLAGS="$(GRAPHITE_CFLAGS)" \ + GRAPHITE2_LIBS="$(GRAPHITE_LIBS)" \ ./configure \ --enable-static \ --disable-shared \ @@ -33,6 +35,7 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) : --with-fontconfig=no \ --with-cairo=no \ --with-glib=no \ + --with-graphite2=yes \ $(if $(verbose),--disable-silent-rules,--enable-silent-rules) \ $(if $(CROSS_COMPILING),--build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM)) \ $(if $(filter LINUX,$(OS)),CXXFLAGS="$(CXXFLAGS) -fvisibility=hidden") \ commit 082181df7a0581486ce50958268629a60c90e619 Author: Akash Jain <akash...@gmail.com> Date: Wed Jul 20 23:51:56 2016 +0530 GSoC: Integrate new CommonSalLayout in quartz/ code Change-Id: I07a9c956f09be5d43ee58ff0784ba0f81f52cd9a diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 1145567..1fe3a6e 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -26,6 +26,7 @@ #elif defined(MACOSX) || defined(IOS) #include <com/sun/star/i18n/XBreakIterator.hpp> #include "quartz/ctfonts.hxx" +#include <hb-coretext.h> #else #include "unx/freetype_glyphcache.hxx" diff --git a/vcl/quartz/ctfonts.hxx b/vcl/inc/quartz/ctfonts.hxx similarity index 100% rename from vcl/quartz/ctfonts.hxx rename to vcl/inc/quartz/ctfonts.hxx diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index ba0200b..104699b 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -111,6 +111,8 @@ private: CFMutableDictionaryRef mpStyleDict; friend class CTLayout; + friend class AquaSalGraphics; + friend class CommonSalLayout; CFMutableDictionaryRef GetStyleDict( void ) const { return mpStyleDict; } }; diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index 36b155d..28be80b 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -25,7 +25,7 @@ #include <vcl/settings.hxx> -#include "ctfonts.hxx" +#include "quartz/ctfonts.hxx" #include "impfont.hxx" #ifdef MACOSX #include "osx/saldata.hxx" diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx index 35f7143..f7fe0af 100644 --- a/vcl/quartz/ctlayout.cxx +++ b/vcl/quartz/ctlayout.cxx @@ -25,9 +25,10 @@ #include <sal/types.h> #include <tools/debug.hxx> -#include "ctfonts.hxx" +#include "quartz/ctfonts.hxx" #include "CTRunData.hxx" #include "quartz/utils.h" +#include "CommonSalLayout.hxx" class CTLayout : public SalLayout @@ -781,7 +782,10 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {} SalLayout* CoreTextStyle::GetTextLayout() const { - return new CTLayout( this); + if (getenv("SAL_USE_COMMON_LAYOUT")) + return new CommonSalLayout(*this); + else + return new CTLayout(this); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index d0f73a8..bb99737 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -36,7 +36,7 @@ #include <vcl/svapp.hxx> #include <vcl/sysdata.hxx> -#include "ctfonts.hxx" +#include "quartz/ctfonts.hxx" #include "fontsubset.hxx" #include "impfont.hxx" #include "impfontcharmap.hxx" @@ -414,8 +414,39 @@ bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect return bRC; } -void AquaSalGraphics::DrawSalLayout( const CommonSalLayout& ) -{ +void AquaSalGraphics::DrawSalLayout(const CommonSalLayout& rLayout) +{ + CGContextRef context = mrContext; + SAL_INFO("vcl.ct", "CGContextSaveGState(" << context << ")"); + CGContextSaveGState(context); + SAL_INFO("vcl.ct", "CGContextScaleCTM(" << context << ",1.0,-1.0)"); + const CoreTextStyle& rCTStyle = rLayout.getFontData(); + + CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCTStyle.GetStyleDict(), kCTFontAttributeName)); + CGContextScaleCTM(context, 1.0, -1.0); + CGContextSetShouldAntialias(context, !mbNonAntialiasedText); + // rotate the matrix + const CGFloat fRadians = rCTStyle.mfFontRotation; + CGContextRotateCTM(context, +fRadians); + const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation(-fRadians); + CGContextSetFillColor(context, maTextColor.AsArray()); + + // draw the text + Point aPos; + sal_GlyphId aGlyphId; + std::vector<CGGlyph> aGlyphIds; + std::vector<CGPoint> aGlyphPos; + int nStart = 0; + for (; rLayout.GetNextGlyphs(1, &aGlyphId, aPos, nStart); ) + { + aGlyphIds.push_back(aGlyphId & GF_IDXMASK); + aGlyphPos.push_back(CGPointApplyAffineTransform(CGPointMake(aPos.X(), -1*aPos.Y()), aInvMatrix)); + } + CTFontDrawGlyphs(pFont, aGlyphIds.data(), aGlyphPos.data(), nStart, context); + + // restore the original graphic context transformations + SAL_INFO("vcl.ct", "CGContextRestoreGState(" << context << ")"); + CGContextRestoreGState(context); } void AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ ) diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 485dcef..89acdb7 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -57,7 +57,7 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU hb_blob_t* pBlob = nullptr; if (pBuffer != nullptr) -#if defined(_WIN32) +#if defined(_WIN32) || defined(MACOSX) || defined(IOS) pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); }); #else @@ -97,7 +97,13 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) maFontSelData(rCoreTextStyle.maFontSelData), mrCoreTextStyle(rCoreTextStyle) { - mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); + CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName)); + CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL); + if (pCGFont) + mpHbFace = hb_coretext_face_create(pCGFont); + else + mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr); + CGFontRelease(pCGFont); } #else commit 813cbeabd0c04b784d90f94257ee7ab8158567c5 Author: Akash Jain <akash...@gmail.com> Date: Wed Jul 6 17:56:15 2016 +0530 GSoC: Integrate new CommonSalLayout in win/ code Change-Id: Ifeb2fa7ca9e2cd0da1c504d4e770aa0bb1b0b0de diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index c096f62..485dcef 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -57,7 +57,12 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU hb_blob_t* pBlob = nullptr; if (pBuffer != nullptr) +#if defined(_WIN32) + pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, + const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); }); +#else pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr); +#endif return pBlob; } @@ -74,12 +79,18 @@ static hb_unicode_funcs_t* getUnicodeFuncs() #if defined(_WIN32) CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance) : mhDC(hDC), + mhFont((HFONT)GetCurrentObject(hDC, OBJ_FONT)), mpHbFace(nullptr), maFontSelData(rWinFontInstance.maFontSelData) { mpHbFace = hb_face_create_for_tables(getFontTable, &hDC, nullptr); } +void CommonSalLayout::InitFont() const +{ + SelectObject(mhDC, mhFont); +} + #elif defined(MACOSX) || defined(IOS) CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) : mpHbFace(nullptr), diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 0d77b61..d86d881 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -2453,7 +2453,4 @@ void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont, } } -void WinSalGraphics::DrawSalLayout( const CommonSalLayout& ) -{} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index cbf0b58..10af89e 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -34,6 +34,7 @@ #include "sft.hxx" #include "sallayout.hxx" +#include "CommonSalLayout.hxx" #include <cstdio> #include <cstdlib> @@ -67,7 +68,7 @@ public: virtual ~TextOutRenderer() = default; - virtual bool operator ()(WinLayout const &rLayout, HDC hDC, + virtual bool operator ()(SalLayout const &rLayout, HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) = 0; }; @@ -81,7 +82,7 @@ public: explicit ExTextOutRenderer() = default; virtual ~ExTextOutRenderer() override = default; - bool operator ()(WinLayout const &rLayout, HDC hDC, + bool operator ()(SalLayout const &rLayout, HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) override; }; @@ -106,7 +107,7 @@ public: explicit D2DWriteTextOutRenderer(); virtual ~D2DWriteTextOutRenderer() override; - bool operator ()(WinLayout const &rLayout, HDC hDC, + bool operator ()(SalLayout const &rLayout, HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) override; @@ -138,7 +139,7 @@ private: D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; - bool GetDWriteInkBox(IDWriteFontFace & rFontFace, WinLayout const &rLayout, float const lfEmHeight, Rectangle &) const; + bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const; bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd, float * pAdvances, Point * pOffsets) /*override*/; @@ -3485,7 +3486,7 @@ TextOutRenderer & TextOutRenderer::get() } -bool ExTextOutRenderer::operator ()(WinLayout const &rLayout, HDC hDC, +bool ExTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) { @@ -3544,7 +3545,7 @@ D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer() CleanupModules(); } -bool D2DWriteTextOutRenderer::operator ()(WinLayout const &rLayout, HDC hDC, +bool D2DWriteTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) { @@ -3784,7 +3785,7 @@ bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** p return succeeded; } -bool D2DWriteTextOutRenderer::GetDWriteInkBox(IDWriteFontFace & rFontFace, WinLayout const &rLayout, float const /*lfEmHeight*/, Rectangle & rOut) const +bool D2DWriteTextOutRenderer::GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const /*lfEmHeight*/, Rectangle & rOut) const { rOut.SetEmpty(); @@ -3979,66 +3980,73 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ]; WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ]; - bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter; - - if (!bUspInited) - InitUSP(); - - if( !(rArgs.mnFlags & SalLayoutFlags::ComplexDisabled) ) + if (getenv("SAL_USE_COMMON_LAYOUT")) { -#if ENABLE_GRAPHITE - if (rFontFace.SupportsGraphite()) - { - pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); - } - else -#endif // ENABLE_GRAPHITE - { - // script complexity is determined in upper layers - pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); - // NOTE: it must be guaranteed that the WinSalGraphics lives longer than - // the created UniscribeLayout, otherwise the data passed into the - // constructor might become invalid too early - } + return new CommonSalLayout(getHDC(), rFontInstance); } else { -#if ENABLE_GRAPHITE - if (rFontFace.SupportsGraphite()) - { - pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); - } - else -#endif // ENABLE_GRAPHITE - { - static bool bAvoidSimpleWinLayout = (std::getenv("VCL_NO_SIMPLEWINLAYOUT") != NULL); + bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter; - if (!bAvoidSimpleWinLayout) - { - if( (rArgs.mnFlags & SalLayoutFlags::KerningPairs) && !rFontInstance.HasKernData() ) - { - // TODO: directly cache kerning info in the rFontInstance - // TODO: get rid of kerning methods+data in WinSalGraphics object - GetKernPairs(); - rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs ); - } + if (!bUspInited) + InitUSP(); - pWinLayout = new SimpleWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); + if( !(rArgs.mnFlags & SalLayoutFlags::ComplexDisabled) ) + { +#if ENABLE_GRAPHITE + if (rFontFace.SupportsGraphite()) + { + pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); } else +#endif // ENABLE_GRAPHITE { + // script complexity is determined in upper layers pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL); // NOTE: it must be guaranteed that the WinSalGraphics lives longer than // the created UniscribeLayout, otherwise the data passed into the // constructor might become invalid too early } } - } + else + { +#if ENABLE_GRAPHITE + if (rFontFace.SupportsGraphite()) + { ... etc. - the rest is truncated
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits