Fix transformations on DirectWrite rasterized text

There were a few bugs in the DirectWrite font engine that caused
transformed text to break.

First of all, alphaMapForGlyph() ignored the transform, so no gray
antialiased text would be transformed.

Second of all, the imageForGlyph() function would use the wrong
bounding box for the rasterized glyph, causing its positioning to
become a little bit off when rotating. The fix is to get the bounding
box from the system and add a margin to this instead of trying to predict
how it will appear after the vertical hinting etc. has been applied.

So that the positioning metrics are in sync with the actual metrics used
by the alphaMap* functions, we also need to implement the
alphaMapBoundingBox() function.

Task-number: QTBUG-19829
Reviewed-by: Jiang Jiang
(cherry picked from commit f54c5d9133d7aa7636988db36fa6cc51d26434b6)

Change-Id: I3c3840b41e19fcacf926dbf454bdc2cba4bd5a99
Reviewed-on: http://codereview.qt.nokia.com/948
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2011-06-30 11:57:09 +02:00 committed by Qt by Nokia
parent 7a9c5eea81
commit 0fc1e852ae
2 changed files with 101 additions and 44 deletions

View File

@ -390,6 +390,60 @@ glyph_metrics_t QFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs)
return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0); return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0);
} }
glyph_metrics_t QFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition,
const QTransform &matrix,
GlyphFormat /*format*/)
{
glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance
UINT16 glyphIndex = glyph;
FLOAT glyphAdvance = 0;
DWRITE_GLYPH_OFFSET glyphOffset;
glyphOffset.advanceOffset = 0;
glyphOffset.ascenderOffset = 0;
DWRITE_GLYPH_RUN glyphRun;
glyphRun.fontFace = m_directWriteFontFace;
glyphRun.fontEmSize = fontDef.pixelSize;
glyphRun.glyphCount = 1;
glyphRun.glyphIndices = &glyphIndex;
glyphRun.glyphAdvances = &glyphAdvance;
glyphRun.isSideways = false;
glyphRun.bidiLevel = 0;
glyphRun.glyphOffsets = &glyphOffset;
DWRITE_MATRIX transform;
transform.dx = subPixelPosition.toReal();
transform.dy = 0;
transform.m11 = matrix.m11();
transform.m12 = matrix.m12();
transform.m21 = matrix.m21();
transform.m22 = matrix.m22();
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis(
&glyphRun,
1.0f,
&transform,
DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
DWRITE_MEASURING_MODE_NATURAL,
0.0, 0.0,
&glyphAnalysis
);
if (SUCCEEDED(hr)) {
RECT rect;
glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
glyphAnalysis->Release();
return glyph_metrics_t(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
bbox.xoff, bbox.yoff);
} else {
return glyph_metrics_t();
}
}
glyph_metrics_t QFontEngineDirectWrite::boundingBox(glyph_t g) glyph_metrics_t QFontEngineDirectWrite::boundingBox(glyph_t g)
{ {
if (m_directWriteFontFace == 0) if (m_directWriteFontFace == 0)
@ -459,9 +513,10 @@ qreal QFontEngineDirectWrite::maxCharWidth() const
extern uint qt_pow_gamma[256]; extern uint qt_pow_gamma[256];
QImage QFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) QImage QFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
const QTransform &xform)
{ {
QImage im = imageForGlyph(glyph, subPixelPosition, 0, QTransform()); QImage im = imageForGlyph(glyph, subPixelPosition, 0, xform);
QImage indexed(im.width(), im.height(), QImage::Format_Indexed8); QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
QVector<QRgb> colors(256); QVector<QRgb> colors(256);
@ -492,12 +547,8 @@ QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
int margin, int margin,
const QTransform &xform) const QTransform &xform)
{ {
glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform);
int width = (metrics.width + margin * 2 + 4).ceil().toInt() ;
int height = (metrics.height + margin * 2 + 4).ceil().toInt();
UINT16 glyphIndex = t; UINT16 glyphIndex = t;
FLOAT glyphAdvance = metrics.xoff.toReal(); FLOAT glyphAdvance = 0;
DWRITE_GLYPH_OFFSET glyphOffset; DWRITE_GLYPH_OFFSET glyphOffset;
glyphOffset.advanceOffset = 0; glyphOffset.advanceOffset = 0;
@ -513,12 +564,9 @@ QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
glyphRun.bidiLevel = 0; glyphRun.bidiLevel = 0;
glyphRun.glyphOffsets = &glyphOffset; glyphRun.glyphOffsets = &glyphOffset;
QFixed x = margin - metrics.x.round() + subPixelPosition;
QFixed y = margin - metrics.y.floor();
DWRITE_MATRIX transform; DWRITE_MATRIX transform;
transform.dx = x.toReal(); transform.dx = subPixelPosition.toReal();
transform.dy = y.toReal(); transform.dy = 0;
transform.m11 = xform.m11(); transform.m11 = xform.m11();
transform.m12 = xform.m12(); transform.m12 = xform.m12();
transform.m21 = xform.m21(); transform.m21 = xform.m21();
@ -537,12 +585,18 @@ QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
RECT rect; RECT rect;
rect.left = 0; glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
rect.top = 0;
rect.right = width; rect.left -= margin;
rect.bottom = height; rect.top -= margin;
rect.right += margin;
rect.bottom += margin;
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int size = width * height * 3; int size = width * height * 3;
if (size > 0) {
BYTE *alphaValues = new BYTE[size]; BYTE *alphaValues = new BYTE[size];
qMemSet(alphaValues, size, 0); qMemSet(alphaValues, size, 0);
@ -569,16 +623,15 @@ QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
} }
delete[] alphaValues; delete[] alphaValues;
glyphAnalysis->Release();
return img; return img;
} else { } else {
delete[] alphaValues; delete[] alphaValues;
glyphAnalysis->Release();
qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateAlphaTexture failed"); qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateAlphaTexture failed");
} }
}
glyphAnalysis->Release();
} else { } else {
qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateGlyphRunAnalysis failed"); qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateGlyphRunAnalysis failed");
} }

View File

@ -86,6 +86,10 @@ public:
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
glyph_metrics_t boundingBox(glyph_t g); glyph_metrics_t boundingBox(glyph_t g);
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
QFixed subPixelPosition,
const QTransform &matrix,
GlyphFormat format);
QFixed ascent() const; QFixed ascent() const;
QFixed descent() const; QFixed descent() const;
@ -97,7 +101,7 @@ public:
bool supportsSubPixelPositions() const; bool supportsSubPixelPositions() const;
QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition); QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin,
const QTransform &xform); const QTransform &xform);