Commits

Lenard Lindstrom  committed 0d2fb51

add use_bitmap_strike property to pygame.freetype.Font (towards Issue #75)

Allow the user to control whether or not bitmaps embedded in an outline font
file are used. Also prevent using embedded bitmaps for rotated text or for
styles strong and oblique.

  • Participants
  • Parent commits 2aa48db

Comments (0)

Files changed (8)

File docs/reST/ref/freetype.rst

    .. method:: get_sizes
 
       | :sl:`return the available sizes of embedded bitmaps`
-      | :sg:`get_sizes() -> [(int, int, float, float, float), ...]`
+      | :sg:`get_sizes() -> [(int, int, int, float, float), ...]`
       | :sg:`get_sizes() -> []`
 
       This returns a list of tuple records, one for each point size
-      supported. Each tuple containing the height in pixels, width in pixels,
-      nominal size of the strike in fractional points, horizontal ppem
-      (nominal width) in fractional pixels, and vertical ppem (nominal height)
-      in fractional pixels. The point size is equivalent to the rounded
-      vertical ppem ― index 3 ― of the tuple. Use it for the ptsize argument
-      of the render methods.
+      supported. Each tuple containing the point size, the height in pixels,
+      width in pixels, horizontal ppem (nominal width) in fractional pixels,
+      and vertical ppem (nominal height) in fractional pixels.
 
    .. method:: render
 
       Read only. Return True if the font contains outline glyphs. If so,
       the point size is not limited to available bitmap sizes.
 
+   .. attribute:: use_bitmap_strikes
+
+      | :sl:`allow the use of embeddeded bitmaps in an outline font file`
+      | :sg:`use_bitmap_strikes -> bool`
+
+      Some scalable fonts contain embedded bitmaps for particular point
+      sizes. This property controls whether or not those bitmap strikes
+      are used. Setting ``False`` disables the loading of any bitmap strike.
+      Setting ``True``, the default value, allows bitmap strikes for an
+      unrotated render when no style other than :attr:`wide` or
+      :attr:`underline` is set. This property has no effect on bitmap files.
+
+      See also :attr:`fixed_sizes` and :meth:`get_sizes`.
+
    .. attribute:: antialiased
 
       | :sl:`Font anti-aliasing mode`

File src/_freetype.c

         (void *)FT_RFLAG_UCS4
     },
     {
+        "use_bitmap_strikes",
+        (getter)_ftfont_getrender_flag,
+        (setter)_ftfont_setrender_flag,
+        DOC_FONTUSEBITMAPSTRIKES,
+        (void *)FT_RFLAG_USE_BITMAP_STRIKES
+    },
+    {
         "resolution",
         (getter)_ftfont_getresolution,
         0,
     int nsizes;
     unsigned i;
     int rc;
+    long ptsize = 0;
     long height = 0, width = 0;
-    double size = 0.0;
     double x_ppem = 0.0, y_ppem = 0.0;
     PyObject *size_list = 0;
     PyObject *size_item;
     if (!size_list) goto error;
     for (i = 0; i < nsizes; ++i) {
         rc = _PGFT_Font_GetAvailableSize(ft, self, i,
-                                         &height, &width,
-                                         &size, &x_ppem, &y_ppem);
+                                         &ptsize, &height, &width,
+                                         &x_ppem, &y_ppem);
         if (rc < 0) goto error;
         assert(rc > 0);
-        size_item = Py_BuildValue("llddd", height, width, size, x_ppem, y_ppem);
+        size_item = Py_BuildValue("llldd",
+                                  ptsize, height, width, x_ppem, y_ppem);
         if (!size_item) goto error;
         PyList_SET_ITEM(size_list, i, size_item);
     }

File src/doc/freetype_doc.h

 
 #define DOC_FONTGETSIZEDGLYPHHEIGHT "get_sized_glyph_height() -> int\nThe scaled bounding box height of the font in pixels"
 
-#define DOC_FONTGETSIZES "get_sizes() -> [(int, int, float, float, float), ...]\nget_sizes() -> []\nreturn the available sizes of embedded bitmaps"
+#define DOC_FONTGETSIZES "get_sizes() -> [(int, int, int, float, float), ...]\nget_sizes() -> []\nreturn the available sizes of embedded bitmaps"
 
 #define DOC_FONTRENDER "render(text, fgcolor, bgcolor=None, style=STYLE_DEFAULT, rotation=0, ptsize=default) -> (Surface, Rect)\nReturn rendered text as a surface"
 
 
 #define DOC_FONTSCALABLE "scalable -> bool\nGets whether the font is scalable"
 
