From 2ddfa640af28b592ecf4295f0b1b7b43c923f707 Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Fri, 15 Jan 2010 19:32:29 -0800 Subject: [PATCH] added kerning to fonts --- lib/gfxdevice.h | 8 ++++++ lib/pdf/InfoOutputDev.cc | 62 +++++++++++++++++++++++++++++++++++++++- lib/pdf/InfoOutputDev.h | 4 +++ lib/q.c | 67 +++++++++++++++++++++++++++++++++++++++++++ lib/q.h | 17 +++++++++++ lib/ruby/gfx.c | 19 +++++++++++++ lib/xml.c | 71 +++++++++++++++++++++++++--------------------- 7 files changed, 215 insertions(+), 33 deletions(-) diff --git a/lib/gfxdevice.h b/lib/gfxdevice.h index 2e508bf..181d0b9 100644 --- a/lib/gfxdevice.h +++ b/lib/gfxdevice.h @@ -30,6 +30,11 @@ typedef struct _gfxglyph const char*name; } gfxglyph_t; +typedef struct _gfxkerning +{ + int c1,c2,advance; +} gfxkerning_t; + typedef struct _gfxfont { const char*id; @@ -40,6 +45,9 @@ typedef struct _gfxfont gfxglyph_t*glyphs; int* unicode2glyph; + + gfxkerning_t*kerning; + int kerning_size; } gfxfont_t; typedef struct _gfxcolor diff --git a/lib/pdf/InfoOutputDev.cc b/lib/pdf/InfoOutputDev.cc index 6e20426..3c65bd8 100644 --- a/lib/pdf/InfoOutputDev.cc +++ b/lib/pdf/InfoOutputDev.cc @@ -15,6 +15,7 @@ #endif #include "GfxState.h" #include "../log.h" +#include "../types.h" #include "../q.h" #include #include @@ -52,11 +53,14 @@ InfoOutputDev::~InfoOutputDev() delete id2font;id2font=0; delete splash;splash=0; } + void FontInfo::grow(int size) { if(size >= this->num_glyphs) { this->glyphs = (GlyphInfo**)realloc(this->glyphs, sizeof(GlyphInfo*)*(size)); + this->kerning = (dict_t**)realloc(this->kerning, sizeof(dict_t*)*(size)); memset(&this->glyphs[this->num_glyphs], 0, sizeof(SplashPath*)*((size)-this->num_glyphs)); + memset(&this->kerning[this->num_glyphs], 0, sizeof(dict_t*)*((size)-this->num_glyphs)); this->num_glyphs = size; } } @@ -67,6 +71,7 @@ FontInfo::FontInfo(char*id) this->seen = 0; this->num_glyphs = 0; this->glyphs = 0; + this->kerning = 0; this->splash_font = 0; this->lastchar = -1; this->lastx = 0; @@ -93,6 +98,17 @@ FontInfo::~FontInfo() free(glyphs);glyphs=0; if(this->gfxfont) gfxfont_free(this->gfxfont); + + if(kerning) { + for(t=0;tnum_glyphs;t++) { + dict_t* d = src->kerning[t]; + if(!d) continue; + DICT_ITERATE_ITEMS(d,void*,key,mtf_t*,m) { + if(m) { + kerning_size++; + } + } + } + font->kerning_size = kerning_size; + font->kerning = (gfxkerning_t*)malloc(sizeof(gfxkerning_t)*kerning_size); + int pos = 0; + for(t=0;tnum_glyphs;t++) { + dict_t* d = src->kerning[t]; + if(!d) continue; + DICT_ITERATE_ITEMS(d,void*,key,mtf_t*,m) { + if(m) { + font->kerning[pos].c1 = t; + font->kerning[pos].c2 = (int)(ptroff_t)key; + font->kerning[pos].advance = (int)(ptroff_t)m->first->key; + pos++; + } + } + } + //int advance = (int)(ptroff_t)m->first->key; + return font; } @@ -407,15 +451,31 @@ void InfoOutputDev::drawChar(GfxState *state, double x, double y, g->unicode = u[0]; } if(currentfont->lastchar>=0 && currentfont->lasty == y) { - double xshift = x - currentfont->lastx; + double xshift = (x - currentfont->lastx); if(xshift>=0 && xshift > g->advance_max) { g->advance_max = xshift; } + int advance = (int)xshift; + if(advance>=0 && advanceadvance*4 && advance!=currentfont->lastadvance) { + int c1 = currentfont->lastchar; + int c2 = code; + dict_t*d = currentfont->kerning[c1]; + if(!d) { + d = currentfont->kerning[c1] = dict_new2(&int_type); + } + mtf_t*k = (mtf_t*)dict_lookup(d, (void*)(ptroff_t)c2); + if(!k) { + k = mtf_new(&int_type); + dict_put(d, (void*)(ptroff_t)c2, k); + } + mtf_increase(k, (void*)(ptroff_t)advance); + } } currentfont->lastx = x; currentfont->lasty = y; currentfont->lastchar = code; + currentfont->lastadvance = (int)(g->advance+0.5); } GBool InfoOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) diff --git a/lib/pdf/InfoOutputDev.h b/lib/pdf/InfoOutputDev.h index 0934add..e5ea3c6 100644 --- a/lib/pdf/InfoOutputDev.h +++ b/lib/pdf/InfoOutputDev.h @@ -44,6 +44,7 @@ #include "../gfxdevice.h" #include "../gfxtools.h" #include "../gfxfont.h" +#include "../q.h" #define INTERNAL_FONT_SIZE 1024.0 #define GLYPH_IS_SPACE(g) ((!(g)->line || ((g)->line->type==gfx_moveTo && !(g)->line->next)) && (g)->advance) @@ -72,6 +73,7 @@ public: double lastx,lasty; int lastchar; + int lastadvance; double ascender,descender; @@ -81,6 +83,8 @@ public: double max_size; int num_glyphs; GlyphInfo**glyphs; + dict_t**kerning; + int*charid2glyph; SplashFont*splash_font; char seen; diff --git a/lib/q.c b/lib/q.c index a2d7a63..8971616 100644 --- a/lib/q.c +++ b/lib/q.c @@ -887,6 +887,23 @@ void ptr_free(void*o) return; } +char int_equals(const void*o1, const void*o2) +{ + return o1==o2; +} +unsigned int int_hash(const void*o) +{ + return string_hash3((const char*)&o, sizeof(o)); +} +void* int_dup(const void*o) +{ + return (void*)o; +} +void int_free(void*o) +{ + return; +} + char charptr_equals(const void*o1, const void*o2) { if(!o1 || !o2) @@ -952,6 +969,13 @@ void stringstruct_free(void*o) string_free(o); } +type_t int_type = { + equals: int_equals, + hash: int_hash, + dup: int_dup, + free: int_free, +}; + type_t ptr_type = { equals: ptr_equals, hash: ptr_hash, @@ -1302,6 +1326,49 @@ void dict_destroy(dict_t*dict) rfx_free(dict); } +// ------------------------------- mtf_t -------------------------------------- +mtf_t* mtf_new(type_t*type) +{ + NEW(mtf_t, mtf); + mtf->type = type; + return mtf; +} +void mtf_increase(mtf_t*m, const void*key) +{ + mtf_item_t*item = m->first; + mtf_item_t*last = 0; + while(item) { + if(m->type->equals(item->key, key)) { + item->num++; + if(last) last->next = item->next; + else m->first = item->next; + item->next = m->first; + m->first = item; + return; + } + last = item; + item = item->next; + } + NEW(mtf_item_t,n); + if(last) last->next = n; + else m->first = n; + n->key = key; + n->num = 1; +} +void mtf_destroy(mtf_t*m) +{ + if(!m) return; + mtf_item_t*item = m->first; + m->first = 0; + while(item) { + mtf_item_t*next = item->next; + item->next = 0; + free(item); + item = next; + } + free(m); +} + // ------------------------------- map_t -------------------------------------- typedef struct _map_internal_t diff --git a/lib/q.h b/lib/q.h index f6d597d..2ea7fe1 100644 --- a/lib/q.h +++ b/lib/q.h @@ -73,6 +73,7 @@ typedef struct _type_t { extern type_t charptr_type; extern type_t stringstruct_type; extern type_t ptr_type; +extern type_t int_type; typedef struct _dictentry { void*key; @@ -132,6 +133,18 @@ typedef struct _trie { void*rollback; } trie_t; +/* move to front list structure */ +typedef struct _mtf_item { + const void*key; + int num; + struct _mtf_item*next; +} mtf_item_t; + +typedef struct _mtf { + mtf_item_t*first; + type_t*type; +} mtf_t; + char* strdup_n(const char*str, int size); char* allocprintf(const char*str, ...); @@ -242,6 +255,10 @@ void trie_remember(trie_t*t); void trie_rollback(trie_t*t); void trie_dump(trie_t*t); +mtf_t* mtf_new(type_t*type); +void mtf_increase(mtf_t*m, const void*key); +void mtf_destroy(mtf_t*m); + array_t* array_new(); array_t* array_new2(type_t*type); void array_free(array_t*array); diff --git a/lib/ruby/gfx.c b/lib/ruby/gfx.c index 958ce40..9384d19 100644 --- a/lib/ruby/gfx.c +++ b/lib/ruby/gfx.c @@ -347,6 +347,23 @@ static VALUE font_glyphs(VALUE cls) return font->glyph_array; } +static VALUE font_kerning(VALUE cls) +{ + Get_Font(font,cls); + gfxkerning_t*kerning = font->font->kerning; + int kerning_size = font->font->kerning_size; + volatile VALUE a = rb_ary_new2(kerning_size); + int t; + for(t=0;t ? 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 9, 4, 7, @@ -48,7 +48,7 @@ static int group[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f // P Q R S T U V W X Y Z [ \ ] ^ _ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11, 0,12, 0, 0, // 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f // ` a b c d e f g h i j k l m n o 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -97,32 +97,32 @@ static const char*errors[]= }; static int new_state[][16]= -{ /* dt ws " < > & ; ? / = EOB*/ - /* 0 */{ E1, 0,E1, 1,E1,E1,E1,E1,E1,E1,-63}, // .< - /* 1 */{ E1,E1,E1,E1,E1,E1,E1, 9,E1,E1,-63}, // <.? - /* 2 */{ -3, 2,E3,E2,E2,E2,E2,E2,12,E2,-63}, // <. - /* 3 */{ E3,E3,E3,E3,-1,E3,E3,E3,E3,E1,-63}, // < /.> - /* 4 */{ E3,E3,E3,E3,-2,E3,E3,E3,E3,E1,-63}, // < .> - /* 5 */{ 5, 5, 5,-4, 5, 5, 5, 5, 5, 5,-63}, // da.ta - /* 6 */{ 6,-7,E3,E2,-6,E2,E2,E3,-9,E3,-63}, // & ; ? / = ! [ ] - EOB*/ + /* 0 */{ E1, 0,E1, 1,E1,E1,E1,E1,E1,E1,E3,E1,E1,-63}, // .< + /* 1 */{ E1,E1,E1,E1,E1,E1,E1, 9,E1,E1,E3,E1,E1,-63}, // <.? + /* 2 */{ -3, 2,E3,E2,E2,E2,E2,E2,12,E2,16,E2,E2,-63}, // <. + /* 3 */{ E3,E3,E3,E3,-1,E3,E3,E3,E3,E1,E3,E3,E3,-63}, // < /.> + /* 4 */{ E3,E3,E3,E3,-2,E3,E3,E3,E3,E1,E1,E3,E3,-63}, // < .> + /* 5 */{ 5, 5, 5,-4, 5, 5, 5, 5, 5, 5, 5,E3,E3,-63}, // da.ta + /* 6 */{ 6,-7,E3,E2,-6,E2,E2,E3,-9,E3,E3,E3,E3,-63}, //