/* * Lua interface for the cairo graphics library * Copyright 2007 Niels Martin Hansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Contact: E-mail: IRC: jfs in #aegisub on irc.rizon.net */ #ifndef CAIRO_WRAP_H #define CAIRO_WRAP_H #include "../lua51/src/lua.h" #include #include #include int luaopen_cairo(lua_State *L); template class LuaCairoBase { private: // Default handlers for metatable stuff static int lua_index(lua_State *L) { LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1); return (*obj)->internal_lua_index(L); } static int lua_newindex(lua_State *L) { LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1); return (*obj)->internal_lua_newindex(L); } static int lua_callobj(lua_State *L) { LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1); return (*obj)->internal_lua_callobj(L); } static int lua_gc(lua_State *L) { LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1); delete *obj; return 0; } // Hidden constructors LuaCairoBase() { } LuaCairoBase(const LuaCairoBase &obj) { } // List of callables typedef std::map CallableMap; CallableMap callables; // "Magic" value - used to test that pointers are really valid lua_CFunction magic; protected: virtual int internal_lua_index(lua_State *L) { if (lua_type(L, 2) == LUA_TSTRING) { const char *field = lua_tostring(L, 2); CallableMap::iterator func = callables.find(field); if (func != callables.end()) { lua_pushvalue(L, 1); lua_pushcclosure(L, func->second, 1); return 1; } if (strcmp("_type", lua_tostring(L, 2))) { lua_pushstring(L, GetTypeName()); return 1; } } return 0; } virtual int internal_lua_newindex(lua_State *L) { lua_pushfstring(L, "Cairo object of type '%s' can not have field set", GetTypeName()); lua_error(L); return 0; } virtual int internal_lua_callobj(lua_State *L) { lua_pushfstring(L, "Cairo objct of type '%s' can not be called", GetTypeName()); lua_error(L); return 0; } virtual const char *GetTypeName() { return "_base"; } virtual void CreateMetaTable(lua_State *L) { lua_newtable(L); lua_pushcclosure(L, lua_index, 0); lua_setfield(L, -2, "__index"); lua_pushcclosure(L, lua_newindex, 0); lua_setfield(L, -2, "__newindex"); lua_pushcclosure(L, lua_callobj, 0); lua_setfield(L, -2, "__call"); lua_pushcclosure(L, lua_gc, 0); lua_setfield(L, -2, "__gc"); } void AddCallable(lua_CFunction func, const char *name) { callables[name] = func; } // Primary constructor for use with inherited stuff LuaCairoBase(lua_State *L) { LuaCairoBase **ud = (LuaCairoBase**)lua_newuserdata(L, sizeof(ChildClass*)); *ud = this; CreateMetaTable(L); lua_setmetatable(L, -2); magic = luaopen_cairo; } public: virtual ~LuaCairoBase() { } // Helper: Get the object pointer from a callback static ChildClass *GetObjPointer(lua_State *L, int index) { if (!lua_isuserdata(L, index)) { lua_pushliteral(L, "Passed non-userdata where one expected"); lua_error(L); } ChildClass *obj = CheckPointer(*(void**)lua_touserdata(L, index)); return obj; } // Check whether a pointer plausibly points to an object of this class static ChildClass *CheckPointer(void *ptr) { ChildClass *testptr = (ChildClass*)ptr; if (testptr->magic == luaopen_cairo) return testptr; else return 0; } }; #define CALLABLE(name) static int lua_ ## name (lua_State *L) class LuaCairoContext : public LuaCairoBase { private: cairo_t *context; CALLABLE(reference); CALLABLE(status); CALLABLE(save); CALLABLE(restore); CALLABLE(get_target); CALLABLE(push_group); CALLABLE(push_group_with_content); CALLABLE(pop_group); CALLABLE(pop_group_to_source); CALLABLE(get_group_target); CALLABLE(set_source_rgb); CALLABLE(set_source_rgba); CALLABLE(set_source); CALLABLE(set_source_surface); CALLABLE(get_source); CALLABLE(set_antialias); CALLABLE(get_antialias); CALLABLE(set_dash); CALLABLE(get_dash_count); CALLABLE(get_dash); CALLABLE(set_fill_rule); CALLABLE(get_fill_rule); CALLABLE(set_line_cap); CALLABLE(get_line_cap); CALLABLE(set_line_join); CALLABLE(get_line_join); CALLABLE(set_line_width); CALLABLE(get_line_width); CALLABLE(set_miter_limit); CALLABLE(get_miter_limit); CALLABLE(set_operator); CALLABLE(get_operator); CALLABLE(set_tolerance); CALLABLE(get_tolerance); CALLABLE(clip); CALLABLE(clip_preserve); CALLABLE(clip_extents); CALLABLE(reset_clip); // rectangle_list_destroy is not needed, // copy_clip_rectangle_list will convert the rect list into a pure Lua structure CALLABLE(copy_clip_rectangle_list); CALLABLE(fill); CALLABLE(fill_preserve); CALLABLE(fill_extents); CALLABLE(in_fill); CALLABLE(mask); CALLABLE(mask_surface); CALLABLE(paint); CALLABLE(paint_with_alpha); CALLABLE(stroke); CALLABLE(stroke_preserve); CALLABLE(stroke_extents); CALLABLE(in_stroke); CALLABLE(copy_page); CALLABLE(show_page); // Path operations CALLABLE(copy_path); CALLABLE(copy_path_flat); CALLABLE(append_path); CALLABLE(get_current_point); CALLABLE(new_path); CALLABLE(new_sub_path); CALLABLE(close_path); CALLABLE(arc); CALLABLE(arc_negative); CALLABLE(curve_to); CALLABLE(line_to); CALLABLE(move_to); CALLABLE(rectangle); CALLABLE(glyph_path); CALLABLE(text_path); CALLABLE(rel_curve_to); CALLABLE(rel_line_to); CALLABLE(rel_move_to); // Transformations CALLABLE(translate); CALLABLE(scale); CALLABLE(rotate); CALLABLE(transform); CALLABLE(set_matrix); CALLABLE(get_matrix); CALLABLE(identity_matrix); CALLABLE(user_to_device); CALLABLE(user_to_device_distance); CALLABLE(device_to_user); CALLABLE(device_to_user_distance); // Text/font operations CALLABLE(select_font_face); CALLABLE(set_font_size); CALLABLE(set_font_matrix); CALLABLE(get_font_matrix); CALLABLE(set_font_options); CALLABLE(get_font_options); CALLABLE(set_font_face); CALLABLE(get_font_face); CALLABLE(set_scaled_font); CALLABLE(get_scaled_font); CALLABLE(show_text); CALLABLE(show_glyphs); CALLABLE(font_extents); CALLABLE(text_extents); CALLABLE(glyph_extents); protected: const char *GetTypeName(); public: // Create another reference for a context LuaCairoContext(lua_State *L, cairo_t *_context); // Destructor virtual ~LuaCairoContext(); }; class LuaCairoSurface : public LuaCairoBase { private: CALLABLE(create_similar); CALLABLE(reference); CALLABLE(status); // Create cairo context for this surface // This deviates from the regular cairo API CALLABLE(create_context); CALLABLE(finish); CALLABLE(flush); CALLABLE(get_font_options); CALLABLE(get_content); CALLABLE(mark_dirty); CALLABLE(mark_dirty_rectangle); CALLABLE(set_device_offset); CALLABLE(get_device_offset); CALLABLE(set_fallback_resolution); CALLABLE(get_type); // Image surface functions CALLABLE(image_get_format); CALLABLE(image_get_width); CALLABLE(image_get_height); // These replace the get_data and get_stride functions CALLABLE(image_set_pixel); CALLABLE(image_get_pixel); protected: // Protected because inheriting classes might want it too cairo_surface_t *surface; const char *GetTypeName(); // For child classes that will set surface themselves LuaCairoSurface(lua_State *L); public: // Create another reference for a surface LuaCairoSurface(lua_State *L, cairo_surface_t *_surface); // Destructor virtual ~LuaCairoSurface(); cairo_surface_t *GetSurface() { return surface; } // Creation functions - these aren't in image surface objects but in a global table CALLABLE(image_surface_create); }; class LuaCairoFontFace : public LuaCairoBase { private: cairo_font_face_t *font_face; CALLABLE(create_scaled_font); CALLABLE(reference); CALLABLE(status); CALLABLE(get_type); protected: const char *GetTypeName(); public: // Create another reference for a font face LuaCairoFontFace(lua_State *L, cairo_font_face_t *_font_face); // Destructor virtual ~LuaCairoFontFace(); cairo_font_face_t *GetFontFace() { return font_face; } }; class LuaCairoScaledFont : public LuaCairoBase { private: cairo_scaled_font_t *scaled_font; CALLABLE(reference); CALLABLE(status); CALLABLE(extents); CALLABLE(text_extents); CALLABLE(glyph_extents); CALLABLE(get_font_face); CALLABLE(get_font_options); CALLABLE(get_font_matrix); CALLABLE(get_ctm); CALLABLE(get_type); protected: const char *GetTypeName(); public: // Create another reference for a scaled font LuaCairoScaledFont(lua_State *L, cairo_scaled_font_t *_scaled_font); // Destructor virtual ~LuaCairoScaledFont(); cairo_scaled_font_t *GetScaledFont() { return scaled_font; } }; class LuaCairoFontOptions : public LuaCairoBase { private: cairo_font_options_t *font_options; bool owned; CALLABLE(copy); CALLABLE(status); CALLABLE(merge); CALLABLE(hash); CALLABLE(equal); CALLABLE(set_antialias); CALLABLE(get_antialias); CALLABLE(set_subpixel_order); CALLABLE(get_subpixel_order); CALLABLE(set_hint_style); CALLABLE(get_hint_style); CALLABLE(set_hint_metrics); CALLABLE(get_hint_metrics); void RegFontOptionsCallables(); protected: const char *GetTypeName(); public: // Create a new font options object - will be owned LuaCairoFontOptions(lua_State *L); // Wrap an existing font options object - will not be owned LuaCairoFontOptions(lua_State *L, cairo_font_options_t *_font_options); // Destructor - only destroy font_options if owned virtual ~LuaCairoFontOptions(); cairo_font_options_t *GetFontOptions() { return font_options; } // Creation function - global CALLABLE(create); }; class LuaCairoMatrix : public LuaCairoBase { private: cairo_matrix_t matrix; CALLABLE(init); CALLABLE(init_identity); CALLABLE(init_translate); CALLABLE(init_scale); CALLABLE(init_rotate); CALLABLE(translate); CALLABLE(scale); CALLABLE(rotate); // Matrix inversion CALLABLE(invert); // Matrix multiplication CALLABLE(multiply); CALLABLE(transform_distance); CALLABLE(transform_point); // Pointwise arithmetic on matrices - not part of cairo API CALLABLE(op_add); CALLABLE(op_sub); CALLABLE(op_mul); CALLABLE(op_div); CALLABLE(op_unm); // Equality operator CALLABLE(op_eq); // Not in cairo API CALLABLE(copy); void RegMatrixCallables(lua_State *L); protected: virtual int internal_lua_index(lua_State *L); virtual int internal_lua_newindex(lua_State *L); const char *GetTypeName(); // Extend the meta table with various operators void CreateMetaTable(lua_State *L); public: // Create new matrix, inited to identity matrix LuaCairoMatrix(lua_State *L); // Duplicate exixting matrix LuaCairoMatrix(lua_State *L, const cairo_matrix_t *_matrix); // Destructor virtual ~LuaCairoMatrix(); cairo_matrix_t *GetMatrix(); // Creation function - global CALLABLE(create); }; class LuaCairoPath : public LuaCairoBase { private: cairo_path_t *path; // Specifies whether the memory for the cairo_path_t object is owned by the cairo library. // If cairo owns it we cannot add/remove elements from the path. bool cairo_owns_memory; // Number of path elemts we have allocated memory for. Undefined if cairo_owns_memory. // This is different from path->length because that specifies the number of elements in use. size_t path_elements_allocated; // Management void EnsurePathOwned(); // ensure that we own the path memory void EnsureSpaceFor(size_t n); // ensure we own the path memory and there's space to add at least n more elements // TODO: figure out what methods are needed // Something to iterate over the parts at least // Support for creating/modifying paths? CALLABLE(clear); CALLABLE(move_to); CALLABLE(line_to); CALLABLE(curve_to); CALLABLE(close); // Functional programming support CALLABLE(map); // transform each path segment with a function CALLABLE(map_coords); // transform each coordinate pair with a function CALLABLE(fold); // fold path segments into a single result value CALLABLE(fold_coords); // fold coordinate pairs into a single result value void RegPathCallables(lua_State *L); protected: virtual int internal_lua_index(lua_State *L); const char *GetTypeName(); public: // Create object with new path - we will own the memory LuaCairoPath(lua_State *L); // Create object based on path - does not copy path, and lets cairo own the memory LuaCairoPath(lua_State *L, cairo_path_t *_path); // Destructor virtual ~LuaCairoPath(); cairo_path_t *GetPath() { return path; } // Modifying the path void ClearPath(); void MoveTo(double x, double y); void LineTo(double x, double y); void CurveTo(double x0, double y0, double x1, double y1, double x2, double y2); void ClosePath(); }; class LuaCairoPattern : public LuaCairoBase { private: cairo_pattern_t *pattern; CALLABLE(add_color_stop_rgb); CALLABLE(add_color_stop_rgba); CALLABLE(get_color_stop_count); CALLABLE(get_color_stop_rgba); CALLABLE(get_rgba); CALLABLE(get_surface); CALLABLE(get_linear_points); CALLABLE(get_radial_circles); CALLABLE(reference); CALLABLE(status); CALLABLE(set_extend); CALLABLE(get_extend); CALLABLE(set_filter); CALLABLE(get_filter); CALLABLE(set_matrix); CALLABLE(get_matrix); CALLABLE(get_type); protected: const char *GetTypeName(); public: // Create another reference for a pattern object LuaCairoPattern(lua_State *L, cairo_pattern_t *_pattern); // Destructor virtual ~LuaCairoPattern(); cairo_pattern_t *GetPattern() { return pattern; } // Creation functions - these aren't in pattern objects but in a global table CALLABLE(create_rgb); CALLABLE(create_rgba); CALLABLE(create_for_surface); CALLABLE(create_linear); CALLABLE(create_radial); }; #undef CALLABLE #endif