font: implement subpixel antialiasing

This commit is contained in:
Daniel Eklöf 2019-08-18 17:40:57 +02:00
parent 9b6d0cfcd1
commit 0060e33912
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

122
font.c
View file

@ -124,17 +124,11 @@ from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, const font_li
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL; load_flags |= FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL;
else if (fc_hinting && fc_hintstyle == FC_HINT_SLIGHT) else if (fc_hinting && fc_hintstyle == FC_HINT_SLIGHT)
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LIGHT; load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LIGHT;
else if (fc_rgba == FC_RGBA_RGB) { else if (fc_rgba == FC_RGBA_RGB)
if (!is_fallback) load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD;
LOG_WARN("unimplemented: subpixel antialiasing"); else if (fc_rgba == FC_RGBA_VRGB)
// load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD; load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD_V;
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL; else
} else if (fc_rgba == FC_RGBA_VRGB) {
if (!is_fallback)
LOG_WARN("unimplemented: subpixel antialiasing");
//load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD_V;
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL;
} else
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL; load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL;
} }
@ -149,17 +143,11 @@ from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, const font_li
if (!fc_antialias) if (!fc_antialias)
render_flags |= FT_RENDER_MODE_MONO; render_flags |= FT_RENDER_MODE_MONO;
else { else {
if (fc_rgba == FC_RGBA_RGB) { if (fc_rgba == FC_RGBA_RGB)
if (!is_fallback) render_flags |= FT_RENDER_MODE_LCD;
LOG_WARN("unimplemented: subpixel antialiasing"); else if (fc_rgba == FC_RGBA_VRGB)
//render_flags |= FT_RENDER_MODE_LCD; render_flags |= FT_RENDER_MODE_LCD_V;
render_flags |= FT_RENDER_MODE_NORMAL; else
} else if (fc_rgba == FC_RGBA_VRGB) {
if (!is_fallback)
LOG_WARN("unimplemented: subpixel antialiasing");
//render_flags |= FT_RENDER_MODE_LCD_V;
render_flags |= FT_RENDER_MODE_NORMAL;
} else
render_flags |= FT_RENDER_MODE_NORMAL; render_flags |= FT_RENDER_MODE_NORMAL;
} }
@ -360,31 +348,55 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
assert(font->face->glyph->format == FT_GLYPH_FORMAT_BITMAP); assert(font->face->glyph->format == FT_GLYPH_FORMAT_BITMAP);
FT_Bitmap *bitmap = &font->face->glyph->bitmap; FT_Bitmap *bitmap = &font->face->glyph->bitmap;
assert(bitmap->pixel_mode == FT_PIXEL_MODE_MONO ||
bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
if (bitmap->width == 0) if (bitmap->width == 0)
goto err; goto err;
/* Map FT pixel format to pixman format */ pixman_format_code_t pix_format;
pixman_format_code_t pix_format = int width;
bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? PIXMAN_a1 : int rows;
bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ? PIXMAN_a8 :
bitmap->pixel_mode == FT_PIXEL_MODE_BGRA ? PIXMAN_a8r8g8b8 : -1; switch (bitmap->pixel_mode) {
case FT_PIXEL_MODE_MONO:
pix_format = PIXMAN_a1;
width = bitmap->width;
rows = bitmap->rows;
break;
case FT_PIXEL_MODE_GRAY:
pix_format = PIXMAN_a8;
width = bitmap->width;
rows = bitmap->rows;
break;
case FT_PIXEL_MODE_LCD:
pix_format = PIXMAN_x8r8g8b8;
width = bitmap->width / 3;
rows = bitmap->rows;
break;
case FT_PIXEL_MODE_LCD_V:
pix_format = PIXMAN_x8r8g8b8;
width = bitmap->width;
rows = bitmap->rows / 3;
break;
case FT_PIXEL_MODE_BGRA:
pix_format = PIXMAN_a8r8g8b8;
width = bitmap->width;
rows = bitmap->rows;
break;
default:
LOG_ERR("unimplemented: FT pixel mode: %d", bitmap->pixel_mode);
goto err;
break;
}
/* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */ /* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */
int bpp = int stride = (((PIXMAN_FORMAT_BPP(pix_format) * width + 7) / 8 + 4 - 1) & -4);
pix_format == PIXMAN_a1 ? 1 :
pix_format == PIXMAN_a8 ? 8 :
pix_format == PIXMAN_a8r8g8b8 ? 32 : -1;
assert(bpp >= 0);
int stride = (((bpp * bitmap->width + 7) / 8 + 4 - 1) & -4);
assert(stride >= bitmap->pitch); assert(stride >= bitmap->pitch);
uint8_t *data = malloc(bitmap->rows * stride); uint8_t *data = malloc(rows * stride);
assert(bitmap->pitch >= 0);
/* Convert FT bitmap to pixman image */ /* Convert FT bitmap to pixman image */
switch (bitmap->pixel_mode) { switch (bitmap->pixel_mode) {
@ -413,21 +425,37 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
memcpy(data, bitmap->buffer, bitmap->rows * bitmap->pitch); memcpy(data, bitmap->buffer, bitmap->rows * bitmap->pitch);
break; break;
case FT_PIXEL_MODE_LCD:
for (size_t r = 0; r < bitmap->rows; r++) {
for (size_t c = 0; c < bitmap->width; c += 3) {
unsigned char _r = bitmap->buffer[r * bitmap->pitch + c + 0];
unsigned char _g = bitmap->buffer[r * bitmap->pitch + c + 1];
unsigned char _b = bitmap->buffer[r * bitmap->pitch + c + 2];
uint32_t *p = (uint32_t *)&data[r * stride + 4 * (c / 3)];
*p = _r << 16 | _g << 8 | _b;
}
}
break;
default: default:
LOG_ERR("unimplemented FreeType bitmap pixel mode: %d", abort();
bitmap->pixel_mode); break;
free(data);
goto err;
} }
pixman_image_t *pix = pixman_image_create_bits_no_clear( pixman_image_t *pix = pixman_image_create_bits_no_clear(
pix_format, bitmap->width, bitmap->rows, (uint32_t *)data, stride); pix_format, width, rows, (uint32_t *)data, stride);
if (pix == NULL) { if (pix == NULL) {
free(data); free(data);
goto err; goto err;
} }
pixman_image_set_component_alpha(
pix,
bitmap->pixel_mode == FT_PIXEL_MODE_LCD ||
bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V);
if (font->pixel_size_fixup != 1.) { if (font->pixel_size_fixup != 1.) {
struct pixman_transform scale; struct pixman_transform scale;
pixman_transform_init_scale( pixman_transform_init_scale(
@ -443,8 +471,8 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
.pix = pix, .pix = pix,
.x = font->face->glyph->bitmap_left / font->pixel_size_fixup, .x = font->face->glyph->bitmap_left / font->pixel_size_fixup,
.y = font->face->glyph->bitmap_top * font->pixel_size_fixup, .y = font->face->glyph->bitmap_top * font->pixel_size_fixup,
.width = bitmap->width, .width = width,
.height = bitmap->rows, .height = rows,
.valid = true, .valid = true,
}; };