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 © 2009 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 Red Hat, Inc.
  31.  *
  32.  * Contributor(s):
  33.  *      Chris Wilson <chris@chris-wilson.co.uk>
  34.  */
  35.  
  36. #include "cairoint.h"
  37.  
  38. #include "cairo-clip-inline.h"
  39. #include "cairo-error-private.h"
  40. #include "cairo-composite-rectangles-private.h"
  41. #include "cairo-pattern-private.h"
  42.  
  43. /* A collection of routines to facilitate writing compositors. */
  44.  
  45. void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
  46. {
  47.     _cairo_clip_destroy (extents->clip);
  48. }
  49.  
  50. static void
  51. _cairo_composite_reduce_pattern (const cairo_pattern_t *src,
  52.                                  cairo_pattern_union_t *dst)
  53. {
  54.     int tx, ty;
  55.  
  56.     _cairo_pattern_init_static_copy (&dst->base, src);
  57.     if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID)
  58.         return;
  59.  
  60.     dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL),
  61.  
  62.     tx = ty = 0;
  63.     if (_cairo_matrix_is_pixman_translation (&dst->base.matrix,
  64.                                              dst->base.filter,
  65.                                              &tx, &ty))
  66.     {
  67.         dst->base.matrix.x0 = tx;
  68.         dst->base.matrix.y0 = ty;
  69.     }
  70. }
  71.  
  72. static inline cairo_bool_t
  73. _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
  74.                                   cairo_surface_t *surface,
  75.                                   cairo_operator_t op,
  76.                                   const cairo_pattern_t *source,
  77.                                   const cairo_clip_t *clip)
  78. {
  79.     if (_cairo_clip_is_all_clipped (clip))
  80.         return FALSE;
  81.  
  82.     extents->surface = surface;
  83.     extents->op = op;
  84.  
  85.     _cairo_surface_get_extents (surface, &extents->destination);
  86.     extents->clip = NULL;
  87.  
  88.     extents->unbounded = extents->destination;
  89.     if (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
  90.                                               _cairo_clip_get_extents (clip)))
  91.         return FALSE;
  92.  
  93.     extents->bounded = extents->unbounded;
  94.     extents->is_bounded = _cairo_operator_bounded_by_either (op);
  95.  
  96.     extents->original_source_pattern = source;
  97.     _cairo_composite_reduce_pattern (source, &extents->source_pattern);
  98.  
  99.     _cairo_pattern_get_extents (&extents->source_pattern.base,
  100.                                 &extents->source);
  101.     if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
  102.         if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
  103.             return FALSE;
  104.     }
  105.  
  106.     extents->original_mask_pattern = NULL;
  107.     extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
  108.     extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
  109.     extents->mask_pattern.solid.color.alpha_short = 0xffff;
  110.  
  111.     return TRUE;
  112. }
  113.  
  114. cairo_int_status_t
  115. _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
  116.                                             cairo_surface_t *surface,
  117.                                             cairo_operator_t             op,
  118.                                             const cairo_pattern_t       *source,
  119.                                             const cairo_clip_t          *clip)
  120. {
  121.     if (! _cairo_composite_rectangles_init (extents,
  122.                                             surface, op, source, clip))
  123.     {
  124.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  125.     }
  126.  
  127.     extents->mask = extents->destination;
  128.  
  129.     extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
  130.     if (_cairo_clip_is_all_clipped (extents->clip))
  131.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  132.  
  133.     if (! _cairo_rectangle_intersect (&extents->unbounded,
  134.                                       _cairo_clip_get_extents (extents->clip)))
  135.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  136.  
  137.     if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
  138.         _cairo_pattern_sampled_area (&extents->source_pattern.base,
  139.                                      &extents->bounded,
  140.                                      &extents->source_sample_area);
  141.  
  142.     return CAIRO_STATUS_SUCCESS;
  143. }
  144.  
  145. static cairo_int_status_t
  146. _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
  147.                                        const cairo_clip_t *clip)
  148. {
  149.     cairo_bool_t ret;
  150.  
  151.     ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
  152.     if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
  153.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  154.  
  155.     if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
  156.         extents->unbounded = extents->bounded;
  157.     } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
  158.         if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
  159.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  160.     }
  161.  
  162.     extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
  163.     if (_cairo_clip_is_all_clipped (extents->clip))
  164.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  165.  
  166.     if (! _cairo_rectangle_intersect (&extents->unbounded,
  167.                                       _cairo_clip_get_extents (extents->clip)))
  168.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  169.  
  170.     if (! _cairo_rectangle_intersect (&extents->bounded,
  171.                                       _cairo_clip_get_extents (extents->clip)) &&
  172.         extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
  173.     {
  174.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  175.     }
  176.  
  177.     if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
  178.         _cairo_pattern_sampled_area (&extents->source_pattern.base,
  179.                                      &extents->bounded,
  180.                                      &extents->source_sample_area);
  181.     if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
  182.         _cairo_pattern_sampled_area (&extents->mask_pattern.base,
  183.                                      &extents->bounded,
  184.                                      &extents->mask_sample_area);
  185.         if (extents->mask_sample_area.width == 0 ||
  186.             extents->mask_sample_area.height == 0) {
  187.             _cairo_composite_rectangles_fini (extents);
  188.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  189.         }
  190.     }
  191.  
  192.     return CAIRO_STATUS_SUCCESS;
  193. }
  194.  
  195. cairo_int_status_t
  196. _cairo_composite_rectangles_intersect_source_extents (cairo_composite_rectangles_t *extents,
  197.                                                       const cairo_box_t *box)
  198. {
  199.     cairo_rectangle_int_t rect;
  200.     cairo_clip_t *clip;
  201.  
  202.     _cairo_box_round_to_rectangle (box, &rect);
  203.     if (rect.x == extents->source.x &&
  204.         rect.y == extents->source.y &&
  205.         rect.width  == extents->source.width &&
  206.         rect.height == extents->source.height)
  207.     {
  208.         return CAIRO_INT_STATUS_SUCCESS;
  209.     }
  210.  
  211.     _cairo_rectangle_intersect (&extents->source, &rect);
  212.  
  213.     rect = extents->bounded;
  214.     if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source) &&
  215.         extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
  216.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  217.  
  218.     if (rect.width  == extents->bounded.width &&
  219.         rect.height == extents->bounded.height)
  220.         return CAIRO_INT_STATUS_SUCCESS;
  221.  
  222.     if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
  223.         extents->unbounded = extents->bounded;
  224.     } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
  225.         if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
  226.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  227.     }
  228.  
  229.     clip = extents->clip;
  230.     extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
  231.     if (clip != extents->clip)
  232.         _cairo_clip_destroy (clip);
  233.  
  234.     if (_cairo_clip_is_all_clipped (extents->clip))
  235.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  236.  
  237.     if (! _cairo_rectangle_intersect (&extents->unbounded,
  238.                                       _cairo_clip_get_extents (extents->clip)))
  239.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  240.  
  241.     if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
  242.         _cairo_pattern_sampled_area (&extents->source_pattern.base,
  243.                                      &extents->bounded,
  244.                                      &extents->source_sample_area);
  245.     if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
  246.         _cairo_pattern_sampled_area (&extents->mask_pattern.base,
  247.                                      &extents->bounded,
  248.                                      &extents->mask_sample_area);
  249.         if (extents->mask_sample_area.width == 0 ||
  250.             extents->mask_sample_area.height == 0)
  251.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  252.     }
  253.  
  254.     return CAIRO_INT_STATUS_SUCCESS;
  255. }
  256.  
  257. cairo_int_status_t
  258. _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
  259.                                                     const cairo_box_t *box)
  260. {
  261.     cairo_rectangle_int_t mask;
  262.     cairo_clip_t *clip;
  263.  
  264.     _cairo_box_round_to_rectangle (box, &mask);
  265.     if (mask.x == extents->mask.x &&
  266.         mask.y == extents->mask.y &&
  267.         mask.width  == extents->mask.width &&
  268.         mask.height == extents->mask.height)
  269.     {
  270.         return CAIRO_INT_STATUS_SUCCESS;
  271.     }
  272.  
  273.     _cairo_rectangle_intersect (&extents->mask, &mask);
  274.  
  275.     mask = extents->bounded;
  276.     if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
  277.         extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
  278.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  279.  
  280.     if (mask.width  == extents->bounded.width &&
  281.         mask.height == extents->bounded.height)
  282.         return CAIRO_INT_STATUS_SUCCESS;
  283.  
  284.     if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
  285.         extents->unbounded = extents->bounded;
  286.     } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
  287.         if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
  288.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  289.     }
  290.  
  291.     clip = extents->clip;
  292.     extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
  293.     if (clip != extents->clip)
  294.         _cairo_clip_destroy (clip);
  295.  
  296.     if (_cairo_clip_is_all_clipped (extents->clip))
  297.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  298.  
  299.     if (! _cairo_rectangle_intersect (&extents->unbounded,
  300.                                       _cairo_clip_get_extents (extents->clip)))
  301.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  302.  
  303.     if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
  304.         _cairo_pattern_sampled_area (&extents->source_pattern.base,
  305.                                      &extents->bounded,
  306.                                      &extents->source_sample_area);
  307.     if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
  308.         _cairo_pattern_sampled_area (&extents->mask_pattern.base,
  309.                                      &extents->bounded,
  310.                                      &extents->mask_sample_area);
  311.         if (extents->mask_sample_area.width == 0 ||
  312.             extents->mask_sample_area.height == 0)
  313.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  314.     }
  315.  
  316.     return CAIRO_INT_STATUS_SUCCESS;
  317. }
  318.  
  319. cairo_int_status_t
  320. _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
  321.                                            cairo_surface_t*surface,
  322.                                            cairo_operator_t              op,
  323.                                            const cairo_pattern_t        *source,
  324.                                            const cairo_pattern_t        *mask,
  325.                                            const cairo_clip_t           *clip)
  326. {
  327.     if (! _cairo_composite_rectangles_init (extents,
  328.                                             surface, op, source, clip))
  329.     {
  330.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  331.     }
  332.  
  333.     extents->original_mask_pattern = mask;
  334.     _cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
  335.     _cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);
  336.  
  337.     return _cairo_composite_rectangles_intersect (extents, clip);
  338. }
  339.  
  340. cairo_int_status_t
  341. _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
  342.                                              cairo_surface_t *surface,
  343.                                              cairo_operator_t            op,
  344.                                              const cairo_pattern_t      *source,
  345.                                              const cairo_path_fixed_t           *path,
  346.                                              const cairo_stroke_style_t *style,
  347.                                              const cairo_matrix_t       *ctm,
  348.                                              const cairo_clip_t         *clip)
  349. {
  350.     if (! _cairo_composite_rectangles_init (extents,
  351.                                             surface, op, source, clip))
  352.     {
  353.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  354.     }
  355.  
  356.     _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);
  357.  
  358.     return _cairo_composite_rectangles_intersect (extents, clip);
  359. }
  360.  
  361. cairo_int_status_t
  362. _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
  363.                                            cairo_surface_t *surface,
  364.                                            cairo_operator_t              op,
  365.                                            const cairo_pattern_t        *source,
  366.                                            const cairo_path_fixed_t             *path,
  367.                                            const cairo_clip_t           *clip)
  368. {
  369.     if (! _cairo_composite_rectangles_init (extents,
  370.                                             surface, op, source, clip))
  371.     {
  372.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  373.     }
  374.  
  375.     _cairo_path_fixed_approximate_fill_extents (path, &extents->mask);
  376.  
  377.     return _cairo_composite_rectangles_intersect (extents, clip);
  378. }
  379.  
  380. cairo_int_status_t
  381. _cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
  382.                                               cairo_surface_t           *surface,
  383.                                               cairo_operator_t           op,
  384.                                               const cairo_pattern_t     *source,
  385.                                               const cairo_polygon_t     *polygon,
  386.                                               const cairo_clip_t                *clip)
  387. {
  388.     if (! _cairo_composite_rectangles_init (extents,
  389.                                             surface, op, source, clip))
  390.     {
  391.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  392.     }
  393.  
  394.     _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
  395.     return _cairo_composite_rectangles_intersect (extents, clip);
  396. }
  397.  
  398. cairo_int_status_t
  399. _cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
  400.                                               cairo_surface_t           *surface,
  401.                                               cairo_operator_t           op,
  402.                                               const cairo_pattern_t     *source,
  403.                                               const cairo_boxes_t       *boxes,
  404.                                               const cairo_clip_t                *clip)
  405. {
  406.     cairo_box_t box;
  407.  
  408.     if (! _cairo_composite_rectangles_init (extents,
  409.                                             surface, op, source, clip))
  410.     {
  411.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  412.     }
  413.  
  414.     _cairo_boxes_extents (boxes, &box);
  415.     _cairo_box_round_to_rectangle (&box, &extents->mask);
  416.     return _cairo_composite_rectangles_intersect (extents, clip);
  417. }
  418.  
  419. cairo_int_status_t
  420. _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
  421.                                              cairo_surface_t *surface,
  422.                                              cairo_operator_t            op,
  423.                                              const cairo_pattern_t      *source,
  424.                                              cairo_scaled_font_t        *scaled_font,
  425.                                              cairo_glyph_t              *glyphs,
  426.                                              int                         num_glyphs,
  427.                                              const cairo_clip_t         *clip,
  428.                                              cairo_bool_t               *overlap)
  429. {
  430.     cairo_status_t status;
  431.  
  432.     if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
  433.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  434.  
  435.     /* Computing the exact bbox and the overlap is expensive.
  436.      * First perform a cheap test to see if the glyphs are all clipped out.
  437.      */
  438.     if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK &&
  439.         _cairo_scaled_font_glyph_approximate_extents (scaled_font,
  440.                                                       glyphs, num_glyphs,
  441.                                                       &extents->mask))
  442.     {
  443.         if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
  444.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  445.     }
  446.  
  447.     status = _cairo_scaled_font_glyph_device_extents (scaled_font,
  448.                                                       glyphs, num_glyphs,
  449.                                                       &extents->mask,
  450.                                                       overlap);
  451.     if (unlikely (status))
  452.         return status;
  453.  
  454.     if (overlap && *overlap &&
  455.         scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
  456.         _cairo_pattern_is_opaque_solid (&extents->source_pattern.base))
  457.     {
  458.         *overlap = FALSE;
  459.     }
  460.  
  461.     return _cairo_composite_rectangles_intersect (extents, clip);
  462. }
  463.  
  464. cairo_bool_t
  465. _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
  466.                                              cairo_clip_t *clip)
  467. {
  468.     cairo_rectangle_int_t extents;
  469.     cairo_box_t box;
  470.  
  471.     if (clip == NULL)
  472.         return TRUE;
  473.  
  474.     extents = composite->destination;
  475.     if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
  476.         _cairo_rectangle_intersect (&extents, &composite->source);
  477.     if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
  478.         _cairo_rectangle_intersect (&extents, &composite->mask);
  479.  
  480.     _cairo_box_from_rectangle (&box, &extents);
  481.     return _cairo_clip_contains_box (clip, &box);
  482. }
  483.  
  484. cairo_int_status_t
  485. _cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
  486.                                            cairo_boxes_t *damage)
  487. {
  488.     cairo_int_status_t status;
  489.     int n;
  490.  
  491.     for (n = 0; n < composite->clip->num_boxes; n++) {
  492.         status = _cairo_boxes_add (damage,
  493.                           CAIRO_ANTIALIAS_NONE,
  494.                           &composite->clip->boxes[n]);
  495.         if (unlikely (status))
  496.             return status;
  497.     }
  498.  
  499.     return CAIRO_INT_STATUS_SUCCESS;
  500. }
  501.