From 12794cce9ed1f897747f65d2f977075b87bc2446 Mon Sep 17 00:00:00 2001 From: "mh0310.choi" Date: Tue, 26 Apr 2016 20:31:35 +0900 Subject: [PATCH] Update Cairo API Guide Doc for tizen_3.0 branch Change-Id: Icae783e60e9c40a9dbf57e903fcb5bf7c89b4a63 Signed-off-by: mh0310.choi --- org.tizen.guides/html/native/graphics/cairo_n.htm | 372 ++++++++++++++++++---- 1 file changed, 303 insertions(+), 69 deletions(-) diff --git a/org.tizen.guides/html/native/graphics/cairo_n.htm b/org.tizen.guides/html/native/graphics/cairo_n.htm index e99cf18..19c35e9 100644 --- a/org.tizen.guides/html/native/graphics/cairo_n.htm +++ b/org.tizen.guides/html/native/graphics/cairo_n.htm @@ -22,9 +22,9 @@

Content

Related Info

    @@ -38,121 +38,355 @@

    Cairo

    - -

    Cairo is an open source library for 2D vector graphics with support for multiple output devices. In Tizen, Cairo can support output to 2 different backends, such as the image and evas-gl (similar to gl) backend. This guide explains how you can link the Cairo image backend with Evas (in mobile and wearable applications), so that Cairo can draw on the image surface and an Evas object can get the image data from the Cairo image buffer.

    - + +

    Cairo is a famous 2D graphics library with support for multiple output devices. It provides powerful drawing operations to create a graphical experience that you desire, including stroking, filling, compositing images, text rendering, and any affine transforms (such as scale, rotation, and shear). Within the Tizen, cairo is able to output to 2 different backends: Image and GL backend.

    -

    Creating an Evas_Object Image

    -

    Cairo and Evas have completely different concepts:

    -
    • Evas knows the state of each object on the screen and manipulates the state. So when you create, for example, a rectangle with the evas_object_rectangle_add() function, it is not rendered on the screen when the function is called. In the rendering stage, the rectangle can be overlaid by an opaque image and never be rendered on the canvas.
    • -
    • Cairo draws as a person on a paper sheet. Once something is drawn on the Cairo surface, it is rendered on the screen.
    +

    Cairo in Tizen

    +

    Cairo belongs to the Graphics layer in Tizen. As shown in the following figure, the rendering functionality of cairo is provided through the use of the APIs of the lower modules, such as Pixman or OpenGL ES.

    -

    First, as shown in the following code snippet, you can define the appdata structure, which contains all the pointers to the objects to be manipulated:

    +

    Figure: Cairo within the Tizen

    +

    Cairo within the Tizen

    +

    The cairo GL backend allows hardware-accelerated rendering by targeting the OpenGL ES API. The goal of the cairo GL backend is to achieve better performance with equal functionality to the cairo Image backend, whenever possible.

    + + + + + + + + + + +
    Note
    Since Tizen only exposes EvasGL binding in place of EGL, cairo EvasGL APIs have been newly added and specified. To use the cairo GL backend in Tizen, an application must include in its source code the cairo-evas-gl.h header file instead of cairo-gl.h.
    + +

    Creating a Cairo Surface Linked with an Evas Object

    + +

    To display the rendered output using cairo APIs, an application must link a Cairo surface with an Evas object. In this context, the cairo surface is an object that can hold the rendered result within cairo. Cairo can draw an image on the surface appropriate for a particular backend, and Evas can access the image data from the cairo surface.

    + +

    Creating a Cairo Image Surface in Evas GL Backend

    + +

    To develop an application with Elementary, you create a window by using the elementary utility function, elm_win_util_standard_add(). And, in order to make the GL application use the GPU, you must call the elm_config_accel_preference_set() function before creating the window.

    + +

    In the cairo Image backend, you can create a new cairo image surface by using the cairo_image_surface_create() or cairo_image_surface_create_for_data() function. The former function requires only the pixel format and dimensions to be specified, while the latter function requires additional data, such as a pointer to an image buffer (supplied by the application) in which to write the content. In order to display a result of cairo rendering, you must also link an Evas image object to the created cairo image surface. For this purpose, use the evas_object_image_data_set() function.

    + +

    To create the image surface:

    + +
      +
    • With the cairo_image_surface_create() function. + +

      Call the cairo_image_surface_get_data() function before calling the evas_object_image_data_set() function. The cairo_image_surface_get_data() function returns a pointer to the raw image data of the created image surface. This pointer is used for the raw data to be linked with an Evas image object in the evas_object_image_data_set() function.

      +
      -typedef struct appdata 
      -{
      -   Evas_Object *win;
      -   Evas_Object *img;
      -   cairo_surface_t *surface;
      -   cairo_t *cairo;
      -   unsigned char *pixels;
      -} appdata_s;
      +elm_config_accel_preference_set("opengl");
      +Evas_Object *win = elm_win_util_standard_add("Cairo Image Backend guide", " Cairo Image Backend guide");
      +Evas_Object *img = evas_object_image_filled_add(evas_object_evas_get(win));
      +evas_object_geometry_get(win, NULL, NULL, &WIDTH, &HEIGHT);
      +
      +elm_win_resize_object_add(win, img);
      +evas_object_image_content_hint_set(img, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
      +evas_object_image_size_set(img, WIDTH, HEIGHT);
      +evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
      +evas_object_image_alpha_set(img, 0);
      +evas_object_show(img);
      +
      +cairo_surface_t *cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
      +cairo_t *cairo = cairo_create(cairo_surface);
      +// Cairo drawing
      +
      +cairo_surface_flush(cairo_surface);
      +
      +unsigned char *imageData = cairo_image_surface_get_data(cairo_surface);
      +evas_object_image_data_set(img, imageData);
      +evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT);
       
      +
    • + +
    • With the cairo_image_surface_create_for_data() function. +

      To use the function, you need a pointer to an image data, which can be retrieved with the evas_object_image_data_get() function. The function returns the data pointer of an image object and requires a parameter to determine whether the data is modified. If modification is enabled by setting the parameter to EINA_TRUE, Evas updates the image pixels in the next rendering cycle. Finally, you can link the pixel buffer with the image object by using the evas_object_image_data_set() function.

      + +

      Since the default backend for Evas is GL, the cairo Image backend is much slower due to the memory copy operation, which occurs whenever the rendered result from Cairo is uploaded to Evas. To enhance the performance of Cairo Image backend to enable the zero copy feature, set the EVAS_IMAGE_CONTENT_HINT_DYNAMIC property with the evas_object_image_content_hint_set() function. For more information, see Optimizing Evas.

      -

      To create a new Evas_Object image, use the evas_object_image_add() function. The image object can be used for displaying as pixels on the screen:

      +

      To update a rectangular region on the screen, the evas_object_image_data_update_add() function can be used. For more information about the image object functions of Evas, see Image Objects.

      -appdata_s * ad;
      -ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
      -evas_object_show(ad->win);
      -ad->img = evas_object_image_add(evas_object_evas_get(ad->win));
      -evas_object_show(ad->img);
      +Evas_Object *win = elm_win_util_standard_add("Cairo Image Backend guide", " Cairo Image Backend guide");
      +Evas_Object *img = evas_object_image_filled_add(evas_object_evas_get(win));
      +evas_object_geometry_get(win, NULL, NULL, &WIDTH, &HEIGHT);
      +
      +elm_win_resize_object_add(win, img);
      +evas_object_image_content_hint_set(img, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
      +evas_object_image_size_set(img, WIDTH, HEIGHT);
      +evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
      +evas_object_image_alpha_set(img, 0);
      +evas_object_show(img);
      +
      +int row_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, WIDTH);
      +unsigned char *imageData = (unsigned char *) evas_object_image_data_get(img, EINA_TRUE);
      +cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data(imageData, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, row_stride); 
      +cairo_t *cairo = cairo_create(cairo_surface);
      +// Cairo drawing
      +
      +cairo_surface_flush(cairo_surface);
      +
      +evas_object_image_data_set(img, imageData);
      +evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT);
       
      +
    • +
    + + + + + + + + + + +
    Note
    Take care when using the evas_object_image_data_set() function. You must match the evas_object_image_data_get() and evas_object_image_data_set() functions as a pair. Since the evas_object_image_data_get() function keeps a rendering sink, the rendered result with cairo can be reflected outside the Evas area, if the functions are not matched.
    + +

    Creating a Cairo GL Surface in the Evas GL Backend

    - +

    To create the GL surface:

    -

    You can now create a Cairo image surface for the provided pixel and other data by using the cairo_image_surface_create_for_data() function. The pixel data is a pointer to a buffer supplied by the application in which you want to write content.

    -

    The size of the row stride is called by the cairo_format_stride_for_width() function. The function provides a stride value that respects all alignment requirements of the accelerated image-rendering code within Cairo.

    +
      +
    1. Since an application utilizing the cairo GL backend in Tizen is based on Evas GL, an Evas GL handler must be created with the evas_gl_new() function during the initial stage. +

      Afterwards, the evas_gl_config, evas_gl_surface, and evas_gl_context instances are created in that order. For more information on using Evas GL, see Creating OpenGL ES Applications and OpenGL ES Tutorial.

      +
      -int row_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, WIDTH);
      -ad->pixels = (unsigned char *) calloc(sizeof(unsigned char) * row_stride * HEIGHT, 1);
      -ad->surface = cairo_image_surface_create_for_data(ad->pixels, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, row_stride);
      +Evas_Object *win = elm_win_util_standard_add("Cairo GL Backend guide", " Cairo GL Backend guide");
      +Evas_Object *img = evas_object_image_filled_add(evas_object_evas_get(win));
      +
      +Evas_Native_Surface ns;
      +Evas_GL *evas_gl = evas_gl_new(evas_object_evas_get(img));
      +Evas_GL_Config *evas_gl_config = evas_gl_config_new();
      +evas_gl_config->color_format = EVAS_GL_RGBA_8888;
      +evas_gl_config->stencil_bits = EVAS_GL_STENCIL_BIT_8;
      +evas_gl_config->multisample_bits = EVAS_GL_MULTISAMPLE_MED;
      +
      +Evas_GL_Surface *evas_gl_surface = evas_gl_surface_create(evas_gl, evas_gl_config, WIDTH, HEIGHT);
      +Evas_GL_Context *evas_gl_context = evas_gl_context_create(evas_gl, NULL);
      +evas_gl_native_surface_get(evas_gl, evas_gl_surface, &ns);
      +evas_object_image_native_surface_set(img, &ns);
      +
      +
    2. + +
    3. In Tizen, for the purpose of showing the rendered output on screen, a cairo GL application can use evas_object_image_pixels_dirty_set() function. This function allows the rendered result to be redrawn on the screen for every animator callback in the default update refresh rate. The rendered results are saved inside the Evas object (in this example, the img object) connected to the cairo GL backend during the cairo drawing. + +
      +evas_object_image_pixels_dirty_set(img, EINA_TRUE);
      +evas_object_image_pixels_get_callback_set(img, cairo_drawing, 0);
       
      +
    4. + +
    5. If your application employs the cairo GL backend in Tizen, include the cairo-evas-gl.h header file instead of cairo-gl.h.
    6. + +
    7. To fully use the GPU acceleration, set the CAIRO_GL_COMPOSITOR property to MSAA. + +

      In addition, call the cairo_gl_device_set_thread_aware() function with cairo_device and 0 as input parameters to prevent unnecessary context switches. Cairo can be used in multithreaded environments, and switches out the current GL context by default after each draw finishes. Therefore, if no other thread uses cairo for GL rendering, set the thread_aware parameter to 0.

      + +

      To create the cairo GL surface with the cairo_gl_surface_create_for_evas_gl() function, a cairo_device and an evas_gl_surface must be created beforehand:

      +
        +
      • A cairo_device can be created with the cairo_evas_gl_device_create() function, which is an interface to the underlying rendering system. You also need the evas_gl_object and evas_gl_context as input parameters to the cairo_evas_gl_device_create() function.
      • +
      • A evas_gl_surface object is needed to render 2D graphics through the rendering functionality of the cairo GL backend.
      • +
      -

      To create the Cairo context used for all operations, use the following code.

      -cairo = cairo_create(ad->surface);
      +setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
      +cairo_device_t *cairo_device = cairo_evas_gl_device_create(evas_gl, evas_gl_context);
      +cairo_boot_t thread_aware = 0;
      +cairo_gl_device_set_thread_aware(cairo_device, thread_aware);
      +cairo_surface_t *cairo_surface = cairo_gl_surface_create_for_evas_gl(cairo_device, evas_gl_surface, evas_gl_config, WIDTH, HEIGHT);
      +cairo_t *cairo = cairo_create(cairo_surface);
      +// Cairo drawing
       
      +
    8. + +
    9. When any drawing with the cairo API is finished, call the cairo_surface_flush() function. It guarantees a complete rendered result, because it does any pending drawing for the surface and also restores any temporary modifications cairo has made to the surface state. Specially, this function must be called before switching from drawing on the surface with cairo to drawing on it directly with native APIs. -

      Associate the pixels (as raw data) to given image object. The pixels must be of the same size and colorspace as the image object.

      -evas_object_image_data_set(ad->img, ad->pixels);
      +cairo_surface_flush(cairo_surface);
       
      +
    10. +
    + +

    Drawing with Cairo

    + +

    Drawing with Cairo to a surface is accomplished by calling the common backend interface functions. These rendering functions must be called properly for each backend. For more information about the common rendering functions, see the Cairo: A Vector Graphics Library manual.

    + +

    The following sections introduce a general example for drawing a line using cairo APIs, including some special guidelines. Occasionally, you need to adhere to special guidelines to overcome any cairo drawing limitations in Tizen.

    + +

    Using a Surface to Source Pattern

    -

    Once you finish painting by using Cairo, Evas renders a particular rectangular region to be redrawn on the screen:

    +

    Within the cairo API, some functions, such as cairo_set_source_surface() and cairo_mask_surface(), use a surface to set the source pattern. However, the performance of these functions in Tizen, under certain circumstances, can be heavily degraded if the source surface is created using the cairo_gl_surface_create_for_evas_gl() function.

    + +

    In Tizen, you can create a cairo GL surface with either the cairo_gl_surface_create() or cairo_gl_surface_create_for_evas_gl() function. To prevent performance issues, always create the source surface with the cairo_gl_surface_create() function.

    +
    -evas_object_image_data_update_add(ad->img, 0, 0, WIDTH, HEIGHT);
    +// Create a surface for destination
    +cairo_surface_t *cairo_surface = cairo_gl_surface_create_for_evas_gl(cr, evas_gl_surface, evas_gl_config, WIDTH, HEIGHT);
    +
    +Evas_GL_Config *evas_gl_config_source = evas_gl_config_new();
    +evas_gl_config_source->color_format = EVAS_GL_RGBA_8888;
    +evas_gl_config_source->stencil_bits = EVAS_GL_STENCIL_BIT_1;
    +evas_gl_config_source->multisample_bits = EVAS_GL_MULTISAMPLE_LOW;
    +evas_gl_surface_source = evas_gl_surface_create(evas_gl, evas_gl_config_source, WIDTH, HEIGHT);
    +
    +// Create a surface for source
    +cairo_surface_t *image_surface = cairo_image_surface_create_from_png(image);
    +cairo_surface_t *gl_surface = cairo_gl_surface_create(cairo_device, CAIRO_CONTENT_COLOR_ALPHA, image_width, image_height);
    +cairo_t *cairo = cairo_create(gl_surface);
    +cairo_set_source_surface(cairo, image_surface, 0, 0);
    +cairo_paint(cairo);
    +cairo_pattern_create_for_surface(gl_surface);
     
    -

    Drawing with Cairo

    +

    Support for Reading Various Image Files

    -

    Before drawing a line, set the current line width or color as a style. For example, you can set the line width as 2 and the line color as opaque red:

    +

    Cairo does not support a functionality for reading image files in JPEG or SPI format; only PNG is supported. With a PNG file, you can use the cairo_image_surface_create_from_png() function to make a new image surface from the image. However, handle this function with care, because it is experimental and only offers very simple functionality for reading PNG files.

    +
    -cairo_set_line_width(ad->cairo, 2);
    -cairo_set_source_rgba(ad->cairo, 1.0, 0.0, 0.0, 1.0);
    +cairo_surface_t *image = cairo_image_surface_create_from_png("test_image.png"); +cairo_set_source_surface(cairo, image, 0, 0); +cairo_paint(cairo); +cairo_surface_destroy(image); + + +

    On the other hand, cairo applications in Tizen can read JPEG and other image formats by using the Evas APIs. Evas supports image loaders for various formats as plug-in modules:

    +
      +
    1. Create an image buffer as a temporary buffer for decoding an image file with the evas_object_image_add() function.
    2. +
    3. Use the evas_object_image_file_set() function to set the image file on the object (in this example, the decoded_img object).
    4. +
    5. Use other Evas functions for the image object to manage it. Since the temporary buffers are only used for the decoded content of the given image file (in this example, inline_buffr and decoded_img), you do not need to call the evas_object_show() function. For more information about the image object functions, see Image Objects.
    6. +
    -

    You can draw various lines:

    -
      -
    • To set the start position with a user-specific offset, use the cairo_translate() function. It modifies the current transformation matrix (CTM) by translating the user-space origin by (x, y).

      -cairo_translate(ad->cairo, 40, 40);
    • +evas_object_geometry_get(win, NULL, NULL, &surface_w, &surface_h); +Evas_Object *inline_buffr = elm_win_add(win, "Img Read", ELM_WIN_INLINED_IMAGE); +evas_object_move(inline_buffr, 0, 0); +evas_object_resize(inline_buffr, surface_w, surface_h); + +Evas_Object *decoded_img = evas_object_image_add(evas_object_evas_get(inline_buffer)); // As a temporary buffer +evas_object_image_file_set(decoded_img, "test_image.jpeg", NULL); +evas_object_image_size_get(decoded_img, &w, &h); +evas_object_image_fill_set(decoded_img, 0, 0, w, h); +evas_object_image_filled_set(decoded_img, EINA_TRUE); +evas_object_resize(decoded_img, w, h); + -
    • Cairo uses a connect-the-dots style system when creating a path. To draw a line between 2 points (100,100 and 200,150) on the surface, use the cairo_move_to() and cairo_line_to() functions:

      +

      After the image file reading is complete, you can create a cairo surface for the image object by using the evas_object_image_data_get() and cairo_image_surface_create_for_data() functions. The cairo surface is used to create a pattern with the cairo_set_source_surface() function for the cairo drawing. In addition, to prevent memory leaks, delete the temporary buffers that are no longer used.

      +
      -cairo_move_to(ad->cairo, 100, 100);
      -cairo_line_to(ad->cairo, 200, 150);
    • +src_buffer = (unsigned char *)evas_object_image_data_get(decoded_img, EINA_TRUE); +cairo_surface_t *source = cairo_image_surface_create_for_data(src_buffer, CAIRO_FORMAT_ARGB32, w, h, +                                                              evas_object_image_stride_get(decoded_img)); +cairo_set_source_surface(cr, source, 0, 0); +cairo_paint(cr); + +evas_object_del (inline_buffr); +cairo_surface_destroy(img); + + +

      Drawing a Line

      + +

      Now, the general example will be introduced. The following example creates a line drawing with a rectangle, and a path that uses straight sections, arcs, and Bézier curves.

      + +

      Figure: Rectangle and path drawing with Cairo

      +

      Rectangle and path drawing with Cairo

      + +

      To draw lines with cairo APIs:

      + +
        +
      1. Set the line width and color. +

        In this example, the line width is 2 and the color is opaque red:

        -
      2. To draw a line from the endpoint of the current path, use the cairo_rel_line_to() function. The offset by (dx, dy) must be specified as (100, -50).

        -cairo_rel_line_to(ad->cairo, 100, -50);
      3. +cairo_set_line_width(cairo, 2); +cairo_set_source_rgba(cairo, 1.0, 0.0, 0.0, 1.0); + + + +
      4. To create the path: +
          +
        1. To set the starting point with a user-specified offset, use the cairo_translate() function to modify the user-space origin (x, y) by translating it with the current transformation matrix (CTM): -
        2. To draw a circular arc of the given radius (100 * sqrt(2)) to the current path, use the cairo_arc() function.

          -

          The arc is centered at (200, 200), begins at angle1 (-0.25 * M_PI) and proceeds in the direction of increasing angles to end at angle2 (0.25 * M_PI). If angle2 is less than angle1, it is progressively increased by 2*M_PI until it is greater than angle1.

          -cairo_arc(ad->cairo, 200, 200, 100 * sqrt(2), -0.25 * M_PI, 0.25 * M_PI);
        3. +cairo_translate(cairo, 40, 40); + + -
        4. To draw a cubic Bézier spline to the path from the end position of the previous path, use the cairo_rel_curve_to() function. You can use the points offset by (-100, -50) and (-100, 50) as the control points. After the call, the current point is offset by (-200, 0).

          +
        5. To draw a line from point (100,100) to point (200,150) on a surface, use the cairo_move_to() and cairo_line_to() functions: +
          -cairo_rel_curve_to(ad->cairo, -100, -50, -100, 50, -200, 0);
        6. +cairo_move_to(cairo, 100, 100); +cairo_line_to(cairo, 200, 150); + + -
        7. You can add a line segment to the path from the current point to the beginning of the current sub-path. After this call, the current point is at the joined endpoint of the sub-path. The cairo_close_path() function differs from simply calling the cairo_line_to() function with the equivalent coordinate in the case of stroking: there is a line join connecting the final and initial segments of the sub-path.

          +
        8. To add a line on a path from the current point to a point at the offset (dx, dy), use the cairo_rel_line_to() function. In this example, the offset is (100, -50). +
          -cairo_close_path(ad->cairo);
        9. +cairo_rel_line_to(cairo, 100, -50); + + + +
        10. To draw a circular arc of a given radius on the current path, use the cairo_arc() function. +

          In this example, the radius is (100 * sqrt(2)), the arc is centered at (200, 200), begins at an angle (-0.25 * M_PI ) and proceeds in the direction of increasing angles to end at an angle (0.25 * M_PI ). If the end angle is less than the begin angle, the end angle is progressively increased by 2*M_PI until it is greater than the begin angle.

          -
        11. To create a rectangle, use the cairo_rectangle() function. This call draws a rectangle with 400 px in width and height from point (0, 0).

          -cairo_rectangle(ad->cairo, 0, 0, 400, 400);
        12. +cairo_arc(cairo, 200, 200, 100 * sqrt(2), -0.25 * M_PI, 0.25 * M_PI); + + + +
        13. To draw a cubic Bézier spline, use the cairo_rel_curve_to() function. +

          In this example, the offsets of (-100, -50) and (-100, 50) are used as the control points. After this function call, the current point is offset by (-200, 0).

          -
        14. To stroke the paths, use the cairo_stroke() function. It is a drawing operator that strokes the current path according to the current line width, line join, line cap, and dash settings. After the function call, the current path is cleared from the cairo context.

          -cairo_stroke(ad->cairo);
        15. +cairo_rel_curve_to(cairo, -100, -50, -100, 50, -200, 0); + + -
        16. To ensure that any pending Cairo operation are drawn, use the cairo_surface_flush() function after finishing the Cairo drawing:

          +
        17. To add a line segment on the path from the current point to the beginning of the current sub-path, use the cairo_close_path() function. After this call, the current point is repositioned at the joined endpoint of the sub-path. +

          The behavior of the cairo_close_path() function differs from the cairo_line_to() function with the equivalent coordinates very little: in the case of stroking, a line joining the final and initial segments of the sub-path is also created.

          -cairo_surface_flush(ad->surface);
    +cairo_close_path(cairo); + + + + +
  • To draw a rectangle, use the cairo_rectangle() function. +

    In this example, the function draws a rectangle starting from the point (0, 0) with the width and height of 400 px.

    + +
    +cairo_rectangle(cairo, 0, 0, 400, 400);
    +
    +
  • -

    You need to destroy Cairo objects before terminating your application:

    +
  • If you need to create a stroke on a path, the cairo_stroke() function is a drawing operator that draws a stroke on the current path in accordance to the current line width and line color. After the function call, the current path is cleared from the cairo context. +
    -cairo_destroy(ad->cairo);
    -cairo_surface_destroy(ad->surface);
    +cairo_stroke(cairo); + +
  • -

    Figure: Drawing paths and a rectangle with Cairo

    -

    Drawing paths and a rectangle with Cairo

    +
  • To ensure that any pending cairo operations are drawn, use the cairo_surface_flush() function after finishing the cairo drawing: + +
    +cairo_surface_flush(surface);
    +
    +
  • +
  • Destroy the cairo objects when you terminate the application: + +
    +cairo_destroy(cairo);
    +cairo_surface_destroy(surface);
    +
    +
  • + @@ -176,4 +410,4 @@ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga - \ No newline at end of file + -- 2.7.4