diff options
author | Perberos <[email protected]> | 2011-11-09 18:17:43 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-11-09 18:17:43 -0300 |
commit | f6ce926719943751cf65cacde7fae050593eb2d6 (patch) | |
tree | 9224d1751678cf2d1fbd0431f128b711311c0287 /backend/dvi/mdvi-lib/font.c | |
download | atril-f6ce926719943751cf65cacde7fae050593eb2d6.tar.bz2 atril-f6ce926719943751cf65cacde7fae050593eb2d6.tar.xz |
inicial
Diffstat (limited to 'backend/dvi/mdvi-lib/font.c')
-rw-r--r-- | backend/dvi/mdvi-lib/font.c | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/backend/dvi/mdvi-lib/font.c b/backend/dvi/mdvi-lib/font.c new file mode 100644 index 00000000..2f655df0 --- /dev/null +++ b/backend/dvi/mdvi-lib/font.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2000, Matias Atria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <config.h> +#include <stdlib.h> + +#include "mdvi.h" +#include "private.h" + +static ListHead fontlist; + +extern char *_mdvi_fallback_font; + +extern void vf_free_macros(DviFont *); + +#define finfo search.info +#define TYPENAME(font) \ + ((font)->finfo ? (font)->finfo->name : "none") + +int font_reopen(DviFont *font) +{ + if(font->in) + fseek(font->in, (long)0, SEEK_SET); + else if((font->in = fopen(font->filename, "rb")) == NULL) { + DEBUG((DBG_FILES, "reopen(%s) -> Error\n", font->filename)); + return -1; + } + DEBUG((DBG_FILES, "reopen(%s) -> Ok.\n", font->filename)); + return 0; +} + +/* used from context: params and device */ +static int load_font_file(DviParams *params, DviFont *font) +{ + int status; + + if(SEARCH_DONE(font->search)) + return -1; + if(font->in == NULL && font_reopen(font) < 0) + return -1; + DEBUG((DBG_FONTS, "%s: loading %s font from `%s'\n", + font->fontname, + font->finfo->name, font->filename)); + do { + status = font->finfo->load(params, font); + } while(status < 0 && mdvi_font_retry(params, font) == 0); + if(status < 0) + return -1; + if(font->in) { + fclose(font->in); + font->in = NULL; + } + DEBUG((DBG_FONTS, "reload_font(%s) -> %s\n", + font->fontname, status < 0 ? "Error" : "Ok")); + return 0; +} + +void font_drop_one(DviFontRef *ref) +{ + DviFont *font; + + font = ref->ref; + mdvi_free(ref); + /* drop all children */ + for(ref = font->subfonts; ref; ref = ref->next) { + /* just adjust the reference counts */ + ref->ref->links--; + } + if(--font->links == 0) { + /* + * this font doesn't have any more references, but + * we still keep it around in case a virtual font + * requests it. + */ + if(font->in) { + fclose(font->in); + font->in = NULL; + } + if(LIST(font) != fontlist.tail) { + /* move it to the end of the list */ + listh_remove(&fontlist, LIST(font)); + listh_append(&fontlist, LIST(font)); + } + } + DEBUG((DBG_FONTS, "%s: reference dropped, %d more left\n", + font->fontname, font->links)); +} + +void font_drop_chain(DviFontRef *head) +{ + DviFontRef *ptr; + + for(; (ptr = head); ) { + head = ptr->next; + font_drop_one(ptr); + } +} + +int font_free_unused(DviDevice *dev) +{ + DviFont *font, *next; + int count = 0; + + DEBUG((DBG_FONTS, "destroying unused fonts\n")); + for(font = (DviFont *)fontlist.head; font; font = next) { + DviFontRef *ref; + + next = font->next; + if(font->links) + continue; + count++; + DEBUG((DBG_FONTS, "removing unused %s font `%s'\n", + TYPENAME(font), font->fontname)); + listh_remove(&fontlist, LIST(font)); + if(font->in) + fclose(font->in); + /* get rid of subfonts (but can't use `drop_chain' here) */ + for(; (ref = font->subfonts); ) { + font->subfonts = ref->next; + mdvi_free(ref); + } + /* remove this font */ + font_reset_font_glyphs(dev, font, MDVI_FONTSEL_GLYPH); + /* let the font destroy its private data */ + if(font->finfo->freedata) + font->finfo->freedata(font); + /* destroy characters */ + if(font->chars) + mdvi_free(font->chars); + mdvi_free(font->fontname); + mdvi_free(font->filename); + mdvi_free(font); + } + DEBUG((DBG_FONTS, "%d unused fonts removed\n", count)); + return count; +} + +/* used from context: params and device */ +DviFontRef * +font_reference( + DviParams *params, /* rendering parameters */ + Int32 id, /* external id number */ + const char *name, /* font name */ + Int32 sum, /* checksum (from DVI of VF) */ + int hdpi, /* resolution */ + int vdpi, + Int32 scale) /* scaling factor (from DVI or VF) */ +{ + DviFont *font; + DviFontRef *ref; + DviFontRef *subfont_ref; + + /* see if there is a font with the same characteristics */ + for(font = (DviFont *)fontlist.head; font; font = font->next) { + if(strcmp(name, font->fontname) == 0 + && (!sum || !font->checksum || font->checksum == sum) + && font->hdpi == hdpi + && font->vdpi == vdpi + && font->scale == scale) + break; + } + /* try to load the font */ + if(font == NULL) { + font = mdvi_add_font(name, sum, hdpi, vdpi, scale); + if(font == NULL) + return NULL; + listh_append(&fontlist, LIST(font)); + } + if(!font->links && !font->chars && load_font_file(params, font) < 0) { + DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name)); + return NULL; + } + ref = xalloc(DviFontRef); + ref->ref = font; + + font->links++; + for(subfont_ref = font->subfonts; subfont_ref; subfont_ref = subfont_ref->next) { + /* just adjust the reference counts */ + subfont_ref->ref->links++; + } + + ref->fontid = id; + + if(LIST(font) != fontlist.head) { + listh_remove(&fontlist, LIST(font)); + listh_prepend(&fontlist, LIST(font)); + } + + DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n", + font->fontname, font->links)); + return ref; +} + +void font_transform_glyph(DviOrientation orient, DviGlyph *g) +{ + BITMAP *map; + int x, y; + + map = (BITMAP *)g->data; + if(MDVI_GLYPH_ISEMPTY(map)) + map = NULL; + + /* put the glyph in the right orientation */ + switch(orient) { + case MDVI_ORIENT_TBLR: + break; + case MDVI_ORIENT_TBRL: + g->x = g->w - g->x; + if(map) bitmap_flip_horizontally(map); + break; + case MDVI_ORIENT_BTLR: + g->y = g->h - g->y; + if(map) bitmap_flip_vertically(map); + break; + case MDVI_ORIENT_BTRL: + g->x = g->w - g->x; + g->y = g->h - g->y; + if(map) bitmap_flip_diagonally(map); + break; + case MDVI_ORIENT_RP90: + if(map) bitmap_rotate_counter_clockwise(map); + y = g->y; + x = g->w - g->x; + g->x = y; + g->y = x; + SWAPINT(g->w, g->h); + break; + case MDVI_ORIENT_RM90: + if(map) bitmap_rotate_clockwise(map); + y = g->h - g->y; + x = g->x; + g->x = y; + g->y = x; + SWAPINT(g->w, g->h); + break; + case MDVI_ORIENT_IRP90: + if(map) bitmap_flip_rotate_counter_clockwise(map); + y = g->y; + x = g->x; + g->x = y; + g->y = x; + SWAPINT(g->w, g->h); + break; + case MDVI_ORIENT_IRM90: + if(map) bitmap_flip_rotate_clockwise(map); + y = g->h - g->y; + x = g->w - g->x; + g->x = y; + g->y = x; + SWAPINT(g->w, g->h); + break; + } +} + +static int load_one_glyph(DviContext *dvi, DviFont *font, int code) +{ + BITMAP *map; + DviFontChar *ch; + int status; + +#ifndef NODEBUG + ch = FONTCHAR(font, code); + DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n", + code, font->fontname, ch->offset)); +#endif + if(font->finfo->getglyph == NULL) { + /* font type does not need to load glyphs (e.g. vf) */ + return 0; + } + + status = font->finfo->getglyph(&dvi->params, font, code); + if(status < 0) + return -1; + /* get the glyph again (font->chars may have changed) */ + ch = FONTCHAR(font, code); +#ifndef NODEBUG + map = (BITMAP *)ch->glyph.data; + if(DEBUGGING(BITMAP_DATA)) { + DEBUG((DBG_BITMAP_DATA, + "%s: new %s bitmap for character %d:\n", + font->fontname, TYPENAME(font), code)); + if(MDVI_GLYPH_ISEMPTY(map)) + DEBUG((DBG_BITMAP_DATA, "blank bitmap\n")); + else + bitmap_print(stderr, map); + } +#endif + /* check if we have to scale it */ + if(!font->finfo->scalable && font->hdpi != font->vdpi) { + int hs, vs, d; + + /* we scale it ourselves */ + d = Max(font->hdpi, font->vdpi); + hs = d / font->hdpi; + vs = d / font->vdpi; + if(ch->width && ch->height && (hs > 1 || vs > 1)) { + int h, v; + DviGlyph glyph; + + DEBUG((DBG_FONTS, + "%s: scaling glyph %d to resolution %dx%d\n", + font->fontname, code, font->hdpi, font->vdpi)); + h = dvi->params.hshrink; + v = dvi->params.vshrink; + d = dvi->params.density; + dvi->params.hshrink = hs; + dvi->params.vshrink = vs; + dvi->params.density = 50; + /* shrink it */ + font->finfo->shrink0(dvi, font, ch, &glyph); + /* restore parameters */ + dvi->params.hshrink = h; + dvi->params.vshrink = v; + dvi->params.density = d; + /* update glyph data */ + if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data)) + bitmap_destroy((BITMAP *)ch->glyph.data); + ch->glyph.data = glyph.data; + ch->glyph.x = glyph.x; + ch->glyph.y = glyph.y; + ch->glyph.w = glyph.w; + ch->glyph.h = glyph.h; + } + + } + font_transform_glyph(dvi->params.orientation, &ch->glyph); + + return 0; +} + +DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code) +{ + DviFontChar *ch; + +again: + /* if we have not loaded the font yet, do so now */ + if(!font->chars && load_font_file(&dvi->params, font) < 0) + return NULL; + + /* get the unscaled glyph, maybe loading it from disk */ + ch = FONTCHAR(font, code); + if(!ch || !glyph_present(ch)) + return NULL; + if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) { + if(font->chars == NULL) { + /* we need to try another font class */ + goto again; + } + return NULL; + } + /* yes, we have to do this again */ + ch = FONTCHAR(font, code); + + /* Got the glyph. If we also have the right scaled glyph, do no more */ + if(!ch->width || !ch->height || + font->finfo->getglyph == NULL || + (dvi->params.hshrink == 1 && dvi->params.vshrink == 1)) + return ch; + + /* If the glyph is empty, we just need to shrink the box */ + if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) { + if(MDVI_GLYPH_UNSET(ch->shrunk.data)) + mdvi_shrink_box(dvi, font, ch, &ch->shrunk); + return ch; + } else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) { + if(ch->grey.data && + !MDVI_GLYPH_ISEMPTY(ch->grey.data) && + ch->fg == dvi->curr_fg && + ch->bg == dvi->curr_bg) + return ch; + if(ch->grey.data && + !MDVI_GLYPH_ISEMPTY(ch->grey.data)) { + if(dvi->device.free_image) + dvi->device.free_image(ch->grey.data); + ch->grey.data = NULL; + } + font->finfo->shrink1(dvi, font, ch, &ch->grey); + } else if(!ch->shrunk.data) + font->finfo->shrink0(dvi, font, ch, &ch->shrunk); + + return ch; +} + +void font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what) +{ + if(!glyph_present(ch)) + return; + if(what & MDVI_FONTSEL_BITMAP) { + if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data)) + bitmap_destroy((BITMAP *)ch->shrunk.data); + ch->shrunk.data = NULL; + } + if(what & MDVI_FONTSEL_GREY) { + if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) { + if(dev->free_image) + dev->free_image(ch->grey.data); + } + ch->grey.data = NULL; + } + if(what & MDVI_FONTSEL_GLYPH) { + if(MDVI_GLYPH_NONEMPTY(ch->glyph.data)) + bitmap_destroy((BITMAP *)ch->glyph.data); + ch->glyph.data = NULL; + ch->loaded = 0; + } +} + +void font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what) +{ + int i; + DviFontChar *ch; + + if(what & MDVI_FONTSEL_GLYPH) + what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY; + if(font->subfonts) { + DviFontRef *ref; + + for(ref = font->subfonts; ref; ref = ref->next) + font_reset_font_glyphs(dev, ref->ref, what); + } + if(font->in) { + DEBUG((DBG_FILES, "close(%s)\n", font->filename)); + fclose(font->in); + font->in = NULL; + } + if(font->finfo->getglyph == NULL) + return; + DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname)); + for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) { + if(glyph_present(ch)) + font_reset_one_glyph(dev, ch, what); + } + if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset) + font->finfo->reset(font); +} + +void font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what) +{ + DviFontRef *ref; + + for(ref = head; ref; ref = ref->next) + font_reset_font_glyphs(dev, ref->ref, what); +} + +static int compare_refs(const void *p1, const void *p2) +{ + return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid); +} + +void font_finish_definitions(DviContext *dvi) +{ + int count; + DviFontRef **map, *ref; + + /* first get rid of unused fonts */ + font_free_unused(&dvi->device); + + if(dvi->fonts == NULL) { + mdvi_warning(_("%s: no fonts defined\n"), dvi->filename); + return; + } + map = xnalloc(DviFontRef *, dvi->nfonts); + for(count = 0, ref = dvi->fonts; ref; ref = ref->next) + map[count++] = ref; + /* sort the array by font id */ + qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs); + dvi->fontmap = map; +} + +DviFontRef *font_find_flat(DviContext *dvi, Int32 id) +{ + DviFontRef *ref; + + for(ref = dvi->fonts; ref; ref = ref->next) + if(ref->fontid == id) + break; + return ref; +} + +DviFontRef *font_find_mapped(DviContext *dvi, Int32 id) +{ + int lo, hi, n; + DviFontRef **map; + + /* do a binary search */ + lo = 0; hi = dvi->nfonts; + map = dvi->fontmap; + while(lo < hi) { + int sign; + + n = (hi + lo) >> 1; + sign = (map[n]->fontid - id); + if(sign == 0) + break; + else if(sign < 0) + lo = n; + else + hi = n; + } + if(lo >= hi) + return NULL; + return map[n]; +} + |