Commits

Lenard Lindstrom committed a3d81c1

freetype: add Font.path font file path attribute; add vertical argument to Font.__init__

  • Participants
  • Parent commits 84159e7

Comments (0)

Files changed (7)

File docs/reST/ref/freetype.rst

 Pygame comes with a builtin default font. This can always be accessed by
 passing None as the font name to the Font constructor.
 
+New in Pygame 1.9.2
+
 .. function:: get_error
 
    | :sl:`Get the latest error`
 .. class:: Font
 
    | :sl:`Creates a new Font from a supported font file.`
-   | :sg:`Font(file, style=STYLE_NONE, ptsize=-1, face_index=0, resolution=0) -> Font`
+   | :sg:`Font(file, style=STYLE_NONE, ptsize=-1, face_index=0, vertical=0, ucs4=0, resolution=0) -> Font`
 
    'file' can be either a string representing the font's filename, a file-like
    object containing the font, or None; in this last case the default, built-in
    used to draw this font. This style may be overriden on any ``Font.render()``
    call.
 
+   The optional vertical argument, an integer, sets the default orientation
+   for the font: 0 (False) for horizontal, any other value (True) for vertical.
+   See :attr:`Font.vertical`.
+
+   The optional ucs4 argument, an integer, sets the default text translation
+   mode: 0 (False) recognize UTF-16 surrogate pairs, any other value (True),
+   to treat unicode text as UCS-4, with no surrogate pairs. See
+   :attr:`Font.ucs4`.
+
    The optional resolution argument sets the pixel size, in dots per inch,
    to use for scaling glyphs for this Font instance. If 0 then the default
    module value, set by :meth:`freetype.init`, is used. The Font object's
 
       .. ## Font.name ##
 
+   .. attribute:: path
+
+      | :sl:`Gets the path of the font file`
+      | :sg:`path -> unicode`
+
+      Read only. Returns the path of the loaded font file
+
+      .. ## Font.path ##
+
    .. method:: get_size
 
       | :sl:`Gets the size of rendered text`

File src/doc/freetype_doc.h

 
 #define DOC_FONTNAME "Font.name -> string\nGets the name of the font face."
 
+#define DOC_FONTPATH "Font.path -> unicode\nGets the path of the font file"
+
 #define DOC_FONTGETSIZE "Font.get_size(text, style=STYLE_DEFAULT, rotation=0, ptsize=default, surrogates=True) -> (int, int)\nGets the size of rendered text"
 
 #define DOC_FONTGETMETRICS "Font.get_metrics(text, bbmode=BBOX_PIXEL_GRIDFIT, ptsize=default, surrogates=True) -> [(...), ...]\nGets glyph metrics for the font's characters"

File src/freetype.c

 static int _ftfont_setstyle(PyObject *self, PyObject *value, void *closure);
 static PyObject *_ftfont_getheight(PyObject *self, void *closure);
 static PyObject *_ftfont_getname(PyObject *self, void *closure);
+static PyObject *_ftfont_getpath(PyObject *self, void *closure);
 static PyObject *_ftfont_getfixedwidth(PyObject *self, void *closure);
 
 static PyObject *_ftfont_getvertical(PyObject *self, void *closure);
         DOC_FONTNAME,
         NULL 
     },
