tfont.c - xmenu - drop-down menu for X11
 (HTM) git clone git://git.z3bra.org/xmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       tfont.c (6255B)
       ---
            1 #include "font.h"
            2 
            3 /* internal variable holding last loaded font */
            4 static FT_Face face;
            5 static FT_Library ft;
            6 
            7 double
            8 xft_forcedpi(xcb_connection_t *dpy)
            9 {
           10         xcb_xrm_database_t *db;
           11         char *r;
           12 
           13         /* try to set DPI from "Xft.dpi" resource */
           14         db = xcb_xrm_database_from_default(dpy);
           15         if (db) {
           16                 xcb_xrm_resource_get_string(db, "Xft.dpi", NULL, &r);
           17                 if (r)
           18                         return strtod(r, NULL);
           19         }
           20 
           21         return -1;
           22 }
           23 
           24 double
           25 xft_getxdpi(xcb_screen_t *screen)
           26 {
           27         /* return actual screen DPI */
           28         return 25.4 * screen->width_in_pixels/screen->width_in_millimeters;
           29 }
           30 
           31 double
           32 xft_getydpi(xcb_screen_t *screen)
           33 {
           34         /* return actual screen DPI */
           35         return 25.4 * screen->height_in_pixels/screen->height_in_millimeters;
           36 }
           37 
           38 
           39 int
           40 xft_loadfont(xcb_connection_t *dpy, xcb_screen_t *screen, char *query)
           41 {
           42         double dpi[2];
           43         FcResult result;
           44         FcPattern *pattern, *match;
           45         FcValue index, file, pxsz;
           46 
           47         if (FcInit() != FcTrue)
           48                 return -1;
           49 
           50         /* match font pattern */
           51         pattern = FcNameParse((FcChar8 *)query);
           52         if (!pattern)
           53                 return -1;
           54 
           55         FcDefaultSubstitute(pattern);
           56         FcConfigSubstitute(NULL, pattern, FcMatchPattern);
           57         match = FcFontMatch(NULL, pattern, &result);
           58         if (result != FcResultMatch)
           59                 return -1;
           60 
           61         FcPatternDestroy(pattern);
           62 
           63         /* get file associated with the font matched */
           64         if (FcPatternGet(match, FC_FILE, 0, &file) != FcResultMatch) {
           65                 fprintf(stderr, "No font matched\n");
           66                 return -1;
           67         }
           68 
           69         /* use first font if no index matched */
           70         if (FcPatternGet(match, FC_INDEX, 0, &index) != FcResultMatch) {
           71                 index.type = FcTypeInteger;
           72                 index.u.i = 0;
           73         }
           74 
           75         /* set pixel size to 12 by default */
           76         if (FcPatternGet(match, FC_PIXEL_SIZE, 0, &pxsz) != FcResultMatch) {
           77                 pxsz.type = FcTypeInteger;
           78                 pxsz.u.i = 12;
           79         }
           80 
           81         FT_Init_FreeType(&ft);
           82 
           83         if (FT_New_Face(ft, (const char *)file.u.s, index.u.i, &face))
           84                 return -1;
           85 
           86         dpi[0] = dpi[1] = xft_forcedpi(dpy);
           87         if (dpi[0] < 0) {
           88                 dpi[0] = xft_getxdpi(screen);
           89                 dpi[1] = xft_getydpi(screen);
           90         }
           91         FT_Set_Char_Size(face, 0, 64 * pxsz.u.d, dpi[0], dpi[1]);
           92 
           93         FcPatternDestroy(match);
           94 
           95         return 0;
           96 }
           97 
           98 static xcb_render_picture_t
           99 xr_create_canvas(xcb_connection_t *dpy, xcb_drawable_t xid)
          100 {
          101         int val[2];
          102         xcb_render_picture_t pic;
          103         xcb_render_pictforminfo_t *fmt;
          104         const xcb_render_query_pict_formats_reply_t *r;
          105 
          106         /* create a canvas to draw text on */
          107         pic = xcb_generate_id(dpy);
          108 
          109         val[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
          110         val[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
          111 
          112         r = xcb_render_util_query_formats(dpy);
          113         fmt = xcb_render_util_find_standard_format(r,
          114                 XCB_PICT_STANDARD_RGB_24);
          115 
          116         xcb_render_create_picture(dpy, pic, xid, fmt->id,
          117                 XCB_RENDER_CP_POLY_MODE | XCB_RENDER_CP_POLY_EDGE, val);
          118 
          119         return pic;
          120 }
          121 
          122 static xcb_render_picture_t
          123 xr_create_pen(xcb_connection_t *dpy, xcb_render_color_t color)
          124 {
          125         int val[1];
          126         xcb_screen_t *screen;
          127         xcb_pixmap_t px;
          128         xcb_rectangle_t rect = { 0, 0, 1, 1 };
          129         xcb_render_picture_t pen;
          130         xcb_render_pictforminfo_t *fmt;
          131         const xcb_render_query_pict_formats_reply_t *r;
          132 
          133         screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
          134 
          135         px = xcb_generate_id(dpy);
          136         pen = xcb_generate_id(dpy);
          137 
          138         r = xcb_render_util_query_formats(dpy);
          139         fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_ARGB_32);
          140 
          141         val[0] = XCB_RENDER_REPEAT_NORMAL;
          142         xcb_create_pixmap(dpy, 32, px, screen->root, 1, 1);
          143         xcb_render_create_picture(dpy, pen, px, fmt->id, XCB_RENDER_CP_REPEAT, val);
          144 
          145         xcb_render_fill_rectangles(dpy, XCB_RENDER_PICT_OP_OVER, pen, color, 1, &rect);
          146         xcb_free_pixmap(dpy, px);
          147 
          148         return pen;
          149 }
          150 
          151 int
          152 xr_loadglyph(char c, xcb_render_glyphinfo_t *glyph)
          153 {
          154         FT_Select_Charmap(face, FT_ENCODING_UNICODE);
          155         if (FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT))
          156                 return -1;
          157 
          158         glyph->x      = -face->glyph->bitmap_left;
          159         glyph->y      =  face->glyph->bitmap_top;
          160         glyph->width  =  face->glyph->bitmap.width;
          161         glyph->height =  face->glyph->bitmap.rows;
          162         glyph->x_off  =  face->glyph->advance.x / 64;
          163         glyph->y_off  =  face->glyph->advance.y / 64;
          164 
          165         return 0;
          166 }
          167 
          168 size_t
          169 xft_txtw(char *text)
          170 {
          171         size_t i, w;
          172         xcb_render_glyphinfo_t g;
          173 
          174         for (i = w = 0; i < strlen(text); i++) {
          175                 if (xr_loadglyph(text[i], &g) < 0)
          176                         return -1;
          177 
          178                 w += g.x_off;
          179         }
          180 
          181         return w;
          182 }
          183 
          184 size_t
          185 xft_txth(char *text)
          186 {
          187         size_t i, h;
          188         xcb_render_glyphinfo_t g;
          189 
          190         for (i = h = 0; i < strlen(text); i++) {
          191                 if (xr_loadglyph(text[i], &g) < 0)
          192                         return -1;
          193 
          194                 h = g.height > h ? g.height : h;
          195         }
          196 
          197         return h;
          198 }
          199 
          200 int
          201 xft_drawtext(xcb_connection_t *dpy, xcb_drawable_t xid, int x, int y, int color, char *text)
          202 {
          203         xcb_render_color_t argb;
          204         xcb_render_glyphset_t gs;
          205         xcb_render_picture_t pic, pen;
          206         xcb_render_pictforminfo_t *fmt;
          207         const xcb_render_query_pict_formats_reply_t *r;
          208         xcb_render_util_composite_text_stream_t *ts;
          209 
          210         argb.red   = 0x00ff | (((color >> 16) & 0xff) << 8);
          211         argb.green = 0x00ff | (((color >> 8 ) & 0xff) << 8);
          212         argb.blue  = 0x00ff | (((color >> 0 ) & 0xff) << 8);
          213         argb.alpha = 0xffff;
          214 
          215         pic = xr_create_canvas(dpy, xid);
          216         pen = xr_create_pen(dpy, argb);
          217 
          218         /* preload all our glyphs */
          219         r = xcb_render_util_query_formats(dpy);
          220         fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_A_8);
          221         gs = xcb_generate_id(dpy);
          222         xcb_render_create_glyph_set(dpy, gs, fmt->id);
          223 
          224         for (size_t i = 0; i < strlen(text); i++) {
          225                 uint8_t *bmp;
          226                 uint32_t gid;
          227                 xcb_render_glyphinfo_t g;
          228                 xr_loadglyph(text[i], &g);
          229 
          230                 int stride = (g.width + 3) & ~3;
          231                 bmp = calloc(sizeof(*bmp), stride * g.height);
          232 
          233                 for (int y = 0; y < g.height; y++)
          234                         memcpy(bmp+y*stride, face->glyph->bitmap.buffer+y*g.width, g.width);
          235 
          236                 gid = text[i];
          237                 xcb_render_add_glyphs(dpy, gs, 1, &gid, &g, stride * g.height, bmp);
          238                 free(bmp);
          239         }
          240 
          241         ts = xcb_render_util_composite_text_stream(gs, strlen(text), 0);
          242 
          243         /*
          244          * X coordinates are expressed from top-left downwards, while
          245          * font is rendered from bottom-left upwards, so we must add
          246          * the text height to the Y coordinates to be more consistent with
          247          * what X expects
          248          */
          249         xcb_render_util_glyphs_8(ts, x, y + xft_txth(text), strlen(text), (uint8_t *)text);
          250         xcb_render_util_composite_text(dpy, XCB_RENDER_PICT_OP_OVER, pen, pic, 0, 0, 0, ts);
          251 
          252         xcb_render_util_composite_text_free(ts);
          253         xcb_render_free_picture(dpy, pen);
          254         xcb_render_free_picture(dpy, pic);
          255         xcb_render_util_disconnect(dpy);
          256 
          257         return 0;
          258 }
          259 
          260 void
          261 xft_unload(void)
          262 {
          263         FcFini();
          264         FT_Done_FreeType(ft);
          265 }