Cairo is a 2-D graphics library with support for multiple output devices. EGL is one of the backends for Cairo graphics, and this means that it can draw to Wayland surfaces. This chapter looks at this backend binding.
Cairo is a 2-D graphics library originally developed for use in the X Window system, but abstracted away from that in early 2000's. With Cairo, most of the original X Window calls are redundant, and this is one of the drivers for replacing X with Wayland.
Cairo can be output to X, OS X Quartz, PNG files, PDF files, ..., and OpenGL. This last allows Cairo to be used to write to EGL surfaces, and this forms the basis of using Cairo with Wayland.
      Cairo uses as backend a device
      of type cairo_device_t.
      On a device it will create a surface
      of type cairo_surface_t
      to write to. Writing is done using a context
      of type cairo_t
      which holdsthe current state of the rendering device,
      such as the location of objects to be drawn, fonts,
      colours, etc.
    
      The value of fields in the context can be changed by calls such as
      cairo_move_to and objects drawn to the surface
      by calls such as
      cairo_show_text.
    
      The surface may then be rendered to the device by calls
      such as cairo_paint or written
      to a file by calls such as cairo_surface_write_to_png.
      The following program from the Cairo FAQ doesn't create a
      device, but instead creates a surface directly as an image
      surface, draws a string in blue to it and then writes the surface out
      to a PNG file:
      
	
#include <cairo.h>
int
main (int argc, char *argv[])
{
        cairo_surface_t *surface =
            cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 80);
        cairo_t *cr =
            cairo_create (surface);
        cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size (cr, 32.0);
        cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
        cairo_move_to (cr, 10.0, 50.0);
        cairo_show_text (cr, "Hello, world");
        cairo_destroy (cr);
        cairo_surface_write_to_png (surface, "hello.png");
        cairo_surface_destroy (surface);
        return 0;
}
	
      
    
    
      The functions to deal with EGL are not documented in the online
      Cairo documentation. Instead you have to look inside the
      cairo-gl.h header file. This defines the call
      cairo_egl_device_create() which takes an
      EGLDisplay and an EGLContext as
      parameters. To use this call in Wayland means that you to
      have initialised these to Wayland as described in the EGL
      chapter.
    
This can be used as in
	
init_cairo() {
    cairo_device =
      cairo_egl_device_create(egl_display, egl_context);
    if (cairo_device_status(cairo_device) != CAIRO_STATUS_SUCCESS) {
      fprintf(stderr, "failed to get cairo EGL device\n");
      exit(1);
    }
}	  
	
      
    
    Once the Cairo device has been created, it can be used with an EGL surface to create a Cairo surface to render to:
	
cairo_surface = cairo_gl_surface_create_for_egl (cairo_device,
 						 egl_surface,
                                                 width, height);
	
      
    
    
    Once you have a Cairo surface, you draw to it using standard Cairo calls. These are not dealt with here - they would take a whole book. Instead, refer to the tutorials and documentation listed on the Cairo site.
      In the EGL chapter, an EGL buffer was sent to the Wayland
      compositor by EGLSwapBuffers.
      In Cairo, this wrapped in the call
      cairo_gl_surface_swapbuffers(().
      That's it! No other changes need to be made to
      standard Cairo programs.
    
The following example cairo_window.c creates an EGL Wayland window, then a Cairo surface and draws "hello" in green on a yellow rectangle:
      
    
    
      These are defined in cairo-gl.h:
      
	
cairo_public cairo_surface_t *
cairo_gl_surface_create (cairo_device_t *device,
                         cairo_content_t content,
                         int width, int height);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
                                     cairo_content_t content,
                                     unsigned int tex,
                                     int width, int height);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
cairo_public int
cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
cairo_public int
cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
cairo_public void
cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
cairo_public void
cairo_gl_device_set_thread_aware (cairo_device_t        *device,
                                  cairo_bool_t           thread_aware);
cairo_public cairo_device_t *
cairo_egl_device_create (EGLDisplay dpy, EGLContext egl);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_egl (cairo_device_t *device,
                                 EGLSurface      egl,
                                 int             width,
                                 int             height);
cairo_public EGLDisplay
cairo_egl_device_get_display (cairo_device_t *device);
cairo_public EGLSurface
cairo_egl_device_get_context (cairo_device_t *device);