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
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
https://lists.macosforge.org/mailman/listinfo/macruby-devel

Reply via email to