11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/*
21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2010, 2012, Soren Sandmann <sandmann@cs.au.dk>
31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2010, 2011, 2012, Red Hat, Inc
41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission is hereby granted, free of charge, to any person obtaining a
61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copy of this software and associated documentation files (the "Software"),
71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * to deal in the Software without restriction, including without limitation
81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the rights to use, copy, modify, merge, publish, distribute, sublicense,
91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and/or sell copies of the Software, and to permit persons to whom the
101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software is furnished to do so, subject to the following conditions:
111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * The above copyright notice and this permission notice (including the next
131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * paragraph) shall be included in all copies or substantial portions of the
141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software.
151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * DEALINGS IN THE SOFTWARE.
231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Author: Soren Sandmann <sandmann@cs.au.dk>
251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H
281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h>
291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h"
311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdlib.h>
331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
341176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef struct glyph_metrics_t glyph_metrics_t;
351176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef struct glyph_t glyph_t;
361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define TOMBSTONE ((glyph_t *)0x1)
381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* XXX: These numbers are arbitrary---we've never done any measurements.
401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define N_GLYPHS_HIGH_WATER  (16384)
421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define N_GLYPHS_LOW_WATER   (8192)
431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define HASH_SIZE (2 * N_GLYPHS_HIGH_WATER)
441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define HASH_MASK (HASH_SIZE - 1)
451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
461176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstruct glyph_t
471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    void *		font_key;
491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    void *		glyph_key;
501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int			origin_x;
511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int			origin_y;
521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *	image;
531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_link_t	mru_link;
541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck};
551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
561176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstruct pixman_glyph_cache_t
571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int			n_glyphs;
591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int			n_tombstones;
601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int			freeze_count;
611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_list_t	mru;
621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph_t *		glyphs[HASH_SIZE];
631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck};
641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
651176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
661176bdada62cabc6ec4b0308a930e83b679d5d36John Reckfree_glyph (glyph_t *glyph)
671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_list_unlink (&glyph->mru_link);
691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_unref (glyph->image);
701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    free (glyph);
711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
731176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic unsigned int
741176bdada62cabc6ec4b0308a930e83b679d5d36John Reckhash (const void *font_key, const void *glyph_key)
751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    size_t key = (size_t)font_key + (size_t)glyph_key;
771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* This hash function is based on one found on Thomas Wang's
791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * web page at
801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    http://www.concentric.net/~Ttwang/tech/inthash.htm
821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = (key << 15) - key - 1;
851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = key ^ (key >> 12);
861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = key + (key << 2);
871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = key ^ (key >> 4);
881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = key + (key << 3) + (key << 11);
891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    key = key ^ (key >> 16);
901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return key;
921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
941176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic glyph_t *
951176bdada62cabc6ec4b0308a930e83b679d5d36John Recklookup_glyph (pixman_glyph_cache_t *cache,
961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      void                 *font_key,
971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      void                 *glyph_key)
981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    unsigned idx;
1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph_t *g;
1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    idx = hash (font_key, glyph_key);
1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    while ((g = cache->glyphs[idx++ & HASH_MASK]))
1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (g != TOMBSTONE			&&
1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    g->font_key == font_key		&&
1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    g->glyph_key == glyph_key)
1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    return g;
1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return NULL;
1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reckinsert_glyph (pixman_glyph_cache_t *cache,
1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      glyph_t              *glyph)
1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    unsigned idx;
1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph_t **loc;
1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    idx = hash (glyph->font_key, glyph->glyph_key);
1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* Note: we assume that there is room in the table. If there isn't,
1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * this will be an infinite loop.
1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    do
1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	loc = &cache->glyphs[idx++ & HASH_MASK];
1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    } while (*loc && *loc != TOMBSTONE);
1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (*loc == TOMBSTONE)
1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cache->n_tombstones--;
1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_glyphs++;
1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    *loc = glyph;
1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reckremove_glyph (pixman_glyph_cache_t *cache,
1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      glyph_t              *glyph)
1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    unsigned idx;
1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    idx = hash (glyph->font_key, glyph->glyph_key);
1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    while (cache->glyphs[idx & HASH_MASK] != glyph)
1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	idx++;
1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->glyphs[idx & HASH_MASK] = TOMBSTONE;
1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_tombstones++;
1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_glyphs--;
1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* Eliminate tombstones if possible */
1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (cache->glyphs[(idx + 1) & HASH_MASK] == NULL)
1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (cache->glyphs[idx & HASH_MASK] == TOMBSTONE)
1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    cache->glyphs[idx & HASH_MASK] = NULL;
1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    cache->n_tombstones--;
1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    idx--;
1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reckclear_table (pixman_glyph_cache_t *cache)
1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int i;
1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (i = 0; i < HASH_SIZE; ++i)
1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_t *glyph = cache->glyphs[i];
1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (glyph && glyph != TOMBSTONE)
1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    free_glyph (glyph);
1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cache->glyphs[i] = NULL;
1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_glyphs = 0;
1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_tombstones = 0;
1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1851176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT pixman_glyph_cache_t *
1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_create (void)
1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_glyph_cache_t *cache;
1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!(cache = malloc (sizeof *cache)))
1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    memset (cache->glyphs, 0, sizeof (cache->glyphs));
1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_glyphs = 0;
1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->n_tombstones = 0;
1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->freeze_count = 0;
1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_list_init (&cache->mru);
1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return cache;
2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2031176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_destroy (pixman_glyph_cache_t *cache)
2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return_if_fail (cache->freeze_count == 0);
2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    clear_table (cache);
2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    free (cache);
2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2131176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_freeze (pixman_glyph_cache_t  *cache)
2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cache->freeze_count++;
2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2191176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_thaw (pixman_glyph_cache_t  *cache)
2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (--cache->freeze_count == 0					&&
2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cache->n_glyphs + cache->n_tombstones > N_GLYPHS_HIGH_WATER)
2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (cache->n_tombstones > N_GLYPHS_HIGH_WATER)
2261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
2271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    /* More than half the entries are
2281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	     * tombstones. Just dump the whole table.
2291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	     */
2301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    clear_table (cache);
2311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
2321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (cache->n_glyphs > N_GLYPHS_LOW_WATER)
2341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
2351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    glyph_t *glyph = CONTAINER_OF (glyph_t, mru_link, cache->mru.tail);
2361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    remove_glyph (cache, glyph);
2381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    free_glyph (glyph);
2391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
2401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2431176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT const void *
2441176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_lookup (pixman_glyph_cache_t  *cache,
2451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *font_key,
2461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *glyph_key)
2471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return lookup_glyph (cache, font_key, glyph_key);
2491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2511176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT const void *
2521176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_insert (pixman_glyph_cache_t  *cache,
2531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *font_key,
2541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *glyph_key,
2551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   int			  origin_x,
2561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   int                    origin_y,
2571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   pixman_image_t        *image)
2581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph_t *glyph;
2601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int32_t width, height;
2611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return_val_if_fail (cache->freeze_count > 0, NULL);
2631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return_val_if_fail (image->type == BITS, NULL);
2641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    width = image->bits.width;
2661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    height = image->bits.height;
2671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (cache->n_glyphs >= HASH_SIZE)
2691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
2701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!(glyph = malloc (sizeof *glyph)))
2721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
2731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph->font_key = font_key;
2751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph->glyph_key = glyph_key;
2761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph->origin_x = origin_x;
2771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph->origin_y = origin_y;
2781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!(glyph->image = pixman_image_create_bits (
2801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      image->bits.format, width, height, NULL, -1)))
2811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	free (glyph);
2831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
2841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_composite32 (PIXMAN_OP_SRC,
2871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      image, NULL, glyph->image, 0, 0, 0, 0, 0, 0,
2881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      width, height);
2891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (PIXMAN_FORMAT_A   (glyph->image->bits.format) != 0	&&
2911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	PIXMAN_FORMAT_RGB (glyph->image->bits.format) != 0)
2921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_image_set_component_alpha (glyph->image, TRUE);
2941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_list_prepend (&cache->mru, &glyph->mru_link);
2971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_image_validate (glyph->image);
2991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    insert_glyph (cache, glyph);
3001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return glyph;
3021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
3031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3041176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
3051176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_cache_remove (pixman_glyph_cache_t  *cache,
3061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *font_key,
3071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			   void                  *glyph_key)
3081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
3091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    glyph_t *glyph;
3101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if ((glyph = lookup_glyph (cache, font_key, glyph_key)))
3121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
3131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	remove_glyph (cache, glyph);
3141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	free_glyph (glyph);
3161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
3171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
3181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3191176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
3201176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_get_extents (pixman_glyph_cache_t *cache,
3211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			  int                   n_glyphs,
3221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			  pixman_glyph_t       *glyphs,
3231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			  pixman_box32_t       *extents)
3241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
3251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int i;
3261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    extents->x1 = extents->y1 = INT32_MAX;
3281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    extents->x2 = extents->y2 = INT32_MIN;
3291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (i = 0; i < n_glyphs; ++i)
3311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
3321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
3331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	int x1, y1, x2, y2;
3341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	x1 = glyphs[i].x - glyph->origin_x;
3361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	y1 = glyphs[i].y - glyph->origin_y;
3371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	x2 = glyphs[i].x - glyph->origin_x + glyph->image->bits.width;
3381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	y2 = glyphs[i].y - glyph->origin_y + glyph->image->bits.height;
3391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (x1 < extents->x1)
3411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    extents->x1 = x1;
3421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (y1 < extents->y1)
3431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    extents->y1 = y1;
3441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (x2 > extents->x2)
3451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    extents->x2 = x2;
3461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (y2 > extents->y2)
3471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    extents->y2 = y2;
3481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
3491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
3501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* This function returns a format that is suitable for use as a mask for the
3521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * set of glyphs in question.
3531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
3541176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT pixman_format_code_t
3551176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
3561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      int		    n_glyphs,
3571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      const pixman_glyph_t *glyphs)
3581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
3591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_format_code_t format = PIXMAN_a1;
3601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int i;
3611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (i = 0; i < n_glyphs; ++i)
3631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
3641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	const glyph_t *glyph = glyphs[i].glyph;
3651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_format_code_t glyph_format = glyph->image->bits.format;
3661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (PIXMAN_FORMAT_TYPE (glyph_format) == PIXMAN_TYPE_A)
3681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
3691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (PIXMAN_FORMAT_A (glyph_format) > PIXMAN_FORMAT_A (format))
3701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		format = glyph_format;
3711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
3721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	else
3731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
3741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    return PIXMAN_a8r8g8b8;
3751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
3761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
3771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return format;
3791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
3801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3811176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_bool_t
3821176bdada62cabc6ec4b0308a930e83b679d5d36John Reckbox32_intersect (pixman_box32_t *dest,
3831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		 const pixman_box32_t *box1,
3841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		 const pixman_box32_t *box2)
3851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
3861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest->x1 = MAX (box1->x1, box2->x1);
3871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest->y1 = MAX (box1->y1, box2->y1);
3881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest->x2 = MIN (box1->x2, box2->x2);
3891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest->y2 = MIN (box1->y2, box2->y2);
3901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return dest->x2 > dest->x1 && dest->y2 > dest->y1;
3921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
3931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3941176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
3951176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_composite_glyphs_no_mask (pixman_op_t            op,
3961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 pixman_image_t        *src,
3971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 pixman_image_t        *dest,
3981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 int32_t                src_x,
3991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 int32_t                src_y,
4001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 int32_t                dest_x,
4011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 int32_t                dest_y,
4021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 pixman_glyph_cache_t  *cache,
4031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 int                    n_glyphs,
4041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				 const pixman_glyph_t  *glyphs)
4051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
4061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_region32_t region;
4071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_format_code_t glyph_format = PIXMAN_null;
4081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t glyph_flags = 0;
4091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_format_code_t dest_format;
4101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t dest_flags;
4111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_composite_func_t func = NULL;
4121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_implementation_t *implementation = NULL;
4131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_composite_info_t info;
4141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int i;
4151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_image_validate (src);
4171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_image_validate (dest);
4181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_format = dest->common.extended_format_code;
4201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_flags = dest->common.flags;
4211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_region32_init (&region);
4231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!_pixman_compute_composite_region32 (
4241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    &region,
4251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    src, NULL, dest,
4261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    src_x - dest_x, src_y - dest_y, 0, 0, 0, 0,
4271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    dest->bits.width, dest->bits.height))
4281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
4291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	goto out;
4301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
4311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.op = op;
4331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.src_image = src;
4341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.dest_image = dest;
4351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.src_flags = src->common.flags;
4361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.dest_flags = dest->common.flags;
4371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (i = 0; i < n_glyphs; ++i)
4391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
4401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
4411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_image_t *glyph_img = glyph->image;
4421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_box32_t glyph_box;
4431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_box32_t *pbox;
4441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
4451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_box32_t composite_box;
4461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	int n;
4471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x;
4491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y;
4501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
4511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
4521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pbox = pixman_region32_rectangles (&region, &n);
4541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	info.mask_image = glyph_img;
4561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (n--)
4581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
4591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (box32_intersect (&composite_box, pbox, &glyph_box))
4601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
4611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		if (glyph_img->common.extended_format_code != glyph_format	||
4621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    glyph_img->common.flags != glyph_flags)
4631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
4641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    glyph_format = glyph_img->common.extended_format_code;
4651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    glyph_flags = glyph_img->common.flags;
4661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    _pixman_implementation_lookup_composite (
4681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			get_implementation(), op,
4691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			src->common.extended_format_code, src->common.flags,
4701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			glyph_format, glyph_flags | extra,
4711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			dest_format, dest_flags,
4721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			&implementation, &func);
4731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
4741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_x = src_x + composite_box.x1 - dest_x;
4761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_y = src_y + composite_box.y1 - dest_y;
4771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x);
4781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y);
4791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.dest_x = composite_box.x1;
4801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.dest_y = composite_box.y1;
4811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.width = composite_box.x2 - composite_box.x1;
4821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.height = composite_box.y2 - composite_box.y1;
4831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_flags = glyph_flags;
4851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		func (implementation, &info);
4871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
4881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pbox++;
4901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
4911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
4921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
4931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4941176bdada62cabc6ec4b0308a930e83b679d5d36John Reckout:
4951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_region32_fini (&region);
4961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
4971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4981176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
4991176bdada62cabc6ec4b0308a930e83b679d5d36John Reckadd_glyphs (pixman_glyph_cache_t *cache,
5001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pixman_image_t *dest,
5011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    int off_x, int off_y,
5021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    int n_glyphs, const pixman_glyph_t *glyphs)
5031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
5041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_format_code_t glyph_format = PIXMAN_null;
5051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t glyph_flags = 0;
5061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_composite_func_t func = NULL;
5071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_implementation_t *implementation = NULL;
5081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_format_code_t dest_format;
5091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t dest_flags;
5101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_box32_t dest_box;
5111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_composite_info_t info;
5121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *white_img = NULL;
5131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_bool_t white_src = FALSE;
5141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int i;
5151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_image_validate (dest);
5171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_format = dest->common.extended_format_code;
5191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_flags = dest->common.flags;
5201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.op = PIXMAN_OP_ADD;
5221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.dest_image = dest;
5231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.src_x = 0;
5241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.src_y = 0;
5251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    info.dest_flags = dest_flags;
5261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_box.x1 = 0;
5281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_box.y1 = 0;
5291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_box.x2 = dest->bits.width;
5301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    dest_box.y2 = dest->bits.height;
5311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (i = 0; i < n_glyphs; ++i)
5331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
5341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
5351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_image_t *glyph_img = glyph->image;
5361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_box32_t glyph_box;
5371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_box32_t composite_box;
5381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (glyph_img->common.extended_format_code != glyph_format	||
5401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    glyph_img->common.flags != glyph_flags)
5411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
5421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pixman_format_code_t src_format, mask_format;
5431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    glyph_format = glyph_img->common.extended_format_code;
5451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    glyph_flags = glyph_img->common.flags;
5461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (glyph_format == dest->bits.format)
5481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
5491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		src_format = glyph_format;
5501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		mask_format = PIXMAN_null;
5511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
5521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_flags = FAST_PATH_IS_OPAQUE;
5531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_image = NULL;
5541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		white_src = FALSE;
5551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
5561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    else
5571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
5581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		if (!white_img)
5591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
5601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
5611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    if (!(white_img = pixman_image_create_solid_fill (&white)))
5631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			goto out;
5641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    _pixman_image_validate (white_img);
5661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
5671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		src_format = PIXMAN_solid;
5691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		mask_format = glyph_format;
5701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_flags = white_img->common.flags;
5711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
5721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_image = white_img;
5731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		white_src = TRUE;
5741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
5751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    _pixman_implementation_lookup_composite (
5771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		get_implementation(), PIXMAN_OP_ADD,
5781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		src_format, info.src_flags,
5791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		mask_format, info.mask_flags,
5801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		dest_format, dest_flags,
5811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		&implementation, &func);
5821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
5831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
5851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
5861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
5871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
5881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (box32_intersect (&composite_box, &glyph_box, &dest_box))
5901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
5911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    int src_x = composite_box.x1 - glyph_box.x1;
5921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    int src_y = composite_box.y1 - glyph_box.y1;
5931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (white_src)
5951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.mask_image = glyph_img;
5961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    else
5971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		info.src_image = glyph_img;
5981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
5991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.mask_x = info.src_x = src_x;
6001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.mask_y = info.src_y = src_y;
6011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.dest_x = composite_box.x1;
6021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.dest_y = composite_box.y1;
6031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.width = composite_box.x2 - composite_box.x1;
6041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    info.height = composite_box.y2 - composite_box.y1;
6051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    func (implementation, &info);
6071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
6091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
6101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
6111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6121176bdada62cabc6ec4b0308a930e83b679d5d36John Reckout:
6131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (white_img)
6141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_image_unref (white_img);
6151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
6161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
6181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * infinitely big mask image at the position such that the glyph origin point
6191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * is positioned at the (glyphs[i].x, glyphs[i].y) point.
6201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
6211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Then (mask_x, mask_y) in the infinite mask and (src_x, src_y) in the source
6221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * image are both aligned with (dest_x, dest_y) in the destination image. Then
6231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * these three images are composited within the
6241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
6251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *       (dest_x, dest_y, dst_x + width, dst_y + height)
6261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
6271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * rectangle.
6281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
6291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * TODO:
6301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *   - Trim the mask to the destination clip/image?
6311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *   - Trim composite region based on sources, when the op ignores 0s.
6321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
6331176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT void
6341176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_composite_glyphs (pixman_op_t            op,
6351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 pixman_image_t        *src,
6361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 pixman_image_t        *dest,
6371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 pixman_format_code_t   mask_format,
6381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                src_x,
6391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                src_y,
6401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t		mask_x,
6411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t		mask_y,
6421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                dest_x,
6431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                dest_y,
6441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                width,
6451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int32_t                height,
6461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 pixman_glyph_cache_t  *cache,
6471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 int			n_glyphs,
6481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			 const pixman_glyph_t  *glyphs)
6491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
6501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *mask;
6511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
6531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return;
6541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (PIXMAN_FORMAT_A   (mask_format) != 0 &&
6561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	PIXMAN_FORMAT_RGB (mask_format) != 0)
6571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
6581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_image_set_component_alpha (mask, TRUE);
6591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
6601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
6621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_composite32 (op, src, mask, dest,
6641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      src_x, src_y,
6651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      0, 0,
6661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      dest_x, dest_y,
6671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      width, height);
6681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
6691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_unref (mask);
6701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
671