Rebased ref, commits from common ancestor: commit 23c9ccfd1b6fc5cdee4913e96cd02e04c68459fe Author: Khaled Hosny <khaledho...@eglug.org> Date: Sat Oct 15 06:11:26 2016 -0700
Rewrite AquaSalGraphics::DrawSalLayout() Slightly cleaner code and now handles glyph rotation for vertical text. Change-Id: I98cc8fd7df5e73068294e4d7dd6b38a71dcbdcc7 diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index 787ddbf..28e7e99 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -485,37 +485,78 @@ bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect 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 + const CoreTextStyle& rStyle = rLayout.getFontData(); + const FontSelectPattern& rFontSelect = rStyle.maFontSelData; + if (rFontSelect.mnHeight == 0) + return; + + CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName)); + Point aPos; sal_GlyphId aGlyphId; std::vector<CGGlyph> aGlyphIds; std::vector<CGPoint> aGlyphPos; + std::vector<bool> aGlyphRotation; int nStart = 0; - for (; rLayout.GetNextGlyphs(1, &aGlyphId, aPos, nStart); ) + while (rLayout.GetNextGlyphs(1, &aGlyphId, aPos, nStart)) { + CGAffineTransform aMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation); + bool nGlyphRotation = false; + if ((aGlyphId & GF_ROTMASK) == GF_ROTL) + { + nGlyphRotation = true; + double nYdiff = CTFontGetAscent(pFont) - CTFontGetDescent(pFont); + aMatrix = CGAffineTransformTranslate(aMatrix, 0, -nYdiff); + } + aGlyphIds.push_back(aGlyphId & GF_IDXMASK); - aGlyphPos.push_back(CGPointApplyAffineTransform(CGPointMake(aPos.X(), -1*aPos.Y()), aInvMatrix)); + aGlyphPos.push_back(CGPointApplyAffineTransform(CGPointMake(aPos.X(), -aPos.Y()), aMatrix)); + aGlyphRotation.push_back(nGlyphRotation); + } + + if (aGlyphIds.empty()) + return; + + CGContextSaveGState(mrContext); + + CTFontRef pRotatedFont = nullptr; + if (rStyle.mfFontRotation) + { + CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFont); + CGFloat nSize = CTFontGetSize(pFont); + CGAffineTransform aMatrix = CTFontGetMatrix(pFont); + aMatrix = CGAffineTransformRotate(aMatrix, -rStyle.mfFontRotation); + pRotatedFont = CTFontCreateWithFontDescriptor(pDesc, nSize, &aMatrix); + CFRelease(pDesc); + } + + CGContextScaleCTM(mrContext, 1.0, -1.0); + CGContextRotateCTM(mrContext, rStyle.mfFontRotation); + CGContextSetShouldAntialias(mrContext, !mbNonAntialiasedText); + CGContextSetFillColor(mrContext, maTextColor.AsArray()); + + std::vector<bool>::const_iterator aStart = aGlyphRotation.begin(); + std::vector<bool>::const_iterator aEnd = aGlyphRotation.end(); + std::vector<bool>::const_iterator aI = aStart; + while (aI != aEnd) + { + bool nGlyphRotation = *aI; + std::vector<bool>::const_iterator aNext = std::find(aI + 1, aEnd, !nGlyphRotation); + + size_t nStartIndex = std::distance(aStart, aI); + size_t nLen = std::distance(aI, aNext); + + if (nGlyphRotation && pRotatedFont) + CTFontDrawGlyphs(pRotatedFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, mrContext); + else + CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, mrContext); + + aI = aNext; } - CTFontDrawGlyphs(pFont, aGlyphIds.data(), aGlyphPos.data(), nStart, context); - // restore the original graphic context transformations - SAL_INFO("vcl.ct", "CGContextRestoreGState(" << context << ")"); - CGContextRestoreGState(context); + if (pRotatedFont) + CFRelease(pRotatedFont); + CGContextRestoreGState(mrContext); } void AquaSalGraphics::SetFont(FontSelectPattern* pReqFont, int nFallbackLevel) commit 3c7f4735cd1c1e5d9f594699447bbf0eabe8e2f3 Author: Khaled Hosny <khaledho...@eglug.org> Date: Mon Sep 26 19:09:52 2016 +0200 Support vertical text in CommonSalLayout Change-Id: I52a71c9c21ad75c7cb9c8574e5e7e3b7c1c0c0c3 diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index feb37eb..7ee034a 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -212,12 +212,12 @@ struct HbScriptRun { int32_t mnMin; int32_t mnEnd; - hb_script_t maScript; + UScriptCode maScript; HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript) : mnMin(nMin) , mnEnd(nEnd) - , maScript(hb_icu_script_to_script(aScript)) + , maScript(aScript) {} }; @@ -307,6 +307,47 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const rSalGraphics.DrawSalLayout( *this ); } +/* https://drafts.csswg.org/css-writing-modes-3/#script-orientations */ +static int GetVerticalFlagsForScript(UScriptCode aScript) +{ + int nFlag = GF_NONE; + + switch (aScript) + { + /* ttb 0° */ + case USCRIPT_BOPOMOFO: + case USCRIPT_EGYPTIAN_HIEROGLYPHS: + case USCRIPT_HAN: + case USCRIPT_HANGUL: + case USCRIPT_HIRAGANA: + case USCRIPT_KATAKANA: + case USCRIPT_MEROITIC_CURSIVE: + case USCRIPT_MEROITIC_HIEROGLYPHS: + case USCRIPT_YI: + nFlag = GF_ROTL; + break; +#if 0 + /* ttb 90° */ + case USCRIPT_MONGOLIAN: + case USCRIPT_PHAGS_PA: + nFlag = ??; + break; + /* ttb -90° */ + case USCRIPT_ORKHON: + nFlag = ??; + break; + /* btt -90° */ + case USCRIPT_MONGOLIAN: + nFlag = ??; + break; +#endif + default: + break; + } + + return nFlag; +} + bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) { hb_script_t aHbScript = HB_SCRIPT_INVALID; @@ -371,11 +412,19 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) int nMinRunPos = aScriptRun.mnMin; int nEndRunPos = aScriptRun.mnEnd; int nRunLen = nEndRunPos - nMinRunPos; - aHbScript = aScriptRun.maScript; + aHbScript = hb_icu_script_to_script(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); + bool bVertical = false; + if ((rArgs.mnFlags & SalLayoutFlags::Vertical) && + GetVerticalFlagsForScript(aScriptRun.maScript) == GF_ROTL) + { + bVertical = true; + } + int nHbFlags = HB_BUFFER_FLAGS_DEFAULT; if (nMinRunPos == 0) nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */ @@ -387,7 +436,10 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs(); hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); #endif - hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); + if (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); @@ -452,17 +504,35 @@ 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 nAdvance, nXOffset, nYOffset; + if (bVertical) + { + int nVertFlag; +#if 0 /* XXX: does not work as expected for Common script */ + UErrorCode error = U_ZERO_ERROR; + nVertFlag = GetVerticalFlagsForScript(uscript_getScript(aChar, &error)); +#else + nVertFlag = GetVerticalFlags(aChar); + if (nVertFlag == GF_ROTR) + nVertFlag = GF_ROTL; +#endif + nGlyphIndex |= nVertFlag; + nAdvance = -pHbPositions[i].y_advance >> 6; + nXOffset = pHbPositions[i].y_offset >> 6; + nYOffset = -pHbPositions[i].x_offset >> 6; + } + else + { + nAdvance = pHbPositions[i].x_advance >> 6; + nXOffset = pHbPositions[i].x_offset >> 6; + nYOffset = pHbPositions[i].y_offset >> 6; + } Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset)); - const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset); + const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nAdvance, nXOffset); AppendGlyph(aGI); - aCurrPos.X() += nXAdvance; - aCurrPos.Y() += nYAdvance; + aCurrPos.X() += nAdvance; } hb_buffer_destroy(pHbBuffer); diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 35d086d..9fe2ea5 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -323,6 +323,11 @@ void CairoTextRender::DrawServerFontLayout( const GenericSalLayout& rLayout, con { ydiff = font_extents.ascent/nHeight; xdiff = -font_extents.descent/nHeight; + if (SalLayout::UseCommonLayout()) + { + ydiff -= font_extents.descent/nHeight; + xdiff = 0; + } } else if (nGlyphRotation == -1) { commit ac3df4c384e1641c4a41c42d602ab38ec8db528b Author: Khaled Hosny <khaledho...@eglug.org> Date: Fri Oct 14 02:50:27 2016 -0700 Support font fallback on macOS for CommonSalLayout Change-Id: Ifd26b7f14ed77a3aa2a38e5961cac5f9bbb6d796 diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index f7e5156..6958541 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -102,6 +102,8 @@ public: hb_font_t* GetHbFont() const { return mpHbFont; } void SetHbFont(hb_font_t* pHbFont) const { mpHbFont = pHbFont; } + CFMutableDictionaryRef GetStyleDict( void ) const { return mpStyleDict; } + const CoreTextFontFace* mpFontData; /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0 float mfFontStretch; @@ -113,11 +115,6 @@ private: /// CoreText text style object CFMutableDictionaryRef mpStyleDict; mutable hb_font_t* mpHbFont; - - friend class CTLayout; - friend class AquaSalGraphics; - friend class CommonSalLayout; - CFMutableDictionaryRef GetStyleDict( void ) const { return mpStyleDict; } }; // TODO: move into cross-platform headers @@ -172,8 +169,8 @@ protected: RGBAColor maFillColor; // Device Font settings - const CoreTextFontFace* mpFontData; - CoreTextStyle* mpTextStyle; + const CoreTextFontFace* mpFontData[MAX_FALLBACK]; + CoreTextStyle* mpTextStyle[MAX_FALLBACK]; RGBAColor maTextColor; /// allows text to be rendered without antialiasing bool mbNonAntialiasedText; diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx index 856e066..983f50b 100644 --- a/vcl/quartz/ctlayout.cxx +++ b/vcl/quartz/ctlayout.cxx @@ -28,7 +28,6 @@ #include "quartz/ctfonts.hxx" #include "CTRunData.hxx" #include "quartz/utils.h" -#include "CommonSalLayout.hxx" class CTLayout : public SalLayout @@ -782,10 +781,7 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {} SalLayout* CoreTextStyle::GetTextLayout() const { - if (SalLayout::UseCommonLayout()) - return new CommonSalLayout(*this); - else - return new CTLayout(this); + return new CTLayout(this); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index f9e3e0c..787ddbf 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -42,6 +42,8 @@ #include "impfontcharmap.hxx" #include "impfontmetricdata.hxx" #include "CommonSalLayout.hxx" +#include "outdev.h" +#include "PhysicalFontCollection.hxx" #ifdef MACOSX #include "osx/salframe.h" @@ -55,6 +57,49 @@ using namespace vcl; +class CoreTextGlyphFallbackSubstititution +: public ImplGlyphFallbackFontSubstitution +{ +public: + bool FindFontSubstitute(FontSelectPattern&, OUString&) const override; +}; + +bool CoreTextGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern& rPattern, + OUString& rMissingChars) const +{ + bool bFound = false; + CoreTextStyle rStyle(rPattern); + CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName)); + CFStringRef pStr = CreateCFString(rMissingChars); + if (pStr) + { + CTFontRef pFallback = CTFontCreateForString(pFont, pStr, CFRangeMake(0, CFStringGetLength(pStr))); + if (pFallback) + { + bFound = true; + + CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFallback); + FontAttributes rAttr = DevFontFromCTFontDescriptor(pDesc, nullptr); + + rPattern.maSearchName = rAttr.GetFamilyName(); + + rPattern.SetWeight(rAttr.GetWeight()); + rPattern.SetItalic(rAttr.GetItalic()); + rPattern.SetPitch(rAttr.GetPitch()); + rPattern.SetWidthType(rAttr.GetWidthType()); + + SalData* pSalData = GetSalData(); + if (pSalData->mpFontList) + rPattern.mpFontData = pSalData->mpFontList->GetFontDataFromId(reinterpret_cast<sal_IntPtr>(pDesc)); + + CFRelease(pFallback); + } + CFRelease(pStr); + } + + return bFound; +} + CoreTextFontFace::CoreTextFontFace( const CoreTextFontFace& rSrc ) : PhysicalFontFace( rSrc ) , mnFontId( rSrc.mnFontId ) @@ -245,8 +290,6 @@ AquaSalGraphics::AquaSalGraphics() , mxClipPath( nullptr ) , maLineColor( COL_WHITE ) , maFillColor( COL_BLACK ) - , mpFontData( nullptr ) - , mpTextStyle( nullptr ) , maTextColor( COL_BLACK ) , mbNonAntialiasedText( false ) , mbPrinter( false ) @@ -258,6 +301,12 @@ AquaSalGraphics::AquaSalGraphics() #endif { SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this ); + + for (int i = 0; i < MAX_FALLBACK; ++i) + { + mpTextStyle[i] = nullptr; + mpFontData[i] = nullptr; + } } AquaSalGraphics::~AquaSalGraphics() @@ -270,7 +319,8 @@ AquaSalGraphics::~AquaSalGraphics() CGPathRelease( mxClipPath ); } - delete mpTextStyle; + for (int i = 0; i < MAX_FALLBACK; ++i) + delete mpTextStyle[i]; if( mpXorEmulation ) delete mpXorEmulation; @@ -308,9 +358,12 @@ void AquaSalGraphics::SetTextColor( SalColor nSalColor ) // SAL_ DEBUG(std::hex << nSalColor << std::dec << "={" << maTextColor.GetRed() << ", " << maTextColor.GetGreen() << ", " << maTextColor.GetBlue() << ", " << maTextColor.GetAlpha() << "}"); } -void AquaSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int /*nFallbackLevel*/ ) +void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel) { - mpTextStyle->GetFontMetric( rxFontMetric ); + if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel]) + { + mpTextStyle[nFallbackLevel]->GetFontMetric(rxFontMetric); + } } static bool AddTempDevFont(const OUString& rFontFileURL) @@ -387,6 +440,12 @@ void AquaSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) // Copy all PhysicalFontFace objects contained in the SystemFontList pSalData->mpFontList->AnnounceFonts( *pFontCollection ); + + if (SalLayout::UseCommonLayout()) + { + static CoreTextGlyphFallbackSubstititution aSubstFallback; + pFontCollection->SetFallbackHook(&aSubstFallback); + } } void AquaSalGraphics::ClearDevFontCache() @@ -404,14 +463,24 @@ bool AquaSalGraphics::AddTempDevFont( PhysicalFontCollection*, bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rPolyPoly ) { - const bool bRC = mpTextStyle->GetGlyphOutline( aGlyphId, rPolyPoly ); - return bRC; + const int nFallbackLevel = aGlyphId >> GF_FONTSHIFT; + if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel]) + { + const bool bRC = mpTextStyle[nFallbackLevel]->GetGlyphOutline(aGlyphId, rPolyPoly); + return bRC; + } + return false; } bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) { - const bool bRC = mpTextStyle->GetGlyphBoundRect( aGlyphId, rRect ); - return bRC; + const int nFallbackLevel = aGlyphId >> GF_FONTSHIFT; + if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel]) + { + const bool bRC = mpTextStyle[nFallbackLevel]->GetGlyphBoundRect(aGlyphId, rRect); + return bRC; + } + return false; } void AquaSalGraphics::DrawSalLayout(const CommonSalLayout& rLayout) @@ -449,60 +518,71 @@ void AquaSalGraphics::DrawSalLayout(const CommonSalLayout& rLayout) CGContextRestoreGState(context); } -void AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ ) +void AquaSalGraphics::SetFont(FontSelectPattern* pReqFont, int nFallbackLevel) { // release the text style - delete mpTextStyle; - mpTextStyle = nullptr; + for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i) + { + delete mpTextStyle[i]; + mpTextStyle[i] = nullptr; + } // handle NULL request meaning: release-font-resources request if( !pReqFont ) { - mpFontData = nullptr; + mpFontData[nFallbackLevel] = nullptr; return; } // update the text style - mpFontData = static_cast<const CoreTextFontFace*>( pReqFont->mpFontData ); - mpTextStyle = new CoreTextStyle( *pReqFont ); + mpFontData[nFallbackLevel] = static_cast<const CoreTextFontFace*>(pReqFont->mpFontData); + mpTextStyle[nFallbackLevel] = new CoreTextStyle(*pReqFont); SAL_INFO("vcl.ct", "SetFont" - " to " << mpFontData->GetFamilyName() - << ", " << mpFontData->GetStyleName() - << " fontid=" << mpFontData->GetFontId() + " to " << mpFontData[nFallbackLevel]->GetFamilyName() + << ", " << mpFontData[nFallbackLevel]->GetStyleName() + << " fontid=" << mpFontData[nFallbackLevel]->GetFontId() << " for " << pReqFont->GetFamilyName() << ", " << pReqFont->GetStyleName() << " weight=" << pReqFont->GetWeight() << " slant=" << pReqFont->GetItalic() << " size=" << pReqFont->mnHeight << "x" << pReqFont->mnWidth << " orientation=" << pReqFont->mnOrientation + << " fallback level " << nFallbackLevel ); } -SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int /*nFallbackLevel*/ ) +SalLayout* AquaSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int nFallbackLevel) { - SalLayout* pSalLayout = mpTextStyle->GetTextLayout(); + SalLayout* pSalLayout = nullptr; + if (mpTextStyle[nFallbackLevel]) + { + if (SalLayout::UseCommonLayout()) + pSalLayout = new CommonSalLayout(*mpTextStyle[nFallbackLevel]); + else + pSalLayout = mpTextStyle[nFallbackLevel]->GetTextLayout(); + } return pSalLayout; } const FontCharMapRef AquaSalGraphics::GetFontCharMap() const { - if( !mpFontData ) + if (!mpFontData[0]) { FontCharMapRef xFontCharMap( new FontCharMap() ); return xFontCharMap; } - return mpFontData->GetFontCharMap(); + return mpFontData[0]->GetFontCharMap(); } bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const { - if( !mpFontData ) + if (!mpFontData[0]) return false; - return mpFontData->GetFontCapabilities(rFontCapabilities); + return mpFontData[0]->GetFontCapabilities(rFontCapabilities); } // fake a SFNT font directory entry for a font table @@ -772,7 +852,8 @@ void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bV free( const_cast<TTSimpleGlyphMetrics *>(pGlyphMetrics) ); } - FontCharMapRef xFCMap = mpFontData->GetFontCharMap(); + CoreTextFontFace rCTFontData(*pFontData, pFontData->GetFontId()); + FontCharMapRef xFCMap = rCTFontData.GetFontCharMap(); SAL_WARN_IF( !xFCMap.Is() || !xFCMap->GetCharCount(), "vcl", "no charmap" ); // get unicode<->glyph encoding commit ba95ee638e3363f5ce401dbaf29de4ef93a5e868 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 8aaefbf..b865ff9 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 b036307..9b78a72 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -3826,7 +3826,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 b9962f2ad547d842486849d5c7a2c2bca2b12986 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 47d24ee..feb37eb 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) @@ -382,8 +383,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 hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR); @@ -439,7 +440,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 @@ -561,8 +562,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 1689a2f7b833e9287aab8fe3edd1035fea641168 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 3212994..47d24ee 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -588,3 +588,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 b42220770365812d8040790cc5a0a091cbd866e6 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 d19506f..3212994 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 @@ -522,6 +513,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()) @@ -529,16 +530,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 1c52e56500c2c292b15ee2265d23562c9e999a2b 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 03e6818..d19506f 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); @@ -406,13 +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 - 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); @@ -445,6 +438,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 4d3ebeba5270cb23ac19882ce34eebd11c1976c8 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 d19506f..03e6818 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); @@ -405,7 +406,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); @@ -438,7 +445,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 6477c8799c7738018ea65d8af738f2e5083ab127 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 80753e7638db5f160b23d1f73926cd75574716d2 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 c8a8cbf185f873138a8d6d2f32da43eca7fd7e8d 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 18763fce5cdd1f18a2bf1841fdf28d5ef6b5b7df 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 27585c18b5b7980dad24e3b9c9840e8dcbf4ae62 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 ea1439a864672683ea272e2af9e49b45c3503955 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 8cb25a7..c8fe67b 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 b59739659e61dc4787b39692b344e96e012fbda1 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 459966b..8cb25a7 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 c66bbe0c7b6e9b8abadc3fc3c66115f6345e609f 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 33deea24c0931a1123ceb0b2a22143fb21b48701 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 903a784e2b88e30dbad4df8102593b3d14706cee 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 ad93410..473d756 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 cf919c0..84952bb 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 a832b45..44580ff 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -866,7 +866,7 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, mbAliasSymbolsHigh( false ), mbAliasSymbolsLow( false ), mbGsubRead( false ), - mpHbFace( nullptr ) + mpHbFont( nullptr ) { SetBitmapSize( 0, nHeight ); @@ -908,8 +908,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 fe724e4..b036307 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -3991,8 +3991,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 6f6bc939810f616b3c4d326ea09805b76aa65139 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 c4fb26d..ad93410 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/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index fd69ee0..1f04251 100755 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -482,6 +482,7 @@ public: 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; } 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 bc46feb..cf919c0 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 6d4fd5e..a832b45 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -865,7 +865,8 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, mnPitchAndFamily( nPitchAndFamily ), mbAliasSymbolsHigh( false ), mbAliasSymbolsLow( false ), - mbGsubRead( false ) + mbGsubRead( false ), + mpHbFace( nullptr ) { SetBitmapSize( 0, nHeight ); @@ -906,6 +907,9 @@ WinFontFace::~WinFontFace() #endif #endif // ENABLE_GRAPHITE delete mpEncodingVector; + + if( mpHbFace ) + hb_face_destroy( mpHbFace ); } sal_IntPtr WinFontFace::GetFontId() const @@ -1058,16 +1062,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 051f354..fe724e4 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 @@ -3810,7 +3828,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 { @@ -3973,6 +3991,9 @@ PhysicalFontFace* WinFontFace::Clone() const if ( mpGraphiteData ) mpGraphiteData->AddReference(); #endif + if( mpHbFace ) + hb_face_reference( mpHbFace ); + PhysicalFontFace* pClone = new WinFontFace( *this ); return pClone; } commit c899bbf97368bb47260b4b93d29feccbc863cdfb 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 1c706d4..fd69ee0 100755 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -417,4 +417,102 @@ 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() }; + 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; + + 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 fc1dd9d..051f354 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,102 +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; - - 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 ) { ... etc. - the rest is truncated
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits