Files
MiniGUI/src/font/bitmapfont.c
T

691 lines
18 KiB
C

/*
* This file is part of MiniGUI, a mature cross-platform windowing
* and Graphics User Interface (GUI) support system for embedded systems
* and smart IoT devices.
*
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
* Copyright (C) 1998~2002, WEI Yongming
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Or,
*
* As this program is a library, any link to this program must follow
* GNU General Public License version 3 (GPLv3). If you cannot accept
* GPLv3, you need to be licensed from FMSoft.
*
* If you have got a commercial license of this program, please use it
* under the terms and conditions of the commercial license.
*
* For more information about the commercial license, please refer to
* <http://www.minigui.com/en/about/licensing-policy/>.
*/
/*
** bitmapfont.c: The Bitmap Font operation set.
**
** Create date: 2007/09/22
*/
#include "common.h"
#ifdef _MGFONT_BMPF
#include "minigui.h"
#include "gdi.h"
#include "cliprect.h"
#include "gal.h"
#include "window.h"
#include "internals.h"
#include "ctrlclass.h"
#include "dc.h"
#include "readbmp.h"
#include "devfont.h"
#include "charset.h"
#include "fontname.h"
#include "bitmapfont.h"
#if 0
/* default bitmap glyph */
static unsigned char def_bitmap [] = {0xFE, 0x7F};
static int def_glyph_height = 2;
static int def_glyph_width = 8;
#endif
/* default bitmap glyph */
static unsigned char def_glyph [] = {0};
#define DEFGLYPHWIDTH 8
/*** tree ops ***/
/*
* rebalance the tree.
*/
static int rebalance (GLYPHTREENODE **root, int *l, int *m)
{
if ( *root ) {
int ll, lm, ml, mm;
*l = rebalance (&(*root)->left, &ll, &lm);
*m = rebalance (&(*root)->right, &ml, &mm);
if ( (*root)->right ) {
if ( *l + ml + 1 < mm ) {
/* Shift less-ward */
GLYPHTREENODE* b = *root;
GLYPHTREENODE* c = (*root)->right;
*root = c;
b->right = c->left;
c->left = b;
}
}
if ( (*root)->left ) {
if ( *m + lm + 1 < ll ) {
/* Shift more-ward */
GLYPHTREENODE* c = *root;
GLYPHTREENODE* b = (*root)->left;
*root = b;
c->left = b->right;
b->right = c;
}
}
return 1 + *l + *m;
}
else {
*l = *m = 0;
return 0;
}
}
/*
* insert a node
*/
static void insert (GLYPHTREENODE *root, int min, int max,
int glyph_width, BITMAP *bmp)
{
if (max < root->min) {
if (!root->left) {
root->left = (GLYPHTREENODE *) calloc (sizeof (GLYPHTREENODE), 1);
root->left->min = min;
root->left->max = max;
}
insert (root->left, min, max, glyph_width, bmp);
return;
}
else if (min > root->max) {
if (!root->right) {
root->right = (GLYPHTREENODE *) calloc (sizeof (GLYPHTREENODE),
1);
root->right->min = min;
root->right->max = max;
}
insert (root->right, min, max, glyph_width, bmp);
return;
}
else if (min == root->min &&
max == root->max &&
root->nr_glyphs == 0) {
root->data = bmp;
root->nr_glyphs = max - min + 1;
root->glyph_width = glyph_width;
}
return;
}
/* Search in the glyph segment tree and return the pointer to tree node */
static GLYPHTREENODE *look_up (GLYPHTREENODE *root, int offset)
{
GLYPHTREENODE *p;
for (p = root; p; )
{
if (offset < p->min)
p = p->left;
else if (offset > p->max)
p = p->right;
else /* found */
return p;
}
return NULL;
}
/* Destroy segment glyph segment tree */
static void destroy (GLYPHTREENODE *root)
{
GLYPHTREENODE *p, *q;
for (p = root; p; p = q)
if (p->left == NULL) {
q = p->right;
free (p);
}
else
{
q = p->left;
p->left = q->right;
q->right = p;
}
return;
}
/*** device font ops ***/
static DWORD get_glyph_bmptype (LOGFONT* logfont, DEVFONT* devfont)
{
return DEVFONTGLYPHTYPE_PRERDRBMP;
}
static int get_ave_width (LOGFONT* logfont, DEVFONT* devfont)
{
return ((BMPFONTINFO *)devfont->data)->ave_width;
}
static int get_max_width (LOGFONT* logfont, DEVFONT* devfont)
{
return ((BMPFONTINFO *)devfont->data)->max_width;
}
static int get_font_height (LOGFONT* logfont, DEVFONT* devfont)
{
return ((BMPFONTINFO *)devfont->data)->height;
}
static int get_font_size (LOGFONT* logfont, DEVFONT* devfont, int expect, int df_slot)
{
if (df_slot >= 0 && df_slot < MAXNR_DEVFONTS)
SET_DEVFONT_SCALE (logfont, df_slot, 1);
return ((BMPFONTINFO *)devfont->data)->height;
}
static int get_font_ascent (LOGFONT* logfont, DEVFONT* devfont)
{
int height = ((BMPFONTINFO *)devfont->data)->height;
if (height >= 40)
return height - 6;
else if (height >= 20)
return height - 3;
else if (height >= 15)
return height - 2;
else if (height >= 10)
return height - 1;
return height;
}
static int get_font_descent (LOGFONT* logfont, DEVFONT* devfont)
{
int height = ((BMPFONTINFO *)devfont->data)->height;
if (height >= 40)
return 6;
else if (height >= 20)
return 3;
else if (height >= 15)
return 2;
else if (height >= 10)
return 1;
return 0;
}
static int
get_glyph_prbitmap (LOGFONT* logfont, DEVFONT* devfont,
Glyph32 glyph_value, BITMAP *bmp)
{
GLYPHTREENODE *node = NULL;
BMPFONTINFO *bmpfont_info = (BMPFONTINFO *)devfont->data;
GLYPHTREENODE *root = bmpfont_info->tree;
CHARSETOPS* charset_ops = devfont->charset_ops;
if (charset_ops == NULL)
return 0;
node = look_up (root, glyph_value);
if (node == NULL) {
bmp->bmType = BMP_TYPE_NORMAL;
bmp->bmColorKey = 0;
bmp->bmAlpha = 0;
bmp->bmAlphaMask = NULL;
bmp->bmAlphaPitch = 0;
bmp->bmBits = def_glyph;
bmp->bmWidth = 0;
bmp->bmHeight = 0;
bmp->bmPitch = 0;
_DBG_PRINTF ("FONT>Bitmap: "
"Glyph %d does not exist and is replaced with default glyph. \n",
glyph_value);
return 1;
}
bmp->bmType = node->data->bmType;
bmp->bmBitsPerPixel = node->data->bmBitsPerPixel;
bmp->bmBytesPerPixel = node->data->bmBytesPerPixel;
bmp->bmColorKey = node->data->bmColorKey;
bmp->bmWidth = node->glyph_width;
bmp->bmHeight = bmpfont_info->height;
bmp->bmPitch = node->data->bmPitch;
bmp->bmBits = node->data->bmBits;
bmp->bmBits += node->glyph_width * (glyph_value - node->min) *
node->data->bmBytesPerPixel;
if(node->data->bmAlphaMask) {
bmp->bmAlphaMask = node->data->bmAlphaMask + node->glyph_width * (glyph_value - node->min);
bmp->bmAlphaPitch = node->data->bmAlphaPitch;
}
return 1;
}
static BOOL is_glyph_existed (LOGFONT* logfont, DEVFONT* devfont, Glyph32 glyph_value)
{
GLYPHTREENODE *node = NULL;
BMPFONTINFO *bmpfont_info = (BMPFONTINFO *)devfont->data;
GLYPHTREENODE *root = bmpfont_info->tree;
CHARSETOPS* charset_ops = devfont->charset_ops;
if (charset_ops == NULL)
return FALSE;
node = look_up (root, glyph_value);
if (node == NULL)
return FALSE;
else
return TRUE;
}
static int get_glyph_advance (LOGFONT* logfont, DEVFONT* devfont,
Glyph32 glyph_value, int* px, int* py)
{
GLYPHTREENODE *node = NULL;
BMPFONTINFO *bmpfont_info = (BMPFONTINFO *)devfont->data;
GLYPHTREENODE *root = bmpfont_info->tree;
int advance;
node = look_up (root, glyph_value);
if (node == NULL) {
advance = DEFGLYPHWIDTH;
*px += advance;
}
else {
advance = node->glyph_width;
*px += advance;
}
return advance;
}
static int get_glyph_bbox (LOGFONT* logfont, DEVFONT* devfont,
Glyph32 glyph_value, int* px, int* py, int* pwidth, int* pheight)
{
GLYPHTREENODE *node = NULL;
BMPFONTINFO *bmpfont_info = (BMPFONTINFO *)devfont->data;
GLYPHTREENODE *root = bmpfont_info->tree;
if (py)
*py -= get_font_ascent (logfont, devfont);
node = look_up (root, glyph_value);
if (node == NULL) {
if (pwidth)
*pwidth = DEFGLYPHWIDTH;
if (pheight)
*pheight = get_font_height (logfont, devfont);
return DEFGLYPHWIDTH;
}
if (pwidth)
*pwidth = node->glyph_width;
if (pheight)
*pheight = bmpfont_info->height;
return node->glyph_width;
}
/**************************** Global data ************************************/
FONTOPS __mg_bitmap_font_ops = {
get_glyph_bmptype,
get_ave_width,
get_max_width,
get_font_height,
get_font_size,
get_font_ascent,
get_font_descent,
is_glyph_existed,
get_glyph_advance,
get_glyph_bbox,
NULL,
NULL,
get_glyph_prbitmap,
NULL,
NULL,
NULL,
};
static BMPFONTINFO *
build_bmpfont_info (const char *bmpfont_name, const BITMAP* glyph_bmp,
int offset, int nr_glyphs, int glyph_width)
{
BMPFONTINFO *bmpfont_info = (BMPFONTINFO *)calloc (1,
sizeof(BMPFONTINFO));
if (!bmpfont_info)
return NULL;
/* set name */
strncpy (bmpfont_info->name, bmpfont_name, LEN_UNIDEVFONT_NAME);
bmpfont_info->name [LEN_UNIDEVFONT_NAME] = '\0';
/* set height */
if ((bmpfont_info->height
= fontGetHeightFromName (bmpfont_name)) == -1) {
_ERR_PRINTF ("FONT>Bitmap: Invalid font name (height): %s.\n",
bmpfont_name);
goto error_load;
}
bmpfont_info->ave_width = glyph_width;
bmpfont_info->max_width = glyph_width;
bmpfont_info->node_cnt = 1;
/* set tree root */
if (!bmpfont_info->tree) {
bmpfont_info->tree = (GLYPHTREENODE *) calloc (1,
sizeof (GLYPHTREENODE));
if (!bmpfont_info->tree) {
_ERR_PRINTF ("FONT>Bitmap: fail to calloc memory space for root.\n");
goto error_load;
}
}
bmpfont_info->tree->min = offset;
bmpfont_info->tree->max = offset + nr_glyphs - 1;
bmpfont_info->tree->nr_glyphs = nr_glyphs;
bmpfont_info->tree->glyph_width = glyph_width;
bmpfont_info->tree->data = (void *)glyph_bmp;
return bmpfont_info;
error_load:
_ERR_PRINTF ("FONT>Bitmap: Error in building Bitmap Font Info!\n");
free (bmpfont_info);
bmpfont_info = NULL;
return NULL;
}
#if 0 // VincentWei: bad implementation
static int set_devfont_style (char* name, char style)
{
int i;
char* style_part = name;
for (i = 0; i < NR_LOOP_FOR_STYLE; i++) {
if ((style_part = strchr (style_part, '-')) == NULL)
return 0;
if (*(++style_part) == '\0')
return 0;
}
if (style == FONT_WEIGHT_BOLD)
*style_part = FONT_WEIGHT_BOLD;
else if (style == FONT_SLANT_ITALIC)
*(style_part + 1) = FONT_SLANT_ITALIC;
return 1;
}
#endif
/************************/
DEVFONT *CreateBMPDevFont (const char *bmpfont_name, const BITMAP* glyph_bmp,
const char* start_mchar, int nr_glyphs, int glyph_width)
{
DEVFONT* bitmapfont_dev_font = NULL;
CHARSETOPS* charset_ops;
char charset[LEN_LOGFONT_NAME_FIELD + 1];
BMPFONTINFO *bmpfont_info;
int offset;
if (!fontGetCharsetFromName (bmpfont_name, charset)) {
_ERR_PRINTF ("FONT>Bitmap: Invalid font name (charset): %s.\n",
bmpfont_name);
goto error_create;
}
if ((charset_ops = GetCharsetOpsEx (charset)) == NULL) {
_ERR_PRINTF ("FONT>Bitmap: Not supported charset: %s.\n", charset);
goto error_create;
}
offset = (charset_ops->get_char_value) (NULL, 0,
(const unsigned char*) start_mchar, 0);
bmpfont_info = build_bmpfont_info (bmpfont_name, glyph_bmp,
offset, nr_glyphs,
glyph_width);
if (bmpfont_info == NULL)
return NULL;
bitmapfont_dev_font = (DEVFONT *)calloc (1, sizeof (DEVFONT));
if (bitmapfont_dev_font == NULL) {
free(bmpfont_info);
free (bitmapfont_dev_font);
return NULL;
}
/*
* Set device name
*/
strncpy (bitmapfont_dev_font->name, bmpfont_name, LEN_UNIDEVFONT_NAME);
#if 0 // VincentWei: bad implementation
if (!set_devfont_style (bitmapfont_dev_font->name, FONT_WEIGHT_BOLD))
return NULL;
if (!set_devfont_style (bitmapfont_dev_font->name, FONT_SLANT_ITALIC))
return NULL;
#endif
bitmapfont_dev_font->name [LEN_UNIDEVFONT_NAME] = '\0';
bitmapfont_dev_font->style = fontConvertStyle (bitmapfont_dev_font->name);
bitmapfont_dev_font->font_ops = &__mg_bitmap_font_ops;
bitmapfont_dev_font->charset_ops = charset_ops;
bitmapfont_dev_font->data = bmpfont_info;
if (bitmapfont_dev_font->charset_ops->bytes_maxlen_char > 1)
font_AddMBDevFont (bitmapfont_dev_font);
else
font_AddSBDevFont (bitmapfont_dev_font);
return bitmapfont_dev_font;
error_create:
_ERR_PRINTF ("FONT>Bitmap: Error in creating bitmap font!\n");
free (bitmapfont_dev_font);
bitmapfont_dev_font = NULL;
return NULL;
}
BOOL AddGlyphsToBMPFont (DEVFONT* dev_font, BITMAP* glyph_bmp,
const char* start_mchar, int nr_glyphs, int glyph_width)
{
int offset;
int l = 0;
int m = 0;
BMPFONTINFO *info = (BMPFONTINFO *)dev_font->data;
GLYPHTREENODE *root = info->tree;
if (!dev_font || !root)
return FALSE;
/* Insert a node in the avl tree */
offset = (*dev_font->charset_ops->get_char_value) (NULL, 0,
(const unsigned char*)start_mchar, 0);
if (look_up (root, offset) == NULL) {
insert (root, offset, (offset + nr_glyphs - 1 ),
glyph_width, glyph_bmp);
/* rebalance tree. 'root' can't be carried into rebalance */
rebalance (&(((BMPFONTINFO *)dev_font->data)->tree), &l, &m);
/* Update max_width, average_width */
if (glyph_width > info->max_width)
info->max_width = glyph_width;
info->ave_width = (info->ave_width * info->node_cnt + glyph_width)/
(info->node_cnt + 1);
info->node_cnt++;
}
return TRUE;
}
void DestroyBMPFont (DEVFONT* dev_font)
{
if (dev_font == NULL)
return;
/* destroy tree */
if(((BMPFONTINFO *)dev_font->data)->tree != NULL) {
destroy (((BMPFONTINFO *)dev_font->data)->tree);
((BMPFONTINFO *)dev_font->data)->tree = NULL;
}
/* free bitmap font info*/
if (dev_font->data != NULL) {
free(dev_font->data);
dev_font->data = NULL;
}
/*delete dev_font from device font linked list and free dev_fonts*/
if (dev_font->charset_ops->bytes_maxlen_char > 1)
font_DelMBDevFont (dev_font);
else
font_DelSBDevFont (dev_font);
dev_font = NULL;
return;
}
#if 0
static int print_tree_struct ( GLYPHTREENODE *node)
{
if (node == NULL)
return 0;
_MG_PRINTF ("%d", node->min);
if (node->left != NULL || node->right != NULL)
{
_MG_PRINTF ("(");
print_tree_struct (node->left);
if (node->right != NULL)
{
_MG_PRINTF (",");
print_tree_struct (node->right);
}
_MG_PRINTF (")");
}
return 0;
}
static void dump_tree (DEVFONT *dev_font)
{
if (dev_font == NULL ||
dev_font->data == NULL ||
((BMPFONTINFO *)dev_font->data)->tree == NULL) {
_MG_PRINTF ("the tree is empty.\n");
return;
}
print_tree_struct (((BMPFONTINFO *)dev_font->data)->tree);
_MG_PRINTF ("\n");
}
static int avl_look_up (DEVFONT *dev_font, char *start_mchar, int n)
{
GLYPHTREENODE *p;
int offset;
offset = (*dev_font->charset_ops->get_char_value) (NULL, 0,
(const unsigned char*)start_mchar, n);
offset += n;
p = look_up (((BMPFONTINFO *)dev_font->data)->tree, offset);
if (p == NULL) {
_MG_PRINTF ("Find nothing. \n");
return 0;
}
else {
_MG_PRINTF ("Found %s+%d \n", start_mchar, n);
return 1;
}
return 0;
}
static void destroy_avl_tree (DEVFONT *dev_font)
{
if (dev_font && ((BMPFONTINFO *)dev_font->data)->tree != NULL) {
destroy (((BMPFONTINFO *)dev_font->data)->tree);
((BMPFONTINFO *)dev_font->data)->tree = NULL;
_MG_PRINTF ("Succeed to destroy avl tree.\n");
}
}
static void draw_root_bmp (HDC hdc, DEVFONT *dev_font)
{
GLYPHTREENODE *root = ((BMPFONTINFO *)dev_font->data)->tree;
_MG_PRINTF ("draw_root_bmp is run. \n");
if (root->data == NULL)
_MG_PRINTF ("bmp data is NULL. \n");
FillBoxWithBitmap (hdc, 0, 400, 0, 0, root->data);
}
#endif
#endif /* End of _MGFONT_BMPF */