/* * Copyright (C) 2000-2004 Carsten Haitzler, Geoff Harrison and various contributors * * 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: * * 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. * * 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. */ #include "E.h" #if USE_IMLIB2 struct _efont { Imlib_Font *face; }; static void ImlibSetFgColorFromGC(Display * dpy, GC gc, Colormap cm) { XGCValues xgcv; XColor xclr; int r, g, b; XGetGCValues(dpy, gc, GCForeground, &xgcv); xclr.pixel = xgcv.foreground; XQueryColor(dpy, cm, &xclr); EGetColor(&xclr, &r, &g, &b); imlib_context_set_color(r, g, b, 255); } void EFont_draw_string(Display * dpy, Drawable win, GC gc, int x, int y, const char *text, Efont * f, Visual * vis, Colormap cm) { Imlib_Image im; int w, h, ascent, descent; Efont_extents(f, text, &ascent, &descent, &w, NULL, NULL, NULL, NULL); h = ascent + descent; imlib_context_set_drawable(win); im = imlib_create_image_from_drawable(0, x, y - ascent, w, h, 0); imlib_context_set_image(im); imlib_context_set_font(f->face); ImlibSetFgColorFromGC(dpy, gc, cm); imlib_text_draw(0, 0, text); imlib_render_image_on_drawable(x, y - ascent); imlib_free_image(); return; vis = NULL; } void Efont_free(Efont * f) { if (!f) return; imlib_context_set_font(f->face); imlib_free_font(); Efree(f); } Efont * Efont_load(const char *file, int size) { char s[4096]; Efont *f; Imlib_Font *ff; Esnprintf(s, sizeof(s), "%s/%d", file, size); ff = imlib_load_font(s); if (ff == NULL) return NULL; f = Emalloc(sizeof(Efont)); f->face = ff; return f; } void Efont_extents(Efont * f, const 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 height; if (!f) return; imlib_context_set_font(f->face); imlib_get_text_size(text, width_return, &height); if (font_ascent_return) *font_ascent_return = imlib_get_font_ascent(); if (font_descent_return) *font_descent_return = imlib_get_font_descent(); if (max_ascent_return) *max_ascent_return = imlib_get_maximum_font_ascent(); if (max_descent_return) *max_descent_return = imlib_get_maximum_font_descent(); return; lbearing_return = NULL; rbearing_return = NULL; } #else /* USE_IMLIB1 */ #define TT_VALID( handle ) ( ( handle ).z != NULL ) #if TEST_TTFONT #undef XSync #undef IC_RenderDepth #define IC_RenderDepth() DefaultDepth(disp, DefaultScreen(disp)) #define EGetGeometry XGetGeometry #endif #ifdef HAVE_FREETYPE1_FREETYPE_FREETYPE_H #include #elif defined(HAVE_FREETYPE_FREETYPE_H) #include #else #include #endif struct _efont { TT_Engine engine; TT_Face face; TT_Instance instance; TT_Face_Properties properties; int num_glyph; TT_Glyph *glyphs; TT_Raster_Map **glyphs_cached; TT_CharMap char_map; int max_descent; int max_ascent; }; 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 }; struct _imlib_encoding_map { unsigned short char_map[98]; }; typedef struct _imlib_encoding_map ImlibEncodingMap; /* Encoding maps */ static const ImlibEncodingMap iso1 = { { /* ISO-8859-1 encoding (conversion to UTF-8) */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }; static const ImlibEncodingMap iso2 = { { /* ISO-8859-2 encoding (conversion to UTF-8) */ 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }; static const ImlibEncodingMap iso3 = { { /* ISO-8859-3 encoding (conversion to UTF-8) */ 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0124, 0x00A7, 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x017B, 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x017C, 0x00C0, 0x00C1, 0x00C2, 0x00C4, 0x010A, 0x0108, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E4, 0x010B, 0x0109, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9} }; static const ImlibEncodingMap iso4 = { { /* ISO-8859-4 encoding (conversion to UTF-8) */ 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9} }; static const ImlibEncodingMap iso5 = { { /* ISO-8859-5 encoding (conversion to UTF-8) */ 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F} }; static const ImlibEncodingMap *_imlib_encodings[5] = { &iso1, &iso2, &iso3, &iso4, &iso5 }; int IsoEncoding = ENCOING_ISO_8859_1; char encoding_initialized = 0; static void __init_iso_encoding() { /* Set the current ISO encoding based on (in that order): * the "IMLIB_ENCODING" environment variable, * the "LANG" variable, * the ISO-8859-1 default */ char *s, *enc_num, *lang; char iso2lang[21] = "cs hu pl ro hr sk sl"; char iso3lang[6] = "eo mt"; char iso4lang[12] = "et lv lt kl"; char iso5lang[18] = "bg be mk ru sr uk"; /* Check if we already initialized the encoding */ if (!encoding_initialized) { IsoEncoding = 255; /* First check if we have IMLIB_ENCODING variable set */ if ((s = getenv("IMLIB_ENCODING")) != NULL) { if ((enc_num = strstr(s, "8859-")) != NULL) { if (!strcmp((enc_num + 5), "1")) IsoEncoding = 0; else if (!strcmp((enc_num + 5), "2")) IsoEncoding = 1; else if (!strcmp((enc_num + 5), "3")) IsoEncoding = 2; else if (!strcmp((enc_num + 5), "4")) IsoEncoding = 3; else if (!strcmp((enc_num + 5), "5")) IsoEncoding = 4; } } if (IsoEncoding == 255) { /* Still not initialized - try to guess from LANG variable */ if ((lang = getenv("LANG")) != NULL) { if (strstr(iso2lang, lang) != NULL) IsoEncoding = 1; else if (strstr(iso3lang, lang) != NULL) IsoEncoding = 2; else if (strstr(iso4lang, lang) != NULL) IsoEncoding = 3; else if (strstr(iso5lang, lang) != NULL) IsoEncoding = 4; } } if (IsoEncoding == 255) { /* Still not initialized - default to ISO8859-1 */ IsoEncoding = 0; } encoding_initialized = 1; } } static TT_Raster_Map * create_font_raster(int width, int height) { TT_Raster_Map *rmap; rmap = Emalloc(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; if (rmap->size > 0) { rmap->bitmap = Emalloc(rmap->size); memset(rmap->bitmap, 0, rmap->size); } else rmap->bitmap = NULL; return rmap; } static TT_Raster_Map * duplicate_raster(TT_Raster_Map * rmap) { TT_Raster_Map *new_rmap; new_rmap = Emalloc(sizeof(TT_Raster_Map)); *new_rmap = *rmap; if (new_rmap->size > 0) { new_rmap->bitmap = Emalloc(new_rmap->size); memcpy(new_rmap->bitmap, rmap->bitmap, new_rmap->size); } else new_rmap->bitmap = NULL; 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) { if (!rmap) return; if (rmap->bitmap) Efree(rmap->bitmap); Efree(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, const char *text, Efont * f, 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(f, &w, &h, text); rmap = create_font_raster(w, h); render_text(rmap, rtmp, f, text, &inx, &iny); /* XGrabServer(disp); */ GrabX(); erh = XSetErrorHandler((XErrorHandler) handle_x_error); x_error = 0; XGetWindowAttributes(disp, win, &xatt); XFlush(disp); if (x_error) { x_error = 0; is_pixmap = 1; EGetGeometry(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); UngrabX(); /* 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); UngrabX(); /* 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); UngrabX(); /* XUngrabServer(disp); */ /* XFlush(disp, False); */ 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); UngrabX(); /* XUngrabServer(disp); */ /* XFlush(disp); */ #if 0 /* ??? */ 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); } } #endif if (xim) { if (xatt.depth == 16) { if (IC_RenderDepth() == 15) merge_text_15(xim, rmap, clipx, clipy, col); else 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 (xim) { 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]); } if (f->glyphs) Efree(f->glyphs); if (f->glyphs_cached) Efree(f->glyphs_cached); Efree(f); } Efont * Efont_load(const char *file, int size) { TT_Error error; TT_Glyph_Metrics metrics; static TT_Engine engine; static char have_engine = 0; int dpi = 96; Efont *f; unsigned short i, n, index, load_flags; unsigned short num_glyphs = 0, no_cmap = 0; unsigned short platform, encoding; __init_iso_encoding(); if (!have_engine) { error = TT_Init_FreeType(&engine); if (error) return NULL; have_engine = 1; } f = Emalloc(sizeof(Efont)); f->engine = engine; error = TT_Open_Face(f->engine, file, &f->face); if (error) { Efree(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); Efree(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); Efree(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); */ TT_Get_CharMap(f->face, i, &(f->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); Efree(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 *) Emalloc(256 * sizeof(TT_Glyph)); memset(f->glyphs, 0, 256 * sizeof(TT_Glyph)); f->glyphs_cached = (TT_Raster_Map **) Emalloc(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) { index = (i - ' ' + 1) < 0 ? 0 : (i - ' ' + 1); if (index >= num_glyphs) index = 0; } else if (i < 0xA0) index = TT_Char_Index(f->char_map, i); else index = TT_Char_Index(f->char_map, _imlib_encodings[IsoEncoding]-> char_map[(i - 0xA0)]); TT_New_Glyph(f->face, &f->glyphs[i]); TT_Load_Glyph(f->instance, f->glyphs[i], index, 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, const 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; } #endif /* USE_IMLIB1 */ #if TEST_TTFONT #undef XSync Display *disp; int main(int argc, char **argv) { Efont *f; GC gc; XGCValues gcv; Window win; int i, j; disp = XOpenDisplay(NULL); #if USE_IMLIB2 imlib_context_set_display(disp); imlib_context_set_visual(DefaultVisual(disp, DefaultScreen(disp))); imlib_context_set_colormap(DefaultColormap(disp, DefaultScreen(disp))); #endif 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 (;; j++) { 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]) * (i - 2), argv[2], f, DefaultVisual(disp, DefaultScreen(disp)), DefaultColormap(disp, DefaultScreen(disp))); Efont_free(f); f = NULL; } } return 0; } void GrabX() { XGrabServer(disp); } void UngrabX() { XUngrabServer(disp); XFlush(disp); } #endif