void swf_Render_Delete(RENDERBUF*dest) { renderbuf_internal*i = (renderbuf_internal*)dest->internal; int y; bitmap_t*b = i->bitmaps; /* delete canvas */ rfx_free(i->zbuf); rfx_free(i->img); /* delete line buffers */ for(y=0;y<i->height2;y++) { swf_DeleteTag(0, i->lines[y].points); i->lines[y].points = 0; } /* delete bitmaps */ while(b) { bitmap_t*next = b->next; free(b->data);b->data=0; rfx_free(b); b = next; } rfx_free(i->lines); i->lines = 0; rfx_free(dest->internal); dest->internal = 0; }
void swf_ActionFree(ActionTAG*action) { if(!action) { return; } action = action->parent; if(!action) { fprintf(stderr, "Warning: freeing zero action (no parent)"); return; } while(action) { ActionTAG*tmp; if(action->data && action->data != action->tmp) { rfx_free(action->data); action->data = 0; } action->len = 0; tmp = action; action=action->next; rfx_free(tmp); } }
GRADIENT* interpolateGradient(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter) { int i; GRADIENT g; g.ratios = rfx_calloc(16*sizeof(U8)); g.rgba = rfx_calloc(16*sizeof(RGBA)); if (g1->num > g2->num) { copyGradient(&g, g2); growGradient(&g, g1->num); GRADIENT* result = interpolateNodes(g1, &g, fraction, inter); rfx_free(g.rgba); rfx_free(g.ratios); return result; } else if (g1->num < g2->num) { copyGradient(&g, g1); growGradient(&g, g2->num); GRADIENT* result = interpolateNodes(&g, g2, fraction, inter); rfx_free(g.rgba); rfx_free(g.ratios); return result; } else return interpolateNodes(g1, g2, fraction, inter); }
void gfxline_free(gfxline_t*l) { if(l && (l+1) == l->next) { /* flattened */ rfx_free(l); } else { gfxline_t*next; while(l) { next = l->next; l->next = 0; rfx_free(l); l = next; } } }
static void* linedraw_result(gfxdrawer_t*d) { linedraw_internal_t*i = (linedraw_internal_t*)d->internal; void*result = (void*)i->start; rfx_free(i); memset(d, 0, sizeof(gfxdrawer_t)); return result; }
int swf_FreeTags(SWF* swf) { int tag_counter; TAG* t; TAG* tnew; t = swf->firstTag; tag_counter = 0; while(t) { tag_counter++; tnew = t->next; if(t->data) rfx_free(t->data); rfx_free(t); t = tnew; } swf->firstTag = 0; return tag_counter; }
static void swf_ShapeDrawerClear(drawer_t*draw) { SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal; if(sdraw->tagfree) { swf_DeleteTag(0, sdraw->tag); sdraw->tag = 0; } swf_ShapeFree(sdraw->shape); sdraw->shape = 0; rfx_free(draw->internal); draw->internal = 0; }
void gfxline_optimize(gfxline_t*line) { gfxline_t*l = line; /* step 1: convert splines to lines, where possible */ double x=0,y=0; while(l) { if(l->type == gfx_splineTo && splineIsStraight(x,y,l)) { l->type = gfx_lineTo; } x = l->x; y = l->y; l = l->next; } /* step 2: combine adjacent lines and splines, where possible */ l = line; while(l && l->next) { gfxline_t*next = l->next; char combine = 0; double sx=0,sy=0; if(l->type == gfx_lineTo && next->type == gfx_lineTo) { double dx = l->x-x; double dy = l->y-y; double nx = next->x-l->x; double ny = next->y-l->y; if(fabs(dx*ny - dy*nx) < 0.000001 && (dx*nx + dy*ny) >= 0) { combine = 1; } } else if(l->type == gfx_splineTo && next->type == gfx_splineTo) { /* TODO */ } if(combine) { l->next = next->next; next->next = 0; l->x = next->x; l->y = next->y; l->sx = sx; l->sy = sy; rfx_free(next); } else { x = l->x; y = l->y; l = l->next; } } }
static void maketransparent_fillbitmap(gfxfilter_t*f, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform, gfxdevice_t*out) { internal_t*i = (internal_t*)f->internal; gfximage_t img2; img2.width = img->width; img2.height = img->height; img2.data = (gfxcolor_t*)rfx_alloc(img->width*img->height*4); int x,y; for(y=0;y<img->height;y++) { gfxcolor_t*in = &img->data[y*img->width]; gfxcolor_t*out = &img2.data[y*img->width]; for(x=0;x<img->width;x++) { out[x] = transform_color(i, &in[x]); } } out->fillbitmap(out, line, &img2, matrix, cxform); rfx_free(img2.data); }
ActionTAG* swf_ActionCompile(const char* source, int version) { TAG* tag; ActionTAG* a = 0; void*buffer = 0; int len = 0; int ret; tag = swf_InsertTag(NULL, ST_DOACTION); ret = compileSWFActionCode(source, version, &buffer, &len); if(!ret || buffer==0 || len == 0) return 0; swf_SetBlock(tag, (U8*)buffer, len); swf_SetU8(tag, 0); rfx_free(buffer); a = swf_ActionGet(tag); swf_DeleteTag(0, tag); return a; }
void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth) { // renderbuf_internal*i = (renderbuf_internal*)dest->internal; SHAPELINE*line; int x=0,y=0; MATRIX mat = *m; SHAPE2* s2 = 0; SHAPE2* lshape = 0; renderpoint_t p, lp; U32 clipdepth; double widthmultiply = matrixsize(m); memset(&p, 0, sizeof(renderpoint_t)); memset(&lp, 0, sizeof(renderpoint_t)); clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0; p.depth = _depth << 16; mat.tx -= dest->posx*20; mat.ty -= dest->posy*20; s2 = swf_Shape2Clone(shape); line = s2->lines; if(shape->numfillstyles) { int t; p.s = s2; /* multiply fillstyles matrices with placement matrix- important for texture and gradient fill */ for(t=0;t<s2->numfillstyles;t++) { MATRIX nm; swf_MatrixJoin(&nm, &mat, &s2->fillstyles[t].m); /*nm.sx *= i->multiply; nm.sy *= i->multiply; nm.r0 *= i->multiply; nm.r1 *= i->multiply; nm.tx *= i->multiply; nm.ty *= i->multiply;*/ s2->fillstyles[t].m = nm; } } if(shape->numlinestyles) { lshape = linestyle2fillstyle(shape); lp.s = lshape; lp.depth = (_depth << 16)+1; } while(line) { int x1,y1,x2,y2,x3,y3; if(line->type == moveTo) { } else if(line->type == lineTo) { transform_point(&mat, x, y, &x1, &y1); transform_point(&mat, line->x, line->y, &x3, &y3); if(line->linestyle && ! clipdepth) { lp.shapeline = &lshape->lines[line->linestyle-1]; add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp); lp.depth++; } if(line->fillstyle0 || line->fillstyle1) { assert(shape->numfillstyles); p.shapeline = line; add_line(dest, x1, y1, x3, y3, &p); } } else if(line->type == splineTo) { int c,t,parts;//,qparts; double xx,yy; transform_point(&mat, x, y, &x1, &y1); transform_point(&mat, line->sx, line->sy, &x2, &y2); transform_point(&mat, line->x, line->y, &x3, &y3); c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1); xx=x1; yy=y1; parts = (int)(sqrt((float)c)/3); if(!parts) parts = 1; for(t=1;t<=parts;t++) { double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts); double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts); if(line->linestyle && ! clipdepth) { lp.shapeline = &lshape->lines[line->linestyle-1]; add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp); lp.depth++; } if(line->fillstyle0 || line->fillstyle1) { assert(shape->numfillstyles); p.shapeline = line; add_line(dest, xx, yy, nx, ny, &p); } xx = nx; yy = ny; } } x = line->x; y = line->y; line = line->next; } swf_Process(dest, clipdepth); if(s2) { swf_Shape2Free(s2); rfx_free(s2);s2=0; } if(lshape) { swf_Shape2Free(lshape); rfx_free(lshape);lshape=0; } }
int swf_ActionEnumerate(ActionTAG*atag, char*(*callback)(char*), int type) { int t; U8*data; char* cp; int count = 0; while(atag) { U16 poollen = 0; for(t=0;t<definedactions;t++) if(actions[t].op == atag->op) break; if(t==definedactions) { // unknown actiontag atag = atag->next; count++; continue; } cp = actions[t].flags; data = atag->data; if(atag->len) { while(*cp) { U8 * replacepos = 0; int replacelen = 0; U8 * replacement = 0; switch(*cp) { case 'u': { if(type&TYPE_URL) { replacelen = strlen((const char*)data); replacepos = data; replacement = (U8*)callback((char*)data); // may be null } } break; case 't': { if(type&TYPE_TARGET) { replacelen = strlen((const char*)data); replacepos = data; replacement = (U8*)callback((char*)data); // may be null } } break; case 'c': { if(type&TYPE_STRING) { replacelen = strlen((const char*)data); replacepos = data; replacement = (U8*)callback((char*)data); // may be null } } break; case 'C': { poollen = (data[0]+256*data[1]); } break; case 'o': { } break; case 'p': { U8 datatype = *data; char*value = (char*)&data[1]; if(datatype == 0) { //string if(type&TYPE_STRING) { replacelen = strlen(value); replacepos = (U8*)value; replacement = (U8*)callback(value); // may be null } } else if (datatype == 8) { //lookup } } break; } data += OpAdvance(*cp, data); if(*cp!='c' || !poollen) cp++; if(poollen) poollen--; if(replacement) { int newlen = strlen((const char *)replacement); char * newdata = (char*)rfx_alloc(atag->len - replacelen + newlen); int rpos = replacepos - atag->data; memcpy(newdata, atag->data, rpos); memcpy(&newdata[rpos], replacement, newlen); memcpy(&newdata[rpos+newlen], &replacepos[replacelen], &data[atag->len] - &replacepos[replacelen]); rfx_free(atag->data); atag->data = (U8*)newdata; data = &atag->data[rpos+newlen+1]; } } } atag = atag->next; count ++; } return count; }
/* TODO: * this should be in swfdump.c */ void swf_DumpActions(ActionTAG*atag, char*prefix) { int t; U8*data; char* cp; int entry = 0; char spaces[MAX_LEVELS*4+1]; struct { char*text; int count; } counter[MAX_LEVELS]; int countpos = 0; #ifdef MAX_LOOKUP char * lookup[MAX_LOOKUP]; memset(lookup,0x00,sizeof(lookup)); #endif memset(spaces, 32, sizeof(spaces)); spaces[sizeof(spaces)-1] = 0; if (!prefix) prefix=""; while(atag) { char*indent = &spaces[sizeof(spaces)-1-countpos*4]; U16 poollen = 0; for(t=0;t<definedactions;t++) if(actions[t].op == atag->op) break; if(t==definedactions) { printf("%s (%5d bytes) action:%s unknown[%02x]", prefix, atag->len, indent, atag->op); } else { printf("%s (%5d bytes) action:%s %s", prefix, atag->len, indent, actions[t].name); } data = atag->data; if(atag->len && t!=definedactions) //TODO: check for consistency: should we have a length? { cp = actions[t].flags; while(*cp) { switch(*cp) { case 'f': { //frame printf(" %d", data[0]+256*data[1]); } break; case 'u': { printf(" URL:\"%s\"", data); } break; case 't': { printf(" Target:\"%s\"", data); } break; case 'l': { printf(" Label:\"%s\"", data); } break; case 'c': { printf(" String:\"%s\"", data); #ifdef MAX_LOOKUP if (entry<MAX_LOOKUP) lookup[entry++] = strdup((const char*)data); #endif } break; case 'C': { poollen = data[0]+256*data[1]; entry = 0; printf("(%d entries)", poollen); } break; case 's': { printf(" +%d", *data); } break; case 'm': { //m: method (byte) url:(0=none, 1=get, 2=datat)/gf2:(1=play) printf(" %d", *data); } break; case '{': { U16 num; U16 codesize; int s = 0; int t; printf(" %s(", data); while(data[s++]); //name num = (data[s++]); //num num += (data[s++])*256; for(t=0;t<num;t++) { printf("%s",data+s); // 10/22/04 MD: added +s to if(t<num-1) printf(", "); while(data[s++]); //param } printf(")"); codesize = (data[s++]); //num codesize += (data[s++])*256; printf(" codesize:%d ",codesize); printf("\n%s %s{", prefix, indent); if(countpos>=15) { printf("Error: nested too deep\n"); continue; } counter[countpos].text = "}"; counter[countpos].count = codesize + ATAG_FULLLENGTH(atag); countpos++; } break; case 'o': { int t; U16 codesize = data[0]+256*data[1]; printf(" codesize:%d ", codesize); /* the following tries to find the "string" the flash documentation speaks of- I've never actually seen one yet. -mk */ for(t=2;t<atag->len;t++) printf("[%02x]", atag->data[t]); printf("\n%s %s{", prefix, indent); if(countpos>=15) { printf("Error: nested too deep\n"); continue; } counter[countpos].text = "}"; counter[countpos].count = codesize + ATAG_FULLLENGTH(atag); countpos++; } break; case 'b': { printf(" %d", data[0]+256*(signed char)data[1]); } break; case 'r': { printf(" %d", data[0]); } break; case 'p': { U8 type = *data; unsigned char*value = data+1; if(type == 0) { printf(" String:\"%s\"", value); } else if (type == 1) { U32 f = value[0]+(value[1]<<8)+ (value[2]<<16)+(value[3]<<24); printf(" Float:%f", *(float*)&f); } else if (type == 2) { printf(" NULL"); } else if (type == 3) { printf(" Undefined"); } else if (type == 4) { printf(" register:%d", *value); } else if (type == 5) { printf(" bool:%s", *value?"true":"false"); } else if (type == 6) { U8 a[8]; memcpy(&a[4],value,4); memcpy(a,&value[4],4); #ifdef WORDS_BIGENDIAN int t; for(t=0;t<4;t++) { U8 tmp = a[t]; a[t]=a[7-t]; a[7-t] = tmp; } #endif printf(" double:%f", *(double*)a); } else if (type == 7) { printf(" int:%d", value[0]+(value[1]<<8)+ (value[2]<<16)+(value[3]<<24)); } else if (type == 8) { printf(" Lookup:%d", *value); #ifdef MAX_LOOKUP if (lookup[*value]) printf(" (\"%s\")",lookup[*value]); #endif } else if (type == 9) { U32 offset = value[0]+(value[1]<<8); printf(" Lookup16:%d", offset); #ifdef MAX_LOOKUP if (lookup[offset]) printf(" (\"%s\")",lookup[offset]); #endif } else { printf(" UNKNOWN[%02x]",type); } } break; } data += OpAdvance(*cp, data); if((*cp!='c' || !poollen) && (*cp!='p' || !(data<&atag->data[atag->len]))) cp++; if(poollen) poollen--; } } if(data < atag->data + atag->len) { int nl = ((atag->data+atag->len)-data); int t; printf(" (remainder of %d bytes:\"", nl); for(t=0;t<nl;t++) { if(data[t]<32) printf("\\%d",data[t]); else printf("%c", data[t]); } printf("\")"); } printf("\n"); for(t=0;t<countpos;t++) { counter[t].count -= ATAG_FULLLENGTH(atag); if(counter[t].count < 0) { printf("===== Error: Oplength errors =====\n"); countpos = 0; break; } } while(countpos && !counter[countpos-1].count) { printf("%s %s%s\n", prefix, indent, counter[countpos-1].text); indent += 4; countpos--; } atag = atag->next; } #ifdef MAX_LOOKUP for (t=0;t<MAX_LOOKUP;t++) if (lookup[t]) rfx_free(lookup[t]); #endif }
SWFFONT* swf_LoadT1Font(const char*filename) { SWFFONT * font; int nr; float angle,underline; char*fontname,*fullname,*familyname; BBox bbox; int s,num; char**charnames; char**charname; char*encoding[256]; int c; int t; if(!t1lib_initialized) { T1_SetBitmapPad(16); if ((T1_InitLib(NO_LOGFILE)==NULL)){ fprintf(stderr, "Initialization of t1lib failed\n"); return 0; } t1lib_initialized = 1; } nr = T1_AddFont(filename); T1_LoadFont(nr); charnames = T1_GetAllCharNames(nr); if(!charnames) { fprintf(stderr, "No Charnames record- not a Type1 Font?\n"); return 0; } angle = T1_GetItalicAngle(nr); fontname = T1_GetFontName(nr); fullname = T1_GetFullName(nr); familyname = T1_GetFamilyName(nr); underline = T1_GetUnderlinePosition(nr); bbox = T1_GetFontBBox(nr); font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT)); font->version = 2; if(fontname) font->name = (U8*)strdup(fontname); else font->name = 0; font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT)); num = 0; charname = charnames; while(*charname) { charname++; if(num<256) { if(*charname) encoding[num] = strdup(*charname); else encoding[num] = strdup(".notdef"); } num++; } for(t=num;t<256;t++) encoding[t] = strdup(".notdef"); //T1_ReencodeFont(nr, encoding); font->maxascii = num; font->numchars = num; font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0); font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH)); font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16)); font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int)); font->layout->ascent = (U16)(underline - bbox.lly); font->layout->descent = (U16)(bbox.ury - underline); font->layout->leading = (U16)(font->layout->ascent - font->layout->descent - (bbox.lly - bbox.ury)); font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num); font->layout->kerningcount = 0; font->layout->kerning = 0; font->glyphnames = rfx_calloc(num*sizeof(char*)); num = 0; charname = charnames; for(c=0;c<font->numchars;c++) { drawer_t draw; SRECT bbox; T1_OUTLINE * outline; FPOINT pos,last; int firstx; outline = T1_GetCharOutline(nr, c, 100.0, 0); firstx = outline->dest.x/0xffff; pos.x = 0; pos.y = 0; last = pos; font->glyphnames[c] = strdup(*charname); if(c<font->maxascii) font->ascii2glyph[c] = c; font->glyph2ascii[c] = c; swf_Shape01DrawerInit(&draw, 0); while(outline) { pos.x += (outline->dest.x/(float)0xffff); pos.y += (outline->dest.y/(float)0xffff); if(outline->type == T1_PATHTYPE_MOVE) { draw.moveTo(&draw,&pos); } else if(outline->type == T1_PATHTYPE_LINE) { draw.lineTo(&draw,&pos); } else if(outline->type == T1_PATHTYPE_BEZIER) { T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline; FPOINT b,c; b.x = o2->B.x/(float)0xffff+last.x; b.y = o2->B.y/(float)0xffff+last.y; c.x = o2->C.x/(float)0xffff+last.x; c.y = o2->C.y/(float)0xffff+last.y; draw_cubicTo(&draw,&b,&c,&pos); } else { fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type); } last = pos; outline = outline->link; } draw.finish(&draw); font->glyph[c].shape = swf_ShapeDrawerToShape(&draw); bbox = swf_ShapeDrawerGetBBox(&draw); draw.dealloc(&draw); font->layout->bounds[c] = bbox; font->glyph[c].advance = bbox.xmax; if(!font->glyph[c].advance) { font->glyph[c].advance = firstx; } charname++; } T1_DeleteFont(nr); for(t=0;t<256;t++) rfx_free(encoding[t]); return font; }
SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype) { FT_Face face; FT_Error error; const char* name = 0; FT_ULong charcode; FT_UInt gindex; SWFFONT* font; int t; int*glyph2glyph; int max_unicode = 0; int charmap = -1; if(ftlibrary == 0) { if(FT_Init_FreeType(&ftlibrary)) { fprintf(stderr, "Couldn't init freetype library!\n"); exit(1); } } error = FT_New_Face(ftlibrary, filename, 0, &face); if(error || !face) { fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename); return 0; } int scale = flashtype?20:1; FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale); if(face->num_glyphs <= 0) { fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs); return 0; } font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT)); font->id = -1; font->version = flashtype?3:2; font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT)); font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT)); font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0); font->encoding = FONT_ENCODING_UNICODE; font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16)); font->maxascii = 0; font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH)); if(FT_HAS_GLYPH_NAMES(face)) { font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*)); } font->layout->kerningcount = 0; name = face->family_name; if(!(name && *name)) name = FT_Get_Postscript_Name(face); if(name && *name) font->name = (U8*)strdup(name); while(1) { /* // Map Glyphs to Unicode, version 1 (quick and dirty): int t; for(t=0;t<65536;t++) { int index = FT_Get_Char_Index(face, t); if(index>=0 && index<face->num_glyphs) { if(font->glyph2ascii[index]<0) font->glyph2ascii[index] = t; } }*/ // Map Glyphs to Unicode, version 2 (much nicer): // (The third way would be the AGL algorithm, as proposed // by Werner Lemberg on [email protected]) charcode = FT_Get_First_Char(face, &gindex); while(gindex != 0) { if(gindex >= 0 && gindex<face->num_glyphs) { if(!font->glyph2ascii[gindex]) { font->glyph2ascii[gindex] = charcode; if(charcode + 1 > font->maxascii) { font->maxascii = charcode + 1; } } } charcode = FT_Get_Next_Char(face, charcode, &gindex); } /* if we didn't find a single encoding character, try the font's charmaps instead. That usually means that the encoding is no longer unicode. TODO: find a way to convert the encoding to unicode */ if(font->maxascii == 0 && charmap < face->num_charmaps - 1) { charmap++; FT_Set_Charmap(face, face->charmaps[charmap]); font->encoding = 0;//anything but unicode FIXME } else break; } if(full_unicode) font->maxascii = 65535; font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int)); for(t=0;t<font->maxascii;t++) { int g = FT_Get_Char_Index(face, t); if(!g || g>=face->num_glyphs) g = -1; font->ascii2glyph[t] = g; if(g>=0) { max_unicode = t+1; if(!font->glyph2ascii[g]) { font->glyph2ascii[g] = t; } } } font->maxascii = max_unicode; font->numchars = 0; glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int)); SRECT fontbbox = {0,0,0,0}; for(t=0; t < face->num_glyphs; t++) { FT_Glyph glyph; FT_BBox bbox; char name[128]; drawer_t draw; char hasname = 0; name[0]=0; if(FT_HAS_GLYPH_NAMES(face)) { error = FT_Get_Glyph_Name(face, t, name, 127); if(!error && name[0] && !strstr(name, "notdef")) { font->glyphnames[font->numchars] = strdup(name); hasname = 1; } } if(!font->glyph2ascii[t] && !hasname && skip_unused) { continue; } error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP); if(error) { //tends to happen with some pdfs fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error); glyph=0; if(skip_unused) continue; } else { error = FT_Get_Glyph(face->glyph, &glyph); if(error) { fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error); glyph=0; if(skip_unused) continue; } } if(glyph) FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox); else memset(&bbox, 0, sizeof(bbox)); bbox.yMin = -bbox.yMin; bbox.yMax = -bbox.yMax; if(bbox.xMax < bbox.xMin) { // swap bbox.xMax ^= bbox.xMin; bbox.xMin ^= bbox.xMax; bbox.xMax ^= bbox.xMin; } if(bbox.yMax < bbox.yMin) { // swap bbox.yMax ^= bbox.yMin; bbox.yMin ^= bbox.yMax; bbox.yMax ^= bbox.yMin; } swf_Shape01DrawerInit(&draw, 0); //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw); if(glyph) error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw); else error = 0; draw.finish(&draw); if(error) { fprintf(stderr, "Couldn't decompose glyph %d\n", t); draw.dealloc(&draw); continue; } #if 0 if(bbox.xMin > 0) { font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS; } else { font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS; } #else if(glyph) font->glyph[font->numchars].advance = glyph->advance.x*20/65536; else font->glyph[font->numchars].advance = 0; #endif SRECT b = swf_ShapeDrawerGetBBox(&draw); //font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS; font->layout->bounds[font->numchars] = b; font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw); swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]); draw.dealloc(&draw); if(glyph) FT_Done_Glyph(glyph); font->glyph2ascii[font->numchars] = font->glyph2ascii[t]; glyph2glyph[t] = font->numchars; font->numchars++; } //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin; //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax; //font->layout->leading = font->layout->ascent + font->layout->descent; if(-fontbbox.ymin < 0) font->layout->ascent = 0; else font->layout->ascent = -fontbbox.ymin; if(fontbbox.ymax < 0) font->layout->descent = 0; else font->layout->descent = fontbbox.ymax; int leading = fontbbox.ymax - fontbbox.ymin; font->layout->leading = leading>0x7fff?0x7fff:leading; /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will have more memory allocated than just font->numchars, but only the first font->numchars are used/valid */ for(t=0;t<font->maxascii;t++) { if(font->ascii2glyph[t]>=0) { font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]]; } } rfx_free(glyph2glyph); FT_Done_Face(face); FT_Done_FreeType(ftlibrary);ftlibrary=0; return font; }