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);
214 SRECT bounds = {0,0,0,0};
216 for(t=0;t<f->numchars;t++) {
217 SRECT b = f->layout->bounds[t];
219 swf_ExpandRect2(&bounds, &b);
222 int width = bounds.xmax - bounds.xmin;
223 int height = bounds.ymax - bounds.ymin;
224 float*row = rfx_calloc(sizeof(float)*(width+1));
225 float*column_global = rfx_calloc(sizeof(float)*(height+1));
226 float*column = rfx_calloc(sizeof(float)*(height+1));
228 for(t=0;t<f->numchars;t++) {
229 draw_char(f, t, row, column_global, bounds);
231 for(t=0;t<=height;t++) {column_global[t]/=f->numchars/2;}
233 for(t=0;t<f->numchars;t++) {
234 memcpy(column, column_global, sizeof(float)*(height+1));
235 memset(row, 0, sizeof(float)*(width+1));
236 draw_char(f, t, row, column, bounds);
238 SRECT b = f->layout->bounds[t];
240 f->alignzones[t] = detect_for_char(f, t, row, column, bounds, b);
248 void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
250 swf_SetU16(t, f->id);
251 swf_SetU8(t, f->alignzone_flags);
253 for(i=0;i<f->numchars;i++) {
254 ALIGNZONE*a = &f->alignzones[i];
256 if((a->x & a->dx)!=0xffff)
258 if((a->y & a->dy)!=0xffff)
261 if(a->dx != 0xffff || a->dy != 0xffff)
264 if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
265 if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
267 if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
268 if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);