Skip to content

Commit

Permalink
Replace pango with fontconfig+freetype2
Browse files Browse the repository at this point in the history
Signed-off-by: Artem Senichev <artemsen@gmail.com>
  • Loading branch information
artemsen committed Jul 26, 2022
1 parent 0eaab6b commit a155a7b
Show file tree
Hide file tree
Showing 18 changed files with 536 additions and 179 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
sudo apt install --no-install-recommends --yes
build-essential meson pkg-config wayland-protocols
libwayland-dev libcairo-dev libjson-c-dev libxkbcommon-dev
libpango1.0-dev libpangocairo-1.0-0
libfreetype-dev libfontconfig-dev
libavif-dev libgif-dev libjpeg-dev librsvg2-dev libwebp-dev
- name: Check out source code
Expand Down
9 changes: 3 additions & 6 deletions extra/swayimgrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,22 @@ scale = optimal

# Start in full screen mode (yes/no)
fullscreen = no

# Background for transparent images (none, grid, or RGB, e.g. #112233)
background = grid

# Window background mode/color (none or RGB, e.g. #112233)
frame = none

# Show image info: format, size, EXIF, and current scale (yes/no)
info = no

# Font used to show image info
font = monospace 14

font = monospace
# Font size (in pt)
font-size = 14
# Color for image info text
font-color = #ff00ff

# Default order of the image list (none, alpha, or random)
order = alpha

# Read directories recursively (yes/no)
recursive = no

Expand Down
3 changes: 2 additions & 1 deletion extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ Empty lines and comments are ignored.
\fInone\fR: transparent (default);
\fI#XXXXXX\fR: hexadecimal RGB color.
.IP "\fBinfo\fR: show image meta information: format, size, EXIF, and current scale, \fIyes\fR or [\fIno\fR];"
.IP "\fBfont\fR: font name and size used to render image info text in pango format;"
.IP "\fBfont\fR: font name used for printing image meta info, default is \fImonospace\fR;"
.IP "\fBfont-size\fR: font size (in pt) used to render image info text, default is \fI14\fR;"
.IP "\fBfont-color\fR: color used to render text, RGB hex format, default is \fI#ff00ff\fR;"
.IP "\fBorder\fR: order of the image list:"
.nf
Expand Down
11 changes: 6 additions & 5 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ version = get_option('version')

