Commits

Lenard Lindstrom committed 6427fd1

freetype.Font: Now supports (optional) font.Font style underline and bounding box

  • Participants
  • Parent commits c2d5114

Comments (0)

Files changed (8)

File docs/reST/ref/freetype.rst

       calculations unless overriden specifically in the \`render()` or
       \`get_size()` calls, via the 'style' parameter.
 
+   .. attribute:: underscore
+
+      | :sl:`Gets or sets the font's underscore style`
+      | :sg:`underscore -> bool`
+
+      Gets or sets whether the text will be underscored. Unlike underline,
+      the underscore is 1 pixel thick and is positioned descender pixels
+      below the baseline. This is for compatibility with font.Font.
+
    .. attribute:: bold
 
       | :sl:`Gets or sets the font's bold style`
       is taken to be that of the text origin. Otherwise the render position is
       the top-left corner of the text bounding box.
 
+   .. attribute:: pad
+
+      | :sl:`padded boundary mode`
+      | :sg:`pad -> bool`
+
+      If set True, then the text boundary rectangle will be inflated to match
+      that of font.Font. Otherwise, the boundary rectangle is just large
+      enough for the text.
+
    .. attribute:: ucs4
 
       | :sl:`Enables UCS-4 mode`

File docs/ref/freetype.html

 <td>—</td>
 <td>Gets or sets the font&#8217;s underline style</td>
 </tr>
+<tr><td><a class="toc reference external" href="freetype.html#pygame.freetype.Font.underscore">pygame.freetype.Font.underscore</a></td>
+<td>—</td>
+<td>Gets or sets the font&#8217;s underscore style</td>
+</tr>
 <tr><td><a class="toc reference external" href="freetype.html#pygame.freetype.Font.bold">pygame.freetype.Font.bold</a></td>
 <td>—</td>
 <td>Gets or sets the font&#8217;s bold style</td>
 <td>—</td>
 <td>Font render to text origin mode</td>
 </tr>
+<tr><td><a class="toc reference external" href="freetype.html#pygame.freetype.Font.pad">pygame.freetype.Font.pad</a></td>
+<td>—</td>
+<td>padded boundary mode</td>
+</tr>
 <tr><td><a class="toc reference external" href="freetype.html#pygame.freetype.Font.ucs4">pygame.freetype.Font.ucs4</a></td>
 <td>—</td>
 <td>Enables UCS-4 mode</td>
 </dd></dl>
 
 <dl class="definition attribute">
+<dt class="title" id="pygame.freetype.Font.underscore">
+<tt class="descname">underscore</tt><a class="headerlink" href="#pygame.freetype.Font.underscore" title="Permalink to this definition">¶</a></dt>
+<dd><div class="line-block">
+<div class="line"><span class="summaryline">Gets or sets the font&#8217;s underscore style</span></div>
+<div class="line"><span class="signature">underscore -&gt; bool</span></div>
+</div>
+<p>Gets or sets whether the text will be underscored. Unlike underline,
+the underscore is 1 pixel thick and is positioned descender pixels
+below the baseline. This is for compatibility with font.Font.</p>
+</dd></dl>
+
+<dl class="definition attribute">
 <dt class="title" id="pygame.freetype.Font.bold">
 <tt class="descname">bold</tt><a class="headerlink" href="#pygame.freetype.Font.bold" title="Permalink to this definition">¶</a></dt>
 <dd><div class="line-block">
 </dd></dl>
 
 <dl class="definition attribute">
+<dt class="title" id="pygame.freetype.Font.pad">
+<tt class="descname">pad</tt><a class="headerlink" href="#pygame.freetype.Font.pad" title="Permalink to this definition">¶</a></dt>
+<dd><div class="line-block">
+<div class="line"><span class="summaryline">padded boundary mode</span></div>
+<div class="line"><span class="signature">pad -&gt; bool</span></div>
+</div>
+<p>If set True, then the text boundary rectangle will be inflated to match
+that of font.Font. Otherwise, the boundary rectangle is just large
+enough for the text.</p>
+</dd></dl>
+
+<dl class="definition attribute">
 <dt class="title" id="pygame.freetype.Font.ucs4">
 <tt class="descname">ucs4</tt><a class="headerlink" href="#pygame.freetype.Font.ucs4" title="Permalink to this definition">¶</a></dt>
 <dd><div class="line-block">

File src/doc/freetype_doc.h

 
 #define DOC_FONTUNDERLINE "underline -> bool\nGets or sets the font's underline style"
 
+#define DOC_FONTUNDERSCORE "underscore -> bool\nGets or sets the font's underscore style"
+
 #define DOC_FONTBOLD "bold -> bool\nGets or sets the font's bold style"
 
 #define DOC_FONTOBLIQUE "oblique -> bool\nGets or sets the font's oblique style"
 
 #define DOC_FONTORIGIN "vertical -> bool\nFont render to text origin mode"
 
