Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2011 Intel Corporation.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it either under the terms of the GNU Lesser General Public
  7.  * License version 2.1 as published by the Free Software Foundation
  8.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  9.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  10.  * notice, a recipient may use your version of this file under either
  11.  * the MPL or the LGPL.
  12.  *
  13.  * You should have received a copy of the LGPL along with this library
  14.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  15.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  16.  * You should have received a copy of the MPL along with this library
  17.  * in the file COPYING-MPL-1.1
  18.  *
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License at
  22.  * http://www.mozilla.og/MPL/
  23.  *
  24.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  25.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  26.  * the specific language governing rights and limitations.
  27.  *
  28.  * Contributor(s):
  29.  *      Robert Bragg <robert@linux.intel.com>
  30.  */
  31.  
  32. /* so long as we can verify that the ctm doesn't change multiple times
  33.  * during the construction of a path we can build a shadow
  34.  * #cairo_path_fixed_t in user coordinates that we can use to create a
  35.  * hash value for caching tessellations of that path.
  36.  *
  37.  * We need to hook into all the points where the ctm can be changed
  38.  * so we can bump a cr->path_ctm_age counter.
  39.  *
  40.  * We need to hook into all the points where the path can be modified
  41.  * so we can catch the start of a path and reset the cr->path_ctm_age
  42.  * counter at that point.
  43.  *
  44.  * When a draw operation is hit we can then check that the
  45.  * path_ctm_age == 0 and if so we create a hash of the path.
  46.  *
  47.  * We use this hash to lookup a #cairo_cogl_path_meta_t struct which
  48.  * may contain tessellated triangles for the path or may just contain
  49.  * a count of how many times the path has been re-seen (we only cache
  50.  * tessellated triangles if there is evidence that the path is being
  51.  * used multiple times because there is a cost involved in allocating
  52.  * a separate buffer for the triangles).
  53.  */
  54.  
  55. #include "cairoint.h"
  56.  
  57. #include "cairo-cogl-context-private.h"
  58. #include "cairo-freed-pool-private.h"
  59. #include "cairo-arc-private.h"
  60. #include "cairo-path-fixed-private.h"
  61.  
  62. #include <glib.h>
  63.  
  64. static freed_pool_t context_pool;
  65.  
  66. void
  67. _cairo_cogl_context_reset_static_data (void)
  68. {
  69.     _freed_pool_reset (&context_pool);
  70. }
  71.  
  72. static cairo_status_t
  73. _cairo_cogl_context_rectangle_real (cairo_cogl_context_t *cr,
  74.                                     double x, double y,
  75.                                     double width, double height)
  76. {
  77.     cairo_status_t status;
  78.     status = cr->dev->backend_parent.rectangle (cr, x, y, width, height);
  79.     if (unlikely (status))
  80.         return status;
  81.  
  82.     return _cairo_cogl_path_fixed_rectangle (&cr->user_path,
  83.                                              _cairo_fixed_from_double (x),
  84.                                              _cairo_fixed_from_double (y),
  85.                                              _cairo_fixed_from_double (width),
  86.                                              _cairo_fixed_from_double (height));
  87. }
  88.  
  89. /* The idea here is that we have a simplified way of tracking rectangle paths
  90.  * because rectangles are perhaps the most common shape drawn with cairo.
  91.  *
  92.  * Basically we have a speculative store for a rectangle path that doesn't
  93.  * need to use the #cairo_path_fixed_t api to describe a rectangle in terms of
  94.  * (move_to,rel_line_to,rel_line_to,_rel_line_to,close) because if you profile
  95.  * heavy rectangle drawing with Cairo that process can be overly expensive.
  96.  *
  97.  * If the user asks to add more than just a rectangle to their current path
  98.  * then we "flush" any speculative rectangle stored into the current path
  99.  * before continuing to append their operations.
  100.  *
  101.  * In addition to the speculative store cairo-cogl also has a fast-path
  102.  * fill_rectangle drawing operation that further aims to minimize the cost
  103.  * of drawing rectangles.
  104.  */
  105. static cairo_status_t
  106. _flush_cr_rectangle (cairo_cogl_context_t *cr)
  107. {
  108.     if (!cr->path_is_rectangle)
  109.         return CAIRO_STATUS_SUCCESS;
  110.  
  111.     cr->path_is_rectangle = FALSE;
  112.     return _cairo_cogl_context_rectangle_real (cr, cr->x, cr->y, cr->width, cr->height);
  113. }
  114.  
  115. static cairo_status_t
  116. _cairo_cogl_context_restore (void *abstract_cr)
  117. {
  118.     cairo_cogl_context_t *cr = abstract_cr;
  119.  
  120.     if (cr->path_is_rectangle) {
  121.         cairo_status_t status = _flush_cr_rectangle (cr);
  122.         if (unlikely (status))
  123.             return status;
  124.     }
  125.  
  126.     cr->path_ctm_age++;
  127.     return cr->dev->backend_parent.restore (abstract_cr);
  128. }
  129.  
  130. static cairo_status_t
  131. _cairo_cogl_context_translate (void *abstract_cr, double tx, double ty)
  132. {
  133.     cairo_cogl_context_t *cr = abstract_cr;
  134.  
  135.     if (cr->path_is_rectangle) {
  136.         cairo_status_t status = _flush_cr_rectangle (cr);
  137.         if (unlikely (status))
  138.             return status;
  139.     }
  140.  
  141.     cr->path_ctm_age++;
  142.     return cr->dev->backend_parent.translate (abstract_cr, tx, ty);
  143. }
  144.  
  145. static cairo_status_t
  146. _cairo_cogl_context_scale (void *abstract_cr, double sx, double sy)
  147. {
  148.     cairo_cogl_context_t *cr = abstract_cr;
  149.  
  150.     if (cr->path_is_rectangle) {
  151.         cairo_status_t status = _flush_cr_rectangle (cr);
  152.         if (unlikely (status))
  153.             return status;
  154.     }
  155.  
  156.     cr->path_ctm_age++;
  157.     return cr->dev->backend_parent.scale (abstract_cr, sx, sy);
  158. }
  159.  
  160. static cairo_status_t
  161. _cairo_cogl_context_rotate (void *abstract_cr, double theta)
  162. {
  163.     cairo_cogl_context_t *cr = abstract_cr;
  164.  
  165.     if (cr->path_is_rectangle) {
  166.         cairo_status_t status = _flush_cr_rectangle (cr);
  167.         if (unlikely (status))
  168.             return status;
  169.     }
  170.  
  171.     cr->path_ctm_age++;
  172.     return cr->dev->backend_parent.rotate (abstract_cr, theta);
  173. }
  174.  
  175. static cairo_status_t
  176. _cairo_cogl_context_transform (void *abstract_cr, const cairo_matrix_t *matrix)
  177. {
  178.     cairo_cogl_context_t *cr = abstract_cr;
  179.  
  180.     if (cr->path_is_rectangle) {
  181.         cairo_status_t status = _flush_cr_rectangle (cr);
  182.         if (unlikely (status))
  183.             return status;
  184.     }
  185.  
  186.     cr->path_ctm_age++;
  187.     return cr->dev->backend_parent.transform (abstract_cr, matrix);
  188. }
  189.  
  190. static cairo_status_t
  191. _cairo_cogl_context_set_matrix (void *abstract_cr, const cairo_matrix_t *matrix)
  192. {
  193.     cairo_cogl_context_t *cr = abstract_cr;
  194.  
  195.     if (cr->path_is_rectangle) {
  196.         cairo_status_t status = _flush_cr_rectangle (cr);
  197.         if (unlikely (status))
  198.             return status;
  199.     }
  200.  
  201.     cr->path_ctm_age++;
  202.     return cr->dev->backend_parent.set_matrix (abstract_cr, matrix);
  203. }
  204.  
  205. static cairo_status_t
  206. _cairo_cogl_context_set_identity_matrix (void *abstract_cr)
  207. {
  208.     cairo_cogl_context_t *cr = abstract_cr;
  209.  
  210.     if (cr->path_is_rectangle) {
  211.         cairo_status_t status = _flush_cr_rectangle (cr);
  212.         if (unlikely (status))
  213.             return status;
  214.     }
  215.  
  216.     cr->path_ctm_age++;
  217.     return cr->dev->backend_parent.set_identity_matrix (abstract_cr);
  218. }
  219.  
  220. static cairo_status_t
  221. _cairo_cogl_context_new_path (void *abstract_cr)
  222. {
  223.     cairo_cogl_context_t *cr = abstract_cr;
  224.     cairo_status_t status;
  225.  
  226.     if (cr->path_is_rectangle) {
  227.         status = _flush_cr_rectangle (cr);
  228.         if (unlikely (status))
  229.             return status;
  230.     }
  231.  
  232.     status = cr->dev->backend_parent.new_path (abstract_cr);
  233.     if (unlikely (status))
  234.         return status;
  235.  
  236.     _cairo_path_fixed_fini (&cr->user_path);
  237.     _cairo_path_fixed_init (&cr->user_path);
  238.     cr->path_is_rectangle = FALSE;
  239.  
  240.     return CAIRO_STATUS_SUCCESS;
  241. }
  242.  
  243. static cairo_status_t
  244. _cairo_cogl_context_new_sub_path (void *abstract_cr)
  245. {
  246.     cairo_cogl_context_t *cr = abstract_cr;
  247.     cairo_status_t status;
  248.  
  249.     if (cr->path_is_rectangle) {
  250.         status = _flush_cr_rectangle (cr);
  251.         if (unlikely (status))
  252.             return status;
  253.     }
  254.  
  255.     status = cr->dev->backend_parent.new_sub_path (abstract_cr);
  256.     if (unlikely (status))
  257.         return status;
  258.  
  259.     _cairo_path_fixed_new_sub_path (&cr->user_path);
  260.  
  261.     return CAIRO_STATUS_SUCCESS;
  262. }
  263.  
  264. static cairo_status_t
  265. _cairo_cogl_context_move_to (void *abstract_cr, double x, double y)
  266. {
  267.     cairo_cogl_context_t *cr = abstract_cr;
  268.     cairo_status_t status;
  269.     cairo_fixed_t x_fixed, y_fixed;
  270.  
  271.     if (cr->path_is_rectangle) {
  272.         status = _flush_cr_rectangle (cr);
  273.         if (unlikely (status))
  274.             return status;
  275.     }
  276.  
  277.     status = cr->dev->backend_parent.move_to (abstract_cr, x, y);
  278.     if (unlikely (status))
  279.         return status;
  280.  
  281.     x_fixed = _cairo_fixed_from_double (x);
  282.     y_fixed = _cairo_fixed_from_double (y);
  283.  
  284.     return _cairo_path_fixed_move_to (&cr->user_path, x_fixed, y_fixed);
  285. }
  286.  
  287. static cairo_status_t
  288. _cairo_cogl_context_line_to (void *abstract_cr, double x, double y)
  289. {
  290.     cairo_cogl_context_t *cr = abstract_cr;
  291.     cairo_status_t status;
  292.     cairo_fixed_t x_fixed, y_fixed;
  293.  
  294.     if (cr->path_is_rectangle) {
  295.         status = _flush_cr_rectangle (cr);
  296.         if (unlikely (status))
  297.             return status;
  298.     }
  299.  
  300.     status = cr->dev->backend_parent.line_to (abstract_cr, x, y);
  301.     if (unlikely (status))
  302.         return status;
  303.  
  304.     x_fixed = _cairo_fixed_from_double (x);
  305.     y_fixed = _cairo_fixed_from_double (y);
  306.  
  307.     if (cr->user_path.buf.base.num_ops == 0)
  308.         cr->path_ctm_age = 0;
  309.  
  310.     return _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
  311. }
  312.  
  313. static cairo_status_t
  314. _cairo_cogl_context_curve_to (void *abstract_cr,
  315.                                double x1, double y1,
  316.                                double x2, double y2,
  317.                                double x3, double y3)
  318. {
  319.     cairo_cogl_context_t *cr = abstract_cr;
  320.     cairo_status_t status;
  321.     cairo_fixed_t x1_fixed, y1_fixed;
  322.     cairo_fixed_t x2_fixed, y2_fixed;
  323.     cairo_fixed_t x3_fixed, y3_fixed;
  324.  
  325.     if (cr->path_is_rectangle) {
  326.         status = _flush_cr_rectangle (cr);
  327.         if (unlikely (status))
  328.             return status;
  329.     }
  330.  
  331.     status = cr->dev->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3);
  332.     if (unlikely (status))
  333.         return status;
  334.  
  335.     x1_fixed = _cairo_fixed_from_double (x1);
  336.     y1_fixed = _cairo_fixed_from_double (y1);
  337.  
  338.     x2_fixed = _cairo_fixed_from_double (x2);
  339.     y2_fixed = _cairo_fixed_from_double (y2);
  340.  
  341.     x3_fixed = _cairo_fixed_from_double (x3);
  342.     y3_fixed = _cairo_fixed_from_double (y3);
  343.  
  344.     if (cr->user_path.buf.base.num_ops == 0)
  345.         cr->path_ctm_age = 0;
  346.  
  347.     return _cairo_path_fixed_curve_to (&cr->user_path,
  348.                                        x1_fixed, y1_fixed,
  349.                                        x2_fixed, y2_fixed,
  350.                                        x3_fixed, y3_fixed);
  351. }
  352.  
  353. static cairo_status_t
  354. _cairo_cogl_context_arc (void *abstract_cr,
  355.                           double xc, double yc, double radius,
  356.                           double angle1, double angle2,
  357.                           cairo_bool_t forward)
  358. {
  359.     cairo_cogl_context_t *cr = abstract_cr;
  360.     cairo_status_t status;
  361.  
  362.     if (cr->path_is_rectangle) {
  363.         status = _flush_cr_rectangle (cr);
  364.         if (unlikely (status))
  365.             return status;
  366.     }
  367.  
  368.     status = cr->dev->backend_parent.arc (abstract_cr, xc, yc, radius, angle1, angle2, forward);
  369.     if (unlikely (status))
  370.         return status;
  371.  
  372.     if (cr->user_path.buf.base.num_ops == 0)
  373.         cr->path_ctm_age = 0;
  374.  
  375.     /* Do nothing, successfully, if radius is <= 0 */
  376.     if (radius <= 0.0) {
  377.         cairo_fixed_t x_fixed, y_fixed;
  378.  
  379.         x_fixed = _cairo_fixed_from_double (xc);
  380.         y_fixed = _cairo_fixed_from_double (yc);
  381.         status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
  382.         if (unlikely (status))
  383.             return status;
  384.  
  385.         status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
  386.         if (unlikely (status))
  387.             return status;
  388.  
  389.         return CAIRO_STATUS_SUCCESS;
  390.     }
  391.  
  392.     status = _cairo_cogl_context_line_to (cr,
  393.                                           xc + radius * cos (angle1),
  394.                                           yc + radius * sin (angle1));
  395.  
  396.     if (unlikely (status))
  397.         return status;
  398.  
  399.     if (forward)
  400.         _cairo_arc_path (&cr->base.base, xc, yc, radius, angle1, angle2);
  401.     else
  402.         _cairo_arc_path_negative (&cr->base.base, xc, yc, radius, angle1, angle2);
  403.  
  404.     return CAIRO_STATUS_SUCCESS; /* any error will have already been set on cr */
  405. }
  406.  
  407. static cairo_status_t
  408. _cairo_cogl_context_rel_move_to (void *abstract_cr, double dx, double dy)
  409. {
  410.     cairo_cogl_context_t *cr = abstract_cr;
  411.     cairo_status_t status;
  412.     cairo_fixed_t dx_fixed, dy_fixed;
  413.  
  414.     if (cr->path_is_rectangle) {
  415.         status = _flush_cr_rectangle (cr);
  416.         if (unlikely (status))
  417.             return status;
  418.     }
  419.  
  420.     status = cr->dev->backend_parent.rel_move_to (abstract_cr, dx, dy);
  421.     if (unlikely (status))
  422.         return status;
  423.  
  424.     dx_fixed = _cairo_fixed_from_double (dx);
  425.     dy_fixed = _cairo_fixed_from_double (dy);
  426.  
  427.     return _cairo_path_fixed_rel_move_to (&cr->user_path, dx_fixed, dy_fixed);
  428. }
  429.  
  430. static cairo_status_t
  431. _cairo_cogl_context_rel_line_to (void *abstract_cr, double dx, double dy)
  432. {
  433.     cairo_cogl_context_t *cr = abstract_cr;
  434.     cairo_status_t status;
  435.     cairo_fixed_t dx_fixed, dy_fixed;
  436.  
  437.     if (cr->path_is_rectangle) {
  438.         status = _flush_cr_rectangle (cr);
  439.         if (unlikely (status))
  440.             return status;
  441.     }
  442.  
  443.     status = cr->dev->backend_parent.rel_line_to (abstract_cr, dx, dy);
  444.     if (unlikely (status))
  445.         return status;
  446.  
  447.     dx_fixed = _cairo_fixed_from_double (dx);
  448.     dy_fixed = _cairo_fixed_from_double (dy);
  449.  
  450.     if (cr->user_path.buf.base.num_ops == 0)
  451.         cr->path_ctm_age = 0;
  452.  
  453.     return _cairo_path_fixed_rel_line_to (&cr->user_path, dx_fixed, dy_fixed);
  454. }
  455.  
  456.  
  457. static cairo_status_t
  458. _cairo_cogl_context_rel_curve_to (void *abstract_cr,
  459.                                    double dx1, double dy1,
  460.                                    double dx2, double dy2,
  461.                                    double dx3, double dy3)
  462. {
  463.     cairo_cogl_context_t *cr = abstract_cr;
  464.     cairo_status_t status;
  465.     cairo_fixed_t dx1_fixed, dy1_fixed;
  466.     cairo_fixed_t dx2_fixed, dy2_fixed;
  467.     cairo_fixed_t dx3_fixed, dy3_fixed;
  468.  
  469.     if (cr->path_is_rectangle) {
  470.         status = _flush_cr_rectangle (cr);
  471.         if (unlikely (status))
  472.             return status;
  473.     }
  474.  
  475.     status = cr->dev->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3);
  476.     if (unlikely (status))
  477.         return status;
  478.  
  479.     dx1_fixed = _cairo_fixed_from_double (dx1);
  480.     dy1_fixed = _cairo_fixed_from_double (dy1);
  481.  
  482.     dx2_fixed = _cairo_fixed_from_double (dx2);
  483.     dy2_fixed = _cairo_fixed_from_double (dy2);
  484.  
  485.     dx3_fixed = _cairo_fixed_from_double (dx3);
  486.     dy3_fixed = _cairo_fixed_from_double (dy3);
  487.  
  488.     if (cr->user_path.buf.base.num_ops == 0)
  489.         cr->path_ctm_age = 0;
  490.  
  491.     return _cairo_path_fixed_rel_curve_to (&cr->user_path,
  492.                                            dx1_fixed, dy1_fixed,
  493.                                            dx2_fixed, dy2_fixed,
  494.                                            dx3_fixed, dy3_fixed);
  495. }
  496.  
  497. #if 0
  498. static cairo_status_t
  499. _cairo_cogl_context_arc_to (void *abstract_cr,
  500.                             double x1, double y1,
  501.                             double x2, double y2,
  502.                             double radius)
  503. {
  504.     cairo_cogl_context_t *cr = abstract_cr;
  505.     cairo_status_t status;
  506.  
  507.     if (cr->path_is_rectangle) {
  508.         status = _flush_cr_rectangle (cr);
  509.         if (unlikely (status))
  510.             return status;
  511.     }
  512.  
  513.     status = cr->dev->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius);
  514.     if (unlikely (status))
  515.         return status;
  516. #warning "FIXME"
  517. }
  518.  
  519. static cairo_status_t
  520. _cairo_cogl_rel_arc_to (void *cr,
  521.                         double dx1, double dy1,
  522.                         double dx2, double dy2,
  523.                         double radius)
  524. {
  525.     cairo_cogl_context_t *cr = abstract_cr;
  526.     cairo_status_t status;
  527.  
  528.     if (cr->path_is_rectangle) {
  529.         status = _flush_cr_rectangle (cr);
  530.         if (unlikely (status))
  531.             return status;
  532.     }
  533.  
  534.     status = cr->dev->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius);
  535.     if (unlikely (status))
  536.         return status;
  537. #warning "FIXME"
  538. }
  539. #endif
  540.  
  541. static cairo_status_t
  542. _cairo_cogl_context_close_path (void *abstract_cr)
  543. {
  544.     cairo_cogl_context_t *cr = abstract_cr;
  545.     cairo_status_t status;
  546.  
  547.     if (cr->path_is_rectangle) {
  548.         status = _flush_cr_rectangle (cr);
  549.         if (unlikely (status))
  550.             return status;
  551.     }
  552.  
  553.     status = cr->dev->backend_parent.close_path (abstract_cr);
  554.     if (unlikely (status))
  555.         return status;
  556.  
  557.     if (cr->user_path.buf.base.num_ops == 0)
  558.         cr->path_ctm_age = 0;
  559.  
  560.     return _cairo_path_fixed_close_path (&cr->user_path);
  561. }
  562.  
  563. static cairo_status_t
  564. _cairo_cogl_context_rectangle (void *abstract_cr,
  565.                                double x, double y,
  566.                                double width, double height)
  567. {
  568.     cairo_cogl_context_t *cr = abstract_cr;
  569.  
  570.     if (cr->user_path.buf.base.num_ops == 0) {
  571.         cr->path_ctm_age = 0;
  572.  
  573. #if 1
  574.         /* XXX: Since drawing rectangles is so common we have a
  575.          * fast-path for drawing a single rectangle. */
  576.         cr->x = x;
  577.         cr->y = y;
  578.         cr->width = width;
  579.         cr->height = height;
  580.         cr->path_is_rectangle = TRUE;
  581.         return CAIRO_STATUS_SUCCESS;
  582. #endif
  583.     }
  584.  
  585.     if (cr->path_is_rectangle) {
  586.         cairo_status_t status = _flush_cr_rectangle (cr);
  587.         if (unlikely (status))
  588.             return status;
  589.     }
  590.  
  591.     return _cairo_cogl_context_rectangle_real (cr, x, y, width, height);
  592. }
  593.  
  594. /* Since the surface backend drawing operator functions don't get
  595.  * passed the current #cairo_t context we don't have a good way
  596.  * to get our user-coordinates path into our surface operator
  597.  * functions.
  598.  *
  599.  * For now we use this function to set side band data on the surface
  600.  * itself.
  601.  */
  602. static void
  603. _cairo_cogl_surface_set_side_band_state (cairo_cogl_surface_t *surface,
  604.                                          cairo_cogl_context_t *cr)
  605. {
  606.  
  607.     if (cr->path_ctm_age <= 1) {
  608.         surface->user_path = &cr->user_path;
  609.         surface->ctm = &cr->base.gstate->ctm;
  610.         surface->ctm_inverse = &cr->base.gstate->ctm_inverse;
  611.         surface->path_is_rectangle = cr->path_is_rectangle;
  612.         if (surface->path_is_rectangle) {
  613.             surface->path_rectangle_x = cr->x;
  614.             surface->path_rectangle_y = cr->y;
  615.             surface->path_rectangle_width = cr->width;
  616.             surface->path_rectangle_height = cr->height;
  617.         }
  618.     } else {
  619.         surface->user_path = NULL;
  620.         surface->path_is_rectangle = FALSE;
  621.     }
  622. }
  623.  
  624. static cairo_status_t
  625. _cairo_cogl_context_fill (void *abstract_cr)
  626. {
  627.     cairo_cogl_context_t *cr = abstract_cr;
  628.     cairo_status_t status;
  629.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
  630.  
  631.     if (cr->path_is_rectangle) {
  632.         status = _cairo_cogl_surface_fill_rectangle (cr->base.gstate->target,
  633.                                                      cr->base.gstate->op,
  634.                                                      cr->base.gstate->source,
  635.                                                      cr->x,
  636.                                                      cr->y,
  637.                                                      cr->width,
  638.                                                      cr->height,
  639.                                                      &cr->base.gstate->ctm,
  640.                                                      cr->base.gstate->clip);
  641.         if (status == CAIRO_STATUS_SUCCESS)
  642.             goto DONE;
  643.         _flush_cr_rectangle (cr);
  644.     }
  645.  
  646.     _cairo_cogl_surface_set_side_band_state (surface, cr);
  647.  
  648.     status = cr->dev->backend_parent.fill (abstract_cr);
  649.     if (unlikely (status))
  650.         return status;
  651.  
  652. DONE:
  653.     _cairo_path_fixed_fini (&cr->user_path);
  654.     _cairo_path_fixed_init (&cr->user_path);
  655.     cr->path_is_rectangle = FALSE;
  656.  
  657.     return CAIRO_STATUS_SUCCESS;
  658. }
  659.  
  660. static cairo_status_t
  661. _cairo_cogl_context_fill_preserve (void *abstract_cr)
  662. {
  663.     cairo_cogl_context_t *cr = abstract_cr;
  664.     cairo_status_t status;
  665.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
  666.  
  667.     _cairo_cogl_surface_set_side_band_state (surface, cr);
  668.  
  669.     status = cr->dev->backend_parent.fill_preserve (abstract_cr);
  670.     if (unlikely (status))
  671.         return status;
  672.  
  673.     return CAIRO_STATUS_SUCCESS;
  674. }
  675.  
  676. static cairo_status_t
  677. _cairo_cogl_context_stroke (void *abstract_cr)
  678. {
  679.     cairo_cogl_context_t *cr = abstract_cr;
  680.     cairo_status_t status;
  681.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
  682.  
  683.     _cairo_cogl_surface_set_side_band_state (surface, cr);
  684.  
  685.     status = cr->dev->backend_parent.stroke (abstract_cr);
  686.     if (unlikely (status))
  687.         return status;
  688.  
  689.     _cairo_path_fixed_fini (&cr->user_path);
  690.     _cairo_path_fixed_init (&cr->user_path);
  691.     cr->path_is_rectangle = FALSE;
  692.  
  693.     return CAIRO_STATUS_SUCCESS;
  694. }
  695.  
  696. static cairo_status_t
  697. _cairo_cogl_context_stroke_preserve (void *abstract_cr)
  698. {
  699.     cairo_cogl_context_t *cr = abstract_cr;
  700.     cairo_status_t status;
  701.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
  702.  
  703.     _cairo_cogl_surface_set_side_band_state (surface, cr);
  704.  
  705.     status = cr->dev->backend_parent.stroke_preserve (abstract_cr);
  706.     if (unlikely (status))
  707.         return status;
  708.  
  709.     return CAIRO_STATUS_SUCCESS;
  710. }
  711.  
  712. static cairo_status_t
  713. _cairo_cogl_context_clip (void *abstract_cr)
  714. {
  715.     cairo_cogl_context_t *cr = abstract_cr;
  716.     cairo_status_t status;
  717.  
  718.     status = cr->dev->backend_parent.clip (abstract_cr);
  719.     if (unlikely (status))
  720.         return status;
  721.  
  722.     _cairo_path_fixed_fini (&cr->user_path);
  723.     _cairo_path_fixed_init (&cr->user_path);
  724.     cr->path_is_rectangle = FALSE;
  725.  
  726.     return CAIRO_STATUS_SUCCESS;
  727. }
  728.  
  729. static void
  730. _cairo_cogl_context_destroy (void *abstract_cr)
  731. {
  732.     cairo_cogl_context_t *cr = abstract_cr;
  733.  
  734.     _cairo_default_context_fini (&cr->base);
  735.  
  736.     _cairo_path_fixed_fini (&cr->user_path);
  737.  
  738.     /* mark the context as invalid to protect against misuse */
  739.     cr->base.base.status = CAIRO_STATUS_NULL_POINTER;
  740.     _freed_pool_put (&context_pool, cr);
  741. }
  742.  
  743. /* We want to hook into the frontend of the path construction APIs so
  744.  * we can build up a path description in user coordinates instead of
  745.  * backend coordinates so that we can recognize user coordinate
  746.  * rectangles and so we can hash a user path independent of its
  747.  * transform. (With some care to catch unusual cases where the ctm
  748.  * changes mid-path) */
  749. cairo_t *
  750. _cairo_cogl_context_create (void *target)
  751. {
  752.     cairo_cogl_surface_t *surface = target;
  753.     cairo_cogl_context_t *cr;
  754.     cairo_status_t status;
  755.  
  756.     cr = _freed_pool_get (&context_pool);
  757.     if (unlikely (cr == NULL)) {
  758.         cr = malloc (sizeof (cairo_cogl_context_t));
  759.         if (unlikely (cr == NULL))
  760.             return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  761.     }
  762.  
  763.     status = _cairo_default_context_init (&cr->base, target);
  764.     if (unlikely (status)) {
  765.         _freed_pool_put (&context_pool, cr);
  766.         return _cairo_create_in_error (status);
  767.     }
  768.  
  769.     cr->dev = (cairo_cogl_device_t *)surface->base.device;
  770.  
  771.     if (unlikely (cr->dev->backend_vtable_initialized == FALSE)) {
  772.         cairo_backend_t *backend = &cr->dev->backend;
  773.         memcpy (backend, cr->base.base.backend, sizeof (cairo_backend_t));
  774.         memcpy (&cr->dev->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t));
  775.  
  776.         backend->destroy = _cairo_cogl_context_destroy;
  777.  
  778.         backend->restore = _cairo_cogl_context_restore;
  779.         backend->translate = _cairo_cogl_context_translate;
  780.         backend->scale = _cairo_cogl_context_scale;
  781.         backend->rotate = _cairo_cogl_context_rotate;
  782.         backend->transform = _cairo_cogl_context_transform;
  783.         backend->set_matrix = _cairo_cogl_context_set_matrix;
  784.         backend->set_identity_matrix = _cairo_cogl_context_set_identity_matrix;
  785.  
  786.         backend->new_path = _cairo_cogl_context_new_path;
  787.         backend->new_sub_path = _cairo_cogl_context_new_sub_path;
  788.         backend->move_to = _cairo_cogl_context_move_to;
  789.         backend->rel_move_to = _cairo_cogl_context_rel_move_to;
  790.         backend->line_to = _cairo_cogl_context_line_to;
  791.         backend->rel_line_to = _cairo_cogl_context_rel_line_to;
  792.         backend->curve_to = _cairo_cogl_context_curve_to;
  793.         backend->rel_curve_to = _cairo_cogl_context_rel_curve_to;
  794. #if 0
  795.         backend->arc_to = _cairo_cogl_context_arc_to;
  796.         backend->rel_arc_to = _cairo_cogl_context_rel_arc_to;
  797. #endif
  798.         backend->close_path = _cairo_cogl_context_close_path;
  799.         //backend->arc = _cairo_cogl_context_arc;
  800.         backend->rectangle = _cairo_cogl_context_rectangle;
  801.  
  802.         /* Try to automatically catch if any new path APIs are added that mean
  803.          * we may need to overload more functions... */
  804.         assert (((char *)&backend->path_extents - (char *)&backend->device_to_user_distance)
  805.                 == (sizeof (void *) * 14));
  806.  
  807.         backend->fill = _cairo_cogl_context_fill;
  808.         backend->fill_preserve = _cairo_cogl_context_fill_preserve;
  809.         backend->stroke = _cairo_cogl_context_stroke;
  810.         backend->stroke_preserve = _cairo_cogl_context_stroke_preserve;
  811.         backend->clip = _cairo_cogl_context_clip;
  812.  
  813.         cr->dev->backend_vtable_initialized = TRUE;
  814.     }
  815.  
  816.     cr->base.base.backend = &cr->dev->backend;
  817.  
  818.     _cairo_path_fixed_init (&cr->user_path);
  819.     cr->path_is_rectangle = FALSE;
  820.  
  821.     return &cr->base.base;
  822. }
  823.