tarinaretake

git clone https://git.tarina.org/tarinaretake
Log | Files | Refs | README | LICENSE

font.c (9612B)


      1 /*
      2 Copyright (c) 2012, Broadcom Europe Ltd
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are met:
      7     * Redistributions of source code must retain the above copyright
      8       notice, this list of conditions and the following disclaimer.
      9     * Redistributions in binary form must reproduce the above copyright
     10       notice, this list of conditions and the following disclaimer in the
     11       documentation and/or other materials provided with the distribution.
     12     * Neither the name of the copyright holder nor the
     13       names of its contributors may be used to endorse or promote products
     14       derived from this software without specific prior written permission.
     15 
     16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
     20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27 
     28 // Font handling for graphicsx
     29 
     30 /** @file font.c
     31   *
     32   * Fairly primitive font handling, just enough to emulate the old API.
     33   *
     34   * Hinting and Font Size
     35   *
     36   * The old API does not create fonts explicitly, it just renders them
     37   * as needed. That works fine for unhinted fonts, but for hinted fonts we
     38   * care about font size.
     39   *
     40   * Since we now *can* do hinted fonts, we should do. Regenerating the
     41   * fonts each time becomes quite slow, so we maintain a cache of fonts.
     42   *
     43   * For the typical applications which use graphics_x this is fine, but
     44   * won't work well if lots of fonts sizes are used.
     45   *
     46   * Unicode
     47   *
     48   * This API doesn't support unicode at all at present, nor UTF-8.
     49   */
     50 
     51 #include <fcntl.h>
     52 #include <stdio.h>
     53 #include <unistd.h>
     54 #include <sys/types.h>
     55 
     56 #include "graphics_x_private.h"
     57 #include "vgft.h"
     58 
     59 #define VMCS_INSTALL_PREFIX ""
     60 
     61 /** The one and only (default) font we support for now.
     62   */
     63 static struct
     64 {
     65    const char *file;
     66    void *mem;
     67    size_t len;
     68 } default_font = { "VeraMono.ttf" };
     69 
     70 /** An entry in our list of fonts
     71   */
     72 typedef struct gx_font_cache_entry_t
     73 {
     74    struct gx_font_cache_entry_t *next;
     75    VGFT_FONT_T font;
     76    uint32_t ptsize;                    /** size in points, 26.6 */
     77 } gx_font_cache_entry_t;
     78 
     79 static char fname[128];
     80 static int inited;
     81 static gx_font_cache_entry_t *fonts;
     82 
     83 static VGFT_FONT_T *find_font(const char *text, uint32_t text_size);
     84 
     85 VCOS_STATUS_T gx_priv_font_init(const char *font_dir)
     86 {
     87    VCOS_STATUS_T ret;
     88    size_t len;
     89    int rc;
     90    if (vgft_init())
     91    {
     92       ret = VCOS_ENOMEM;
     93       goto fail_init;
     94    }
     95 
     96    int fd = -1;
     97    // search for the font
     98    sprintf(fname, "%s/%s", font_dir, default_font.file);
     99    fd = open(fname, O_RDONLY);
    100 
    101    if (fd < 0)
    102    {
    103       GX_ERROR("Could not open font file '%s'", default_font.file);
    104       ret = VCOS_ENOENT;
    105       goto fail_open;
    106    }
    107 
    108    len = lseek(fd, 0, SEEK_END);
    109    lseek(fd, 0, SEEK_SET);
    110 
    111    default_font.mem = vcos_malloc(len, default_font.file);
    112    if (!default_font.mem)
    113    {
    114       GX_ERROR("No memory for font %s", fname);
    115       ret = VCOS_ENOMEM;
    116       goto fail_mem;
    117    }
    118 
    119    rc = read(fd, default_font.mem, len);
    120    if (rc != len)
    121    {
    122       GX_ERROR("Could not read font %s", fname);
    123       ret = VCOS_EINVAL;
    124       goto fail_rd;
    125    }
    126    default_font.len = len;
    127    close(fd);
    128 
    129    GX_TRACE("Opened font file '%s'", fname);
    130 
    131    inited = 1;
    132    return VCOS_SUCCESS;
    133 
    134 fail_rd:
    135    vcos_free(default_font.mem);
    136 fail_mem:
    137    if (fd >= 0) close(fd);
    138 fail_open:
    139    vgft_term();
    140 fail_init:
    141    return ret;
    142 }
    143 
    144 void gx_priv_font_term(void)
    145 {
    146    gx_font_cache_flush();
    147    vgft_term();
    148    vcos_free(default_font.mem);
    149 }
    150 
    151 /** Render text.
    152   *
    153   * FIXME: Not at all optimal - re-renders each time.
    154   * FIXME: Not UTF-8 aware
    155   * FIXME: better caching
    156   */
    157 VCOS_STATUS_T gx_priv_render_text( GX_DISPLAY_T *disp,
    158                                    GRAPHICS_RESOURCE_HANDLE res,
    159                                    int32_t x,
    160                                    int32_t y,
    161                                    uint32_t width,
    162                                    uint32_t height,
    163                                    uint32_t fg_colour,
    164                                    uint32_t bg_colour,
    165                                    const char *text,
    166                                    uint32_t text_length,
    167                                    uint32_t text_size )
    168 {
    169    VGfloat vg_colour[4];
    170    VGFT_FONT_T *font;
    171    VGPaint fg;
    172    GX_CLIENT_STATE_T save;
    173    VCOS_STATUS_T status = VCOS_SUCCESS;
    174    int clip = 1;
    175 
    176    vcos_demand(inited); // has gx_font_init() been called?
    177 
    178    gx_priv_save(&save, res);
    179 
    180    if (width == GRAPHICS_RESOURCE_WIDTH &&
    181        height == GRAPHICS_RESOURCE_HEIGHT)
    182    {
    183       clip = 0;
    184    }
    185 
    186    width = (width == GRAPHICS_RESOURCE_WIDTH) ? res->width : width;
    187    height = (height == GRAPHICS_RESOURCE_HEIGHT) ? res->height : height;
    188    font = find_font(text, text_size);
    189    if (!font)
    190    {
    191       status = VCOS_ENOMEM;
    192       goto finish;
    193    }
    194 
    195    // setup the clipping rectangle
    196    if (clip)
    197    {
    198       VGint coords[] = {x,y,width,height};
    199       vgSeti(VG_SCISSORING, VG_TRUE);
    200       vgSetiv(VG_SCISSOR_RECTS, 4, coords);
    201    }
    202 
    203    // setup the background colour if needed
    204    if (bg_colour != GRAPHICS_TRANSPARENT_COLOUR)
    205    {
    206       int err;
    207       VGfloat rendered_w, rendered_h;
    208       VGfloat vg_bg_colour[4];
    209 
    210       // setup the background colour...
    211       gx_priv_colour_to_paint(bg_colour, vg_bg_colour);
    212       vgSetfv(VG_CLEAR_COLOR, 4, vg_bg_colour);
    213 
    214       // fill in a rectangle...
    215       vgft_get_text_extents(font, text, text_length, (VGfloat)x, (VGfloat)y, &rendered_w, &rendered_h);
    216 
    217       if ( ( 0 < (VGint)rendered_w ) && ( 0 < (VGint)rendered_h ) )
    218       {
    219          // Have to compensate for the messed up y position of multiline text.
    220          VGfloat offset = vgft_first_line_y_offset(font);
    221          int32_t bottom = y + offset - rendered_h;
    222 
    223          vgClear(x, bottom, (VGint)rendered_w, (VGint)rendered_h);
    224          err = vgGetError();
    225          if (err)
    226          {
    227             GX_LOG("Error %d clearing bg text %d %d %g %g",
    228                    err, x, y, rendered_w, rendered_h);
    229             vcos_assert(0);
    230          } // if
    231       } // if
    232    } // if
    233    // setup the foreground colour
    234    fg = vgCreatePaint();
    235    if (!fg)
    236    {
    237       status = VCOS_ENOMEM;
    238       goto finish;
    239    }
    240 
    241    // draw the foreground text
    242    vgSetParameteri(fg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
    243    gx_priv_colour_to_paint(fg_colour, vg_colour);
    244    vgSetParameterfv(fg, VG_PAINT_COLOR, 4, vg_colour);
    245    vgSetPaint(fg, VG_FILL_PATH);
    246 
    247    vgft_font_draw(font, (VGfloat)x, (VGfloat)y, text, text_length, VG_FILL_PATH);
    248 
    249    vgDestroyPaint(fg);
    250 
    251    vcos_assert(vgGetError() == 0);
    252    vgSeti(VG_SCISSORING, VG_FALSE);
    253 
    254 finish:
    255    gx_priv_restore(&save);
    256 
    257    return status;
    258 }
    259 
    260 
    261 /** Find a font in our cache, or create a new entry in the cache.
    262   *
    263   * Very primitive at present.
    264   */
    265 static VGFT_FONT_T *find_font(const char *text, uint32_t text_size)
    266 {
    267    int ptsize, dpi_x = 0, dpi_y = 0;
    268    VCOS_STATUS_T status;
    269    gx_font_cache_entry_t *font;
    270 
    271    ptsize = text_size << 6; // freetype takes size in points, in 26.6 format.
    272 
    273    for (font = fonts; font; font = font->next)
    274    {
    275       if (font->ptsize == ptsize)
    276          return &font->font;
    277    }
    278 
    279    font = vcos_malloc(sizeof(*font), "font");
    280    if (!font)
    281       return NULL;
    282 
    283    font->ptsize = ptsize;
    284 
    285    status = vgft_font_init(&font->font);
    286    if (status != VCOS_SUCCESS)
    287    {
    288       vcos_free(font);
    289       return NULL;
    290    }
    291 
    292    // load the font
    293    status = vgft_font_load_mem(&font->font, default_font.mem, default_font.len);
    294    if (status != VCOS_SUCCESS)
    295    {
    296       GX_LOG("Could not load font from memory: %d", status);
    297       vgft_font_term(&font->font);
    298       vcos_free(font);
    299       return NULL;
    300    }
    301 
    302    status = vgft_font_convert_glyphs(&font->font, ptsize, dpi_x, dpi_y);
    303    if (status != VCOS_SUCCESS)
    304    {
    305       GX_LOG("Could not convert font '%s' at size %d", fname, ptsize);
    306       vgft_font_term(&font->font);
    307       vcos_free(font);
    308       return NULL;
    309    }
    310 
    311    font->next = fonts;
    312    fonts = font;
    313 
    314    return &font->font;
    315 }
    316 
    317 void gx_font_cache_flush(void)
    318 {
    319    while (fonts != NULL)
    320    {
    321       struct gx_font_cache_entry_t *next = fonts->next;
    322       vgft_font_term(&fonts->font);
    323       vcos_free(fonts);
    324       fonts = next;
    325    }
    326 }
    327 
    328 int32_t graphics_resource_text_dimensions_ext(GRAPHICS_RESOURCE_HANDLE res,
    329                                               const char *text,
    330                                               const uint32_t text_length,
    331                                               uint32_t *width,
    332                                               uint32_t *height,
    333                                               const uint32_t text_size )
    334 {
    335    GX_CLIENT_STATE_T save;
    336    VGfloat w, h;
    337    int ret = -1;
    338 
    339    gx_priv_save(&save, res);
    340 
    341    VGFT_FONT_T *font = find_font(text, text_size);
    342    if (!font)
    343       goto finish;
    344 
    345 
    346    vgft_get_text_extents(font, text, text_length, 0.0, 0.0, &w, &h);
    347    *width = w;
    348    *height = h;
    349    ret = 0;
    350 
    351 finish:
    352    gx_priv_restore(&save);
    353    return ret;
    354 }
    355