+#define DOC_FONTPAD "pad -> bool\npadded boundary mode"
+
 #define DOC_FONTUCS4 "ucs4 -> bool\nEnables UCS-4 mode"
 
 #define DOC_FONTRESOLUTION "resolution -> int\nOutput pixel resolution in dots per inch"
  underline -> bool
 Gets or sets the font's underline style
 
+pygame.freetype.Font.underscore
+ underscore -> bool
+Gets or sets the font's underscore style
+
 pygame.freetype.Font.bold
  bold -> bool
 Gets or sets the font's bold style
  vertical -> bool
 Font render to text origin mode
 
+pygame.freetype.Font.pad
+ pad -> bool
+padded boundary mode
+
 pygame.freetype.Font.ucs4
  ucs4 -> bool
 Enables UCS-4 mode

File src/freetype.c

 static int _ftfont_setucs4(PyObject *self, PyObject *value, void *closure);
 static PyObject *_ftfont_getorigin(PyObject *self, void *closure);
 static int _ftfont_setorigin(PyObject *self, PyObject *value, void *closure);
+static PyObject *_ftfont_getpad(PyObject *self, void *closure);
+static int _ftfont_setpad(PyObject *self, PyObject *value, void *closure);
 
 static PyObject *_ftfont_getresolution(PyObject *self, void *closure);
 
         NULL
     },
     {
+        "pad",
+        _ftfont_getpad,
+        _ftfont_setpad,
+        DOC_FONTPAD,
+        NULL
+    },
+    {
         "oblique",
         _ftfont_getstyle_flag,
         _ftfont_setstyle_flag,
         (void *)FT_STYLE_UNDERLINE
     },
     {
+        "underscore",
+        _ftfont_getstyle_flag,
+        _ftfont_setstyle_flag,
+        DOC_FONTUNDERSCORE,
+        (void *)FT_STYLE_UNDERSCORE
+    },
+    {
         "ucs4",
         _ftfont_getucs4,
         _ftfont_setucs4,
         obj->kerning = 0;
         obj->ucs4 = 0;
         obj->origin = 0;
+	obj->pad = 0;
         obj->do_transform = 0;
         obj->transform.xx = 0x00010000;
         obj->transform.xy = 0x00000000;
 }
 
 
+/** pad bounding box as font.Font does */
+PyObject *
+_ftfont_getpad(PyObject *self, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    
+    return PyBool_FromLong(font->pad);
+}
+
+int
+_ftfont_setpad(PyObject *self, PyObject *value, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    
+    if (!PyBool_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, "Expecting 'bool' type");
+        return -1;
+    }
+    font->pad = (FT_Byte)PyObject_IsTrue(value);
+    return 0;
+}
+
+
 /** resolution pixel size attribute */
 PyObject *
 _ftfont_getresolution(PyObject *self, void *closure)
     DEC_CONST(STYLE_BOLD);
     DEC_CONST(STYLE_OBLIQUE);
     DEC_CONST(STYLE_UNDERLINE);
+    DEC_CONST(STYLE_UNDERSCORE);
 
     DEC_CONST(BBOX_EXACT);
     DEC_CONST(BBOX_EXACT_GRIDFIT);

File src/freetype.h

 #define FT_STYLE_BOLD       0x01
 #define FT_STYLE_OBLIQUE    0x02
 #define FT_STYLE_UNDERLINE  0x04
+#define FT_STYLE_UNDERSCORE 0x08
 #define FT_STYLE_DEFAULT    0xFF
 
 /* Bounding box modes */
 #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_DEFAULTS       (FT_RFLAG_NONE | FT_RFLAG_HINTED)
 
 
     FT_Byte ucs4;
     FT_UInt resolution;
     FT_Byte origin;
+    FT_Byte pad;
     FT_Byte do_transform;
     FT_Matrix transform;
 

File src/freetype/ft_render.c

 #include FT_MODULE_H
 #include FT_OUTLINE_H
 
-#define SLANT_FACTOR    0.22
-FT_Matrix PGFT_SlantMatrix = 
-{
-    (1 << 16),  (FT_Fixed)(SLANT_FACTOR * (1 << 16)),
-    0,          (1 << 16) 
-};
-
 static int _PGFT_Render_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
                                  FontText *text, const FontRenderMode *render,
                                  FontColor *fg_color, FontSurface *surface);
         FT_STYLE_NORMAL |
         FT_STYLE_BOLD   |
         FT_STYLE_OBLIQUE |
-        FT_STYLE_UNDERLINE;
+        FT_STYLE_UNDERLINE |
+        FT_STYLE_UNDERSCORE;
 
     return (style > max_style);
 }
     if (font->antialias)
         mode->render_flags |= FT_RFLAG_ANTIALIAS;
 
