summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiang Jiang <jiang.jiang@nokia.com>2011-02-22 14:15:43 +0100
committerJiang Jiang <jiang.jiang@nokia.com>2011-03-22 12:03:51 +0100
commit037e632d4b3884d06bf9e92de77d726c75fe7898 (patch)
tree6834662159359112e2b2b8acf43f574990dda0e3
parent23098630c94e6655a33042bee0caa6c933c0c7d9 (diff)
downloadqt4-tools-037e632d4b3884d06bf9e92de77d726c75fe7898.tar.gz
Implement subpixel positioning with FreeType
QFontEngineFT are used in raster/OpenGL paint engine and QGLWidget, also in Symbian, etc. We want to make sure it works well in raster and QGLWidget first. Regardless subpixel antialiasing (LCD filtering) is enabled or not (though it does look better when subpixel antialiasing is on). We also need to support transformations. The tricky part here is that, under X11, we have a different code path for QFontEngineFT and other font engines in raster engine, which uses QFontEngineFT's own glyph cache system. While in other platforms (Windows and Mac) and QGLWidget, we will use the generic QTextureGlyphCache. The generic QTextureGlyphCache already has support for subpixel positions, this solution is ported to QFontEngineFT for its QGlyphSet: the key for QGlyphSet hash table has been extended from glyph_t to <glyph_t, QFixed subPixelPosition> pair. The real work to enable subpixel positioning with FreeType is in fact really simple, we just set the horizontal translation to the subpixel position * 64 (FreeType uses a coordinate system of 1/64 of a pixel resolution internally) immediately before loading the glyph. A slight tweek to bitmap width is applied when we are getting the bitmap ourselves instead of using FT_Render_Glyph to accommodate the subpixel translation, which will only be used in non-LCD filtering cases (grayscale antialiasing). From what we have observed, FreeType can generate different bitmaps for at least 12 different subpixel positions (each with a slight difference). To limit the memory consumption, we restrict the number of subpixel positions to be 4 (hardcoded), which should be good enough for most low resolution displays. Subpixel positioning (and fractional glyph advances) will only be enabled when the hintingPreference for the font being used is PreferNoHinting or PreferVerticalHinting. We will use fontconfig hintstyle setting by default when no hintingPreference is set for the font. Task-number: QTBUG-12279 Reviewed-by: Eskil
-rw-r--r--src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp8
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp7
-rw-r--r--src/gui/painting/qpaintengine_x11.cpp2
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp10
-rw-r--r--src/gui/text/qfontdatabase_x11.cpp1
-rw-r--r--src/gui/text/qfontengine_ft.cpp175
-rw-r--r--src/gui/text/qfontengine_ft_p.h52
-rw-r--r--src/gui/text/qfontengine_x11.cpp16
8 files changed, 166 insertions, 105 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp
index 6c4d9f1df6..c202e1f52b 100644
--- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp
+++ b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp
@@ -1052,16 +1052,16 @@ HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *fe
{
HB_Script script = shaper_item->item.script;
- if (!shaper_item->face->supported_scripts[script])
- return false;
-
HB_Face face = shaper_item->face;
if (face->current_script == script && face->current_flags == shaper_item->shaperFlags)
- return true;
+ return shaper_item->face->supported_scripts[script] ? true : false;
face->current_script = script;
face->current_flags = shaper_item->shaperFlags;
+ if (!shaper_item->face->supported_scripts[script])
+ return false;
+
assert(script < HB_ScriptCount);
// find script in our list of supported scripts.
unsigned int tag = ot_scripts[script].tag;
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 9242fb6ee8..3af98d626a 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -3469,7 +3469,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
}
if (!gset || gset->outline_drawing
- || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), neededFormat))
+ || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), positions, neededFormat))
{
QPaintEngine::drawTextItem(p, ti);
return;
@@ -3494,12 +3494,13 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
};
for(int i = 0; i < glyphs.size(); i++) {
- QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i]);
+ QFixed spp = fe->subPixelPositionForX(positions[i].x);
+ QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
if (!glyph || glyph->format != neededFormat) {
if (!lockedFace)
lockedFace = fe->lockFace();
- glyph = fe->loadGlyph(gset, glyphs[i], neededFormat);
+ glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
}
if (!glyph || !glyph->data)
diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp
index 8b71b83185..16ef09bb45 100644
--- a/src/gui/painting/qpaintengine_x11.cpp
+++ b/src/gui/painting/qpaintengine_x11.cpp
@@ -2385,7 +2385,7 @@ void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti)
set = ft->loadTransformedGlyphSet(d->matrix);
if (!set || set->outline_drawing
- || !ft->loadGlyphs(set, glyphs.data(), glyphs.size(), QFontEngineFT::Format_Render))
+ || !ft->loadGlyphs(set, glyphs.data(), glyphs.size(), positions, QFontEngineFT::Format_Render))
{
QPaintEngine::drawTextItem(p, ti);
return;
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index e75c0f58cb..b83dbc057f 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -134,9 +134,13 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
if (!supportsSubPixelPositions) {
m_subPixelPositionCount = 1;
} else {
+#if !defined(Q_WS_X11)
int i = 0;
while (m_subPixelPositionCount == 0 && i < numGlyphs)
m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
+#else
+ m_subPixelPositionCount = 4;
+#endif
}
}
@@ -307,9 +311,11 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition
QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform);
+ QFontEngineFT::Glyph *glyph = NULL;
+ if (gset)
+ glyph = ft->loadGlyph(gset, g, subPixelPosition, format);
- if (gset && ft->loadGlyphs(gset, &g, 1, format)) {
- QFontEngineFT::Glyph *glyph = gset->getGlyph(g);
+ if (glyph) {
const int bytesPerLine = (format == QFontEngineFT::Format_Mono ? ((glyph->width + 31) & ~31) >> 3
: (glyph->width + 3) & ~3);
return QImage(glyph->data, glyph->width, glyph->height, bytesPerLine, imageFormat);
diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp
index 02b01489a1..0c0c4c8343 100644
--- a/src/gui/text/qfontdatabase_x11.cpp
+++ b/src/gui/text/qfontdatabase_x11.cpp
@@ -746,6 +746,7 @@ QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request)
QFontDef fontDef;
fontDef.styleStrategy = request.styleStrategy;
+ fontDef.hintingPreference = request.hintingPreference;
FcChar8 *value = 0;
if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) {
fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value));
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index f5e9e1ca9a..a4211a910b 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -174,9 +174,7 @@ int QFreetypeFace::fsType() const
HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
{
- int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
-
- if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags))
+ if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
return error;
if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
@@ -760,12 +758,9 @@ void QFontEngineFT::setDefaultHintStyle(HintStyle style)
default_hint_style = style;
}
-QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const
+int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
+ bool &hsubpixel, int &vfactor) const
{
- Glyph *g = set->getGlyph(glyph);
- if (g && g->format == format)
- return g;
-
int load_flags = FT_LOAD_DEFAULT | default_load_flags;
int load_target = default_hint_style == HintLight
? FT_LOAD_TARGET_LIGHT
@@ -777,20 +772,35 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph
if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
if (default_hint_style == HintFull)
load_target = FT_LOAD_TARGET_LCD;
+ hsubpixel = true;
} else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
if (default_hint_style == HintFull)
load_target = FT_LOAD_TARGET_LCD_V;
+ vfactor = 3;
}
}
- if (set->outline_drawing)
+ if (set && set->outline_drawing)
load_flags = FT_LOAD_NO_BITMAP;
- if (default_hint_style == HintNone)
+ if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics))
load_flags |= FT_LOAD_NO_HINTING;
else
load_flags |= load_target;
+ return load_flags;
+}
+
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const
+{
+ Glyph *g = set->getGlyph(glyph);
+ if (g && g->format == format)
+ return g;
+
+ bool hsubpixel = false;
+ int vfactor = 1;
+ int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
+
// apply our matrix to this, but note that the metrics will not be affected by this.
FT_Face face = lockFace();
FT_Matrix matrix = this->matrix;
@@ -881,7 +891,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph
return g;
}
-QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, GlyphFormat format, bool fetchMetricsOnly) const
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
+ QFixed subPixelPosition,
+ GlyphFormat format,
+ bool fetchMetricsOnly) const
{
// Q_ASSERT(freetype->lock == 1);
@@ -896,10 +909,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph
}
}
- Glyph *g = set->getGlyph(glyph);
+ Glyph *g = set->getGlyph(glyph, subPixelPosition);
if (g && g->format == format) {
if (uploadToServer && !g->uploadedToServer) {
- set->setGlyph(glyph, 0);
+ set->setGlyph(glyph, subPixelPosition, 0);
delete g;
g = 0;
} else {
@@ -912,33 +925,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph
Q_ASSERT(format != Format_None);
bool hsubpixel = false;
int vfactor = 1;
- int load_flags = FT_LOAD_DEFAULT | default_load_flags;
-
- int load_target = default_hint_style == HintLight
- ? FT_LOAD_TARGET_LIGHT
- : FT_LOAD_TARGET_NORMAL;
-
- if (set->outline_drawing)
- load_flags |= FT_LOAD_NO_BITMAP;
-
- if (format == Format_Mono) {
- load_target = FT_LOAD_TARGET_MONO;
- } else if (format == Format_A32) {
- if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
- if (default_hint_style == HintFull)
- load_target = FT_LOAD_TARGET_LCD;
- hsubpixel = true;
- } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
- if (default_hint_style == HintFull)
- load_target = FT_LOAD_TARGET_LCD_V;
- vfactor = 3;
- }
- }
-
- if (default_hint_style == HintNone)
- load_flags |= FT_LOAD_NO_HINTING;
- else
- load_flags |= load_target;
+ int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
#ifndef Q_WS_QWS
if (format != Format_Mono && !embeddedbitmap)
@@ -955,6 +942,12 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph
load_flags |= FT_LOAD_NO_BITMAP;
FT_Face face = freetype->face;
+
+ FT_Vector v;
+ v.x = FT_Pos((subPixelPosition).toReal() * 64);
+ v.y = 0;
+ FT_Set_Transform(face, &freetype->matrix, &v);
+
FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
load_flags &= ~FT_LOAD_NO_BITMAP;
@@ -1055,6 +1048,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph
top = CEIL(top);
int hpixels = TRUNC(right - left);
+ // subpixel position requires one more pixel
+ if (subPixelPosition > 0)
+ hpixels++;
+
if (hsubpixel)
hpixels = hpixels*3 + 8;
info.width = hpixels;
@@ -1197,7 +1194,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph
uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
}
- set->setGlyph(glyph, g);
+ set->setGlyph(glyph, subPixelPosition, g);
return g;
}
@@ -1430,12 +1427,28 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransfor
return gs;
}
-bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format)
+QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
+{
+ int m_subPixelPositionCount = 4;
+
+ QFixed subPixelPosition;
+ if (x != 0) {
+ subPixelPosition = x - x.floor();
+ QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
+ subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
+ }
+ return subPixelPosition;
+}
+
+bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs,
+ QVarLengthArray<QFixedPoint> &positions,
+ GlyphFormat format)
{
FT_Face face = 0;
for (int i = 0; i < num_glyphs; ++i) {
- Glyph *glyph = gs->getGlyph(glyphs[i]);
+ QFixed spp = subPixelPositionForX(positions[i].x);
+ Glyph *glyph = gs->getGlyph(glyphs[i], spp);
if (glyph == 0 || glyph->format != format) {
if (!face) {
face = lockFace();
@@ -1444,7 +1457,7 @@ bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, G
FT_Set_Transform(face, &m, 0);
freetype->matrix = m;
}
- if (!loadGlyph(gs, glyphs[i], format)) {
+ if (!loadGlyph(gs, glyphs[i], spp, format)) {
unlockFace();
return false;
}
@@ -1668,35 +1681,26 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
{
FT_Face face = 0;
- if (flags & QTextEngine::DesignMetrics) {
- for (int i = 0; i < glyphs->numGlyphs; i++) {
- Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
- if (g) {
- glyphs->advances_x[i] = QFixed::fromFixed(g->linearAdvance);
- } else {
- if (!face)
- face = lockFace();
- g = loadGlyph(glyphs->glyphs[i], Format_None, true);
- glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10);
- }
- glyphs->advances_y[i] = 0;
- }
- } else {
- for (int i = 0; i < glyphs->numGlyphs; i++) {
- Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
- if (g) {
- glyphs->advances_x[i] = QFixed(g->advance);
- } else {
- if (!face)
- face = lockFace();
- g = loadGlyph(glyphs->glyphs[i], Format_None, true);
- glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
- }
- glyphs->advances_y[i] = 0;
+ bool design = (default_hint_style == HintNone ||
+ default_hint_style == HintLight ||
+ (flags & HB_ShaperFlag_UseDesignMetrics));
+ for (int i = 0; i < glyphs->numGlyphs; i++) {
+ Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
+ if (g) {
+ glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
+ } else {
+ if (!face)
+ face = lockFace();
+ g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
+ glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
+ : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
+ if (face)
+ unlockFace();
}
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances_y[i] = 0;
}
- if (face)
- unlockFace();
}
glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
@@ -1716,7 +1720,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
if (!g) {
if (!face)
face = lockFace();
- g = loadGlyph(glyphs.glyphs[i], Format_None, true);
+ g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
}
if (g) {
QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
@@ -1757,7 +1761,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
Glyph *g = defaultGlyphSet.getGlyph(glyph);
if (!g) {
face = lockFace();
- g = loadGlyph(glyph, Format_None, true);
+ g = loadGlyph(glyph, 0, Format_None, true);
}
if (g) {
overall.x = g->x;
@@ -1765,6 +1769,8 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
overall.width = g->width;
overall.height = g->height;
overall.xoff = g->advance;
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ overall.xoff = overall.xoff.round();
} else {
int left = FLOOR(face->glyph->metrics.horiBearingX);
int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
@@ -1866,7 +1872,7 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
- Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format);
+ Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, 0, glyph_format);
if (!glyph) {
unlockFace();
return QFontEngine::alphaMapForGlyph(g);
@@ -1905,7 +1911,7 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, in
GlyphFormat glyph_format = Format_A32;
- Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format);
+ Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
if (!glyph) {
unlockFace();
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
@@ -1920,7 +1926,7 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, in
void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
{
- defaultGlyphSet.removeGlyphFromCache(glyph);
+ defaultGlyphSet.removeGlyphFromCache(glyph, 0);
}
int QFontEngineFT::glyphCount() const
@@ -2000,9 +2006,9 @@ void QFontEngineFT::QGlyphSet::clear()
glyph_data.clear();
}
-void QFontEngineFT::QGlyphSet::removeGlyphFromCache(int index)
+void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
{
- if (index < 256) {
+ if (useFastGlyphData(index, subPixelPosition)) {
if (fast_glyph_data[index]) {
delete fast_glyph_data[index];
fast_glyph_data[index] = 0;
@@ -2010,18 +2016,18 @@ void QFontEngineFT::QGlyphSet::removeGlyphFromCache(int index)
--fast_glyph_count;
}
} else {
- delete glyph_data.take(index);
+ delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
}
}
-void QFontEngineFT::QGlyphSet::setGlyph(int index, Glyph *glyph)
+void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
{
- if (index < 256) {
+ if (useFastGlyphData(index, subPixelPosition)) {
if (!fast_glyph_data[index])
++fast_glyph_count;
fast_glyph_data[index] = glyph;
} else {
- glyph_data.insert(index, glyph);
+ glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
}
}
@@ -2038,7 +2044,10 @@ void QFontEngineFT::freeServerGlyphSet(unsigned long id)
HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
{
lockFace();
- HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
+ bool hsubpixel = true;
+ int vfactor = 1;
+ int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
+ HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
unlockFace();
return result;
}
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index abdbd2099b..63fd9a7634 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -166,6 +166,19 @@ public:
};
#endif
+ struct GlyphAndSubPixelPosition
+ {
+ GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
+
+ bool operator==(const GlyphAndSubPixelPosition &other) const
+ {
+ return glyph == other.glyph && subPixelPosition == other.subPixelPosition;
+ }
+
+ glyph_t glyph;
+ QFixed subPixelPosition;
+ };
+
struct QGlyphSet
{
QGlyphSet();
@@ -174,18 +187,21 @@ public:
unsigned long id; // server sided id, GlyphSet for X11
bool outline_drawing;
- void removeGlyphFromCache(int index);
+ void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition);
void clear();
- inline Glyph *getGlyph(int index) const
+ inline bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const {
+ return (index < 256 && subPixelPosition == 0);
+ }
+ inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const
{
- if (index < 256)
+ if (useFastGlyphData(index, subPixelPosition))
return fast_glyph_data[index];
- return glyph_data.value(index);
+ return glyph_data.value(GlyphAndSubPixelPosition(index, subPixelPosition));
}
- void setGlyph(int index, Glyph *glyph);
+ void setGlyph(glyph_t index, QFixed spp, Glyph *glyph);
private:
- mutable QHash<int, Glyph *> glyph_data; // maps from glyph index to glyph data
+ mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data
mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256
mutable int fast_glyph_count;
};
@@ -193,6 +209,11 @@ private:
virtual QFontEngine::FaceId faceId() const;
virtual QFontEngine::Properties properties() const;
virtual QFixed emSquareSize() const;
+ virtual bool supportsSubPixelPositions() const
+ {
+ return default_hint_style == HintLight ||
+ default_hint_style == HintNone;
+ }
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
virtual int synthesized() const;
@@ -254,17 +275,20 @@ private:
inline bool invalid() const { return xsize == 0 && ysize == 0; }
inline bool isBitmapFont() const { return defaultFormat == Format_Mono; }
- inline Glyph *loadGlyph(uint glyph, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const
- { return loadGlyph(&defaultGlyphSet, glyph, format, fetchMetricsOnly); }
- Glyph *loadGlyph(QGlyphSet *set, uint glyph, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const;
+ inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const
+ { return loadGlyph(&defaultGlyphSet, glyph, subPixelPosition, format, fetchMetricsOnly); }
+ Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const;
QGlyphSet *defaultGlyphs() { return &defaultGlyphSet; }
GlyphFormat defaultGlyphFormat() const { return defaultFormat; }
- inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.getGlyph(g); }
+ inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.getGlyph(g, 0); }
QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix);
- bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format = Format_Render);
+ QFixed subPixelPositionForX(QFixed x);
+ bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs,
+ QVarLengthArray<QFixedPoint> &positions,
+ GlyphFormat format = Format_Render);
#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
virtual void draw(QPaintEngine * /*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt & /*si*/) {}
@@ -309,6 +333,7 @@ protected:
private:
QFontEngineFT::Glyph *loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const;
+ int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
GlyphFormat defaultFormat;
FT_Matrix matrix;
@@ -330,6 +355,11 @@ private:
mutable bool kerning_pairs_loaded;
};
+inline uint qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g)
+{
+ return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();
+}
+
QT_END_NAMESPACE
#endif // QT_NO_FREETYPE
diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp
index d5ec58407d..e44247193c 100644
--- a/src/gui/text/qfontengine_x11.cpp
+++ b/src/gui/text/qfontengine_x11.cpp
@@ -1012,8 +1012,22 @@ QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int s
}
}
+ if (fd.hintingPreference != QFont::PreferDefaultHinting) {
+ switch (fd.hintingPreference) {
+ case QFont::PreferNoHinting:
+ default_hint_style = HintNone;
+ break;
+ case QFont::PreferVerticalHinting:
+ default_hint_style = HintLight;
+ break;
+ case QFont::PreferFullHinting:
+ default:
+ default_hint_style = HintFull;
+ break;
+ }
+ }
#ifdef FC_HINT_STYLE
- {
+ else {
int hint_style = 0;
if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
hint_style = X11->fc_hint_style;