# mandatory dependencies
wlcln = dependency('wayland-client')
cairo = dependency('cairo')
json = dependency('json-c')
xkb = dependency('xkbcommon')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
fontconfig = dependency('fontconfig')
freetype = dependency('freetype2')
rt = cc.find_library('rt')
# optional dependencies: file formats support
avif = dependency('libavif', required: get_option('avif'))
gif = cc.find_library('gif', required: get_option('gif'))
jpeg = dependency('libjpeg', required: get_option('jpeg'))
png = dependency('libpng', required: get_option('png'))
rsvg = dependency('librsvg-2.0', version: '>=2.46', required: get_option('svg'))
cairo = dependency('cairo', required: get_option('svg'))
webp = dependency('libwebp', required: get_option('webp'))
# optional dependencies: other features
exif = dependency('libexif', required: get_option('exif'))
Expand Down Expand Up @@ -117,6 +117,7 @@ sources = [
'src/canvas.c',
'src/config.c',
'src/filelist.c',
'src/font.c',
'src/image.c',
'src/main.c',
'src/sway.c',
Expand Down Expand Up @@ -163,8 +164,8 @@ executable(
jpeg,
json,
jxl,
pango,
pangocairo,
fontconfig,
freetype,
png,
rsvg,
rt,
Expand Down
144 changes: 61 additions & 83 deletions src/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

#include "canvas.h"

#include <cairo/cairo.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#include "font.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -32,7 +31,7 @@ struct canvas {
float scale; ///< Scale, 1.0 = 100%
struct rect image; ///< Image position and size
struct size window; ///< Output window size
void* font_handle; ///< Font handle to draw text
struct font* font; ///< Font context
};

/**
Expand Down Expand Up @@ -97,22 +96,18 @@ struct canvas* canvas_init(struct config* cfg)
struct canvas* ctx;

ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
return NULL;
if (ctx) {
ctx->config = cfg;
ctx->font = font_init(cfg);
}

ctx->config = cfg;
ctx->font_handle = pango_font_description_from_string(cfg->font_face);

return ctx;
}

void canvas_free(struct canvas* ctx)
{
if (ctx) {
if (ctx->font_handle) {
pango_font_description_free(ctx->font_handle);
}
font_free(ctx->font);
free(ctx);
}
}
Expand Down Expand Up @@ -161,7 +156,7 @@ void canvas_clear(const struct canvas* ctx, argb_t* wnd)
for (size_t y = 0; y < ctx->window.height; ++y) {
argb_t* line = &wnd[y * ctx->window.width];
for (size_t x = 0; x < ctx->window.width; ++x) {
line[x] = ARGB_ALPHA_MASK | ctx->config->frame;
line[x] = ARGB_FROM_A(0xff) | ctx->config->frame;
}
}
}
Expand Down Expand Up @@ -191,102 +186,85 @@ void canvas_draw_image(const struct canvas* ctx, bool alpha, const argb_t* img,
if (!alpha) {
wnd_line[x] = fg;
} else {
// alpha blend
const uint8_t alpha = fg >> ARGB_ALPHA_SHIFT;
const uint16_t alpha_inv = 256 - alpha;
argb_t alpha_set, bg;
// alpha blending
const uint8_t alpha = ARGB_A_FROM(fg);
uint8_t alpha_set;
argb_t bg;

if (ctx->config->background == COLOR_TRANSPARENT) {
bg = 0;
alpha_set = fg & ARGB_ALPHA_MASK;
alpha_set = alpha;
} else if (ctx->config->background == BACKGROUND_GRID) {
const bool shift = (y / GRID_STEP) % 2;
const size_t tail = x / GRID_STEP;
const argb_t grid =
(tail % 2) ^ shift ? GRID_COLOR1 : GRID_COLOR2;
bg = grid;
alpha_set = ARGB_ALPHA_MASK;
alpha_set = 0xff;
} else {
bg = ctx->config->background;
alpha_set = ARGB_ALPHA_MASK;
alpha_set = 0xff;
}
// clang-format off
wnd_line[x] = alpha_set |
((alpha * ((fg >> 16) & 0xff) + alpha_inv * ((bg >> 16) & 0xff)) >> 8) << 16 |
((alpha * ((fg >> 8) & 0xff) + alpha_inv * ((bg >> 8) & 0xff)) >> 8) << 8 |
((alpha * ((fg >> 0) & 0xff) + alpha_inv * ((bg >> 0) & 0xff)) >> 8);
// clang-format on

wnd_line[x] = ARGB_ALPHA_BLEND(alpha, alpha_set, bg, fg);
}
}
}
}

void canvas_print(const struct canvas* ctx, argb_t* wnd,
enum canvas_corner corner, const char* text)
void canvas_print_line(const struct canvas* ctx, argb_t* wnd,
enum canvas_corner corner, const char* text)
{
PangoLayout* layout;
PangoTabArray* tab;
cairo_surface_t* window;
cairo_t* cairo;
int x = 0, y = 0;
int txt_w = 0, txt_h = 0;

if (!ctx->font_handle) {
return;
}

window = cairo_image_surface_create_for_data(
(uint8_t*)wnd, CAIRO_FORMAT_ARGB32, ctx->window.width,
ctx->window.height, ctx->window.width * sizeof(argb_t));
cairo = cairo_create(window);
layout = pango_cairo_create_layout(cairo);
if (!layout) {
return;
}

// setup layout
pango_layout_set_font_description(layout, ctx->font_handle);
pango_layout_set_text(layout, text, -1);

// magic, need to handle tabs in a right way
tab = pango_tab_array_new_with_positions(1, true, PANGO_TAB_LEFT, 150);
pango_layout_set_tabs(layout, tab);
pango_tab_array_free(tab);
struct point pos = { 0, 0 };

// calculate layout position
pango_layout_get_size(layout, &txt_w, &txt_h);
txt_w /= PANGO_SCALE;
txt_h /= PANGO_SCALE;
switch (corner) {
case cc_top_left:
x = TEXT_PADDING;
y = TEXT_PADDING;
break;
case cc_top_right:
x = ctx->window.width - txt_w - TEXT_PADDING;
y = TEXT_PADDING;
pos.x = ctx->window.width - font_text_width(ctx->font, text, 0) -
TEXT_PADDING;
pos.y = TEXT_PADDING;
break;
case cc_bottom_left:
x = TEXT_PADDING;
y = ctx->window.height - txt_h - TEXT_PADDING;
break;
case cc_bottom_right:
x = ctx->window.width - txt_w - TEXT_PADDING;
y = ctx->window.height - txt_h - TEXT_PADDING;
pos.x = TEXT_PADDING;
pos.y = ctx->window.height - font_height(ctx->font) - TEXT_PADDING;
break;
}

// put layout on cairo surface
cairo_set_source_rgb(
cairo, ((double)((ctx->config->font_color >> 16) & 0xff) / 255),
((double)((ctx->config->font_color >> 8) & 0xff) / 255),
((double)(ctx->config->font_color & 0xff) / 255));
cairo_move_to(cairo, x, y);
pango_cairo_show_layout(cairo, layout);

g_object_unref(layout);
cairo_destroy(cairo);
cairo_surface_destroy(window);
font_print(ctx->font, wnd, &ctx->window, &pos, text, 0);
}

void canvas_print_meta(const struct canvas* ctx, argb_t* wnd,
const struct meta* info)
{
const struct meta* it;
size_t val_offset = 0;
struct point pos = { .x = TEXT_PADDING, .y = TEXT_PADDING };

// draw keys block
it = info;
while (it) {
size_t width;
struct point pos_delim;
width = font_print(ctx->font, wnd, &ctx->window, &pos, it->key, 0);
pos_delim.x = TEXT_PADDING + width;
pos_delim.y = pos.y;
width +=
font_print(ctx->font, wnd, &ctx->window, &pos_delim, ":", 0) * 3;
if (width > val_offset) {
val_offset = width;
}
pos.y += font_height(ctx->font);
it = it->next;
}

// draw values block
pos.x = TEXT_PADDING + val_offset + TEXT_PADDING;
pos.y = TEXT_PADDING;
it = info;
while (it) {
font_print(ctx->font, wnd, &ctx->window, &pos, it->value, 0);
pos.y += font_height(ctx->font);
it = it->next;
}
}

bool canvas_move(struct canvas* ctx, enum canvas_move mv)
Expand Down
28 changes: 16 additions & 12 deletions src/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,11 @@
#pragma once

#include "config.h"
#include "types.h"
#include "image.h"

/** Canvas context. */
struct canvas;

/** Corner position. */
enum canvas_corner {
cc_top_left,
cc_top_right,
cc_bottom_left,
cc_bottom_right
};

/** Viewport movement. */
enum canvas_move {
cm_center, ///< Center of the image
Expand All @@ -38,6 +30,9 @@ enum canvas_scale {
cs_zoom_out ///< Reduce by one step
};

/** Corner position. */
enum canvas_corner { cc_top_right, cc_bottom_left };

/**
* Initialize canvas.
* @param ctx canvas context
Expand Down Expand Up @@ -92,14 +87,23 @@ void canvas_draw_image(const struct canvas* ctx, bool aplha, const argb_t* img,
argb_t* wnd);

/**
* Print text on canvas.
* Print text line on canvas.
* @param ctx canvas context
* @param wnd window buffer
* @param corner text block position
* @param text printed text
*/
void canvas_print(const struct canvas* ctx, argb_t* wnd,
enum canvas_corner corner, const char* text);
void canvas_print_line(const struct canvas* ctx, argb_t* wnd,
enum canvas_corner corner, const char* text);

/**
* Print meta info table on canvas.
* @param ctx canvas context
* @param wnd window buffer
* @param info meta info to print
*/
void canvas_print_meta(const struct canvas* ctx, argb_t* wnd,
const struct meta* info);

/**
* Move viewport.
Expand Down
Loading

0 comments on commit a155a7b

Please sign in to comment.