From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/src/core/fonts.c | 660 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100755 Source/DirectFB/src/core/fonts.c (limited to 'Source/DirectFB/src/core/fonts.c') diff --git a/Source/DirectFB/src/core/fonts.c b/Source/DirectFB/src/core/fonts.c new file mode 100755 index 0000000..2e6b599 --- /dev/null +++ b/Source/DirectFB/src/core/fonts.c @@ -0,0 +1,660 @@ +/* + (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 +#include + + +D_DEBUG_DOMAIN( Core_Font, "Core/Font", "DirectFB Core Font" ); +D_DEBUG_DOMAIN( Core_FontSurfaces, "Core/Font/Surf", "DirectFB Core Font Surfaces" ); + +/**********************************************************************************************************************/ + +static bool free_glyphs( DirectHash *hash, + unsigned long key, + void *value, + void *ctx ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_create( CoreDFB *core, + const DFBFontDescription *description, + const char *url, + CoreFont **ret_font ) +{ + DFBResult ret; + int i; + CoreFont *font; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_ASSERT( core != NULL ); + D_ASSERT( ret_font != NULL ); + + font = D_CALLOC( 1, sizeof(CoreFont) ); + if (!font) + return D_OOM(); + + for (i=0; ilayers[i].glyph_hash ); + if (ret) { + while (i--) + direct_hash_destroy( font->layers[i].glyph_hash ); + + D_FREE( font ); + return ret; + } + } + + font->description = *description; + font->url = D_STRDUP( url ); + + font->core = core; + font->max_rows = 2; + + direct_util_recursive_pthread_mutex_init( &font->lock ); + + /* the proposed pixel_format, may be changed by the font provider */ + font->pixel_format = dfb_config->font_format ? : DSPF_A8; + + if ((font->pixel_format == DSPF_ARGB || font->pixel_format == DSPF_ARGB4444) && dfb_config->font_premult) + font->surface_caps = DSCAPS_PREMULTIPLIED; + + font->blittingflags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE; + + D_MAGIC_SET( font, CoreFont ); + + *ret_font = font; + + return DFB_OK; +} + +void +dfb_font_destroy( CoreFont *font ) +{ + int i; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + + D_MAGIC_CLEAR( font ); + + D_FREE( font->url ); + + pthread_mutex_lock( &font->lock ); + + for (i=0; ilayers[i].glyph_hash, free_glyphs, NULL ); + + direct_hash_destroy( font->layers[i].glyph_hash ); + } + + if (font->rows) { + for (i = 0; i < font->num_rows; i++) { + CoreFontCacheRow *row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + dfb_surface_unref( row->surface ); + + D_MAGIC_CLEAR( row ); + + D_FREE( row ); + } + + D_FREE( font->rows ); + } + + D_ASSERT( font->encodings != NULL || !font->last_encoding ); + + for (i=DTEID_OTHER; i<=font->last_encoding; i++) { + CoreFontEncoding *encoding = font->encodings[i]; + + D_ASSERT( encoding != NULL ); + D_ASSERT( encoding->name != NULL ); + + D_MAGIC_CLEAR( encoding ); + + D_FREE( encoding->name ); + D_FREE( encoding ); + } + + if (font->encodings) + D_FREE( font->encodings ); + + pthread_mutex_unlock( &font->lock ); + pthread_mutex_destroy( &font->lock ); + + D_FREE( font ); +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_get_glyph_data( CoreFont *font, + unsigned int index, + unsigned int layer, + CoreGlyphData **ret_data ) +{ + DFBResult ret; + CoreGlyphData *data; + int i; + int align; + CoreFontCacheRow *row = NULL; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( ret_data != NULL ); + + D_ASSERT( layer < D_ARRAY_SIZE(font->layers) ); + D_ASSERT( font->num_rows >= 0 ); + + if (font->num_rows) { + D_ASSERT( font->num_rows <= font->max_rows || font->max_rows < 0 ); + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + } + + if (index < 128 && font->layers[layer].glyph_data[index]) { + data = font->layers[layer].glyph_data[index]; + if (data->failed) + goto retry; + + *ret_data = font->layers[layer].glyph_data[index]; + return DFB_OK; + } + + data = direct_hash_lookup( font->layers[layer].glyph_hash, index ); + if (data) { + D_MAGIC_ASSERT( data, CoreGlyphData ); + + if (font->rows) { + D_ASSERT( data->row >= 0 ); + D_ASSERT( data->row < font->num_rows ); + + row = font->rows[data->row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + row->stamp = font->row_stamp++; + } + + if (data->failed) + goto retry; + + *ret_data = data; + return DFB_OK; + } + + if (!font->GetGlyphData) + return DFB_UNSUPPORTED; + + data = D_CALLOC( 1, sizeof(CoreGlyphData) ); + if (!data) + return D_OOM(); + + D_MAGIC_SET( data, CoreGlyphData ); + + data->index = index; + data->layer = layer; + +retry: + data->failed = false; + + ret = font->GetGlyphData( font, index, data ); + if (ret) { + D_DERROR( ret, "Core/Font: Could not get glyph info for index %d!\n", index ); + data->start = data->width = data->height = 0; + data->failed = true; + goto out; + } + + if (data->width < 1 || data->height < 1) { + data->start = data->width = data->height = 0; + goto out; + } + + if (font->rows) { + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + + row = font->rows[font->active_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + } + else { + /* Calculate row width? */ + if (font->row_width == 0) { + int width = 2048 * font->height / 64; + + if (width > 2048) + width = 2048; + + if (width < font->maxadvance) + width = font->maxadvance; + + font->row_width = (width + 7) & ~7; + } + } + + /* Need another font surface? */ + if (!row || (row->next_x + data->width > font->row_width)) { + D_ASSERT( font->max_rows != 0 ); + + /* Maximum number of rows reached? */ + if (font->num_rows == font->max_rows) { + int best_row = -1; + unsigned int best_val = 0; + + /* Check for trailing space first. */ + for (i=0; inum_rows; i++) { + row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + if (row->next_x + data->width <= font->row_width) { + if (best_row == -1 || best_val < row->next_x) { + best_row = i; + best_val = row->next_x; + } + } + } + + /* Found a row with enough trailing space? */ + if (best_row != -1) { + font->active_row = best_row; + row = font->rows[best_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + D_DEBUG_AT( Core_FontSurfaces, " -> using trailing space of row %d - %dx%d %s\n", + font->active_row, row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + } + else { + CoreGlyphData *d, *n; + + D_ASSERT( best_row == -1 ); + D_ASSERT( best_val == 0 ); + + /* Reuse the least recently used row. */ + for (i=0; inum_rows; i++) { + row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + if (best_row == -1 || best_val > row->stamp) { + best_row = i; + best_val = row->stamp; + } + } + + D_ASSERT( best_row != -1 ); + + font->active_row = best_row; + row = font->rows[best_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + D_DEBUG_AT( Core_FontSurfaces, " -> reusing row %d - %dx%d %s\n", + font->active_row, row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + + /* Kick out all glyphs. */ + direct_list_foreach_safe (d, n, row->glyphs) { + D_MAGIC_ASSERT( d, CoreGlyphData ); + D_ASSERT( d->layer < D_ARRAY_SIZE(font->layers) ); + + /*ret =*/ direct_hash_remove( font->layers[d->layer].glyph_hash, d->index ); + //FIXME: use D_ASSERT( ret == DFB_OK ); + + if (d->index < 128) + font->layers[d->layer].glyph_data[d->index] = NULL; + + D_MAGIC_CLEAR( d ); + D_FREE( d ); + } + + /* Reset row. */ + row->glyphs = NULL; + row->next_x = 0; + } + } + else { + /* Allocate new font cache row structure. */ + row = D_CALLOC( 1, sizeof(CoreFontCacheRow) ); + if (!row) { + ret = D_OOM(); + goto error; + } + + /* Create a new font surface. */ + ret = dfb_surface_create_simple( font->core, + font->row_width, + MAX( font->height + 1, 8 ), + font->pixel_format, + font->surface_caps, CSTF_FONT, + 0 /* FIXME: no shared fonts, no font id */, + NULL, &row->surface ); + if (ret) { + D_DERROR( ret, "Core/Font: Could not create font surface!\n" ); + D_FREE( row ); + goto error; + } + + D_DEBUG_AT( Core_FontSurfaces, " -> new row %d - %dx%d %s\n", font->num_rows, + row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + + D_MAGIC_SET( row, CoreFontCacheRow ); + + + /* Append to array. FIXME: Use vector to avoid realloc each time! */ + font->rows = D_REALLOC( font->rows, sizeof(void*) * (font->num_rows + 1) ); + D_ASSERT( font->rows != NULL ); + + font->rows[font->num_rows] = row; + + /* Set new row to use. */ + font->active_row = font->num_rows++; + } + } + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + D_ASSERT( font->num_rows > 0 ); + D_ASSERT( font->num_rows <= font->max_rows || font->max_rows < 0 ); + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + D_ASSERT( row == font->rows[font->active_row] ); + + D_DEBUG_AT( Core_FontSurfaces, " -> render %2d - %2dx%2d at %d:%03d font <%p>\n", + index, data->width, data->height, font->active_row, row->next_x, font ); + + data->row = font->active_row; + data->start = row->next_x; + data->surface = row->surface; + + align = (8 / (DFB_BYTES_PER_PIXEL( font->pixel_format ) ? : 1)) * + (DFB_PIXELFORMAT_ALIGNMENT( font->pixel_format ) + 1) - 1; + + row->next_x += (data->width + align) & ~align; + + row->stamp = font->row_stamp++; + + /* Render the glyph data into the surface. */ + ret = font->RenderGlyph( font, index, data ); + if (ret) { + data->start = data->width = data->height = 0; + data->failed = true; + goto out; + } + + dfb_gfxcard_flush_texture_cache(); + + +out: + if (!data->inserted) { + if (row) + direct_list_append( &row->glyphs, &data->link ); + + direct_hash_insert( font->layers[layer].glyph_hash, index, data ); + + if (index < 128) + font->layers[layer].glyph_data[index] = data; + + data->inserted = true; + } + + *ret_data = data; + + return DFB_OK; + + +error: + D_MAGIC_CLEAR( data ); + D_FREE( data ); + + return ret; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_register_encoding( CoreFont *font, + const char *name, + const CoreFontEncodingFuncs *funcs, + DFBTextEncodingID encoding_id ) +{ + CoreFontEncoding *encoding; + CoreFontEncoding **encodings; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( encoding_id == DTEID_UTF8 || name != NULL ); + D_ASSERT( funcs != NULL ); + + if (!funcs->GetCharacterIndex) + return DFB_INVARG; + + /* Special case for default, native format. */ + if (encoding_id == DTEID_UTF8) { + font->utf8 = funcs; + + return DFB_OK; + } + + if (!funcs->DecodeText) + return DFB_INVARG; + + /* Setup new encoding information. */ + encoding = D_CALLOC( 1, sizeof(CoreFontEncoding) ); + if (!encoding) + return D_OOM(); + + encoding->encoding = font->last_encoding + 1; + encoding->funcs = funcs; + encoding->name = D_STRDUP( name ); + + if (!encoding->name) { + D_FREE( encoding ); + return D_OOM(); + } + + /* Add to array. */ + encodings = D_REALLOC( font->encodings, + (encoding->encoding + 1) * sizeof(CoreFontEncoding*) ); + if (!encodings) { + D_FREE( encoding->name ); + D_FREE( encoding ); + return D_OOM(); + } + + font->encodings = encodings; + + font->last_encoding++; + + D_ASSERT( font->last_encoding == encoding->encoding ); + + encodings[encoding->encoding] = encoding; + + D_MAGIC_SET( encoding, CoreFontEncoding ); + + return DFB_OK; +} + +DFBResult +dfb_font_decode_text( CoreFont *font, + DFBTextEncodingID encoding, + const void *text, + int length, + unsigned int *ret_indices, + int *ret_num ) +{ + int pos = 0, num = 0; + const u8 *bytes = text; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( text != NULL ); + D_ASSERT( length >= 0 ); /* TODO: handle -1 here? */ + D_ASSERT( ret_indices != NULL ); + D_ASSERT( ret_num != NULL ); + + if (encoding != DTEID_UTF8) { + if (encoding > font->last_encoding) + return DFB_IDNOTFOUND; + + D_ASSERT( font->encodings[encoding] != NULL ); + D_ASSERT( font->encodings[encoding]->funcs != NULL ); + D_ASSERT( font->encodings[encoding]->funcs->DecodeText != NULL ); + + return font->encodings[encoding]->funcs->DecodeText( font, text, length, + ret_indices, ret_num ); + } + else if (font->utf8) { + const CoreFontEncodingFuncs *funcs = font->utf8; + + if (funcs->DecodeText) + return funcs->DecodeText( font, text, length, ret_indices, ret_num ); + + D_ASSERT( funcs->GetCharacterIndex != NULL ); + + while (pos < length) { + unsigned int c; + + if (bytes[pos] < 128) + c = bytes[pos++]; + else { + c = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); + pos += DIRECT_UTF8_SKIP(bytes[pos]); + } + + if (funcs->GetCharacterIndex( font, c, &ret_indices[num] ) == DFB_OK) + num++; + } + + } + else { + while (pos < length) { + if (bytes[pos] < 128) + ret_indices[num++] = bytes[pos++]; + else { + ret_indices[num++] = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); + pos += DIRECT_UTF8_SKIP(bytes[pos]); + } + } + } + + *ret_num = num; + + return DFB_OK; +} + +DFBResult +dfb_font_decode_character( CoreFont *font, + DFBTextEncodingID encoding, + u32 character, + unsigned int *ret_index ) +{ + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( ret_index != NULL ); + + if (encoding > font->last_encoding) + return DFB_IDNOTFOUND; + + if (encoding != DTEID_UTF8) { + D_ASSERT( font->encodings[encoding] != NULL ); + D_ASSERT( font->encodings[encoding]->funcs != NULL ); + D_ASSERT( font->encodings[encoding]->funcs->GetCharacterIndex != NULL ); + + return font->encodings[encoding]->funcs->GetCharacterIndex( font, character, ret_index ); + } + else if (font->utf8) { + const CoreFontEncodingFuncs *funcs = font->utf8; + + D_ASSERT( funcs->GetCharacterIndex != NULL ); + + return funcs->GetCharacterIndex( font, character, ret_index ); + } + else + *ret_index = character; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static bool +free_glyphs( DirectHash *hash, + unsigned long key, + void *value, + void *ctx ) +{ + CoreGlyphData *data = value; + + D_MAGIC_ASSERT( data, CoreGlyphData ); + + D_MAGIC_CLEAR( data ); + D_FREE( data ); + + return true; +} + -- cgit