#include #include #include #include #include #include #include "drw.h" #include "util.h" /* static function declarations */ static Color to_color(uint32_t color); static uint32_t to_uint32_t(Color color); static void draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color); Color to_color(uint32_t color) { return *(Color*)(&color); } uint32_t to_uint32_t(Color color) { return *(uint32_t*)(&color); } Canvas* create_drw(struct wl_shm *shm, unsigned width, unsigned height) { struct wl_shm_pool *pool; Canvas *canvas; int stride; int fd; canvas = malloc(sizeof(Canvas)); canvas->width = width; canvas->height = height; stride = width * sizeof(uint32_t); canvas->size = stride * height; fd = allocate_shm_file(canvas->size); if (fd == -1) { return NULL; } canvas->data = mmap( NULL, canvas->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); if (canvas->data == MAP_FAILED) { close(fd); return NULL; } pool = wl_shm_create_pool( shm, fd, canvas->size ); canvas->buffer = wl_shm_pool_create_buffer( pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888 ); wl_shm_pool_destroy(pool); close(fd); fd = allocate_shm_file(canvas->size); canvas->tmp_data = mmap(NULL, canvas->size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (canvas->tmp_data == MAP_FAILED) { perror("mmap failed"); return NULL; } close(fd); return canvas; } void free_drw(Canvas *canvas) { munmap(canvas->data, canvas->size); munmap(canvas->tmp_data, canvas->size); free(canvas); } void drw_push(Canvas *canvas) { memcpy(canvas->data, canvas->tmp_data, canvas->size); } void draw_point(Canvas *canvas, unsigned x, unsigned y, uint32_t color) { if (!(x < canvas->width && y < canvas->height)) return; canvas->tmp_data[x + canvas->width * y] = color; } void draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned height, uint32_t color) { int py; int px; for (py = y; py < y + height; ++py) { for (px = x; px < x + width; ++px) { draw_point(canvas, px, py, color); } } } Font * create_font(const char *fontpath, unsigned size) { FT_Error error; Font * font; font = malloc(sizeof(Font)); error = FT_Init_FreeType(&font->library); if (error) die("cannot init library"); error = FT_New_Face(font->library, fontpath, 0, &font->face); if (error) die("cannot open face"); error = FT_Set_Pixel_Sizes(font->face, 0, size); if (error) die("cannot set char size"); error = FT_Select_Charmap(font->face, ft_encoding_unicode); if (error) die("cannot set unicode"); return font; } void free_font(Font *font) { FT_Done_Face(font->face); FT_Done_FreeType(font->library); free(font); } void draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color) { FT_Int i, j, p, q; double strength; uint32_t pixel; Color fg = to_color(color); Color bg; Color c; c.a = fg.a; i = x; p = 0; while (p < bitmap->width) { j = y; q = 0; while (q < bitmap->rows) { if (i < 0 || j < 0 || i >= canvas->width || j >= canvas->height) { j++; q++; continue; } bg = to_color(canvas->tmp_data[i + j * canvas->width]); strength = bitmap->buffer[p + q * bitmap->width]; strength /= 255; c.r = (strength * fg.r) + ((1 - strength) * bg.r); c.g = (strength * fg.g) + ((1 - strength) * bg.g); c.b = (strength * fg.b) + ((1 - strength) * bg.b); pixel = to_uint32_t(c); draw_point(canvas, i, j, pixel); j++; q++; } i++; p++; } } unsigned draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; uint_least32_t charcode; FT_Bool has_kerning = FT_HAS_KERNING(font->face); FT_Vector delta; slot = font->face->glyph; for (; *text;) { text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); glyph_index = FT_Get_Char_Index(font->face, charcode); if (has_kerning && previous && glyph_index) { FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); x += delta.x >> 6; } error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); if (error) { fprintf(stderr, "warning: char not loaded, skipping...\n"); continue; } draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color); x += slot->advance.x >> 6; } return x; } unsigned font_width(Font *font, const char *text) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; uint_least32_t charcode; FT_Bool has_kerning = FT_HAS_KERNING(font->face); FT_Vector delta; unsigned x = 0; slot = font->face->glyph; for (; *text;) { text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); glyph_index = FT_Get_Char_Index(font->face, charcode); if (has_kerning && previous && glyph_index) { FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); x += delta.x >> 6; } error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); if (error) { fprintf(stderr, "warning: char not loaded, skipping...\n"); continue; } x += slot->advance.x >> 6; } return x; }