started implementing the remove_font_transforms filter
[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     double size; // not hashed
35 } mymatrix_t;
36
37 static void* mymatrix_clone(const void*_m) {
38     if(_m==0) 
39         return 0;
40     const mymatrix_t*m1=_m;
41     mymatrix_t*m2 = malloc(sizeof(mymatrix_t));
42     *m2 = *m1;
43     m2->id = strdup(m1->id);
44     return m2;
45 }
46 static unsigned int mymatrix_hash(const void*_m) {
47     if(!_m)
48         return 0;
49     const mymatrix_t*m = (mymatrix_t*)_m;
50     unsigned int h=0;
51     h = crc32_add_bytes(h, (char*)&m->m00, sizeof(m->m00));
52     h = crc32_add_bytes(h, (char*)&m->m01, sizeof(m->m01));
53     h = crc32_add_bytes(h, (char*)&m->m10, sizeof(m->m10));
54     h = crc32_add_bytes(h, (char*)&m->m11, sizeof(m->m11));
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 }
79 type_t mymatrix_type = {
80     dup: mymatrix_clone,
81     hash: mymatrix_hash,
82     free: mymatrix_destroy,
83     equals: mymatrix_equals
84 };
85
86 typedef struct _internal {
87     dict_t*matrices;
88     char first;
89 } internal_t;
90
91
92 #ifdef __GNUC__
93 void __attribute__((noinline)) 
94      matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out)
95 #else
96 void matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out)
97 #endif
98 {
99     double l1 = sqrt(in->m00 * in->m00 + in->m01 * in->m01);
100     double l2 = sqrt(in->m10 * in->m10 + in->m11 * in->m11);
101     double l = l1+l2;
102     if(l < 1e-20) {
103         memset(out, 0, sizeof(*out));
104         return;
105     }
106     out->m00 = in->m00 / l;
107     out->m01 = in->m01 / l;
108     out->m10 = in->m10 / l;
109     out->m11 = in->m11 / l;
110     out->id = (char*)id;
111     out->size = l;
112 }
113
114 typedef struct _matrixdata {
115     gfxfontlist_t*fonts;
116 } matrixdata_t;
117
118 typedef struct _transformedfont {
119     gfxfont_t*orig;
120     gfxfont_t*font;
121     mymatrix_t matrix;
122     int*used;
123 } transformedfont_t;
124
125 static transformedfont_t* transformedfont_new(gfxfont_t*orig, mymatrix_t*m)
126 {
127     transformedfont_t*f = rfx_calloc(sizeof(transformedfont_t));
128     f->orig = orig;
129     f->matrix = *m;
130     f->used = malloc(sizeof(f->used[0])*orig->num_glyphs);
131     return f;
132 }
133
134 static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
135 {
136     internal_t*i = (internal_t*)f->internal;
137     mymatrix_t m;
138     matrix_convert(matrix, font->id, &m);
139     transformedfont_t*fd = dict_lookup(i->matrices, &m);
140     if(!fd) {
141         fd = transformedfont_new(font, &m);
142         dict_put(i->matrices, &m, fd);
143     }
144     fd->used[glyphnr]=1;
145     out->drawchar(out, font, glyphnr, color, matrix);
146 }
147
148 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
149 {
150     internal_t*i = (internal_t*)f->internal;
151     DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
152         gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
153         char id[80];
154         static int fontcount=0;
155         sprintf(id, "font%d", fontcount++);
156         font->id = strdup(id);
157         int t;
158         int count=0;
159         for(t=0;t<fd->orig->num_glyphs;t++) {
160             if(fd->used[t]) count++;
161         }
162         font->num_glyphs = count;
163         font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
164         count = 0;
165         for(t=0;t<fd->orig->num_glyphs;t++) {
166             if(fd->used[t]) {
167                 font->glyphs[count] = fd->orig->glyphs[t];
168                 fd->used[t] = count;
169                 count++;
170             }
171         }
172         gfxfont_fix_unicode(font);
173     }
174     return out->finish(out);
175 }
176
177 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
178 {
179     internal_t*i = (internal_t*)f->internal;
180
181     if(i->first) {
182         i->first = 0;
183         DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
184             out->addfont(out, fd->font);
185         }
186     }
187
188     mymatrix_t m;
189     matrix_convert(matrix, font->id, &m);
190     transformedfont_t*d = dict_lookup(i->matrices, &m);
191     out->drawchar(out, d->font, d->used[glyphnr], color, matrix);
192 }
193
194 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
195 {
196     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
197
198     memset(f, 0, sizeof(gfxtwopassfilter_t));
199     f->type = gfxfilter_twopass;
200
201     f->pass1.name = "remove font transforms pass 1";
202     f->pass1.drawchar = pass1_drawchar;
203     f->pass1.finish = pass1_finish;
204     f->pass1.internal = i;
205
206     f->pass2.name = "remove font transforms pass 2";
207     f->pass2.drawchar = pass2_drawchar;
208     f->pass2.internal = i;
209
210     i->matrices = dict_new2(&mymatrix_type);
211     i->first = 1;
212 }
213