+    if (font->pad)
+        mode->render_flags |= FT_RFLAG_PAD;
+
     angle = rotation % 360;
     while (angle < 0) angle += 360;
     mode->rotation_angle = PGFT_INT_TO_16(angle);
             render_mono(x, y, surface, &(image->bitmap), fg_color);
     }
 
-    if (text->underline_size > 0)
+    if (render->style & FT_STYLE_UNDERLINE)
     {
         surface->fill(
             PGFT_TRUNC(PGFT_CEIL(left - text->offset.x)),
             surface, fg_color);
     }
 
+    if (render->style & FT_STYLE_UNDERSCORE)
+    {
+        surface->fill(
+            PGFT_TRUNC(PGFT_CEIL(left - text->offset.x)),
+            PGFT_TRUNC(PGFT_CEIL(top - text->descender)),
+            text->width, 1, surface, fg_color);
+    }
+
     if (error)
     {
         RAISE(PyExc_SDLError, "(exception under construction)"

File src/freetype/ft_text.c

 #include FT_BITMAP_H
 #include FT_CACHE_H
 
+#define FX6_ONE 64
+#define FX16_ONE 65536
+
 #define SLANT_FACTOR    0.22
 static FT_Matrix PGFT_SlantMatrix = 
 {
-    (1 << 16),  (FT_Fixed)(SLANT_FACTOR * (1 << 16)),
-    0,          (1 << 16) 
+    FX16_ONE,  (FT_Fixed)(SLANT_FACTOR * FX16_ONE),
+    0,         FX16_ONE 
 };
 
 static FT_Matrix PGFT_Unit =
 {
-    (1 << 16),  0,
-    0,          (1 << 16) 
+    FX16_ONE,  0,
+    0,         FX16_ONE 
 };
 
 typedef struct __fonttextcontext
 
     FT_Vector   *next_pos;
 
-    int         vertical = font->vertical;
+    int         vertical = render->render_flags & FT_RFLAG_VERTICAL;
     int         use_kerning = font->kerning;
+    int         pad = render->render_flags & FT_RFLAG_PAD;
     FT_UInt     prev_glyph_index = 0;
 
     /* All these are 16.16 precision */
     }
     ftext->length = string_length;
     ftext->underline_pos = ftext->underline_size = 0;
+    ftext->descender = face->size->metrics.descender;
 
     /* fill it with the glyphs */
     fill_context(&context, ft, font, render, face);
         ++next_pos;
     }
 
+    if (pad && rotation_angle == 0)
+    {
+        FT_Size_Metrics *sz_metrics = &face->size->metrics;
+
+        if (pen.x > max_x)
+            max_x = pen.x;
+        else if (pen.x < min_x)
+            min_x = pen.x;
+        if (pen.y > max_y)
+            max_y = pen.y;
+        else if (pen.y < min_y)
+            min_y = pen.y;
+        if (vertical)
+        {
+            FT_Fixed right = sz_metrics->max_advance / 2;
+            
+            if (max_x < right)
+                max_x = right;
+            if (min_x > -right)
+                min_x = -right;
+            if (min_y > 0)
+                min_y = 0;
+            else if (max_y < pen.y)
+                max_y = pen.y;
+        }
+        else
+        {
+            FT_Fixed ascender = sz_metrics->ascender;
+            FT_Fixed descender = sz_metrics->descender;
+
+            if (min_x > 0)
+                min_x = 0;
+            if (max_x < pen.x)
+                max_x = pen.x;
+            if (min_y > -ascender)
+                min_y = -ascender;
+            if (max_y <= -descender)
+                max_y = -descender + /* underscore allowance */ FX6_ONE;
+            else
+            {
+                ftext->descender = -max_y;
+                max_y += FX6_ONE;
+            }
+        }
+    }
+    else if (render->style & FT_STYLE_UNDERSCORE && !vertical &&
+             rotation_angle == 0)
+    {
+        if (-ftext->descender >= max_y)
+            max_y = -ftext->descender + /* underscore allowance */ FX6_ONE;
+        else
+            ftext->descender = -max_y;
+    }
+
     if (render->style & FT_STYLE_UNDERLINE && !vertical && rotation_angle == 0)
     {
-        FT_Fixed scale;
+        FT_Fixed scale = face->size->metrics.y_scale;
         FT_Fixed underline_pos;
         FT_Fixed underline_size;
         FT_Fixed max_y_underline;
         
-        scale = face->size->metrics.y_scale;
-
         underline_pos = -FT_MulFix(face->underline_position, scale) / 4; /*(1)*/
         underline_size = FT_MulFix(face->underline_thickness, scale) + bold_str;
         max_y_underline = underline_pos + underline_size / 2;

File src/freetype/ft_wrap.h

 
     FT_Vector offset;
     FT_Vector advance;
-    FT_Pos   underline_size;
-    FT_Pos   underline_pos;
+    FT_Pos    underline_size;
+    FT_Pos    underline_pos;
+    FT_Pos    descender;
 
     int       buffer_size;
     FontGlyph **glyphs;