xserver-multidpi/exa/exa_glyphs.c
Keith Packard 9838b7032e Introduce a consistent coding style
This is strictly the application of the script 'x-indent-all.sh'
from util/modular. Compared to the patch that Daniel posted in
January, I've added a few indent flags:

	-bap
	-psl
	-T PrivatePtr
	-T pmWait
	-T _XFUNCPROTOBEGIN
	-T _XFUNCPROTOEND
	-T _X_EXPORT

The typedefs were needed to make the output of sdksyms.sh match the
previous output, otherwise, the code is formatted badly enough that
sdksyms.sh generates incorrect output.

The generated code was compared with the previous version and found to
be essentially identical -- "assert" line numbers and BUILD_TIME were
the only differences found.

The comparison was done with this script:

dir1=$1
dir2=$2

for dir in $dir1 $dir2; do
	(cd $dir && find . -name '*.o' | while read file; do
		dir=`dirname $file`
		base=`basename $file .o`
		dump=$dir/$base.dump
		objdump -d $file > $dump
	done)
done

find $dir1 -name '*.dump' | while read dump; do
	otherdump=`echo $dump | sed "s;$dir1;$dir2;"`
	diff -u $dump $otherdump
done

Signed-off-by: Keith Packard <keithp@keithp.com>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Acked-by: Alan Coopersmith <alan.coopersmith@oracle.com>
2012-03-21 13:54:42 -07:00

840 lines
26 KiB
C

/*
* 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);
}
}