mirror of https://github.com/odrling/Aegisub
654 lines
14 KiB
C++
654 lines
14 KiB
C++
/*
|
|
* 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: <jiifurusu@gmail.com>
|
|
IRC: jfs in #aegisub on irc.rizon.net
|
|
|
|
*/
|
|
|
|
#ifndef CAIRO_WRAP_H
|
|
#define CAIRO_WRAP_H
|
|
|
|
#include "../lua51/src/lua.h"
|
|
#include <cairo.h>
|
|
#include <string>
|
|
#include <map>
|
|
|
|
|
|
int luaopen_cairo(lua_State *L);
|
|
|
|
|
|
template <class ChildClass>
|
|
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<std::string, lua_CFunction> 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<LuaCairoContext> {
|
|
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<LuaCairoSurface> {
|
|
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<LuaCairoFontFace> {
|
|
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<LuaCairoScaledFont> {
|
|
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<LuaCairoFontOptions> {
|
|
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<LuaCairoMatrix> {
|
|
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<LuaCairoPath> {
|
|
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<LuaCairoPattern> {
|
|
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
|