/* * sc_interp.c * * Copyright © 2014 Thomas White * * This file is part of Colloquium. * * Colloquium 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 3 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, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "sc_parse.h" #include "sc_interp.h" #include "shape.h" #include "wrap.h" struct sc_state { PangoFontDescription *fontdesc; PangoFont *font; double col[4]; int ascent; int height; struct frame *fr; /* The current frame */ }; struct _scinterp { PangoContext *pc; PangoLanguage *lang; struct slide_constants *s_constants; struct presentation_constants *p_constants; struct sc_state *state; int j; /* Index of the current state */ int max_state; struct wrap_line *boxes; }; PangoFont *sc_interp_get_font(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->font; } PangoFontDescription *sc_interp_get_fontdesc(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->fontdesc; } double *sc_interp_get_fgcol(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->col; } int sc_interp_get_ascent(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->ascent; } int sc_interp_get_height(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->height; } static void set_font(SCInterpreter *scin, const char *font_name) { PangoFontMetrics *metrics; struct sc_state *st = &scin->state[scin->j]; st->fontdesc = pango_font_description_from_string(font_name); if ( st->fontdesc == NULL ) { fprintf(stderr, "Couldn't describe font.\n"); return; } st->font = pango_font_map_load_font(pango_context_get_font_map(scin->pc), scin->pc, st->fontdesc); if ( st->font == NULL ) { fprintf(stderr, "Couldn't load font.\n"); return; } /* FIXME: Language for box */ metrics = pango_font_get_metrics(st->font, NULL); st->ascent = pango_font_metrics_get_ascent(metrics); st->height = st->ascent + pango_font_metrics_get_descent(metrics); pango_font_metrics_unref(metrics); } /* This sets the colour for the font at the top of the stack */ static void set_colour(SCInterpreter *scin, const char *colour) { GdkRGBA col; struct sc_state *st = &scin->state[scin->j]; if ( colour == NULL ) { printf("Invalid colour\n"); st->col[0] = 0.0; st->col[1] = 0.0; st->col[2] = 0.0; st->col[3] = 1.0; return; } gdk_rgba_parse(&col, colour); st->col[0] = col.red; st->col[1] = col.green; st->col[2] = col.blue; st->col[3] = col.alpha; } void sc_interp_save(SCInterpreter *scin) { if ( scin->j+1 == scin->max_state ) { struct sc_state *stack_new; stack_new = realloc(scin->state, sizeof(struct sc_state) * (scin->max_state+8)); if ( stack_new == NULL ) { fprintf(stderr, "Failed to add to stack.\n"); return; } scin->state = stack_new; scin->max_state += 8; } /* When n_fonts=0, we leave the first font uninitialised. This allows * the stack to be "bootstrapped", but requires the first caller to do * set_font and set_colour straight away. */ scin->state[scin->j+1] = scin->state[scin->j]; scin->j++; } void sc_interp_restore(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; if ( scin->j > 0 ) { if ( st->fontdesc != scin->state[scin->j-1].fontdesc ) { pango_font_description_free(st->fontdesc); } /* else the font is the same as the previous one, and we * don't need to free it just yet */ } scin->j--; } struct frame *sc_interp_get_frame(SCInterpreter *scin) { struct sc_state *st = &scin->state[scin->j]; return st->fr; } static void set_frame(SCInterpreter *scin, struct frame *fr) { struct sc_state *st = &scin->state[scin->j]; st->fr = fr; } SCInterpreter *sc_interp_new(PangoContext *pc, struct frame *top) { SCInterpreter *scin; scin = malloc(sizeof(SCInterpreter)); if ( scin == NULL ) return NULL; scin->state = malloc(8*sizeof(struct sc_state)); if ( scin->state == NULL ) { free(scin); return NULL; } scin->j = 0; scin->max_state = 8; scin->pc = pc; scin->s_constants = NULL; scin->p_constants = NULL; /* FIXME: Determine proper language (somehow...) */ scin->lang = pango_language_from_string("en_GB"); scin->boxes = malloc(sizeof(struct wrap_line)); if ( scin->boxes == NULL ) { fprintf(stderr, "Failed to allocate boxes.\n"); return NULL; } initialise_line(scin->boxes); /* The "ultimate" default font */ set_font(scin, "Sans 12"); set_colour(scin, "#000000"); set_frame(scin, top); return scin; } void sc_interp_destroy(SCInterpreter *scin) { /* Empty the stack */ while ( scin->j > 0 ) { sc_interp_restore(scin); } pango_font_description_free(scin->state[0].fontdesc); free(scin); } static LengthUnits get_units(const char *t) { size_t len = strlen(t); if ( t[len-1] == 'f' ) return UNITS_FRAC; if ( t[len-1] == 'u' ) return UNITS_SLIDE; fprintf(stderr, "Invalid units in '%s'\n", t); return UNITS_SLIDE; } static void parse_frame_option(struct frame *fr, struct frame *parent, const char *opt) { if ( (index(opt, 'x') != NULL) && (index(opt, '+') != NULL) && (index(opt, '+') != rindex(opt, '+')) ) { char *w; char *h; char *x; char *y; char *check; LengthUnits h_units, w_units; /* Looks like a dimension/position thing */ w = strdup(opt); h = index(w, 'x'); h[0] = '\0'; h++; x = index(h, '+'); if ( x == NULL ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } x[0] = '\0'; x++; y = index(x, '+'); if ( x == NULL ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } y[0] = '\0'; y++; fr->w = strtod(w, &check); if ( check == w ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } w_units = get_units(w); if ( w_units == UNITS_FRAC ) { fr->w = parent->w * fr->w; } fr->h = strtod(h, &check); if ( check == h ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } h_units = get_units(h); if ( h_units == UNITS_FRAC ) { fr->h = parent->h * fr->h; } fr->x = strtod(x, &check); if ( check == x ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } fr->y = strtod(y, &check); if ( check == y ) { fprintf(stderr, "Invalid option '%s'\n", opt); return; } } } static void parse_frame_options(struct frame *fr, struct frame *parent, const char *opth) { int i; size_t len; size_t start; char *opt; if ( opth == NULL ) return; opt = strdup(opth); len = strlen(opt); start = 0; for ( i=0; iboxes, scin->pc, contents, scin->lang, 1, scin); } else if ( strcmp(name, "font") == 0 ) { set_font(scin, options); } else if ( strcmp(name, "fgcol") == 0 ) { set_colour(scin, options); #if 0 } else if ( strcmp(name, "image")==0 ) { int w, h; if ( get_size(options, fr, &w, &h) == 0 ) { add_image_box(boxes, b->contents, offset, w, h, editable); } } else if ( strcmp(name, "slidenumber")==0) { char *tmp = malloc(64); if ( tmp != NULL ) { snprintf(tmp, 63, "%i", slide_constants->slide_number); add_wrap_box(boxes, tmp, offset, WRAP_SPACE_NONE, pc, &fonts->stack[fonts->n_fonts-1], 0); } /* else go away and sulk about it */ #endif } else if ( strcmp(name, "f")==0 ) { struct frame *fr = sc_block_frame(bl); if ( fr == NULL ) { fr = add_subframe(sc_interp_get_frame(scin)); sc_block_set_frame(bl, fr); fr->scblocks = child; } if ( fr == NULL ) { fprintf(stderr, "Failed to add frame.\n"); goto next; } parse_frame_options(fr, sc_interp_get_frame(scin), options); set_frame(scin, fr); } else { fprintf(stderr, "Don't know what to do with this:\n"); show_sc_block(bl, ""); } next: if ( child != NULL ) { sc_interp_add_blocks(scin, child); sc_interp_restore(scin); } bl = sc_block_next(bl); } return 0; } struct wrap_line *sc_interp_get_boxes(SCInterpreter *scin) { return scin->boxes; }