Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2009 Adrian Johnson
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it either under the terms of the GNU Lesser General Public
  8.  * License version 2.1 as published by the Free Software Foundation
  9.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  10.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  11.  * notice, a recipient may use your version of this file under either
  12.  * the MPL or the LGPL.
  13.  *
  14.  * You should have received a copy of the LGPL along with this library
  15.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  17.  * You should have received a copy of the MPL along with this library
  18.  * in the file COPYING-MPL-1.1
  19.  *
  20.  * The contents of this file are subject to the Mozilla Public License
  21.  * Version 1.1 (the "License"); you may not use this file except in
  22.  * compliance with the License. You may obtain a copy of the License at
  23.  * http://www.mozilla.org/MPL/
  24.  *
  25.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  26.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  27.  * the specific language governing rights and limitations.
  28.  *
  29.  * The Original Code is the cairo graphics library.
  30.  *
  31.  * The Initial Developer of the Original Code is Adrian Johnson.
  32.  *
  33.  * Contributor(s):
  34.  *      Adrian Johnson <ajohnson@redneon.com>
  35.  */
  36.  
  37. #include "cairoint.h"
  38.  
  39. #if CAIRO_HAS_PDF_OPERATORS
  40.  
  41. #include "cairo-pdf-shading-private.h"
  42.  
  43. #include "cairo-array-private.h"
  44. #include "cairo-error-private.h"
  45. #include <float.h>
  46.  
  47. static unsigned char *
  48. encode_coordinate (unsigned char *p, double c)
  49. {
  50.     uint32_t f;
  51.  
  52.     f = c;
  53.     *p++ = f >> 24;
  54.     *p++ = (f >> 16) & 0xff;
  55.     *p++ = (f >> 8)  & 0xff;
  56.     *p++ = f & 0xff;
  57.  
  58.     return p;
  59. }
  60.  
  61. static unsigned char *
  62. encode_point (unsigned char *p, const cairo_point_double_t *point)
  63. {
  64.     p = encode_coordinate (p, point->x);
  65.     p = encode_coordinate (p, point->y);
  66.  
  67.     return p;
  68. }
  69.  
  70. static unsigned char *
  71. encode_color_component (unsigned char *p, double color)
  72. {
  73.     uint16_t c;
  74.  
  75.     c = _cairo_color_double_to_short (color);
  76.     *p++ = c >> 8;
  77.     *p++ = c & 0xff;
  78.  
  79.     return p;
  80. }
  81.  
  82. static unsigned char *
  83. encode_color (unsigned char *p, const cairo_color_t *color)
  84. {
  85.     p = encode_color_component (p, color->red);
  86.     p = encode_color_component (p, color->green);
  87.     p = encode_color_component (p, color->blue);
  88.  
  89.     return p;
  90. }
  91.  
  92. static unsigned char *
  93. encode_alpha (unsigned char *p, const cairo_color_t *color)
  94. {
  95.     p = encode_color_component (p, color->alpha);
  96.  
  97.     return p;
  98. }
  99.  
  100. static cairo_status_t
  101. _cairo_pdf_shading_generate_decode_array (cairo_pdf_shading_t        *shading,
  102.                                           const cairo_mesh_pattern_t *mesh,
  103.                                           cairo_bool_t                is_alpha)
  104. {
  105.     unsigned int num_color_components, i;
  106.     cairo_bool_t is_valid;
  107.  
  108.     if (is_alpha)
  109.         num_color_components = 1;
  110.     else
  111.         num_color_components = 3;
  112.  
  113.     shading->decode_array_length = 4 + num_color_components * 2;
  114.     shading->decode_array = _cairo_malloc_ab (shading->decode_array_length,
  115.                                               sizeof (double));
  116.     if (unlikely (shading->decode_array == NULL))
  117.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  118.  
  119.     is_valid = _cairo_mesh_pattern_coord_box (mesh,
  120.                                               &shading->decode_array[0],
  121.                                               &shading->decode_array[2],
  122.                                               &shading->decode_array[1],
  123.                                               &shading->decode_array[3]);
  124.  
  125.     assert (is_valid);
  126.     assert (shading->decode_array[1] - shading->decode_array[0] >= DBL_EPSILON);
  127.     assert (shading->decode_array[3] - shading->decode_array[2] >= DBL_EPSILON);
  128.  
  129.     for (i = 0; i < num_color_components; i++) {
  130.         shading->decode_array[4 + 2*i] = 0;
  131.         shading->decode_array[5 + 2*i] = 1;
  132.     }
  133.  
  134.     return CAIRO_STATUS_SUCCESS;
  135. }
  136.  
  137. /* The ISO32000 specification mandates this order for the points which
  138.  * define the patch. */
  139. static const int pdf_points_order_i[16] = {
  140.     0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };
  141. static const int pdf_points_order_j[16] = {
  142.     0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };
  143.  
  144. static cairo_status_t
  145. _cairo_pdf_shading_generate_data (cairo_pdf_shading_t        *shading,
  146.                                   const cairo_mesh_pattern_t *mesh,
  147.                                   cairo_bool_t                is_alpha)
  148. {
  149.     const cairo_mesh_patch_t *patch;
  150.     double x_off, y_off, x_scale, y_scale;
  151.     unsigned int num_patches;
  152.     unsigned int num_color_components;
  153.     unsigned char *p;
  154.     unsigned int i, j;
  155.  
  156.     if (is_alpha)
  157.         num_color_components = 1;
  158.     else
  159.         num_color_components = 3;
  160.  
  161.     num_patches = _cairo_array_num_elements (&mesh->patches);
  162.     patch = _cairo_array_index_const (&mesh->patches, 0);
  163.  
  164.     /* Each patch requires:
  165.      *
  166.      * 1 flag - 1 byte
  167.      * 16 points. Each point is 2 coordinates. Each coordinate is
  168.      * stored in 4 bytes.
  169.      *
  170.      * 4 colors. Each color is stored in 2 bytes * num_color_components.
  171.      */
  172.     shading->data_length = num_patches * (1 + 16 * 2 * 4 + 4 * 2 * num_color_components);
  173.     shading->data = malloc (shading->data_length);
  174.     if (unlikely (shading->data == NULL))
  175.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  176.  
  177.     x_off = shading->decode_array[0];
  178.     y_off = shading->decode_array[2];
  179.     x_scale = UINT32_MAX / (shading->decode_array[1] - x_off);
  180.     y_scale = UINT32_MAX / (shading->decode_array[3] - y_off);
  181.  
  182.     p = shading->data;
  183.     for (i = 0; i < num_patches; i++) {
  184.         /* edge flag */
  185.         *p++ = 0;
  186.  
  187.         /* 16 points */
  188.         for (j = 0; j < 16; j++) {
  189.             cairo_point_double_t point;
  190.             int pi, pj;
  191.  
  192.             pi = pdf_points_order_i[j];
  193.             pj = pdf_points_order_j[j];
  194.             point = patch[i].points[pi][pj];
  195.  
  196.             /* Transform the point as specified in the decode array */
  197.             point.x -= x_off;
  198.             point.y -= y_off;
  199.             point.x *= x_scale;
  200.             point.y *= y_scale;
  201.  
  202.             /* Make sure that rounding errors don't cause
  203.              * wraparounds */
  204.             point.x = _cairo_restrict_value (point.x, 0, UINT32_MAX);
  205.             point.y = _cairo_restrict_value (point.y, 0, UINT32_MAX);
  206.  
  207.             p = encode_point (p, &point);
  208.         }
  209.  
  210.         /* 4 colors */
  211.         for (j = 0; j < 4; j++) {
  212.             if (is_alpha)
  213.                 p = encode_alpha (p, &patch[i].colors[j]);
  214.             else
  215.                 p = encode_color (p, &patch[i].colors[j]);
  216.         }
  217.     }
  218.  
  219.     assert (p == shading->data + shading->data_length);
  220.  
  221.     return CAIRO_STATUS_SUCCESS;
  222. }
  223.  
  224. static cairo_status_t
  225. _cairo_pdf_shading_init (cairo_pdf_shading_t        *shading,
  226.                          const cairo_mesh_pattern_t *mesh,
  227.                          cairo_bool_t                is_alpha)
  228. {
  229.     cairo_status_t status;
  230.  
  231.     assert (mesh->base.status == CAIRO_STATUS_SUCCESS);
  232.     assert (mesh->current_patch == NULL);
  233.  
  234.     shading->shading_type = 7;
  235.  
  236.     /*
  237.      * Coordinates from the minimum to the maximum value of the mesh
  238.      * map to the [0..UINT32_MAX] range and are represented as
  239.      * uint32_t values.
  240.      *
  241.      * Color components are represented as uint16_t (in a 0.16 fixed
  242.      * point format, as in the rest of cairo).
  243.      */
  244.     shading->bits_per_coordinate = 32;
  245.     shading->bits_per_component = 16;
  246.     shading->bits_per_flag = 8;
  247.  
  248.     shading->decode_array = NULL;
  249.     shading->data = NULL;
  250.  
  251.     status = _cairo_pdf_shading_generate_decode_array (shading, mesh, is_alpha);
  252.     if (unlikely (status))
  253.         return status;
  254.  
  255.     return _cairo_pdf_shading_generate_data (shading, mesh, is_alpha);
  256. }
  257.  
  258. cairo_status_t
  259. _cairo_pdf_shading_init_color (cairo_pdf_shading_t        *shading,
  260.                                const cairo_mesh_pattern_t *pattern)
  261. {
  262.     return _cairo_pdf_shading_init (shading, pattern, FALSE);
  263. }
  264.  
  265. cairo_status_t
  266. _cairo_pdf_shading_init_alpha (cairo_pdf_shading_t        *shading,
  267.                                const cairo_mesh_pattern_t *pattern)
  268. {
  269.     return _cairo_pdf_shading_init (shading, pattern, TRUE);
  270. }
  271.  
  272. void
  273. _cairo_pdf_shading_fini (cairo_pdf_shading_t *shading)
  274. {
  275.     free (shading->data);
  276.     free (shading->decode_array);
  277. }
  278.  
  279. #endif /* CAIRO_HAS_PDF_OPERATORS */
  280.