cache freetype glyphs, massive reduction in cpu requirement
svn path=/trunk/netsurf/; revision=6622
This commit is contained in:
parent
caf41b6b19
commit
743f722bcb
|
@ -270,37 +270,33 @@ static bool fb_16bpp_text(int x, int y, const struct css_style *style,
|
||||||
{
|
{
|
||||||
uint32_t ucs4;
|
uint32_t ucs4;
|
||||||
size_t nxtchr = 0;
|
size_t nxtchr = 0;
|
||||||
FT_UInt glyph_index;
|
FT_Glyph glyph;
|
||||||
FT_Face face = fb_get_face(style);
|
FT_BitmapGlyph bglyph;
|
||||||
FT_Error error;
|
|
||||||
|
|
||||||
while (nxtchr < length) {
|
while (nxtchr < length) {
|
||||||
ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
|
ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
|
||||||
nxtchr = utf8_next(text, length, nxtchr);
|
nxtchr = utf8_next(text, length, nxtchr);
|
||||||
glyph_index = FT_Get_Char_Index(face, ucs4);
|
|
||||||
|
|
||||||
error = FT_Load_Glyph(face,
|
glyph = fb_getglyph(style, ucs4);
|
||||||
glyph_index,
|
if (glyph == NULL)
|
||||||
FT_LOAD_RENDER |
|
|
||||||
FT_LOAD_FORCE_AUTOHINT |
|
|
||||||
ft_load_type);
|
|
||||||
if (error)
|
|
||||||
continue;
|
continue;
|
||||||
|
if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
|
||||||
|
bglyph = (FT_BitmapGlyph)glyph;
|
||||||
|
|
||||||
/* now, draw to our target surface */
|
/* now, draw to our target surface */
|
||||||
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
|
if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
|
||||||
fb_16bpp_draw_ft_monobitmap( &face->glyph->bitmap,
|
fb_16bpp_draw_ft_monobitmap(&bglyph->bitmap,
|
||||||
x + face->glyph->bitmap_left,
|
x + bglyph->left,
|
||||||
y - face->glyph->bitmap_top,
|
y - bglyph->top,
|
||||||
c);
|
c);
|
||||||
} else {
|
} else {
|
||||||
fb_16bpp_draw_ft_bitmap( &face->glyph->bitmap,
|
fb_16bpp_draw_ft_bitmap(&bglyph->bitmap,
|
||||||
x + face->glyph->bitmap_left,
|
x + bglyph->left,
|
||||||
y - face->glyph->bitmap_top,
|
y - bglyph->top,
|
||||||
c);
|
c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
x += glyph->advance.x >> 16;
|
||||||
x += face->glyph->advance.x >> 6;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -324,37 +324,34 @@ static bool fb_32bpp_text(int x, int y, const struct css_style *style,
|
||||||
{
|
{
|
||||||
uint32_t ucs4;
|
uint32_t ucs4;
|
||||||
size_t nxtchr = 0;
|
size_t nxtchr = 0;
|
||||||
FT_UInt glyph_index;
|
FT_Glyph glyph;
|
||||||
FT_Face face = fb_get_face(style);
|
FT_BitmapGlyph bglyph;
|
||||||
FT_Error error;
|
|
||||||
|
|
||||||
while (nxtchr < length) {
|
while (nxtchr < length) {
|
||||||
ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
|
ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
|
||||||
nxtchr = utf8_next(text, length, nxtchr);
|
nxtchr = utf8_next(text, length, nxtchr);
|
||||||
glyph_index = FT_Get_Char_Index(face, ucs4);
|
|
||||||
|
|
||||||
error = FT_Load_Glyph(face,
|
glyph = fb_getglyph(style, ucs4);
|
||||||
glyph_index,
|
if (glyph == NULL)
|
||||||
FT_LOAD_RENDER |
|
|
||||||
FT_LOAD_FORCE_AUTOHINT |
|
|
||||||
ft_load_type);
|
|
||||||
if (error)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* now, draw to our target surface */
|
if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
|
||||||
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
|
bglyph = (FT_BitmapGlyph)glyph;
|
||||||
fb_32bpp_draw_ft_monobitmap( &face->glyph->bitmap,
|
|
||||||
x + face->glyph->bitmap_left,
|
|
||||||
y - face->glyph->bitmap_top,
|
|
||||||
c);
|
|
||||||
} else {
|
|
||||||
fb_32bpp_draw_ft_bitmap( &face->glyph->bitmap,
|
|
||||||
x + face->glyph->bitmap_left,
|
|
||||||
y - face->glyph->bitmap_top,
|
|
||||||
c);
|
|
||||||
}
|
|
||||||
|
|
||||||
x += face->glyph->advance.x >> 6;
|
/* now, draw to our target surface */
|
||||||
|
if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
|
||||||
|
fb_32bpp_draw_ft_monobitmap(&bglyph->bitmap,
|
||||||
|
x + bglyph->left,
|
||||||
|
y - bglyph->top,
|
||||||
|
c);
|
||||||
|
} else {
|
||||||
|
fb_32bpp_draw_ft_bitmap(&bglyph->bitmap,
|
||||||
|
x + bglyph->left,
|
||||||
|
y - bglyph->top,
|
||||||
|
c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x += glyph->advance.x >> 16;
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,8 +26,9 @@ bool fb_font_finalise(void);
|
||||||
|
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
#include <freetype/ftglyph.h>
|
||||||
|
|
||||||
FT_Face fb_get_face(const struct css_style *style);
|
FT_Glyph fb_getglyph(const struct css_style *style, uint32_t ucs4);
|
||||||
|
|
||||||
extern int ft_load_type;
|
extern int ft_load_type;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <freetype/ftcache.h>
|
||||||
|
|
||||||
#include "css/css.h"
|
#include "css/css.h"
|
||||||
#include "render/font.h"
|
#include "render/font.h"
|
||||||
#include "desktop/options.h"
|
#include "desktop/options.h"
|
||||||
|
@ -30,10 +32,22 @@
|
||||||
#include "framebuffer/fb_font.h"
|
#include "framebuffer/fb_font.h"
|
||||||
|
|
||||||
static FT_Library library;
|
static FT_Library library;
|
||||||
static FT_Face face_sans_serif;
|
static FTC_Manager ft_cmanager;
|
||||||
|
static FTC_CMapCache ft_cmap_cache ;
|
||||||
|
static FTC_ImageCache ft_image_cache;
|
||||||
|
|
||||||
int ft_load_type;
|
int ft_load_type;
|
||||||
|
|
||||||
|
/* cache manager faceID data to create freetype faceid on demand */
|
||||||
|
typedef struct fb_faceid_s {
|
||||||
|
char *fontfile; /* path to font */
|
||||||
|
int index; /* index of font */
|
||||||
|
} fb_faceid_t;
|
||||||
|
|
||||||
|
|
||||||
|
static fb_faceid_t *fb_face_sans_serif; /* global default face */
|
||||||
|
|
||||||
|
|
||||||
utf8_convert_ret utf8_to_local_encoding(const char *string,
|
utf8_convert_ret utf8_to_local_encoding(const char *string,
|
||||||
size_t len,
|
size_t len,
|
||||||
char **result)
|
char **result)
|
||||||
|
@ -41,33 +55,66 @@ utf8_convert_ret utf8_to_local_encoding(const char *string,
|
||||||
return utf8_to_enc(string, "UTF-8", len, result);
|
return utf8_to_enc(string, "UTF-8", len, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* map cache manager handle to face id */
|
||||||
|
static FT_Error ft_face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *face )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
fb_faceid_t *fb_face = (fb_faceid_t *)face_id;
|
||||||
|
|
||||||
|
error = FT_New_Face(library, fb_face->fontfile, fb_face->index, face);
|
||||||
|
if (error) {
|
||||||
|
LOG(("Could not find font (code %d)\n", error));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(("Loaded face from %s\n", fb_face->fontfile));
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fb_faceid_t *
|
||||||
|
fb_new_face(const char *fontfile)
|
||||||
|
{
|
||||||
|
fb_faceid_t *newf;
|
||||||
|
newf = calloc(1, sizeof(fb_faceid_t));
|
||||||
|
newf->fontfile=strdup(fontfile);
|
||||||
|
return newf;
|
||||||
|
}
|
||||||
|
|
||||||
/* initialise font handling */
|
/* initialise font handling */
|
||||||
bool fb_font_init(void)
|
bool fb_font_init(void)
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
FT_Face aface;
|
||||||
|
|
||||||
|
/* freetype library initialise */
|
||||||
error = FT_Init_FreeType( &library );
|
error = FT_Init_FreeType( &library );
|
||||||
if (error) {
|
if (error) {
|
||||||
LOG(("Freetype could not initialised (code %d)\n", error));
|
LOG(("Freetype could not initialised (code %d)\n", error));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = FT_New_Face(library,
|
/* cache manager initialise */
|
||||||
"/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf",
|
error = FTC_Manager_New(library, 0, 0, 0, ft_face_requester, NULL, &ft_cmanager);
|
||||||
0,
|
if (error) {
|
||||||
&face_sans_serif );
|
LOG(("Freetype could not initialise cache manager (code %d)\n", error));
|
||||||
|
FT_Done_FreeType(library);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = FTC_CMapCache_New(ft_cmanager, &ft_cmap_cache);
|
||||||
|
|
||||||
|
error = FTC_ImageCache_New(ft_cmanager, &ft_image_cache);
|
||||||
|
|
||||||
|
|
||||||
|
fb_face_sans_serif = fb_new_face("/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf");
|
||||||
|
|
||||||
|
error = FTC_Manager_LookupFace(ft_cmanager, (FTC_FaceID)fb_face_sans_serif, &aface);
|
||||||
if (error) {
|
if (error) {
|
||||||
LOG(("Could not find default font (code %d)\n", error));
|
LOG(("Could not find default font (code %d)\n", error));
|
||||||
FT_Done_FreeType(library);
|
FT_Done_FreeType(library);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = FT_Set_Pixel_Sizes(face_sans_serif, 0, 14 );
|
|
||||||
if (error) {
|
|
||||||
LOG(("Could not set pixel size (code %d)\n", error));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the default render mode */
|
/* set the default render mode */
|
||||||
//ft_load_type = FT_LOAD_MONOCHROME; /* faster but less pretty */
|
//ft_load_type = FT_LOAD_MONOCHROME; /* faster but less pretty */
|
||||||
|
@ -82,35 +129,47 @@ bool fb_font_finalise(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fb_fill_scalar(const struct css_style *style, FTC_Scaler srec)
|
||||||
|
|
||||||
FT_Face
|
|
||||||
fb_get_face(const struct css_style *style)
|
|
||||||
{
|
{
|
||||||
FT_Face face;
|
srec->face_id = (FTC_FaceID)fb_face_sans_serif; /* should derive from style */
|
||||||
face = face_sans_serif;
|
|
||||||
FT_Error error;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
if (style->font_size.value.length.unit == CSS_UNIT_PX) {
|
if (style->font_size.value.length.unit == CSS_UNIT_PX) {
|
||||||
size = style->font_size.value.length.value;
|
srec->width = srec->height = style->font_size.value.length.value;
|
||||||
|
srec->pixel = 1;
|
||||||
error = FT_Set_Pixel_Sizes(face_sans_serif, 0, size );
|
|
||||||
if (error) {
|
|
||||||
LOG(("Could not set pixel size (code %d)\n", error));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
size = css_len2pt(&style->font_size.value.length, style);
|
srec->width = srec->height =
|
||||||
error = FT_Set_Char_Size( face, 0, size*64, 72, 72 );
|
css_len2pt(&style->font_size.value.length, style) * 64;
|
||||||
if (error) {
|
srec->pixel = 0;
|
||||||
LOG(("Could not set pixel size (code %d)\n", error));
|
|
||||||
}
|
srec->x_res = srec->y_res = 72;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return face;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FT_Glyph fb_getglyph(const struct css_style *style, uint32_t ucs4)
|
||||||
|
{
|
||||||
|
FT_UInt glyph_index;
|
||||||
|
FTC_ScalerRec srec;
|
||||||
|
FT_Glyph glyph;
|
||||||
|
FT_Error error;
|
||||||
|
|
||||||
|
fb_fill_scalar(style, &srec);
|
||||||
|
|
||||||
|
glyph_index = FTC_CMapCache_Lookup(ft_cmap_cache, srec.face_id, 0, ucs4);
|
||||||
|
|
||||||
|
error = FTC_ImageCache_LookupScaler(ft_image_cache,
|
||||||
|
&srec,
|
||||||
|
FT_LOAD_RENDER |
|
||||||
|
FT_LOAD_FORCE_AUTOHINT |
|
||||||
|
ft_load_type,
|
||||||
|
glyph_index,
|
||||||
|
&glyph,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
LOG(("Returning glyph %p for index %d advance %d", glyph, glyph_index,glyph->advance.x>>16));
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Measure the width of a string.
|
* Measure the width of a string.
|
||||||
*
|
*
|
||||||
|
@ -127,21 +186,18 @@ static bool nsfont_width(const struct css_style *style,
|
||||||
{
|
{
|
||||||
uint32_t ucs4;
|
uint32_t ucs4;
|
||||||
size_t nxtchr = 0;
|
size_t nxtchr = 0;
|
||||||
FT_UInt glyph_index;
|
FT_Glyph glyph;
|
||||||
FT_Face face = fb_get_face(style);
|
|
||||||
FT_Error error;
|
|
||||||
|
|
||||||
*width = 0;
|
*width = 0;
|
||||||
while (nxtchr < length) {
|
while (nxtchr < length) {
|
||||||
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
||||||
nxtchr = utf8_next(string, length, nxtchr);
|
nxtchr = utf8_next(string, length, nxtchr);
|
||||||
glyph_index = FT_Get_Char_Index(face, ucs4);
|
|
||||||
|
|
||||||
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
glyph = fb_getglyph(style, ucs4);
|
||||||
if (error)
|
if (glyph == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*width += face->glyph->advance.x >> 6;
|
*width += glyph->advance.x >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -166,20 +222,17 @@ static bool nsfont_position_in_string(const struct css_style *style,
|
||||||
{
|
{
|
||||||
uint32_t ucs4;
|
uint32_t ucs4;
|
||||||
size_t nxtchr = 0;
|
size_t nxtchr = 0;
|
||||||
FT_UInt glyph_index;
|
FT_Glyph glyph;
|
||||||
FT_Face face = fb_get_face(style);
|
|
||||||
FT_Error error;
|
|
||||||
|
|
||||||
*actual_x = 0;
|
*actual_x = 0;
|
||||||
while (nxtchr < length) {
|
while (nxtchr < length) {
|
||||||
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
||||||
glyph_index = FT_Get_Char_Index(face, ucs4);
|
|
||||||
|
|
||||||
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
glyph = fb_getglyph(style, ucs4);
|
||||||
if (error)
|
if (glyph == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*actual_x += face->glyph->advance.x >> 6;
|
*actual_x += glyph->advance.x >> 16;
|
||||||
if (*actual_x > x)
|
if (*actual_x > x)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -214,21 +267,16 @@ static bool nsfont_split(const struct css_style *style,
|
||||||
{
|
{
|
||||||
uint32_t ucs4;
|
uint32_t ucs4;
|
||||||
size_t nxtchr = 0;
|
size_t nxtchr = 0;
|
||||||
FT_UInt glyph_index;
|
|
||||||
FT_Face face = fb_get_face(style);
|
|
||||||
FT_Error error;
|
|
||||||
int last_space_x = 0;
|
int last_space_x = 0;
|
||||||
int last_space_idx = 0;
|
int last_space_idx = 0;
|
||||||
|
FT_Glyph glyph;
|
||||||
|
|
||||||
*actual_x = 0;
|
*actual_x = 0;
|
||||||
while (nxtchr < length) {
|
while (nxtchr < length) {
|
||||||
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
|
||||||
|
|
||||||
|
glyph = fb_getglyph(style, ucs4);
|
||||||
glyph_index = FT_Get_Char_Index(face, ucs4);
|
if (glyph == NULL)
|
||||||
|
|
||||||
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
|
||||||
if (error)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ucs4 == 0x20) {
|
if (ucs4 == 0x20) {
|
||||||
|
@ -236,7 +284,7 @@ static bool nsfont_split(const struct css_style *style,
|
||||||
last_space_idx = nxtchr;
|
last_space_idx = nxtchr;
|
||||||
}
|
}
|
||||||
|
|
||||||
*actual_x += face->glyph->advance.x >> 6;
|
*actual_x += glyph->advance.x >> 16;
|
||||||
if (*actual_x > x) {
|
if (*actual_x > x) {
|
||||||
/* string has exceeded available width return previous
|
/* string has exceeded available width return previous
|
||||||
* space
|
* space
|
||||||
|
|
Loading…
Reference in New Issue