a2d7c445b5dfb42b9ae576568e42c2f9263b3ff8
[swftools.git] / lib / filters / remove_font_transforms.c
1 /* remove_font_transform.c
2
3    Part of the swftools package.
4
5    Copyright (c) 2010 Matthias Kramm <kramm@quiss.org> 
6  
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.
11
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.
16
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 */
20
21 #include <stdlib.h>
22 #include <math.h>
23 #include <memory.h>
24 #include "../gfxfilter.h"
25 #include "../gfxtools.h"
26 #include "../gfxfont.h"
27 #include "../types.h"
28 #include "../mem.h"
29 #include "../q.h"
30
31 typedef struct _mymatrix {
32     float m00,m01,m10,m11;
33     char*id;
34 } mymatrix_t;
35
36 static void* mymatrix_clone(const void*_m) {
37     if(_m==0) 
38         return 0;
39     const mymatrix_t*m1=_m;
40     mymatrix_t*m2 = malloc(sizeof(mymatrix_t));
41     *m2 = *m1;
42     m2->id = strdup(m1->id);
43     return m2;
44 }
45 static unsigned int mymatrix_hash(const void*_m) {
46     if(!_m)
47         return 0;
48     const mymatrix_t*m = (mymatrix_t*)_m;
49     unsigned int h=0;
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);
55     return h;
56 }
57 static void mymatrix_destroy(void*_m) {
58     mymatrix_t*m = (mymatrix_t*)_m;
59     free(m->id);m->id=0;
60     free(m);
61 }
62 static char mymatrix_equals(const void*_m1, const void*_m2) {
63     const mymatrix_t*m1=_m1;
64     const mymatrix_t*m2=_m2;
65     if(!m1 || !m2) 
66         return m1==m2;
67     
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);
79 }
80 type_t mymatrix_type = {
81     dup: mymatrix_clone,
82     hash: mymatrix_hash,
83     free: mymatrix_destroy,
84     equals: mymatrix_equals
85 };
86
87 typedef struct _internal {
88     dict_t*matrices;
89     char first;
90 } internal_t;
91
92
93 #ifdef __GNUC__
94 void __attribute__((noinline)) 
95      matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix)
96 #else
97 void matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix)
98 #endif
99 {
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;
103     if(l < 1e-10) {
104         memset(out, 0, sizeof(*out));
105         return;
106     }
107     out->m00 = in->m00 / l;
108     out->m01 = in->m01 / l;
109     out->m10 = in->m10 / l;
110     out->m11 = in->m11 / l;
111     out->id = (char*)id;
112
113     if(scalematrix) {
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;
120     }
121 }
122
123 typedef struct _matrixdata {
124     gfxfontlist_t*fonts;
125 } matrixdata_t;
126
127 typedef struct _transformedfont {
128     gfxfont_t*orig;
129     gfxfont_t*font;
130     mymatrix_t matrix;
131     int*used;
132 } transformedfont_t;
133
134 static transformedfont_t* transformedfont_new(gfxfont_t*orig, mymatrix_t*m)
135 {
136     transformedfont_t*f = rfx_calloc(sizeof(transformedfont_t));
137     f->orig = orig;
138     f->matrix = *m;
139     f->used = malloc(sizeof(f->used[0])*orig->num_glyphs);
140     return f;
141 }
142
143 static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
144 {
145     internal_t*i = (internal_t*)f->internal;
146     mymatrix_t m;
147     matrix_convert(matrix, font->id, &m, 0);
148     transformedfont_t*fd = dict_lookup(i->matrices, &m);
149     if(!fd) {
150         fd = transformedfont_new(font, &m);
151         dict_put(i->matrices, &m, fd);
152     }
153     fd->used[glyphnr]=1;
154     out->drawchar(out, font, glyphnr, color, matrix);
155 }
156
157 static void glyph_transform(gfxglyph_t*g, mymatrix_t*mm)
158 {
159     gfxmatrix_t m;
160     m.m00 = mm->m00;
161     m.m01 = mm->m01;
162     m.m10 = mm->m10;
163     m.m11 = mm->m11;
164     m.tx = 0;
165     m.ty = 0;
166     gfxline_transform(g->line, &m);
167     g->advance *= m.m00;
168     if(g->advance<0) 
169         g->advance = 0;
170 }
171
172 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
173 {
174     internal_t*i = (internal_t*)f->internal;
175     DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
176         gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
177         char id[80];
178         static int fontcount=0;
179         sprintf(id, "font%d", fontcount++);
180         font->id = strdup(id);
181         int t;
182         int count=0;
183         for(t=0;t<fd->orig->num_glyphs;t++) {
184             if(fd->used[t]) 
185                 count++;
186         }
187         font->num_glyphs = count;
188         font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
189         count = 0;
190         for(t=0;t<fd->orig->num_glyphs;t++) {
191             if(fd->used[t]) {
192                 font->glyphs[count] = fd->orig->glyphs[t];
193                 glyph_transform(&font->glyphs[count], &fd->matrix);
194                 fd->used[t] = count;
195                 count++;
196             }
197         }
198         gfxfont_fix_unicode(font);
199     }
200     return out->finish(out);
201 }
202
203 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
204 {
205     internal_t*i = (internal_t*)f->internal;
206
207     if(i->first) {
208         i->first = 0;
209         DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
210             out->addfont(out, fd->font);
211         }
212     }
213
214     mymatrix_t m;
215     gfxmatrix_t scalematrix;
216     matrix_convert(matrix, font->id, &m, &scalematrix);
217     transformedfont_t*d = dict_lookup(i->matrices, &m);
218     out->drawchar(out, d->font, d->used[glyphnr], color, &scalematrix);
219 }
220
221 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
222 {
223     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
224
225     memset(f, 0, sizeof(gfxtwopassfilter_t));
226     f->type = gfxfilter_twopass;
227
228     f->pass1.name = "remove font transforms pass 1";
229     f->pass1.drawchar = pass1_drawchar;
230     f->pass1.finish = pass1_finish;
231     f->pass1.internal = i;
232
233     f->pass2.name = "remove font transforms pass 2";
234     f->pass2.drawchar = pass2_drawchar;
235     f->pass2.internal = i;
236
237     i->matrices = dict_new2(&mymatrix_type);
238     i->first = 1;
239 }
240