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 Eric Anholt
  4.  * Copyright © 2009 Chris Wilson
  5.  * Copyright © 2005,2010 Red Hat, Inc
  6.  * Copyright © 2011 Intel Corporation
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it either under the terms of the GNU Lesser General Public
  10.  * License version 2.1 as published by the Free Software Foundation
  11.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  12.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  13.  * notice, a recipient may use your version of this file under either
  14.  * the MPL or the LGPL.
  15.  *
  16.  * You should have received a copy of the LGPL along with this library
  17.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  19.  * You should have received a copy of the MPL along with this library
  20.  * in the file COPYING-MPL-1.1
  21.  *
  22.  * The contents of this file are subject to the Mozilla Public License
  23.  * Version 1.1 (the "License"); you may not use this file except in
  24.  * compliance with the License. You may obtain a copy of the License at
  25.  * http://www.mozilla.org/MPL/
  26.  *
  27.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  28.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  29.  * the specific language governing rights and limitations.
  30.  *
  31.  * The Original Code is the cairo graphics library.
  32.  *
  33.  * The Initial Developer of the Original Code is Red Hat, Inc.
  34.  *
  35.  * Contributor(s):
  36.  *      Benjamin Otte <otte@gnome.org>
  37.  *      Carl Worth <cworth@cworth.org>
  38.  *      Chris Wilson <chris@chris-wilson.co.uk>
  39.  *      Eric Anholt <eric@anholt.net>
  40.  */
  41.  
  42. #include "cairoint.h"
  43.  
  44. #include "cairo-gl-private.h"
  45.  
  46. #include "cairo-composite-rectangles-private.h"
  47. #include "cairo-compositor-private.h"
  48. #include "cairo-default-context-private.h"
  49. #include "cairo-error-private.h"
  50. #include "cairo-image-surface-private.h"
  51. #include "cairo-spans-compositor-private.h"
  52. #include "cairo-surface-backend-private.h"
  53. #include "cairo-surface-offset-private.h"
  54.  
  55. static cairo_int_status_t
  56. acquire (void *abstract_dst)
  57. {
  58.     return CAIRO_STATUS_SUCCESS;
  59. }
  60.  
  61. static cairo_int_status_t
  62. release (void *abstract_dst)
  63. {
  64.     return CAIRO_STATUS_SUCCESS;
  65. }
  66.  
  67. static cairo_int_status_t
  68. set_clip_region (void *_surface,
  69.                  cairo_region_t *region)
  70. {
  71.     cairo_gl_surface_t *surface = _surface;
  72.  
  73.     surface->clip_region = region;
  74.     return CAIRO_STATUS_SUCCESS;
  75. }
  76.  
  77. static cairo_int_status_t
  78. draw_image_boxes (void *_dst,
  79.                   cairo_image_surface_t *image,
  80.                   cairo_boxes_t *boxes,
  81.                   int dx, int dy)
  82. {
  83.     cairo_gl_surface_t *dst = _dst;
  84.     struct _cairo_boxes_chunk *chunk;
  85.     int i;
  86.  
  87.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  88.         for (i = 0; i < chunk->count; i++) {
  89.             cairo_box_t *b = &chunk->base[i];
  90.             int x = _cairo_fixed_integer_part (b->p1.x);
  91.             int y = _cairo_fixed_integer_part (b->p1.y);
  92.             int w = _cairo_fixed_integer_part (b->p2.x) - x;
  93.             int h = _cairo_fixed_integer_part (b->p2.y) - y;
  94.             cairo_status_t status;
  95.  
  96.             status = _cairo_gl_surface_draw_image (dst, image,
  97.                                                    x + dx, y + dy,
  98.                                                    w, h,
  99.                                                    x, y,
  100.                                                    TRUE);
  101.             if (unlikely (status))
  102.                 return status;
  103.         }
  104.     }
  105.  
  106.     return CAIRO_STATUS_SUCCESS;
  107. }
  108.  
  109. static void
  110. emit_aligned_boxes (cairo_gl_context_t *ctx,
  111.                     const cairo_boxes_t *boxes)
  112. {
  113.     const struct _cairo_boxes_chunk *chunk;
  114.     cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
  115.     int i;
  116.  
  117.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  118.         for (i = 0; i < chunk->count; i++) {
  119.             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  120.             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  121.             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  122.             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  123.             emit (ctx, x1, y1, x2, y2);
  124.         }
  125.     }
  126. }
  127.  
  128. static cairo_int_status_t
  129. fill_boxes (void                *_dst,
  130.             cairo_operator_t     op,
  131.             const cairo_color_t *color,
  132.             cairo_boxes_t       *boxes)
  133. {
  134.     cairo_gl_composite_t setup;
  135.     cairo_gl_context_t *ctx;
  136.     cairo_int_status_t status;
  137.  
  138.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  139.     if (unlikely (status))
  140.         goto FAIL;
  141.  
  142.    _cairo_gl_composite_set_solid_source (&setup, color);
  143.  
  144.     status = _cairo_gl_composite_begin (&setup, &ctx);
  145.     if (unlikely (status))
  146.         goto FAIL;
  147.  
  148.     emit_aligned_boxes (ctx, boxes);
  149.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  150.  
  151. FAIL:
  152.     _cairo_gl_composite_fini (&setup);
  153.     return status;
  154. }
  155.  
  156. static cairo_int_status_t
  157. composite_boxes (void                   *_dst,
  158.                  cairo_operator_t       op,
  159.                  cairo_surface_t        *abstract_src,
  160.                  cairo_surface_t        *abstract_mask,
  161.                  int                    src_x,
  162.                  int                    src_y,
  163.                  int                    mask_x,
  164.                  int                    mask_y,
  165.                  int                    dst_x,
  166.                  int                    dst_y,
  167.                  cairo_boxes_t          *boxes,
  168.                  const cairo_rectangle_int_t  *extents)
  169. {
  170.     cairo_gl_composite_t setup;
  171.     cairo_gl_context_t *ctx;
  172.     cairo_int_status_t status;
  173.  
  174.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  175.     if (unlikely (status))
  176.         goto FAIL;
  177.  
  178.     _cairo_gl_composite_set_source_operand (&setup,
  179.                                             source_to_operand (abstract_src));
  180.     _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y);
  181.  
  182.     _cairo_gl_composite_set_mask_operand (&setup,
  183.                                           source_to_operand (abstract_mask));
  184.     _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y);
  185.  
  186.     status = _cairo_gl_composite_begin (&setup, &ctx);
  187.     if (unlikely (status))
  188.         goto FAIL;
  189.  
  190.     emit_aligned_boxes (ctx, boxes);
  191.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  192.  
  193. FAIL:
  194.     _cairo_gl_composite_fini (&setup);
  195.     return status;
  196. }
  197.  
  198. static cairo_int_status_t
  199. composite (void                 *_dst,
  200.            cairo_operator_t     op,
  201.            cairo_surface_t      *abstract_src,
  202.            cairo_surface_t      *abstract_mask,
  203.            int                  src_x,
  204.            int                  src_y,
  205.            int                  mask_x,
  206.            int                  mask_y,
  207.            int                  dst_x,
  208.            int                  dst_y,
  209.            unsigned int         width,
  210.            unsigned int         height)
  211. {
  212.     cairo_gl_composite_t setup;
  213.     cairo_gl_context_t *ctx;
  214.     cairo_int_status_t status;
  215.  
  216.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  217.     if (unlikely (status))
  218.         goto FAIL;
  219.  
  220.     _cairo_gl_composite_set_source_operand (&setup,
  221.                                             source_to_operand (abstract_src));
  222.     _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y);
  223.  
  224.     _cairo_gl_composite_set_mask_operand (&setup,
  225.                                           source_to_operand (abstract_mask));
  226.     _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y);
  227.  
  228.     status = _cairo_gl_composite_begin (&setup, &ctx);
  229.     if (unlikely (status))
  230.         goto FAIL;
  231.  
  232.     /* XXX clip */
  233.     _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
  234.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  235.  
  236. FAIL:
  237.     _cairo_gl_composite_fini (&setup);
  238.     return status;
  239. }
  240.  
  241. static cairo_int_status_t
  242. lerp (void                      *dst,
  243.       cairo_surface_t           *src,
  244.       cairo_surface_t           *mask,
  245.       int                       src_x,
  246.       int                       src_y,
  247.       int                       mask_x,
  248.       int                       mask_y,
  249.       int                       dst_x,
  250.       int                       dst_y,
  251.       unsigned int              width,
  252.       unsigned int              height)
  253. {
  254.     cairo_int_status_t status;
  255.  
  256.     /* we could avoid some repetition... */
  257.     status = composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  258.                         mask_x, mask_y,
  259.                         0, 0,
  260.                         dst_x, dst_y,
  261.                         width, height);
  262.     if (unlikely (status))
  263.         return status;
  264.  
  265.     status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
  266.                         src_x, src_y,
  267.                         mask_x, mask_y,
  268.                         dst_x, dst_y,
  269.                         width, height);
  270.     if (unlikely (status))
  271.         return status;
  272.  
  273.     return CAIRO_STATUS_SUCCESS;
  274. }
  275.  
  276. static cairo_int_status_t
  277. traps_to_operand (void *_dst,
  278.                   const cairo_rectangle_int_t *extents,
  279.                   cairo_antialias_t     antialias,
  280.                   cairo_traps_t         *traps,
  281.                   cairo_gl_operand_t    *operand,
  282.                   int dst_x, int dst_y)
  283. {
  284.     pixman_format_code_t pixman_format;
  285.     pixman_image_t *pixman_image;
  286.     cairo_surface_t *image, *mask;
  287.     cairo_surface_pattern_t pattern;
  288.     cairo_status_t status;
  289.  
  290.     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
  291.     pixman_image = pixman_image_create_bits (pixman_format,
  292.                                              extents->width,
  293.                                              extents->height,
  294.                                              NULL, 0);
  295.     if (unlikely (pixman_image == NULL))
  296.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  297.  
  298.     _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
  299.     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
  300.                                                           pixman_format);
  301.     if (unlikely (image->status)) {
  302.         pixman_image_unref (pixman_image);
  303.         return image->status;
  304.     }
  305.  
  306.     /* GLES2 only supports RGB/RGBA when uploading */
  307.     if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
  308.         cairo_surface_pattern_t pattern;
  309.         cairo_surface_t *rgba_image;
  310.  
  311.         /* XXX perform this fixup inside _cairo_gl_draw_image() */
  312.  
  313.         rgba_image =
  314.             _cairo_image_surface_create_with_pixman_format (NULL,
  315.                                                             _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
  316.                                                             extents->width,
  317.                                                             extents->height,
  318.                                                             0);
  319.         if (unlikely (rgba_image->status))
  320.             return rgba_image->status;
  321.  
  322.         _cairo_pattern_init_for_surface (&pattern, image);
  323.         status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
  324.                                        &pattern.base, NULL);
  325.         _cairo_pattern_fini (&pattern.base);
  326.  
  327.         cairo_surface_destroy (image);
  328.         image = rgba_image;
  329.  
  330.         if (unlikely (status)) {
  331.             cairo_surface_destroy (image);
  332.             return status;
  333.         }
  334.     }
  335.  
  336.     mask = _cairo_surface_create_similar_scratch (_dst,
  337.                                                   CAIRO_CONTENT_COLOR_ALPHA,
  338.                                                   extents->width,
  339.                                                   extents->height);
  340.     if (unlikely (mask->status)) {
  341.         cairo_surface_destroy (image);
  342.         return mask->status;
  343.     }
  344.  
  345.     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
  346.                                            (cairo_image_surface_t *)image,
  347.                                            0, 0,
  348.                                            extents->width, extents->height,
  349.                                            0, 0,
  350.                                            TRUE);
  351.     cairo_surface_destroy (image);
  352.  
  353.     if (unlikely (status))
  354.         goto error;
  355.  
  356.     _cairo_pattern_init_for_surface (&pattern, mask);
  357.     cairo_matrix_init_translate (&pattern.base.matrix,
  358.                                  -extents->x+dst_x, -extents->y+dst_y);
  359.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  360.     pattern.base.extend = CAIRO_EXTEND_NONE;
  361.     status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
  362.                                      &_cairo_unbounded_rectangle,
  363.                                      &_cairo_unbounded_rectangle,
  364.                                      FALSE);
  365.     _cairo_pattern_fini (&pattern.base);
  366.  
  367.     if (unlikely (status))
  368.         goto error;
  369.  
  370.     operand->texture.owns_surface = (cairo_gl_surface_t *)mask;
  371.     return CAIRO_STATUS_SUCCESS;
  372.  
  373. error:
  374.     cairo_surface_destroy (mask);
  375.     return status;
  376. }
  377.  
  378. static cairo_int_status_t
  379. composite_traps (void                   *_dst,
  380.                  cairo_operator_t       op,
  381.                  cairo_surface_t        *abstract_src,
  382.                  int                    src_x,
  383.                  int                    src_y,
  384.                  int                    dst_x,
  385.                  int                    dst_y,
  386.                  const cairo_rectangle_int_t *extents,
  387.                  cairo_antialias_t      antialias,
  388.                  cairo_traps_t          *traps)
  389. {
  390.     cairo_gl_composite_t setup;
  391.     cairo_gl_context_t *ctx;
  392.     cairo_int_status_t status;
  393.  
  394.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  395.     if (unlikely (status))
  396.         goto FAIL;
  397.  
  398.     _cairo_gl_composite_set_source_operand (&setup,
  399.                                             source_to_operand (abstract_src));
  400.     _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y);
  401.     status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask, dst_x, dst_y);
  402.     if (unlikely (status))
  403.         goto FAIL;
  404.  
  405.     status = _cairo_gl_composite_begin (&setup, &ctx);
  406.     if (unlikely (status))
  407.         goto FAIL;
  408.  
  409.     /* XXX clip */
  410.     _cairo_gl_context_emit_rect (ctx,
  411.                                  extents->x-dst_x, extents->y-dst_y,
  412.                                  extents->x-dst_x+extents->width,
  413.                                  extents->y-dst_y+extents->height);
  414.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  415.  
  416. FAIL:
  417.     _cairo_gl_composite_fini (&setup);
  418.     return status;
  419. }
  420.  
  421. static cairo_gl_surface_t *
  422. tristrip_to_surface (void *_dst,
  423.                   const cairo_rectangle_int_t *extents,
  424.                   cairo_antialias_t     antialias,
  425.                   cairo_tristrip_t      *strip)
  426. {
  427.     pixman_format_code_t pixman_format;
  428.     pixman_image_t *pixman_image;
  429.     cairo_surface_t *image, *mask;
  430.     cairo_status_t status;
  431.  
  432.     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
  433.     pixman_image = pixman_image_create_bits (pixman_format,
  434.                                              extents->width,
  435.                                              extents->height,
  436.                                              NULL, 0);
  437.     if (unlikely (pixman_image == NULL))
  438.         return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  439.  
  440.     _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
  441.     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
  442.                                                           pixman_format);
  443.     if (unlikely (image->status)) {
  444.         pixman_image_unref (pixman_image);
  445.         return (cairo_gl_surface_t *)image;
  446.     }
  447.  
  448.     mask = _cairo_surface_create_similar_scratch (_dst,
  449.                                                   CAIRO_CONTENT_COLOR_ALPHA,
  450.                                                   extents->width,
  451.                                                   extents->height);
  452.     if (unlikely (mask->status)) {
  453.         cairo_surface_destroy (image);
  454.         return (cairo_gl_surface_t *)mask;
  455.     }
  456.  
  457.     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
  458.                                            (cairo_image_surface_t *)image,
  459.                                            0, 0,
  460.                                            extents->width, extents->height,
  461.                                            0, 0,
  462.                                            TRUE);
  463.     cairo_surface_destroy (image);
  464.     if (unlikely (status)) {
  465.         cairo_surface_destroy (mask);
  466.         return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
  467.     }
  468.  
  469.     return (cairo_gl_surface_t*)mask;
  470. }
  471.  
  472. static cairo_int_status_t
  473. composite_tristrip (void                *_dst,
  474.                     cairo_operator_t    op,
  475.                     cairo_surface_t     *abstract_src,
  476.                     int                 src_x,
  477.                     int                 src_y,
  478.                     int                 dst_x,
  479.                     int                 dst_y,
  480.                     const cairo_rectangle_int_t *extents,
  481.                     cairo_antialias_t   antialias,
  482.                     cairo_tristrip_t    *strip)
  483. {
  484.     cairo_gl_composite_t setup;
  485.     cairo_gl_context_t *ctx;
  486.     cairo_gl_surface_t *mask;
  487.     cairo_int_status_t status;
  488.  
  489.     mask = tristrip_to_surface (_dst, extents, antialias, strip);
  490.     if (unlikely (mask->base.status))
  491.         return mask->base.status;
  492.  
  493.     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
  494.     if (unlikely (status))
  495.         goto FAIL;
  496.  
  497.     _cairo_gl_composite_set_source_operand (&setup,
  498.                                             source_to_operand (abstract_src));
  499.  
  500.     //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
  501.  
  502.     status = _cairo_gl_composite_begin (&setup, &ctx);
  503.     if (unlikely (status))
  504.         goto FAIL;
  505.  
  506.     /* XXX clip */
  507.     _cairo_gl_context_emit_rect (ctx,
  508.                                  dst_x, dst_y,
  509.                                  dst_x+extents->width,
  510.                                  dst_y+extents->height);
  511.     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
  512.  
  513. FAIL:
  514.     _cairo_gl_composite_fini (&setup);
  515.     cairo_surface_destroy (&mask->base);
  516.     return status;
  517. }
  518.  
  519. static cairo_int_status_t
  520. check_composite (const cairo_composite_rectangles_t *extents)
  521. {
  522.     if (! _cairo_gl_operator_is_supported (extents->op))
  523.         return UNSUPPORTED ("unsupported operator");
  524.  
  525.     return CAIRO_STATUS_SUCCESS;
  526. }
  527.  
  528. const cairo_compositor_t *
  529. _cairo_gl_traps_compositor_get (void)
  530. {
  531.     static cairo_traps_compositor_t compositor;
  532.  
  533.     if (compositor.base.delegate == NULL) {
  534.         _cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
  535.         compositor.acquire = acquire;
  536.         compositor.release = release;
  537.         compositor.set_clip_region = set_clip_region;
  538.         compositor.pattern_to_surface = _cairo_gl_pattern_to_source;
  539.         compositor.draw_image_boxes = draw_image_boxes;
  540.         //compositor.copy_boxes = copy_boxes;
  541.         compositor.fill_boxes = fill_boxes;
  542.         compositor.check_composite = check_composite;
  543.         compositor.composite = composite;
  544.         compositor.lerp = lerp;
  545.         //compositor.check_composite_boxes = check_composite_boxes;
  546.         compositor.composite_boxes = composite_boxes;
  547.         //compositor.check_composite_traps = check_composite_traps;
  548.         compositor.composite_traps = composite_traps;
  549.         //compositor.check_composite_tristrip = check_composite_traps;
  550.         compositor.composite_tristrip = composite_tristrip;
  551.         compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
  552.         compositor.composite_glyphs = _cairo_gl_composite_glyphs;
  553.     }
  554.  
  555.     return &compositor.base;
  556. }
  557.