+#define DOC_FONTUSEBITMAPSTRIKES "use_bitmap_strikes -> bool\nallow the use of embeddeded bitmaps in an outline font file"
+
 #define DOC_FONTANTIALIASED "antialiased -> bool\nFont anti-aliasing mode"
 
 #define DOC_FONTKERNING "kerning -> bool\nCharacter kerning mode"
 The scaled bounding box height of the font in pixels
 
 pygame.freetype.Font.get_sizes
- get_sizes() -> [(int, int, float, float, float), ...]
+ get_sizes() -> [(int, int, int, float, float), ...]
  get_sizes() -> []
 return the available sizes of embedded bitmaps
 
  scalable -> bool
 Gets whether the font is scalable
 
+pygame.freetype.Font.use_bitmap_strikes
+ use_bitmap_strikes -> bool
+allow the use of embeddeded bitmaps in an outline font file
+
 pygame.freetype.Font.antialiased
  antialiased -> bool
 Font anti-aliasing mode

File src/freetype.h

 #define FT_BBOX_PIXEL_GRIDFIT   FT_GLYPH_BBOX_PIXELS
 
 /* Rendering flags */
-#define FT_RFLAG_NONE           (0)
-#define FT_RFLAG_ANTIALIAS      (1 << 0)
-#define FT_RFLAG_AUTOHINT       (1 << 1)
-#define FT_RFLAG_VERTICAL       (1 << 2)
-#define FT_RFLAG_HINTED         (1 << 3)
-#define FT_RFLAG_KERNING        (1 << 4)
-#define FT_RFLAG_TRANSFORM      (1 << 5)
-#define FT_RFLAG_PAD            (1 << 6)
-#define FT_RFLAG_ORIGIN         (1 << 7)
-#define FT_RFLAG_UCS4           (1 << 8)
-#define FT_RFLAG_DEFAULTS       (FT_RFLAG_HINTED | FT_RFLAG_ANTIALIAS)
+#define FT_RFLAG_NONE                  (0)
+#define FT_RFLAG_ANTIALIAS             (1 << 0)
+#define FT_RFLAG_AUTOHINT              (1 << 1)
+#define FT_RFLAG_VERTICAL              (1 << 2)
+#define FT_RFLAG_HINTED                (1 << 3)
+#define FT_RFLAG_KERNING               (1 << 4)
+#define FT_RFLAG_TRANSFORM             (1 << 5)
+#define FT_RFLAG_PAD                   (1 << 6)
+#define FT_RFLAG_ORIGIN                (1 << 7)
+#define FT_RFLAG_UCS4                  (1 << 8)
+#define FT_RFLAG_USE_BITMAP_STRIKES    (1 << 9)
+#define FT_RFLAG_DEFAULTS              (FT_RFLAG_HINTED | \
+                                        FT_RFLAG_USE_BITMAP_STRIKES | \
+                                        FT_RFLAG_ANTIALIAS)
 
 
 #define FT_RENDER_NEWBYTEARRAY      0x0

File src/freetype/ft_layout.c

         load_flags |= FT_LOAD_NO_HINTING;
     }
 
+    if (!(mode->render_flags & FT_RFLAG_USE_BITMAP_STRIKES) ||
+        (mode->render_flags & FT_RFLAG_TRANSFORM) ||
+        (mode->rotation_angle != 0) ||
+        (mode->style & (FT_STYLE_STRONG | FT_STYLE_OBLIQUE))) {
+        load_flags |= FT_LOAD_NO_BITMAP;
+    }
+
     return load_flags;
 }

File src/freetype/ft_wrap.c

 
 int
 _PGFT_Font_GetAvailableSize(FreeTypeInstance *ft, PgFontObject *fontobj,
-                            unsigned n, long *height_p, long *width_p,
-                            double *size_p, double *x_ppem_p, double *y_ppem_p)
+                            unsigned n, long *ptsize_p,
+                            long *height_p, long *width_p,
+                            double *x_ppem_p, double *y_ppem_p)
 {
     FT_Face font = _PGFT_GetFont(ft, fontobj);
     FT_Bitmap_Size *bitmap_size_p;
         return 0;
     }
     bitmap_size_p = font->available_sizes + n;
+    *ptsize_p = FX6_TRUNC(FX6_ROUND(bitmap_size_p->size));
     *height_p = (long)bitmap_size_p->height;
     *width_p = (long)bitmap_size_p->width;
-    *size_p = FX6_TO_DBL(bitmap_size_p->size);
     *x_ppem_p = FX6_TO_DBL(bitmap_size_p->x_ppem);
     *y_ppem_p = FX6_TO_DBL(bitmap_size_p->y_ppem);
     return 1;

