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.org/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.  * The Original Code is the cairo graphics library.
  29.  *
  30.  * The Initial Developer of the Original Code is Intel Corporation.
  31.  *
  32.  * Contributor(s):
  33.  *      Chris Wilson <chris@chris-wilson.co.uk>
  34.  */
  35.  
  36. #include "cairoint.h"
  37.  
  38. #include "cairo-surface-observer-private.h"
  39. #include "cairo-surface-observer-inline.h"
  40.  
  41. #include "cairo-array-private.h"
  42. #include "cairo-combsort-inline.h"
  43. #include "cairo-composite-rectangles-private.h"
  44. #include "cairo-error-private.h"
  45. #include "cairo-image-surface-private.h"
  46. #include "cairo-list-inline.h"
  47. #include "cairo-pattern-private.h"
  48. #include "cairo-output-stream-private.h"
  49. #include "cairo-recording-surface-private.h"
  50. #include "cairo-surface-subsurface-inline.h"
  51. #include "cairo-reference-count-private.h"
  52.  
  53. #if CAIRO_HAS_SCRIPT_SURFACE
  54. #include "cairo-script-private.h"
  55. #endif
  56.  
  57. static const cairo_surface_backend_t _cairo_surface_observer_backend;
  58.  
  59. /* observation/stats */
  60.  
  61. static void init_stats (struct stat *s)
  62. {
  63.     s->min = HUGE_VAL;
  64.     s->max = -HUGE_VAL;
  65. }
  66.  
  67. static void init_extents (struct extents *e)
  68. {
  69.     init_stats (&e->area);
  70. }
  71.  
  72. static void init_pattern (struct pattern *p)
  73. {
  74. }
  75.  
  76. static void init_path (struct path *p)
  77. {
  78. }
  79.  
  80. static void init_clip (struct clip *c)
  81. {
  82. }
  83.  
  84. static void init_paint (struct paint *p)
  85. {
  86.     init_extents (&p->extents);
  87.     init_pattern (&p->source);
  88.     init_clip (&p->clip);
  89. }
  90.  
  91. static void init_mask (struct mask *m)
  92. {
  93.     init_extents (&m->extents);
  94.     init_pattern (&m->source);
  95.     init_pattern (&m->mask);
  96.     init_clip (&m->clip);
  97. }
  98.  
  99. static void init_fill (struct fill *f)
  100. {
  101.     init_extents (&f->extents);
  102.     init_pattern (&f->source);
  103.     init_path (&f->path);
  104.     init_clip (&f->clip);
  105. }
  106.  
  107. static void init_stroke (struct stroke *s)
  108. {
  109.     init_extents (&s->extents);
  110.     init_pattern (&s->source);
  111.     init_path (&s->path);
  112.     init_clip (&s->clip);
  113. }
  114.  
  115. static void init_glyphs (struct glyphs *g)
  116. {
  117.     init_extents (&g->extents);
  118.     init_pattern (&g->source);
  119.     init_clip (&g->clip);
  120. }
  121.  
  122. static cairo_status_t
  123. log_init (cairo_observation_t *log,
  124.           cairo_bool_t record)
  125. {
  126.     memset (log, 0, sizeof(*log));
  127.  
  128.     init_paint (&log->paint);
  129.     init_mask (&log->mask);
  130.     init_fill (&log->fill);
  131.     init_stroke (&log->stroke);
  132.     init_glyphs (&log->glyphs);
  133.  
  134.     _cairo_array_init (&log->timings, sizeof (cairo_observation_record_t));
  135.  
  136.     if (record) {
  137.         log->record = (cairo_recording_surface_t *)
  138.             cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
  139.         if (unlikely (log->record->base.status))
  140.             return log->record->base.status;
  141.  
  142.         log->record->optimize_clears = FALSE;
  143.     }
  144.  
  145.     return CAIRO_STATUS_SUCCESS;
  146. }
  147.  
  148. static void
  149. log_fini (cairo_observation_t *log)
  150. {
  151.     _cairo_array_fini (&log->timings);
  152.     cairo_surface_destroy (&log->record->base);
  153. }
  154.  
  155. static cairo_surface_t*
  156. get_pattern_surface (const cairo_pattern_t *pattern)
  157. {
  158.     return ((cairo_surface_pattern_t *)pattern)->surface;
  159. }
  160.  
  161. static int
  162. classify_pattern (const cairo_pattern_t *pattern,
  163.                   const cairo_surface_t *target)
  164. {
  165.     int classify;
  166.  
  167.     switch (pattern->type) {
  168.     case CAIRO_PATTERN_TYPE_SURFACE:
  169.         if (get_pattern_surface (pattern)->type == target->type)
  170.             classify = 0;
  171.         else if (get_pattern_surface (pattern)->type == CAIRO_SURFACE_TYPE_RECORDING)
  172.             classify = 1;
  173.         else
  174.             classify = 2;
  175.         break;
  176.     default:
  177.     case CAIRO_PATTERN_TYPE_SOLID:
  178.         classify = 3;
  179.         break;
  180.     case CAIRO_PATTERN_TYPE_LINEAR:
  181.         classify = 4;
  182.         break;
  183.     case CAIRO_PATTERN_TYPE_RADIAL:
  184.         classify = 5;
  185.         break;
  186.     case CAIRO_PATTERN_TYPE_MESH:
  187.         classify = 6;
  188.         break;
  189.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  190.         classify = 7;
  191.         break;
  192.     }
  193.     return classify;
  194. }
  195.  
  196. static void
  197. add_pattern (struct pattern *stats,
  198.              const cairo_pattern_t *pattern,
  199.              const cairo_surface_t *target)
  200. {
  201.     stats->type[classify_pattern(pattern, target)]++;
  202. }
  203.  
  204. static int
  205. classify_path (const cairo_path_fixed_t *path,
  206.                cairo_bool_t is_fill)
  207. {
  208.     int classify;
  209.  
  210.     /* XXX improve for stroke */
  211.     classify = -1;
  212.     if (is_fill) {
  213.         if (path->fill_is_empty)
  214.             classify = 0;
  215.         else if (_cairo_path_fixed_fill_is_rectilinear (path))
  216.             classify = path->fill_maybe_region ? 1 : 2;
  217.     } else {
  218.         if (_cairo_path_fixed_stroke_is_rectilinear (path))
  219.             classify = 2;
  220.     }
  221.     if (classify == -1)
  222.         classify = 3 + (path->has_curve_to != 0);
  223.  
  224.     return classify;
  225. }
  226.  
  227. static void
  228. add_path (struct path *stats,
  229.           const cairo_path_fixed_t *path,
  230.           cairo_bool_t is_fill)
  231. {
  232.     stats->type[classify_path(path, is_fill)]++;
  233. }
  234.  
  235. static int
  236. classify_clip (const cairo_clip_t *clip)
  237. {
  238.     int classify;
  239.  
  240.     if (clip == NULL)
  241.         classify = 0;
  242.     else if (_cairo_clip_is_region (clip))
  243.         classify = 1;
  244.     else if (clip->path == NULL)
  245.         classify = 2;
  246.     else if (clip->path->prev == NULL)
  247.         classify = 3;
  248.     else if (_cairo_clip_is_polygon (clip))
  249.         classify = 4;
  250.     else
  251.         classify = 5;
  252.  
  253.     return classify;
  254. }
  255.  
  256. static void
  257. add_clip (struct clip *stats,
  258.           const cairo_clip_t *clip)
  259. {
  260.     stats->type[classify_clip (clip)]++;
  261. }
  262.  
  263. static void
  264. stats_add (struct stat *s, double v)
  265. {
  266.     if (v < s->min)
  267.         s->min = v;
  268.     if (v > s->max)
  269.         s->max = v;
  270.     s->sum += v;
  271.     s->sum_sq += v*v;
  272.     s->count++;
  273. }
  274.  
  275. static void
  276. add_extents (struct extents *stats,
  277.              const cairo_composite_rectangles_t *extents)
  278. {
  279.     const cairo_rectangle_int_t *r = extents->is_bounded ? &extents->bounded :&extents->unbounded;
  280.     stats_add (&stats->area, r->width * r->height);
  281.     stats->bounded += extents->is_bounded != 0;
  282.     stats->unbounded += extents->is_bounded == 0;
  283. }
  284.  
  285. /* device interface */
  286.  
  287. static void
  288. _cairo_device_observer_lock (void *_device)
  289. {
  290.     cairo_device_observer_t *device = (cairo_device_observer_t *) _device;
  291.     cairo_status_t ignored;
  292.  
  293.     /* cairo_device_acquire() can fail for nil and finished
  294.      * devices. We don't care about observing them. */
  295.     ignored = cairo_device_acquire (device->target);
  296. }
  297.  
  298. static void
  299. _cairo_device_observer_unlock (void *_device)
  300. {
  301.     cairo_device_observer_t *device = (cairo_device_observer_t *) _device;
  302.     cairo_device_release (device->target);
  303. }
  304.  
  305. static cairo_status_t
  306. _cairo_device_observer_flush (void *_device)
  307. {
  308.     cairo_device_observer_t *device = (cairo_device_observer_t *) _device;
  309.  
  310.     if (device->target == NULL)
  311.         return CAIRO_STATUS_SUCCESS;
  312.  
  313.     cairo_device_flush (device->target);
  314.     return device->target->status;
  315. }
  316.  
  317. static void
  318. _cairo_device_observer_finish (void *_device)
  319. {
  320.     cairo_device_observer_t *device = (cairo_device_observer_t *) _device;
  321.     log_fini (&device->log);
  322.     cairo_device_finish (device->target);
  323. }
  324.  
  325. static void
  326. _cairo_device_observer_destroy (void *_device)
  327. {
  328.     cairo_device_observer_t *device = (cairo_device_observer_t *) _device;
  329.     cairo_device_destroy (device->target);
  330.     free (device);
  331. }
  332.  
  333. static const cairo_device_backend_t _cairo_device_observer_backend = {
  334.     CAIRO_INTERNAL_DEVICE_TYPE_OBSERVER,
  335.  
  336.     _cairo_device_observer_lock,
  337.     _cairo_device_observer_unlock,
  338.  
  339.     _cairo_device_observer_flush,
  340.     _cairo_device_observer_finish,
  341.     _cairo_device_observer_destroy,
  342. };
  343.  
  344. static cairo_device_t *
  345. _cairo_device_create_observer_internal (cairo_device_t *target,
  346.                                         cairo_bool_t record)
  347. {
  348.     cairo_device_observer_t *device;
  349.     cairo_status_t status;
  350.  
  351.     device = malloc (sizeof (cairo_device_observer_t));
  352.     if (unlikely (device == NULL))
  353.         return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  354.  
  355.     _cairo_device_init (&device->base, &_cairo_device_observer_backend);
  356.     status = log_init (&device->log, record);
  357.     if (unlikely (status)) {
  358.         free (device);
  359.         return _cairo_device_create_in_error (status);
  360.     }
  361.  
  362.     device->target = cairo_device_reference (target);
  363.  
  364.     return &device->base;
  365. }
  366.  
  367. /* surface interface */
  368.  
  369. static cairo_device_observer_t *
  370. to_device (cairo_surface_observer_t *suface)
  371. {
  372.     return (cairo_device_observer_t *)suface->base.device;
  373. }
  374.  
  375. static cairo_surface_t *
  376. _cairo_surface_create_observer_internal (cairo_device_t *device,
  377.                                          cairo_surface_t *target)
  378. {
  379.     cairo_surface_observer_t *surface;
  380.     cairo_status_t status;
  381.  
  382.     surface = malloc (sizeof (cairo_surface_observer_t));
  383.     if (unlikely (surface == NULL))
  384.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  385.  
  386.     _cairo_surface_init (&surface->base,
  387.                          &_cairo_surface_observer_backend, device,
  388.                          target->content);
  389.  
  390.     status = log_init (&surface->log,
  391.                        ((cairo_device_observer_t *)device)->log.record != NULL);
  392.     if (unlikely (status)) {
  393.         free (surface);
  394.         return _cairo_surface_create_in_error (status);
  395.     }
  396.  
  397.     surface->target = cairo_surface_reference (target);
  398.     surface->base.type = surface->target->type;
  399.     surface->base.is_clear = surface->target->is_clear;
  400.  
  401.     cairo_list_init (&surface->paint_callbacks);
  402.     cairo_list_init (&surface->mask_callbacks);
  403.     cairo_list_init (&surface->fill_callbacks);
  404.     cairo_list_init (&surface->stroke_callbacks);
  405.     cairo_list_init (&surface->glyphs_callbacks);
  406.  
  407.     cairo_list_init (&surface->flush_callbacks);
  408.     cairo_list_init (&surface->finish_callbacks);
  409.  
  410.     surface->log.num_surfaces++;
  411.     to_device (surface)->log.num_surfaces++;
  412.  
  413.     return &surface->base;
  414. }
  415.  
  416. static inline void
  417. do_callbacks (cairo_surface_observer_t *surface, cairo_list_t *head)
  418. {
  419.     struct callback_list *cb;
  420.  
  421.     cairo_list_foreach_entry (cb, struct callback_list, head, link)
  422.         cb->func (&surface->base, surface->target, cb->data);
  423. }
  424.  
  425.  
  426. static cairo_status_t
  427. _cairo_surface_observer_finish (void *abstract_surface)
  428. {
  429.     cairo_surface_observer_t *surface = abstract_surface;
  430.  
  431.     do_callbacks (surface, &surface->finish_callbacks);
  432.  
  433.     cairo_surface_destroy (surface->target);
  434.     log_fini (&surface->log);
  435.  
  436.     return CAIRO_STATUS_SUCCESS;
  437. }
  438.  
  439. static cairo_surface_t *
  440. _cairo_surface_observer_create_similar (void *abstract_other,
  441.                                         cairo_content_t content,
  442.                                         int width, int height)
  443. {
  444.     cairo_surface_observer_t *other = abstract_other;
  445.     cairo_surface_t *target, *surface;
  446.  
  447.     target = NULL;
  448.     if (other->target->backend->create_similar)
  449.         target = other->target->backend->create_similar (other->target, content,
  450.                                                          width, height);
  451.     if (target == NULL)
  452.         target = _cairo_image_surface_create_with_content (content,
  453.                                                            width, height);
  454.  
  455.     surface = _cairo_surface_create_observer_internal (other->base.device,
  456.                                                        target);
  457.     cairo_surface_destroy (target);
  458.  
  459.     return surface;
  460. }
  461.  
  462. static cairo_surface_t *
  463. _cairo_surface_observer_create_similar_image (void *other,
  464.                                               cairo_format_t format,
  465.                                               int width, int height)
  466. {
  467.     cairo_surface_observer_t *surface = other;
  468.  
  469.     if (surface->target->backend->create_similar_image)
  470.         return surface->target->backend->create_similar_image (surface->target,
  471.                                                                format,
  472.                                                                width, height);
  473.  
  474.     return NULL;
  475. }
  476.  
  477. static cairo_image_surface_t *
  478. _cairo_surface_observer_map_to_image (void *abstract_surface,
  479.                                       const cairo_rectangle_int_t *extents)
  480. {
  481.     cairo_surface_observer_t *surface = abstract_surface;
  482.     return _cairo_surface_map_to_image (surface->target, extents);
  483. }
  484.  
  485. static cairo_int_status_t
  486. _cairo_surface_observer_unmap_image (void *abstract_surface,
  487.                                      cairo_image_surface_t *image)
  488. {
  489.     cairo_surface_observer_t *surface = abstract_surface;
  490.     return _cairo_surface_unmap_image (surface->target, image);
  491. }
  492.  
  493. static void
  494. record_target (cairo_observation_record_t *r,
  495.                cairo_surface_t *target)
  496. {
  497.     cairo_rectangle_int_t extents;
  498.  
  499.     r->target_content = target->content;
  500.     if (_cairo_surface_get_extents (target, &extents)) {
  501.         r->target_width = extents.width;
  502.         r->target_height = extents.height;
  503.     } else {
  504.         r->target_width = -1;
  505.         r->target_height = -1;
  506.     }
  507. }
  508.  
  509. static cairo_observation_record_t *
  510. record_paint (cairo_observation_record_t *r,
  511.               cairo_surface_t *target,
  512.               cairo_operator_t op,
  513.               const cairo_pattern_t *source,
  514.               const cairo_clip_t *clip,
  515.               cairo_time_t elapsed)
  516. {
  517.     record_target (r, target);
  518.  
  519.     r->op = op;
  520.     r->source = classify_pattern (source, target);
  521.     r->mask = -1;
  522.     r->num_glyphs = -1;
  523.     r->path = -1;
  524.     r->fill_rule = -1;
  525.     r->tolerance = -1;
  526.     r->antialias = -1;
  527.     r->clip = classify_clip (clip);
  528.     r->elapsed = elapsed;
  529.  
  530.     return r;
  531. }
  532.  
  533. static cairo_observation_record_t *
  534. record_mask (cairo_observation_record_t *r,
  535.              cairo_surface_t *target,
  536.              cairo_operator_t op,
  537.              const cairo_pattern_t *source,
  538.              const cairo_pattern_t *mask,
  539.              const cairo_clip_t *clip,
  540.              cairo_time_t elapsed)
  541. {
  542.     record_target (r, target);
  543.  
  544.     r->op = op;
  545.     r->source = classify_pattern (source, target);
  546.     r->mask = classify_pattern (mask, target);
  547.     r->num_glyphs = -1;
  548.     r->path = -1;
  549.     r->fill_rule = -1;
  550.     r->tolerance = -1;
  551.     r->antialias = -1;
  552.     r->clip = classify_clip (clip);
  553.     r->elapsed = elapsed;
  554.  
  555.     return r;
  556. }
  557.  
  558. static cairo_observation_record_t *
  559. record_fill (cairo_observation_record_t *r,
  560.              cairo_surface_t            *target,
  561.              cairo_operator_t           op,
  562.              const cairo_pattern_t      *source,
  563.              const cairo_path_fixed_t   *path,
  564.              cairo_fill_rule_t           fill_rule,
  565.              double                      tolerance,
  566.              cairo_antialias_t           antialias,
  567.              const cairo_clip_t         *clip,
  568.              cairo_time_t elapsed)
  569. {
  570.     record_target (r, target);
  571.  
  572.     r->op = op;
  573.     r->source = classify_pattern (source, target);
  574.     r->mask = -1;
  575.     r->num_glyphs = -1;
  576.     r->path = classify_path (path, TRUE);
  577.     r->fill_rule = fill_rule;
  578.     r->tolerance = tolerance;
  579.     r->antialias = antialias;
  580.     r->clip = classify_clip (clip);
  581.     r->elapsed = elapsed;
  582.  
  583.     return r;
  584. }
  585.  
  586. static cairo_observation_record_t *
  587. record_stroke (cairo_observation_record_t *r,
  588.                cairo_surface_t          *target,
  589.                cairo_operator_t         op,
  590.                const cairo_pattern_t    *source,
  591.                const cairo_path_fixed_t *path,
  592.                const cairo_stroke_style_t       *style,
  593.                const cairo_matrix_t     *ctm,
  594.                const cairo_matrix_t     *ctm_inverse,
  595.                double                    tolerance,
  596.                cairo_antialias_t         antialias,
  597.                const cairo_clip_t       *clip,
  598.                cairo_time_t              elapsed)
  599. {
  600.     record_target (r, target);
  601.  
  602.     r->op = op;
  603.     r->source = classify_pattern (source, target);
  604.     r->mask = -1;
  605.     r->num_glyphs = -1;
  606.     r->path = classify_path (path, FALSE);
  607.     r->fill_rule = -1;
  608.     r->tolerance = tolerance;
  609.     r->antialias = antialias;
  610.     r->clip = classify_clip (clip);
  611.     r->elapsed = elapsed;
  612.  
  613.     return r;
  614. }
  615.  
  616. static cairo_observation_record_t *
  617. record_glyphs (cairo_observation_record_t *r,
  618.                cairo_surface_t          *target,
  619.                cairo_operator_t         op,
  620.                const cairo_pattern_t    *source,
  621.                cairo_glyph_t            *glyphs,
  622.                int                       num_glyphs,
  623.                cairo_scaled_font_t      *scaled_font,
  624.                const cairo_clip_t       *clip,
  625.                cairo_time_t              elapsed)
  626. {
  627.     record_target (r, target);
  628.  
  629.     r->op = op;
  630.     r->source = classify_pattern (source, target);
  631.     r->mask = -1;
  632.     r->path = -1;
  633.     r->num_glyphs = num_glyphs;
  634.     r->fill_rule = -1;
  635.     r->tolerance = -1;
  636.     r->antialias = -1;
  637.     r->clip = classify_clip (clip);
  638.     r->elapsed = elapsed;
  639.  
  640.     return r;
  641. }
  642.  
  643. static void
  644. add_record (cairo_observation_t *log,
  645.             cairo_observation_record_t *r)
  646. {
  647.     cairo_int_status_t status;
  648.  
  649.     r->index = log->record ? log->record->commands.num_elements : 0;
  650.  
  651.     status = _cairo_array_append (&log->timings, r);
  652.     assert (status == CAIRO_INT_STATUS_SUCCESS);
  653. }
  654.  
  655. static void
  656. sync (cairo_surface_t *target, int x, int y)
  657. {
  658.     cairo_rectangle_int_t extents;
  659.  
  660.     extents.x = x;
  661.     extents.y = y;
  662.     extents.width  = 1;
  663.     extents.height = 1;
  664.  
  665.     _cairo_surface_unmap_image (target,
  666.                                 _cairo_surface_map_to_image (target,
  667.                                                              &extents));
  668. }
  669.  
  670. static void
  671. midpt (const cairo_composite_rectangles_t *extents, int *x, int *y)
  672. {
  673.     *x = extents->bounded.x + extents->bounded.width / 2;
  674.     *y = extents->bounded.y + extents->bounded.height / 2;
  675. }
  676.  
  677. static void
  678. add_record_paint (cairo_observation_t *log,
  679.                  cairo_surface_t *target,
  680.                  cairo_operator_t op,
  681.                  const cairo_pattern_t *source,
  682.                  const cairo_clip_t *clip,
  683.                  cairo_time_t elapsed)
  684. {
  685.     cairo_observation_record_t record;
  686.     cairo_int_status_t status;
  687.  
  688.     add_record (log,
  689.                 record_paint (&record, target, op, source, clip, elapsed));
  690.  
  691.     /* We have to bypass the high-level surface layer in case it tries to be
  692.      * too smart and discard operations; we need to record exactly what just
  693.      * happened on the target.
  694.      */
  695.     if (log->record) {
  696.         status = log->record->base.backend->paint (&log->record->base,
  697.                                                    op, source, clip);
  698.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  699.     }
  700.  
  701.     if (_cairo_time_gt (elapsed, log->paint.slowest.elapsed))
  702.         log->paint.slowest = record;
  703.     log->paint.elapsed = _cairo_time_add (log->paint.elapsed, elapsed);
  704. }
  705.  
  706. static cairo_int_status_t
  707. _cairo_surface_observer_paint (void *abstract_surface,
  708.                                cairo_operator_t op,
  709.                                const cairo_pattern_t *source,
  710.                                const cairo_clip_t *clip)
  711. {
  712.     cairo_surface_observer_t *surface = abstract_surface;
  713.     cairo_device_observer_t *device = to_device (surface);
  714.     cairo_composite_rectangles_t composite;
  715.     cairo_int_status_t status;
  716.     cairo_time_t t;
  717.     int x, y;
  718.  
  719.     /* XXX device locking */
  720.  
  721.     surface->log.paint.count++;
  722.     surface->log.paint.operators[op]++;
  723.     add_pattern (&surface->log.paint.source, source, surface->target);
  724.     add_clip (&surface->log.paint.clip, clip);
  725.  
  726.     device->log.paint.count++;
  727.     device->log.paint.operators[op]++;
  728.     add_pattern (&device->log.paint.source, source, surface->target);
  729.     add_clip (&device->log.paint.clip, clip);
  730.  
  731.     status = _cairo_composite_rectangles_init_for_paint (&composite,
  732.                                                          surface->target,
  733.                                                          op, source,
  734.                                                          clip);
  735.     if (unlikely (status)) {
  736.         surface->log.paint.noop++;
  737.         device->log.paint.noop++;
  738.         return status;
  739.     }
  740.  
  741.     midpt (&composite, &x, &y);
  742.  
  743.     add_extents (&surface->log.paint.extents, &composite);
  744.     add_extents (&device->log.paint.extents, &composite);
  745.     _cairo_composite_rectangles_fini (&composite);
  746.  
  747.     t = _cairo_time_get ();
  748.     status = _cairo_surface_paint (surface->target,
  749.                                    op, source,
  750.                                    clip);
  751.     if (unlikely (status))
  752.         return status;
  753.  
  754.     sync (surface->target, x, y);
  755.     t = _cairo_time_get_delta (t);
  756.  
  757.     add_record_paint (&surface->log, surface->target, op, source, clip, t);
  758.     add_record_paint (&device->log, surface->target, op, source, clip, t);
  759.  
  760.     do_callbacks (surface, &surface->paint_callbacks);
  761.  
  762.     return CAIRO_STATUS_SUCCESS;
  763. }
  764.  
  765. static void
  766. add_record_mask (cairo_observation_t *log,
  767.                  cairo_surface_t *target,
  768.                  cairo_operator_t op,
  769.                  const cairo_pattern_t *source,
  770.                  const cairo_pattern_t *mask,
  771.                  const cairo_clip_t *clip,
  772.                  cairo_time_t elapsed)
  773. {
  774.     cairo_observation_record_t record;
  775.     cairo_int_status_t status;
  776.  
  777.     add_record (log,
  778.                 record_mask (&record, target, op, source, mask, clip, elapsed));
  779.  
  780.     if (log->record) {
  781.         status = log->record->base.backend->mask (&log->record->base,
  782.                                                   op, source, mask, clip);
  783.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  784.     }
  785.  
  786.     if (_cairo_time_gt (elapsed, log->mask.slowest.elapsed))
  787.         log->mask.slowest = record;
  788.     log->mask.elapsed = _cairo_time_add (log->mask.elapsed, elapsed);
  789. }
  790.  
  791. static cairo_int_status_t
  792. _cairo_surface_observer_mask (void *abstract_surface,
  793.                               cairo_operator_t op,
  794.                               const cairo_pattern_t *source,
  795.                               const cairo_pattern_t *mask,
  796.                               const cairo_clip_t *clip)
  797. {
  798.     cairo_surface_observer_t *surface = abstract_surface;
  799.     cairo_device_observer_t *device = to_device (surface);
  800.     cairo_composite_rectangles_t composite;
  801.     cairo_int_status_t status;
  802.     cairo_time_t t;
  803.     int x, y;
  804.  
  805.     surface->log.mask.count++;
  806.     surface->log.mask.operators[op]++;
  807.     add_pattern (&surface->log.mask.source, source, surface->target);
  808.     add_pattern (&surface->log.mask.mask, mask, surface->target);
  809.     add_clip (&surface->log.mask.clip, clip);
  810.  
  811.     device->log.mask.count++;
  812.     device->log.mask.operators[op]++;
  813.     add_pattern (&device->log.mask.source, source, surface->target);
  814.     add_pattern (&device->log.mask.mask, mask, surface->target);
  815.     add_clip (&device->log.mask.clip, clip);
  816.  
  817.     status = _cairo_composite_rectangles_init_for_mask (&composite,
  818.                                                         surface->target,
  819.                                                         op, source, mask,
  820.                                                         clip);
  821.     if (unlikely (status)) {
  822.         surface->log.mask.noop++;
  823.         device->log.mask.noop++;
  824.         return status;
  825.     }
  826.  
  827.     midpt (&composite, &x, &y);
  828.  
  829.     add_extents (&surface->log.mask.extents, &composite);
  830.     add_extents (&device->log.mask.extents, &composite);
  831.     _cairo_composite_rectangles_fini (&composite);
  832.  
  833.     t = _cairo_time_get ();
  834.     status =  _cairo_surface_mask (surface->target,
  835.                                    op, source, mask,
  836.                                    clip);
  837.     if (unlikely (status))
  838.         return status;
  839.  
  840.     sync (surface->target, x, y);
  841.     t = _cairo_time_get_delta (t);
  842.  
  843.     add_record_mask (&surface->log,
  844.                      surface->target, op, source, mask, clip,
  845.                      t);
  846.     add_record_mask (&device->log,
  847.                      surface->target, op, source, mask, clip,
  848.                      t);
  849.  
  850.     do_callbacks (surface, &surface->mask_callbacks);
  851.  
  852.     return CAIRO_STATUS_SUCCESS;
  853. }
  854.  
  855. static void
  856. add_record_fill (cairo_observation_t *log,
  857.                  cairo_surface_t *target,
  858.                  cairo_operator_t               op,
  859.                  const cairo_pattern_t          *source,
  860.                  const cairo_path_fixed_t       *path,
  861.                  cairo_fill_rule_t               fill_rule,
  862.                  double                          tolerance,
  863.                  cairo_antialias_t               antialias,
  864.                  const cairo_clip_t              *clip,
  865.                  cairo_time_t elapsed)
  866. {
  867.     cairo_observation_record_t record;
  868.     cairo_int_status_t status;
  869.  
  870.     add_record (log,
  871.                 record_fill (&record,
  872.                              target, op, source,
  873.                              path, fill_rule, tolerance, antialias,
  874.                              clip, elapsed));
  875.  
  876.     if (log->record) {
  877.         status = log->record->base.backend->fill (&log->record->base,
  878.                                                   op, source,
  879.                                                   path, fill_rule,
  880.                                                   tolerance, antialias,
  881.                                                   clip);
  882.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  883.     }
  884.  
  885.     if (_cairo_time_gt (elapsed, log->fill.slowest.elapsed))
  886.         log->fill.slowest = record;
  887.     log->fill.elapsed = _cairo_time_add (log->fill.elapsed, elapsed);
  888. }
  889.  
  890. static cairo_int_status_t
  891. _cairo_surface_observer_fill (void                      *abstract_surface,
  892.                               cairo_operator_t          op,
  893.                               const cairo_pattern_t     *source,
  894.                               const cairo_path_fixed_t  *path,
  895.                               cairo_fill_rule_t         fill_rule,
  896.                               double                     tolerance,
  897.                               cairo_antialias_t         antialias,
  898.                               const cairo_clip_t        *clip)
  899. {
  900.     cairo_surface_observer_t *surface = abstract_surface;
  901.     cairo_device_observer_t *device = to_device (surface);
  902.     cairo_composite_rectangles_t composite;
  903.     cairo_int_status_t status;
  904.     cairo_time_t t;
  905.     int x, y;
  906.  
  907.     surface->log.fill.count++;
  908.     surface->log.fill.operators[op]++;
  909.     surface->log.fill.fill_rule[fill_rule]++;
  910.     surface->log.fill.antialias[antialias]++;
  911.     add_pattern (&surface->log.fill.source, source, surface->target);
  912.     add_path (&surface->log.fill.path, path, TRUE);
  913.     add_clip (&surface->log.fill.clip, clip);
  914.  
  915.     device->log.fill.count++;
  916.     device->log.fill.operators[op]++;
  917.     device->log.fill.fill_rule[fill_rule]++;
  918.     device->log.fill.antialias[antialias]++;
  919.     add_pattern (&device->log.fill.source, source, surface->target);
  920.     add_path (&device->log.fill.path, path, TRUE);
  921.     add_clip (&device->log.fill.clip, clip);
  922.  
  923.     status = _cairo_composite_rectangles_init_for_fill (&composite,
  924.                                                         surface->target,
  925.                                                         op, source, path,
  926.                                                         clip);
  927.     if (unlikely (status)) {
  928.         surface->log.fill.noop++;
  929.         device->log.fill.noop++;
  930.         return status;
  931.     }
  932.  
  933.     midpt (&composite, &x, &y);
  934.  
  935.     add_extents (&surface->log.fill.extents, &composite);
  936.     add_extents (&device->log.fill.extents, &composite);
  937.     _cairo_composite_rectangles_fini (&composite);
  938.  
  939.     t = _cairo_time_get ();
  940.     status = _cairo_surface_fill (surface->target,
  941.                                   op, source, path,
  942.                                   fill_rule, tolerance, antialias,
  943.                                   clip);
  944.     if (unlikely (status))
  945.         return status;
  946.  
  947.     sync (surface->target, x, y);
  948.     t = _cairo_time_get_delta (t);
  949.  
  950.     add_record_fill (&surface->log,
  951.                      surface->target, op, source, path,
  952.                      fill_rule, tolerance, antialias,
  953.                      clip, t);
  954.  
  955.     add_record_fill (&device->log,
  956.                      surface->target, op, source, path,
  957.                      fill_rule, tolerance, antialias,
  958.                      clip, t);
  959.  
  960.     do_callbacks (surface, &surface->fill_callbacks);
  961.  
  962.     return CAIRO_STATUS_SUCCESS;
  963. }
  964.  
  965. static void
  966. add_record_stroke (cairo_observation_t *log,
  967.                  cairo_surface_t *target,
  968.                  cairo_operator_t                op,
  969.                  const cairo_pattern_t          *source,
  970.                  const cairo_path_fixed_t       *path,
  971.                  const cairo_stroke_style_t     *style,
  972.                  const cairo_matrix_t           *ctm,
  973.                  const cairo_matrix_t           *ctm_inverse,
  974.                  double                          tolerance,
  975.                  cairo_antialias_t               antialias,
  976.                  const cairo_clip_t             *clip,
  977.                  cairo_time_t elapsed)
  978. {
  979.     cairo_observation_record_t record;
  980.     cairo_int_status_t status;
  981.  
  982.     add_record (log,
  983.                 record_stroke (&record,
  984.                                target, op, source,
  985.                                path, style, ctm,ctm_inverse,
  986.                                tolerance, antialias,
  987.                                clip, elapsed));
  988.  
  989.     if (log->record) {
  990.         status = log->record->base.backend->stroke (&log->record->base,
  991.                                                     op, source,
  992.                                                     path, style, ctm,ctm_inverse,
  993.                                                     tolerance, antialias,
  994.                                                     clip);
  995.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  996.     }
  997.  
  998.     if (_cairo_time_gt (elapsed, log->stroke.slowest.elapsed))
  999.         log->stroke.slowest = record;
  1000.     log->stroke.elapsed = _cairo_time_add (log->stroke.elapsed, elapsed);
  1001. }
  1002.  
  1003. static cairo_int_status_t
  1004. _cairo_surface_observer_stroke (void                            *abstract_surface,
  1005.                                 cairo_operator_t                 op,
  1006.                                 const cairo_pattern_t           *source,
  1007.                                 const cairo_path_fixed_t        *path,
  1008.                                 const cairo_stroke_style_t      *style,
  1009.                                 const cairo_matrix_t            *ctm,
  1010.                                 const cairo_matrix_t            *ctm_inverse,
  1011.                                 double                           tolerance,
  1012.                                 cairo_antialias_t                antialias,
  1013.                                 const cairo_clip_t              *clip)
  1014. {
  1015.     cairo_surface_observer_t *surface = abstract_surface;
  1016.     cairo_device_observer_t *device = to_device (surface);
  1017.     cairo_composite_rectangles_t composite;
  1018.     cairo_int_status_t status;
  1019.     cairo_time_t t;
  1020.     int x, y;
  1021.  
  1022.     surface->log.stroke.count++;
  1023.     surface->log.stroke.operators[op]++;
  1024.     surface->log.stroke.antialias[antialias]++;
  1025.     surface->log.stroke.caps[style->line_cap]++;
  1026.     surface->log.stroke.joins[style->line_join]++;
  1027.     add_pattern (&surface->log.stroke.source, source, surface->target);
  1028.     add_path (&surface->log.stroke.path, path, FALSE);
  1029.     add_clip (&surface->log.stroke.clip, clip);
  1030.  
  1031.     device->log.stroke.count++;
  1032.     device->log.stroke.operators[op]++;
  1033.     device->log.stroke.antialias[antialias]++;
  1034.     device->log.stroke.caps[style->line_cap]++;
  1035.     device->log.stroke.joins[style->line_join]++;
  1036.     add_pattern (&device->log.stroke.source, source, surface->target);
  1037.     add_path (&device->log.stroke.path, path, FALSE);
  1038.     add_clip (&device->log.stroke.clip, clip);
  1039.  
  1040.     status = _cairo_composite_rectangles_init_for_stroke (&composite,
  1041.                                                           surface->target,
  1042.                                                           op, source,
  1043.                                                           path, style, ctm,
  1044.                                                           clip);
  1045.     if (unlikely (status)) {
  1046.         surface->log.stroke.noop++;
  1047.         device->log.stroke.noop++;
  1048.         return status;
  1049.     }
  1050.  
  1051.     midpt (&composite, &x, &y);
  1052.  
  1053.     add_extents (&surface->log.stroke.extents, &composite);
  1054.     add_extents (&device->log.stroke.extents, &composite);
  1055.     _cairo_composite_rectangles_fini (&composite);
  1056.  
  1057.     t = _cairo_time_get ();
  1058.     status = _cairo_surface_stroke (surface->target,
  1059.                                   op, source, path,
  1060.                                   style, ctm, ctm_inverse,
  1061.                                   tolerance, antialias,
  1062.                                   clip);
  1063.     if (unlikely (status))
  1064.         return status;
  1065.  
  1066.     sync (surface->target, x, y);
  1067.     t = _cairo_time_get_delta (t);
  1068.  
  1069.     add_record_stroke (&surface->log,
  1070.                        surface->target, op, source, path,
  1071.                        style, ctm,ctm_inverse,
  1072.                        tolerance, antialias,
  1073.                        clip, t);
  1074.  
  1075.     add_record_stroke (&device->log,
  1076.                        surface->target, op, source, path,
  1077.                        style, ctm,ctm_inverse,
  1078.                        tolerance, antialias,
  1079.                        clip, t);
  1080.  
  1081.     do_callbacks (surface, &surface->stroke_callbacks);
  1082.  
  1083.     return CAIRO_STATUS_SUCCESS;
  1084. }
  1085.  
  1086. static void
  1087. add_record_glyphs (cairo_observation_t  *log,
  1088.                    cairo_surface_t      *target,
  1089.                    cairo_operator_t      op,
  1090.                    const cairo_pattern_t*source,
  1091.                    cairo_glyph_t        *glyphs,
  1092.                    int                   num_glyphs,
  1093.                    cairo_scaled_font_t  *scaled_font,
  1094.                    const cairo_clip_t   *clip,
  1095.                    cairo_time_t elapsed)
  1096. {
  1097.     cairo_observation_record_t record;
  1098.     cairo_int_status_t status;
  1099.  
  1100.     add_record (log,
  1101.                 record_glyphs (&record,
  1102.                                target, op, source,
  1103.                                glyphs, num_glyphs, scaled_font,
  1104.                                clip, elapsed));
  1105.  
  1106.     if (log->record) {
  1107.         status = log->record->base.backend->show_text_glyphs (&log->record->base,
  1108.                                                               op, source,
  1109.                                                               NULL, 0,
  1110.                                                               glyphs, num_glyphs,
  1111.                                                               NULL, 0, 0,
  1112.                                                               scaled_font,
  1113.                                                               clip);
  1114.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  1115.     }
  1116.  
  1117.     if (_cairo_time_gt (elapsed, log->glyphs.slowest.elapsed))
  1118.         log->glyphs.slowest = record;
  1119.     log->glyphs.elapsed = _cairo_time_add (log->glyphs.elapsed, elapsed);
  1120. }
  1121.  
  1122. static cairo_int_status_t
  1123. _cairo_surface_observer_glyphs (void                    *abstract_surface,
  1124.                                 cairo_operator_t         op,
  1125.                                 const cairo_pattern_t   *source,
  1126.                                 cairo_glyph_t           *glyphs,
  1127.                                 int                      num_glyphs,
  1128.                                 cairo_scaled_font_t     *scaled_font,
  1129.                                 const cairo_clip_t              *clip)
  1130. {
  1131.     cairo_surface_observer_t *surface = abstract_surface;
  1132.     cairo_device_observer_t *device = to_device (surface);
  1133.     cairo_composite_rectangles_t composite;
  1134.     cairo_int_status_t status;
  1135.     cairo_glyph_t *dev_glyphs;
  1136.     cairo_time_t t;
  1137.     int x, y;
  1138.  
  1139.     surface->log.glyphs.count++;
  1140.     surface->log.glyphs.operators[op]++;
  1141.     add_pattern (&surface->log.glyphs.source, source, surface->target);
  1142.     add_clip (&surface->log.glyphs.clip, clip);
  1143.  
  1144.     device->log.glyphs.count++;
  1145.     device->log.glyphs.operators[op]++;
  1146.     add_pattern (&device->log.glyphs.source, source, surface->target);
  1147.     add_clip (&device->log.glyphs.clip, clip);
  1148.  
  1149.     status = _cairo_composite_rectangles_init_for_glyphs (&composite,
  1150.                                                           surface->target,
  1151.                                                           op, source,
  1152.                                                           scaled_font,
  1153.                                                           glyphs, num_glyphs,
  1154.                                                           clip,
  1155.                                                           NULL);
  1156.     if (unlikely (status)) {
  1157.         surface->log.glyphs.noop++;
  1158.         device->log.glyphs.noop++;
  1159.         return status;
  1160.     }
  1161.  
  1162.     midpt (&composite, &x, &y);
  1163.  
  1164.     add_extents (&surface->log.glyphs.extents, &composite);
  1165.     add_extents (&device->log.glyphs.extents, &composite);
  1166.     _cairo_composite_rectangles_fini (&composite);
  1167.  
  1168.     /* XXX We have to copy the glyphs, because the backend is allowed to
  1169.      * modify! */
  1170.     dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
  1171.     if (unlikely (dev_glyphs == NULL))
  1172.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1173.     memcpy (dev_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
  1174.  
  1175.     t = _cairo_time_get ();
  1176.     status = _cairo_surface_show_text_glyphs (surface->target, op, source,
  1177.                                               NULL, 0,
  1178.                                               dev_glyphs, num_glyphs,
  1179.                                               NULL, 0, 0,
  1180.                                               scaled_font,
  1181.                                               clip);
  1182.     free (dev_glyphs);
  1183.     if (unlikely (status))
  1184.         return status;
  1185.  
  1186.     sync (surface->target, x, y);
  1187.     t = _cairo_time_get_delta (t);
  1188.  
  1189.     add_record_glyphs (&surface->log,
  1190.                        surface->target, op, source,
  1191.                        glyphs, num_glyphs, scaled_font,
  1192.                        clip, t);
  1193.  
  1194.     add_record_glyphs (&device->log,
  1195.                        surface->target, op, source,
  1196.                        glyphs, num_glyphs, scaled_font,
  1197.                        clip, t);
  1198.  
  1199.     do_callbacks (surface, &surface->glyphs_callbacks);
  1200.  
  1201.     return CAIRO_STATUS_SUCCESS;
  1202. }
  1203.  
  1204. static cairo_status_t
  1205. _cairo_surface_observer_flush (void *abstract_surface, unsigned flags)
  1206. {
  1207.     cairo_surface_observer_t *surface = abstract_surface;
  1208.  
  1209.     do_callbacks (surface, &surface->flush_callbacks);
  1210.     return _cairo_surface_flush (surface->target, flags);
  1211. }
  1212.  
  1213. static cairo_status_t
  1214. _cairo_surface_observer_mark_dirty (void *abstract_surface,
  1215.                                       int x, int y,
  1216.                                       int width, int height)
  1217. {
  1218.     cairo_surface_observer_t *surface = abstract_surface;
  1219.     cairo_status_t status;
  1220.  
  1221.     printf ("mark-dirty (%d, %d) x (%d, %d)\n", x, y, width, height);
  1222.  
  1223.     status = CAIRO_STATUS_SUCCESS;
  1224.     if (surface->target->backend->mark_dirty_rectangle)
  1225.         status = surface->target->backend->mark_dirty_rectangle (surface->target,
  1226.                                                        x,y, width,height);
  1227.  
  1228.     return status;
  1229. }
  1230.  
  1231. static cairo_int_status_t
  1232. _cairo_surface_observer_copy_page (void *abstract_surface)
  1233. {
  1234.     cairo_surface_observer_t *surface = abstract_surface;
  1235.     cairo_status_t status;
  1236.  
  1237.     status = CAIRO_STATUS_SUCCESS;
  1238.     if (surface->target->backend->copy_page)
  1239.         status = surface->target->backend->copy_page (surface->target);
  1240.  
  1241.     return status;
  1242. }
  1243.  
  1244. static cairo_int_status_t
  1245. _cairo_surface_observer_show_page (void *abstract_surface)
  1246. {
  1247.     cairo_surface_observer_t *surface = abstract_surface;
  1248.     cairo_status_t status;
  1249.  
  1250.     status = CAIRO_STATUS_SUCCESS;
  1251.     if (surface->target->backend->show_page)
  1252.         status = surface->target->backend->show_page (surface->target);
  1253.  
  1254.     return status;
  1255. }
  1256.  
  1257. static cairo_bool_t
  1258. _cairo_surface_observer_get_extents (void *abstract_surface,
  1259.                                      cairo_rectangle_int_t *extents)
  1260. {
  1261.     cairo_surface_observer_t *surface = abstract_surface;
  1262.     return _cairo_surface_get_extents (surface->target, extents);
  1263. }
  1264.  
  1265. static void
  1266. _cairo_surface_observer_get_font_options (void *abstract_surface,
  1267.                                           cairo_font_options_t *options)
  1268. {
  1269.     cairo_surface_observer_t *surface = abstract_surface;
  1270.  
  1271.     if (surface->target->backend->get_font_options != NULL)
  1272.         surface->target->backend->get_font_options (surface->target, options);
  1273. }
  1274.  
  1275. static cairo_surface_t *
  1276. _cairo_surface_observer_source (void                    *abstract_surface,
  1277.                                 cairo_rectangle_int_t   *extents)
  1278. {
  1279.     cairo_surface_observer_t *surface = abstract_surface;
  1280.     return _cairo_surface_get_source (surface->target, extents);
  1281. }
  1282.  
  1283. static cairo_status_t
  1284. _cairo_surface_observer_acquire_source_image (void                    *abstract_surface,
  1285.                                                 cairo_image_surface_t  **image_out,
  1286.                                                 void                   **image_extra)
  1287. {
  1288.     cairo_surface_observer_t *surface = abstract_surface;
  1289.  
  1290.     surface->log.num_sources_acquired++;
  1291.     to_device (surface)->log.num_sources_acquired++;
  1292.  
  1293.     return _cairo_surface_acquire_source_image (surface->target,
  1294.                                                 image_out, image_extra);
  1295. }
  1296.  
  1297. static void
  1298. _cairo_surface_observer_release_source_image (void                   *abstract_surface,
  1299.                                                 cairo_image_surface_t  *image,
  1300.                                                 void                   *image_extra)
  1301. {
  1302.     cairo_surface_observer_t *surface = abstract_surface;
  1303.  
  1304.     _cairo_surface_release_source_image (surface->target, image, image_extra);
  1305. }
  1306.  
  1307. static cairo_surface_t *
  1308. _cairo_surface_observer_snapshot (void *abstract_surface)
  1309. {
  1310.     cairo_surface_observer_t *surface = abstract_surface;
  1311.  
  1312.     /* XXX hook onto the snapshot so that we measure number of reads */
  1313.  
  1314.     if (surface->target->backend->snapshot)
  1315.         return surface->target->backend->snapshot (surface->target);
  1316.  
  1317.     return NULL;
  1318. }
  1319.  
  1320. static cairo_t *
  1321. _cairo_surface_observer_create_context(void *target)
  1322. {
  1323.     cairo_surface_observer_t *surface = target;
  1324.  
  1325.     if (_cairo_surface_is_subsurface (&surface->base))
  1326.         surface = (cairo_surface_observer_t *)
  1327.             _cairo_surface_subsurface_get_target (&surface->base);
  1328.  
  1329.     surface->log.num_contexts++;
  1330.     to_device (surface)->log.num_contexts++;
  1331.  
  1332.     return surface->target->backend->create_context (target);
  1333. }
  1334.  
  1335. static const cairo_surface_backend_t _cairo_surface_observer_backend = {
  1336.     CAIRO_INTERNAL_SURFACE_TYPE_OBSERVER,
  1337.     _cairo_surface_observer_finish,
  1338.  
  1339.     _cairo_surface_observer_create_context,
  1340.  
  1341.     _cairo_surface_observer_create_similar,
  1342.     _cairo_surface_observer_create_similar_image,
  1343.     _cairo_surface_observer_map_to_image,
  1344.     _cairo_surface_observer_unmap_image,
  1345.  
  1346.     _cairo_surface_observer_source,
  1347.     _cairo_surface_observer_acquire_source_image,
  1348.     _cairo_surface_observer_release_source_image,
  1349.     _cairo_surface_observer_snapshot,
  1350.  
  1351.     _cairo_surface_observer_copy_page,
  1352.     _cairo_surface_observer_show_page,
  1353.  
  1354.     _cairo_surface_observer_get_extents,
  1355.     _cairo_surface_observer_get_font_options,
  1356.  
  1357.     _cairo_surface_observer_flush,
  1358.     _cairo_surface_observer_mark_dirty,
  1359.  
  1360.     _cairo_surface_observer_paint,
  1361.     _cairo_surface_observer_mask,
  1362.     _cairo_surface_observer_stroke,
  1363.     _cairo_surface_observer_fill,
  1364.     NULL, /* fill-stroke */
  1365.     _cairo_surface_observer_glyphs,
  1366. };
  1367.  
  1368. /**
  1369.  * cairo_surface_create_observer:
  1370.  * @target: an existing surface for which the observer will watch
  1371.  *
  1372.  * Create a new surface that exists solely to watch another is doing. In
  1373.  * the process it will log operations and times, which are fast, which are
  1374.  * slow, which are frequent, etc.
  1375.  *
  1376.  * Return value: a pointer to the newly allocated surface. The caller
  1377.  * owns the surface and should call cairo_surface_destroy() when done
  1378.  * with it.
  1379.  *
  1380.  * This function always returns a valid pointer, but it will return a
  1381.  * pointer to a "nil" surface if @other is already in an error state
  1382.  * or any other error occurs.
  1383.  *
  1384.  * Since: 1.12
  1385.  **/
  1386. cairo_surface_t *
  1387. cairo_surface_create_observer (cairo_surface_t *target,
  1388.                                cairo_surface_observer_mode_t mode)
  1389. {
  1390.     cairo_device_t *device;
  1391.     cairo_surface_t *surface;
  1392.     cairo_bool_t record;
  1393.  
  1394.     if (unlikely (target->status))
  1395.         return _cairo_surface_create_in_error (target->status);
  1396.     if (unlikely (target->finished))
  1397.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  1398.  
  1399.     record = mode & CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS;
  1400.     device = _cairo_device_create_observer_internal (target->device, record);
  1401.     if (unlikely (device->status))
  1402.         return _cairo_surface_create_in_error (device->status);
  1403.  
  1404.     surface = _cairo_surface_create_observer_internal (device, target);
  1405.     cairo_device_destroy (device);
  1406.  
  1407.     return surface;
  1408. }
  1409.  
  1410. static cairo_status_t
  1411. _cairo_surface_observer_add_callback (cairo_list_t *head,
  1412.                                       cairo_surface_observer_callback_t func,
  1413.                                       void *data)
  1414. {
  1415.     struct callback_list *cb;
  1416.  
  1417.     cb = malloc (sizeof (*cb));
  1418.     if (unlikely (cb == NULL))
  1419.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1420.  
  1421.     cairo_list_add (&cb->link, head);
  1422.     cb->func = func;
  1423.     cb->data = data;
  1424.  
  1425.     return CAIRO_STATUS_SUCCESS;
  1426. }
  1427.  
  1428. cairo_status_t
  1429. cairo_surface_observer_add_paint_callback (cairo_surface_t *abstract_surface,
  1430.                                             cairo_surface_observer_callback_t func,
  1431.                                             void *data)
  1432. {
  1433.     cairo_surface_observer_t *surface;
  1434.  
  1435.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1436.         return abstract_surface->status;
  1437.  
  1438.     if (! _cairo_surface_is_observer (abstract_surface))
  1439.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1440.  
  1441.     surface = (cairo_surface_observer_t *)abstract_surface;
  1442.     return _cairo_surface_observer_add_callback (&surface->paint_callbacks,
  1443.                                                  func, data);
  1444. }
  1445.  
  1446. cairo_status_t
  1447. cairo_surface_observer_add_mask_callback (cairo_surface_t *abstract_surface,
  1448.                                           cairo_surface_observer_callback_t func,
  1449.                                           void *data)
  1450. {
  1451.     cairo_surface_observer_t *surface;
  1452.  
  1453.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1454.         return abstract_surface->status;
  1455.  
  1456.     if (! _cairo_surface_is_observer (abstract_surface))
  1457.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1458.  
  1459.     surface = (cairo_surface_observer_t *)abstract_surface;
  1460.     return _cairo_surface_observer_add_callback (&surface->mask_callbacks,
  1461.                                                  func, data);
  1462. }
  1463.  
  1464. cairo_status_t
  1465. cairo_surface_observer_add_fill_callback (cairo_surface_t *abstract_surface,
  1466.                                           cairo_surface_observer_callback_t func,
  1467.                                           void *data)
  1468. {
  1469.     cairo_surface_observer_t *surface;
  1470.  
  1471.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1472.         return abstract_surface->status;
  1473.  
  1474.     if (! _cairo_surface_is_observer (abstract_surface))
  1475.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1476.  
  1477.     surface = (cairo_surface_observer_t *)abstract_surface;
  1478.     return _cairo_surface_observer_add_callback (&surface->fill_callbacks,
  1479.                                                  func, data);
  1480. }
  1481.  
  1482. cairo_status_t
  1483. cairo_surface_observer_add_stroke_callback (cairo_surface_t *abstract_surface,
  1484.                                             cairo_surface_observer_callback_t func,
  1485.                                             void *data)
  1486. {
  1487.     cairo_surface_observer_t *surface;
  1488.  
  1489.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1490.         return abstract_surface->status;
  1491.  
  1492.     if (! _cairo_surface_is_observer (abstract_surface))
  1493.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1494.  
  1495.     surface = (cairo_surface_observer_t *)abstract_surface;
  1496.     return _cairo_surface_observer_add_callback (&surface->stroke_callbacks,
  1497.                                                  func, data);
  1498. }
  1499.  
  1500. cairo_status_t
  1501. cairo_surface_observer_add_glyphs_callback (cairo_surface_t *abstract_surface,
  1502.                                             cairo_surface_observer_callback_t func,
  1503.                                             void *data)
  1504. {
  1505.     cairo_surface_observer_t *surface;
  1506.  
  1507.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1508.         return abstract_surface->status;
  1509.  
  1510.     if (! _cairo_surface_is_observer (abstract_surface))
  1511.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1512.  
  1513.     surface = (cairo_surface_observer_t *)abstract_surface;
  1514.     return _cairo_surface_observer_add_callback (&surface->glyphs_callbacks,
  1515.                                                  func, data);
  1516. }
  1517.  
  1518. cairo_status_t
  1519. cairo_surface_observer_add_flush_callback (cairo_surface_t *abstract_surface,
  1520.                                            cairo_surface_observer_callback_t func,
  1521.                                            void *data)
  1522. {
  1523.     cairo_surface_observer_t *surface;
  1524.  
  1525.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1526.         return abstract_surface->status;
  1527.  
  1528.     if (! _cairo_surface_is_observer (abstract_surface))
  1529.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1530.  
  1531.     surface = (cairo_surface_observer_t *)abstract_surface;
  1532.     return _cairo_surface_observer_add_callback (&surface->flush_callbacks,
  1533.                                                  func, data);
  1534. }
  1535.  
  1536. cairo_status_t
  1537. cairo_surface_observer_add_finish_callback (cairo_surface_t *abstract_surface,
  1538.                                             cairo_surface_observer_callback_t func,
  1539.                                             void *data)
  1540. {
  1541.     cairo_surface_observer_t *surface;
  1542.  
  1543.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1544.         return abstract_surface->status;
  1545.  
  1546.     if (! _cairo_surface_is_observer (abstract_surface))
  1547.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1548.  
  1549.     surface = (cairo_surface_observer_t *)abstract_surface;
  1550.     return _cairo_surface_observer_add_callback (&surface->finish_callbacks,
  1551.                                                  func, data);
  1552. }
  1553.  
  1554. static void
  1555. print_extents (cairo_output_stream_t *stream, const struct extents *e)
  1556. {
  1557.     _cairo_output_stream_printf (stream,
  1558.                                  "  extents: total %g, avg %g [unbounded %d]\n",
  1559.                                  e->area.sum,
  1560.                                  e->area.sum / e->area.count,
  1561.                                  e->unbounded);
  1562. }
  1563.  
  1564. static inline int ordercmp (int a, int b, const unsigned int *array)
  1565. {
  1566.     /* high to low */
  1567.     return array[b] - array[a];
  1568. }
  1569. CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_order, int, ordercmp)
  1570.  
  1571. static void
  1572. print_array (cairo_output_stream_t *stream,
  1573.              const unsigned int *array,
  1574.              const char **names,
  1575.              int count)
  1576. {
  1577.     int order[64];
  1578.     int i, j;
  1579.  
  1580.     assert (count < ARRAY_LENGTH (order));
  1581.     for (i = j = 0; i < count; i++) {
  1582.         if (array[i] != 0)
  1583.             order[j++] = i;
  1584.     }
  1585.  
  1586.     sort_order (order, j, (void *)array);
  1587.     for (i = 0; i < j; i++)
  1588.         _cairo_output_stream_printf (stream, " %d %s%s",
  1589.                                      array[order[i]], names[order[i]],
  1590.                                      i < j -1 ? "," : "");
  1591. }
  1592.  
  1593. static const char *operator_names[] = {
  1594.     "CLEAR",    /* CAIRO_OPERATOR_CLEAR */
  1595.  
  1596.     "SOURCE",   /* CAIRO_OPERATOR_SOURCE */
  1597.     "OVER",             /* CAIRO_OPERATOR_OVER */
  1598.     "IN",               /* CAIRO_OPERATOR_IN */
  1599.     "OUT",              /* CAIRO_OPERATOR_OUT */
  1600.     "ATOP",             /* CAIRO_OPERATOR_ATOP */
  1601.  
  1602.     "DEST",             /* CAIRO_OPERATOR_DEST */
  1603.     "DEST_OVER",        /* CAIRO_OPERATOR_DEST_OVER */
  1604.     "DEST_IN",  /* CAIRO_OPERATOR_DEST_IN */
  1605.     "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */
  1606.     "DEST_ATOP",        /* CAIRO_OPERATOR_DEST_ATOP */
  1607.  
  1608.     "XOR",              /* CAIRO_OPERATOR_XOR */
  1609.     "ADD",              /* CAIRO_OPERATOR_ADD */
  1610.     "SATURATE", /* CAIRO_OPERATOR_SATURATE */
  1611.  
  1612.     "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */
  1613.     "SCREEN",   /* CAIRO_OPERATOR_SCREEN */
  1614.     "OVERLAY",  /* CAIRO_OPERATOR_OVERLAY */
  1615.     "DARKEN",   /* CAIRO_OPERATOR_DARKEN */
  1616.     "LIGHTEN",  /* CAIRO_OPERATOR_LIGHTEN */
  1617.     "DODGE",    /* CAIRO_OPERATOR_COLOR_DODGE */
  1618.     "BURN",             /* CAIRO_OPERATOR_COLOR_BURN */
  1619.     "HARD_LIGHT",       /* CAIRO_OPERATOR_HARD_LIGHT */
  1620.     "SOFT_LIGHT",       /* CAIRO_OPERATOR_SOFT_LIGHT */
  1621.     "DIFFERENCE",       /* CAIRO_OPERATOR_DIFFERENCE */
  1622.     "EXCLUSION",        /* CAIRO_OPERATOR_EXCLUSION */
  1623.     "HSL_HUE",  /* CAIRO_OPERATOR_HSL_HUE */
  1624.     "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
  1625.     "HSL_COLOR",        /* CAIRO_OPERATOR_HSL_COLOR */
  1626.     "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
  1627. };
  1628. static void
  1629. print_operators (cairo_output_stream_t *stream, unsigned int *array)
  1630. {
  1631.     _cairo_output_stream_printf (stream, "  op:");
  1632.     print_array (stream, array, operator_names, NUM_OPERATORS);
  1633.     _cairo_output_stream_printf (stream, "\n");
  1634. }
  1635.  
  1636. static const char *fill_rule_names[] = {
  1637.     "non-zero",
  1638.     "even-odd",
  1639. };
  1640. static void
  1641. print_fill_rule (cairo_output_stream_t *stream, unsigned int *array)
  1642. {
  1643.     _cairo_output_stream_printf (stream, "  fill rule:");
  1644.     print_array (stream, array, fill_rule_names, ARRAY_LENGTH(fill_rule_names));
  1645.     _cairo_output_stream_printf (stream, "\n");
  1646. }
  1647.  
  1648. static const char *cap_names[] = {
  1649.     "butt",             /* CAIRO_LINE_CAP_BUTT */
  1650.     "round",    /* CAIRO_LINE_CAP_ROUND */
  1651.     "square"    /* CAIRO_LINE_CAP_SQUARE */
  1652. };
  1653. static void
  1654. print_line_caps (cairo_output_stream_t *stream, unsigned int *array)
  1655. {
  1656.     _cairo_output_stream_printf (stream, "  caps:");
  1657.     print_array (stream, array, cap_names, NUM_CAPS);
  1658.     _cairo_output_stream_printf (stream, "\n");
  1659. }
  1660.  
  1661. static const char *join_names[] = {
  1662.     "miter",    /* CAIRO_LINE_JOIN_MITER */
  1663.     "round",    /* CAIRO_LINE_JOIN_ROUND */
  1664.     "bevel",    /* CAIRO_LINE_JOIN_BEVEL */
  1665. };
  1666. static void
  1667. print_line_joins (cairo_output_stream_t *stream, unsigned int *array)
  1668. {
  1669.     _cairo_output_stream_printf (stream, "  joins:");
  1670.     print_array (stream, array, join_names, NUM_JOINS);
  1671.     _cairo_output_stream_printf (stream, "\n");
  1672. }
  1673.  
  1674. static const char *antialias_names[] = {
  1675.     "default",
  1676.     "none",
  1677.     "gray",
  1678.     "subpixel",
  1679.     "fast",
  1680.     "good",
  1681.     "best"
  1682. };
  1683. static void
  1684. print_antialias (cairo_output_stream_t *stream, unsigned int *array)
  1685. {
  1686.     _cairo_output_stream_printf (stream, "  antialias:");
  1687.     print_array (stream, array, antialias_names, NUM_ANTIALIAS);
  1688.     _cairo_output_stream_printf (stream, "\n");
  1689. }
  1690.  
  1691. static const char *pattern_names[] = {
  1692.     "native",
  1693.     "record",
  1694.     "other surface",
  1695.     "solid",
  1696.     "linear",
  1697.     "radial",
  1698.     "mesh",
  1699.     "raster"
  1700. };
  1701. static void
  1702. print_pattern (cairo_output_stream_t *stream,
  1703.                const char *name,
  1704.                const struct pattern *p)
  1705. {
  1706.     _cairo_output_stream_printf (stream, "  %s:", name);
  1707.     print_array (stream, p->type, pattern_names, ARRAY_LENGTH (pattern_names));
  1708.     _cairo_output_stream_printf (stream, "\n");
  1709. }
  1710.  
  1711. static const char *path_names[] = {
  1712.     "empty",
  1713.     "pixel-aligned",
  1714.     "rectliinear",
  1715.     "straight",
  1716.     "curved",
  1717. };
  1718. static void
  1719. print_path (cairo_output_stream_t *stream,
  1720.             const struct path *p)
  1721. {
  1722.     _cairo_output_stream_printf (stream, "  path:");
  1723.     print_array (stream, p->type, path_names, ARRAY_LENGTH (path_names));
  1724.     _cairo_output_stream_printf (stream, "\n");
  1725. }
  1726.  
  1727. static const char *clip_names[] = {
  1728.     "none",
  1729.     "region",
  1730.     "boxes",
  1731.     "single path",
  1732.     "polygon",
  1733.     "general",
  1734. };
  1735. static void
  1736. print_clip (cairo_output_stream_t *stream, const struct clip *c)
  1737. {
  1738.     _cairo_output_stream_printf (stream, "  clip:");
  1739.     print_array (stream, c->type, clip_names, ARRAY_LENGTH (clip_names));
  1740.     _cairo_output_stream_printf (stream, "\n");
  1741. }
  1742.  
  1743. static void
  1744. print_record (cairo_output_stream_t *stream,
  1745.               cairo_observation_record_t *r)
  1746. {
  1747.     _cairo_output_stream_printf (stream, "  op: %s\n", operator_names[r->op]);
  1748.     _cairo_output_stream_printf (stream, "  source: %s\n",
  1749.                                  pattern_names[r->source]);
  1750.     if (r->mask != -1)
  1751.         _cairo_output_stream_printf (stream, "  mask: %s\n",
  1752.                                      pattern_names[r->mask]);
  1753.     if (r->num_glyphs != -1)
  1754.         _cairo_output_stream_printf (stream, "  num_glyphs: %d\n",
  1755.                                      r->num_glyphs);
  1756.     if (r->path != -1)
  1757.         _cairo_output_stream_printf (stream, "  path: %s\n",
  1758.                                     path_names[r->path]);
  1759.     if (r->fill_rule != -1)
  1760.         _cairo_output_stream_printf (stream, "  fill rule: %s\n",
  1761.                                      fill_rule_names[r->fill_rule]);
  1762.     if (r->antialias != -1)
  1763.         _cairo_output_stream_printf (stream, "  antialias: %s\n",
  1764.                                      antialias_names[r->antialias]);
  1765.     _cairo_output_stream_printf (stream, "  clip: %s\n", clip_names[r->clip]);
  1766.     _cairo_output_stream_printf (stream, "  elapsed: %f ns\n",
  1767.                                  _cairo_time_to_ns (r->elapsed));
  1768. }
  1769.  
  1770. static double percent (cairo_time_t a, cairo_time_t b)
  1771. {
  1772.     /* Fake %.1f */
  1773.     return _cairo_round (_cairo_time_to_s (a) * 1000 /
  1774.                          _cairo_time_to_s (b)) / 10;
  1775. }
  1776.  
  1777. static cairo_bool_t
  1778. replay_record (cairo_observation_t *log,
  1779.                cairo_observation_record_t *r,
  1780.                cairo_device_t *script)
  1781. {
  1782. #if CAIRO_HAS_SCRIPT_SURFACE
  1783.     cairo_surface_t *surface;
  1784.     cairo_int_status_t status;
  1785.  
  1786.     if (log->record == NULL || script == NULL)
  1787.         return FALSE;
  1788.  
  1789.     surface = cairo_script_surface_create (script,
  1790.                                            r->target_content,
  1791.                                            r->target_width,
  1792.                                            r->target_height);
  1793.     status =
  1794.         _cairo_recording_surface_replay_one (log->record, r->index, surface);
  1795.     cairo_surface_destroy (surface);
  1796.  
  1797.     assert (status == CAIRO_INT_STATUS_SUCCESS);
  1798.  
  1799.     return TRUE;
  1800. #else
  1801.     return FALSE;
  1802. #endif
  1803. }
  1804.  
  1805. static cairo_time_t
  1806. _cairo_observation_total_elapsed (cairo_observation_t *log)
  1807. {
  1808.     cairo_time_t total;
  1809.  
  1810.     total = log->paint.elapsed;
  1811.     total = _cairo_time_add (total, log->mask.elapsed);
  1812.     total = _cairo_time_add (total, log->fill.elapsed);
  1813.     total = _cairo_time_add (total, log->stroke.elapsed);
  1814.     total = _cairo_time_add (total, log->glyphs.elapsed);
  1815.  
  1816.     return total;
  1817. }
  1818.  
  1819. static void
  1820. _cairo_observation_print (cairo_output_stream_t *stream,
  1821.                           cairo_observation_t *log)
  1822. {
  1823.     cairo_device_t *script;
  1824.     cairo_time_t total;
  1825.  
  1826. #if CAIRO_HAS_SCRIPT_SURFACE
  1827.     script = _cairo_script_context_create_internal (stream);
  1828.     _cairo_script_context_attach_snapshots (script, FALSE);
  1829. #else
  1830.     script = NULL;
  1831. #endif
  1832.  
  1833.     total = _cairo_observation_total_elapsed (log);
  1834.  
  1835.     _cairo_output_stream_printf (stream, "elapsed: %f\n",
  1836.                                  _cairo_time_to_ns (total));
  1837.     _cairo_output_stream_printf (stream, "surfaces: %d\n",
  1838.                                  log->num_surfaces);
  1839.     _cairo_output_stream_printf (stream, "contexts: %d\n",
  1840.                                  log->num_contexts);
  1841.     _cairo_output_stream_printf (stream, "sources acquired: %d\n",
  1842.                                  log->num_sources_acquired);
  1843.  
  1844.  
  1845.     _cairo_output_stream_printf (stream, "paint: count %d [no-op %d], elapsed %f [%f%%]\n",
  1846.                                  log->paint.count, log->paint.noop,
  1847.                                  _cairo_time_to_ns (log->paint.elapsed),
  1848.                                  percent (log->paint.elapsed, total));
  1849.     if (log->paint.count) {
  1850.         print_extents (stream, &log->paint.extents);
  1851.         print_operators (stream, log->paint.operators);
  1852.         print_pattern (stream, "source", &log->paint.source);
  1853.         print_clip (stream, &log->paint.clip);
  1854.  
  1855.         _cairo_output_stream_printf (stream, "slowest paint: %f%%\n",
  1856.                                      percent (log->paint.slowest.elapsed,
  1857.                                               log->paint.elapsed));
  1858.         print_record (stream, &log->paint.slowest);
  1859.  
  1860.         _cairo_output_stream_printf (stream, "\n");
  1861.         if (replay_record (log, &log->paint.slowest, script))
  1862.             _cairo_output_stream_printf (stream, "\n\n");
  1863.     }
  1864.  
  1865.     _cairo_output_stream_printf (stream, "mask: count %d [no-op %d], elapsed %f [%f%%]\n",
  1866.                                  log->mask.count, log->mask.noop,
  1867.                                  _cairo_time_to_ns (log->mask.elapsed),
  1868.                                  percent (log->mask.elapsed, total));
  1869.     if (log->mask.count) {
  1870.         print_extents (stream, &log->mask.extents);
  1871.         print_operators (stream, log->mask.operators);
  1872.         print_pattern (stream, "source", &log->mask.source);
  1873.         print_pattern (stream, "mask", &log->mask.mask);
  1874.         print_clip (stream, &log->mask.clip);
  1875.  
  1876.         _cairo_output_stream_printf (stream, "slowest mask: %f%%\n",
  1877.                                      percent (log->mask.slowest.elapsed,
  1878.                                               log->mask.elapsed));
  1879.         print_record (stream, &log->mask.slowest);
  1880.  
  1881.         _cairo_output_stream_printf (stream, "\n");
  1882.         if (replay_record (log, &log->mask.slowest, script))
  1883.             _cairo_output_stream_printf (stream, "\n\n");
  1884.     }
  1885.  
  1886.     _cairo_output_stream_printf (stream, "fill: count %d [no-op %d], elaspsed %f [%f%%]\n",
  1887.                                  log->fill.count, log->fill.noop,
  1888.                                  _cairo_time_to_ns (log->fill.elapsed),
  1889.                                  percent (log->fill.elapsed, total));
  1890.     if (log->fill.count) {
  1891.         print_extents (stream, &log->fill.extents);
  1892.         print_operators (stream, log->fill.operators);
  1893.         print_pattern (stream, "source", &log->fill.source);
  1894.         print_path (stream, &log->fill.path);
  1895.         print_fill_rule (stream, log->fill.fill_rule);
  1896.         print_antialias (stream, log->fill.antialias);
  1897.         print_clip (stream, &log->fill.clip);
  1898.  
  1899.         _cairo_output_stream_printf (stream, "slowest fill: %f%%\n",
  1900.                                      percent (log->fill.slowest.elapsed,
  1901.                                               log->fill.elapsed));
  1902.         print_record (stream, &log->fill.slowest);
  1903.  
  1904.         _cairo_output_stream_printf (stream, "\n");
  1905.         if (replay_record (log, &log->fill.slowest, script))
  1906.             _cairo_output_stream_printf (stream, "\n\n");
  1907.     }
  1908.  
  1909.     _cairo_output_stream_printf (stream, "stroke: count %d [no-op %d], elapsed %f [%f%%]\n",
  1910.                                  log->stroke.count, log->stroke.noop,
  1911.                                  _cairo_time_to_ns (log->stroke.elapsed),
  1912.                                  percent (log->stroke.elapsed, total));
  1913.     if (log->stroke.count) {
  1914.         print_extents (stream, &log->stroke.extents);
  1915.         print_operators (stream, log->stroke.operators);
  1916.         print_pattern (stream, "source", &log->stroke.source);
  1917.         print_path (stream, &log->stroke.path);
  1918.         print_antialias (stream, log->stroke.antialias);
  1919.         print_line_caps (stream, log->stroke.caps);
  1920.         print_line_joins (stream, log->stroke.joins);
  1921.         print_clip (stream, &log->stroke.clip);
  1922.  
  1923.         _cairo_output_stream_printf (stream, "slowest stroke: %f%%\n",
  1924.                                      percent (log->stroke.slowest.elapsed,
  1925.                                               log->stroke.elapsed));
  1926.         print_record (stream, &log->stroke.slowest);
  1927.  
  1928.         _cairo_output_stream_printf (stream, "\n");
  1929.         if (replay_record (log, &log->stroke.slowest, script))
  1930.             _cairo_output_stream_printf (stream, "\n\n");
  1931.     }
  1932.  
  1933.     _cairo_output_stream_printf (stream, "glyphs: count %d [no-op %d], elasped %f [%f%%]\n",
  1934.                                  log->glyphs.count, log->glyphs.noop,
  1935.                                  _cairo_time_to_ns (log->glyphs.elapsed),
  1936.                                  percent (log->glyphs.elapsed, total));
  1937.     if (log->glyphs.count) {
  1938.         print_extents (stream, &log->glyphs.extents);
  1939.         print_operators (stream, log->glyphs.operators);
  1940.         print_pattern (stream, "source", &log->glyphs.source);
  1941.         print_clip (stream, &log->glyphs.clip);
  1942.  
  1943.         _cairo_output_stream_printf (stream, "slowest glyphs: %f%%\n",
  1944.                                      percent (log->glyphs.slowest.elapsed,
  1945.                                               log->glyphs.elapsed));
  1946.         print_record (stream, &log->glyphs.slowest);
  1947.  
  1948.         _cairo_output_stream_printf (stream, "\n");
  1949.         if (replay_record (log, &log->glyphs.slowest, script))
  1950.             _cairo_output_stream_printf (stream, "\n\n");
  1951.     }
  1952.  
  1953.     cairo_device_destroy (script);
  1954. }
  1955.  
  1956. cairo_status_t
  1957. cairo_surface_observer_print (cairo_surface_t *abstract_surface,
  1958.                               cairo_write_func_t write_func,
  1959.                               void *closure)
  1960. {
  1961.     cairo_output_stream_t *stream;
  1962.     cairo_surface_observer_t *surface;
  1963.  
  1964.     if (unlikely (abstract_surface->status))
  1965.         return abstract_surface->status;
  1966.  
  1967.     if (unlikely (! _cairo_surface_is_observer (abstract_surface)))
  1968.         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1969.  
  1970.     surface = (cairo_surface_observer_t *) abstract_surface;
  1971.  
  1972.     stream = _cairo_output_stream_create (write_func, NULL, closure);
  1973.     _cairo_observation_print (stream, &surface->log);
  1974.     return _cairo_output_stream_destroy (stream);
  1975. }
  1976.  
  1977. double
  1978. cairo_surface_observer_elapsed (cairo_surface_t *abstract_surface)
  1979. {
  1980.     cairo_surface_observer_t *surface;
  1981.  
  1982.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
  1983.         return -1;
  1984.  
  1985.     if (! _cairo_surface_is_observer (abstract_surface))
  1986.         return -1;
  1987.  
  1988.     surface = (cairo_surface_observer_t *) abstract_surface;
  1989.     return _cairo_time_to_ns (_cairo_observation_total_elapsed (&surface->log));
  1990. }
  1991.  
  1992. cairo_status_t
  1993. cairo_device_observer_print (cairo_device_t *abstract_device,
  1994.                              cairo_write_func_t write_func,
  1995.                              void *closure)
  1996. {
  1997.     cairo_output_stream_t *stream;
  1998.     cairo_device_observer_t *device;
  1999.  
  2000.     if (unlikely (abstract_device->status))
  2001.         return abstract_device->status;
  2002.  
  2003.     if (unlikely (! _cairo_device_is_observer (abstract_device)))
  2004.         return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  2005.  
  2006.     device = (cairo_device_observer_t *) abstract_device;
  2007.  
  2008.     stream = _cairo_output_stream_create (write_func, NULL, closure);
  2009.     _cairo_observation_print (stream, &device->log);
  2010.     return _cairo_output_stream_destroy (stream);
  2011. }
  2012.  
  2013. double
  2014. cairo_device_observer_elapsed (cairo_device_t *abstract_device)
  2015. {
  2016.     cairo_device_observer_t *device;
  2017.  
  2018.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2019.         return -1;
  2020.  
  2021.     if (! _cairo_device_is_observer (abstract_device))
  2022.         return -1;
  2023.  
  2024.     device = (cairo_device_observer_t *) abstract_device;
  2025.     return _cairo_time_to_ns (_cairo_observation_total_elapsed (&device->log));
  2026. }
  2027.  
  2028. double
  2029. cairo_device_observer_paint_elapsed (cairo_device_t *abstract_device)
  2030. {
  2031.     cairo_device_observer_t *device;
  2032.  
  2033.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2034.         return -1;
  2035.  
  2036.     if (! _cairo_device_is_observer (abstract_device))
  2037.         return -1;
  2038.  
  2039.     device = (cairo_device_observer_t *) abstract_device;
  2040.     return _cairo_time_to_ns (device->log.paint.elapsed);
  2041. }
  2042.  
  2043. double
  2044. cairo_device_observer_mask_elapsed (cairo_device_t *abstract_device)
  2045. {
  2046.     cairo_device_observer_t *device;
  2047.  
  2048.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2049.         return -1;
  2050.  
  2051.     if (! _cairo_device_is_observer (abstract_device))
  2052.         return -1;
  2053.  
  2054.     device = (cairo_device_observer_t *) abstract_device;
  2055.     return _cairo_time_to_ns (device->log.mask.elapsed);
  2056. }
  2057.  
  2058. double
  2059. cairo_device_observer_fill_elapsed (cairo_device_t *abstract_device)
  2060. {
  2061.     cairo_device_observer_t *device;
  2062.  
  2063.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2064.         return -1;
  2065.  
  2066.     if (! _cairo_device_is_observer (abstract_device))
  2067.         return -1;
  2068.  
  2069.     device = (cairo_device_observer_t *) abstract_device;
  2070.     return _cairo_time_to_ns (device->log.fill.elapsed);
  2071. }
  2072.  
  2073. double
  2074. cairo_device_observer_stroke_elapsed (cairo_device_t *abstract_device)
  2075. {
  2076.     cairo_device_observer_t *device;
  2077.  
  2078.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2079.         return -1;
  2080.  
  2081.     if (! _cairo_device_is_observer (abstract_device))
  2082.         return -1;
  2083.  
  2084.     device = (cairo_device_observer_t *) abstract_device;
  2085.     return _cairo_time_to_ns (device->log.stroke.elapsed);
  2086. }
  2087.  
  2088. double
  2089. cairo_device_observer_glyphs_elapsed (cairo_device_t *abstract_device)
  2090. {
  2091.     cairo_device_observer_t *device;
  2092.  
  2093.     if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count)))
  2094.         return -1;
  2095.  
  2096.     if (! _cairo_device_is_observer (abstract_device))
  2097.         return -1;
  2098.  
  2099.     device = (cairo_device_observer_t *) abstract_device;
  2100.     return _cairo_time_to_ns (device->log.glyphs.elapsed);
  2101. }
  2102.