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);
161 static ALIGNZONE detect_for_char(SWFFONT * f, int nr, float*row, float*column, SRECT font_bbox, SRECT char_bbox)
163 ALIGNZONE a = {0xffff,0xffff,0xffff,0xffff};
164 int width = font_bbox.xmax - font_bbox.xmin;
165 int height = font_bbox.ymax - font_bbox.ymin;
166 if(!width || !height)
169 /* find two best x values */
170 int x1=-1,y1=-1,x2=-1,y2=-1;
173 find_best(row, width, &x1, &x2, f->use->smallest_size,
174 char_bbox.xmin - font_bbox.xmin,
175 char_bbox.xmax - font_bbox.xmin, nr_x,
177 if(nr_x>0 && x1>=0) a.x = floatToF16((x1+font_bbox.xmin) / 20480.0);
178 if(nr_x>1 && x2>=0) a.dx = floatToF16((x2-x1) / 20480.0);
180 find_best(column, height, &y1, &y2, f->use->smallest_size,
181 char_bbox.ymin - font_bbox.ymin,
182 char_bbox.ymax - font_bbox.ymin, 2,
184 if(y1>=0) a.y = floatToF16((y1+font_bbox.ymin) / 20480.0);
185 if(y2>=0) a.dy = floatToF16((y2-y1) / 20480.0);
190 void swf_FontCreateAlignZones(SWFFONT * f)
196 fprintf(stderr, "Error: font needs a layout for alignzones to be detected.");
200 f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
201 f->alignzone_flags = FONTALIGN_MEDIUM;
203 if(!f->layout || !f->use) {
205 for(t=0;t<f->numchars;t++) {
206 // just align the baseline
207 f->alignzones[t].x = 0xffff;
208 f->alignzones[t].y = 0;
209 f->alignzones[t].dx = 0xffff;
210 f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
213 SRECT bounds = {0,0,0,0};
215 for(t=0;t<f->numchars;t++) {
216 SRECT b = f->layout->bounds[t];
218 swf_ExpandRect2(&bounds, &b);
221 int width = bounds.xmax - bounds.xmin;
222 int height = bounds.ymax - bounds.ymin;
223 float*row = rfx_calloc(sizeof(float)*(width+1));
224 float*column_global = rfx_calloc(sizeof(float)*(height+1));
225 float*column = rfx_calloc(sizeof(float)*(height+1));
227 for(t=0;t<f->numchars;t++) {
228 draw_char(f, t, row, column_global, bounds);
230 for(t=0;t<=height;t++) {column_global[t]/=f->numchars/2;}
232 for(t=0;t<f->numchars;t++) {
233 //memcpy(column, column_global, sizeof(float)*(height+1));
235 memset(column, 0, sizeof(float)*(height+1));
238 printf("[font %d] pairing %c with ", f->id, f->glyph2ascii[t]);
239 for(s=0;s<f->use->num_neighbors;s++) {
240 if(f->use->neighbors[s].char2 == t) {
241 printf("%c ", f->glyph2ascii[f->use->neighbors[s].char1]);
242 draw_char(f, f->use->neighbors[s].char1, row, column, bounds);
248 for(s=0;s<=height;s++) {
249 column[t] /= drawn*2;
252 memset(row, 0, sizeof(float)*(width+1));
253 draw_char(f, t, row, column, bounds);
255 SRECT b = f->layout->bounds[t];
257 f->alignzones[t] = detect_for_char(f, t, row, column, bounds, b);
265 void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
267 swf_SetU16(t, f->id);
268 swf_SetU8(t, f->alignzone_flags);
270 for(i=0;i<f->numchars;i++) {
271 ALIGNZONE*a = &f->alignzones[i];
273 if((a->x & a->dx)!=0xffff)
275 if((a->y & a->dy)!=0xffff)
278 if(a->dx != 0xffff || a->dy != 0xffff)
281 if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
282 if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
284 if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
285 if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);