+    { 
+        "path", 
+        _ftfont_getpath, 
+        NULL,
+        DOC_FONTPATH,
+        NULL 
+    },
     {
         "fixed_width",
         _ftfont_getfixedwidth,
 {
     PyFreeTypeFont *obj = (PyFreeTypeFont *)(subtype->tp_alloc(subtype, 0));
     
-    if (obj != NULL) {
+    if (obj != NULL)
+    {
         obj->id.open_args.flags = 0;
+        obj->id.open_args.pathname = NULL;
+        obj->path = NULL;
         obj->resolution = 0;
         obj->_internals = NULL;
-        /* Set defaults here so not reset by __init__ */
         obj->ptsize = -1;
         obj->style = FT_STYLE_NORMAL;
         obj->vertical = 0;
         obj->antialias = 1;
-	obj->kerning = 0;
+        obj->kerning = 0;
         obj->ucs4 = 0;
     }
     return (PyObject *)obj;
      * a freetype instance. */
     PGFT_UnloadFont(FREETYPE_STATE->freetype, self);
 
+    Py_XDECREF(self->path);
     ((PyObject *)self)->ob_type->tp_free((PyObject *)self);
 }
 
 {
     static char *kwlist[] = 
     { 
-        "font", "ptsize", "style", "face_index", "ucs4", "resolution", NULL
+        "font", "ptsize", "style", "face_index", "vertical",
+        "ucs4", "resolution", NULL
     };
 
     PyFreeTypeFont *font = (PyFreeTypeFont *)self;
     int ptsize;
     int font_style;
     int ucs4;
+    int vertical;
     unsigned resolution = 0;
 
     FreeTypeInstance *ft;
     ptsize = font->ptsize;
     font_style = font->style;
     ucs4 = font->ucs4;
+    vertical = font->vertical;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiIiI", kwlist, 
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiIiiI", kwlist, 
                                      &file, &ptsize, &font_style, &face_index,
-                                     &ucs4, &resolution))
+                                     &vertical, &ucs4, &resolution))
         return -1;
 
     original_file = file;
 
     PGFT_UnloadFont(ft, font);
+    Py_XDECREF(font->path);
+    font->path = NULL;
     
-    /* TODO: Ask for vertical? */
-
     if (PGFT_CheckStyle(font_style))
     {
         PyErr_Format(PyExc_ValueError,
     font->ptsize = (FT_Int16)((ptsize <= 0) ? -1 : ptsize);
     font->style = (FT_Byte)font_style;
     font->ucs4 = ucs4 ? (FT_Byte)1 : (FT_Byte)0;
+    font->vertical = vertical;
     if (resolution)
     {
         font->resolution = (FT_UInt)resolution;
     }
     if (Bytes_Check(file))
     {
-        PGFT_TryLoadFont_Filename(ft, font, Bytes_AS_STRING(file), face_index);
+        if (PGFT_TryLoadFont_Filename(ft, font, Bytes_AS_STRING(file),
+                                      face_index))
+        {
+            goto end;
+        }
+	if (PyUnicode_Check(original_file))
+        {
+            /* Make sure to save a pure Unicode object to prevent possible
+             * cycles from a derived class. This means no tp_traverse or
+             * tp_clear for the PyFreetypeFont type.
+             */
+            font->path = Object_Unicode(original_file);
+        }
+        else
+        {
+            font->path = PyUnicode_FromEncodedObject(file, "unicode_escape",
+						     "replace");
+        }
     }
     else
     {
         SDL_RWops *source = RWopsFromFileObject(original_file);
+        PyObject *str = NULL;
+        PyObject *path = NULL;
 
         if (source == NULL)
         {
             goto end;
         }
 
-        if (PGFT_TryLoadFont_RWops(ft, font, source, face_index) != 0);
+        if (PGFT_TryLoadFont_RWops(ft, font, source, face_index))
         {
             goto end;
         }
+
+        path = PyObject_GetAttrString(original_file, "name");
+        if (!path)
+        {
+            PyErr_Clear();
+            str = Bytes_FromFormat("<%s instance at %p>",
+                                   Py_TYPE(file)->tp_name, (void *)file);
+            if (str)
+            {
+                font->path = PyUnicode_FromEncodedObject(str,
+                                                         "ascii", "strict");
+                Py_DECREF(str);
+            }
+        }
+	else if (PyUnicode_Check(path))
+        {
+            /* Make sure to save a pure Unicode object to prevent possible
+             * cycles from a derived class. This means no tp_traverse or
+             * tp_clear for the PyFreetypeFont type.
+             */
+            font->path = Object_Unicode(path);
+        }
+        else if (Bytes_Check(path))
+        {
+            font->path = PyUnicode_FromEncodedObject(file,
+                                               "unicode_escape", "replace");
+        }
+        else
+        {
+            font->path = Object_Unicode(path);
+        }
+        Py_XDECREF(path);
     }
 
 end:
     PyFreeTypeFont *font = (PyFreeTypeFont *)self;
 
     if (PyFreeTypeFont_IS_ALIVE(font))
-        return Text_FromFormat("Font('%.1024s')", font->id.open_args.pathname);
+    {
+#if PY3
+        return PyUnicode_FromFormat("Font('%.1024u')", font->path);
+#else
+        PyObject *str = PyUnicode_AsEncodedString(font->path,
+                                                  "raw_unicode_escape",
+                                                  "replace");
+        PyObject *rval = NULL;
+
+        if (str)
+        {
+            rval = PyString_FromFormat("Font('%.1024s')",
+                                       PyString_AS_STRING(str));
+            Py_DECREF(str);
+        }
+        return rval;
+#endif
+    }
     return Text_FromFormat("<uninitialized Font object at %p>", (void *)self);
 }
 
 }
 
 PyObject *
