Add new system for external library extensions

This commit is contained in:
K. Lange 2018-09-21 13:13:49 +09:00
parent 120f95c584
commit cb419b74f2
2 changed files with 203 additions and 0 deletions

View File

@ -309,3 +309,21 @@ $(eval $(call virtualbox-runner,virtualbox,"Other",))
$(eval $(call virtualbox-runner,virtualbox-efi,"Other",--firmware efi))
$(eval $(call virtualbox-runner,virtualbox-efi64,"Other_64",--firmware efi))
# Optional Extensions
#
# These optional extension libraries require third-party components to build,
# but allow the native applications to make use of functionality such as
# TrueType fonts or PNG images. You must have the necessary elements to build
# these already installed into your sysroot for this to work.
EXT_LIBS=$(patsubst ext/%.c,%,$(wildcard ext/*.c))
EXT_LIBS_X=$(foreach lib,$(EXT_LIBS),base/lib/libtoaru_$(lib).so)
EXT_LIBS_Y=$(foreach lib,$(EXT_LIBS),.make/$(lib).elmak)
.make/%.elmak: ext/%.c util/auto-dep.py | dirs
util/auto-dep.py --makelib $< > $@
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
-include ${EXT_LIBS_Y}
endif
ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so

185
ext/ext_freetype_fonts.c Normal file
View File

@ -0,0 +1,185 @@
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2018 K. Lange
*
* Extension library for freetype font rendering.
*/
#include <syscall.h>
#include <toaru/yutani.h>
#include <toaru/graphics.h>
#include <toaru/decodeutf8.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_CACHE_H
#define SERVER_NAME "fonts"
#define FONT_SANS_SERIF 0
#define FONT_SANS_SERIF_BOLD 1
#define FONT_SANS_SERIF_ITALIC 2
#define FONT_SANS_SERIF_BOLD_ITALIC 3
#define FONT_MONOSPACE 4
#define FONT_MONOSPACE_BOLD 5
#define FONT_MONOSPACE_ITALIC 6
#define FONT_MONOSPACE_BOLD_ITALIC 7
#define FONT_JAPANESE 8
#define FONT_SYMBOLA 9
#define FONTS_TOTAL 10
#define FONT_SIZE 12
static FT_Library library;
static FT_Face faces[FONTS_TOTAL]; /* perhaps make this an array ? */
static FT_GlyphSlot slot;
static int selected_face = 0;
static int fallbacks[] = {FONT_JAPANESE, FONT_SYMBOLA, -1};
#define SGFX(CTX,x,y,WIDTH) *((uint32_t *)&CTX[((WIDTH) * (y) + (x)) * 4])
static void _load_font(int i, char * name) {
uint8_t * font;
size_t s = 0;
int error;
char tmp[100];
snprintf(tmp, 100, "sys.%s%s", SERVER_NAME, name);
font = (void*)syscall_shm_obtain(tmp, &s);
error = FT_New_Memory_Face(library, font, s, 0, &faces[i]);
if (error) {
fprintf(stderr, "[freetype backend] encountered error\n");
}
error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE);
if (error) {
fprintf(stderr, "[freetype backend] encountered error\n");
}
}
static void _load_font_f(int i, char * path) {
int error;
error = FT_New_Face(library, path, 0, &faces[i]);
if (error) {
fprintf(stderr, "[freetype backend] encountered error\n");
}
error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE);
if (error) {
fprintf(stderr, "[freetype backend] encountered error\n");
}
}
static void _load_fonts() {
_load_font(FONT_SANS_SERIF, ".fonts.sans-serif");
_load_font(FONT_SANS_SERIF_BOLD, ".fonts.sans-serif.bold");
_load_font(FONT_SANS_SERIF_ITALIC, ".fonts.sans-serif.italic");
_load_font(FONT_SANS_SERIF_BOLD_ITALIC, ".fonts.sans-serif.bolditalic");
_load_font(FONT_MONOSPACE, ".fonts.monospace");
_load_font(FONT_MONOSPACE_BOLD, ".fonts.monospace.bold");
_load_font(FONT_MONOSPACE_ITALIC, ".fonts.monospace.italic");
_load_font(FONT_MONOSPACE_BOLD_ITALIC, ".fonts.monospace.bolditalic");
_load_font_f(FONT_JAPANESE, "/usr/share/fonts/VLGothic.ttf");
_load_font_f(FONT_SYMBOLA, "/usr/share/fonts/Symbola.ttf");
}
void set_font_face(int font) {
selected_face = font;
}
void set_font_size(int size) {
for (int i = 0; i < FONTS_TOTAL; ++i) {
FT_Set_Pixel_Sizes(faces[i], size, size);
}
}
static void draw_char(FT_Bitmap * bitmap, int x, int y, uint32_t fg, gfx_context_t * ctx) {
int i, j, p, q;
int x_max = x + bitmap->width;
int y_max = y + bitmap->rows;
for (j = y, q = 0; j < y_max; j++, q++) {
if (j < 0 || j >= ctx->height) continue;
for ( i = x, p = 0; i < x_max; i++, p++) {
uint32_t a = _ALP(fg);
a = (a * bitmap->buffer[q * bitmap->width + p]) / 255;
uint32_t tmp = premultiply(rgba(_RED(fg),_GRE(fg),_BLU(fg),a));
if (i < 0 || i >= ctx->width) continue;
SGFX(ctx->backbuffer,i,j,ctx->width) = alpha_blend_rgba(SGFX(ctx->backbuffer,i,j,ctx->width),tmp);
}
}
}
void draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string) {
slot = faces[selected_face]->glyph;
int pen_x = x, pen_y = y;
int error;
uint8_t * s = (uint8_t *)string;
uint32_t codepoint;
uint32_t state = 0;
while (*s) {
uint32_t o = 0;
while (*s) {
if (!decode(&state, &codepoint, (uint8_t)*s)) {
o = (uint32_t)codepoint;
s++;
goto finished;
} else if (state == UTF8_REJECT) {
state = 0;
}
s++;
}
finished:
if (!o) continue;
FT_UInt glyph_index;
glyph_index = FT_Get_Char_Index( faces[selected_face], o);
if (glyph_index) {
error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT);
if (error) {
fprintf(stderr, "Error loading glyph for '%lu'\n", o);
continue;
}
slot = (faces[selected_face])->glyph;
if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
error = FT_Render_Glyph((faces[selected_face])->glyph, FT_RENDER_MODE_NORMAL);
if (error) {
fprintf(stderr, "Error rendering glyph for '%lu'\n", o);
continue;
}
}
} else {
int i = 0;
while (!glyph_index && fallbacks[i] != -1) {
int fallback = fallbacks[i++];
glyph_index = FT_Get_Char_Index( faces[fallback], o);
error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT);
if (error) {
fprintf(stderr, "Error loading glyph for '%lu'\n", o);
continue;
}
slot = (faces[fallback])->glyph;
if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
error = FT_Render_Glyph((faces[fallback])->glyph, FT_RENDER_MODE_NORMAL);
if (error) {
fprintf(stderr, "Error rendering glyph for '%lu'\n", o);
continue;
}
}
}
}
draw_char(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, fg, ctx);
pen_x += slot->advance.x >> 6;
pen_y += slot->advance.y >> 6;
}
}
__attribute__((constructor)) static void init_lib(void) {
FT_Init_FreeType(&library);
_load_fonts();
selected_face = FONT_SANS_SERIF;
}