[MacRuby-devel] Pointer to an array of structs?
John Labovitz
johnl at johnlabovitz.com
Wed Apr 24 11:19:13 PDT 2013
I just spent a couple of days on figuring out how to properly get a pointer to an array of C-structs. I finally figured it out, but it seems like more work than necessary, and I'm wondering what other folks think.
I'm using Harfbuzz, a C library, to do some OpenType text shaping & positioning -- that is, converting a Unicode string, plus a given font, to a sequence of glyphs with positions. In this specific code, I'm trying to convert an array of Ruby strings to 'features,' which are represented in Harfbuzz by the 'hb_feature_t' struct. The function hb_feature_from_string() handles the conversion, but needs a pointer to a pre-allocated 'hb_feature_t' struct. The set of features needs to be stored as an array of contiguous structs, which is then passed into the shaping function hb_shape().
Here are the definitions from the .h files:
typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
hb_feature_from_string (const char *str,
int len,
hb_feature_t *feature);
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
I've built a small framework with the Harfbuzz library and the BridgeSupport file that resulted from running gen_bridge_metadata on those .h files.
Here are excerpts from my current working MacRuby code.
feature_strings = %w{dlig kern}
features = feature_strings.map do |feature_string|
feature = Pointer.new('{hb_feature_t=IIII}')
hb_feature_from_string(feature_string, -1, feature)
feature.value
end
features_ptr = Pointer.new_with_type('^{hb_feature_t=IIII}')
features_ptr.assign(features)
@features = features_ptr.value
@num_features = features.length
# ...later on...
hb_shape_full(@font.hb_font, buffer, @features, @num_features)
In my first attempts, I tried to allocated a single Pointer object that would contain all the features, and then call hb_feature_from_string() with each element in turn, like this:
@features = Pointer.new('{hb_feature_t=IIII}', feature_strings.length)
feature_strings.each_with_index do |feature_string, i|
hb_feature_from_string(feature_string, -1, @features[i])
end
@num_features = feature_strings.length
The code ran, but the '@features' pointer remained in the initialized state -- that is, all the values were 0. I tried this in several different ways, and no matter what, the values were never set. This seems like a potential bug.
(It also seems odd to need to specify the exact members of the type -- the '=IIII' part -- but MacRuby complained mightily when I removed that part.)
Can some Pointer guru take a look at the above and give me a reality check? Is the way I'm doing it just the way it must be done? Or should the second method, with the single Pointer object, actually work?
Best,
--John
More information about the MacRuby-devel
mailing list