+_ftfont_getpath(PyObject *self, void *closure)
+{
+    PyObject *path = ((PyFreeTypeFont *)self)->path;
+
+    if (!path)
+    {
+        PyErr_SetString(PyExc_AttributeError, "path unavailable");
+        return NULL;
+    }
+    Py_INCREF(path);
+    return path;
+}
+
+PyObject *
 _ftfont_getfixedwidth(PyObject *self, void *closure)
 {
     FreeTypeInstance *ft;

File src/freetype.h

 {
     PyObject_HEAD
     FontId id;
+    PyObject *path;
 
     FT_Int16 ptsize;
     FT_Byte style;

File src/freetype/ft_wrap.c

     if (font->id.open_args.flags == FT_OPEN_STREAM)
     {
         _PGFT_free(font->id.open_args.pathname);
+	font->id.open_args.pathname = NULL;
     }
     else if (font->id.open_args.flags == FT_OPEN_PATHNAME)
     {

File src/pgcompat.h

 #define Bytes_AsString PyBytes_AsString
 #define Bytes_AsStringAndSize PyBytes_AsStringAndSize
 #define Bytes_FromStringAndSize PyBytes_FromStringAndSize
+#define Bytes_FromFormat PyBytes_FromFormat
 #define Bytes_AS_STRING PyBytes_AS_STRING
 #define Bytes_GET_SIZE PyBytes_GET_SIZE
+#define Bytes_AsDecodeObject PyBytes_AsDecodedObject
+
+#define Object_Unicode PyObject_Str
 
 #define IsTextObj(x) (PyUnicode_Check(x) || PyBytes_Check(x))
 
 #define Bytes_AsString PyString_AsString
 #define Bytes_AsStringAndSize PyString_AsStringAndSize
 #define Bytes_FromStringAndSize PyString_FromStringAndSize
+#define Bytes_FromFormat PyString_FromFormat
 #define Bytes_AS_STRING PyString_AS_STRING
 #define Bytes_GET_SIZE PyString_GET_SIZE
+#define Bytes_AsDecodedObject PyString_AsDecodedObject
+
+#define Object_Unicode PyObject_Unicode
 
 /* Renamed builtins */
 #define BUILTINS_MODULE "__builtin__"

File test/freetype_font_test.py

         finally:
             ft.set_default_resolution()
 
+    def test_freetype_Font_path(self):
+        self.assertEqual(self._TEST_FONTS['sans'].path, self._sans_path)
+        self.assertRaises(AttributeError, getattr, nullfont(), 'path')
+
 
 class FreeTypeFont(unittest.TestCase):