X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fdevices%2Frecord.c;h=d0d771516acc6598200039d0e0aed6c61db79a58;hp=a8a0088672b5ea848c97cc726d857c3204b00077;hb=122910b2a27ff211d01e633e14f29bb0653b4631;hpb=e0a702738ce558dd303389b345ec5349f39a5ccf diff --git a/lib/devices/record.c b/lib/devices/record.c index a8a0088..d0d7715 100644 --- a/lib/devices/record.c +++ b/lib/devices/record.c @@ -30,20 +30,34 @@ #include #endif #include +#include #include "../gfxdevice.h" #include "../gfxtools.h" #include "../types.h" #include "../bitio.h" #include "../log.h" +#include "../os.h" #include "record.h" +typedef struct _state { + char*last_string[16]; + gfxcolor_t last_color[16]; + gfxmatrix_t last_matrix[16]; +} state_t; + typedef struct _internal { gfxfontlist_t* fontlist; + state_t state; + writer_t w; int cliplevel; + char use_tempfile; + char*filename; } internal_t; typedef struct _internal_result { + char use_tempfile; + char*filename; void*data; int length; } internal_result_t; @@ -63,9 +77,11 @@ typedef struct _internal_result { #define OP_ENDPAGE 0x0c #define OP_FINISH 0x0d -#define OP_MOVETO 0x0e -#define OP_LINETO 0x0f -#define OP_SPLINETO 0x10 +#define FLAG_SAME_AS_LAST 0x10 + +#define LINE_MOVETO 0x0e +#define LINE_LINETO 0x0f +#define LINE_SPLINETO 0x10 static int record_setparameter(struct _gfxdevice*dev, const char*key, const char*value) { @@ -81,15 +97,15 @@ static void dumpLine(writer_t*w, gfxline_t*line) { while(line) { if(line->type == gfx_moveTo) { - writer_writeU8(w, OP_MOVETO); + writer_writeU8(w, LINE_MOVETO); writer_writeDouble(w, line->x); writer_writeDouble(w, line->y); } else if(line->type == gfx_lineTo) { - writer_writeU8(w, OP_LINETO); + writer_writeU8(w, LINE_LINETO); writer_writeDouble(w, line->x); writer_writeDouble(w, line->y); } else if(line->type == gfx_splineTo) { - writer_writeU8(w, OP_SPLINETO); + writer_writeU8(w, LINE_SPLINETO); writer_writeDouble(w, line->x); writer_writeDouble(w, line->y); writer_writeDouble(w, line->sx); @@ -113,15 +129,15 @@ static gfxline_t* readLine(reader_t*r) pos->next = line; pos = line; } - if(op == OP_MOVETO) { + if(op == LINE_MOVETO) { line->type = gfx_moveTo; line->x = reader_readDouble(r); line->y = reader_readDouble(r); - } else if(op == OP_LINETO) { + } else if(op == LINE_LINETO) { line->type = gfx_lineTo; line->x = reader_readDouble(r); line->y = reader_readDouble(r); - } else if(op == OP_SPLINETO) { + } else if(op == LINE_SPLINETO) { line->type = gfx_splineTo; line->x = reader_readDouble(r); line->y = reader_readDouble(r); @@ -160,6 +176,12 @@ static gfxcolor_t readColor(reader_t*r) col.a = reader_readU8(r); return col; } +static void readXY(reader_t*r, gfxmatrix_t*m) +{ + m->tx = reader_readDouble(r); + m->ty = reader_readDouble(r); +} + static gfxgradient_t* readGradient(reader_t*r) { gfxgradient_t*start = 0, *pos = 0; @@ -208,6 +230,11 @@ static void dumpMatrix(writer_t*w, gfxmatrix_t*matrix) writer_writeDouble(w, matrix->tx); writer_writeDouble(w, matrix->ty); } +static void dumpXY(writer_t*w, gfxmatrix_t*matrix) +{ + writer_writeDouble(w, matrix->tx); + writer_writeDouble(w, matrix->ty); +} static void dumpGradient(writer_t*w, gfxgradient_t*gradient) { while(gradient) { @@ -241,6 +268,8 @@ static void dumpFont(writer_t*w, gfxfont_t*font) writer_writeString(w, font->id); writer_writeU32(w, font->num_glyphs); writer_writeU32(w, font->max_unicode); + writer_writeDouble(w, font->ascent); + writer_writeDouble(w, font->descent); int t; for(t=0;tnum_glyphs;t++) { dumpLine(w, font->glyphs[t].line); @@ -255,6 +284,12 @@ static void dumpFont(writer_t*w, gfxfont_t*font) for(t=0;tmax_unicode;t++) { writer_writeU32(w, font->unicode2glyph[t]); } + writer_writeU32(w, font->kerning_size); + for(t=0;tkerning_size;t++) { + writer_writeU32(w, font->kerning[t].c1); + writer_writeU32(w, font->kerning[t].c2); + writer_writeU32(w, font->kerning[t].advance); + } } static gfxfont_t*readFont(reader_t*r) { @@ -262,6 +297,8 @@ static gfxfont_t*readFont(reader_t*r) font->id = reader_readString(r); font->num_glyphs = reader_readU32(r); font->max_unicode = reader_readU32(r); + font->ascent = reader_readDouble(r); + font->descent = reader_readDouble(r); font->glyphs = (gfxglyph_t*)rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs); font->unicode2glyph = (int*)rfx_calloc(sizeof(font->unicode2glyph[0])*font->max_unicode); int t; @@ -278,6 +315,15 @@ static gfxfont_t*readFont(reader_t*r) for(t=0;tmax_unicode;t++) { font->unicode2glyph[t] = reader_readU32(r); } + font->kerning_size = reader_readU32(r); + if(font->kerning_size) { + font->kerning = malloc(sizeof(gfxkerning_t)*font->kerning_size); + for(t=0;tkerning_size;t++) { + font->kerning[t].c1 = reader_readU32(r); + font->kerning[t].c2 = reader_readU32(r); + font->kerning[t].advance = reader_readU32(r); + } + } return font; } @@ -364,14 +410,26 @@ static void record_drawchar(struct _gfxdevice*dev, gfxfont_t*font, int glyphnr, } msg(" record: %08x DRAWCHAR %d\n", glyphnr, dev); - writer_writeU8(&i->w, OP_DRAWCHAR); - if(font) - writer_writeString(&i->w, font->id); - else - writer_writeString(&i->w, "*NULL*"); + const char*font_id = font->id?font->id:"*NULL*"; + + gfxmatrix_t*l = &i->state.last_matrix[OP_DRAWCHAR]; + + char same_font = i->state.last_string[OP_DRAWCHAR] && !strcmp(i->state.last_string[OP_DRAWCHAR], font_id); + char same_matrix = (l->m00 == matrix->m00) && (l->m01 == matrix->m01) && (l->m10 == matrix->m10) && (l->m11 == matrix->m11); + char same_color = !memcmp(color, &i->state.last_color[OP_DRAWCHAR], sizeof(gfxcolor_t)); + U8 flags = 0; + if(same_font && same_matrix && same_color) + flags |= FLAG_SAME_AS_LAST; + + writer_writeU8(&i->w, OP_DRAWCHAR|flags); writer_writeU32(&i->w, glyphnr); - dumpColor(&i->w, color); - dumpMatrix(&i->w, matrix); + if(!(flags&FLAG_SAME_AS_LAST)) { + writer_writeString(&i->w, font_id); + dumpColor(&i->w, color); + dumpMatrix(&i->w, matrix); + } else { + dumpXY(&i->w, matrix); + } } static void record_startpage(struct _gfxdevice*dev, int width, int height) @@ -399,20 +457,58 @@ static void record_drawlink(struct _gfxdevice*dev, gfxline_t*line, const char*ac writer_writeString(&i->w, action); } -static void replay(struct _gfxdevice*dev, gfxdevice_t*out, void*data, int length) +static char* read_string(reader_t*r, state_t*state, U8 id, U8 flags) +{ + assert(id>=0 && id<16); + if(flags&FLAG_SAME_AS_LAST) { + assert(state->last_string[id]); + return state->last_string[id]; + } + char*s = reader_readString(r); + state->last_string[id] = strdup(s); + return s; +} +static gfxcolor_t read_color(reader_t*r, state_t*s, U8 id, U8 flags) +{ + assert(id>=0 && id<16); + if(flags&FLAG_SAME_AS_LAST) + return s->last_color[id]; + gfxcolor_t c = readColor(r); + s->last_color[id] = c; + return c; +} +static gfxmatrix_t read_matrix(reader_t*r, state_t*s, U8 id, U8 flags) +{ + assert(id>=0 && id<16); + if(flags&FLAG_SAME_AS_LAST) { + gfxmatrix_t m = s->last_matrix[id]; + readXY(r, &m); + return m; + } + gfxmatrix_t m = readMatrix(r); + s->last_matrix[id] = m; + return m; +} + +static void replay(struct _gfxdevice*dev, gfxdevice_t*out, reader_t*r) { internal_t*i = 0; if(dev) { i = (internal_t*)dev->internal; } - reader_t r2; - reader_t*r = &r2; - reader_init_memreader(r, data, length); + state_t state; + memset(&state, 0, sizeof(state)); + gfxfontlist_t* fontlist = gfxfontlist_create(); - while(r->pos < length) { - unsigned char op = reader_readU8(r); + while(1) { + unsigned char op; + if(r->read(r, &op, 1)!=1) + break; + unsigned char flags = op&0xf0; + op&=0x0f; + switch(op) { case OP_END: goto finish; @@ -436,6 +532,7 @@ static void replay(struct _gfxdevice*dev, gfxdevice_t*out, void*data, int length } case OP_ENDPAGE: { msg(" replay: ENDPAGE"); + out->endpage(out); break; } case OP_FINISH: { @@ -532,15 +629,17 @@ static void replay(struct _gfxdevice*dev, gfxdevice_t*out, void*data, int length break; } case OP_DRAWCHAR: { - char* id = reader_readString(r); + U32 glyph = reader_readU32(r); + gfxmatrix_t m = {1,0,0, 0,1,0}; + char* id = read_string(r, &state, op, flags); + gfxcolor_t color = read_color(r, &state, op, flags); + gfxmatrix_t matrix = read_matrix(r, &state, op, flags); + gfxfont_t*font = id?gfxfontlist_findfont(fontlist, id):0; if(i && !font) { font = gfxfontlist_findfont(i->fontlist, id); } - U32 glyph = reader_readU32(r); msg(" replay: DRAWCHAR font=%s glyph=%d", id, glyph); - gfxcolor_t color = readColor(r); - gfxmatrix_t matrix = readMatrix(r); out->drawchar(out, font, glyph, &color, &matrix); free(id); break; @@ -558,24 +657,38 @@ finish: void gfxresult_record_replay(gfxresult_t*result, gfxdevice_t*device) { internal_result_t*i = (internal_result_t*)result->internal; - replay(0, device, i->data, i->length); + + reader_t r; + if(i->use_tempfile) { + reader_init_filereader2(&r, i->filename); + } else { + reader_init_memreader(&r, i->data, i->length); + } + + replay(0, device, &r); } static void record_result_write(gfxresult_t*r, int filedesc) { internal_result_t*i = (internal_result_t*)r->internal; - write(filedesc, i->data, i->length); + if(i->data) { + write(filedesc, i->data, i->length); + } } static int record_result_save(gfxresult_t*r, const char*filename) { internal_result_t*i = (internal_result_t*)r->internal; - FILE*fi = fopen(filename, "wb"); - if(!fi) { - fprintf(stderr, "Couldn't open file %s for writing\n", filename); - return -1; + if(i->use_tempfile) { + move_file(i->filename, filename); + } else { + FILE*fi = fopen(filename, "wb"); + if(!fi) { + fprintf(stderr, "Couldn't open file %s for writing\n", filename); + return -1; + } + fwrite(i->data, i->length, 1, fi); + fclose(fi); } - fwrite(i->data, i->length, 1, fi); - fclose(fi); return 0; } static void*record_result_get(gfxresult_t*r, const char*name) @@ -594,6 +707,10 @@ static void record_result_destroy(gfxresult_t*r) if(i->data) { free(i->data);i->data = 0; } + if(i->filename) { + unlink(i->filename); + free(i->filename); + } free(r->internal);r->internal = 0; free(r); } @@ -627,11 +744,18 @@ void gfxdevice_record_flush(gfxdevice_t*dev, gfxdevice_t*out) { internal_t*i = (internal_t*)dev->internal; if(out) { - int len=0; - void*data = writer_growmemwrite_memptr(&i->w, &len); - replay(dev, out, data, len); + if(!i->use_tempfile) { + int len=0; + void*data = writer_growmemwrite_memptr(&i->w, &len); + reader_t r; + reader_init_memreader(&r, data, len); + replay(dev, out, &r); + writer_growmemwrite_reset(&i->w); + } else { + msg(" Flushing not supported for file based record device"); + exit(1); + } } - writer_growmemwrite_reset(&i->w); } static gfxresult_t* record_finish(struct _gfxdevice*dev) @@ -648,8 +772,14 @@ static gfxresult_t* record_finish(struct _gfxdevice*dev) gfxfontlist_free(i->fontlist, 0); internal_result_t*ir = (internal_result_t*)rfx_calloc(sizeof(gfxresult_t)); - ir->data = writer_growmemwrite_getmem(&i->w); - ir->length = i->w.pos; + + ir->use_tempfile = i->use_tempfile; + if(i->use_tempfile) { + ir->filename = i->filename; + } else { + ir->data = writer_growmemwrite_getmem(&i->w); + ir->length = i->w.pos; + } i->w.finish(&i->w); gfxresult_t*result= (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t)); @@ -662,7 +792,8 @@ static gfxresult_t* record_finish(struct _gfxdevice*dev) return result; } -void gfxdevice_record_init(gfxdevice_t*dev) + +void gfxdevice_record_init(gfxdevice_t*dev, char use_tempfile) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); memset(dev, 0, sizeof(gfxdevice_t)); @@ -670,8 +801,15 @@ void gfxdevice_record_init(gfxdevice_t*dev) dev->name = "record"; dev->internal = i; - - writer_init_growingmemwriter(&i->w, 1048576); + + i->use_tempfile = use_tempfile; + if(!use_tempfile) { + writer_init_growingmemwriter(&i->w, 1048576); + } else { + char buffer[128]; + i->filename = strdup(mktempname(buffer, "gfx")); + writer_init_filewriter2(&i->w, i->filename); + } i->fontlist = gfxfontlist_create(); i->cliplevel = 0;