📄 devfont.caching.c
字号:
Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index)
{
TT_Glyph_Metrics metrics;
if (TT_Load_Glyph ( pf->instance, pf->glyph,
TT_Char_Index (pf->char_map,glyph_index),
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
{
/* Try to load default glyph: index 0 */
if (TT_Load_Glyph ( pf->instance, pf->glyph, 0,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
return 0;
}
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
return((metrics.advance & 0xFFFFFFC0) >> 6);
}
static MWFREETYPEFONTCACHE *
find_cache_glyph ( PMWFREETYPEFONT pf, unsigned curchar )
{
MWFREETYPEFONTCACHE ** inode = &pf->glyph_cache;
while (1)
{
if (*inode == 0)
{
*inode = calloc(sizeof(MWFREETYPEFONTCACHE),1);
(*inode)->curchar = curchar;
}
if (curchar < (*inode)->curchar)
inode = &(*inode)->l;
else if (curchar > (*inode)->curchar)
inode = &(*inode)->r;
else
return *inode;
}
}
static void
free_cache_glyph ( MWFREETYPEFONTCACHE * node )
{
if (node->l != 0)
free_cache_glyph(node->l);
if (node->r != 0)
free_cache_glyph(node->r);
free(node);
}
/* Render a single glyph*/
static void
drawchar(PMWFREETYPEFONT pf, PSD psd, unsigned curchar, int x_offset,
int y_offset)
{
TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z;
unsigned char *src, *srcptr;
MWPIXELVAL *dst, *dstptr;
MWPIXELVAL *bitmap;
int size, width, height;
TT_Outline outline;
TT_BBox bbox;
TT_Raster_Map Raster;
TT_Error error;
/*MWPIXELVAL save;*/
MWFREETYPEFONTCACHE * cache;
/* we begin by grid-fitting the bounding box */
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Get_Outline_BBox (&outline, &bbox);
xmin = (bbox.xMin & -64) >> 6;
ymin = (bbox.yMin & -64) >> 6;
xmax = ((bbox.xMax + 63) & -64) >> 6;
ymax = ((bbox.yMax + 63) & -64) >> 6;
width = xmax - xmin;
height = ymax - ymin;
size = width * height;
/* now re-allocate the raster bitmap */
Raster.rows = height;
Raster.width = width;
if (pf->fontattr&MWTF_ANTIALIAS)
Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */
else
Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */
cache = find_cache_glyph(pf,curchar);
/* SDR: if cache is 0 here, something really really bad happened */
Raster.flow = TT_Flow_Up;
Raster.size = Raster.rows * Raster.cols;
Raster.bitmap = cache->buffer;
if (Raster.bitmap == 0)
{
Raster.bitmap = malloc (Raster.size);
memset (Raster.bitmap, 0, Raster.size);
/* now render the glyph in the small pixmap */
/* IMPORTANT NOTE: the offset parameters passed to the function */
/* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */
/* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
/* This is why we _did_ grid-fit the bounding box, especially xmin */
/* and ymin. */
if (!(pf->fontattr&MWTF_ANTIALIAS))
error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
else
error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
if (error) {
free (Raster.bitmap);
return;
}
cache->buffer = Raster.bitmap;
}
#if MWFREETYPEFONT_CACHEBITMAP
if ((memcmp(&gr_foreground,&cache->fg,sizeof(gr_foreground)) != 0) ||
(memcmp(&gr_background,&cache->bg,sizeof(gr_background)) != 0) ||
(gr_usebg != cache->usebg))
{
if (cache->bitmap)
{
free(cache->bitmap);
cache->bitmap = 0;
}
}
bitmap = cache->bitmap;
#else
bitmap = 0;
#endif
if (bitmap == 0)
{
bitmap = malloc (size * sizeof (MWPIXELVAL));
memset (bitmap, 0, size * sizeof (MWPIXELVAL));
src = (char *) Raster.bitmap;
dst = bitmap + (size - width);
for (y = ymin; y < ymax; y++)
{
srcptr = src;
dstptr = dst;
for (x = xmin; x < xmax; x++)
{
if (pf->fontattr&MWTF_ANTIALIAS)
*dstptr++ = gray_palette[(int) *srcptr];
else
{
for ( z=0;
z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7);
z++ )
*dstptr++ = ((*srcptr << z) & 0x80) ? gr_foreground : gr_background;
x += 7;
}
srcptr++;
}
src += Raster.cols;
dst -= width;
}
#if MWFREETYPEFONT_CACHEBITMAP
cache->fg = gr_foreground;
cache->bg = gr_background;
cache->usebg = gr_usebg;
cache->bitmap = bitmap;
#endif
}
/* Now draw the bitmap ... */
GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height,
bitmap, MWPF_PIXELVAL);
#if !MWFREETYPEFONT_CACHEBITMAP
free(bitmap);
#endif
}
/*
* Draw unicode 16 text string using FREETYPE type font
*/
static void
freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
const void *text, int cc, int flags)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = ax, y = ay;
TT_Pos vec_x, vec_y;
int i;
TT_F26Dot6 startx, starty;
TT_Outline outline;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_F26Dot6 ascent, descent;
static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 };
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
/*
* Compute instance ascent & descent values
* in fractional units (1/64th pixel)
*/
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000);
descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000);
/*
* Offset the starting point if necessary,
* FreeType always aligns at baseline
*/
if (flags&MWTF_BOTTOM) {
vec_x = 0;
vec_y = descent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
} else if (flags&MWTF_TOP) {
vec_x = 0;
vec_y = ascent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
}
/* Set the "graylevels" */
if (pf->fontattr&MWTF_ANTIALIAS) {
TT_Set_Raster_Gray_Palette (engine, virtual_palette);
alphablend(psd, gray_palette, gr_foreground, gr_background,
blend, 5);
}
startx = x;
starty = y;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_DEFAULT) != TT_Err_Ok)
continue;
if (pf->fontrotation) {
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Transform_Outline (&outline, &pf->matrix);
}
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
if (pf->fontrotation) {
vec_x = compute_kernval(pf, curchar);
vec_y = 0;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x += vec_x / 64;
y -= vec_y / 64;
} else
x += compute_kernval(pf, curchar) / 64;
}
drawchar(pf, psd, curchar, x, y);
if (pf->fontrotation) {
vec_x = metrics.advance;
vec_y = 0;
TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix);
x += vec_x / 64;
y -= vec_y / 64;
} else {
x += metrics.advance / 64;
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
}
pf->last_glyph_code = curchar;
}
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, startx, starty, x, y, FALSE);
}
/*
* Return information about a specified font.
*/
static MWBOOL
freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
int i;
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_UShort last_glyph_index;
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
/* Fill up the fields */
pfontinfo->height = (((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender * \
imetrics.y_scale)/ 0x10000) >> 6);
pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \
imetrics.x_scale)/ 0x10000) >> 6;
pfontinfo->baseline = ((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6;
pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL);
pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL);
pfontinfo->fixed = properties.postscript->isFixedPitch;
last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1;
/* Doesn't work ... don't know why ....*/
#if 0
if (TT_Get_Face_Widths( pf->face, 0,
last_glyph_index, widths, NULL ) != TT_Err_Ok) {
return TRUE;
}
for(i=0; i<=last_glyph_index; i++)
DPRINTF("widths[%d]: %d\n", i, widths[i]);
#endif
/* Get glyphs widths */
for(i=0; i<=last_glyph_index; i++)
pfontinfo->widths[i] = Get_Glyph_Width(pf, i);
#if 0
DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\
x_resolution: %d\ny_resolution: %d\n",
imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \
imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution);
DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\
Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\
sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\
usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\
OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\
Postscript Say monospaced?: %d\n",\
properties.horizontal->Ascender,
properties.horizontal->Descender,
properties.horizontal->xMax_Extent,
(properties.header->Mac_Style & 0x2)?1:0,
(properties.header->Mac_Style & 0x1)?1:0,
properties.os2->sTypoAscender,
properties.os2->sTypoDescender,
properties.os2->usWinAscent,
properties.os2->usWinDescent,
properties.os2->usFirstCharIndex,
properties.os2->usLastCharIndex,
(properties.os2->fsSelection & 0x1)?1:0,
(properties.os2->fsSelection & 0x20)?1:0,
properties.postscript->isFixedPitch,
(properties.os2->panose[3] == 9)?1:0);
#endif
return TRUE;
}
static void
freetype_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = 0;
int i;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
continue;
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
x += compute_kernval(pf, curchar) / 64;
}
x += metrics.advance / 64;
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
pf->last_glyph_code = curchar;
}
*pwidth = x;
*pheight = (((properties.horizontal->Ascender *
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender *
imetrics.y_scale)/ 0x10000) >> 6);
/* FIXME: is it what's required ?? */
*pbase = (((-properties.horizontal->Descender) *
imetrics.y_scale)/ 0x10000) >> 6;
}
static void
freetype_destroyfont(PMWFONT pfont)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
TT_Close_Face(pf->face);
/*----------*/
if (pf->glyph_cache != 0)
free_cache_glyph(pf->glyph_cache);
/*----------*/
free(pf);
}
static void
freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
pf->fontsize = fontsize;
/* We want real pixel sizes ... not points ...*/
TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize,
pf->fontsize, pf->fontsize * 64 );
#if 0
/* set charsize (convert to points for freetype)*/
TT_Set_Instance_CharSize (pf->instance,
((pf->fontsize * 72 + 96/2) / 96) * 64);
#endif
}
static void
freetype_setfontrotation(PMWFONT pfont, int tenthdegrees)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
float angle;
pf->fontrotation = tenthdegrees;
/* Build the rotation matrix with the given angle */
TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE);
angle = pf->fontrotation * M_PI / 1800;
pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16));
pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16));
pf->matrix.xx = pf->matrix.yy;
pf->matrix.xy = -pf->matrix.yx;
}
#endif /* HAVE_FREETYPE_SUPPORT*/
/* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g.
* a single 4-byte UTF-8 character is encoded into a surrogate pair.
* On the other hand, if the UTF-8 string contains surrogate values, this
* is considered an error and returned as such.
*
* The destination array must be able to hold as many Unicode-16 characters
* as there are ASCII characters in the UTF-8 string. This in case all UTF-8
* characters are ASCII characters. No more will be needed.
*
* Copyright (c) 2000 Morten Rolland, Screen Media
*/
static int
utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16)
{
int count = 0;
unsigned char c0, c1;
unsigned long scalar;
while(--cc >= 0) {
c0 = *utf8++;
/*DPRINTF("Trying: %02x\n",c0);*/
if ( c0 < 0x80 ) {
/* Plain ASCII character, simple translation :-) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -