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 = rfx_calloc(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;
154 msg("<error> Font has no ID");
155 matrix_convert(matrix, font->id?font->id:"unknown", &m, 0);
156 transformedfont_t*fd = dict_lookup(i->matrices, &m);
158 fd = transformedfont_new(font, &m);
159 dict_put(i->matrices, &m, fd);
162 out->drawchar(out, font, glyphnr, color, matrix);
165 static void glyph_transform(gfxglyph_t*g, mymatrix_t*mm)
174 g->line = gfxline_clone(g->line);
175 gfxline_transform(g->line, &m);
180 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
182 internal_t*i = (internal_t*)f->internal;
183 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
184 gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
186 static int fontcount=0;
187 sprintf(id, "font%d", fontcount++);
188 font->id = strdup(id);
191 for(t=0;t<fd->orig->num_glyphs;t++) {
195 font->num_glyphs = count;
196 font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
198 for(t=0;t<fd->orig->num_glyphs;t++) {
200 font->glyphs[count] = fd->orig->glyphs[t];
201 glyph_transform(&font->glyphs[count], &fd->matrix);
207 /* adjust the origin so that every character is to the
208 right of the origin */
209 gfxbbox_t total = {0,0,0,0};
210 double average_xmax = 0;
211 for(t=0;t<count;t++) {
212 gfxline_t*line = font->glyphs[t].line;
213 gfxbbox_t b = gfxline_getbbox(line);
214 total = gfxbbox_expand_to_bbox(total, b);
217 average_xmax /= count;
219 fd->dx = -total.xmin;
221 font->ascent = total.ymax;
222 font->descent = -total.ymin;
224 for(t=0;t<count;t++) {
225 gfxline_t*line = font->glyphs[t].line;
232 gfxfont_fix_unicode(font);
234 return out->finish(out);
237 static void pass2_addfont(gfxfilter_t*f, gfxfont_t*font, gfxdevice_t*out)
239 /* we throw away original fonts, and do the addfont() for the transformed
240 fonts in the first drawchar() */
243 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
245 internal_t*i = (internal_t*)f->internal;
249 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
250 out->addfont(out, fd->font);
255 gfxmatrix_t scalematrix;
256 matrix_convert(matrix, font->id?font->id:"unknown", &m, &scalematrix);
257 transformedfont_t*d = dict_lookup(i->matrices, &m);
258 scalematrix.tx -= d->dx*scalematrix.m00;
259 out->drawchar(out, d->font, d->used[glyphnr], color, &scalematrix);
262 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
264 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
266 memset(f, 0, sizeof(gfxtwopassfilter_t));
267 f->type = gfxfilter_twopass;
269 f->pass1.name = "remove font transforms pass 1";
270 f->pass1.drawchar = pass1_drawchar;
271 f->pass1.finish = pass1_finish;
272 f->pass1.internal = i;
274 f->pass2.name = "remove font transforms pass 2";
275 f->pass2.addfont = pass2_addfont;
276 f->pass2.drawchar = pass2_drawchar;
277 f->pass2.internal = i;
279 i->matrices = dict_new2(&mymatrix_type);