Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nick87720z/53a1c952d479b67a7f2b096a88deed81 to your computer and use it in GitHub Desktop.
Save nick87720z/53a1c952d479b67a7f2b096a88deed81 to your computer and use it in GitHub Desktop.
======= Makefile =======
CFLAGS = -Wall -Wextra -O0 -g3 -ggdb3 `pkg-config --cflags x11 cairo pangocairo`
LDFLAGS = -O0 `pkg-config --libs x11 cairo pangocairo`
all: ui-cairo-x11
ui-cairo-x11: ui-cairo-x11.o
ui-cairo-x11.o: ui-cairo-x11.c
clean:
rm *.o
run:
valgrind -s --leak-check=full --show-leak-kinds=all ./ui-cairo-x11
.PHONY: clean run
======== ui-cairo-x11.c ========
/* pkg-config: cairo, x11, xext, xrandr, pangocairo */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <cairo-xlib.h>
#include <pango/pangocairo.h>
/* In-place counter wrapper code */
#define begin_perf(time, idle_time, name) { \
clock_t tstart = clock (); \
clock_t tcur = 0; \
guint64 counter = 0; \
int sec = -(idle_time); \
while (1) \
{ \
counter++; \
tcur = clock (); \
if (time == -1) \
{ \
printf ("clock doesn't work\n"); \
break; \
} \
if ( tcur - tstart >= CLOCKS_PER_SEC ) \
{ \
sec++; \
tstart = tcur; \
if (sec <= 0) \
{ \
counter = 0; \
continue; \
} \
printf ("%s: %lu cycles\n", (name), counter / sec); \
if (sec >= (time)) \
break; \
}
#define end_perf \
} \
}
/*******************************/
/* noop, unused */
static void mainloop (void)
{
while (1)
{
break;
}
}
/* FIXME: helper to circumvent cairo bug, when subpixel rendering failed with some cairo clip paths */
static void draw_pango_layout (cairo_t * cr, PangoLayout * layout, int x, int y)
{
static cairo_surface_t * txt_surf = NULL;
static cairo_t * txt_cr = NULL;
cairo_pattern_t * cr_pat;
if (0)
cairo_save (cr);
else {
cr_pat = cairo_get_source (cr);
cairo_pattern_reference (cr_pat);
}
/* 2. surf creation */
if (txt_surf == NULL || 1)
{
txt_surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
txt_cr = cairo_create (txt_surf);
}
if (0) {
cairo_set_operator (txt_cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (txt_cr);
cairo_set_operator (txt_cr, CAIRO_OPERATOR_OVER);
}
cairo_set_source (txt_cr, cairo_get_source (cr));
pango_cairo_show_layout (txt_cr, layout);
cairo_set_source_surface (cr, txt_surf, x, y);
cairo_paint (cr);
/* -2. surf deconstruction */
cairo_destroy (txt_cr);
cairo_surface_destroy (txt_surf);
if (0)
cairo_restore (cr);
else {
cairo_set_source (cr, cr_pat);
}
}
//#define TEXT "subpixel test"
#define TEXT "subpixel test subpixel test subpixel test subpixel test subpixel test subpixel test subpixel test subpixel test"
static void draw (cairo_t * cr)
{
if (0) { /* Clear surface */
cairo_operator_t op = cairo_get_operator (cr);
cairo_antialias_t aa = cairo_get_antialias (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
cairo_set_source_rgba (cr, 0.4, 0.0, 0.7, 0.3);
cairo_paint (cr);
cairo_set_operator (cr, op);
cairo_set_antialias (cr, aa);
}
if (0) { /* test curve speedup (default value is 0.1) */
cairo_set_tolerance (cr, 0.2);
}
if (0) { /* 360 deg circle path*/
cairo_new_path (cr);
cairo_arc (cr, 110.5, 112.5, 100, 0, M_PI*2);
cairo_close_path (cr);
}
if (0) { /* rounded rectangle path */
cairo_new_path (cr);
cairo_arc (cr, 100, 100, 40.5, -M_PI, -M_PI_2);
cairo_arc (cr, 200, 100, 40.5, -M_PI_2, 0);
cairo_arc (cr, 200, 200, 40.5, 0, M_PI_2);
cairo_arc (cr, 100, 200, 40.5, M_PI_2, M_PI);
cairo_close_path (cr);
}
if (0) { /* under-line (shadow) */
cairo_set_line_width (cr, 3.0);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.4);
cairo_stroke_preserve (cr);
}
if (0) { /* main line */
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 1.0, 0.8, 0.4, 1.0);
cairo_stroke (cr);
}
/* Issue test: text loses subpixel rendering in certain clip variants */
if (0) {
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, 110, 0);
cairo_line_to (cr, 400, 400);
cairo_line_to (cr, 0, 400);
cairo_close_path (cr);
cairo_clip_preserve (cr);
cairo_set_source_rgba (cr, 0, 0, 0, 0.4);
cairo_paint (cr);
}
/* text subpixel + clip workaround test */
PangoFontDescription * font_desc;
font_desc = pango_font_description_from_string ("Mono 10");
cairo_set_source_rgba (cr, 1, 1, 0.7, 1);
cairo_move_to (cr, 112, 110);
if (1) /* pango way */
{
PangoLayout * playout;
playout = pango_cairo_create_layout (cr);
pango_layout_set_text (playout, TEXT, -1);
pango_layout_set_font_description (playout, font_desc);
if (1) draw_pango_layout (cr, playout, 112, 110);
else pango_cairo_show_layout (cr, playout);
}
else /* cairo toy api way */
{
PangoContext * pcontext;
PangoCairoFont * pfont;
cairo_scaled_font_t * cfont;
cairo_text_extents_t ext;
pcontext = pango_cairo_create_context (cr);
pfont = PANGO_CAIRO_FONT (pango_context_load_font (pcontext, font_desc));
cfont = pango_cairo_font_get_scaled_font (pfont);
cairo_set_scaled_font (cr, cfont);
cairo_text_extents (cr, TEXT, & ext);
//printf ("cairo text extents: %.0f×%.0f\n", ext.width, ext.height);
cairo_show_text (cr, TEXT);
}
}
int main (int argc, char ** argv)
{
Display * display;
int screen, depth;
Window win, root;
XVisualInfo vinfo;
XSetWindowAttributes attr;
cairo_surface_t * surf;
cairo_t * cr;
const int
w=640, h=480,
bw=0;
display = XOpenDisplay (NULL);
screen = DefaultScreen (display);
depth = DefaultDepth(display,screen);
root = DefaultRootWindow (display);
printf ("Default depth: %i\n", depth);
fflush (stdout);
XMatchVisualInfo (display, screen, 32, TrueColor, &vinfo);
attr.colormap = XCreateColormap (display, root, vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.background_pixmap = None;
win = XCreateWindow (
display, root,
0, 0, w, h,
bw, vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixmap | CWBackPixel, &attr);
//XMapWindow (display, win);
surf = cairo_xlib_surface_create (
display, win, vinfo.visual,
w, h);
cr = cairo_create (surf);
begin_perf (60, 2, "draw()");
draw (cr);
end_perf;
cairo_surface_flush (surf);
XSync (display, False);
sleep (6);
cairo_destroy (cr);
cairo_surface_destroy (surf);
XUnmapWindow (display, win);
XDestroyWindow (display, win);
XCloseDisplay (display);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment