https://www.cairographics.org/manual/cairo-cairo-scaled-font-t.html#cairo-text-extents-t
I spent hours staring at examples that make no sense and this is the best I can come up with.
https://www.cairographics.org/manual/cairo-cairo-scaled-font-t.html#cairo-text-extents-t
I spent hours staring at examples that make no sense and this is the best I can come up with.
What you have looks pretty close. The only real issue is that the first argument to field
should be the structure type, so instead of this:
let x_bearing = field x_bearing "x_bearing" double
you should have
let x_bearing = field cairo_text_extents_t "x_bearing" double
You can read this as: “add to the structure type cairo_text_extents_t
a field with the name "cairo_text_extents_t"
and type double
”.
In more detail, since Cairo documentation defines the type as follows
struct cairo_text_extents_t {
double xBearing;
double yBearing;
double width;
double height;
double xAdvance;
double yAdvance;
};
the corresponding ctypes definition should look like this:
type cairo_text_extents_t
let cairo_text_extents_t : cairo_text_extents_t structure typ =
structure "cairo_text_extents_t"
let xBearing = field cairo_text_extents_t "xBearing" double
let yBearing = field cairo_text_extents_t "yBearing" double
let width = field cairo_text_extents_t "width" double
let height = field cairo_text_extents_t "height" double
let xAdvance = field cairo_text_extents_t "xAdvance" double
let yAdvance = field cairo_text_extents_t "yAdvance" double
let () = seal cairo_text_extents_t (* tell ctypes that there are no more fields to come *)
I made progress with your advice. Thank you!
Now, how hard it would be to show me how to access the elements of the structure so that I can center the text?
I think you’ll usually be dealing with pointers to cairo_text_extents_t
objects, so there are three ctypes functions that you’ll need:
val ( |-> ) : 'b structure ptr -> ('a, 'b structure) field -> 'a ptr
The |->
operator (documentation here) takes a pointer to a struct along with a field name and returns a pointer to the field.
For example, if you have a value p
of type cairo_text_extents_t structure ptr
then p |-> xBearing
is a pointer to the xBearing
field of p
. (The |->
operator returns a pointer to the field rather than just returning the field directly so that you can both read and write through it.)
val ( !@ ) : 'a ptr -> 'a
The !@
operator (documentation here) reads a value from a pointer.
val ( <-@ ) : 'a ptr -> 'a -> unit
The <-@
operator (documentation here) writes a value through a pointer.
Putting these three together, if you have a value p
of type cairo_text_extents_t structure ptr
then you can read and write the values of the fields of the structure like this:
(p |-> xBearing) <-@ 3.0; (* write to the value of p's xBearing field *)
let v = !@(p |-> xBearing) (* read the value from p's xBearing field *)
Thank you for trying to help, but I do not understand your help at all.
What’s the first thing in my reply that you don’t understand?
[I edited your post to delete the off-topic song.]
I do not understand anything.
I am not able to read the values to center the text.
The only way to move ahead is if someone said verbatim how to correct the code fragment.
Could you post the code fragment that you’re having trouble with?
I try to get the width and height of the text from text extents, but OCaml errors make no sense to me.
I agree that the error messages that OCaml gives for your code are difficult to understand. What you have is actually pretty close to working, though.
You currently have this binding to cairo_text_extents
:
let text_extents =
foreign "cairo_text_extents"
(gpointer @-> string @-> returning cairo_text_extents_t)
which says that cairo_text_extents
takes two arguments and returns a cairo_text_extents_t
value.
However, according to the Cairo documentation, that’s not quite right. Here’s the C signature for the function
void cairo_text_extents (cairo_t *cr, const char *utf8, cairo_text_extents_t *extents)
i.e. cairo_text_extents
actually takes three arguments, and the last argument is a pointer to an existing cairo_text_extents_t
structure which the caller needs to allocate.
So the first change you need is to fix your foreign
binding to match the C signature, like this:
let text_extents =
foreign "cairo_text_extents"
(gpointer @-> string @-> ptr cairo_text_extents_t @-> returning void)
and then you can fix the calling code so that rather than expecting text_extents
to return a struct, like this:
let tc = text_extents cr "a" in
you can first allocate a structure
let tc = addr (make cairo_text_extents_t) in
and then pass its address to the text_extents
function:
text_extents cr "a" tc;
Bravo!
Your example was very helpful. Thank you very much!