void importGlyphPoints( FT_Vector *points, int n, value callbacks, field lineTo, field curveTo, bool cubic ) { value arg[4]; int i; if( n==0 ) { val_ocall2( callbacks, lineTo, alloc_int( points[0].x ), alloc_int( points[0].y ) ); } else if( n==1 ) { arg[0] = alloc_int( points[0].x ); arg[1] = alloc_int( points[0].y ); arg[2] = alloc_int( points[1].x ); arg[3] = alloc_int( points[1].y ); val_ocallN( callbacks, curveTo, arg, 4 ); } else if( n>=2 ) { if( cubic ) { // printf(stderr,"ERROR: cubic beziers in fonts are not yet implemented.\n"); } else { int x1, y1, x2, y2, midx, midy; for( i=0; i<n-1; i++ ) { x1 = points[i].x; y1 = points[i].y; x2 = points[i+1].x; y2 = points[i+1].y; midx = x1 + ((x2-x1)/2); midy = y1 + ((y2-y1)/2); arg[0] = alloc_int( x1 ); arg[1] = alloc_int( y1 ); arg[2] = alloc_int( midx ); arg[3] = alloc_int( midy ); val_ocallN( callbacks, curveTo, arg, 4 ); } arg[0] = alloc_int( x2 ); arg[1] = alloc_int( y2 ); arg[2] = alloc_int( points[n].x ); arg[3] = alloc_int( points[n].y ); val_ocallN( callbacks, curveTo, arg, 4 ); } } else { } }
static value unserialize_rec( sbuffer *b, value loader ) { switch( read_char(b) ) { case 'N': return val_null; case 'T': return val_true; case 'F': return val_false; case 'i': return alloc_int(read_int(b)); case 'I': return alloc_int32(read_int(b)); case 'f': { tfloat d; read_str(b,sizeof(tfloat),&d); return alloc_float(d); } case 's': { int l = read_int(b); value v; if( l < 0 || l > max_string_size ) ERROR(); v = alloc_empty_string(l); add_ref(b,v); read_str(b,l,(char*)val_string(v)); return v; } case 'o': { int f; value o = alloc_object(NULL); add_ref(b,o); while( (f = read_int(b)) != 0 ) { value fval = unserialize_rec(b,loader); alloc_field(o,(field)f,fval); } switch( read_char(b) ) { case 'p': { value v = unserialize_rec(b,loader); if( !val_is_object(v) ) ERROR(); ((vobject*)o)->proto = (vobject*)v; } break; case 'z': break; default: ERROR(); } return o; } case 'r': { int n = read_int(b); if( n < 0 || n >= b->nrefs ) ERROR(); return b->trefs[b->nrefs - n - 1]; } case 'a': { int i; int n = read_int(b); value o; value *t; if( n < 0 || n > max_array_size ) ERROR(); o = alloc_array(n); t = val_array_ptr(o); add_ref(b,o); for(i=0;i<n;i++) t[i] = unserialize_rec(b,loader); return o; } case 'p': { int nargs = read_int(b); vfunction *f = (vfunction*)alloc_function((void*)1,nargs,NULL); vfunction *f2; value name; add_ref(b,(value)f); name = unserialize_rec(b,loader); f2 = (vfunction*)val_ocall2(loader,id_loadprim,name,alloc_int(nargs)); if( !val_is_function(f2) || val_fun_nargs(f2) != nargs ) failure("Loader returned not-a-function"); f->t = f2->t; f->addr = f2->addr; f->module = f2->module; return (value)f; } case 'L': { vfunction *f = (vfunction*)alloc_function((void*)1,0,NULL); value mname; int pos; int nargs; value env; add_ref(b,(value)f); mname = unserialize_rec(b,loader); pos = read_int(b); nargs = read_int(b); env = unserialize_rec(b,loader); if( !val_is_array(env) ) ERROR(); { value exp = val_ocall2(loader,id_loadmodule,mname,loader); value mval; unsigned int i; int_val *mpos; neko_module *m; if( !val_is_object(exp) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } mval = val_field(exp,id_module); if( !val_is_kind(mval,neko_kind_module) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid type"); bfailure(b); } m = (neko_module*)val_data(mval); mpos = m->code + pos; for(i=0;i<m->nglobals;i++) { vfunction *g = (vfunction*)m->globals[i]; if( val_is_function(g) && g->addr == mpos && g->module == m && g->nargs == nargs ) { f->t = VAL_FUNCTION; f->env = env; f->addr = mpos; f->nargs = nargs; f->module = m; return (value)f; } } { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has been modified"); bfailure(b); } } return val_null; } case 'x': { value mname = unserialize_rec(b,loader); value data = unserialize_rec(b,loader); value exports = val_ocall2(loader,id_loadmodule,mname,loader); value s; if( !val_is_object(exports) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } s = val_field(exports,id_unserialize); if( !val_is_function(s) || (val_fun_nargs(s) != 1 && val_fun_nargs(s) != VAR_ARGS) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid __unserialize function"); } s = val_call1(s,data); add_ref(b,s); return s; } case 'h': { int i; vhash *h = (vhash*)alloc(sizeof(vhash)); h->ncells = read_int(b); h->nitems = read_int(b); h->cells = (hcell**)alloc(sizeof(hcell*)*h->ncells); for(i=0;i<h->ncells;i++) h->cells[i] = NULL; for(i=0;i<h->nitems;i++) { hcell **p; hcell *c = (hcell*)alloc(sizeof(hcell)); c->hkey = read_int(b); c->key = unserialize_rec(b,loader); c->val = unserialize_rec(b,loader); c->next = NULL; p = &h->cells[c->hkey % h->ncells]; while( *p != NULL ) p = &(*p)->next; *p = c; } return alloc_abstract(k_hash,h); } default: ERROR(); return val_null; } }
value ftIterateGlyphs( value font, value callbacks ) { if( !val_is_object(callbacks) ) { ft_failure_v("not a callback function object: ", callbacks ); } // printf("A\n"); field endGlyph = val_id("endGlyph"); field startContour = val_id("startContour"); field endContour = val_id("endContour"); field lineTo = val_id("lineTo"); field curveTo = val_id("curveTo"); // printf("B\n"); if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); // printf("C\n"); FT_UInt glyph_index; FT_ULong character; FT_Outline *outline; field f_character = val_id("character"); field f_advance = val_id("advance"); character = FT_Get_First_Char( *face, &glyph_index ); // printf("D\n"); while( character != 0 ) { if( FT_Load_Glyph( *face, glyph_index, FT_LOAD_NO_BITMAP ) ) { // ignore (TODO report?) } else if( (*face)->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) { // ignore (TODO) } else { outline = &((*face)->glyph->outline); int start = 0, end, contour, p; char control, cubic; int n,i; // printf(" 1\n"); for( contour = 0; contour < outline->n_contours; contour++ ) { end = outline->contours[contour]; n=0; for( p = start; p<=end; p++ ) { control = !(outline->tags[p] & 0x01); cubic = outline->tags[p] & 0x02; if( p==start ) { val_ocall2( callbacks, startContour, alloc_int( outline->points[p-n].x ), alloc_int( outline->points[p-n].y ) ); } if( !control && n > 0 ) { importGlyphPoints( &(outline->points[(p-n)+1]), n-1, callbacks, lineTo, curveTo, cubic ); n=1; } else { n++; } } if( n ) { // special case: repeat first point FT_Vector points[n+1]; int s=(end-n)+2; for( i=0; i<n-1; i++ ) { points[i].x = outline->points[s+i].x; points[i].y = outline->points[s+i].y; } points[n-1].x = outline->points[start].x; points[n-1].y = outline->points[start].y; importGlyphPoints( points, n-1, callbacks, lineTo, curveTo, false ); } start = end+1; val_ocall0( callbacks, endContour ); } // printf(" 2\n"); val_ocall2( callbacks, endGlyph, alloc_int( character ), alloc_int( (*face)->glyph->advance.x ) ); // printf(" 3\n"); } // printf(" E\n"); character = FT_Get_Next_Char( *face, character, &glyph_index ); // printf(" F\n"); } // printf(" Goo\n"); return val_true; }
value api_val_ocall2(value arg1,int arg2,value arg3,value arg4) { return val_ocall2(arg1,arg2,arg3,arg4); }
static void do_parse_xml( const char *xml, const char **lp, int *line, value callb, const char *parentname ) { STATE state = BEGIN; STATE next = BEGIN; field aname = (field)0; value attribs = NULL_VAL; value nodename = NULL_VAL; const char *start = NULL; const char *p = *lp; char c = *p; int nsubs = 0, nbrackets = 0; while( c ) { switch( state ) { case IGNORE_SPACES: switch( c ) { case '\n': case '\r': case '\t': case ' ': break; default: state = next; continue; } break; case BEGIN: switch( c ) { case '<': state = IGNORE_SPACES; next = BEGIN_NODE; break; default: start = p; state = PCDATA; continue; } break; case PCDATA: if( c == '<' ) { val_ocall1(callb,id_pcdata,copy_string(start,p-start)); nsubs++; state = IGNORE_SPACES; next = BEGIN_NODE; } break; case CDATA: if( c == ']' && p[1] == ']' && p[2] == '>' ) { val_ocall1(callb,id_cdata,copy_string(start,p-start)); nsubs++; p += 2; state = BEGIN; } break; case BEGIN_NODE: switch( c ) { case '!': if( p[1] == '[' ) { p += 2; if( (p[0] != 'C' && p[0] != 'c') || (p[1] != 'D' && p[1] != 'd') || (p[2] != 'A' && p[2] != 'a') || (p[3] != 'T' && p[3] != 't') || (p[4] != 'A' && p[4] != 'a') || (p[5] != '[') ) ERROR("Expected <![CDATA["); p += 5; state = CDATA; start = p + 1; break; } if( p[1] == 'D' || p[1] == 'd' ) { if( (p[2] != 'O' && p[2] != 'o') || (p[3] != 'C' && p[3] != 'c') || (p[4] != 'T' && p[4] != 't') || (p[5] != 'Y' && p[5] != 'y') || (p[6] != 'P' && p[6] != 'p') || (p[7] != 'E' && p[7] != 'e') ) ERROR("Expected <!DOCTYPE"); p += 7; state = DOCTYPE; start = p + 1; break; } if( p[1] != '-' || p[2] != '-' ) ERROR("Expected <!--"); p += 2; state = COMMENT; start = p + 1; break; case '?': state = HEADER; start = p; break; case '/': if( parentname == NULL ) ERROR("Expected node name"); start = p + 1; state = IGNORE_SPACES; next = CLOSE; break; default: state = TAG_NAME; start = p; continue; } break; case TAG_NAME: if( !is_valid_char(c) ) { if( p == start ) ERROR("Expected node name"); nodename = copy_string(start,p-start); attribs = alloc_empty_object(); state = IGNORE_SPACES; next = BODY; continue; } break; case BODY: switch( c ) { case '/': state = WAIT_END; nsubs++; val_ocall2(callb,id_xml,nodename,attribs); break; case '>': state = CHILDS; nsubs++; val_ocall2(callb,id_xml,nodename,attribs); break; default: state = ATTRIB_NAME; start = p; continue; } break; case ATTRIB_NAME: if( !is_valid_char(c) ) { value tmp; if( start == p ) ERROR("Expected attribute name"); tmp = copy_string(start,p-start); aname = val_id(val_string(tmp)); if( !val_is_null(val_field(attribs,aname)) ) ERROR("Duplicate attribute"); state = IGNORE_SPACES; next = EQUALS; continue; } break; case EQUALS: switch( c ) { case '=': state = IGNORE_SPACES; next = ATTVAL_BEGIN; break; default: ERROR("Expected ="); } break; case ATTVAL_BEGIN: switch( c ) { case '"': case '\'': state = ATTRIB_VAL; start = p; break; default: ERROR("Expected \""); } break; case ATTRIB_VAL: if( c == *start ) { value aval = copy_string(start+1,p-start-1); alloc_field(attribs,aname,aval); state = IGNORE_SPACES; next = BODY; } break; case CHILDS: *lp = p; do_parse_xml(xml,lp,line,callb,val_string(nodename)); p = *lp; start = p; state = BEGIN; break; case WAIT_END: switch( c ) { case '>': val_ocall0(callb,id_done); state = BEGIN; break; default : ERROR("Expected >"); } break; case WAIT_END_RET: switch( c ) { case '>': if( nsubs == 0 ) val_ocall1(callb,id_pcdata,alloc_string("")); val_ocall0(callb,id_done); *lp = p; return; default : ERROR("Expected >"); } break; case CLOSE: if( !is_valid_char(c) ) { if( start == p ) ERROR("Expected node name"); { value v = copy_string(start,p - start); if( _strcmpi(parentname,val_string(v)) != 0 ) { buffer b = alloc_buffer("Expected </"); buffer_append(b,parentname); buffer_append(b,">"); ERROR(buffer_data(b)); } } state = IGNORE_SPACES; next = WAIT_END_RET; continue; } break; case COMMENT: if( c == '-' && p[1] == '-' && p[2] == '>' ) { val_ocall1(callb,id_comment,copy_string(start,p-start)); p += 2; state = BEGIN; } break; case DOCTYPE: if( c == '[' ) nbrackets++; else if( c == ']' ) nbrackets--; else if( c == '>' && nbrackets == 0 ) { val_ocall1(callb,id_doctype,copy_string(start,p-start)); state = BEGIN; } break; case HEADER: if( c == '?' && p[1] == '>' ) { p++; val_ocall1(callb,id_comment,copy_string(start,p-start)); state = BEGIN; } break; } c = *++p; if( c == '\n' ) (*line)++; } if( state == BEGIN ) { start = p; state = PCDATA; } if( parentname == NULL && state == PCDATA ) { if( p != start || nsubs == 0 ) val_ocall1(callb,id_pcdata,copy_string(start,p-start)); return; } ERROR("Unexpected end"); }