[Libreoffice-commits] core.git: Branch 'feature/commonsallayout' - 7 commits - vcl/inc vcl/quartz vcl/source vcl/unx vcl/win
Khaled Hosny
khaledhosny at eglug.org
Sat Oct 15 00:45:16 UTC 2016
Rebased ref, commits from common ancestor:
commit c8e0298987f12f732c686f3ccd2ee4e342d8f89c
Author: Khaled Hosny <khaledhosny at 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 bb99737..caa7e35 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 || !xFCMap->GetCharCount(), "vcl", "no charmap" );
// get unicode<->glyph encoding
commit 6a9723c2aa90cd455c9f07adef6061caaff04ada
Author: Khaled Hosny <khaledhosny at eglug.org>
Date: Thu Oct 13 22:46:28 2016 +0200
Check SAL_USE_COMMON_LAYOUT envar in one place
Makes it easier to flip the switch in the future (or even do something
more fancy other than checking envvar).
Change-Id: Ie42ca012c167b2108f0fca1ce9ff7beee95f1be7
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 1050943..364bd48 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -201,6 +201,8 @@ public:
virtual std::shared_ptr<vcl::TextLayoutCache>
CreateTextLayoutCache(OUString const&) const;
+ static bool UseCommonLayout();
+
protected:
// used by layout engines
SalLayout();
diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx
index f7fe0af..856e066 100644
--- a/vcl/quartz/ctlayout.cxx
+++ b/vcl/quartz/ctlayout.cxx
@@ -782,7 +782,7 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {}
SalLayout* CoreTextStyle::GetTextLayout() const
{
- if (getenv("SAL_USE_COMMON_LAYOUT"))
+ if (SalLayout::UseCommonLayout())
return new CommonSalLayout(*this);
else
return new CTLayout(this);
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index ea16f4f..86b3ab1d 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -768,6 +768,12 @@ bool SalLayout::IsSpacingGlyph( sal_GlyphId nGlyph )
return bRet;
}
+bool SalLayout::UseCommonLayout()
+{
+ static bool bUse = getenv("SAL_USE_COMMON_LAYOUT") != nullptr;
+ return bUse;
+}
+
GenericSalLayout::GenericSalLayout()
{}
diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx
index 46b9326..35d086d 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -532,7 +532,7 @@ SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackL
if( mpServerFont[ nFallbackLevel ]
&& !(rArgs.mnFlags & SalLayoutFlags::DisableGlyphProcessing) )
{
- if (getenv("SAL_USE_COMMON_LAYOUT"))
+ if (SalLayout::UseCommonLayout())
{
pLayout = new CommonSalLayout(*mpServerFont[nFallbackLevel]);
}
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index de0b4bf..9681986 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -3900,7 +3900,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ];
WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
- if (getenv("SAL_USE_COMMON_LAYOUT"))
+ if (SalLayout::UseCommonLayout())
{
return new CommonSalLayout(this, rFontInstance, rFontFace);
}
commit d5282a6ebfd2c60288a5505f6dd4ecc098fa9a76
Author: Khaled Hosny <khaledhosny at 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 0f2ea62a1b3a26adf96be80064a143826a23cdb1
Author: Khaled Hosny <khaledhosny at 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 b351497f54cc2f106a48b3c40b41e6ea6b0835d8
Author: Khaled Hosny <khaledhosny at 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 730063001e6281a6879908cd3dd9c74d0a657484
Author: Khaled Hosny <khaledhosny at 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 0a203470270fd76a45733b694af1f97105a7ca1f
Author: Khaled Hosny <khaledhosny at 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
More information about the Libreoffice-commits
mailing list