1999-10-04 14:53:55 -07:00
|
|
|
/*
|
2000-01-06 00:15:51 -08:00
|
|
|
Copyright (C) 2000 Carsten Haitzler, Geoff Harrison and various contributors
|
|
|
|
|
1999-10-04 14:53:55 -07:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to
|
|
|
|
deal in the Software without restriction, including without limitation the
|
|
|
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
2000-01-06 00:15:51 -08:00
|
|
|
|
1999-10-04 14:53:55 -07:00
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies of the Software, its documentation and marketing & publicity
|
|
|
|
materials, and acknowledgment shall be given in the documentation, materials
|
|
|
|
and software packages that this Software was used.
|
2000-01-06 00:15:51 -08:00
|
|
|
|
1999-10-04 14:53:55 -07:00
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
2000-01-06 00:15:51 -08:00
|
|
|
|
1999-08-17 15:56:46 -07:00
|
|
|
#include "dox.h"
|
|
|
|
|
|
|
|
typedef struct _efont_color_tab EfontColorTable;
|
|
|
|
|
|
|
|
struct _efont_color_tab
|
|
|
|
{
|
|
|
|
Colormap cmap;
|
|
|
|
|
|
|
|
XColor list[256];
|
|
|
|
unsigned char match[8][8][8];
|
|
|
|
};
|
|
|
|
|
|
|
|
/*static EfontColorTable *color_tab = NULL; */
|
|
|
|
static unsigned char alpha_lut[5] =
|
|
|
|
{0, 64, 128, 192, 255};
|
|
|
|
static unsigned char bounded_palette[9] =
|
|
|
|
{0, 1, 2, 3, 4, 4, 4, 4, 4};
|
|
|
|
|
|
|
|
static TT_Raster_Map *
|
|
|
|
create_font_raster(int width, int height)
|
|
|
|
{
|
|
|
|
TT_Raster_Map *rmap;
|
|
|
|
|
|
|
|
rmap = malloc(sizeof(TT_Raster_Map));
|
|
|
|
rmap->width = (width + 3) & -4;
|
|
|
|
rmap->rows = height;
|
|
|
|
rmap->flow = TT_Flow_Down;
|
|
|
|
rmap->cols = rmap->width;
|
|
|
|
rmap->size = rmap->rows * rmap->width;
|
|
|
|
rmap->bitmap = malloc(rmap->size);
|
|
|
|
memset(rmap->bitmap, 0, rmap->size);
|
|
|
|
return rmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static TT_Raster_Map *
|
|
|
|
duplicate_raster(TT_Raster_Map * rmap)
|
|
|
|
{
|
|
|
|
TT_Raster_Map *new_rmap;
|
|
|
|
|
|
|
|
new_rmap = malloc(sizeof(TT_Raster_Map));
|
|
|
|
*new_rmap = *rmap;
|
|
|
|
new_rmap->bitmap = malloc(new_rmap->size);
|
|
|
|
memcpy(new_rmap->bitmap, rmap->bitmap, new_rmap->size);
|
|
|
|
return new_rmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_raster(TT_Raster_Map * rmap)
|
|
|
|
{
|
|
|
|
memset(rmap->bitmap, 0, rmap->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
destroy_font_raster(TT_Raster_Map * rmap)
|
|
|
|
{
|
|
|
|
free(rmap->bitmap);
|
|
|
|
free(rmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static TT_Raster_Map *
|
|
|
|
calc_size(Efont * f, int *width, int *height, char *text)
|
|
|
|
{
|
|
|
|
int i, upm, ascent, descent, pw, ph;
|
|
|
|
TT_Instance_Metrics imetrics;
|
|
|
|
TT_Glyph_Metrics gmetrics;
|
|
|
|
TT_Raster_Map *rtmp;
|
|
|
|
|
|
|
|
TT_Get_Instance_Metrics(f->instance, &imetrics);
|
|
|
|
upm = f->properties.header->Units_Per_EM;
|
|
|
|
ascent = (f->properties.horizontal->Ascender * imetrics.y_ppem) / upm;
|
|
|
|
descent = (f->properties.horizontal->Descender * imetrics.y_ppem) / upm;
|
|
|
|
if (descent < 0)
|
|
|
|
descent = -descent;
|
|
|
|
pw = 0;
|
|
|
|
ph = ((f->max_ascent) - f->max_descent) / 64;
|
|
|
|
|
|
|
|
for (i = 0; text[i]; i++)
|
|
|
|
{
|
|
|
|
unsigned char j = text[i];
|
|
|
|
|
|
|
|
if (!TT_VALID(f->glyphs[j]))
|
|
|
|
continue;
|
|
|
|
TT_Get_Glyph_Metrics(f->glyphs[j], &gmetrics);
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
pw += ((-gmetrics.bearingX) / 64);
|
|
|
|
}
|
|
|
|
if (text[i + 1] == 0)
|
|
|
|
{
|
|
|
|
pw += (gmetrics.bbox.xMax / 64);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pw += gmetrics.advance / 64;
|
|
|
|
}
|
|
|
|
*width = pw;
|
|
|
|
*height = ph;
|
|
|
|
|
|
|
|
rtmp = create_font_raster(imetrics.x_ppem + 32, imetrics.y_ppem + 32);
|
|
|
|
rtmp->flow = TT_Flow_Up;
|
|
|
|
return rtmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
render_text(TT_Raster_Map * rmap, TT_Raster_Map * rchr, Efont * f, char *text,
|
|
|
|
int *xor, int *yor)
|
|
|
|
{
|
|
|
|
TT_Glyph_Metrics metrics;
|
|
|
|
TT_Instance_Metrics imetrics;
|
|
|
|
TT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
|
|
|
|
int i, ioff, iread;
|
|
|
|
char *off, *read, *_off, *_read;
|
|
|
|
int x_offset, y_offset;
|
|
|
|
unsigned char j;
|
|
|
|
TT_Raster_Map *rtmp;
|
|
|
|
|
|
|
|
TT_Get_Instance_Metrics(f->instance, &imetrics);
|
|
|
|
|
|
|
|
j = text[0];
|
|
|
|
TT_Get_Glyph_Metrics(f->glyphs[j], &metrics);
|
|
|
|
x_offset = (-metrics.bearingX) / 64;
|
|
|
|
|
|
|
|
y_offset = -(f->max_descent / 64);
|
|
|
|
|
|
|
|
*xor = x_offset;
|
|
|
|
*yor = rmap->rows - y_offset;
|
|
|
|
|
|
|
|
rtmp = NULL;
|
|
|
|
for (i = 0; text[i]; i++)
|
|
|
|
{
|
|
|
|
j = text[i];
|
|
|
|
|
|
|
|
if (!TT_VALID(f->glyphs[j]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TT_Get_Glyph_Metrics(f->glyphs[j], &metrics);
|
|
|
|
|
|
|
|
xmin = metrics.bbox.xMin & -64;
|
|
|
|
ymin = metrics.bbox.yMin & -64;
|
|
|
|
xmax = (metrics.bbox.xMax + 63) & -64;
|
|
|
|
ymax = (metrics.bbox.yMax + 63) & -64;
|
|
|
|
|
|
|
|
if (f->glyphs_cached[j])
|
|
|
|
rtmp = f->glyphs_cached[j];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rtmp = rchr;
|
|
|
|
clear_raster(rtmp);
|
|
|
|
TT_Get_Glyph_Pixmap(f->glyphs[j], rtmp, -xmin, -ymin);
|
|
|
|
f->glyphs_cached[j] = duplicate_raster(rtmp);
|
|
|
|
}
|
|
|
|
/* Blit-or the resulting small pixmap into the biggest one */
|
|
|
|
/* We do that by hand, and provide also clipping. */
|
|
|
|
|
|
|
|
xmin = (xmin >> 6) + x_offset;
|
|
|
|
ymin = (ymin >> 6) + y_offset;
|
|
|
|
xmax = (xmax >> 6) + x_offset;
|
|
|
|
ymax = (ymax >> 6) + y_offset;
|
|
|
|
|
|
|
|
/* Take care of comparing xmin and ymin with signed values! */
|
|
|
|
/* This was the cause of strange misplacements when Bit.rows */
|
|
|
|
/* was unsigned. */
|
|
|
|
|
|
|
|
if (xmin >= (int)rmap->width ||
|
|
|
|
ymin >= (int)rmap->rows ||
|
|
|
|
xmax < 0 ||
|
|
|
|
ymax < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Note that the clipping check is performed _after_ rendering */
|
|
|
|
/* the glyph in the small bitmap to let this function return */
|
|
|
|
/* potential error codes for all glyphs, even hidden ones. */
|
|
|
|
|
|
|
|
/* In exotic glyphs, the bounding box may be larger than the */
|
|
|
|
/* size of the small pixmap. Take care of that here. */
|
|
|
|
|
|
|
|
if (xmax - xmin + 1 > rtmp->width)
|
|
|
|
xmax = xmin + rtmp->width - 1;
|
|
|
|
|
|
|
|
if (ymax - ymin + 1 > rtmp->rows)
|
|
|
|
ymax = ymin + rtmp->rows - 1;
|
|
|
|
|
|
|
|
/* set up clipping and cursors */
|
|
|
|
|
|
|
|
iread = 0;
|
|
|
|
if (ymin < 0)
|
|
|
|
{
|
|
|
|
iread -= ymin * rtmp->cols;
|
|
|
|
ioff = 0;
|
|
|
|
ymin = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ioff = (rmap->rows - ymin - 1) * rmap->cols;
|
|
|
|
|
|
|
|
if (ymax >= rmap->rows)
|
|
|
|
ymax = rmap->rows - 1;
|
|
|
|
|
|
|
|
if (xmin < 0)
|
|
|
|
{
|
|
|
|
iread -= xmin;
|
|
|
|
xmin = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ioff += xmin;
|
|
|
|
|
|
|
|
if (xmax >= rmap->width)
|
|
|
|
xmax = rmap->width - 1;
|
|
|
|
|
|
|
|
_read = (char *)rtmp->bitmap + iread;
|
|
|
|
_off = (char *)rmap->bitmap + ioff;
|
|
|
|
|
|
|
|
for (y = ymin; y <= ymax; y++)
|
|
|
|
{
|
|
|
|
read = _read;
|
|
|
|
off = _off;
|
|
|
|
|
|
|
|
for (x = xmin; x <= xmax; x++)
|
|
|
|
{
|
|
|
|
*off = bounded_palette[*off | *read];
|
|
|
|
off++;
|
|
|
|
read++;
|
|
|
|
}
|
|
|
|
_read += rtmp->cols;
|
|
|
|
_off -= rmap->cols;
|
|
|
|
}
|
|
|
|
x_offset += metrics.advance / 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
merge_text_16(XImage * xim, TT_Raster_Map * rmap, int offset_x, int offset_y,
|
|
|
|
unsigned long col)
|
|
|
|
{
|
|
|
|
int x, y, tmp;
|
|
|
|
unsigned char *ptr;
|
|
|
|
unsigned char cr, cg, cb, a, r, g, b, nr, ng, nb;
|
|
|
|
unsigned long pixel;
|
|
|
|
|
|
|
|
cr = (col >> 8) & 0xf8;
|
|
|
|
cg = (col >> 3) & 0xfc;
|
|
|
|
cb = (col << 3) & 0xf8;
|
|
|
|
for (y = 0; y < xim->height; y++)
|
|
|
|
{
|
|
|
|
ptr = (unsigned char *)rmap->bitmap + offset_x + ((y + offset_y) * rmap->cols);
|
|
|
|
for (x = 0; x < xim->width; x++)
|
|
|
|
{
|
|
|
|
if ((a = alpha_lut[*ptr]) > 0)
|
|
|
|
{
|
|
|
|
if (a < 255)
|
|
|
|
{
|
|
|
|
pixel = XGetPixel(xim, x, y);
|
|
|
|
r = (pixel >> 8) & 0xf8;
|
|
|
|
g = (pixel >> 3) & 0xfc;
|
|
|
|
b = (pixel << 3) & 0xf8;
|
|
|
|
|
|
|
|
tmp = (cr - r) * a;
|
|
|
|
nr = r + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cg - g) * a;
|
|
|
|
ng = g + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cb - b) * a;
|
|
|
|
nb = b + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
pixel = ((nr & 0xf8) << 8) | ((ng & 0xfc) << 3) | ((nb & 0xf8) >> 3);
|
|
|
|
XPutPixel(xim, x, y, pixel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
XPutPixel(xim, x, y, col);
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
merge_text_15(XImage * xim, TT_Raster_Map * rmap, int offset_x, int offset_y,
|
|
|
|
unsigned long col)
|
|
|
|
{
|
|
|
|
int x, y, tmp;
|
|
|
|
unsigned char *ptr;
|
|
|
|
unsigned char cr, cg, cb, a, r, g, b, nr, ng, nb;
|
|
|
|
unsigned long pixel;
|
|
|
|
|
|
|
|
cr = (col >> 7) & 0xf8;
|
|
|
|
cg = (col >> 2) & 0xf8;
|
|
|
|
cb = (col << 3) & 0xf8;
|
|
|
|
for (y = 0; y < xim->height; y++)
|
|
|
|
{
|
|
|
|
ptr = (unsigned char *)rmap->bitmap + offset_x + ((y + offset_y) * rmap->cols);
|
|
|
|
for (x = 0; x < xim->width; x++)
|
|
|
|
{
|
|
|
|
if ((a = alpha_lut[*ptr]) > 0)
|
|
|
|
{
|
|
|
|
if (a < 255)
|
|
|
|
{
|
|
|
|
pixel = XGetPixel(xim, x, y);
|
|
|
|
r = (pixel >> 7) & 0xf8;
|
|
|
|
g = (pixel >> 2) & 0xf8;
|
|
|
|
b = (pixel << 3) & 0xf8;
|
|
|
|
|
|
|
|
tmp = (cr - r) * a;
|
|
|
|
nr = r + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cg - g) * a;
|
|
|
|
ng = g + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cb - b) * a;
|
|
|
|
nb = b + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
pixel = ((nr & 0xf8) << 7) | ((ng & 0xf8) << 2) | ((nb & 0xf8) >> 3);
|
|
|
|
XPutPixel(xim, x, y, pixel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
XPutPixel(xim, x, y, col);
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
merge_text_24(XImage * xim, TT_Raster_Map * rmap, int offset_x, int offset_y,
|
|
|
|
unsigned long col)
|
|
|
|
{
|
|
|
|
int x, y, tmp;
|
|
|
|
unsigned char *ptr;
|
|
|
|
unsigned char cr, cg, cb, a, r, g, b, nr, ng, nb;
|
|
|
|
unsigned long pixel;
|
|
|
|
|
|
|
|
cr = (col >> 16) & 0xff;
|
|
|
|
cg = (col >> 8) & 0xff;
|
|
|
|
cb = col & 0xff;
|
|
|
|
for (y = 0; y < xim->height; y++)
|
|
|
|
{
|
|
|
|
ptr = (unsigned char *)rmap->bitmap + offset_x + ((y + offset_y) * rmap->cols);
|
|
|
|
for (x = 0; x < xim->width; x++)
|
|
|
|
{
|
|
|
|
if ((a = alpha_lut[*ptr]) > 0)
|
|
|
|
{
|
|
|
|
if (a < 255)
|
|
|
|
{
|
|
|
|
pixel = XGetPixel(xim, x, y);
|
|
|
|
r = (pixel >> 16) & 0xff;
|
|
|
|
g = (pixel >> 8) & 0xff;
|
|
|
|
b = pixel & 0xff;
|
|
|
|
|
|
|
|
tmp = (cr - r) * a;
|
|
|
|
nr = r + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cg - g) * a;
|
|
|
|
ng = g + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
tmp = (cb - b) * a;
|
|
|
|
nb = b + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
pixel = ((nr << 16) | (ng << 8) | (nb));
|
|
|
|
XPutPixel(xim, x, y, pixel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
XPutPixel(xim, x, y, col);
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* static void
|
|
|
|
* merge_text_8(XImage * xim, TT_Raster_Map * rmap, int offset_x, int offset_y,
|
|
|
|
* unsigned long col, Colormap cm)
|
|
|
|
* {
|
|
|
|
* int x, y, tmp;
|
|
|
|
* unsigned char *ptr;
|
|
|
|
* unsigned char a, r, g, b, nr, ng, nb;
|
|
|
|
* unsigned long pixel;
|
|
|
|
*
|
|
|
|
* for (y = 0; y < xim->height; y++)
|
|
|
|
* {
|
|
|
|
* ptr = (unsigned char *)rmap->bitmap + offset_x + ((y + offset_y) * rmap->cols);
|
|
|
|
* for (x = 0; x < xim->width; x++)
|
|
|
|
* {
|
|
|
|
* if ((a = alpha_lut[*ptr]) > 0)
|
|
|
|
* {
|
|
|
|
* pixel = XGetPixel(xim, x, y);
|
|
|
|
* r = (pixel >> 8) & 0xf8;
|
|
|
|
* g = (pixel >> 3) & 0xfc;
|
|
|
|
* b = (pixel << 3) & 0xf8;
|
|
|
|
*
|
|
|
|
* tmp = (255 - r) * a;
|
|
|
|
* nr = r + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
* tmp = (255 - g) * a;
|
|
|
|
* ng = g + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
* tmp = (255 - b) * a;
|
|
|
|
* nb = b + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
|
|
|
* pixel = ((nr & 0xf8) << 8) | ((ng & 0xfc) << 3) | ((nb & 0xf8) >> 3);
|
|
|
|
* XPutPixel(xim, x, y, pixel);
|
|
|
|
* }
|
|
|
|
* ptr++;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* col = 0;
|
|
|
|
* cm = 0;
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
merge_text_1(XImage * xim, TT_Raster_Map * rmap, int offset_x, int offset_y,
|
|
|
|
unsigned long col)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
unsigned char *ptr;
|
|
|
|
|
|
|
|
for (y = 0; y < xim->height; y++)
|
|
|
|
{
|
|
|
|
ptr = (unsigned char *)rmap->bitmap + offset_x + ((y + offset_y) * rmap->cols);
|
|
|
|
for (x = 0; x < xim->width; x++)
|
|
|
|
{
|
|
|
|
if (alpha_lut[*ptr] > 2)
|
|
|
|
XPutPixel(xim, x, y, col);
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char x_error = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_x_error(Display * d, XErrorEvent * ev)
|
|
|
|
{
|
|
|
|
d = NULL;
|
|
|
|
ev = NULL;
|
|
|
|
x_error = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
EFont_draw_string(Display * disp, Drawable win, GC gc, int x, int y, char *text,
|
|
|
|
Efont * font, Visual * vis, Colormap cm)
|
|
|
|
{
|
|
|
|
XImage *xim;
|
|
|
|
XShmSegmentInfo shminfo;
|
|
|
|
int width, height, w, h, inx, iny, clipx, clipy, rx, ry;
|
|
|
|
XWindowAttributes xatt, ratt;
|
|
|
|
TT_Raster_Map *rmap, *rtmp;
|
|
|
|
unsigned long col;
|
|
|
|
XGCValues gcv;
|
|
|
|
static char shm_checked = 0, shm = 1;
|
|
|
|
XErrorHandler erh = NULL;
|
|
|
|
Window chld;
|
|
|
|
char is_pixmap = 0;
|
|
|
|
|
|
|
|
inx = 0;
|
|
|
|
iny = 0;
|
|
|
|
rtmp = calc_size(font, &w, &h, text);
|
|
|
|
rmap = create_font_raster(w, h);
|
|
|
|
|
|
|
|
render_text(rmap, rtmp, font, text, &inx, &iny);
|
|
|
|
|
|
|
|
XGrabServer(disp);
|
|
|
|
erh = XSetErrorHandler((XErrorHandler) handle_x_error);
|
|
|
|
x_error = 0;
|
|
|
|
XGetWindowAttributes(disp, win, &xatt);
|
|
|
|
XFlush(disp);
|
|
|
|
if (x_error)
|
|
|
|
{
|
|
|
|
x_error = 0;
|
|
|
|
is_pixmap = 1;
|
|
|
|
XGetGeometry(disp, win, &chld, &rx, &rx,
|
|
|
|
(unsigned int *)&xatt.width, (unsigned int *)&xatt.height,
|
|
|
|
(unsigned int *)&rx, (unsigned int *)&xatt.depth);
|
|
|
|
XFlush(disp);
|
|
|
|
if (x_error)
|
|
|
|
{
|
|
|
|
destroy_font_raster(rmap);
|
|
|
|
destroy_font_raster(rtmp);
|
|
|
|
XUngrabServer(disp);
|
|
|
|
XFlush(disp);
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
if (!is_pixmap)
|
|
|
|
{
|
|
|
|
XGetWindowAttributes(disp, xatt.root, &ratt);
|
|
|
|
XTranslateCoordinates(disp, win, xatt.root, 0, 0, &rx, &ry, &chld);
|
|
|
|
if ((xatt.map_state != IsViewable) &&
|
|
|
|
(xatt.backing_store == NotUseful))
|
|
|
|
{
|
|
|
|
destroy_font_raster(rmap);
|
|
|
|
destroy_font_raster(rtmp);
|
|
|
|
XUngrabServer(disp);
|
|
|
|
XFlush(disp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XGetGCValues(disp, gc, GCForeground, &gcv);
|
|
|
|
col = gcv.foreground;
|
|
|
|
|
|
|
|
clipx = 0;
|
|
|
|
clipy = 0;
|
|
|
|
|
|
|
|
x = x - inx;
|
|
|
|
y = y - iny;
|
|
|
|
|
|
|
|
width = xatt.width - x;
|
|
|
|
height = xatt.height - y;
|
|
|
|
if (width > w)
|
|
|
|
width = w;
|
|
|
|
if (height > h)
|
|
|
|
height = h;
|
|
|
|
|
|
|
|
if (!is_pixmap)
|
|
|
|
{
|
|
|
|
if ((rx + x + width) > ratt.width)
|
|
|
|
width = ratt.width - (rx + x);
|
|
|
|
if ((ry + y + height) > ratt.height)
|
|
|
|
height = ratt.height - (ry + y);
|
|
|
|
}
|
|
|
|
if (x < 0)
|
|
|
|
{
|
|
|
|
clipx = -x;
|
|
|
|
width += x;
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (y < 0)
|
|
|
|
{
|
|
|
|
clipy = -y;
|
|
|
|
height += y;
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
if (!is_pixmap)
|
|
|
|
{
|
|
|
|
if ((rx + x) < 0)
|
|
|
|
{
|
|
|
|
clipx -= (rx + x);
|
|
|
|
width += (rx + x);
|
|
|
|
x = -rx;
|
|
|
|
}
|
|
|
|
if ((ry + y) < 0)
|
|
|
|
{
|
|
|
|
clipy -= (ry + y);
|
|
|
|
height += (ry + y);
|
|
|
|
y = -ry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((width <= 0) || (height <= 0))
|
|
|
|
{
|
|
|
|
destroy_font_raster(rmap);
|
|
|
|
destroy_font_raster(rtmp);
|
|
|
|
XUngrabServer(disp);
|
|
|
|
XFlush(disp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (shm)
|
|
|
|
{
|
|
|
|
if (!shm_checked)
|
|
|
|
{
|
|
|
|
erh = XSetErrorHandler((XErrorHandler) handle_x_error);
|
|
|
|
}
|
|
|
|
xim = XShmCreateImage(disp, vis, xatt.depth, ZPixmap, NULL,
|
|
|
|
&shminfo, width, height);
|
|
|
|
if (!shm_checked)
|
|
|
|
{
|
|
|
|
XSync(disp, False);
|
|
|
|
if (x_error)
|
|
|
|
{
|
|
|
|
shm = 0;
|
|
|
|
XDestroyImage(xim);
|
|
|
|
xim = XGetImage(disp, win, x, y, width, height, 0xffffffff, ZPixmap);
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
shm_checked = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line *
|
|
|
|
xim->height, IPC_CREAT | 0666);
|
|
|
|
if (shminfo.shmid < 0)
|
|
|
|
{
|
|
|
|
shm = 0;
|
|
|
|
XDestroyImage(xim);
|
|
|
|
xim = XGetImage(disp, win, x, y, width, height, 0xffffffff, ZPixmap);
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
shm_checked = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shminfo.shmaddr = xim->data = shmat(shminfo.shmid, 0, 0);
|
|
|
|
shminfo.readOnly = False;
|
|
|
|
XShmAttach(disp, &shminfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line *
|
|
|
|
xim->height, IPC_CREAT | 0666);
|
|
|
|
if (shminfo.shmid < 0)
|
|
|
|
{
|
|
|
|
shm = 0;
|
|
|
|
XDestroyImage(xim);
|
|
|
|
xim = XGetImage(disp, win, x, y, width, height, 0xffffffff, ZPixmap);
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
shm_checked = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shminfo.shmaddr = xim->data = shmat(shminfo.shmid, 0, 0);
|
|
|
|
shminfo.readOnly = False;
|
|
|
|
XShmAttach(disp, &shminfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!shm_checked)
|
|
|
|
{
|
|
|
|
XSync(disp, False);
|
|
|
|
if (x_error)
|
|
|
|
{
|
|
|
|
shm = 0;
|
|
|
|
XDestroyImage(xim);
|
|
|
|
xim = XGetImage(disp, win, x, y, width, height, 0xffffffff, ZPixmap);
|
|
|
|
shm_checked = 1;
|
|
|
|
}
|
|
|
|
XSetErrorHandler((XErrorHandler) erh);
|
|
|
|
shm_checked = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
xim = XGetImage(disp, win, x, y, width, height, 0xffffffff, ZPixmap);
|
|
|
|
if (shm)
|
|
|
|
XShmGetImage(disp, win, xim, x, y, 0xffffffff);
|
|
|
|
XUngrabServer(disp);
|
|
|
|
XFlush(disp);
|
|
|
|
|
|
|
|
if (xatt.depth == 16)
|
|
|
|
{
|
|
|
|
XVisualInfo xvi, *xvir;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
xvi.visualid = XVisualIDFromVisual(vis);;
|
|
|
|
xvir = XGetVisualInfo(disp, VisualIDMask, &xvi, &num);
|
|
|
|
if (xvir)
|
|
|
|
{
|
|
|
|
if (xvir->red_mask != 0xf800)
|
|
|
|
xatt.depth = 15;
|
|
|
|
XFree(xvir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (xatt.depth == 16)
|
|
|
|
merge_text_16(xim, rmap, clipx, clipy, col);
|
|
|
|
else if ((xatt.depth == 24) || (xatt.depth == 32))
|
|
|
|
merge_text_24(xim, rmap, clipx, clipy, col);
|
|
|
|
/* else if (xatt.depth == 8)
|
|
|
|
* merge_text_8(xim, rmap, clipx, clipy, cm, col); */
|
|
|
|
else if (xatt.depth == 15)
|
|
|
|
merge_text_15(xim, rmap, clipx, clipy, col);
|
|
|
|
else if (xatt.depth <= 8)
|
|
|
|
merge_text_1(xim, rmap, clipx, clipy, col);
|
|
|
|
|
|
|
|
if (shm)
|
|
|
|
XShmPutImage(disp, win, gc, xim, 0, 0, x, y,
|
|
|
|
width, height, False);
|
|
|
|
else
|
|
|
|
XPutImage(disp, win, gc, xim, 0, 0, x, y, width, height);
|
|
|
|
destroy_font_raster(rmap);
|
|
|
|
destroy_font_raster(rtmp);
|
|
|
|
if (shm)
|
|
|
|
{
|
|
|
|
XSync(disp, False);
|
|
|
|
XShmDetach(disp, &shminfo);
|
|
|
|
shmdt(shminfo.shmaddr);
|
|
|
|
shmctl(shminfo.shmid, IPC_RMID, 0);
|
|
|
|
}
|
|
|
|
XDestroyImage(xim);
|
|
|
|
cm = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Efont_free(Efont * f)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
TT_Done_Instance(f->instance);
|
|
|
|
TT_Close_Face(f->face);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
if (f->glyphs_cached[i])
|
|
|
|
destroy_font_raster(f->glyphs_cached[i]);
|
|
|
|
if (!TT_VALID(f->glyphs[i]))
|
|
|
|
TT_Done_Glyph(f->glyphs[i]);
|
|
|
|
}
|
|
|
|
free(f->glyphs);
|
|
|
|
free(f->glyphs_cached);
|
|
|
|
free(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
Efont *
|
|
|
|
Efont_load(char *file, int size)
|
|
|
|
{
|
|
|
|
TT_Error error;
|
|
|
|
TT_CharMap char_map;
|
|
|
|
TT_Glyph_Metrics metrics;
|
|
|
|
static TT_Engine engine;
|
|
|
|
static char have_engine = 0;
|
|
|
|
int dpi = 96;
|
|
|
|
Efont *f;
|
|
|
|
unsigned short i, n, code, load_flags;
|
|
|
|
unsigned short num_glyphs = 0, no_cmap = 0;
|
|
|
|
unsigned short platform, encoding;
|
|
|
|
|
|
|
|
if (!have_engine)
|
|
|
|
{
|
|
|
|
error = TT_Init_FreeType(&engine);
|
|
|
|
if (error)
|
|
|
|
return NULL;
|
|
|
|
have_engine = 1;
|
|
|
|
}
|
|
|
|
f = malloc(sizeof(Efont));
|
|
|
|
f->engine = engine;
|
|
|
|
error = TT_Open_Face(f->engine, file, &f->face);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
free(f);
|
|
|
|
/* fprintf(stderr, "Unable to open font\n"); */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
error = TT_Get_Face_Properties(f->face, &f->properties);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
TT_Close_Face(f->face);
|
|
|
|
free(f);
|
|
|
|
/* fprintf(stderr, "Unable to get face properties\n"); */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
error = TT_New_Instance(f->face, &f->instance);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
TT_Close_Face(f->face);
|
|
|
|
free(f);
|
|
|
|
/* fprintf(stderr, "Unable to create instance\n"); */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
TT_Set_Instance_Resolutions(f->instance, dpi, dpi);
|
|
|
|
TT_Set_Instance_CharSize(f->instance, size * 64);
|
|
|
|
|
|
|
|
n = f->properties.num_CharMaps;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
TT_Get_CharMap_ID(f->face, i, &platform, &encoding);
|
|
|
|
if ((platform == 3 && encoding == 1) ||
|
|
|
|
(platform == 0 && encoding == 0))
|
|
|
|
{
|
|
|
|
TT_Get_CharMap(f->face, i, &char_map);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == n)
|
|
|
|
{
|
|
|
|
no_cmap = 1;
|
|
|
|
num_glyphs = f->properties.num_Glyphs;
|
|
|
|
TT_Done_Instance(f->instance);
|
|
|
|
TT_Close_Face(f->face);
|
|
|
|
free(f);
|
|
|
|
/* fprintf(stderr, "Sorry, but this font doesn't contain any Unicode mapping table\n"); */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
f->num_glyph = 256;
|
|
|
|
f->glyphs = (TT_Glyph *) malloc(256 * sizeof(TT_Glyph));
|
|
|
|
memset(f->glyphs, 0, 256 * sizeof(TT_Glyph));
|
|
|
|
f->glyphs_cached = (TT_Raster_Map **) malloc(256 * sizeof(TT_Raster_Map *));
|
|
|
|
memset(f->glyphs_cached, 0, 256 * sizeof(TT_Raster_Map *));
|
|
|
|
|
|
|
|
load_flags = TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH;
|
|
|
|
|
|
|
|
f->max_descent = 0;
|
|
|
|
f->max_ascent = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < 256; ++i)
|
|
|
|
{
|
|
|
|
if (TT_VALID(f->glyphs[i]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (no_cmap)
|
|
|
|
{
|
|
|
|
code = (i - ' ' + 1) < 0 ? 0 : (i - ' ' + 1);
|
|
|
|
if (code >= num_glyphs)
|
|
|
|
code = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
code = TT_Char_Index(char_map, i);
|
|
|
|
|
|
|
|
TT_New_Glyph(f->face, &f->glyphs[i]);
|
|
|
|
TT_Load_Glyph(f->instance, f->glyphs[i], code, load_flags);
|
|
|
|
TT_Get_Glyph_Metrics(f->glyphs[i], &metrics);
|
|
|
|
|
|
|
|
if ((metrics.bbox.yMin & -64) < f->max_descent)
|
|
|
|
f->max_descent = (metrics.bbox.yMin & -64);
|
|
|
|
if (((metrics.bbox.yMax + 63) & -64) > f->max_ascent)
|
|
|
|
f->max_ascent = ((metrics.bbox.yMax + 63) & -64);
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Efont_extents(Efont * f, char *text, int *font_ascent_return,
|
|
|
|
int *font_descent_return, int *width_return,
|
|
|
|
int *max_ascent_return, int *max_descent_return,
|
|
|
|
int *lbearing_return, int *rbearing_return)
|
|
|
|
{
|
|
|
|
int i, upm, ascent, descent, pw;
|
|
|
|
TT_Instance_Metrics imetrics;
|
|
|
|
TT_Glyph_Metrics gmetrics;
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TT_Get_Instance_Metrics(f->instance, &imetrics);
|
|
|
|
upm = f->properties.header->Units_Per_EM;
|
|
|
|
ascent = (f->properties.horizontal->Ascender * imetrics.y_ppem) / upm;
|
|
|
|
descent = (f->properties.horizontal->Descender * imetrics.y_ppem) / upm;
|
|
|
|
if (ascent < 0)
|
|
|
|
ascent = -ascent;
|
|
|
|
if (descent < 0)
|
|
|
|
descent = -descent;
|
|
|
|
pw = 0;
|
|
|
|
|
|
|
|
for (i = 0; text[i]; i++)
|
|
|
|
{
|
|
|
|
unsigned char j = text[i];
|
|
|
|
|
|
|
|
if (!TT_VALID(f->glyphs[j]))
|
|
|
|
continue;
|
|
|
|
TT_Get_Glyph_Metrics(f->glyphs[j], &gmetrics);
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
if (lbearing_return)
|
|
|
|
*lbearing_return = ((-gmetrics.bearingX) / 64);
|
|
|
|
}
|
|
|
|
if (text[i + 1] == 0)
|
|
|
|
{
|
|
|
|
if (rbearing_return)
|
|
|
|
*rbearing_return = ((gmetrics.bbox.xMax - gmetrics.advance) / 64);
|
|
|
|
}
|
|
|
|
pw += gmetrics.advance / 64;
|
|
|
|
}
|
|
|
|
if (font_ascent_return)
|
|
|
|
*font_ascent_return = ascent;
|
|
|
|
if (font_descent_return)
|
|
|
|
*font_descent_return = descent;
|
|
|
|
if (width_return)
|
|
|
|
*width_return = pw;
|
|
|
|
if (max_ascent_return)
|
|
|
|
*max_ascent_return = f->max_ascent;
|
|
|
|
if (max_descent_return)
|
|
|
|
*max_descent_return = f->max_descent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* int
|
|
|
|
* main( int argc, char **argv)
|
|
|
|
* {
|
|
|
|
* Display *disp;
|
|
|
|
* Efont *f;
|
|
|
|
* GC gc;
|
|
|
|
* XGCValues gcv;
|
|
|
|
* Window win;
|
|
|
|
* int i;
|
|
|
|
*
|
|
|
|
* disp=XOpenDisplay(NULL);
|
|
|
|
* XSync(disp, False);
|
|
|
|
* srand(time(NULL));
|
|
|
|
* win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 640, 480, 0,
|
|
|
|
* 0, 0);
|
|
|
|
* XMapWindow(disp, win);
|
|
|
|
* XSync(disp, False);
|
|
|
|
*
|
|
|
|
* gcv.subwindow_mode = IncludeInferiors;
|
|
|
|
* gc = XCreateGC(disp, win, GCSubwindowMode, &gcv);
|
|
|
|
* for (;;)
|
|
|
|
* {
|
|
|
|
* for (i = 3; i < argc; i++)
|
|
|
|
* {
|
|
|
|
* XSetForeground(disp, gc, rand()<<16 | rand());
|
|
|
|
* f = Efont_load(argv[i], atoi(argv[1]));
|
|
|
|
* if (f)
|
|
|
|
* EFont_draw_string(disp, win, gc, 20, (atoi(argv[1])/10) * (i-2), argv[2],
|
|
|
|
* f,
|
|
|
|
* DefaultVisual(disp, DefaultScreen(disp)),
|
|
|
|
* DefaultColormap(disp, DefaultScreen(disp)));
|
|
|
|
* Efont_free(f);
|
|
|
|
* f = NULL;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* return 0;
|
|
|
|
* }
|
|
|
|
*/
|