File src/freetype/ft_wrap.h

 int _PGFT_Font_IsFixedWidth(FreeTypeInstance *, PgFontObject *);
 int _PGFT_Font_NumFixedSizes(FreeTypeInstance *, PgFontObject *);
 int _PGFT_Font_GetAvailableSize(FreeTypeInstance *, PgFontObject *, unsigned,
-                                long *, long *, double *, double *, double *);
+                                long *, long *, long *, double *, double *);
 const char *_PGFT_Font_GetName(FreeTypeInstance *, PgFontObject *);
 int _PGFT_TryLoadFont_Filename(FreeTypeInstance *,
                                PgFontObject *, const char *, long);

File test/freetype_test.py

         self.assertTrue(isinstance(szlist, list))
         self.assertEqual(len(szlist), 1)
         size8 = szlist[0]
+        self.assertTrue(isinstance(size8[0], int))
+        self.assertEqual(size8[0], 8)
+        self.assertTrue(isinstance(size8[1], int))
+        self.assertTrue(isinstance(size8[2], int))
+        self.assertTrue(isinstance(size8[3], float))
         self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64)
+        self.assertTrue(isinstance(size8[4], float))
         self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64)
         f = self._TEST_FONTS['mono']
         szlist = f.get_sizes()
         self.assertTrue(isinstance(szlist, list))
         self.assertEqual(len(szlist), 2)
         size8 = szlist[0]
+        self.assertEqual(size8[3], 8)
         self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64)
         self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64)
         size19 = szlist[1]
+        self.assertEqual(size19[3], 19)
         self.assertEqual(int(size19[3] * 64.0 + 0.5), 19 * 64)
         self.assertEqual(int(size19[4] * 64.0 + 0.5), 19 * 64)
 
+    def test_freetype_Font_use_bitmap_strikes(self):
+        f = self._TEST_FONTS['mono']
+        try:
+            # use_bitmap_strikes == True
+            #
+            self.assertTrue(f.use_bitmap_strikes)
+
+            # bitmap compatible properties
+            s_strike, sz = f.render_raw('A', ptsize=19)
+            try:
+                f.vertical = True
+                s_strike_vert, sz = f.render_raw('A', ptsize=19)
+            finally:
+                f.vertical = False
+            try:
+                f.wide = True
+                s_strike_wide, sz = f.render_raw('A', ptsize=19)
+            finally:
+                f.wide = False
+            try:
+                f.underline = True
+                s_strike_underline, sz = f.render_raw('A', ptsize=19)
+            finally:
+                f.underline = False
+
+            # bitmap incompatible properties
+            s_strike_rot45, sz = f.render_raw('A', ptsize=19, rotation=45)
+            try:
+                f.strong = True
+                s_strike_strong, sz = f.render_raw('A', ptsize=19)
+            finally:
+                f.strong = False
+            try:
+                f.oblique = True
+                s_strike_oblique, sz = f.render_raw('A', ptsize=19)
+            finally:
+                f.oblique = False
+
+            # compare with use_bitmap_strikes == False
+            #
+            f.use_bitmap_strikes = False
+            self.assertFalse(f.use_bitmap_strikes)
+
+            # bitmap compatible properties
+            s_outline, sz = f.render_raw('A', ptsize=19)
+            self.assertNotEqual(s_outline, s_strike)
+            try:
+                f.vertical = True
+                s_outline, sz = f.render_raw('A', ptsize=19)
+                self.assertNotEqual(s_outline, s_strike_vert)
+            finally:
+                f.vertical = False
+            try:
+                f.wide = True
+                s_outline, sz = f.render_raw('A', ptsize=19)
+                self.assertNotEqual(s_outline, s_strike_wide)
+            finally:
+                f.wide = False
+            try:
+                f.underline = True
+                s_outline, sz = f.render_raw('A', ptsize=19)
+                self.assertNotEqual(s_outline, s_strike_underline)
+            finally:
+                f.underline = False
+
+            # bitmap incompatible properties
+            s_outline, sz = f.render_raw('A', ptsize=19, rotation=45)
+            self.assertEqual(s_outline, s_strike_rot45)
+            try:
+                f.strong = True
+                s_outline, sz = f.render_raw('A', ptsize=19)
+                self.assertEqual(s_outline, s_strike_strong)
+            finally:
+                f.strong = False
+            try:
+                f.oblique = True
+                s_outline, sz = f.render_raw('A', ptsize=19)
+                self.assertEqual(s_outline, s_strike_oblique)
+            finally:
+                f.oblique = False
+        finally:
+            f.use_bitmap_strikes = True
+
     def test_freetype_Font_get_metrics(self):
 
         font = self._TEST_FONTS['sans']