3 static inline double sqr(double x) {return x*x;}
5 static void draw_line(float*row, float x1, float x2, float y1, float y2, int min, int max)
7 if(x2<x1) {int x=x1;x1=x2;x2=x;}
9 fprintf(stderr, "error: glyph x stroke out of bounds\n");
15 double d = sqrt(sqr(y2-y1)+sqr(x2-x1));
16 if(floor(x1)==floor(x2)) {
17 row[(int)floor(x1)] += d;
23 row[xx1] += i*(xx1-x1);
24 row[xx2] += i*(x2-xx2);
25 for(x=xx1;x<xx2;x++) {
31 static void draw_line_xy(float*row,float*column, float x1, float y1, float x2, float y2,SRECT* area)
33 draw_line(row, x1, x2, y1, y2, area->xmin, area->xmax);
34 draw_line(column, y1, y2, x1, x2, area->ymin, area->ymax);
37 static void find_best(float*_row, int width, int*_x1, int*_x2, int min_size, int from, int to, int num, char debug)
40 float max1=-1e20,max2=-1e20;
42 float*row = malloc(sizeof(float)*(width+1));
44 float* filter = malloc(sizeof(float)*(filter_size*2+1));
45 double var = filter_size/3;
46 for(t=-filter_size;t<=filter_size;t++) {
49 filter[filter_size+t] = exp(-r);
51 //filter[0]=1;filter_size=0;
53 for(t=0;t<=width;t++) {
56 for(s=-filter_size;s<=filter_size;s++) {
58 if(t+s>width) continue;
59 sum += _row[t+s]*filter[s+filter_size];
65 for(t=from;t<=to;t++) {
76 /* this code is slightly wrong, in that it assumes that the glyph distortion problem
77 gets worse when the font sizes get smaller. it doesn't. in fact, the smaller
78 the font size, the more of the scaling bugs disappear (http://www.quiss.org/files/scaletest.swf)
79 A better way would probably to use the font size you need for the two alignzones
80 to come to lie in different pixels, which what I think is what makes the problems
84 double scale = min_size/1024.0;
85 for(t=from;t<=to;t++) {
90 double r1 = (t<x1?t:x1)*scale;
91 double r2 = (t<x1?x1:t)*scale;
95 double ext1 = r1-from*scale;
96 double ext2 = to*scale-r2;
97 double add1 = ext1*s - ext1;
98 double add2 = ext2*s - ext2;
100 /* don't allow the char to grow more than one pixel */
101 if(add1>=1 || add2>=1) {
106 for(t=from;t<=to;t++) {
113 if(x1>=0 && x2>=0 && x1>x2) {int x=x1;x1=x2;x2=x;}
122 static void negate_y(SRECT* b)
125 int by1=b->ymin,by2=b->ymax;
130 static void draw_char(SWFFONT * f, int nr, float*row, float*column, SRECT b)
132 SWFGLYPH*g = &f->glyph[nr];
134 SHAPE2*s = swf_ShapeToShape2(g->shape);
135 SHAPELINE*l = s->lines;
138 if(l->type == lineTo) {
139 draw_line_xy(row,column,x,-y,l->x,-l->y,&b);
140 } else if(l->type == splineTo) {
141 double x1=x,x2=l->sx,x3=l->x;
142 double y1=y,y2=l->sy,y3=l->y;
143 double c = fabs(x3-2*x2+x1) + fabs(y3-2*y2+y1);
144 int parts = ((int)(sqrt(c)/6))*2+1;
147 for(t=1;t<=parts;t++) {
148 float nx = ((t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts));
149 float ny = ((t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts));
150 draw_line_xy(row,column,xx,-yy,nx,-ny,&b);
163 static ALIGNZONE detect_for_char(SWFFONT * f, int nr, float*row, float*column, SRECT font_bbox, SRECT char_bbox)
165 ALIGNZONE a = {0xffff,0xffff,0xffff,0xffff};
166 int width = font_bbox.xmax - font_bbox.xmin;
167 int height = font_bbox.ymax - font_bbox.ymin;
168 if(!width || !height)
171 /* find two best x values */
172 int x1=-1,y1=-1,x2=-1,y2=-1;
175 find_best(row, width, &x1, &x2, f->use->smallest_size,
176 char_bbox.xmin - font_bbox.xmin,
177 char_bbox.xmax - font_bbox.xmin, nr_x,
179 if(nr_x>0 && x1>=0) a.x = floatToF16((x1+font_bbox.xmin) / 20480.0);
180 if(nr_x>1 && x2>=0) a.dx = floatToF16((x2-x1) / 20480.0);
182 find_best(column, height, &y1, &y2, f->use->smallest_size,
183 char_bbox.ymin - font_bbox.ymin,
184 char_bbox.ymax - font_bbox.ymin, 2,
186 if(y1>=0) a.y = floatToF16((y1+font_bbox.ymin) / 20480.0);
187 if(y2>=0) a.dy = floatToF16((y2-y1) / 20480.0);
192 void swf_FontCreateAlignZones(SWFFONT * f)
198 fprintf(stderr, "Error: font needs a layout for alignzones to be detected.");
202 f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
203 f->alignzone_flags = FONTALIGN_MEDIUM;
205 if(!f->layout || !f->use) {
207 for(t=0;t<f->numchars;t++) {
208 // just align the baseline
209 f->alignzones[t].x = 0xffff;
210 f->alignzones[t].y = 0;
211 f->alignzones[t].dx = 0xffff;
212 f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
215 SRECT bounds = {0,0,0,0};
217 for(t=0;t<f->numchars;t++) {
218 SRECT b = f->layout->bounds[t];
220 swf_ExpandRect2(&bounds, &b);
223 int width = bounds.xmax - bounds.xmin;
224 int height = bounds.ymax - bounds.ymin;
225 float*row = rfx_calloc(sizeof(float)*(width+1));
226 float*column_global = rfx_calloc(sizeof(float)*(height+1));
227 float*column = rfx_calloc(sizeof(float)*(height+1));
229 for(t=0;t<f->numchars;t++) {
230 draw_char(f, t, row, column_global, bounds);
232 for(t=0;t<=height;t++) {column_global[t]/=f->numchars/2;}
234 for(t=0;t<f->numchars;t++) {
235 //memcpy(column, column_global, sizeof(float)*(height+1));
237 memset(column, 0, sizeof(float)*(height+1));
240 for(s=0;s<f->use->num_neighbors;s++) {
241 int char1 = f->use->neighbors[s].char1;
242 int char2 = f->use->neighbors[s].char2;
243 if(char1 == t || char2 == t) {
244 int other = t==char1?char2:char1;
245 draw_char(f, other, row, column, bounds);
250 for(s=0;s<=height;s++) {
251 column[t] /= drawn*2;
254 memset(row, 0, sizeof(float)*(width+1));
255 draw_char(f, t, row, column, bounds);
257 SRECT b = f->layout->bounds[t];
259 f->alignzones[t] = detect_for_char(f, t, row, column, bounds, b);
267 void swf_FontPostprocess(SWF*swf)
269 TAG*tag = swf->firstTag;
271 TAG*next = tag->next;
272 if(tag->id == ST_DEFINEFONT3) {
273 U16 id = swf_GetDefineID(tag);
275 swf_FontExtract(swf, id, &font);
276 if(!font->alignzones) {
277 swf_FontCreateAlignZones(font);
278 tag = swf_InsertTag(tag, ST_DEFINEFONTALIGNZONES);
279 swf_FontSetAlignZones(tag, font);
287 void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
289 swf_SetU16(t, f->id);
290 swf_SetU8(t, f->alignzone_flags);
292 for(i=0;i<f->numchars;i++) {
293 ALIGNZONE*a = &f->alignzones[i];
295 if((a->x & a->dx)!=0xffff)
297 if((a->y & a->dy)!=0xffff)
300 if(a->dx != 0xffff || a->dy != 0xffff)
303 if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
304 if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
306 if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
307 if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);