-
Notifications
You must be signed in to change notification settings - Fork 16
/
ttf.c.m4
375 lines (339 loc) · 11.8 KB
/
ttf.c.m4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/* -*- mode: C -*- */
#ifdef HAVE_SDL_TTF_H
#include "rubysdl2_internal.h"
#include <SDL_ttf.h>
#include <ruby/encoding.h>
static VALUE cTTF;
static VALUE mStyle;
static VALUE mHinting;
#define TTF_ERROR() do { HANDLE_ERROR(SDL_SetError("%s", TTF_GetError())); } while (0)
#define HANDLE_TTF_ERROR(code) \
do { if ((code) < 0) { TTF_ERROR(); } } while (0)
typedef struct TTF {
TTF_Font* font;
} TTF;
#define TTF_ATTRIBUTE(attr, capitalized_attr, ruby2c, c2ruby) \
static VALUE TTF_##attr(VALUE self) \
{ \
return c2ruby(TTF_Get##capitalized_attr(Get_TTF_Font(self))); \
} \
static VALUE TTF_set_##attr(VALUE self, VALUE val) \
{ \
TTF_Set##capitalized_attr(Get_TTF_Font(self), ruby2c(val)); \
return Qnil; \
}
#define TTF_ATTRIBUTE_INT(attr, capitalized_attr) \
TTF_ATTRIBUTE(attr, capitalized_attr, NUM2INT, INT2NUM)
#define TTF_ATTR_READER(attr, capitalized_attr, c2ruby) \
static VALUE TTF_##attr(VALUE self) \
{ \
return c2ruby(TTF_Font##capitalized_attr(Get_TTF_Font(self))); \
}
static void TTF_free(TTF* f)
{
if (rubysdl2_is_active() && f->font)
TTF_CloseFont(f->font);
free(f);
}
static VALUE TTF_new(TTF_Font* font)
{
TTF* f = ALLOC(TTF);
f->font = font;
return Data_Wrap_Struct(cTTF, 0, TTF_free, f);
}
DEFINE_WRAPPER(TTF_Font, TTF, font, cTTF, "SDL2::TTF");
/*
* Document-class: SDL2::TTF
*
* This class represents font information.
*
* You can render TrueType fonts using [SDL_ttf](https://www.libsdl.org/projects/SDL_ttf/)
* and this class.
*
* @!attribute style
* Font style.
* The OR'd bits of the constants of {SDL2::TTF::Style}.
* @return [Integer]
*
* @!attribute outline
* The outline pixel width of the font.
* @return [Integer]
*
* @!attribute hinting
* Font hinting.
* One of the constants of {SDL2::TTF::Hinting}.
* @return [Integer]
*
* @!attribute kerning
* True if kerning is enabled.
* @return [boolean]
*
* @!attribute [r] height
* The maximum pixel height of all glyphs of the font.
* You can use this height to render text as close together vertically
* as possible.
* @return [Integer]
* @see #line_skip
*
* @!attribute [r] ascent
* The maximum pixel ascent of all glyphs of the font.
* The distance from the top of the font to the baseline.
* @return [Integer]
* @see #descent
*
* @!attribute [r] descent
* The maximum pixel descent of all glyphs of the font.
* The distance from the bottom of the font to the baseline.
* @return [Integer]
* @see #ascent
*
* @!attribute [r] line_skip
* The recommended pixel height of rendered line of text
* of the font. Normally, this value is larger than {#height}.
* @return [Integer]
*
* @!attribute [r] num_faces
* The number of faces available in the font.
* @return [Integer]
*
* @!attribute [r] face_family_name
* The current font face family name of the font.
* @return [String]
*
* @!attribute [r] face_style_name
* The current font face style name of the font.
* @return [String]
*
*/
/*
* Initialize TrueType font rendering submodule.
*
* This function must be called before calling other methods/class methods
* of {TTF}.
*
* @return [nil]
*/
static VALUE TTF_s_init(VALUE self)
{
HANDLE_TTF_ERROR(TTF_Init());
return Qnil;
}
/*
* Open a font data from file.
*
* @overload open(fname, ptsize, index=0)
* @param fname [String] the path of the font file
* @param ptsize [Integer] the point size of the font (72DPI).
* @param index [Integer] the index of the font faces.
* Some font files have multiple font faces, and you
* can select one of them using **index**. 0 origin.
* If a font have only one font face, 0 is the only
* valid index.
*
* @return [SDL2::TTF] opened font information
* @raise [SDL2::Error] occurs when you fail to open a file.
*
*/
static VALUE TTF_s_open(int argc, VALUE* argv, VALUE self)
{
TTF_Font* font;
VALUE fname, ptsize, index;
rb_scan_args(argc, argv, "21", &fname, &ptsize, &index);
font = TTF_OpenFontIndex(StringValueCStr(fname), NUM2INT(ptsize),
index == Qnil ? 0 : NUM2LONG(index));
if (!font)
TTF_ERROR();
return TTF_new(font);
}
/*
* Destroy the font data and release memory.
*
* @return [nil]
*/
static VALUE TTF_destroy(VALUE self)
{
TTF* f = Get_TTF(self);
if (f->font)
TTF_CloseFont(f->font);
f->font = NULL;
return Qnil;
}
TTF_ATTRIBUTE_INT(style, FontStyle);
TTF_ATTRIBUTE_INT(outline, FontOutline);
TTF_ATTRIBUTE_INT(hinting, FontHinting);
TTF_ATTRIBUTE(kerning, FontKerning, RTEST, INT2BOOL);
TTF_ATTR_READER(height, Height, INT2FIX);
TTF_ATTR_READER(ascent, Ascent, INT2FIX);
TTF_ATTR_READER(descent, Descent, INT2FIX);
TTF_ATTR_READER(line_skip, LineSkip, INT2FIX);
TTF_ATTR_READER(num_faces, Faces, LONG2NUM);
TTF_ATTR_READER(face_is_fixed_width_p, FaceIsFixedWidth, INT2BOOL);
TTF_ATTR_READER(face_family_name, FaceFamilyName, utf8str_new_cstr);
TTF_ATTR_READER(face_style_name, FaceStyleName, utf8str_new_cstr);
/*
* @overload size_text(text)
* Calculate the size of rendered surface of **text** using the font.
*
* @param text [String] the string to size up
*
* @return [Array(Integer, Integer)] a pair of width and height of the rendered surface
*
* @raise [SDL2::Error] It is raised when an error occurs, such as a glyph ins the
* string not being found.
*/
static VALUE TTF_size_text(VALUE self, VALUE text)
{
int w, h;
text = rb_str_export_to_enc(text, rb_utf8_encoding());
HANDLE_TTF_ERROR(TTF_SizeUTF8(Get_TTF_Font(self), StringValueCStr(text), &w, &h));
return rb_ary_new3(2, INT2NUM(w), INT2NUM(h));
}
static SDL_Surface* render_solid(TTF_Font* font, const char* text, SDL_Color fg, SDL_Color bg)
{
return TTF_RenderUTF8_Solid(font, text, fg);
}
static SDL_Surface* render_blended(TTF_Font* font, const char* text, SDL_Color fg, SDL_Color bg)
{
return TTF_RenderUTF8_Blended(font, text, fg);
}
static VALUE render(SDL_Surface* (*renderer)(TTF_Font*, const char*, SDL_Color, SDL_Color),
VALUE font, VALUE text, VALUE fg, VALUE bg)
{
SDL_Surface* surface;
text = rb_str_export_to_enc(text, rb_utf8_encoding());
surface = renderer(Get_TTF_Font(font), StringValueCStr(text),
Array_to_SDL_Color(fg), Array_to_SDL_Color(bg));
if (!surface)
TTF_ERROR();
return Surface_new(surface);
}
/*
* @overload render_solid(text, fg)
* Render **text** using the font with fg color on a new surface, using
* *Solid* mode.
*
* Solid mode rendering is quick but dirty.
*
* @param text [String] the text to render
* @param fg [Array(Integer, Integer, Integer)]
* the color to render. An array of r, g, and b components.
*
* @return [SDL2::Surface]
*
* @raise [SDL2::Error] raised when the randering fails.
*/
static VALUE TTF_render_solid(VALUE self, VALUE text, VALUE fg)
{
return render(render_solid, self, text, fg, Qnil);
}
/*
* @overload render_shaded(text, fg, bg)
* Render **text** using the font with fg color on a new surface, using
* *Shaded* mode.
*
* Shaded mode rendering is slow and nice, but with a solid box filled by
* the background color.
*
* @param text [String] the text to render
* @param fg [Array(Integer, Integer, Integer)]
* the color to render. An array of r, g, and b components.
* @param bg [Array(Integer, Integer, Integer)]
* the background color. An array of r, g, and b components.
*
* @return [SDL2::Surface]
*
* @raise [SDL2::Error] raised when the randering fails.
*/
static VALUE TTF_render_shaded(VALUE self, VALUE text, VALUE fg, VALUE bg)
{
return render(TTF_RenderUTF8_Shaded, self, text, fg, bg);
}
/*
* @overload render_blended(text, fg)
* Render **text** using the font with fg color on a new surface, using
* *Blended* mode.
*
* Blended mode rendering is very slow but very nice.
* The rendered surface has an alpha channel,
*
* @param text [String] the text to render
* @param fg [Array(Integer, Integer, Integer)]
* the color to render. An array of r, g, and b components.
*
* @return [SDL2::Surface]
*
* @raise [SDL2::Error] raised when the randering fails.
*/
static VALUE TTF_render_blended(VALUE self, VALUE text, VALUE fg)
{
return render(render_blended, self, text, fg, Qnil);
}
/*
* Document-module: SDL2::TTF::Style
*
* Constants represents font styles.
*/
/* Document-module: SDL2::TTF::Hinting
*
* Constants represents font hinting for FreeType.
*/
void rubysdl2_init_ttf(void)
{
cTTF = rb_define_class_under(mSDL2, "TTF", rb_cObject);
rb_undef_alloc_func(cTTF);
rb_define_singleton_method(cTTF, "init", TTF_s_init, 0);
rb_define_singleton_method(cTTF, "open", TTF_s_open, -1);
/* Return true if the font is destroyed by {#destroy}. */
rb_define_method(cTTF, "destroy?", TTF_destroy_p, 0);
rb_define_method(cTTF, "destroy", TTF_destroy, 0);
#define DEFINE_TTF_ATTRIBUTE(attr) do { \
rb_define_method(cTTF, #attr, TTF_##attr, 0); \
rb_define_method(cTTF, #attr "=", TTF_set_##attr, 1); \
} while (0)
DEFINE_TTF_ATTRIBUTE(style);
DEFINE_TTF_ATTRIBUTE(outline);
DEFINE_TTF_ATTRIBUTE(hinting);
DEFINE_TTF_ATTRIBUTE(kerning);
#define DEFINE_TTF_ATTR_READER(attr) \
rb_define_method(cTTF, #attr, TTF_##attr, 0)
DEFINE_TTF_ATTR_READER(height);
DEFINE_TTF_ATTR_READER(ascent);
DEFINE_TTF_ATTR_READER(descent);
DEFINE_TTF_ATTR_READER(line_skip);
DEFINE_TTF_ATTR_READER(num_faces);
/* Return true if the font is fixed width. */
rb_define_method(cTTF, "face_is_fixed_width?", TTF_face_is_fixed_width_p, 0);
DEFINE_TTF_ATTR_READER(face_family_name);
DEFINE_TTF_ATTR_READER(face_style_name);
rb_define_method(cTTF, "size_text", TTF_size_text, 1);
rb_define_method(cTTF, "render_solid", TTF_render_solid, 2);
rb_define_method(cTTF, "render_shaded", TTF_render_shaded, 3);
rb_define_method(cTTF, "render_blended", TTF_render_blended, 2);
mStyle = rb_define_module_under(cTTF, "Style");
/* define(`DEFINE_TTF_STYLE_CONST',`rb_define_const(mStyle, "$1", INT2NUM((TTF_STYLE_$1)))') */
/* @return [Integer] integer representing normal style */
DEFINE_TTF_STYLE_CONST(NORMAL);
/* @return [Integer] integer representing bold style */
DEFINE_TTF_STYLE_CONST(BOLD);
/* @return [Integer] integer representing italic style */
DEFINE_TTF_STYLE_CONST(ITALIC);
/* @return [Integer] integer representing underline style */
DEFINE_TTF_STYLE_CONST(UNDERLINE);
/* @return [Integer] integer representing strikethrough style */
DEFINE_TTF_STYLE_CONST(STRIKETHROUGH);
mHinting = rb_define_module_under(cTTF, "Hinting");
/* define(`DEFINE_TTF_HINTING_CONST',`rb_define_const(mHinting, "$1", INT2NUM((TTF_HINTING_$1)))') */
/* @return [Integer] integer representing normal hinting, default */
DEFINE_TTF_HINTING_CONST(NORMAL);
/* @return [Integer] integer representing lighter hinting for non-monochrome modes */
DEFINE_TTF_HINTING_CONST(LIGHT);
/* @return [Integer] integer representing strong hinting, only used for monochrome output */
DEFINE_TTF_HINTING_CONST(MONO);
/* @return [Integer] integer representing no hinting */
DEFINE_TTF_HINTING_CONST(NONE);
}
#else /* HAVE_SDL_TTF_H */
void rubysdl2_init_ttf(void)
{
}
#endif /* HAVE_SDL_TTF_H */