/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /**********************************************************************************************************************/ static DFBResult Probe( IDirectFBFont_ProbeContext *ctx ); static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ); /**********************************************************************************************************************/ #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, DGIFF ) /**********************************************************************************************************************/ typedef struct { void *map; /* Memory map of the file. */ int size; /* Size of the memory map. */ } DGIFFImplData; /**********************************************************************************************************************/ static void IDirectFBFont_DGIFF_Destruct( IDirectFBFont *thiz ) { IDirectFBFont_data *data = thiz->priv; CoreFont *font = data->font; DGIFFImplData *impl = font->impl_data; munmap( impl->map, impl->size ); D_FREE( impl ); IDirectFBFont_Destruct( thiz ); } static DirectResult IDirectFBFont_DGIFF_Release( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA(IDirectFBFont) if (--data->ref == 0) { IDirectFBFont_DGIFF_Destruct( thiz ); } return DFB_OK; } static DFBResult Probe( IDirectFBFont_ProbeContext *ctx ) { DFBResult ret = DFB_OK; int fd; DGIFFHeader header; if (!ctx->filename) return DFB_UNSUPPORTED; /* Open the file. */ fd = open( ctx->filename, O_RDONLY ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "Font/DGIFF: Failure during open() of '%s'!\n", ctx->filename ); goto out; } /* Read the header. */ if (read( fd, &header, sizeof(header) ) != sizeof(header)) { ret = errno2result( errno ); D_PERROR( "Font/DGIFF: Failure reading %zu bytes from '%s'!\n", sizeof(header), ctx->filename ); goto out; } /* Check the magic. */ if (strncmp( (char*) header.magic, "DGIFF", 5 )) ret = DFB_UNSUPPORTED; out: if (fd >= 0) close( fd ); return ret; } static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ) { DFBResult ret; int i; int fd; struct stat stat; void *ptr = MAP_FAILED; CoreFont *font = NULL; DGIFFHeader *header; DGIFFFaceHeader *face; DGIFFGlyphInfo *glyphs; DGIFFGlyphRow *row; DGIFFImplData *data; char *filename; CoreSurfaceConfig config; // if (desc->flags & (DFDESC_WIDTH | DFDESC_ATTRIBUTES | DFDESC_FIXEDADVANCE)) // return DFB_UNSUPPORTED; /* use the filename for backwards compatibility */ filename = ctx->filename; if (desc->flags & DFDESC_ROTATION) return DFB_UNSUPPORTED; /* Open the file. */ fd = open( filename, O_RDONLY ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "Font/DGIFF: Failure during open() of '%s'!\n", filename ); return ret; } /* Query file size etc. */ if (fstat( fd, &stat ) < 0) { ret = errno2result( errno ); D_PERROR( "Font/DGIFF: Failure during fstat() of '%s'!\n", filename ); goto error; } /* Memory map the file. */ ptr = mmap( NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if (ptr == MAP_FAILED) { ret = errno2result( errno ); D_PERROR( "Font/DGIFF: Failure during mmap() of '%s'!\n", filename ); goto error; } /* Keep entry pointers for main header and face. */ header = ptr; face = ptr + sizeof(DGIFFHeader); /* Lookup requested face, otherwise use first if nothing requested or show error if not found. */ if (desc->flags & DFDESC_HEIGHT) { for (i=0; inum_faces; i++) { if (face->size == desc->height) break; face = ((void*) face) + face->next_face; } if (i == header->num_faces) { ret = DFB_UNSUPPORTED; D_ERROR( "Font/DGIFF: Requested size %d not found in '%s'!\n", desc->height, filename ); goto error; } } glyphs = (void*)(face + 1); row = (void*)(glyphs + face->num_glyphs); /* Create the core object. */ ret = dfb_font_create( core, desc, filename, &font ); if (ret) goto error; /* Fill font information. */ font->ascender = face->ascender; font->descender = face->descender; font->height = face->height; font->up_unit_x = 0.0; font->up_unit_y = -1.0; font->maxadvance = face->max_advance; font->pixel_format = face->pixelformat; font->surface_caps = DSCAPS_NONE; font->num_rows = face->num_rows; if (face->blittingflags) font->blittingflags = face->blittingflags; /* Allocate array for glyph cache rows. */ font->rows = D_CALLOC( face->num_rows, sizeof(void*) ); if (!font->rows) { ret = D_OOM(); goto error; } /* Build glyph cache rows. */ config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_PREALLOCATED; config.format = face->pixelformat; config.preallocated[1].addr = NULL; config.preallocated[1].pitch = 0; for (i=0; inum_rows; i++) { font->rows[i] = D_CALLOC( 1, sizeof(CoreFontCacheRow) ); if (!font->rows[i]) { ret = D_OOM(); goto error; } config.size.w = row->width; config.size.h = row->height; config.preallocated[0].addr = (void*)(row+1); config.preallocated[0].pitch = row->pitch; ret = dfb_surface_create( core, &config, CSTF_PREALLOCATED, 0, NULL, &font->rows[i]->surface ); if (ret) { D_DERROR( ret, "DGIFF/Font: Could not create preallocated %s %dx%d glyph row surface!\n", dfb_pixelformat_name(face->pixelformat), row->width, row->height ); goto error; } D_MAGIC_SET( font->rows[i], CoreFontCacheRow ); /* Jump to next row. */ row = (void*)(row + 1) + row->pitch * row->height; } /* Build glyph infos. */ for (i=0; inum_glyphs; i++) { CoreGlyphData *data; DGIFFGlyphInfo *glyph = &glyphs[i]; data = D_CALLOC( 1, sizeof(CoreGlyphData) ); if (!data) { ret = D_OOM(); goto error; } data->surface = font->rows[glyph->row]->surface; data->start = glyph->offset; data->width = glyph->width; data->height = glyph->height; data->left = glyph->left; data->top = glyph->top; data->xadvance = glyph->advance; data->yadvance = 0; D_MAGIC_SET( data, CoreGlyphData ); direct_hash_insert( font->layers[0].glyph_hash, glyph->unicode, data ); if (glyph->unicode < 128) font->layers[0].glyph_data[glyph->unicode] = data; } data = D_CALLOC( 1, sizeof(DGIFFImplData) ); if (!data) { ret = D_OOM(); goto error; } data->map = ptr; data->size = stat.st_size; font->impl_data = data; /* Already close, we still have the map. */ close( fd ); ret = IDirectFBFont_Construct( thiz, font ); D_ASSERT( ret == DFB_OK ); thiz->Release = IDirectFBFont_DGIFF_Release; return DFB_OK; error: if (font) { if (font->rows) { for (i=0; inum_rows; i++) { if (font->rows[i]) { if (font->rows[i]->surface) dfb_surface_unref( font->rows[i]->surface ); D_FREE( font->rows[i] ); } } D_FREE( font->rows ); font->rows = NULL; } dfb_font_destroy( font ); } if (ptr != MAP_FAILED) munmap( ptr, stat.st_size ); close( fd ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; }