Fix FreeType glyph caching for high resolution
authorJiang Jiang <jiang.jiang@nokia.com>
Wed, 16 May 2012 16:14:45 +0000 (18:14 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 18 May 2012 08:39:49 +0000 (10:39 +0200)
For high resolution or extremely large font sizes, the advance
cached here is likely to overflow, since FreeType returns 26.6
fixed point value and we only take signed char here for advance.

In those cases we should skip caching because there won't be
that many big glyphs after all.

Also move the metrics caching block a bit down to take glyph
embolden and oblique into account.

As a result we also don't need to increase the linearAdvance
size because any linearAdvance less than 128 should fit in
the old 10.6 fixed format.

Change-Id: Ic4920ada49954ce1e0a8673c9f33f30e385e3046
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
src/gui/text/qfontengine_ft.cpp
src/gui/text/qfontengine_ft_p.h

index ac9dd99..f83ddd3 100644 (file)
@@ -856,26 +856,6 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
 
     FT_GlyphSlot slot = face->glyph;
-    if ((set && set->outline_drawing) || fetchMetricsOnly) {
-        g = new Glyph;
-        g->data = 0;
-        g->linearAdvance = slot->linearHoriAdvance >> 10;
-        int left  = FLOOR(slot->metrics.horiBearingX);
-        int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
-        int top    = CEIL(slot->metrics.horiBearingY);
-        int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
-        g->width = TRUNC(right-left);
-        g->height = TRUNC(top-bottom);
-        g->x = TRUNC(left);
-        g->y = TRUNC(top);
-        g->advance = TRUNC(ROUND(slot->advance.x));
-        g->format = format;
-
-        if (set)
-            set->setGlyph(glyph, subPixelPosition, g);
-
-        return g;
-    }
 
     if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
     if (obliquen) {
@@ -898,6 +878,30 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
     info.xOff = TRUNC(ROUND(slot->advance.x));
     info.yOff = 0;
 
+    if ((set && set->outline_drawing) || fetchMetricsOnly) {
+        // If the advance doesn't fit in signed char, don't cache it
+        if (qAbs(info.xOff) >= 128)
+            return 0;
+        g = new Glyph;
+        g->data = 0;
+        g->linearAdvance = slot->linearHoriAdvance >> 10;
+        int left  = FLOOR(slot->metrics.horiBearingX);
+        int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
+        int top    = CEIL(slot->metrics.horiBearingY);
+        int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
+        g->width = TRUNC(right-left);
+        g->height = TRUNC(top-bottom);
+        g->x = TRUNC(left);
+        g->y = TRUNC(top);
+        g->advance = TRUNC(ROUND(slot->advance.x));
+        g->format = format;
+
+        if (set)
+            set->setGlyph(glyph, subPixelPosition, g);
+
+        return g;
+    }
+
     uchar *glyph_buffer = 0;
     int glyph_buffer_size = 0;
 #if defined(QT_USE_FREETYPE_LCDFILTER)
index e665ce8..5abcadc 100644 (file)
@@ -141,7 +141,7 @@ public:
     /* we don't cache glyphs that are too large anyway, so we can make this struct rather small */
     struct Glyph {
         ~Glyph();
-        int linearAdvance : 22; // 16.6
+        short linearAdvance;
         unsigned char width;
         unsigned char height;
         signed char x;