1 /* remove_font_transform.c
3 Part of the swftools package.
5 Copyright (c) 2010 Matthias Kramm <kramm@quiss.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "../gfxfilter.h"
25 #include "../gfxtools.h"
26 #include "../gfxfont.h"
31 typedef struct _mymatrix {
32 float m00,m01,m10,m11;
36 static void* mymatrix_clone(const void*_m) {
39 const mymatrix_t*m1=_m;
40 mymatrix_t*m2 = malloc(sizeof(mymatrix_t));
42 m2->id = strdup(m1->id);
45 static unsigned int mymatrix_hash(const void*_m) {
48 const mymatrix_t*m = (mymatrix_t*)_m;
50 h = crc32_add_bytes(h, (char*)&m->m00, sizeof(m->m00));
51 h = crc32_add_bytes(h, (char*)&m->m01, sizeof(m->m01));
52 h = crc32_add_bytes(h, (char*)&m->m10, sizeof(m->m10));
53 h = crc32_add_bytes(h, (char*)&m->m11, sizeof(m->m11));
54 h = crc32_add_string(h, m->id);
57 static void mymatrix_destroy(void*_m) {
58 mymatrix_t*m = (mymatrix_t*)_m;
62 static char mymatrix_equals(const void*_m1, const void*_m2) {
63 const mymatrix_t*m1=_m1;
64 const mymatrix_t*m2=_m2;
68 /* we do a binary comparison of the float32
69 bits here instead of a numerical comparison
70 to prevent the compiler from e.g. removing the
71 (float) cast during optimization, which would break
72 the equivalence between equals() and hash() (as
73 the hash is derived from the float32 values) */
74 return *(U32*)&m1->m00 == *(U32*)&m2->m00 &&
75 *(U32*)&m1->m01 == *(U32*)&m2->m01 &&
76 *(U32*)&m1->m10 == *(U32*)&m2->m10 &&
77 *(U32*)&m1->m11 == *(U32*)&m2->m11 &&
78 !strcmp(m1->id, m2->id);
80 type_t mymatrix_type = {
83 free: mymatrix_destroy,
84 equals: mymatrix_equals
87 typedef struct _internal {
94 void __attribute__((noinline))
95 matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix)
97 void matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix)
100 double l1 = sqrt(in->m00 * in->m00 + in->m01 * in->m01);
101 double l2 = sqrt(in->m10 * in->m10 + in->m11 * in->m11);
102 double l = (l1+l2)/2.0;
104 memset(out, 0, sizeof(*out));
107 out->m00 = in->m00 / l;
108 out->m10 = in->m10 / l;
109 out->m01 = -in->m01 / l;
110 out->m11 = -in->m11 / l;
114 scalematrix->m00 = l;
115 scalematrix->m01 = 0;
116 scalematrix->m10 = 0;
117 scalematrix->m11 = -l;
118 scalematrix->tx = in->tx;
119 scalematrix->ty = in->ty;
123 typedef struct _matrixdata {
127 typedef struct _transformedfont {
135 static transformedfont_t* transformedfont_new(gfxfont_t*orig, mymatrix_t*m)
137 transformedfont_t*f = rfx_calloc(sizeof(transformedfont_t));
140 f->used = malloc(sizeof(f->used[0])*orig->num_glyphs);
142 for(t=0;t<orig->num_glyphs;t++) {
143 if(orig->glyphs[t].unicode==32)
144 f->used[t]=1; //always preserve the space char in fonts
149 static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
151 internal_t*i = (internal_t*)f->internal;
153 matrix_convert(matrix, font->id, &m, 0);
154 transformedfont_t*fd = dict_lookup(i->matrices, &m);
156 fd = transformedfont_new(font, &m);
157 dict_put(i->matrices, &m, fd);
160 out->drawchar(out, font, glyphnr, color, matrix);
163 static void glyph_transform(gfxglyph_t*g, mymatrix_t*mm)
172 g->line = gfxline_clone(g->line);
173 gfxline_transform(g->line, &m);
178 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
180 internal_t*i = (internal_t*)f->internal;
181 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
182 gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
184 static int fontcount=0;
185 sprintf(id, "font%d", fontcount++);
186 font->id = strdup(id);
189 for(t=0;t<fd->orig->num_glyphs;t++) {
193 font->num_glyphs = count;
194 font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
196 for(t=0;t<fd->orig->num_glyphs;t++) {
198 font->glyphs[count] = fd->orig->glyphs[t];
199 glyph_transform(&font->glyphs[count], &fd->matrix);
205 /* adjust the origin so that every character is to the
206 right of the origin */
207 gfxbbox_t total = {0,0,0,0};
208 double average_xmax = 0;
209 for(t=0;t<count;t++) {
210 gfxline_t*line = font->glyphs[t].line;
211 gfxbbox_t b = gfxline_getbbox(line);
212 total = gfxbbox_expand_to_bbox(total, b);
215 average_xmax /= count;
217 fd->dx = -total.xmin;
219 font->ascent = total.ymax;
220 font->descent = -total.ymin;
222 for(t=0;t<count;t++) {
223 gfxline_t*line = font->glyphs[t].line;
230 gfxfont_fix_unicode(font);
232 return out->finish(out);
235 static void pass2_addfont(gfxfilter_t*f, gfxfont_t*font, gfxdevice_t*out)
237 /* we throw away original fonts, and do the addfont() for the transformed
238 fonts in the first drawchar() */
241 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
243 internal_t*i = (internal_t*)f->internal;
247 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
248 out->addfont(out, fd->font);
253 gfxmatrix_t scalematrix;
254 matrix_convert(matrix, font->id, &m, &scalematrix);
255 transformedfont_t*d = dict_lookup(i->matrices, &m);
256 scalematrix.tx -= d->dx*scalematrix.m00;
257 out->drawchar(out, d->font, d->used[glyphnr], color, &scalematrix);
260 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
262 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
264 memset(f, 0, sizeof(gfxtwopassfilter_t));
265 f->type = gfxfilter_twopass;
267 f->pass1.name = "remove font transforms pass 1";
268 f->pass1.drawchar = pass1_drawchar;
269 f->pass1.finish = pass1_finish;
270 f->pass1.internal = i;
272 f->pass2.name = "remove font transforms pass 2";
273 f->pass2.addfont = pass2_addfont;
274 f->pass2.drawchar = pass2_drawchar;
275 f->pass2.internal = i;
277 i->matrices = dict_new2(&mymatrix_type);