Hi, I have submitted a patch for review:
https://gerrit.libreoffice.org/3518 To pull it, you can do: git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/18/3518/1 Add support for using HarfBuzz instead of ICU LE Change-Id: I07e698f7486379bae68329771695cd94d6e561b5 --- M vcl/generic/glyphs/gcach_layout.cxx 1 file changed, 178 insertions(+), 15 deletions(-) diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx index ddf6d7c..02392c2 100644 --- a/vcl/generic/glyphs/gcach_layout.cxx +++ b/vcl/generic/glyphs/gcach_layout.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <config_harfbuzz.h> #include <gcach_ftyp.hxx> #include <sallayout.hxx> #include <salgdi.hxx> @@ -30,10 +31,15 @@ #include <sal/alloca.h> #include <rtl/instance.hxx> +#if ENABLE_HARFBUZZ +#include <hb-ft.h> +#include <hb-icu.h> +#else #include <layout/LayoutEngine.h> #include <layout/LEFontInstance.h> #include <layout/LELanguages.h> #include <layout/LEScripts.h> +#endif // ENABLE_HARFBUZZ #include <unicode/uscript.h> #include <unicode/ubidi.h> @@ -86,6 +92,172 @@ } } +// ======================================================================= + +static bool lcl_CharIsJoiner(sal_Unicode cChar) +{ + return ((cChar == 0x200C) || (cChar == 0x200D)); +} + +static bool needPreviousCode(sal_Unicode cChar) +{ + return lcl_CharIsJoiner(cChar) || U16_IS_LEAD(cChar); +} + +static bool needNextCode(sal_Unicode cChar) +{ + return lcl_CharIsJoiner(cChar) || U16_IS_TRAIL(cChar); +} + +#if ENABLE_HARFBUZZ +class HbLayoutEngine : public ServerFontLayoutEngine +{ +private: + UScriptCode meScriptCode; + +public: + HbLayoutEngine(ServerFont&); + virtual ~HbLayoutEngine(){}; + + virtual bool layout(ServerFontLayout&, ImplLayoutArgs&); +}; + +HbLayoutEngine::HbLayoutEngine(ServerFont& /*rServerFont*/) +: meScriptCode(USCRIPT_INVALID_CODE) +{} + +bool HbLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs) +{ + ServerFont& rFont = rLayout.GetServerFont(); + FT_Face aFace = rFont.GetFtFace(); + + // allocate temporary arrays, note: round to even + int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1; + + rLayout.Reserve(nGlyphCapacity); + + Point aNewPos(0, 0); + while (true) + { + int nMinRunPos, nEndRunPos; + bool bRightToLeft; + if (!rArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRightToLeft)) + break; + + int nRunLen = nEndRunPos - nMinRunPos; + + // find matching script + // TODO: use ICU's UScriptRun API + UScriptCode eScriptCode = USCRIPT_INVALID_CODE; + for (int i = nMinRunPos; i < nEndRunPos; ++i) + { + UErrorCode rcI18n = U_ZERO_ERROR; + UScriptCode eNextScriptCode = uscript_getScript(rArgs.mpStr[i], &rcI18n); + if ((eNextScriptCode > USCRIPT_INHERITED)) + { + eScriptCode = eNextScriptCode; + if (eNextScriptCode != USCRIPT_LATIN) + break; + } + } + if (eScriptCode < 0) // TODO: handle errors better + eScriptCode = USCRIPT_LATIN; + + meScriptCode = eScriptCode; + + hb_font_t *aHbFont = hb_ft_font_create(aFace, NULL); + + LanguageTag aLangTag(rArgs.meLanguage); + OString sLanguage = OUStringToOString(aLangTag.getLanguage(), RTL_TEXTENCODING_UTF8); + + hb_buffer_t *aHbBuffer = hb_buffer_create(); + hb_buffer_set_direction(aHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); + hb_buffer_set_script(aHbBuffer, hb_icu_script_to_script(eScriptCode)); + hb_buffer_set_language(aHbBuffer, hb_language_from_string(sLanguage.getStr(), -1)); + hb_buffer_add_utf16(aHbBuffer, rArgs.mpStr, nRunLen, nMinRunPos, nRunLen); + hb_shape(aHbFont, aHbBuffer, NULL, 0); + + int nRunGlyphCount = hb_buffer_get_length(aHbBuffer); + hb_glyph_info_t *aHbGlyphInfos = hb_buffer_get_glyph_infos(aHbBuffer, NULL); + hb_glyph_position_t *aHbPositions = hb_buffer_get_glyph_positions(aHbBuffer, NULL); + + int32_t nLastCluster = -1; + for (int i = 0; i < nRunGlyphCount; ++i) { + int32_t nGlyphIndex = aHbGlyphInfos[i].codepoint; + int32_t nCluster = aHbGlyphInfos[i].cluster; + int32_t nCharPos = nCluster; + + // if needed request glyph fallback by updating LayoutArgs + if (!nGlyphIndex) + { + if (nCharPos >= 0) + { + rArgs.NeedFallback(nCharPos, bRightToLeft); + // XXX: do we need this in harfbuzz? + if ((nCharPos > 0) && needPreviousCode(rArgs.mpStr[nCharPos-1])) + rArgs.NeedFallback(nCharPos-1, bRightToLeft); + else if ((nCharPos + 1 < nEndRunPos) && needNextCode(rArgs.mpStr[nCharPos+1])) + rArgs.NeedFallback(nCharPos+1, bRightToLeft); + } + + if (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) + continue; + } + + const GlyphMetric& rGM = rFont.GetGlyphMetric(nGlyphIndex); + int nGlyphWidth = rGM.GetCharWidth(); + + long nGlyphFlags = 0; + if (bRightToLeft) + nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; + + // what is this for? + // XXX: rtl clusters + bool bInCluster = false; + if (nCluster == nLastCluster) + bInCluster = true; + nLastCluster = nCluster; + if (bInCluster) + nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; + + // XXX: query GDEF glyph class? Do we even need this? + if (aHbPositions[i].x_advance == 0) + nGlyphFlags |= GlyphItem::IS_DIACRITIC; + + aHbPositions[i].x_offset /= 64; + aHbPositions[i].y_offset /= 64; + aHbPositions[i].x_advance /= 64; + aHbPositions[i].y_advance /= 64; + + aNewPos = Point(aNewPos.X() + aHbPositions[i].x_offset, aNewPos.Y() - aHbPositions[i].y_offset); + + GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth); + + if (i + 1 < nRunGlyphCount) + aGI.mnNewWidth = nGlyphWidth + (aHbPositions[i + 1].x_offset / 64); + + rLayout.AppendGlyph(aGI); + + aNewPos.X() += aHbPositions[i].x_advance; + aNewPos.Y() += aHbPositions[i].y_advance; + } + + hb_buffer_destroy(aHbBuffer); + hb_font_destroy(aHbFont); + } + + // sort glyphs in visual order + // and then in logical order (e.g. diacritics after cluster start) + rLayout.SortGlyphItems(); + + // determine need for kashida justification + if((rArgs.mpDXArray || rArgs.mnLayoutWidth) + && ((meScriptCode == USCRIPT_ARABIC) || (meScriptCode == USCRIPT_SYRIAC))) + rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON; + + return true; +} +#else // ======================================================================= // bridge to ICU LayoutEngine // ======================================================================= @@ -301,21 +473,6 @@ } // ----------------------------------------------------------------------- - -static bool lcl_CharIsJoiner(sal_Unicode cChar) -{ - return ((cChar == 0x200C) || (cChar == 0x200D)); -} - -static bool needPreviousCode(sal_Unicode cChar) -{ - return lcl_CharIsJoiner(cChar) || U16_IS_LEAD(cChar); -} - -static bool needNextCode(sal_Unicode cChar) -{ - return lcl_CharIsJoiner(cChar) || U16_IS_TRAIL(cChar); -} namespace { @@ -742,6 +899,7 @@ #ifdef ARABIC_BANDAID aGI.mnNewWidth = nNewWidth; #endif + rLayout.AppendGlyph( aGI ); ++nFilteredRunGlyphCount; nLastCharPos = nCharPos; @@ -762,6 +920,7 @@ return true; } +#endif // ENABLE_HARFBUZZ // ======================================================================= @@ -769,7 +928,11 @@ { // find best layout engine for font, platform, script and language if (!mpLayoutEngine) +#if ENABLE_HARFBUZZ + mpLayoutEngine = new HbLayoutEngine(*this); +#else mpLayoutEngine = new IcuLayoutEngine(*this); +#endif // ENABLE_HARFBUZZ return mpLayoutEngine; } -- To view, visit https://gerrit.libreoffice.org/3518 To unsubscribe, visit https://gerrit.libreoffice.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I07e698f7486379bae68329771695cd94d6e561b5 Gerrit-PatchSet: 1 Gerrit-Project: core Gerrit-Branch: master Gerrit-Owner: Khaled Hosny <khaledho...@eglug.org> _______________________________________________ LibreOffice mailing list LibreOffice@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice