diff options
author | root <root@zombrain.(none)> | 2011-07-25 08:54:41 (GMT) |
---|---|---|
committer | root <root@zombrain.(none)> | 2011-07-25 08:54:41 (GMT) |
commit | ab4fcaad149d4bdccefa8f693c2a8e044b40dd4c (patch) | |
tree | c95c280caabc70e7aedbde723e38820047357be7 /exa/exa_glyphs.c |
initial state (xorg-server 1.10.2)
Diffstat (limited to 'exa/exa_glyphs.c')
-rw-r--r-- | exa/exa_glyphs.c | 863 |
1 files changed, 863 insertions, 0 deletions
diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c new file mode 100644 index 0000000..5c46ec9 --- /dev/null +++ b/exa/exa_glyphs.c @@ -0,0 +1,863 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor <otaylor@fishsoup.net> + * Based on code by: Keith Packard + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdlib.h> + +#include "exa_priv.h" + +#include "mipict.h" + +#if DEBUG_GLYPH_CACHE +#define DBG_GLYPH_CACHE(a) ErrorF a +#else +#define DBG_GLYPH_CACHE(a) +#endif + +/* Width of the pixmaps we use for the caches; this should be less than + * max texture size of the driver; this may need to actually come from + * the driver. + */ +#define CACHE_PICTURE_WIDTH 1024 + +/* Maximum number of glyphs we buffer on the stack before flushing + * rendering to the mask or destination surface. + */ +#define GLYPH_BUFFER_SIZE 256 + +typedef struct { + PicturePtr mask; + ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; + int count; +} ExaGlyphBuffer, *ExaGlyphBufferPtr; + +typedef enum { + ExaGlyphSuccess, /* Glyph added to render buffer */ + ExaGlyphFail, /* out of memory, etc */ + ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ +} ExaGlyphCacheResult; + +void +exaGlyphsInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i = 0; + + memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); + + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + + assert(i == EXA_NUM_GLYPH_CACHES); + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; + pExaScr->glyphCaches[i].size = 256; + pExaScr->glyphCaches[i].hashSize = 557; + } +} + +static void +exaUnrealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->format != format) + continue; + + if (cache->picture) { + FreePicture ((pointer) cache->picture, (XID) 0); + cache->picture = NULL; + } + + free(cache->hashEntries); + cache->hashEntries = NULL; + + free(cache->glyphs); + cache->glyphs = NULL; + cache->glyphCount = 0; + } +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +/* All caches for a single format share a single pixmap for glyph storage, + * allowing mixing glyphs of different sizes without paying a penalty + * for switching between mask pixmaps. (Note that for a size of font + * right at the border between two sizes, we might be switching for almost + * every glyph.) + * + * This function allocates the storage pixmap, and then fills in the + * rest of the allocated structures for all caches with the given format. + */ +static Bool +exaRealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + + int depth = PIXMAN_FORMAT_DEPTH(format); + PictFormatPtr pPictFormat; + PixmapPtr pPixmap; + PicturePtr pPicture; + CARD32 component_alpha; + int height; + int i; + int error; + + pPictFormat = PictureMatchFormat(pScreen, depth, format); + if (!pPictFormat) + return FALSE; + + /* Compute the total vertical size needed for the format */ + + height = 0; + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int rows; + + if (cache->format != format) + continue; + + cache->yOffset = height; + + rows = (cache->size + cache->columns - 1) / cache->columns; + height += rows * cache->glyphHeight; + } + + /* Now allocate the pixmap and picture */ + pPixmap = (*pScreen->CreatePixmap) (pScreen, + CACHE_PICTURE_WIDTH, + height, depth, 0); + if (!pPixmap) + return FALSE; + + component_alpha = NeedsComponent(pPictFormat->format); + pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, serverClient, + &error); + + (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ + + if (!pPicture) + return FALSE; + + /* And store the picture in all the caches for the format */ + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int j; + + if (cache->format != format) + continue; + + cache->picture = pPicture; + cache->picture->refcnt++; + cache->hashEntries = malloc(sizeof(int) * cache->hashSize); + cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size); + cache->glyphCount = 0; + + if (!cache->hashEntries || !cache->glyphs) + goto bail; + + for (j = 0; j < cache->hashSize; j++) + cache->hashEntries[j] = -1; + + cache->evictionPosition = rand() % cache->size; + } + + /* Each cache references the picture individually */ + FreePicture ((pointer) pPicture, (XID) 0); + return TRUE; + +bail: + exaUnrealizeGlyphCaches(pScreen, format); + return FALSE; +} + +void +exaGlyphsFini (ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->picture) + exaUnrealizeGlyphCaches(pScreen, cache->format); + } +} + +static int +exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, + GlyphPtr pGlyph) +{ + int slot; + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + if (entryPos == -1) + return -1; + + if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ + return entryPos; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, + GlyphPtr pGlyph, + int pos) +{ + int slot; + + memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + if (cache->hashEntries[slot] == -1) { + cache->hashEntries[slot] = pos; + return; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, + int pos) +{ + int slot; + int emptiedSlot = -1; + + slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + + if (entryPos == -1) + return; + + if (entryPos == pos) { + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } else if (emptiedSlot != -1) { + /* See if we can move this entry into the emptied slot, we can't + * do that if if entry would have hashed between the current position + * and the emptied slot. (taking wrapping into account). Bad positions + * are: + * + * | XXXXXXXXXX | + * i j + * + * |XXX XXXX| + * j i + * + * i - slot, j - emptiedSlot + * + * (Knuth 6.4R) + */ + + int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; + + if (!((entrySlot >= slot && entrySlot < emptiedSlot) || + (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) + { + cache->hashEntries[emptiedSlot] = entryPos; + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) +#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) + +/* The most efficient thing to way to upload the glyph to the screen + * is to use the UploadToScreen() driver hook; this allows us to + * pipeline glyph uploads and to avoid creating gpu backed pixmaps for + * glyphs that we'll never use again. + * + * If we can't do it with UploadToScreen (because the glyph has a gpu copy, + * etc), we fall back to CompositePicture. + * + * We need to damage the cache pixmap manually in either case because the damage + * layer unwrapped the picture screen before calling exaGlyphs. + */ +static void +exaGlyphCacheUploadGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + int x, + int y, + GlyphPtr pGlyph) +{ + ExaScreenPriv(pScreen); + PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; + ExaPixmapPriv(pGlyphPixmap); + PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; + + if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) + goto composite; + + /* If the glyph pixmap is already uploaded, no point in doing + * things this way */ + if (exaPixmapHasGpuCopy(pGlyphPixmap)) + goto composite; + + /* UploadToScreen only works if bpp match */ + if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) + goto composite; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + /* cache pixmap must have a gpu copy. */ + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pCachePixmap; + pixmaps[0].pReg = NULL; + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy(pCachePixmap)) + goto composite; + + /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ + if (pExaScr->info->UploadToScreen(pCachePixmap, + x, + y, + pGlyph->info.width, + pGlyph->info.height, + (char *)pExaPixmap->sys_ptr, + pExaPixmap->sys_pitch)) + goto damage; + +composite: + CompositePicture (PictOpSrc, + pGlyphPicture, + None, + cache->picture, + 0, 0, + 0, 0, + x, + y, + pGlyph->info.width, + pGlyph->info.height); + +damage: + /* The cache pixmap isn't a window, so no need to offset coordinates. */ + exaPixmapDirty (pCachePixmap, + x, + y, + x + cache->glyphWidth, + y + cache->glyphHeight); +} + +static ExaGlyphCacheResult +exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) +{ + ExaCompositeRectPtr rect; + int pos; + int x, y; + + if (buffer->mask && buffer->mask != cache->picture) + return ExaGlyphNeedFlush; + + if (!cache->picture) { + if (!exaRealizeGlyphCaches(pScreen, cache->format)) + return ExaGlyphFail; + } + + DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", + cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", + (long)*(CARD32 *) pGlyph->sha1)); + + pos = exaGlyphCacheHashLookup(cache, pGlyph); + if (pos != -1) { + DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); + x = CACHE_X(pos); + y = CACHE_Y(pos); + } else { + if (cache->glyphCount < cache->size) { + /* Space remaining; we fill from the start */ + pos = cache->glyphCount; + x = CACHE_X(pos); + y = CACHE_Y(pos); + cache->glyphCount++; + DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); + + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + } else { + /* Need to evict an entry. We have to see if any glyphs + * already in the output buffer were at this position in + * the cache + */ + pos = cache->evictionPosition; + x = CACHE_X(pos); + y = CACHE_Y(pos); + DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); + if (buffer->count) { + int i; + + for (i = 0; i < buffer->count; i++) { + if (pSrc ? + (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : + (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { + DBG_GLYPH_CACHE((" must flush buffer\n")); + return ExaGlyphNeedFlush; + } + } + } + + /* OK, we're all set, swap in the new glyph */ + exaGlyphCacheHashRemove(cache, pos); + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + /* And pick a new eviction position */ + cache->evictionPosition = rand() % cache->size; + } + + exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph); + } + + buffer->mask = cache->picture; + + rect = &buffer->rects[buffer->count]; + + if (pSrc) + { + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = x; + rect->yMask = y; + } + else + { + rect->xSrc = x; + rect->ySrc = y; + rect->xMask = 0; + rect->yMask = 0; + } + + rect->pDst = pDst; + rect->xDst = xDst; + rect->yDst = yDst; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; + + buffer->count++; + + return ExaGlyphSuccess; +} + +#undef CACHE_X +#undef CACHE_Y + +static ExaGlyphCacheResult +exaBufferGlyph(ScreenPtr pScreen, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) +{ + ExaScreenPriv(pScreen); + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; + int height = pGlyph->info.height; + ExaCompositeRectPtr rect; + PicturePtr mask; + int i; + + if (buffer->count == GLYPH_BUFFER_SIZE) + return ExaGlyphNeedFlush; + + if (PICT_FORMAT_BPP(format) == 1) + format = PICT_a8; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (format == cache->format && + width <= cache->glyphWidth && + height <= cache->glyphHeight) { + ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, + &pExaScr->glyphCaches[i], + buffer, + pGlyph, + pSrc, + pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst); + switch (result) { + case ExaGlyphFail: + break; + case ExaGlyphSuccess: + case ExaGlyphNeedFlush: + return result; + } + } + } + + /* Couldn't find the glyph in the cache, use the glyph picture directly */ + + mask = GlyphPicture(pGlyph)[pScreen->myNum]; + if (buffer->mask && buffer->mask != mask) + return ExaGlyphNeedFlush; + + buffer->mask = mask; + + rect = &buffer->rects[buffer->count]; + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = xMask; + rect->yMask = yMask; + rect->xDst = xDst; + rect->yDst = yDst; + rect->width = width; + rect->height = height; + + buffer->count++; + + return ExaGlyphSuccess; +} + +static void +exaGlyphsToMask(PicturePtr pMask, + ExaGlyphBufferPtr buffer) +{ + exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, + buffer->count, buffer->rects); + + buffer->count = 0; + buffer->mask = NULL; +} + +static void +exaGlyphsToDst(PicturePtr pSrc, + PicturePtr pDst, + ExaGlyphBufferPtr buffer) +{ + exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, + buffer->rects); + + buffer->count = 0; + buffer->mask = NULL; +} + +/* Cut and paste from render/glyph.c - probably should export it instead */ +static void +GlyphExtents (int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + if (x1 < extents->x1) + extents->x1 = x1; + if (x2 > extents->x2) + extents->x2 = x2; + if (y1 < extents->y1) + extents->y1 = y1; + if (y2 > extents->y2) + extents->y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +void +exaGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask = NULL; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int first_xOff = list->xOff, first_yOff = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents = {0, 0, 0, 0}; + CARD32 component_alpha; + ExaGlyphBuffer buffer; + + if (maskFormat) + { + ExaScreenPriv(pScreen); + GCPtr pGC; + xRectangle rect; + + GlyphExtents (nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + + if (maskFormat->depth == 1) { + PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); + + if (a8Format) + maskFormat = a8Format; + } + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pMask || + (!component_alpha && pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) + { + PictFormatPtr argbFormat; + + (*pScreen->DestroyPixmap) (pMaskPixmap); + + if (!pMask) + return; + + /* The driver can't seem to composite to a8, let's try argb (but + * without component-alpha) */ + FreePicture ((pointer) pMask, (XID) 0); + + argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + + if (argbFormat) + maskFormat = argbFormat; + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + + pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, + serverClient, &error); + if (!pMask) { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + x = 0; + y = 0; + } + buffer.count = 0; + buffer.mask = NULL; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) + { + glyph = *glyphs++; + + if (glyph->info.width > 0 && glyph->info.height > 0) + { + /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ + if (maskFormat) + { + if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) + { + exaGlyphsToMask(pMask, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } + else + { + if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y) + == ExaGlyphNeedFlush) + { + exaGlyphsToDst(pSrc, pDst, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (buffer.count) { + if (maskFormat) + exaGlyphsToMask(pMask, &buffer); + else + exaGlyphsToDst(pSrc, pDst, &buffer); + } + + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - first_xOff, + ySrc + y - first_yOff, + 0, 0, + x, y, + width, height); + FreePicture ((pointer) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } +} |