Skip to content

Commit

Permalink
Fix stretched fonts with large pixel size
Browse files Browse the repository at this point in the history
The Windows and Cocoa font engines ignored the stretch factor when
the pixel size is so large that QPainterPath rendering is used
instead of native.

Fixes: QTBUG-14315
Change-Id: I93390528ac264452b7d6af7d39f49f4b0dd56279
Reviewed-by: Eskil Abrahamsen Blomfeldt <[email protected]>
  • Loading branch information
aavit committed Mar 27, 2019
1 parent 0ba8ed2 commit e20f4d9
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 20 deletions.
21 changes: 12 additions & 9 deletions src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -491,35 +491,37 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)

struct ConvertPathInfo
{
ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos) : path(newPath), pos(newPos) {}
ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos, qreal newStretch = 1.0) :
path(newPath), pos(newPos), stretch(newStretch) {}
QPainterPath *path;
QPointF pos;
qreal stretch;
};

static void convertCGPathToQPainterPath(void *info, const CGPathElement *element)
{
ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info);
switch(element->type) {
case kCGPathElementMoveToPoint:
myInfo->path->moveTo(element->points[0].x + myInfo->pos.x(),
myInfo->path->moveTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y());
break;
case kCGPathElementAddLineToPoint:
myInfo->path->lineTo(element->points[0].x + myInfo->pos.x(),
myInfo->path->lineTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y());
break;
case kCGPathElementAddQuadCurveToPoint:
myInfo->path->quadTo(element->points[0].x + myInfo->pos.x(),
myInfo->path->quadTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y(),
element->points[1].x + myInfo->pos.x(),
(element->points[1].x * myInfo->stretch) + myInfo->pos.x(),
element->points[1].y + myInfo->pos.y());
break;
case kCGPathElementAddCurveToPoint:
myInfo->path->cubicTo(element->points[0].x + myInfo->pos.x(),
myInfo->path->cubicTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y(),
element->points[1].x + myInfo->pos.x(),
(element->points[1].x * myInfo->stretch) + myInfo->pos.x(),
element->points[1].y + myInfo->pos.y(),
element->points[2].x + myInfo->pos.x(),
(element->points[2].x * myInfo->stretch) + myInfo->pos.x(),
element->points[2].y + myInfo->pos.y());
break;
case kCGPathElementCloseSubpath:
Expand All @@ -543,9 +545,10 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element
if (synthesisFlags & QFontEngine::SynthesizedItalic)
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));

qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
for (int i = 0; i < nGlyphs; ++i) {
QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix);
ConvertPathInfo info(path, positions[i].toPointF());
ConvertPathInfo info(path, positions[i].toPointF(), stretch);
CGPathApply(cgpath, &info, convertCGPathToQPainterPath);
}
}
Expand Down
25 changes: 14 additions & 11 deletions src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,16 +702,17 @@ static inline double qt_fixed_to_double(const FIXED &p) {
return ((p.value << 16) + p.fract) / 65536.0;
}

static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) {
return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
}

#ifndef GGO_UNHINTED
#define GGO_UNHINTED 0x0100
#endif

static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0,
qreal scale = 1.0, qreal stretch = 1.0)
{
MAT2 mat;
mat.eM11.value = mat.eM22.value = 1;
Expand Down Expand Up @@ -761,15 +762,15 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
while (headerOffset < bufferSize) {
const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset);

QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
path->moveTo(lastPoint + oset);
offset += sizeof(TTPOLYGONHEADER);
while (offset < headerOffset + ttph->cb) {
const TTPOLYCURVE *curve = reinterpret_cast<const TTPOLYCURVE *>(dataBuffer + offset);
switch (curve->wType) {
case TT_PRIM_LINE: {
for (int i=0; i<curve->cpfx; ++i) {
QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
path->lineTo(p);
}
break;
Expand All @@ -779,8 +780,8 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
QPointF prev(elm.x, elm.y);
QPointF endPoint;
for (int i=0; i<curve->cpfx - 1; ++i) {
QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
if (i < curve->cpfx - 2) {
endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
} else {
Expand All @@ -795,9 +796,9 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
}
case TT_PRIM_CSPLINE: {
for (int i=0; i<curve->cpfx; ) {
QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
path->cubicTo(p2, p3, p4);
}
break;
Expand Down Expand Up @@ -829,9 +830,11 @@ void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions
HDC hdc = m_fontEngineData->hdc;
HGDIOBJ oldfont = SelectObject(hdc, hf);

qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
for(int i = 0; i < nglyphs; ++i) {
if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
qreal(fontDef.pixelSize) / unitsPerEm)) {
scale, stretch)) {
// Some windows fonts, like "Modern", are vector stroke
// fonts, which are reported as TMPF_VECTOR but do not
// support GetGlyphOutline, and thus we set this bit so
Expand Down

0 comments on commit e20f4d9

Please sign in to comment.