static value dialogs_open_file( value title, value msg, value initialdir, value mask,value multi) { value result = val_null; struct ARG_FILEFILTERS filters = {0,0,0}; struct RES_STRINGLIST files; val_check(title,string); val_check(msg,string); val_check(multi,bool); val_check(initialdir, string); if (val_is_object(mask)) { value count = val_field(mask,val_id("count")); value descriptions = val_field(mask,val_id("descriptions")); value extensions = val_field(mask,val_id("extensions")); val_check(count,int); val_check(descriptions,array); val_check(extensions,array); filters.count = val_int(count); if (filters.count) { long i = filters.count; filters.descriptions = (const char**) malloc(i*sizeof(char*)); filters.extensions = (const char**) malloc(i*sizeof(char*)); while(i) { i--; filters.descriptions[i] = val_string(val_array_i(descriptions,i)); filters.extensions[i] = val_string(val_array_i(extensions,i)); } } } systools_dialogs_open_file(val_string(title),val_string(msg),val_string(initialdir),filters.count? &filters : NULL ,val_bool(multi) ,&files); if (files.count) { result = alloc_array(files.count); while(files.count) { files.count--; val_array_set_i(result, files.count, alloc_string(files.strings[files.count])); free(files.strings[files.count]); } free(files.strings); } // clean up allocated mem. for filters: if (val_is_object(mask)) { free(filters.descriptions); free(filters.extensions); } return result; }
char *Val2Str(value inVal) { if (val_is_string(inVal)) return (char *)val_string(inVal); if (val_is_object(inVal)) { value __s = val_field(inVal, val_id("__s")); if (val_is_string(__s)) return (char *)val_string(__s); } else if (val_is_object(inVal)) return val_bool(inVal) ? (char *)"true":(char *)"false"; return (char *)""; }
/** $objcall : o:any -> f:int -> args:array -> any <doc>Call the field [f] of [o] with [args] and return the value or [null] is [o] is not an object</doc> **/ static value builtin_objcall( value o, value f, value args ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); val_check(args,array); return val_ocallN(o,val_int(f),val_array_ptr(args),val_array_size(args)); }
/** $objset : o:any -> f:int -> v:any -> any <doc>Set the field [f] of [o] to [v] and return [v] if [o] is an object or [null] if not</doc> **/ static value builtin_objset( value o, value f, value v ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); alloc_field(o,val_int(f),v); return v; }
static value dialogs_save_file( value title, value msg, value initialdir, value mask) { char * v; struct ARG_FILEFILTERS filters = {0,0,0}; value result = val_null; val_check(title, string); val_check(msg, string); val_check(initialdir, string); if (val_is_object(mask)) { value count = val_field(mask,val_id("count")); value descriptions = val_field(mask,val_id("descriptions")); value extensions = val_field(mask,val_id("extensions")); val_check(count,int); val_check(descriptions,array); val_check(extensions,array); filters.count = val_int(count); if (filters.count) { long i = filters.count; filters.descriptions = (const char**) malloc(i*sizeof(char*)); filters.extensions = (const char**) malloc(i*sizeof(char*)); while(i) { i--; filters.descriptions[i] = val_string(val_array_i(descriptions,i)); filters.extensions[i] = val_string(val_array_i(extensions,i)); } } } result = val_null; v = systools_dialogs_save_file(val_string(title),val_string(msg),val_string(initialdir),filters.count? &filters : NULL); if (v) { result = alloc_string(v); free((void*)v); } // clean up allocated mem. for filters: if (val_is_object(mask)) { free(filters.descriptions); free(filters.extensions); } return result; }
value ftRenderGlyph( value font, value _index, value _size, value _hint ) { 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 ); val_check( _size, number ); int size = val_number(_size); FT_Set_Char_Size( *face, size, size, 72, 72 ); val_check( _hint, bool ); int hint = val_bool(_hint); val_check(_index,number); /* int index = FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ); fprintf( stderr, "char %i is glyph %i\n", (int)val_number(_index), (int)index ); int err = FT_Load_Glyph( *face, index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING ); fprintf( stderr, "Load Glyph idx %i->%i/%i, sz %i, face %p: err 0x%x\n", (int)val_number(_index), index, (int)((*face)->num_glyphs), size>>6, face, err ); */ int err = FT_Load_Char( *face, (FT_ULong)val_number(_index), FT_LOAD_RENDER | (hint?0:FT_LOAD_NO_HINTING) ); if( err ) { fprintf( stderr, "Load_Char failed: %x char index %i\n", err, FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ) ); val_throw(alloc_string("Could not load requested Glyph")); // return( val_null ); } FT_GlyphSlot glyph = (*face)->glyph; /* err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL ); if( err || glyph->format != ft_glyph_format_bitmap ) { val_throw(alloc_string("Could not render requested Glyph")); } */ FT_Bitmap bitmap = glyph->bitmap; value ret = alloc_object(NULL); alloc_field( ret, val_id("width"), alloc_int(bitmap.width) ); alloc_field( ret, val_id("height"), alloc_int(bitmap.rows) ); alloc_field( ret, val_id("bitmap"), copy_string( (char*)bitmap.buffer, bitmap.width*bitmap.rows ) ); alloc_field( ret, val_id("x"), alloc_int( glyph->metrics.horiBearingX ) ); alloc_field( ret, val_id("y"), alloc_int( glyph->metrics.horiBearingY ) ); alloc_field( ret, val_id("advance"), alloc_float( glyph->advance.x )); return ret; }
EXTERN value alloc_object( value cpy ) { vobject *v; if( cpy != NULL && !val_is_null(cpy) && !val_is_object(cpy) ) val_throw(alloc_string("$new")); // 'new' opcode simulate $new v = (vobject*)gc_alloc(sizeof(vobject)); v->t = VAL_OBJECT; if( cpy == NULL || val_is_null(cpy) ) { v->proto = NULL; otable_init(&v->table); } else { v->proto = ((vobject*)cpy)->proto; otable_copy(&((vobject*)cpy)->table,&v->table); } return (value)v; }
value ftIterateKerningPairs( value font, value callback ) { 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 ); if( !FT_HAS_KERNING((*face)) ) { return val_null; } FT_UInt left_index, right_index; FT_ULong left, right; FT_Vector vec; left = FT_Get_First_Char( *face, &left_index ); while( left != 0 ) { right = FT_Get_First_Char( *face, &right_index ); while( right != 0 ) { if( !FT_Get_Kerning( *face, left_index, right_index, FT_KERNING_UNFITTED, &vec ) && vec.x ) { // printf("KERNING %c_%c: %f\n", left, right, vec.x ); val_call3( callback, alloc_int( (int)left ), alloc_int( (int)right ), alloc_float( vec.x ) ); } right = FT_Get_Next_Char( *face, right, &right_index ); } left = FT_Get_Next_Char( *face, left, &left_index ); } return val_true; }
/** $objfield : o:any -> f:int -> bool <doc>Return true if [o] is an object which have field [f]</doc> **/ static value builtin_objfield( value o, value f ) { val_check(f,int); return alloc_bool( val_is_object(o) && otable_find(&((vobject*)o)->table, val_int(f)) != NULL ); }
/** $objget : o:any -> f:int -> any <doc>Return the field [f] of [o] or [null] if doesn't exists or [o] is not an object</doc> **/ static value builtin_objget( value o, value f ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); return val_field(o,val_int(f)); }
/** $new : object? -> object <doc>Return a copy of the object or a new object if [null]</doc> **/ static value builtin_new( value o ) { if( !val_is_null(o) && !val_is_object(o) ) neko_error(); return alloc_object(o); }
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; }