tdf#103403: Wrong glyph advances with Graphite
Always create HarfBuzz font at the UPEM size and scale HarfBuzz output with the desired size instead. This theoretically means we loss any size-specific adjustments in the font but in practice very few fonts do this and in general modern APIs prefer stable glyph positioning across font sizes. Change-Id: Idf396eec5e241cc5fb9d0db698f2c081b7de29e3
This commit is contained in:
@@ -55,7 +55,7 @@ class CommonSalLayout : public GenericSalLayout
|
|||||||
OString msLanguage;
|
OString msLanguage;
|
||||||
std::vector<hb_feature_t> maFeatures;
|
std::vector<hb_feature_t> maFeatures;
|
||||||
|
|
||||||
hb_font_t* getHbFont();
|
void getScale(double* nXScale, double* nYScale);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
@@ -80,31 +80,28 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
|
|||||||
static hb_font_t* createHbFont(hb_face_t* pHbFace)
|
static hb_font_t* createHbFont(hb_face_t* pHbFace)
|
||||||
{
|
{
|
||||||
hb_font_t* pHbFont = hb_font_create(pHbFace);
|
hb_font_t* pHbFont = hb_font_create(pHbFace);
|
||||||
|
unsigned int nUPEM = hb_face_get_upem(pHbFace);
|
||||||
|
hb_font_set_scale(pHbFont, nUPEM, nUPEM);
|
||||||
hb_ot_font_set_funcs(pHbFont);
|
hb_ot_font_set_funcs(pHbFont);
|
||||||
|
|
||||||
|
hb_face_destroy(pHbFace);
|
||||||
|
|
||||||
return pHbFont;
|
return pHbFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We cache and re-use the HarfBuzz font for different layout instances, so we
|
void CommonSalLayout::getScale(double* nXScale, double* nYScale)
|
||||||
// need sure to set the correct scale (font size) before using the font.
|
|
||||||
hb_font_t* CommonSalLayout::getHbFont()
|
|
||||||
{
|
{
|
||||||
unsigned int nXScale = mrFontSelData.mnWidth << 6;
|
hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
|
||||||
unsigned int nYScale = mrFontSelData.mnHeight << 6;
|
unsigned int nUPEM = hb_face_get_upem(pHbFace);
|
||||||
|
|
||||||
|
double nHeight(mrFontSelData.mnHeight);
|
||||||
|
double nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth : nHeight);
|
||||||
|
|
||||||
|
if (nYScale)
|
||||||
|
*nYScale = nHeight / nUPEM;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
// HACK to get stretched/shrunken text. TODO: Get rid of HACK
|
|
||||||
if (nXScale)
|
if (nXScale)
|
||||||
nXScale = double(nXScale) * 1.812;
|
*nXScale = nWidth / nUPEM;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!nXScale)
|
|
||||||
nXScale = nYScale;
|
|
||||||
|
|
||||||
hb_font_set_ppem(mpHbFont, nXScale, nYScale);
|
|
||||||
hb_font_set_scale(mpHbFont, nXScale, nYScale);
|
|
||||||
|
|
||||||
return mpHbFont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !HB_VERSION_ATLEAST(1, 1, 0)
|
#if !HB_VERSION_ATLEAST(1, 1, 0)
|
||||||
@@ -182,8 +179,6 @@ CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance, con
|
|||||||
|
|
||||||
mpHbFont = createHbFont(pHbFace);
|
mpHbFont = createHbFont(pHbFace);
|
||||||
rWinFontFace.SetHbFont(mpHbFont);
|
rWinFontFace.SetHbFont(mpHbFont);
|
||||||
|
|
||||||
hb_face_destroy(pHbFace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +201,6 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
|
|||||||
|
|
||||||
mpHbFont = createHbFont(pHbFace);
|
mpHbFont = createHbFont(pHbFace);
|
||||||
rCoreTextStyle.SetHbFont(mpHbFont);
|
rCoreTextStyle.SetHbFont(mpHbFont);
|
||||||
|
|
||||||
hb_face_destroy(pHbFace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,8 +216,6 @@ CommonSalLayout::CommonSalLayout(FreetypeFont& rFreetypeFont)
|
|||||||
|
|
||||||
mpHbFont = createHbFont(pHbFace);
|
mpHbFont = createHbFont(pHbFace);
|
||||||
mrFreetypeFont.SetHbFont(mpHbFont);
|
mrFreetypeFont.SetHbFont(mpHbFont);
|
||||||
|
|
||||||
hb_face_destroy(pHbFace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -370,8 +361,7 @@ static int GetVerticalFlagsForScript(UScriptCode aScript)
|
|||||||
|
|
||||||
bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
||||||
{
|
{
|
||||||
hb_font_t* pHbFont = getHbFont();
|
hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
|
||||||
hb_face_t* pHbFace = hb_font_get_face(pHbFont);
|
|
||||||
hb_script_t aHbScript = HB_SCRIPT_INVALID;
|
hb_script_t aHbScript = HB_SCRIPT_INVALID;
|
||||||
|
|
||||||
int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos);
|
int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos);
|
||||||
@@ -401,6 +391,10 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
|||||||
|
|
||||||
ParseFeatures(mrFontSelData.maTargetName);
|
ParseFeatures(mrFontSelData.maTargetName);
|
||||||
|
|
||||||
|
double nXScale = 0;
|
||||||
|
double nYScale = 0;
|
||||||
|
getScale(&nXScale, &nYScale);
|
||||||
|
|
||||||
Point aCurrPos(0, 0);
|
Point aCurrPos(0, 0);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -485,7 +479,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
|||||||
hb_segment_properties_t aHbProps;
|
hb_segment_properties_t aHbProps;
|
||||||
hb_buffer_get_segment_properties(pHbBuffer, &aHbProps);
|
hb_buffer_get_segment_properties(pHbBuffer, &aHbProps);
|
||||||
hb_shape_plan_t* pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, maFeatures.data(), maFeatures.size(), pHbShapers);
|
hb_shape_plan_t* pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, maFeatures.data(), maFeatures.size(), pHbShapers);
|
||||||
bool ok = hb_shape_plan_execute(pHbPlan, pHbFont, pHbBuffer, maFeatures.data(), maFeatures.size());
|
bool ok = hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, maFeatures.data(), maFeatures.size());
|
||||||
assert(ok);
|
assert(ok);
|
||||||
(void) ok;
|
(void) ok;
|
||||||
hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
||||||
@@ -543,7 +537,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
|||||||
if (bDiacritic)
|
if (bDiacritic)
|
||||||
nGlyphFlags |= GlyphItem::IS_DIACRITIC;
|
nGlyphFlags |= GlyphItem::IS_DIACRITIC;
|
||||||
|
|
||||||
int32_t nAdvance, nXOffset, nYOffset;
|
DeviceCoordinate nAdvance, nXOffset, nYOffset;
|
||||||
if (bVertical)
|
if (bVertical)
|
||||||
{
|
{
|
||||||
int nVertFlag;
|
int nVertFlag;
|
||||||
@@ -556,15 +550,15 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
|
|||||||
nVertFlag = GF_ROTL;
|
nVertFlag = GF_ROTL;
|
||||||
#endif
|
#endif
|
||||||
nGlyphIndex |= nVertFlag;
|
nGlyphIndex |= nVertFlag;
|
||||||
nAdvance = -pHbPositions[i].y_advance >> 6;
|
nAdvance = -pHbPositions[i].y_advance * nYScale;
|
||||||
nXOffset = pHbPositions[i].y_offset >> 6;
|
nXOffset = pHbPositions[i].y_offset * nYScale;
|
||||||
nYOffset = -pHbPositions[i].x_offset >> 6;
|
nYOffset = -pHbPositions[i].x_offset * nXScale;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nAdvance = pHbPositions[i].x_advance >> 6;
|
nAdvance = pHbPositions[i].x_advance * nXScale;
|
||||||
nXOffset = pHbPositions[i].x_offset >> 6;
|
nXOffset = pHbPositions[i].x_offset * nXScale;
|
||||||
nYOffset = pHbPositions[i].y_offset >> 6;
|
nYOffset = pHbPositions[i].y_offset * nYScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
|
Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
|
||||||
@@ -649,9 +643,12 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
|
|||||||
if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification)
|
if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification)
|
||||||
{
|
{
|
||||||
// Find Kashida glyph width and index.
|
// Find Kashida glyph width and index.
|
||||||
hb_font_t* pHbFont = getHbFont();
|
if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex))
|
||||||
if (hb_font_get_glyph(pHbFont, 0x0640, 0, &nKashidaIndex))
|
{
|
||||||
nKashidaWidth = hb_font_get_glyph_h_advance(pHbFont, nKashidaIndex) / 64;
|
double nXScale = 0;
|
||||||
|
getScale(&nXScale, nullptr);
|
||||||
|
nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, nKashidaIndex) * nXScale;
|
||||||
|
}
|
||||||
bKashidaJustify = nKashidaWidth != 0;
|
bKashidaJustify = nKashidaWidth != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user