Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2010, 2012, Soren Sandmann <sandmann@cs.au.dk>
  3.  * Copyright 2010, 2011, 2012, Red Hat, Inc
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a
  6.  * copy of this software and associated documentation files (the "Software"),
  7.  * to deal in the Software without restriction, including without limitation
  8.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9.  * and/or sell copies of the Software, and to permit persons to whom the
  10.  * Software is furnished to do so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice (including the next
  13.  * paragraph) shall be included in all copies or substantial portions of the
  14.  * Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Author: Soren Sandmann <sandmann@cs.au.dk>
  25.  */
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include <config.h>
  29. #endif
  30. #include "pixman-private.h"
  31.  
  32. #include <stdlib.h>
  33.  
  34. typedef struct glyph_metrics_t glyph_metrics_t;
  35. typedef struct glyph_t glyph_t;
  36.  
  37. #define TOMBSTONE ((glyph_t *)0x1)
  38.  
  39. /* XXX: These numbers are arbitrary---we've never done any measurements.
  40.  */
  41. #define N_GLYPHS_HIGH_WATER  (16384)
  42. #define N_GLYPHS_LOW_WATER   (8192)
  43. #define HASH_SIZE (2 * N_GLYPHS_HIGH_WATER)
  44. #define HASH_MASK (HASH_SIZE - 1)
  45.  
  46. struct glyph_t
  47. {
  48.     void *              font_key;
  49.     void *              glyph_key;
  50.     int                 origin_x;
  51.     int                 origin_y;
  52.     pixman_image_t *    image;
  53.     pixman_link_t       mru_link;
  54. };
  55.  
  56. struct pixman_glyph_cache_t
  57. {
  58.     int                 n_glyphs;
  59.     int                 n_tombstones;
  60.     int                 freeze_count;
  61.     pixman_list_t       mru;
  62.     glyph_t *           glyphs[HASH_SIZE];
  63. };
  64.  
  65. static void
  66. free_glyph (glyph_t *glyph)
  67. {
  68.     pixman_list_unlink (&glyph->mru_link);
  69.     pixman_image_unref (glyph->image);
  70.     free (glyph);
  71. }
  72.  
  73. static unsigned int
  74. hash (const void *font_key, const void *glyph_key)
  75. {
  76.     size_t key = (size_t)font_key + (size_t)glyph_key;
  77.  
  78.     /* This hash function is based on one found on Thomas Wang's
  79.      * web page at
  80.      *
  81.      *    http://www.concentric.net/~Ttwang/tech/inthash.htm
  82.      *
  83.      */
  84.     key = (key << 15) - key - 1;
  85.     key = key ^ (key >> 12);
  86.     key = key + (key << 2);
  87.     key = key ^ (key >> 4);
  88.     key = key + (key << 3) + (key << 11);
  89.     key = key ^ (key >> 16);
  90.  
  91.     return key;
  92. }
  93.  
  94. static glyph_t *
  95. lookup_glyph (pixman_glyph_cache_t *cache,
  96.               void                 *font_key,
  97.               void                 *glyph_key)
  98. {
  99.     unsigned idx;
  100.     glyph_t *g;
  101.  
  102.     idx = hash (font_key, glyph_key);
  103.     while ((g = cache->glyphs[idx++ & HASH_MASK]))
  104.     {
  105.         if (g != TOMBSTONE                      &&
  106.             g->font_key == font_key             &&
  107.             g->glyph_key == glyph_key)
  108.         {
  109.             return g;
  110.         }
  111.     }
  112.  
  113.     return NULL;
  114. }
  115.  
  116. static void
  117. insert_glyph (pixman_glyph_cache_t *cache,
  118.               glyph_t              *glyph)
  119. {
  120.     unsigned idx;
  121.     glyph_t **loc;
  122.  
  123.     idx = hash (glyph->font_key, glyph->glyph_key);
  124.  
  125.     /* Note: we assume that there is room in the table. If there isn't,
  126.      * this will be an infinite loop.
  127.      */
  128.     do
  129.     {
  130.         loc = &cache->glyphs[idx++ & HASH_MASK];
  131.     } while (*loc && *loc != TOMBSTONE);
  132.  
  133.     if (*loc == TOMBSTONE)
  134.         cache->n_tombstones--;
  135.     cache->n_glyphs++;
  136.  
  137.     *loc = glyph;
  138. }
  139.  
  140. static void
  141. remove_glyph (pixman_glyph_cache_t *cache,
  142.               glyph_t              *glyph)
  143. {
  144.     unsigned idx;
  145.  
  146.     idx = hash (glyph->font_key, glyph->glyph_key);
  147.     while (cache->glyphs[idx & HASH_MASK] != glyph)
  148.         idx++;
  149.  
  150.     cache->glyphs[idx & HASH_MASK] = TOMBSTONE;
  151.     cache->n_tombstones++;
  152.     cache->n_glyphs--;
  153.  
  154.     /* Eliminate tombstones if possible */
  155.     if (cache->glyphs[(idx + 1) & HASH_MASK] == NULL)
  156.     {
  157.         while (cache->glyphs[idx & HASH_MASK] == TOMBSTONE)
  158.         {
  159.             cache->glyphs[idx & HASH_MASK] = NULL;
  160.             cache->n_tombstones--;
  161.             idx--;
  162.         }
  163.     }
  164. }
  165.  
  166. static void
  167. clear_table (pixman_glyph_cache_t *cache)
  168. {
  169.     int i;
  170.  
  171.     for (i = 0; i < HASH_SIZE; ++i)
  172.     {
  173.         glyph_t *glyph = cache->glyphs[i];
  174.  
  175.         if (glyph && glyph != TOMBSTONE)
  176.             free_glyph (glyph);
  177.  
  178.         cache->glyphs[i] = NULL;
  179.     }
  180.  
  181.     cache->n_glyphs = 0;
  182.     cache->n_tombstones = 0;
  183. }
  184.  
  185. PIXMAN_EXPORT pixman_glyph_cache_t *
  186. pixman_glyph_cache_create (void)
  187. {
  188.     pixman_glyph_cache_t *cache;
  189.  
  190.     if (!(cache = malloc (sizeof *cache)))
  191.         return NULL;
  192.  
  193.     memset (cache->glyphs, 0, sizeof (cache->glyphs));
  194.     cache->n_glyphs = 0;
  195.     cache->n_tombstones = 0;
  196.     cache->freeze_count = 0;
  197.  
  198.     pixman_list_init (&cache->mru);
  199.  
  200.     return cache;
  201. }
  202.  
  203. PIXMAN_EXPORT void
  204. pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache)
  205. {
  206.     return_if_fail (cache->freeze_count == 0);
  207.  
  208.     clear_table (cache);
  209.  
  210.     free (cache);
  211. }
  212.  
  213. PIXMAN_EXPORT void
  214. pixman_glyph_cache_freeze (pixman_glyph_cache_t  *cache)
  215. {
  216.     cache->freeze_count++;
  217. }
  218.  
  219. PIXMAN_EXPORT void
  220. pixman_glyph_cache_thaw (pixman_glyph_cache_t  *cache)
  221. {
  222.     if (--cache->freeze_count == 0                                      &&
  223.         cache->n_glyphs + cache->n_tombstones > N_GLYPHS_HIGH_WATER)
  224.     {
  225.         if (cache->n_tombstones > N_GLYPHS_HIGH_WATER)
  226.         {
  227.             /* More than half the entries are
  228.              * tombstones. Just dump the whole table.
  229.              */
  230.             clear_table (cache);
  231.         }
  232.  
  233.         while (cache->n_glyphs > N_GLYPHS_LOW_WATER)
  234.         {
  235.             glyph_t *glyph = CONTAINER_OF (glyph_t, mru_link, cache->mru.tail);
  236.  
  237.             remove_glyph (cache, glyph);
  238.             free_glyph (glyph);
  239.         }
  240.     }
  241. }
  242.  
  243. PIXMAN_EXPORT const void *
  244. pixman_glyph_cache_lookup (pixman_glyph_cache_t  *cache,
  245.                            void                  *font_key,
  246.                            void                  *glyph_key)
  247. {
  248.     return lookup_glyph (cache, font_key, glyph_key);
  249. }
  250.  
  251. PIXMAN_EXPORT const void *
  252. pixman_glyph_cache_insert (pixman_glyph_cache_t  *cache,
  253.                            void                  *font_key,
  254.                            void                  *glyph_key,
  255.                            int                    origin_x,
  256.                            int                    origin_y,
  257.                            pixman_image_t        *image)
  258. {
  259.     glyph_t *glyph;
  260.     int32_t width, height;
  261.  
  262.     return_val_if_fail (cache->freeze_count > 0, NULL);
  263.     return_val_if_fail (image->type == BITS, NULL);
  264.  
  265.     width = image->bits.width;
  266.     height = image->bits.height;
  267.  
  268.     if (cache->n_glyphs >= HASH_SIZE)
  269.         return NULL;
  270.  
  271.     if (!(glyph = malloc (sizeof *glyph)))
  272.         return NULL;
  273.  
  274.     glyph->font_key = font_key;
  275.     glyph->glyph_key = glyph_key;
  276.     glyph->origin_x = origin_x;
  277.     glyph->origin_y = origin_y;
  278.  
  279.     if (!(glyph->image = pixman_image_create_bits (
  280.               image->bits.format, width, height, NULL, -1)))
  281.     {
  282.         free (glyph);
  283.         return NULL;
  284.     }
  285.  
  286.     pixman_image_composite32 (PIXMAN_OP_SRC,
  287.                               image, NULL, glyph->image, 0, 0, 0, 0, 0, 0,
  288.                               width, height);
  289.  
  290.     if (PIXMAN_FORMAT_A   (glyph->image->bits.format) != 0      &&
  291.         PIXMAN_FORMAT_RGB (glyph->image->bits.format) != 0)
  292.     {
  293.         pixman_image_set_component_alpha (glyph->image, TRUE);
  294.     }
  295.  
  296.     pixman_list_prepend (&cache->mru, &glyph->mru_link);
  297.  
  298.     _pixman_image_validate (glyph->image);
  299.     insert_glyph (cache, glyph);
  300.  
  301.     return glyph;
  302. }
  303.  
  304. PIXMAN_EXPORT void
  305. pixman_glyph_cache_remove (pixman_glyph_cache_t  *cache,
  306.                            void                  *font_key,
  307.                            void                  *glyph_key)
  308. {
  309.     glyph_t *glyph;
  310.  
  311.     if ((glyph = lookup_glyph (cache, font_key, glyph_key)))
  312.     {
  313.         remove_glyph (cache, glyph);
  314.  
  315.         free_glyph (glyph);
  316.     }
  317. }
  318.  
  319. PIXMAN_EXPORT void
  320. pixman_glyph_get_extents (pixman_glyph_cache_t *cache,
  321.                           int                   n_glyphs,
  322.                           pixman_glyph_t       *glyphs,
  323.                           pixman_box32_t       *extents)
  324. {
  325.     int i;
  326.  
  327.     extents->x1 = extents->y1 = INT32_MAX;
  328.     extents->x2 = extents->y2 = INT32_MIN;
  329.  
  330.     for (i = 0; i < n_glyphs; ++i)
  331.     {
  332.         glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
  333.         int x1, y1, x2, y2;
  334.  
  335.         x1 = glyphs[i].x - glyph->origin_x;
  336.         y1 = glyphs[i].y - glyph->origin_y;
  337.         x2 = glyphs[i].x - glyph->origin_x + glyph->image->bits.width;
  338.         y2 = glyphs[i].y - glyph->origin_y + glyph->image->bits.height;
  339.  
  340.         if (x1 < extents->x1)
  341.             extents->x1 = x1;
  342.         if (y1 < extents->y1)
  343.             extents->y1 = y1;
  344.         if (x2 > extents->x2)
  345.             extents->x2 = x2;
  346.         if (y2 > extents->y2)
  347.             extents->y2 = y2;
  348.     }
  349. }
  350.  
  351. /* This function returns a format that is suitable for use as a mask for the
  352.  * set of glyphs in question.
  353.  */
  354. PIXMAN_EXPORT pixman_format_code_t
  355. pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
  356.                               int                   n_glyphs,
  357.                               const pixman_glyph_t *glyphs)
  358. {
  359.     pixman_format_code_t format = PIXMAN_a1;
  360.     int i;
  361.  
  362.     for (i = 0; i < n_glyphs; ++i)
  363.     {
  364.         const glyph_t *glyph = glyphs[i].glyph;
  365.         pixman_format_code_t glyph_format = glyph->image->bits.format;
  366.  
  367.         if (PIXMAN_FORMAT_TYPE (glyph_format) == PIXMAN_TYPE_A)
  368.         {
  369.             if (PIXMAN_FORMAT_A (glyph_format) > PIXMAN_FORMAT_A (format))
  370.                 format = glyph_format;
  371.         }
  372.         else
  373.         {
  374.             return PIXMAN_a8r8g8b8;
  375.         }
  376.     }
  377.  
  378.     return format;
  379. }
  380.  
  381. static pixman_bool_t
  382. box32_intersect (pixman_box32_t *dest,
  383.                  const pixman_box32_t *box1,
  384.                  const pixman_box32_t *box2)
  385. {
  386.     dest->x1 = MAX (box1->x1, box2->x1);
  387.     dest->y1 = MAX (box1->y1, box2->y1);
  388.     dest->x2 = MIN (box1->x2, box2->x2);
  389.     dest->y2 = MIN (box1->y2, box2->y2);
  390.  
  391.     return dest->x2 > dest->x1 && dest->y2 > dest->y1;
  392. }
  393.  
  394. PIXMAN_EXPORT void
  395. pixman_composite_glyphs_no_mask (pixman_op_t            op,
  396.                                  pixman_image_t        *src,
  397.                                  pixman_image_t        *dest,
  398.                                  int32_t                src_x,
  399.                                  int32_t                src_y,
  400.                                  int32_t                dest_x,
  401.                                  int32_t                dest_y,
  402.                                  pixman_glyph_cache_t  *cache,
  403.                                  int                    n_glyphs,
  404.                                  const pixman_glyph_t  *glyphs)
  405. {
  406.     pixman_region32_t region;
  407.     pixman_format_code_t glyph_format = PIXMAN_null;
  408.     uint32_t glyph_flags = 0;
  409.     pixman_format_code_t dest_format;
  410.     uint32_t dest_flags;
  411.     pixman_composite_func_t func = NULL;
  412.     pixman_implementation_t *implementation = NULL;
  413.     pixman_composite_info_t info;
  414.     int i;
  415.  
  416.     _pixman_image_validate (src);
  417.     _pixman_image_validate (dest);
  418.    
  419.     dest_format = dest->common.extended_format_code;
  420.     dest_flags = dest->common.flags;
  421.    
  422.     pixman_region32_init (&region);
  423.     if (!_pixman_compute_composite_region32 (
  424.             &region,
  425.             src, NULL, dest,
  426.             src_x - dest_x, src_y - dest_y, 0, 0, 0, 0,
  427.             dest->bits.width, dest->bits.height))
  428.     {
  429.         goto out;
  430.     }
  431.  
  432.     info.op = op;
  433.     info.src_image = src;
  434.     info.dest_image = dest;
  435.     info.src_flags = src->common.flags;
  436.     info.dest_flags = dest->common.flags;
  437.  
  438.     for (i = 0; i < n_glyphs; ++i)
  439.     {
  440.         glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
  441.         pixman_image_t *glyph_img = glyph->image;
  442.         pixman_box32_t glyph_box;
  443.         pixman_box32_t *pbox;
  444.         uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
  445.         pixman_box32_t composite_box;
  446.         int n;
  447.  
  448.         glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x;
  449.         glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y;
  450.         glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
  451.         glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
  452.        
  453.         pbox = pixman_region32_rectangles (&region, &n);
  454.        
  455.         info.mask_image = glyph_img;
  456.  
  457.         while (n--)
  458.         {
  459.             if (box32_intersect (&composite_box, pbox, &glyph_box))
  460.             {
  461.                 if (glyph_img->common.extended_format_code != glyph_format      ||
  462.                     glyph_img->common.flags != glyph_flags)
  463.                 {
  464.                     glyph_format = glyph_img->common.extended_format_code;
  465.                     glyph_flags = glyph_img->common.flags;
  466.  
  467.                     _pixman_implementation_lookup_composite (
  468.                         get_implementation(), op,
  469.                         src->common.extended_format_code, src->common.flags,
  470.                         glyph_format, glyph_flags | extra,
  471.                         dest_format, dest_flags,
  472.                         &implementation, &func);
  473.                 }
  474.  
  475.                 info.src_x = src_x + composite_box.x1 - dest_x;
  476.                 info.src_y = src_y + composite_box.y1 - dest_y;
  477.                 info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x);
  478.                 info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y);
  479.                 info.dest_x = composite_box.x1;
  480.                 info.dest_y = composite_box.y1;
  481.                 info.width = composite_box.x2 - composite_box.x1;
  482.                 info.height = composite_box.y2 - composite_box.y1;
  483.  
  484.                 info.mask_flags = glyph_flags;
  485.  
  486.                 func (implementation, &info);
  487.             }
  488.  
  489.             pbox++;
  490.         }
  491.         pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
  492.     }
  493.  
  494. out:
  495.     pixman_region32_fini (&region);
  496. }
  497.  
  498. static void
  499. add_glyphs (pixman_glyph_cache_t *cache,
  500.             pixman_image_t *dest,
  501.             int off_x, int off_y,
  502.             int n_glyphs, const pixman_glyph_t *glyphs)
  503. {
  504.     pixman_format_code_t glyph_format = PIXMAN_null;
  505.     uint32_t glyph_flags = 0;
  506.     pixman_composite_func_t func = NULL;
  507.     pixman_implementation_t *implementation = NULL;
  508.     pixman_format_code_t dest_format;
  509.     uint32_t dest_flags;
  510.     pixman_box32_t dest_box;
  511.     pixman_composite_info_t info;
  512.     pixman_image_t *white_img = NULL;
  513.     pixman_bool_t white_src = FALSE;
  514.     int i;
  515.  
  516.     _pixman_image_validate (dest);
  517.  
  518.     dest_format = dest->common.extended_format_code;
  519.     dest_flags = dest->common.flags;
  520.  
  521.     info.op = PIXMAN_OP_ADD;
  522.     info.dest_image = dest;
  523.     info.src_x = 0;
  524.     info.src_y = 0;
  525.     info.dest_flags = dest_flags;
  526.  
  527.     dest_box.x1 = 0;
  528.     dest_box.y1 = 0;
  529.     dest_box.x2 = dest->bits.width;
  530.     dest_box.y2 = dest->bits.height;
  531.  
  532.     for (i = 0; i < n_glyphs; ++i)
  533.     {
  534.         glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
  535.         pixman_image_t *glyph_img = glyph->image;
  536.         pixman_box32_t glyph_box;
  537.         pixman_box32_t composite_box;
  538.  
  539.         if (glyph_img->common.extended_format_code != glyph_format      ||
  540.             glyph_img->common.flags != glyph_flags)
  541.         {
  542.             pixman_format_code_t src_format, mask_format;
  543.  
  544.             glyph_format = glyph_img->common.extended_format_code;
  545.             glyph_flags = glyph_img->common.flags;
  546.  
  547.             if (glyph_format == dest->bits.format)
  548.             {
  549.                 src_format = glyph_format;
  550.                 mask_format = PIXMAN_null;
  551.                 info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
  552.                 info.mask_flags = FAST_PATH_IS_OPAQUE;
  553.                 info.mask_image = NULL;
  554.                 white_src = FALSE;
  555.             }
  556.             else
  557.             {
  558.                 if (!white_img)
  559.                 {
  560.                     static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
  561.  
  562.                     if (!(white_img = pixman_image_create_solid_fill (&white)))
  563.                         goto out;
  564.  
  565.                     _pixman_image_validate (white_img);
  566.                 }
  567.  
  568.                 src_format = PIXMAN_solid;
  569.                 mask_format = glyph_format;
  570.                 info.src_flags = white_img->common.flags;
  571.                 info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
  572.                 info.src_image = white_img;
  573.                 white_src = TRUE;
  574.             }
  575.  
  576.             _pixman_implementation_lookup_composite (
  577.                 get_implementation(), PIXMAN_OP_ADD,
  578.                 src_format, info.src_flags,
  579.                 mask_format, info.mask_flags,
  580.                 dest_format, dest_flags,
  581.                 &implementation, &func);
  582.         }
  583.  
  584.         glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
  585.         glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
  586.         glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
  587.         glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
  588.        
  589.         if (box32_intersect (&composite_box, &glyph_box, &dest_box))
  590.         {
  591.             int src_x = composite_box.x1 - glyph_box.x1;
  592.             int src_y = composite_box.y1 - glyph_box.y1;
  593.  
  594.             if (white_src)
  595.                 info.mask_image = glyph_img;
  596.             else
  597.                 info.src_image = glyph_img;
  598.  
  599.             info.mask_x = info.src_x = src_x;
  600.             info.mask_y = info.src_y = src_y;
  601.             info.dest_x = composite_box.x1;
  602.             info.dest_y = composite_box.y1;
  603.             info.width = composite_box.x2 - composite_box.x1;
  604.             info.height = composite_box.y2 - composite_box.y1;
  605.  
  606.             func (implementation, &info);
  607.  
  608.             pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
  609.         }
  610.     }
  611.  
  612. out:
  613.     if (white_img)
  614.         pixman_image_unref (white_img);
  615. }
  616.  
  617. /* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
  618.  * infinitely big mask image at the position such that the glyph origin point
  619.  * is positioned at the (glyphs[i].x, glyphs[i].y) point.
  620.  *
  621.  * Then (mask_x, mask_y) in the infinite mask and (src_x, src_y) in the source
  622.  * image are both aligned with (dest_x, dest_y) in the destination image. Then
  623.  * these three images are composited within the
  624.  *
  625.  *       (dest_x, dest_y, dst_x + width, dst_y + height)
  626.  *
  627.  * rectangle.
  628.  *
  629.  * TODO:
  630.  *   - Trim the mask to the destination clip/image?
  631.  *   - Trim composite region based on sources, when the op ignores 0s.
  632.  */
  633. PIXMAN_EXPORT void
  634. pixman_composite_glyphs (pixman_op_t            op,
  635.                          pixman_image_t        *src,
  636.                          pixman_image_t        *dest,
  637.                          pixman_format_code_t   mask_format,
  638.                          int32_t                src_x,
  639.                          int32_t                src_y,
  640.                          int32_t                mask_x,
  641.                          int32_t                mask_y,
  642.                          int32_t                dest_x,
  643.                          int32_t                dest_y,
  644.                          int32_t                width,
  645.                          int32_t                height,
  646.                          pixman_glyph_cache_t  *cache,
  647.                          int                    n_glyphs,
  648.                          const pixman_glyph_t  *glyphs)
  649. {
  650.     pixman_image_t *mask;
  651.  
  652.     if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
  653.         return;
  654.  
  655.     if (PIXMAN_FORMAT_A   (mask_format) != 0 &&
  656.         PIXMAN_FORMAT_RGB (mask_format) != 0)
  657.     {
  658.         pixman_image_set_component_alpha (mask, TRUE);
  659.     }
  660.  
  661.     add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
  662.  
  663.     pixman_image_composite32 (op, src, mask, dest,
  664.                               src_x, src_y,
  665.                               0, 0,
  666.                               dest_x, dest_y,
  667.                               width, height);
  668.  
  669.     pixman_image_unref (mask);
  670. }
  671.