tReplace venam's xcbft.h by my own implementation - xmenu - drop-down menu for X11
(HTM) git clone git://git.z3bra.org/xmenu.git
(DIR) Log
(DIR) Files
(DIR) Refs
---
(DIR) commit fd1386309fc2b03ccb4387c28cce4ad852bb2c2b
(DIR) parent 8695651f358780a5fe85ac4f5b5a0a8ac5e5a4d6
(HTM) Author: Willy Goiffon <dev@z3bra.org>
Date: Mon, 18 Nov 2019 08:15:46 +0100
Replace venam's xcbft.h by my own implementation
The main advantage is that I understand mine better :)
There are less abstract structure types used to save stuff like face
and glyphsets.
This might be a more rigid model, but it suits our needs better.
Diffstat:
A font.c | 222 ++++++++++++++++++++++++++++++
A font.h | 17 +++++++++++++++++
M makefile | 3 ++-
D utf8.h | 48 -------------------------------
D xcbft.h | 813 ------------------------------
M xmenu.c | 70 ++++----------------------------
6 files changed, 248 insertions(+), 925 deletions(-)
---
(DIR) diff --git a/font.c b/font.c
t@@ -0,0 +1,222 @@
+#include "font.h"
+
+/* internal variable holding last loaded font */
+static FT_Face face;
+
+int
+xft_loadfont(char *query, double dpi)
+{
+ FcResult result;
+ FcPattern *pattern, *match;
+ FcValue index, file, pxsz;
+ FT_Library ft;
+
+ if (FcInit() != FcTrue)
+ return -1;
+
+ /* match font pattern */
+ pattern = FcNameParse((FcChar8 *)query);
+ if (!pattern)
+ return -1;
+
+ match = FcFontMatch(NULL, pattern, &result);
+ if (result != FcResultMatch)
+ return -1;
+
+ FcPatternDestroy(pattern);
+
+ /* get file associated with the font matched */
+ if (FcPatternGet(match, FC_FILE, 0, &file) != FcResultMatch) {
+ fprintf(stderr, "No font matched\n");
+ return -1;
+ }
+
+ /* use first font if no index matched */
+ if (FcPatternGet(match, FC_INDEX, 0, &index) != FcResultMatch) {
+ index.type = FcTypeInteger;
+ index.u.i = 0;
+ }
+
+ /* set pixel size to 12 by default */
+ if (FcPatternGet(match, FC_PIXEL_SIZE, 0, &pxsz) != FcResultMatch) {
+ pxsz.type = FcTypeInteger;
+ pxsz.u.i = 12;
+ }
+
+ FT_Init_FreeType(&ft);
+
+ if (FT_New_Face(ft, (const char *)file.u.s, index.u.i, &face))
+ return -1;
+
+ FT_Set_Char_Size(face, 0, 64 * pxsz.u.d/(dpi/72.0), dpi, dpi);
+
+ return 0;
+}
+
+static xcb_render_picture_t
+xr_create_canvas(xcb_connection_t *dpy, xcb_drawable_t xid)
+{
+ int val[2];
+ xcb_render_picture_t pic;
+ xcb_render_pictforminfo_t *fmt;
+ const xcb_render_query_pict_formats_reply_t *r;
+
+ /* create a canvas to draw text on */
+ pic = xcb_generate_id(dpy);
+
+ val[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
+ val[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
+
+ r = xcb_render_util_query_formats(dpy);
+ fmt = xcb_render_util_find_standard_format(r,
+ XCB_PICT_STANDARD_RGB_24);
+
+ xcb_render_create_picture(dpy, pic, xid, fmt->id,
+ XCB_RENDER_CP_POLY_MODE | XCB_RENDER_CP_POLY_EDGE, val);
+
+ return pic;
+}
+
+static xcb_render_picture_t
+xr_create_pen(xcb_connection_t *dpy, xcb_render_color_t color)
+{
+ int val[1];
+ xcb_screen_t *screen;
+ xcb_pixmap_t px;
+ xcb_rectangle_t rect = { 0, 0, 1, 1 };
+ xcb_render_picture_t pen;
+ xcb_render_pictforminfo_t *fmt;
+ const xcb_render_query_pict_formats_reply_t *r;
+
+ screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
+
+ px = xcb_generate_id(dpy);
+ pen = xcb_generate_id(dpy);
+
+ r = xcb_render_util_query_formats(dpy);
+ fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_ARGB_32);
+
+ val[0] = XCB_RENDER_REPEAT_NORMAL;
+ xcb_create_pixmap(dpy, 32, px, screen->root, 1, 1);
+ xcb_render_create_picture(dpy, pen, px, fmt->id, XCB_RENDER_CP_REPEAT, val);
+
+ xcb_render_fill_rectangles(dpy, XCB_RENDER_PICT_OP_OVER, pen, color, 1, &rect);
+ xcb_free_pixmap(dpy, px);
+
+ return pen;
+}
+
+int
+xr_loadglyph(char c, xcb_render_glyphinfo_t *glyph)
+{
+ FT_Select_Charmap(face, FT_ENCODING_UNICODE);
+ if (FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT))
+ return -1;
+
+ glyph->x = -face->glyph->bitmap_left;
+ glyph->y = face->glyph->bitmap_top;
+ glyph->width = face->glyph->bitmap.width;
+ glyph->height = face->glyph->bitmap.rows;
+ glyph->x_off = face->glyph->advance.x / 64;
+ glyph->y_off = face->glyph->advance.y / 64;
+
+ return 0;
+}
+
+size_t
+xft_txtw(char *text)
+{
+ size_t i, w;
+ xcb_render_glyphinfo_t g;
+
+ for (i = w = 0; i < strlen(text); i++) {
+ if (xr_loadglyph(text[i], &g) < 0)
+ return -1;
+
+ w += g.x_off;
+ }
+
+ return w;
+}
+
+size_t
+xft_txth(char *text)
+{
+ size_t i, h;
+ xcb_render_glyphinfo_t g;
+
+ for (i = h = 0; i < strlen(text); i++) {
+ if (xr_loadglyph(text[i], &g) < 0)
+ return -1;
+
+ h = g.height > h ? g.height : h;
+ }
+
+ return h;
+}
+
+int
+xft_drawtext(xcb_connection_t *dpy, xcb_drawable_t xid, int x, int y, int color, char *text)
+{
+ xcb_render_color_t argb;
+ xcb_render_glyphset_t gs;
+ xcb_render_picture_t pic, pen;
+ xcb_render_pictforminfo_t *fmt;
+ const xcb_render_query_pict_formats_reply_t *r;
+ xcb_render_util_composite_text_stream_t *ts;
+
+ argb.red = 0x00ff | (((color >> 16) & 0xff) << 8);
+ argb.green = 0x00ff | (((color >> 8 ) & 0xff) << 8);
+ argb.blue = 0x00ff | (((color >> 0 ) & 0xff) << 8);
+ argb.alpha = 0xffff;
+
+ pic = xr_create_canvas(dpy, xid);
+ pen = xr_create_pen(dpy, argb);
+
+ /* preload all our glyphs */
+ r = xcb_render_util_query_formats(dpy);
+ fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_A_8);
+ gs = xcb_generate_id(dpy);
+ xcb_render_create_glyph_set(dpy, gs, fmt->id);
+
+ for (size_t i = 0; i < strlen(text); i++) {
+ uint8_t *bmp;
+ uint32_t gid;
+ xcb_render_glyphinfo_t g;
+ xr_loadglyph(text[i], &g);
+
+ int stride = (g.width + 3) & ~3;
+ bmp = calloc(sizeof(*bmp), stride * g.height);
+
+ for (int y = 0; y < g.height; y++)
+ memcpy(bmp+y*stride, face->glyph->bitmap.buffer+y*g.width, g.width);
+
+ gid = text[i];
+ xcb_render_add_glyphs(dpy, gs, 1, &gid, &g, stride * g.height, bmp);
+ free(bmp);
+ }
+
+ ts = xcb_render_util_composite_text_stream(gs, strlen(text), 0);
+
+ /*
+ * X coordinates are expressed from top-left downwards, while
+ * font is rendered from bottom-left upwards, so we must add
+ * the text height to the Y coordinates to be more consistent with
+ * what X expects
+ */
+ xcb_render_util_glyphs_8(ts, x, y + xft_txth(text), strlen(text), (uint8_t *)text);
+ xcb_render_util_composite_text(dpy, XCB_RENDER_PICT_OP_OVER, pen, pic, 0, 0, 0, ts);
+
+ xcb_render_util_composite_text_free(ts);
+ xcb_render_free_picture(dpy, pen);
+ xcb_render_free_picture(dpy, pic);
+ xcb_render_util_disconnect(dpy);
+
+ return 0;
+}
+
+void
+xft_unload(void)
+{
+ FcFini();
+}
(DIR) diff --git a/font.h b/font.h
t@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <xcb/render.h>
+#include <xcb/xcb_renderutil.h>
+
+int xft_loadfont(char *, double);
+int xft_drawtext(xcb_connection_t *, xcb_drawable_t, int, int, int, char *);
+size_t xft_txtw(char *);
+size_t xft_txth(char *);
+void xft_unload(void);
(DIR) diff --git a/makefile b/makefile
t@@ -1,7 +1,8 @@
include config.mk
-xmenu: xmenu.o
+xmenu: xmenu.o font.o
xmenu.o: xmenu.c config.h
+font.o: font.c font.h
config.h: config.def.h
cp config.def.h config.h
(DIR) diff --git a/utf8.h b/utf8.h
t@@ -1,48 +0,0 @@
-#ifndef _UTF8_UTILS_
-#define _UTF8_UTILS_
-
-#include <fontconfig/fontconfig.h>
-
-struct utf_holder {
- FcChar32 *str;
- unsigned int length;
-};
-struct utf_holder char_to_uint32(char *str);
-void utf_holder_destroy(struct utf_holder holder);
-
-struct utf_holder
-char_to_uint32(char *str)
-{
- struct utf_holder holder;
- FcChar32 *output = NULL;
- int length = 0, shift = 0;
-
- // there should be less than or same as the strlen of str
- output = (FcChar32 *)malloc(sizeof(FcChar32)*strlen(str));
- if (!output) {
- puts("couldn't allocate mem for char_to_uint32");
- }
-
- while (*(str+shift)) {
- shift += FcUtf8ToUcs4(
- (FcChar8*)(str+shift),
- output+length,
- strlen(str)-shift
- );
- length++;
- }
-
- holder.length = length;
- holder.str = output;
-
- return holder;
-}
-
-void
-utf_holder_destroy(struct utf_holder holder)
-{
-
- free(holder.str);
-}
-
-#endif
(DIR) diff --git a/xcbft.h b/xcbft.h
t@@ -1,813 +0,0 @@
-#ifndef _XCBFT
-#define _XCBFT
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <math.h>
-
-#include <fontconfig/fontconfig.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#include <xcb/xcb.h>
-#include <xcb/render.h>
-#include <xcb/xcb_renderutil.h>
-#include <xcb/xcb_xrm.h>
-
-#include "utf8.h"
-
-struct xcbft_patterns_holder {
- FcPattern **patterns;
- uint8_t length;
-};
-
-struct xcbft_face_holder {
- FT_Face *faces;
- uint8_t length;
- FT_Library library;
-};
-
-struct xcbft_glyphset_and_advance {
- xcb_render_glyphset_t glyphset;
- FT_Vector advance;
-};
-
-// signatures
-bool xcbft_init(void);
-void xcbft_done(void);
-FcPattern* xcbft_query_fontsearch(FcChar8 *);
-struct xcbft_face_holder xcbft_query_by_char_support(
- FcChar32, const FcPattern *, long);
-struct xcbft_patterns_holder xcbft_query_fontsearch_all(FcStrSet *);
-double xcbft_get_pixel_size(struct xcbft_patterns_holder patterns);
-struct xcbft_face_holder xcbft_load_faces(
- struct xcbft_patterns_holder, long);
-FcStrSet* xcbft_extract_fontsearch_list(char *);
-void xcbft_patterns_holder_destroy(struct xcbft_patterns_holder);
-void xcbft_face_holder_destroy(struct xcbft_face_holder);
-FT_Vector xcbft_draw_text(xcb_connection_t*, xcb_drawable_t,
- int16_t, int16_t, struct utf_holder, xcb_render_color_t,
- struct xcbft_face_holder, long);
-xcb_render_picture_t xcbft_create_pen(xcb_connection_t*,
- xcb_render_color_t);
-struct xcbft_glyphset_and_advance xcbft_load_glyphset(xcb_connection_t *,
- struct xcbft_face_holder, struct utf_holder, long);
-FT_Vector xcbft_load_glyph(xcb_connection_t *, xcb_render_glyphset_t,
- FT_Face, int);
-long xcbft_get_dpi(xcb_connection_t *);
-xcb_pixmap_t xcbft_create_text_pixmap(xcb_connection_t *,
- struct utf_holder, xcb_render_color_t, xcb_render_color_t,
- struct xcbft_patterns_holder, long);
-static uint32_t xcb_color_to_uint32(xcb_render_color_t);
-
-void
-xcbft_done(void)
-{
- FcFini();
-}
-
-bool
-xcbft_init(void)
-{
- FcBool status;
-
- status = FcInit();
- if (status == FcFalse) {
- fprintf(stderr, "Could not initialize fontconfig");
- }
-
- return status == FcTrue;
-}
-
-// Inspired by https://www.codeproject.com/Articles/1202772/Color-Topics-for-Programmers
-static uint32_t
-xcb_color_to_uint32(xcb_render_color_t rgb)
-{
- uint32_t sm1 = 65536 - 1; // from 2^16
- uint32_t scale = 256; // to 2^8
-
- return
- (uint32_t) ( ((double)rgb.red/sm1 * (scale-1)) * scale * scale)
- + (uint32_t) ( ((double)rgb.green/sm1 * (scale-1)) * scale)
- + (uint32_t) ( ((double)rgb.blue/sm1 * (scale-1)) );
-}
-
-xcb_pixmap_t
-xcbft_create_text_pixmap(
- xcb_connection_t *c,
- struct utf_holder text,
- xcb_render_color_t text_color,
- xcb_render_color_t background_color,
- struct xcbft_patterns_holder font_patterns,
- long dpi)
-{
- xcb_pixmap_t pmap, resize_pmap;
- xcb_screen_t *screen;
- screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
- struct xcbft_face_holder faces;
- double pix_size = 12;
- uint32_t mask = 0;
- uint32_t values[2];
- xcb_gcontext_t gc;
-
- pix_size = xcbft_get_pixel_size(font_patterns);
- pmap = xcb_generate_id(c);
- faces = xcbft_load_faces(font_patterns, dpi);
-
- // 0.2 being the factor padding on both side
- // 0.3 being the extra factor padding for the width protection
- uint16_t width = (pix_size*text.length/1.6)+pix_size*0.7;
- uint16_t height = pix_size+pix_size*0.4;
-
- xcb_create_pixmap(c, screen->root_depth, pmap, screen->root, width, height);
-
- xcb_rectangle_t rectangles[] = { { .x = 0, .y = 0,
- .width = width, .height = height } };
- gc = xcb_generate_id(c);
- mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
- values[0] = xcb_color_to_uint32(background_color) | 0xff000000;
- values[1] = 0;
- xcb_create_gc(c, gc, pmap, mask, values);
- // draw a rectangle filling the whole pixmap with a single color
- xcb_poly_fill_rectangle(c, pmap, gc, 1, rectangles);
-
- FT_Vector advance = xcbft_draw_text(c, pmap,
- 0.2*pix_size, 0.2*pix_size+pix_size, // x, y
- text, text_color, faces, dpi);
-
- resize_pmap = xcb_generate_id(c);
- width = advance.x+pix_size*0.4; // 0.2 on both sides
- xcb_create_pixmap(c, screen->root_depth, resize_pmap, screen->root, width, height);
- xcb_copy_area(c, pmap, resize_pmap, gc, 0, 0, 0, 0, width, height);
-
- xcb_free_pixmap(c, pmap);
- xcbft_face_holder_destroy(faces);
-
- return resize_pmap;
-}
-
-/*
- * Do the font queries through fontconfig and return the info
- *
- * Assumes:
- * Fontconfig is already init & cleaned outside
- * the FcPattern return needs to be cleaned outside
- */
-FcPattern*
-xcbft_query_fontsearch(FcChar8 *fontquery)
-{
- FcBool status;
- FcPattern *fc_finding_pattern, *pat_output;
- FcResult result;
-
- fc_finding_pattern = FcNameParse(fontquery);
-
- // to match we need to fix the pattern (fill unspecified info)
- FcDefaultSubstitute(fc_finding_pattern);
- status = FcConfigSubstitute(NULL, fc_finding_pattern, FcMatchPattern);
- if (status == FcFalse) {
- fprintf(stderr, "could not perform config font substitution");
- return NULL;
- }
-
- pat_output = FcFontMatch(NULL, fc_finding_pattern, &result);
-
- FcPatternDestroy(fc_finding_pattern);
- if (result == FcResultMatch) {
- return pat_output;
- } else if (result == FcResultNoMatch) {
- fprintf(stderr, "there wasn't a match");
- } else {
- fprintf(stderr, "the match wasn't as good as it should be");
- }
- return NULL;
-}
-
-/*
- * Query a font based on character support
- * Optionally pass a pattern that it'll use as the base for the search
- *
- * fallback of font added to the list or somehow done when drawing,
- * to do that we need to search by the charset we want to draw
- * and if they are in one of the font already specified, thus need to
- * know what the users want to insert as text. This needs more thinking
- * to be decoupled.
-
- Assumes the ft2 library is already loaded
- Assumes the face will be cleaned outside
- */
-struct xcbft_face_holder
-xcbft_query_by_char_support(FcChar32 character,
- const FcPattern *copy_pattern, long dpi)
-{
- FcBool status;
- FcResult result;
- FcCharSet *charset;
- FcPattern *charset_pattern, *pat_output;
- struct xcbft_patterns_holder patterns;
- struct xcbft_face_holder faces;
-
- faces.length = 0;
-
- // add characters we need to a charset
- charset = FcCharSetCreate();
- FcCharSetAddChar(charset, character);
-
- // if we pass a pattern then copy it to get something close
- if (copy_pattern != NULL) {
- charset_pattern = FcPatternDuplicate(copy_pattern);
- } else {
- charset_pattern = FcPatternCreate();
- }
-
- // use the charset for the pattern search
- FcPatternAddCharSet(charset_pattern, FC_CHARSET, charset);
- // also force it to be scalable
- FcPatternAddBool(charset_pattern, FC_SCALABLE, FcTrue);
-
- // default & config substitutions, the usual
- FcDefaultSubstitute(charset_pattern);
- status = FcConfigSubstitute(NULL, charset_pattern, FcMatchPattern);
- if (status == FcFalse) {
- fprintf(stderr, "could not perform config font substitution");
- FcCharSetDestroy(charset);
- return faces;
- }
-
- pat_output = FcFontMatch(NULL, charset_pattern, &result);
-
- FcPatternDestroy(charset_pattern);
-
- if (result != FcResultMatch) {
- fprintf(stderr, "there wasn't a match");
- FcCharSetDestroy(charset);
- return faces;
- }
-
- patterns.patterns = malloc(sizeof(FcPattern *));
- patterns.length = 1;
- patterns.patterns[0] = pat_output;
-
- faces = xcbft_load_faces(patterns, dpi);
-
- // cleanup
- xcbft_patterns_holder_destroy(patterns);
- FcCharSetDestroy(charset);
-
- return faces;
-}
-
-struct xcbft_patterns_holder
-xcbft_query_fontsearch_all(FcStrSet *queries)
-{
- struct xcbft_patterns_holder font_patterns;
- FcPattern *font_pattern;
- uint8_t current_allocated;
-
- font_patterns.patterns = NULL;
- font_patterns.length = 0;
-
- // start with 5, expand if needed
- current_allocated = 5;
- font_patterns.patterns = malloc(sizeof(FcPattern *)*current_allocated);
-
- // safely iterate over set
- FcStrList *iterator = FcStrListCreate(queries);
- FcChar8 *fontquery = NULL;
- FcStrListFirst(iterator);
- while ((fontquery = FcStrListNext(iterator)) != NULL) {
- font_pattern = xcbft_query_fontsearch(fontquery);
- if (font_pattern != NULL) {
- if (font_patterns.length + 1 > current_allocated) {
- current_allocated += 5;
- font_patterns.patterns = realloc(
- font_patterns.patterns,
- sizeof(FcPattern*) * current_allocated);
- }
- font_patterns.patterns[font_patterns.length] = font_pattern;
- font_patterns.length++;
- }
- }
- FcStrListDone(iterator);
- // end of safely iterate over set
-
- return font_patterns;
-}
-
-// There's no way to predict the width and height of every characters
-// as they can go outside the em, so let's just use whatever we have as
-// the biggest pixel size so far in all the loaded patterns
-double
-xcbft_get_pixel_size(struct xcbft_patterns_holder patterns)
-{
- int i;
- double maximum_pix_size;
- FcValue fc_pixel_size;
- FcResult result;
-
- maximum_pix_size = 0;
- for (i = 0; i < patterns.length; i++) {
- result = FcPatternGet(patterns.patterns[i], FC_PIXEL_SIZE, 0, &fc_pixel_size);
- if (result != FcResultMatch || fc_pixel_size.u.d == 0) {
- fprintf(stderr, "font has no pixel size, using 12 by default");
- fc_pixel_size.type = FcTypeInteger;
- fc_pixel_size.u.d = 12.0;
- }
- if (fc_pixel_size.u.d > maximum_pix_size) {
- maximum_pix_size = fc_pixel_size.u.d;
- }
- }
-
- return maximum_pix_size;
-}
-
-struct xcbft_face_holder
-xcbft_load_faces(struct xcbft_patterns_holder patterns, long dpi)
-{
- int i;
- struct xcbft_face_holder faces;
- FcResult result;
- FcValue fc_file, fc_index, fc_matrix, fc_pixel_size;
- FT_Matrix ft_matrix;
- FT_Error error;
- FT_Library library;
-
- faces.length = 0;
- error = FT_Init_FreeType(&library);
- if (error != FT_Err_Ok) {
- perror(NULL);
- return faces;
- }
-
- // allocate the same size as patterns as it should be <= its length
- faces.faces = malloc(sizeof(FT_Face)*patterns.length);
-
- for (i = 0; i < patterns.length; i++) {
- // get the information needed from the pattern
- result = FcPatternGet(patterns.patterns[i], FC_FILE, 0, &fc_file);
- if (result != FcResultMatch) {
- fprintf(stderr, "font has not file location");
- continue;
- }
- result = FcPatternGet(patterns.patterns[i], FC_INDEX, 0, &fc_index);
- if (result != FcResultMatch) {
- fprintf(stderr, "font has no index, using 0 by default");
- fc_index.type = FcTypeInteger;
- fc_index.u.i = 0;
- }
- // TODO: load more info like
- // autohint
- // hinting
- // verticallayout
-
- // load the face
- error = FT_New_Face(
- library,
- (const char *) fc_file.u.s,
- fc_index.u.i,
- &(faces.faces[faces.length]) );
- if (error == FT_Err_Unknown_File_Format) {
- fprintf(stderr, "wrong file format");
- continue;
- } else if (error == FT_Err_Cannot_Open_Resource) {
- fprintf(stderr, "could not open resource");
- continue;
- } else if (error) {
- fprintf(stderr, "another sort of error");
- continue;
- }
- if (faces.faces[faces.length] == NULL) {
- fprintf(stderr, "face was empty");
- continue;
- }
-
- result = FcPatternGet(patterns.patterns[i], FC_MATRIX, 0, &fc_matrix);
- if (result == FcResultMatch) {
- ft_matrix.xx = (FT_Fixed)(fc_matrix.u.m->xx * 0x10000L);
- ft_matrix.xy = (FT_Fixed)(fc_matrix.u.m->xy * 0x10000L);
- ft_matrix.yx = (FT_Fixed)(fc_matrix.u.m->yx * 0x10000L);
- ft_matrix.yy = (FT_Fixed)(fc_matrix.u.m->yy * 0x10000L);
-
- // apply the matrix
- FT_Set_Transform(
- faces.faces[faces.length],
- &ft_matrix,
- NULL);
- }
-
- result = FcPatternGet(patterns.patterns[i], FC_PIXEL_SIZE, 0, &fc_pixel_size);
- if (result != FcResultMatch || fc_pixel_size.u.d == 0) {
- fprintf(stderr, "font has no pixel size, using 12 by default");
- fc_pixel_size.type = FcTypeInteger;
- fc_pixel_size.u.d = 12;
- }
- //error = FT_Set_Pixel_Sizes(
- // faces.faces[faces.length],
- // 0, // width
- // fc_pixel_size.u.d); // height
-
- // pixel_size/ (dpi/72.0)
- FT_Set_Char_Size(
- faces.faces[faces.length], 0,
- (fc_pixel_size.u.d/((double)dpi/72.0))*64,
- dpi, dpi);
- if (error != FT_Err_Ok) {
- perror(NULL);
- fprintf(stderr, "could not char size");
- continue;
- }
-
- faces.length++;
- }
-
- faces.library = library;
-
- return faces;
-}
-
-FcStrSet*
-xcbft_extract_fontsearch_list(char *string)
-{
- FcStrSet *fontsearch = NULL;
- FcChar8 *fontquery;
- FcBool result = FcFalse;
- char *r = strdup(string);
- char *p_to_r = r;
- char *token = NULL;
-
- fontsearch = FcStrSetCreate();
-
- token = strtok(r, ",");
- while (token != NULL) {
- fontquery = (FcChar8*)token;
- result = FcStrSetAdd(fontsearch, fontquery);
- if (result == FcFalse) {
- fprintf(stderr,
- "Couldn't add fontquery to fontsearch set");
- }
- token = strtok(NULL, ",");
- }
-
- free(p_to_r);
-
- return fontsearch;
-}
-
-
-
-void
-xcbft_patterns_holder_destroy(struct xcbft_patterns_holder patterns)
-{
- int i = 0;
-
- for (; i < patterns.length; i++) {
- FcPatternDestroy(patterns.patterns[i]);
- }
- free(patterns.patterns);
- // FcFini(); // TODO: we can't leave that here, find a way for cleanup
-}
-
-void
-xcbft_face_holder_destroy(struct xcbft_face_holder faces)
-{
- int i = 0;
-
- for (; i < faces.length; i++) {
- FT_Done_Face(faces.faces[i]);
- }
- if (faces.faces) {
- free(faces.faces);
- }
- FT_Done_FreeType(faces.library);
-}
-
-FT_Vector
-xcbft_draw_text(
- xcb_connection_t *c, // conn
- xcb_drawable_t pmap, // win or pixmap
- int16_t x, int16_t y, // x, y
- struct utf_holder text, // text
- xcb_render_color_t color,
- struct xcbft_face_holder faces,
- long dpi)
-{
- xcb_void_cookie_t cookie;
- uint32_t values[2];
- xcb_generic_error_t *error;
- xcb_render_picture_t picture;
- xcb_render_pictforminfo_t *fmt;
- const xcb_render_query_pict_formats_reply_t *fmt_rep =
- xcb_render_util_query_formats(c);
-
- fmt = xcb_render_util_find_standard_format(
- fmt_rep,
- XCB_PICT_STANDARD_RGB_24
- );
-
- // create the picture with its attribute and format
- picture = xcb_generate_id(c);
- values[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
- values[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
- cookie = xcb_render_create_picture_checked(c,
- picture, // pid
- pmap, // drawable from the user
- fmt->id, // format
- XCB_RENDER_CP_POLY_MODE|XCB_RENDER_CP_POLY_EDGE,
- values); // make it smooth
-
- error = xcb_request_check(c, cookie);
- if (error) {
- fprintf(stderr, "ERROR: %s : %d\n",
- "could not create picture",
- error->error_code);
- }
-
- // create a 1x1 pixel pen (on repeat mode) of a certain color
- xcb_render_picture_t fg_pen = xcbft_create_pen(c, color);
-
- // load all the glyphs in a glyphset
- // TODO: maybe cache the xcb_render_glyphset_t
- struct xcbft_glyphset_and_advance glyphset_advance =
- xcbft_load_glyphset(c, faces, text, dpi);
-
- // we now have a text stream - a bunch of glyphs basically
- xcb_render_util_composite_text_stream_t *ts =
- xcb_render_util_composite_text_stream(
- glyphset_advance.glyphset,
- text.length, 0);
-
- // draw the text at a certain positions
- xcb_render_util_glyphs_32(ts, x, y, text.length, text.str);
-
- // finally render using the repeated pen color on the picture
- // (which is related to the pixmap)
- xcb_render_util_composite_text(
- c, // connection
- XCB_RENDER_PICT_OP_OVER, //op
- fg_pen, // src
- picture, // dst
- 0, // fmt
- 0, // src x
- 0, // src y
- ts); // txt stream
-
- xcb_render_util_composite_text_free(ts);
- xcb_render_free_picture(c, picture);
- xcb_render_free_picture(c, fg_pen);
- xcb_render_util_disconnect(c);
-
- return glyphset_advance.advance;
-}
-
-xcb_render_picture_t
-xcbft_create_pen(xcb_connection_t *c, xcb_render_color_t color)
-{
- xcb_render_pictforminfo_t *fmt;
- const xcb_render_query_pict_formats_reply_t *fmt_rep =
- xcb_render_util_query_formats(c);
- // alpha can only be used with a picture containing a pixmap
- fmt = xcb_render_util_find_standard_format(
- fmt_rep,
- XCB_PICT_STANDARD_ARGB_32
- );
-
- xcb_drawable_t root = xcb_setup_roots_iterator(
- xcb_get_setup(c)
- ).data->root;
-
- xcb_pixmap_t pm = xcb_generate_id(c);
- xcb_create_pixmap(c, 32, pm, root, 1, 1);
-
- uint32_t values[1];
- values[0] = XCB_RENDER_REPEAT_NORMAL;
-
- xcb_render_picture_t picture = xcb_generate_id(c);
-
- xcb_render_create_picture(c,
- picture,
- pm,
- fmt->id,
- XCB_RENDER_CP_REPEAT,
- values);
-
- xcb_rectangle_t rect = {
- .x = 0,
- .y = 0,
- .width = 1,
- .height = 1
- };
-
- xcb_render_fill_rectangles(c,
- XCB_RENDER_PICT_OP_OVER,
- picture,
- color, 1, &rect);
-
- xcb_free_pixmap(c, pm);
- return picture;
-}
-
-struct xcbft_glyphset_and_advance
-xcbft_load_glyphset(
- xcb_connection_t *c,
- struct xcbft_face_holder faces,
- struct utf_holder text,
- long dpi)
-{
- unsigned int i, j;
- int glyph_index;
- xcb_render_glyphset_t gs;
- xcb_render_pictforminfo_t *fmt_a8;
- struct xcbft_face_holder faces_for_unsupported;
- const xcb_render_query_pict_formats_reply_t *fmt_rep =
- xcb_render_util_query_formats(c);
- FT_Vector total_advance, glyph_advance;
- struct xcbft_glyphset_and_advance glyphset_advance;
-
- total_advance.x = total_advance.y = 0;
- glyph_index = 0;
- faces_for_unsupported.length = 0;
- // create a glyphset with a specific format
- fmt_a8 = xcb_render_util_find_standard_format(
- fmt_rep,
- XCB_PICT_STANDARD_A_8
- );
- gs = xcb_generate_id(c);
- xcb_render_create_glyph_set(c, gs, fmt_a8->id);
-
- for (i = 0; i < text.length; i++) {
- for (j = 0; j < faces.length; j++) {
- glyph_index = FT_Get_Char_Index(
- faces.faces[j],
- text.str[i]);
- if (glyph_index != 0) break;
- }
- // here use face at index j
- if (glyph_index != 0) {
- glyph_advance = xcbft_load_glyph(c, gs, faces.faces[j], text.str[i]);
- total_advance.x += glyph_advance.x;
- total_advance.y += glyph_advance.y;
- } else {
- // fallback
- // TODO pass at least some of the query (font size, italic, etc..)
-
- glyph_index = 0;
- // check if we already loaded that face as fallback
- if (faces_for_unsupported.length > 0) {
- glyph_index = FT_Get_Char_Index(
- faces_for_unsupported.faces[0],
- text.str[i]);
- }
- if (glyph_index == 0) {
- if (faces_for_unsupported.length > 0) {
- xcbft_face_holder_destroy(faces_for_unsupported);
- }
- faces_for_unsupported = xcbft_query_by_char_support(
- text.str[i],
- NULL, dpi);
- }
- if (faces_for_unsupported.length == 0) {
- fprintf(stderr,
- "No faces found supporting character: %02x\n",
- text.str[i]);
- // draw a block using whatever font
- glyph_advance = xcbft_load_glyph(c, gs, faces.faces[0], text.str[i]);
- total_advance.x += glyph_advance.x;
- total_advance.y += glyph_advance.y;
- } else {
- FT_Set_Char_Size(
- faces_for_unsupported.faces[0],
- 0, (faces.faces[0]->size->metrics.x_ppem/((double)dpi/72.0))*64,
- dpi, dpi);
-
- glyph_advance = xcbft_load_glyph(c, gs,
- faces_for_unsupported.faces[0],
- text.str[i]);
- total_advance.x += glyph_advance.x;
- total_advance.y += glyph_advance.y;
- }
- }
- }
- if (faces_for_unsupported.length > 0) {
- xcbft_face_holder_destroy(faces_for_unsupported);
- }
-
- glyphset_advance.advance = total_advance;
- glyphset_advance.glyphset = gs;
- return glyphset_advance;
-}
-
-FT_Vector
-xcbft_load_glyph(
- xcb_connection_t *c, xcb_render_glyphset_t gs, FT_Face face, int charcode)
-{
- uint32_t gid;
- int glyph_index;
- FT_Vector glyph_advance;
- xcb_render_glyphinfo_t ginfo;
- FT_Bitmap *bitmap;
-
- FT_Select_Charmap(face, ft_encoding_unicode);
- glyph_index = FT_Get_Char_Index(face, charcode);
-
- FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
-
- bitmap = &face->glyph->bitmap;
-
- ginfo.x = -face->glyph->bitmap_left;
- ginfo.y = face->glyph->bitmap_top;
- ginfo.width = bitmap->width;
- ginfo.height = bitmap->rows;
- glyph_advance.x = face->glyph->advance.x/64;
- glyph_advance.y = face->glyph->advance.y/64;
- ginfo.x_off = glyph_advance.x;
- ginfo.y_off = glyph_advance.y;
-
- // keep track of the max horiBearingY (yMax) and yMin
- // 26.6 fractional pixel format
- // yMax = face->glyph->metrics.horiBearingY/64; (yMax);
- // yMin = -(face->glyph->metrics.height -
- // face->glyph->metrics.horiBearingY)/64;
-
- gid = charcode;
-
- int stride = (ginfo.width+3)&~3;
- uint8_t *tmpbitmap = calloc(sizeof(uint8_t),stride*ginfo.height);
- int y;
-
- for (y = 0; y < ginfo.height; y++)
- memcpy(tmpbitmap+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width);
-
- xcb_render_add_glyphs_checked(c,
- gs, 1, &gid, &ginfo, stride*ginfo.height, tmpbitmap);
-
- free(tmpbitmap);
-
- xcb_flush(c);
- return glyph_advance;
-}
-
-long
-xcbft_get_dpi(xcb_connection_t *c)
-{
- int i;
- long dpi;
- long xres;
- xcb_xrm_database_t *xrm_db;
- xcb_screen_iterator_t iter;
-
- xrm_db = xcb_xrm_database_from_default(c);
- if (xrm_db != NULL) {
- i = xcb_xrm_resource_get_long(xrm_db, "Xft.dpi", NULL, &dpi);
- xcb_xrm_database_free(xrm_db);
- if (i < 0) {
- fprintf(stderr,
- "Could not fetch value of Xft.dpi from Xresources falling back to highest dpi found\n");
- } else {
- return dpi;
- }
- } else {
- fprintf(stderr,
- "Could not open Xresources database falling back to highest dpi found\n");
- }
-
- iter = xcb_setup_roots_iterator(xcb_get_setup(c));
- dpi = 0;
- for (; iter.rem; xcb_screen_next(&iter)) {
- /*
- * Inspired by xdpyinfo
- *
- * there are 2.54 centimeters to an inch; so
- * there are 25.4 millimeters.
- *
- * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
- * = N pixels / (M inch / 25.4)
- * = N * 25.4 pixels / M inch
- */
- if (iter.data != NULL) {
- xres = ((((double) iter.data->width_in_pixels) * 25.4) /
- ((double) iter.data->width_in_millimeters));
-
- // ignore y resolution for now
- //yres = ((((double) iter.data->height_in_pixels) * 25.4) /
- // ((double) iter.data->height_in_millimeters));
- if (xres > dpi) {
- dpi = xres;
- }
- }
- }
-
- if (dpi == 0) {
- // if everything fails use 96
- fprintf(stderr,
- "Could get highest dpi, using 96 as default\n");
-
- dpi = 96;
- }
-
- return dpi;
-}
-
-#endif // _XCBFT
(DIR) diff --git a/xmenu.c b/xmenu.c
t@@ -10,7 +10,7 @@
#include "arg.h"
#include "config.h"
-#include "xcbft.h"
+#include "font.h"
int verbose = 0;
xcb_connection_t *dpy;
t@@ -24,61 +24,11 @@ usage(FILE *fd, char *name)
}
int
-setfont(char *fn, FT_Face *face)
-{
- FcBool status;
- FcResult result;
- FcPattern *pattern, *match;
- FcValue file, index;
-
- FT_Library lib;
-
- FcInit();
- FT_Init_FreeType(&lib);
-
- /* parse font name and fill default attributes */
- pattern = FcNameParse((FcChar8 *)fn);
- FcDefaultSubstitute(pattern);
- status = FcConfigSubstitute(NULL, pattern, FcMatchPattern);
- if (status == FcFalse) {
- fprintf(stderr, "Bad font name '%s'\n", fn);
- return -1;
- }
-
- /* load and actual font from the previously matched pattern */
- match = FcFontMatch(NULL, pattern, &result);
- if (result != FcResultMatch) {
- fprintf(stderr, "Font not found: '%s'\n", fn);
- return -1;
- }
-
- /* get fontconfig attributes from matched pattern like filename and index */
- if (FcPatternGet(match, FC_FILE, 0, &file) != FcResultMatch) {
- fprintf(stderr, "Font has no file: '%s'\n", fn);
- return -1;
- }
- if (FcPatternGet(match, FC_INDEX, 0, &index) != FcResultMatch) {
- fprintf(stderr, "Font has no file: '%s'\n", fn);
- index.type = FcTypeInteger;
- index.u.i = 0;
- }
-
- /* allocate freetype face according from fontconfig result */
- return FT_New_Face(lib, (const char *)file.u.s, index.u.i, face);
-}
-
-int
main(int argc, char *argv[])
{
int mask, val[4];
char *argv0;
-
long dpi;
- xcb_render_color_t color = { 0xffff, 0xffff, 0xffff, 0xffff };
- FcStrSet *fontsearch;
- struct xcbft_patterns_holder fontpattern;
- struct xcbft_face_holder faces;
- struct utf_holder text;
ARGBEGIN {
case 'h':
t@@ -95,7 +45,7 @@ main(int argc, char *argv[])
} ARGEND;
if (argc < 1)
- return 0;
+ return -1;
dpy = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(dpy))
t@@ -105,6 +55,9 @@ main(int argc, char *argv[])
if (!screen)
return -1;
+ /* 1 inch = 25.4 millimeters */
+ dpi = (screen->height_in_pixels / screen->height_in_millimeters) * 25.4;
+
mask = XCB_CW_BACK_PIXEL
| XCB_CW_EVENT_MASK;
t@@ -121,18 +74,9 @@ main(int argc, char *argv[])
xcb_map_window(dpy, wid);
- xcbft_init();
- dpi = xcbft_get_dpi(dpy);
- fontsearch = xcbft_extract_fontsearch_list(font);
- fontpattern = xcbft_query_fontsearch_all(fontsearch);
- faces = xcbft_load_faces(fontpattern, dpi);
-
- FcStrSetDestroy(fontsearch);
- xcbft_patterns_holder_destroy(fontpattern);
+ xft_loadfont(font, dpi);
+ xft_drawtext(dpy, wid, (width - xft_txtw(argv[0]))/2, 8, foreground, argv[0]);
- text = char_to_uint32(argv[0]);
- xcbft_draw_text(dpy, wid, 16, 28, text, color, faces, dpi);
-
xcb_flush(dpy);
sleep(50);