fontconfig 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +21 -0
- data/ext/fontconfig/extconf.rb +6 -0
- data/ext/fontconfig/fc_config.c +357 -0
- data/ext/fontconfig/fc_fontset.c +111 -0
- data/ext/fontconfig/fc_objectset.c +87 -0
- data/ext/fontconfig/fc_pattern.c +202 -0
- data/ext/fontconfig/fontconfig.c +24 -0
- data/ext/fontconfig/rb_fontconfig.h +19 -0
- data/fontconfig.gemspec +24 -0
- data/lib/fontconfig/version.rb +3 -0
- data/lib/fontconfig.rb +32 -0
- data/spec/base_spec.rb +16 -0
- data/spec/config_spec.rb +39 -0
- data/spec/object_set_spec.rb +26 -0
- data/spec/pattern_spec.rb +51 -0
- data/spec/test_helper.rb +5 -0
- metadata +141 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Vasily Fedoseyev
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Fontconfig
|
2
|
+
|
3
|
+
Ruby bindings for fontconfig (http://fontconfig.org)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'fontconfig'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install fontconfig
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rake/extensiontask'
|
5
|
+
Rake::ExtensionTask.new('fontconfig')
|
6
|
+
|
7
|
+
require 'rake/testtask'
|
8
|
+
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.pattern = 'spec/**/*_spec.rb'
|
11
|
+
t.libs.push 'spec'
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
task :bundler do
|
16
|
+
require 'bundler/setup'
|
17
|
+
end
|
18
|
+
|
19
|
+
task :test => [:compile, :bundler]
|
20
|
+
|
21
|
+
task :default => :test
|
@@ -0,0 +1,357 @@
|
|
1
|
+
#include "rb_fontconfig.h"
|
2
|
+
|
3
|
+
VALUE rb_cFcConfig;
|
4
|
+
|
5
|
+
static size_t fc_config_memsize(const void *p) { return 0; }
|
6
|
+
static void fc_config_free(void* p){
|
7
|
+
if(p){
|
8
|
+
// FcConfigDestroy -- Destroy a configuration
|
9
|
+
FcConfigDestroy((FcConfig*)p);
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
static const rb_data_type_t Fc_Config_data_type = {
|
14
|
+
"FcConfig", 0, fc_config_free, fc_config_memsize,
|
15
|
+
};
|
16
|
+
|
17
|
+
static VALUE config_wrap(FcConfig* p){
|
18
|
+
return TypedData_Wrap_Struct(rb_cFcConfig, &Fc_Config_data_type, p);
|
19
|
+
}
|
20
|
+
|
21
|
+
int is_fc_config(VALUE val){
|
22
|
+
return rb_typeddata_is_kind_of(val, &Fc_Config_data_type);
|
23
|
+
}
|
24
|
+
|
25
|
+
#define CONFIG_UNWRAP(c) ((FcConfig*)RTYPEDDATA_DATA(c))
|
26
|
+
|
27
|
+
// FcConfigParseAndLoad -- load a configuration file
|
28
|
+
static VALUE rb_config_parse_and_load(int argc, VALUE *argv, VALUE self){
|
29
|
+
VALUE path, complain = Qnil;
|
30
|
+
rb_scan_args(argc, argv, "11", &path, &complain);
|
31
|
+
if(TYPE(path)!=T_STRING)
|
32
|
+
path = rb_any_to_s(path);
|
33
|
+
|
34
|
+
int res = FcConfigParseAndLoad(CONFIG_UNWRAP(self), RSTRING_PTR(path), RTEST(complain));
|
35
|
+
return BOOL2VAL(res);
|
36
|
+
}
|
37
|
+
|
38
|
+
// FcConfigCreate -- Create a configuration
|
39
|
+
static VALUE rb_config_new(int argc, VALUE *argv, VALUE klass){
|
40
|
+
FcConfig * conf = FcConfigCreate();
|
41
|
+
VALUE file;
|
42
|
+
rb_scan_args(argc, argv, "01", &file);
|
43
|
+
|
44
|
+
if(!conf){
|
45
|
+
rb_raise(rb_eRuntimeError, "Cannot create FcConfig");
|
46
|
+
}
|
47
|
+
VALUE self = config_wrap(conf);
|
48
|
+
if(RTEST(file)){
|
49
|
+
if(!rb_config_parse_and_load(1, &file, self) == Qfalse){
|
50
|
+
FcConfigDestroy(conf);
|
51
|
+
RTYPEDDATA_DATA(self) = 0;
|
52
|
+
rb_raise(rb_eRuntimeError, "Cannot load FcConfig");
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return self;
|
56
|
+
}
|
57
|
+
|
58
|
+
// FcConfigFilename -- Find a config file
|
59
|
+
static VALUE rb_config_filename(VALUE klass, VALUE filename){
|
60
|
+
// in FONTCONFIG_PATH
|
61
|
+
char* fname = 0;
|
62
|
+
if(RTEST(filename)){
|
63
|
+
if(TYPE(filename) != T_STRING)
|
64
|
+
filename = rb_any_to_s(filename);
|
65
|
+
fname = RSTRING_PTR(filename);
|
66
|
+
}
|
67
|
+
char* res = FcConfigFilename(fname);
|
68
|
+
if(!res){
|
69
|
+
rb_raise(rb_eRuntimeError, "cannot get config filename");
|
70
|
+
}
|
71
|
+
VALUE rb_res = rb_str_new2(res);
|
72
|
+
FcStrFree(res); //?
|
73
|
+
return rb_res;
|
74
|
+
}
|
75
|
+
|
76
|
+
// FcConfigGetCurrent -- Return current configuration
|
77
|
+
//// FcConfigReference -- Increment config reference count
|
78
|
+
static VALUE rb_config_get_current(VALUE klass){
|
79
|
+
FcConfig* conf = FcConfigGetCurrent();
|
80
|
+
if(!conf)
|
81
|
+
rb_raise(rb_eRuntimeError, "no current in FcConfigGetCurrent");
|
82
|
+
FcConfigReference(conf);
|
83
|
+
return config_wrap(conf);
|
84
|
+
}
|
85
|
+
|
86
|
+
// FcConfigSetCurrent -- Set configuration as default
|
87
|
+
static VALUE rb_config_set_current(VALUE self){
|
88
|
+
return BOOL2VAL(FcConfigSetCurrent(CONFIG_UNWRAP(self)));
|
89
|
+
}
|
90
|
+
|
91
|
+
// FcConfigUptoDate -- Check timestamps on config files
|
92
|
+
static VALUE rb_config_up_to_date_p(VALUE self){
|
93
|
+
return BOOL2VAL(FcConfigUptoDate(CONFIG_UNWRAP(self)));
|
94
|
+
}
|
95
|
+
|
96
|
+
// FcConfigHome -- return the current home directory.
|
97
|
+
static VALUE rb_config_home(VALUE klass){
|
98
|
+
char* home = FcConfigHome();
|
99
|
+
if(!home)
|
100
|
+
return Qnil;
|
101
|
+
return rb_str_new2(home);
|
102
|
+
}
|
103
|
+
|
104
|
+
// FcConfigEnableHome -- controls use of the home directory.
|
105
|
+
static VALUE rb_config_enable_home(int argc, VALUE *argv, VALUE klass){
|
106
|
+
VALUE enable;
|
107
|
+
if(rb_scan_args(argc, argv, "01", &enable) == 0){
|
108
|
+
enable = Qtrue;
|
109
|
+
}
|
110
|
+
return BOOL2VAL(FcConfigEnableHome(RTEST(enable)));
|
111
|
+
}
|
112
|
+
|
113
|
+
// FcConfigBuildFonts -- Build font database
|
114
|
+
static VALUE rb_config_build_fonts(VALUE self){
|
115
|
+
//TODO: set some flag?
|
116
|
+
//changes after this have undetermined effects
|
117
|
+
return BOOL2VAL(FcConfigBuildFonts(CONFIG_UNWRAP(self)));
|
118
|
+
}
|
119
|
+
|
120
|
+
VALUE FcStrList2Array(FcStrList* list){
|
121
|
+
VALUE res = rb_ary_new();
|
122
|
+
char* str;
|
123
|
+
while(str = FcStrListNext(list)){
|
124
|
+
rb_ary_push(res, rb_str_new2(str));
|
125
|
+
}
|
126
|
+
FcStrListDone(list);
|
127
|
+
return res;
|
128
|
+
}
|
129
|
+
|
130
|
+
// FcConfigGetConfigDirs -- Get config directories
|
131
|
+
static VALUE rb_config_get_config_dirs(VALUE self){
|
132
|
+
FcStrList * list = FcConfigGetConfigDirs(CONFIG_UNWRAP(self));
|
133
|
+
return FcStrList2Array(list);
|
134
|
+
}
|
135
|
+
|
136
|
+
// FcConfigGetFontDirs -- Get font directories
|
137
|
+
static VALUE rb_config_get_font_dirs(VALUE self){
|
138
|
+
FcStrList * list = FcConfigGetFontDirs(CONFIG_UNWRAP(self));
|
139
|
+
return FcStrList2Array(list);
|
140
|
+
}
|
141
|
+
|
142
|
+
// FcConfigGetConfigFiles -- Get config files
|
143
|
+
static VALUE rb_config_get_config_files(VALUE self){
|
144
|
+
FcStrList * list = FcConfigGetConfigFiles(CONFIG_UNWRAP(self));
|
145
|
+
return FcStrList2Array(list);
|
146
|
+
}
|
147
|
+
|
148
|
+
// FcConfigGetCacheDirs -- return the list of directories searched for cache files
|
149
|
+
static VALUE rb_config_get_cache_dirs(VALUE self){
|
150
|
+
FcStrList * list = FcConfigGetCacheDirs(CONFIG_UNWRAP(self));
|
151
|
+
return FcStrList2Array(list);
|
152
|
+
}
|
153
|
+
|
154
|
+
// FcConfigGetRescanInterval -- Get config rescan interval
|
155
|
+
static VALUE rb_config_get_rescan_interval(VALUE self){
|
156
|
+
return INT2FIX(FcConfigGetRescanInterval(CONFIG_UNWRAP(self)));
|
157
|
+
}
|
158
|
+
|
159
|
+
// FcConfigSetRescanInterval -- Set config rescan interval
|
160
|
+
static VALUE rb_config_set_rescan_interval(VALUE self, VALUE interval){
|
161
|
+
interval = rb_to_int(interval);
|
162
|
+
return INT2FIX(FcConfigSetRescanInterval(CONFIG_UNWRAP(self), NUM2INT(interval)));
|
163
|
+
}
|
164
|
+
|
165
|
+
// FcConfigGetSysRoot -- Obtain the system root directory
|
166
|
+
static VALUE rb_config_get_sys_root(VALUE self){
|
167
|
+
const char* res = FcConfigGetSysRoot(CONFIG_UNWRAP(self));
|
168
|
+
if(!res)
|
169
|
+
return Qnil;
|
170
|
+
return rb_str_new2(res);
|
171
|
+
}
|
172
|
+
|
173
|
+
// FcConfigSetSysRoot -- Set the system root directory
|
174
|
+
static VALUE rb_config_set_sys_root(VALUE self, VALUE root){
|
175
|
+
FcConfigSetSysRoot(CONFIG_UNWRAP(self), StringValuePtr(root));
|
176
|
+
return self;
|
177
|
+
}
|
178
|
+
|
179
|
+
// FcFontRenderPrepare -- Prepare pattern for loading font file
|
180
|
+
static VALUE rb_config_font_render_prepare(VALUE self, VALUE pat, VALUE font){
|
181
|
+
if(!is_fc_pattern(pat) || !is_fc_pattern(font)){
|
182
|
+
rb_raise(rb_eArgError, "arguments must be Fontconfig::Pattern");
|
183
|
+
}
|
184
|
+
FcPattern * res = FcFontRenderPrepare(CONFIG_UNWRAP(self), (FcPattern*)RTYPEDDATA_DATA(pat), (FcPattern*)RTYPEDDATA_DATA(font));
|
185
|
+
if(!res){
|
186
|
+
rb_raise(rb_eRuntimeError, "FcFontRenderPrepare returned NULL");
|
187
|
+
}
|
188
|
+
return pattern_wrap(res);
|
189
|
+
}
|
190
|
+
|
191
|
+
// FcConfigAppFontClear -- Remove all app fonts from font database
|
192
|
+
static VALUE rb_config_app_font_clear(VALUE self){
|
193
|
+
FcConfigAppFontClear(CONFIG_UNWRAP(self));
|
194
|
+
return self;
|
195
|
+
}
|
196
|
+
|
197
|
+
// FcConfigAppFontAddFile -- Add font file to font database
|
198
|
+
static VALUE rb_config_app_font_add_file(VALUE self, VALUE path){
|
199
|
+
return BOOL2VAL(FcConfigAppFontAddFile(CONFIG_UNWRAP(self), StringValuePtr(path)));
|
200
|
+
}
|
201
|
+
|
202
|
+
// FcConfigAppFontAddDir -- Add fonts from directory to font database
|
203
|
+
static VALUE rb_config_app_font_add_dir(VALUE self, VALUE path){
|
204
|
+
return BOOL2VAL(FcConfigAppFontAddDir(CONFIG_UNWRAP(self), StringValuePtr(path)));
|
205
|
+
}
|
206
|
+
|
207
|
+
|
208
|
+
// FcFontMatch -- Return best font
|
209
|
+
// This function should be called only after FcConfigSubstitute and FcDefaultSubstitute called on pattern
|
210
|
+
// TODO: check for this?
|
211
|
+
static VALUE rb_config_font_match(VALUE self, VALUE pattern){
|
212
|
+
if(!is_fc_pattern(pattern)){
|
213
|
+
rb_raise(rb_eArgError, "argument must be Fontconfig::Pattern");
|
214
|
+
}
|
215
|
+
FcResult res; // result of FcFontRenderPrepare for font and the provided pattern //???
|
216
|
+
FcPattern* match = FcFontMatch(CONFIG_UNWRAP(self), RTYPEDDATA_DATA(pattern), &res);
|
217
|
+
if(match){
|
218
|
+
return pattern_wrap(match);
|
219
|
+
}
|
220
|
+
return Qnil;
|
221
|
+
}
|
222
|
+
|
223
|
+
VALUE symPattern, symFont, symScan;
|
224
|
+
|
225
|
+
FcMatchKind sym2match_kind(VALUE match_kind){
|
226
|
+
if(match_kind == symPattern)
|
227
|
+
return FcMatchPattern;
|
228
|
+
else if(match_kind == symFont)
|
229
|
+
return FcMatchFont;
|
230
|
+
else if(match_kind == symScan)
|
231
|
+
return FcMatchScan;
|
232
|
+
else
|
233
|
+
rb_raise(rb_eArgError, "match_kind argument must be one of [:pattern, :font, :scan]");
|
234
|
+
return FcMatchPattern;
|
235
|
+
}
|
236
|
+
|
237
|
+
// FcConfigSubstitute -- Execute substitutions
|
238
|
+
static VALUE rb_config_substitute(int argc, VALUE *argv, VALUE self){
|
239
|
+
VALUE pattern, match_kind;
|
240
|
+
rb_scan_args(argc, argv, "11", &pattern, &match_kind);
|
241
|
+
|
242
|
+
if(!is_fc_pattern(pattern)){
|
243
|
+
rb_raise(rb_eArgError, "argument must be Fontconfig::Pattern");
|
244
|
+
}
|
245
|
+
FcMatchKind kind = FcMatchPattern; //TODO: default?
|
246
|
+
if(RTEST(match_kind))
|
247
|
+
kind = sym2match_kind(match_kind);
|
248
|
+
|
249
|
+
return BOOL2VAL(FcConfigSubstitute(CONFIG_UNWRAP(self), RTYPEDDATA_DATA(pattern), kind));
|
250
|
+
}
|
251
|
+
|
252
|
+
// FcConfigSubstituteWithPat -- Execute substitutions
|
253
|
+
static VALUE rb_config_substitute_with_pat(int argc, VALUE *argv, VALUE self){
|
254
|
+
VALUE pattern, pat, match_kind;
|
255
|
+
int n = rb_scan_args(argc, argv, "12", &pattern, &pat, &match_kind);
|
256
|
+
|
257
|
+
if(n == 2){
|
258
|
+
match_kind = pat;
|
259
|
+
pat = Qnil;
|
260
|
+
}
|
261
|
+
|
262
|
+
if(!is_fc_pattern(pattern)){
|
263
|
+
rb_raise(rb_eArgError, "argument must be Fontconfig::Pattern");
|
264
|
+
}
|
265
|
+
FcPattern* pat_pat = 0;
|
266
|
+
if(RTEST(pat)){
|
267
|
+
if(!is_fc_pattern(pat)){
|
268
|
+
rb_raise(rb_eArgError, "argument must be Fontconfig::Pattern");
|
269
|
+
}
|
270
|
+
pat_pat = RTYPEDDATA_DATA(pat);
|
271
|
+
}
|
272
|
+
FcMatchKind kind = FcMatchPattern; //TODO: default?
|
273
|
+
if(RTEST(match_kind))
|
274
|
+
kind = sym2match_kind(match_kind);
|
275
|
+
|
276
|
+
return BOOL2VAL(FcConfigSubstituteWithPat(CONFIG_UNWRAP(self), RTYPEDDATA_DATA(pattern), pat_pat, kind));
|
277
|
+
}
|
278
|
+
|
279
|
+
// FcFontList -- List fonts
|
280
|
+
static VALUE rb_config_font_list(int argc, VALUE *argv, VALUE self){
|
281
|
+
// FcPattern *p, FcObjectSet *os(optional)
|
282
|
+
VALUE pattern, object_set;
|
283
|
+
FcObjectSet* os = 0;
|
284
|
+
rb_scan_args(argc, argv, "11", &pattern, &object_set);
|
285
|
+
if(!is_fc_pattern(pattern)){
|
286
|
+
rb_raise(rb_eArgError, "argument must be Fontconfig::Pattern");
|
287
|
+
}
|
288
|
+
if(object_set){
|
289
|
+
if(is_FcObjectSet(object_set)){
|
290
|
+
os = RTYPEDDATA_DATA(object_set);
|
291
|
+
} else {
|
292
|
+
//TODO: convert array to os?
|
293
|
+
rb_raise(rb_eArgError, "os must be Fontconfig::ObjectSet");
|
294
|
+
}
|
295
|
+
}
|
296
|
+
FcFontSet* set = FcFontList(CONFIG_UNWRAP(self), RTYPEDDATA_DATA(pattern), os);
|
297
|
+
|
298
|
+
return self;
|
299
|
+
}
|
300
|
+
|
301
|
+
// FcConfigGetFonts -- Get config font set
|
302
|
+
static VALUE config_get_fonts(VALUE self, FcSetName set_name){
|
303
|
+
FcFontSet* set = FcConfigGetFonts(CONFIG_UNWRAP(self), set_name);
|
304
|
+
|
305
|
+
}
|
306
|
+
|
307
|
+
static VALUE rb_config_get_system_fonts(VALUE self){
|
308
|
+
return config_get_fonts(self, FcSetSystem);
|
309
|
+
}
|
310
|
+
|
311
|
+
static VALUE rb_config_get_application_fonts(VALUE self){
|
312
|
+
return config_get_fonts(self, FcSetApplication);
|
313
|
+
}
|
314
|
+
|
315
|
+
|
316
|
+
void Init_fontconfig_config(){
|
317
|
+
rb_cFcConfig = rb_define_class_under(rb_cFontconfig, "Config", rb_cObject);
|
318
|
+
rb_define_singleton_method(rb_cFcConfig, "new", rb_config_new, -1);
|
319
|
+
rb_define_method(rb_cFcConfig, "parse_and_load", rb_config_parse_and_load, -1);
|
320
|
+
rb_define_singleton_method(rb_cFcConfig, "filename", rb_config_filename, 1);
|
321
|
+
rb_define_singleton_method(rb_cFcConfig, "get_current", rb_config_get_current, 0);
|
322
|
+
rb_define_method(rb_cFcConfig, "set_current!", rb_config_set_current, 0);
|
323
|
+
rb_define_method(rb_cFcConfig, "up_to_date?", rb_config_up_to_date_p, 0);
|
324
|
+
rb_define_singleton_method(rb_cFcConfig, "home", rb_config_home, 0);
|
325
|
+
rb_define_singleton_method(rb_cFcConfig, "enable_home!", rb_config_enable_home, -1);
|
326
|
+
rb_define_method(rb_cFcConfig, "build_fonts!", rb_config_build_fonts, 0);
|
327
|
+
|
328
|
+
rb_define_method(rb_cFcConfig, "config_dirs", rb_config_get_config_dirs, 0);
|
329
|
+
rb_define_method(rb_cFcConfig, "font_dirs", rb_config_get_font_dirs, 0);
|
330
|
+
rb_define_method(rb_cFcConfig, "config_files", rb_config_get_config_files, 0);
|
331
|
+
rb_define_method(rb_cFcConfig, "cache_dirs", rb_config_get_cache_dirs, 0);
|
332
|
+
|
333
|
+
rb_define_method(rb_cFcConfig, "rescan_interval", rb_config_get_rescan_interval, 0);
|
334
|
+
rb_define_method(rb_cFcConfig, "rescan_interval=", rb_config_set_rescan_interval, 1);
|
335
|
+
rb_define_method(rb_cFcConfig, "sys_root", rb_config_get_sys_root, 0);
|
336
|
+
rb_define_method(rb_cFcConfig, "set_sys_root!", rb_config_set_sys_root, 1);
|
337
|
+
|
338
|
+
rb_define_method(rb_cFcConfig, "font_render_prepare", rb_config_font_render_prepare, 2);
|
339
|
+
|
340
|
+
rb_define_method(rb_cFcConfig, "app_font_clear!", rb_config_app_font_clear, 0);
|
341
|
+
rb_define_method(rb_cFcConfig, "app_font_add_file", rb_config_app_font_add_file, 1);
|
342
|
+
rb_define_method(rb_cFcConfig, "app_font_add_dir", rb_config_app_font_add_dir, 1);
|
343
|
+
|
344
|
+
rb_define_method(rb_cFcConfig, "font_match", rb_config_font_match, 1);
|
345
|
+
|
346
|
+
symPattern = ID2SYM(rb_intern("pattern"));
|
347
|
+
symFont = ID2SYM(rb_intern("font"));
|
348
|
+
symScan = ID2SYM(rb_intern("scan"));
|
349
|
+
rb_define_method(rb_cFcConfig, "substitute", rb_config_substitute, -1);
|
350
|
+
rb_define_method(rb_cFcConfig, "substitute_with_pat", rb_config_substitute_with_pat, -1);
|
351
|
+
|
352
|
+
|
353
|
+
// FcConfigGetBlanks -- Get config blanks
|
354
|
+
// FcFontSort -- Return list of matching fonts
|
355
|
+
|
356
|
+
// FcConfigGetCache -- DEPRECATED used to return per-user cache filename
|
357
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
#include "rb_fontconfig.h"
|
2
|
+
|
3
|
+
VALUE rb_cFcFontSet;
|
4
|
+
|
5
|
+
static size_t fc_object_set_memsize(const void *p) { return 0; }
|
6
|
+
static void fc_object_set_free(void* p){
|
7
|
+
if(p){
|
8
|
+
FcFontSetDestroy((FcFontSet*)p);
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
static const rb_data_type_t FcFontSet_data_type = {
|
13
|
+
"FcFontSet", 0, fc_object_set_free, fc_object_set_memsize,
|
14
|
+
};
|
15
|
+
|
16
|
+
VALUE font_set_wrap(FcFontSet* p){
|
17
|
+
return TypedData_Wrap_Struct(rb_cFcFontSet, &FcFontSet_data_type, p);
|
18
|
+
}
|
19
|
+
|
20
|
+
int is_FcFontSet(VALUE val){
|
21
|
+
return rb_typeddata_is_kind_of(val, &FcFontSet_data_type);
|
22
|
+
}
|
23
|
+
|
24
|
+
#define OSET_UNWRAP(c) ((FcFontSet*)RTYPEDDATA_DATA(c))
|
25
|
+
|
26
|
+
static VALUE rb_oset_add(VALUE self, VALUE val){
|
27
|
+
if(!is_fc_pattern(val)){
|
28
|
+
rb_raise(rb_eArgError, "argument must be a FcPattern");
|
29
|
+
}
|
30
|
+
if(!FcFontSetAdd(OSET_UNWRAP(self), pattern_unwrap(val))){
|
31
|
+
rb_raise(rb_eRuntimeError, "cannot insert into FcFontSet");
|
32
|
+
}
|
33
|
+
return val;
|
34
|
+
}
|
35
|
+
|
36
|
+
static VALUE oset_add_i(VALUE str, VALUE self, int argc, VALUE *argv){
|
37
|
+
return rb_oset_add(self, str);
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE rb_oset_new(int argc, VALUE *argv, VALUE klass){
|
41
|
+
VALUE optional = Qnil;
|
42
|
+
rb_scan_args(argc, argv, "01", &optional);
|
43
|
+
FcFontSet* set = FcFontSetCreate();
|
44
|
+
if(!set)
|
45
|
+
rb_raise(rb_eRuntimeError, "cannot create FcFontSet");
|
46
|
+
|
47
|
+
VALUE self = object_set_wrap(set);
|
48
|
+
if(optional != Qnil){
|
49
|
+
ID each = rb_intern("each");
|
50
|
+
if(!rb_respond_to(optional, each))
|
51
|
+
rb_raise(rb_eArgError, "parameter must be enumerable");
|
52
|
+
rb_block_call(optional, each, 0, 0, oset_add_i, self);
|
53
|
+
}
|
54
|
+
return self;
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
static VALUE rb_oset_each(VALUE self){
|
59
|
+
int i;
|
60
|
+
FcFontSet* os = OSET_UNWRAP(self);
|
61
|
+
for (i = 0; i < os->nfont; i++){
|
62
|
+
rb_yield(pattern_wrap(os->fonts[i]));
|
63
|
+
}
|
64
|
+
return self;
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE rb_oset_size(VALUE self){
|
68
|
+
return INT2NUM(OSET_UNWRAP(self)->nfont);
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE rb_oset_at(VALUE self, VALUE index){
|
72
|
+
|
73
|
+
int i = NUM2INT(index);
|
74
|
+
FcFontSet* os = OSET_UNWRAP(self);
|
75
|
+
|
76
|
+
if(i < 0 || i >= os->nfont)
|
77
|
+
return Qnil;
|
78
|
+
return pattern_wrap(os->fonts[i]);
|
79
|
+
}
|
80
|
+
|
81
|
+
static VALUE rb_oset_print(VALUE self){
|
82
|
+
FcFontSetPrint(OSET_UNWRAP(self));
|
83
|
+
return self;
|
84
|
+
}
|
85
|
+
|
86
|
+
static VALUE rb_oset_match(VALUE self, VALUE config, VALUE pattern){
|
87
|
+
FcFontSet* set = OSET_UNWRAP(self);
|
88
|
+
FcConfig* conf = 0;
|
89
|
+
if(RTEST(config) && is_fc_config(config))
|
90
|
+
conf = CONFIG_UNWRAP(config);
|
91
|
+
if(!RTEST(pattern) || !is_fc_pattern(pattern))
|
92
|
+
rb_raise(rb_eArgError, "pattern must be Fontconfig::Pattern");
|
93
|
+
FcResult res;
|
94
|
+
FcPattern* result = FcFontSetMatch(conf, &set, 1, pattern_unwrap(pattern), &res);
|
95
|
+
if(!result)
|
96
|
+
return Qnil;
|
97
|
+
return pattern_wrap(result);
|
98
|
+
}
|
99
|
+
|
100
|
+
void Init_fontconfig_fontset(){
|
101
|
+
rb_cFcFontSet = rb_define_class_under(rb_cFontconfig, "FontSet", rb_cObject);
|
102
|
+
rb_define_singleton_method(rb_cFcFontSet, "new", rb_oset_new, -1);
|
103
|
+
rb_define_method(rb_cFcFontSet, "add", rb_oset_add, 1);
|
104
|
+
rb_define_method(rb_cFcFontSet, "<<", rb_oset_add, 1);
|
105
|
+
rb_define_method(rb_cFcFontSet, "each", rb_oset_each, 0);
|
106
|
+
rb_define_method(rb_cFcFontSet, "size", rb_oset_size, 0);
|
107
|
+
rb_define_method(rb_cFcFontSet, "[]", rb_oset_at, 1);
|
108
|
+
rb_define_method(rb_cFcFontSet, "debug_print", rb_oset_print, 0);
|
109
|
+
rb_define_method(rb_cFcFontSet, "match_pattern", rb_oset_match, 1);
|
110
|
+
rb_include_module(rb_cFcFontSet, rb_mEnumerable);
|
111
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#include "rb_fontconfig.h"
|
2
|
+
|
3
|
+
VALUE rb_cFcObjectSet;
|
4
|
+
|
5
|
+
static size_t fc_object_set_memsize(const void *p) { return 0; }
|
6
|
+
static void fc_object_set_free(void* p){
|
7
|
+
if(p){
|
8
|
+
FcObjectSetDestroy((FcObjectSet*)p);
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
static const rb_data_type_t FcObjectSet_data_type = {
|
13
|
+
"FcObjectSet", 0, fc_object_set_free, fc_object_set_memsize,
|
14
|
+
};
|
15
|
+
|
16
|
+
static VALUE object_set_wrap(FcObjectSet* p){
|
17
|
+
return TypedData_Wrap_Struct(rb_cFcObjectSet, &FcObjectSet_data_type, p);
|
18
|
+
}
|
19
|
+
|
20
|
+
int is_FcObjectSet(VALUE val){
|
21
|
+
return rb_typeddata_is_kind_of(val, &FcObjectSet_data_type);
|
22
|
+
}
|
23
|
+
|
24
|
+
#define OSET_UNWRAP(c) ((FcObjectSet*)RTYPEDDATA_DATA(c))
|
25
|
+
|
26
|
+
static VALUE rb_oset_add(VALUE self, VALUE str){
|
27
|
+
if(!FcObjectSetAdd(OSET_UNWRAP(self), StringValuePtr(str))){
|
28
|
+
rb_raise(rb_eRuntimeError, "cannot insert into FcObjectSet");
|
29
|
+
}
|
30
|
+
return str;
|
31
|
+
}
|
32
|
+
|
33
|
+
static VALUE oset_add_i(VALUE str, VALUE self, int argc, VALUE *argv){
|
34
|
+
return rb_oset_add(self, str);
|
35
|
+
}
|
36
|
+
|
37
|
+
static VALUE rb_oset_new(int argc, VALUE *argv, VALUE klass){
|
38
|
+
VALUE optional = Qnil;
|
39
|
+
rb_scan_args(argc, argv, "01", &optional);
|
40
|
+
FcObjectSet* set = FcObjectSetCreate();
|
41
|
+
if(!set)
|
42
|
+
rb_raise(rb_eRuntimeError, "cannot create FcObjectSet");
|
43
|
+
|
44
|
+
VALUE self = object_set_wrap(set);
|
45
|
+
if(optional != Qnil){
|
46
|
+
ID each = rb_intern("each");
|
47
|
+
if(!rb_respond_to(optional, each))
|
48
|
+
rb_raise(rb_eArgError, "parameter must be enumerable");
|
49
|
+
rb_block_call(optional, each, 0, 0, oset_add_i, self);
|
50
|
+
}
|
51
|
+
return self;
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
static VALUE rb_oset_each(VALUE self){
|
56
|
+
int i;
|
57
|
+
FcObjectSet* os = OSET_UNWRAP(self);
|
58
|
+
for (i = 0; i < os->nobject; i++){
|
59
|
+
rb_yield(rb_str_new2(os->objects[i]));
|
60
|
+
}
|
61
|
+
return self;
|
62
|
+
}
|
63
|
+
|
64
|
+
static VALUE rb_oset_size(VALUE self){
|
65
|
+
return INT2NUM(OSET_UNWRAP(self)->nobject);
|
66
|
+
}
|
67
|
+
|
68
|
+
static VALUE rb_oset_at(VALUE self, VALUE index){
|
69
|
+
|
70
|
+
int i = NUM2INT(index);
|
71
|
+
FcObjectSet* os = OSET_UNWRAP(self);
|
72
|
+
|
73
|
+
if(i < 0 || i >= os->nobject)
|
74
|
+
return Qnil;
|
75
|
+
return rb_str_new2(os->objects[i]);
|
76
|
+
}
|
77
|
+
|
78
|
+
void Init_fontconfig_objectset(){
|
79
|
+
rb_cFcObjectSet = rb_define_class_under(rb_cFontconfig, "ObjectSet", rb_cObject);
|
80
|
+
rb_define_singleton_method(rb_cFcObjectSet, "new", rb_oset_new, -1);
|
81
|
+
rb_define_method(rb_cFcObjectSet, "add", rb_oset_add, 1);
|
82
|
+
rb_define_method(rb_cFcObjectSet, "<<", rb_oset_add, 1);
|
83
|
+
rb_define_method(rb_cFcObjectSet, "each", rb_oset_each, 0);
|
84
|
+
rb_define_method(rb_cFcObjectSet, "size", rb_oset_size, 0);
|
85
|
+
rb_define_method(rb_cFcObjectSet, "[]", rb_oset_at, 1);
|
86
|
+
rb_include_module(rb_cFcObjectSet, rb_mEnumerable);
|
87
|
+
}
|
@@ -0,0 +1,202 @@
|
|
1
|
+
#include "rb_fontconfig.h"
|
2
|
+
#include <fontconfig/fontconfig.h>
|
3
|
+
|
4
|
+
VALUE rb_cFcPattern;
|
5
|
+
|
6
|
+
static size_t fc_pattern_memsize(const void *p) { return 0; }
|
7
|
+
static void fc_pattern_free(void* p){
|
8
|
+
if(p){
|
9
|
+
FcPatternDestroy((FcPattern*)p);
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
static const rb_data_type_t Fc_Pattern_data_type = {
|
14
|
+
"FcPattern", 0, fc_pattern_free, fc_pattern_memsize,
|
15
|
+
};
|
16
|
+
|
17
|
+
VALUE pattern_wrap(FcPattern* p){
|
18
|
+
return TypedData_Wrap_Struct(rb_cFcPattern, &Fc_Pattern_data_type, p);
|
19
|
+
}
|
20
|
+
|
21
|
+
int is_fc_pattern(VALUE val){
|
22
|
+
return rb_typeddata_is_kind_of(val, &Fc_Pattern_data_type);
|
23
|
+
}
|
24
|
+
|
25
|
+
#define PATTERN_UNWRAP(c) ((FcPattern*)RTYPEDDATA_DATA(c))
|
26
|
+
|
27
|
+
|
28
|
+
static VALUE rb_pattern_parse(VALUE klass, VALUE string){
|
29
|
+
if(TYPE(string) != T_STRING)
|
30
|
+
string = rb_any_to_s(string);
|
31
|
+
FcPattern* p = FcNameParse(RSTRING_PTR(string));
|
32
|
+
return pattern_wrap(p);
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE rb_pattern_new(int argc, VALUE *argv, VALUE klass){
|
36
|
+
VALUE optional = Qnil;
|
37
|
+
rb_scan_args(argc, argv, "01", &optional);
|
38
|
+
if(optional != Qnil){
|
39
|
+
if(TYPE(optional) == T_STRING)
|
40
|
+
return rb_pattern_parse(klass, optional);
|
41
|
+
|
42
|
+
rb_raise(rb_eArgError, "parameter must be a string");
|
43
|
+
} else {
|
44
|
+
return pattern_wrap(FcPatternCreate());
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE rb_pattern_format(VALUE self, VALUE format){
|
49
|
+
if(TYPE(format) != T_STRING)
|
50
|
+
format = rb_any_to_s(format);
|
51
|
+
char* res = FcPatternFormat(PATTERN_UNWRAP(self), RSTRING_PTR(format));
|
52
|
+
VALUE str = rb_str_new2((char*)res);
|
53
|
+
FcStrFree(res);
|
54
|
+
return str;
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE rb_pattern_to_s(VALUE self){
|
58
|
+
char* res = FcNameUnparse(PATTERN_UNWRAP(self));
|
59
|
+
VALUE str = rb_str_new2((char*)res);
|
60
|
+
FcStrFree(res);
|
61
|
+
return str;
|
62
|
+
}
|
63
|
+
|
64
|
+
static VALUE rb_pattern_duplicate(VALUE self){
|
65
|
+
FcPattern* p = FcPatternDuplicate(PATTERN_UNWRAP(self));
|
66
|
+
return pattern_wrap(p);
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE rb_pattern_debugprint(VALUE self){
|
70
|
+
FcPatternPrint(PATTERN_UNWRAP(self));
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE rb_pattern_equal(VALUE self, VALUE other){
|
75
|
+
if(!is_fc_pattern(other)){
|
76
|
+
//TODO: cast?
|
77
|
+
return Qfalse;
|
78
|
+
}
|
79
|
+
return FcPatternEqual(PATTERN_UNWRAP(self), PATTERN_UNWRAP(other)) ? Qtrue : Qfalse;
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE rb_pattern_hash(VALUE self){
|
83
|
+
int res = FcPatternHash(PATTERN_UNWRAP(self));
|
84
|
+
return INT2NUM(res);
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE rb_pattern_add(int argc, VALUE *argv, VALUE self){
|
88
|
+
VALUE object, value, append;
|
89
|
+
rb_scan_args(argc, argv, "21", &object, &value, &append);
|
90
|
+
FcValue val;
|
91
|
+
switch(TYPE(value)){
|
92
|
+
case T_NONE: case T_NIL: val.type = FcTypeVoid; break;
|
93
|
+
case T_FIXNUM: val.type = FcTypeInteger; val.u.i = NUM2INT(value); break;
|
94
|
+
case T_FLOAT: val.type = FcTypeDouble; val.u.d = NUM2DBL(value); break;
|
95
|
+
case T_STRING: val.type = FcTypeString; val.u.s = RSTRING_PTR(value); break;
|
96
|
+
case T_TRUE: val.type = FcTypeBool; val.u.b = 1; break;
|
97
|
+
case T_FALSE: val.type = FcTypeBool; val.u.b = 0; break;
|
98
|
+
case T_OBJECT:
|
99
|
+
//TODO: increment object references?
|
100
|
+
// ...
|
101
|
+
// FcTypeMatrix: // m FcMatrix *
|
102
|
+
// FcTypeCharSet: // c FcCharSet *
|
103
|
+
// FcTypeFTFace: // f void * (FT_Face)
|
104
|
+
// FcTypeLangSet
|
105
|
+
default:
|
106
|
+
rb_raise(rb_eArgError, "unsupported type for value");
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
if(TYPE(object)!=T_STRING)
|
110
|
+
object = rb_any_to_s(object);
|
111
|
+
int res = FcPatternAdd(PATTERN_UNWRAP(self), RSTRING_PTR(object), val, RTEST(append));
|
112
|
+
//TODO: raise on errors?
|
113
|
+
return res? Qtrue : Qfalse;
|
114
|
+
}
|
115
|
+
|
116
|
+
static VALUE fc_value_to_value(FcValue* val){
|
117
|
+
//FcTypeString, FcTypeMatrix and FcTypeCharSet reference memory, need FcValueDestroy or so
|
118
|
+
switch(val->type){
|
119
|
+
case FcTypeVoid: return Qnil;
|
120
|
+
case FcTypeInteger: return INT2FIX(val->u.i);
|
121
|
+
case FcTypeDouble: return rb_float_new(val->u.d);
|
122
|
+
case FcTypeString: return rb_str_new2(val->u.s);
|
123
|
+
case FcTypeBool: return val->u.b? Qtrue : Qfalse;
|
124
|
+
case FcTypeMatrix: // m FcMatrix *
|
125
|
+
case FcTypeCharSet: // c FcCharSet *
|
126
|
+
case FcTypeFTFace: // f void * (FT_Face)
|
127
|
+
case FcTypeLangSet: // l FcLangSet * l
|
128
|
+
//TODO
|
129
|
+
// note: data is not copied, we have a pointer to internal structure
|
130
|
+
return Qnil;
|
131
|
+
default:
|
132
|
+
rb_raise(rb_eRuntimeError, "got unknown FcValue type %d", val->type);
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
return Qnil;
|
136
|
+
}
|
137
|
+
|
138
|
+
static VALUE rb_pattern_get(VALUE self, VALUE object, VALUE id){
|
139
|
+
Check_Type(id, T_FIXNUM);
|
140
|
+
if(TYPE(object)!=T_STRING)
|
141
|
+
object = rb_any_to_s(object);
|
142
|
+
FcValue val;
|
143
|
+
FcResult res = FcPatternGet(PATTERN_UNWRAP(self), RSTRING_PTR(object), FIX2INT(id), &val);
|
144
|
+
if(res == FcResultMatch){
|
145
|
+
VALUE r_res = fc_value_to_value(&val);
|
146
|
+
// FcValueDestroy(val); // gives malloc error
|
147
|
+
return r_res;
|
148
|
+
}
|
149
|
+
if(res == FcResultNoMatch || res == FcResultNoId){
|
150
|
+
//raise?
|
151
|
+
return Qnil;
|
152
|
+
}
|
153
|
+
if(res == FcResultOutOfMemory){
|
154
|
+
rb_raise(rb_eRuntimeError, "FcResultOutOfMemory");
|
155
|
+
}
|
156
|
+
//FcResultTypeMismatch cannot be here
|
157
|
+
return Qnil;
|
158
|
+
}
|
159
|
+
|
160
|
+
static VALUE rb_pattern_delete(VALUE self, VALUE object){
|
161
|
+
if(TYPE(object)!=T_STRING)
|
162
|
+
object = rb_any_to_s(object);
|
163
|
+
int res = FcPatternDel(PATTERN_UNWRAP(self), RSTRING_PTR(object));
|
164
|
+
return res? Qtrue : Qfalse;
|
165
|
+
}
|
166
|
+
|
167
|
+
static VALUE rb_pattern_remove(VALUE self, VALUE object, VALUE id){
|
168
|
+
Check_Type(id, T_FIXNUM);
|
169
|
+
if(TYPE(object)!=T_STRING)
|
170
|
+
object = rb_any_to_s(object);
|
171
|
+
int res = FcPatternRemove(PATTERN_UNWRAP(self), RSTRING_PTR(object), FIX2INT(id));
|
172
|
+
return res? Qtrue : Qfalse;
|
173
|
+
}
|
174
|
+
|
175
|
+
rb_pattern_default_substitute(VALUE self){
|
176
|
+
FcDefaultSubstitute(PATTERN_UNWRAP(self));
|
177
|
+
return self;
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
void Init_fontconfig_pattern(){
|
182
|
+
rb_cFcPattern = rb_define_class_under(rb_cFontconfig, "Pattern", rb_cObject);
|
183
|
+
rb_define_singleton_method(rb_cFcPattern, "new", rb_pattern_new, -1);
|
184
|
+
rb_define_singleton_method(rb_cFcPattern, "parse", rb_pattern_parse, 1);
|
185
|
+
rb_define_method(rb_cFcPattern, "dup", rb_pattern_duplicate, 0);
|
186
|
+
|
187
|
+
rb_define_method(rb_cFcPattern, "==", rb_pattern_equal, 1);
|
188
|
+
// rb_define_method(rb_cFcPattern, "equal_subset", rb_pattern_equal, 1);
|
189
|
+
// filter - need set
|
190
|
+
rb_define_method(rb_cFcPattern, "add", rb_pattern_add, -1);
|
191
|
+
rb_define_method(rb_cFcPattern, "get", rb_pattern_get, 2);
|
192
|
+
rb_define_method(rb_cFcPattern, "delete", rb_pattern_delete, 1);
|
193
|
+
rb_define_method(rb_cFcPattern, "remove", rb_pattern_remove, 2);
|
194
|
+
|
195
|
+
rb_define_method(rb_cFcPattern, "hash", rb_pattern_hash, 0);
|
196
|
+
rb_define_method(rb_cFcPattern, "to_s", rb_pattern_to_s, 0);
|
197
|
+
rb_define_method(rb_cFcPattern, "unparse", rb_pattern_to_s, 0);
|
198
|
+
rb_define_method(rb_cFcPattern, "format", rb_pattern_format, 1);
|
199
|
+
rb_define_method(rb_cFcPattern, "debug_print", rb_pattern_debugprint, 0);
|
200
|
+
rb_define_method(rb_cFcPattern, "default_substitute!", rb_pattern_default_substitute, 0);
|
201
|
+
|
202
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#include "rb_fontconfig.h"
|
2
|
+
#include <fontconfig/fontconfig.h>
|
3
|
+
|
4
|
+
VALUE rb_cFontconfig;
|
5
|
+
|
6
|
+
static VALUE rb_fc_version(VALUE self){
|
7
|
+
int version = FcGetVersion();
|
8
|
+
return INT2FIX(version);
|
9
|
+
}
|
10
|
+
|
11
|
+
|
12
|
+
void Init_fontconfig_pattern();
|
13
|
+
void Init_fontconfig_objectset();
|
14
|
+
void Init_fontconfig_fontset();
|
15
|
+
void Init_fontconfig_config();
|
16
|
+
|
17
|
+
void Init_fontconfig(){
|
18
|
+
rb_cFontconfig = rb_define_module("Fontconfig");
|
19
|
+
rb_define_singleton_method(rb_cFontconfig, "library_version", rb_fc_version, 0);
|
20
|
+
Init_fontconfig_pattern();
|
21
|
+
Init_fontconfig_objectset();
|
22
|
+
Init_fontconfig_fontset();
|
23
|
+
Init_fontconfig_config();
|
24
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <fontconfig/fontconfig.h>
|
3
|
+
|
4
|
+
extern VALUE rb_cFontconfig;
|
5
|
+
|
6
|
+
|
7
|
+
#define BOOL2VAL(p) ((p) ? Qtrue : Qfalse)
|
8
|
+
|
9
|
+
int is_fc_pattern(VALUE val);
|
10
|
+
VALUE pattern_wrap(FcPattern* p);
|
11
|
+
#define pattern_unwrap(c) ((FcPattern*)RTYPEDDATA_DATA(c))
|
12
|
+
|
13
|
+
int is_FcObjectSet(VALUE val);
|
14
|
+
|
15
|
+
VALUE font_set_wrap(FcFontSet* p);
|
16
|
+
int is_FcFontSet(VALUE val);
|
17
|
+
|
18
|
+
int is_fc_config(VALUE val);
|
19
|
+
#define CONFIG_UNWRAP(c) ((FcConfig*)RTYPEDDATA_DATA(c))
|
data/fontconfig.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/fontconfig/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Vasily Fedoseyev"]
|
6
|
+
gem.email = ["vasilyfedoseyev@gmail.com"]
|
7
|
+
gem.description = %q{}
|
8
|
+
gem.summary = %q{Ruby bindings for fontconfig library}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "fontconfig"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Fontconfig::VERSION
|
17
|
+
|
18
|
+
gem.extensions = "ext/fontconfig/extconf.rb"
|
19
|
+
|
20
|
+
gem.add_dependency "pkg-config"
|
21
|
+
gem.add_development_dependency "rake-compiler"
|
22
|
+
gem.add_development_dependency "minitest"
|
23
|
+
gem.add_development_dependency "minitest-reporters"
|
24
|
+
end
|
data/lib/fontconfig.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "fontconfig/version"
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
require "fontconfig.#{RbConfig::CONFIG['DLEXT']}"
|
5
|
+
|
6
|
+
module Fontconfig
|
7
|
+
class Pattern
|
8
|
+
|
9
|
+
class Proxy
|
10
|
+
def initialize pattern, key
|
11
|
+
@pattern = pattern
|
12
|
+
@key = key
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](num)
|
16
|
+
@pattern.get(@key, num)
|
17
|
+
end
|
18
|
+
|
19
|
+
def <<(obj)
|
20
|
+
@pattern.add(@key, obj, true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete!
|
24
|
+
@pattern.delete(@key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
return Proxy.new(self, key)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
describe Fontconfig do
|
5
|
+
subject { Fontconfig }
|
6
|
+
|
7
|
+
it "should be" do
|
8
|
+
subject.wont_be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "version" do
|
12
|
+
# puts "Lib version #{subject.library_version}"
|
13
|
+
subject.library_version.must_be :>, 0
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
describe Fontconfig::Config do
|
5
|
+
describe "class methods" do
|
6
|
+
subject { Fontconfig::Config }
|
7
|
+
describe "new" do
|
8
|
+
it "works" do
|
9
|
+
subject.new.must_be_instance_of subject
|
10
|
+
end
|
11
|
+
|
12
|
+
it "loads config" do
|
13
|
+
skip
|
14
|
+
subject.new "some_config_file"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises if cannot load" do
|
18
|
+
assert_raises(RuntimeError){
|
19
|
+
subject.new "some_config_file"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "filename" do
|
25
|
+
res = subject.filename('')
|
26
|
+
puts "res is #{res}"
|
27
|
+
res.must_be_instance_of String
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
subject { Fontconfig::Config.new }
|
32
|
+
|
33
|
+
|
34
|
+
it "config_dirs" do
|
35
|
+
r = subject.config_dirs
|
36
|
+
puts "config_dirs is '#{r}'"
|
37
|
+
r.must_be_instance_of Array
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
describe Fontconfig::ObjectSet do
|
5
|
+
describe "class methods" do
|
6
|
+
subject { Fontconfig::ObjectSet }
|
7
|
+
describe "new" do
|
8
|
+
it "works" do
|
9
|
+
subject.new.must_be_instance_of subject
|
10
|
+
end
|
11
|
+
|
12
|
+
it "init by array of strings" do
|
13
|
+
arr = %w{str1 str2 str3}.sort
|
14
|
+
(s = subject.new(arr)).must_be_instance_of subject
|
15
|
+
s.to_a.sort.must_equal arr
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { Fontconfig::ObjectSet.new }
|
21
|
+
|
22
|
+
it "add" do
|
23
|
+
subject << "str"
|
24
|
+
subject.to_a.must_equal ["str"]
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
describe Fontconfig::Pattern do
|
5
|
+
|
6
|
+
describe "class methods" do
|
7
|
+
subject { Fontconfig::Pattern }
|
8
|
+
|
9
|
+
it "create by parsing" do
|
10
|
+
res = subject.parse("Monospace Bold 12px")
|
11
|
+
res.must_be_instance_of subject
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "instance" do
|
17
|
+
subject { Fontconfig::Pattern.parse("monospace-Bold-Italic 21") }
|
18
|
+
|
19
|
+
it "to_s" do
|
20
|
+
res = subject.to_s
|
21
|
+
res.must_be_kind_of String
|
22
|
+
end
|
23
|
+
|
24
|
+
it "format" do
|
25
|
+
res = subject.format("%{family}")
|
26
|
+
# subject.debug_print
|
27
|
+
# puts "format #{res}"
|
28
|
+
res.must_be_kind_of String
|
29
|
+
end
|
30
|
+
|
31
|
+
it "hash" do
|
32
|
+
subject.hash.must_be_kind_of Fixnum
|
33
|
+
end
|
34
|
+
|
35
|
+
it "set/det/delete" do
|
36
|
+
subject.add("key", "value")
|
37
|
+
subject.add("key", "value2", true)
|
38
|
+
subject.get("key", 0).must_equal "value"
|
39
|
+
subject.get("key", 1).must_equal "value2"
|
40
|
+
subject.delete("key")
|
41
|
+
subject.get("key", 0).must_be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "default_substitute!" do
|
45
|
+
subject.default_substitute!
|
46
|
+
subject["familylang"][0].must_equal "en"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/spec/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fontconfig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Vasily Fedoseyev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pkg-config
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake-compiler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: minitest
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest-reporters
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: ''
|
79
|
+
email:
|
80
|
+
- vasilyfedoseyev@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions:
|
83
|
+
- ext/fontconfig/extconf.rb
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- ext/fontconfig/extconf.rb
|
92
|
+
- ext/fontconfig/fc_config.c
|
93
|
+
- ext/fontconfig/fc_fontset.c
|
94
|
+
- ext/fontconfig/fc_objectset.c
|
95
|
+
- ext/fontconfig/fc_pattern.c
|
96
|
+
- ext/fontconfig/fontconfig.c
|
97
|
+
- ext/fontconfig/rb_fontconfig.h
|
98
|
+
- fontconfig.gemspec
|
99
|
+
- lib/fontconfig.rb
|
100
|
+
- lib/fontconfig/version.rb
|
101
|
+
- spec/base_spec.rb
|
102
|
+
- spec/config_spec.rb
|
103
|
+
- spec/object_set_spec.rb
|
104
|
+
- spec/pattern_spec.rb
|
105
|
+
- spec/test_helper.rb
|
106
|
+
homepage: ''
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
segments:
|
119
|
+
- 0
|
120
|
+
hash: -3843724065432744597
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
hash: -3843724065432744597
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 1.8.24
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: Ruby bindings for fontconfig library
|
136
|
+
test_files:
|
137
|
+
- spec/base_spec.rb
|
138
|
+
- spec/config_spec.rb
|
139
|
+
- spec/object_set_spec.rb
|
140
|
+
- spec/pattern_spec.rb
|
141
|
+
- spec/test_helper.rb
|