xserver-multidpi/hw/xgl/xglglyph.c
Aaron Plattner f2e310132f Add CreatePixmap allocation hints.
These hints allow an acceleration architecture to optimize allocation of certain
types of pixmaps, such as pixmaps that will serve as backing pixmaps for
redirected windows.
2007-11-04 16:11:28 -08:00

1171 lines
26 KiB
C

/*
* Copyright © 2005 Novell, 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
* Novell, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* Novell, Inc. makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL NOVELL, INC. 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: David Reveman <davidr@novell.com>
*/
#include "xgl.h"
#ifdef RENDER
#include "gcstruct.h"
#include "picturestr.h"
#define BITMAP_CACHE_SIZE 256000
#define BITMAP_CACHE_MAX_LEVEL ~0
#define BITMAP_CACHE_MAX_SIZE 512
#define TEXTURE_CACHE_SIZE 512
#define TEXTURE_CACHE_MAX_LEVEL 64
#define TEXTURE_CACHE_MAX_HEIGHT 72
#define TEXTURE_CACHE_MAX_WIDTH 72
#define NEXT_GLYPH_SERIAL_NUMBER ((++glyphSerialNumber) > MAX_SERIAL_NUM ? \
(glyphSerialNumber = 1): glyphSerialNumber)
#define GLYPH_GET_AREA_PRIV(pArea) \
((xglGlyphAreaPtr) (pArea)->devPrivate.ptr)
#define GLYPH_AREA_PRIV(pArea) \
xglGlyphAreaPtr pAreaPriv = GLYPH_GET_AREA_PRIV (pArea)
#define NEEDS_COMPONENT(f) (PICT_FORMAT_A (f) != 0 && PICT_FORMAT_RGB (f) != 0)
#define WRITE_VEC2(ptr, _x, _y) \
*(ptr)++ = (_x); \
*(ptr)++ = (_y)
#define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, box) \
WRITE_VEC2 (ptr, _vx1, _vy1); \
WRITE_VEC2 (ptr, (box).x1, (box).y2); \
WRITE_VEC2 (ptr, _vx2, _vy1); \
WRITE_VEC2 (ptr, (box).x2, (box).y2); \
WRITE_VEC2 (ptr, _vx2, _vy2); \
WRITE_VEC2 (ptr, (box).x2, (box).y1); \
WRITE_VEC2 (ptr, _vx1, _vy2); \
WRITE_VEC2 (ptr, (box).x1, (box).y1)
typedef union _xglGlyphList {
glitz_short_t *s;
glitz_float_t *f;
} xglGlyphListRec, *xglGlyphListPtr;
typedef struct _xglGlyphArray {
int lastX, lastY;
} xglGlyphArrayRec, *xglGlyphArrayPtr;
typedef union _xglGlyphVertexData {
xglGlyphArrayRec array;
xglGlyphListRec list;
} xglGlyphVertexDataRec, *xglGlyphVertexDataPtr;
typedef struct _xglGlyphOp {
GlyphListPtr pLists;
int listLen;
GlyphPtr *ppGlyphs;
int nGlyphs;
int xOff;
int yOff;
Bool noCache;
} xglGlyphOpRec, *xglGlyphOpPtr;
unsigned long glyphSerialNumber = 0;
xglAreaRec zeroSizeArea = {
0, 0,
0, 0,
0, 0,
{ NULL, NULL, NULL, NULL }, NULL,
(pointer) 0,
{ 0 }
};
static Bool
xglGlyphCreate (xglAreaPtr pArea)
{
return TRUE;
}
static Bool
xglGlyphMoveIn (xglAreaPtr pArea,
pointer closure)
{
xglGlyphCachePtr pCache = (xglGlyphCachePtr) pArea->pRoot->closure;
GlyphPtr pGlyph = (GlyphPtr) closure;
XGL_GLYPH_PRIV (pCache->pScreen, pGlyph);
pGlyphPriv->pArea = pArea;
return TRUE;
}
static void
xglGlyphMoveOut (xglAreaPtr pArea,
pointer closure)
{
xglGlyphCachePtr pCache = (xglGlyphCachePtr) pArea->pRoot->closure;
GlyphPtr pGlyph = (GlyphPtr) closure;
XGL_GLYPH_PRIV (pCache->pScreen, pGlyph);
pGlyphPriv->pArea = NULL;
}
static int
xglGlyphCompareScore (xglAreaPtr pArea,
pointer closure1,
pointer closure2)
{
GLYPH_AREA_PRIV (pArea);
if (pAreaPriv->serial == glyphSerialNumber)
return 1;
return -1;
}
static const xglAreaFuncsRec xglGlyphAreaFuncs = {
xglGlyphCreate,
xglGlyphMoveIn,
xglGlyphMoveOut,
xglGlyphCompareScore
};
Bool
xglRealizeGlyph (ScreenPtr pScreen,
GlyphPtr pGlyph)
{
PictureScreenPtr pPictureScreen = GetPictureScreen (pScreen);
Bool ret;
XGL_SCREEN_PRIV (pScreen);
XGL_GLYPH_PRIV (pScreen, pGlyph);
XGL_PICTURE_SCREEN_UNWRAP (RealizeGlyph);
ret = (*pPictureScreen->RealizeGlyph) (pScreen, pGlyph);
XGL_PICTURE_SCREEN_WRAP (RealizeGlyph, xglRealizeGlyph);
pGlyphPriv->pArea = NULL;
return ret;
}
void
xglUnrealizeGlyph (ScreenPtr pScreen,
GlyphPtr pGlyph)
{
PictureScreenPtr pPictureScreen = GetPictureScreen (pScreen);
XGL_SCREEN_PRIV (pScreen);
XGL_GLYPH_PRIV (pScreen, pGlyph);
XGL_PICTURE_SCREEN_UNWRAP (UnrealizeGlyph);
(*pPictureScreen->UnrealizeGlyph) (pScreen, pGlyph);
XGL_PICTURE_SCREEN_WRAP (UnrealizeGlyph, xglUnrealizeGlyph);
if (pGlyphPriv->pArea && pGlyphPriv->pArea->width)
xglWithdrawArea (pGlyphPriv->pArea);
}
Bool
xglInitGlyphCache (xglGlyphCachePtr pCache,
ScreenPtr pScreen,
PictFormatPtr format)
{
XGL_SCREEN_PRIV (pScreen);
pCache->depth = format->depth;
if (!pScreenPriv->pSolidAlpha)
{
xglCreateSolidAlphaPicture (pScreen);
if (!pScreenPriv->pSolidAlpha)
return FALSE;
}
if (pCache->depth == 1)
{
int stride;
GEOMETRY_INIT (pScreen, &pCache->u.geometry,
GLITZ_GEOMETRY_TYPE_VERTEX,
GEOMETRY_USAGE_STATIC, BITMAP_CACHE_SIZE);
GEOMETRY_SET_VERTEX_DATA_TYPE (&pCache->u.geometry,
pScreenPriv->geometryDataType);
stride = pCache->u.geometry.f.vertex.bytes_per_vertex;
if (!xglRootAreaInit (&pCache->rootArea,
BITMAP_CACHE_MAX_LEVEL,
BITMAP_CACHE_SIZE / (stride * 4),
0, sizeof (xglGlyphAreaRec),
(xglAreaFuncsPtr) &xglGlyphAreaFuncs,
(pointer) pCache))
{
GEOMETRY_UNINIT (&pCache->u.geometry);
return FALSE;
}
}
else
{
xglGlyphTexturePtr pTexture = &pCache->u.texture;
glitz_surface_t *mask;
glitz_surface_attributes_t attr;
glitz_vertex_format_t *vertex;
xglVisualPtr pVisual;
pVisual = xglFindVisualWithDepth (pScreen, format->depth);
if (!pVisual)
return FALSE;
if (!xglRootAreaInit (&pCache->rootArea,
TEXTURE_CACHE_MAX_LEVEL,
TEXTURE_CACHE_SIZE, TEXTURE_CACHE_SIZE,
sizeof (xglGlyphAreaRec),
(xglAreaFuncsPtr) &xglGlyphAreaFuncs,
(pointer) pCache))
return FALSE;
if (pScreenPriv->geometryDataType == GEOMETRY_DATA_TYPE_SHORT)
{
attr.unnormalized = 1;
mask = glitz_surface_create (pScreenPriv->drawable,
pVisual->format.surface,
TEXTURE_CACHE_SIZE,
TEXTURE_CACHE_SIZE,
GLITZ_SURFACE_UNNORMALIZED_MASK,
&attr);
}
else
mask = NULL;
if (!mask)
{
mask = glitz_surface_create (pScreenPriv->drawable,
pVisual->format.surface,
TEXTURE_CACHE_SIZE,
TEXTURE_CACHE_SIZE,
0, NULL);
if (!mask)
return FALSE;
pTexture->geometryDataType = GEOMETRY_DATA_TYPE_FLOAT;
}
else
pTexture->geometryDataType = GEOMETRY_DATA_TYPE_SHORT;
if (NEEDS_COMPONENT (format->format))
glitz_surface_set_component_alpha (mask, 1);
pTexture->pMask = xglCreateDevicePicture (mask);
if (!pTexture->pMask)
return FALSE;
vertex = &pCache->u.texture.format.vertex;
vertex->primitive = GLITZ_PRIMITIVE_QUADS;
vertex->mask.size = GLITZ_COORDINATE_SIZE_XY;
vertex->attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
if (pTexture->geometryDataType == GEOMETRY_DATA_TYPE_FLOAT)
{
vertex->type = GLITZ_DATA_TYPE_FLOAT;
vertex->bytes_per_vertex = sizeof (glitz_float_t) * 4;
vertex->mask.offset = sizeof (glitz_float_t) * 2;
vertex->mask.type = GLITZ_DATA_TYPE_FLOAT;
}
else
{
vertex->type = GLITZ_DATA_TYPE_SHORT;
vertex->bytes_per_vertex = sizeof (glitz_short_t) * 4;
vertex->mask.offset = sizeof (glitz_short_t) * 2;
vertex->mask.type = GLITZ_DATA_TYPE_SHORT;
}
pTexture->pixel.fourcc = GLITZ_FOURCC_RGB;
pTexture->pixel.masks = pVisual->pPixel->masks;
pTexture->pixel.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
pTexture->pixel.bytes_per_line = 0;
pTexture->pixel.xoffset = 0;
pTexture->pixel.skip_lines = 0;
}
pCache->pScreen = pScreen;
return TRUE;
}
void
xglFiniGlyphCache (xglGlyphCachePtr pCache)
{
if (pCache->pScreen)
{
xglRootAreaFini (&pCache->rootArea);
if (pCache->depth == 1)
{
GEOMETRY_UNINIT (&pCache->u.geometry);
}
else
{
if (pCache->u.texture.pMask)
FreePicture ((pointer) pCache->u.texture.pMask, 0);
}
pCache->pScreen = NULL;
}
}
static xglAreaPtr
xglCacheGlyph (xglGlyphCachePtr pCache,
GlyphPtr pGlyph)
{
ScreenPtr pScreen = pCache->pScreen;
XGL_GLYPH_PRIV (pScreen, pGlyph);
if (pCache->depth == 1)
{
PixmapPtr pPixmap;
RegionPtr pRegion;
int nBox;
pPixmap = GetScratchPixmapHeader (pScreen,
pGlyph->info.width,
pGlyph->info.height,
pCache->depth, pCache->depth, 0,
(pointer) (pGlyph + 1));
if (!pPixmap)
return NULL;
(*pScreen->ModifyPixmapHeader) (pPixmap,
pGlyph->info.width,
pGlyph->info.height,
0, 0, -1, (pointer) (pGlyph + 1));
pRegion = (*pScreen->BitmapToRegion) (pPixmap);
FreeScratchPixmapHeader (pPixmap);
if (!pRegion)
return NULL;
nBox = REGION_NUM_RECTS (pRegion);
if (nBox > BITMAP_CACHE_MAX_SIZE)
{
REGION_DESTROY (pScreen, pRegion);
return NULL;
}
if (nBox > 0)
{
/* Find available area */
if (!xglFindArea (pCache->rootArea.pArea, nBox, 0,
FALSE, (pointer) pGlyph))
{
/* Kicking out area with lower score */
xglFindArea (pCache->rootArea.pArea, nBox, 0,
TRUE, (pointer) pGlyph);
}
if (pGlyphPriv->pArea)
{
int stride;
GLYPH_AREA_PRIV (pGlyphPriv->pArea);
pAreaPriv->serial = glyphSerialNumber;
pAreaPriv->u.range.first = pGlyphPriv->pArea->x * 4;
pAreaPriv->u.range.count = nBox * 4;
stride = pCache->u.geometry.f.vertex.bytes_per_vertex;
GEOMETRY_ADD_REGION_AT (pScreen, &pCache->u.geometry, pRegion,
pGlyphPriv->pArea->x * stride * 4);
}
} else
pGlyphPriv->pArea = &zeroSizeArea;
REGION_DESTROY (pScreen, pRegion);
}
else
{
xglGlyphTexturePtr pTexture = &pCache->u.texture;
if (pGlyph->info.width > TEXTURE_CACHE_MAX_WIDTH ||
pGlyph->info.height > TEXTURE_CACHE_MAX_HEIGHT)
return NULL;
if (pGlyph->info.width > 0 && pGlyph->info.height > 0)
{
glitz_buffer_t *buffer;
buffer = glitz_buffer_create_for_data (pGlyph + 1);
if (!buffer)
return NULL;
/* Find available area */
if (!xglFindArea (pCache->rootArea.pArea,
pGlyph->info.width, pGlyph->info.height,
FALSE, (pointer) pGlyph))
{
/* Kicking out area with lower score */
xglFindArea (pCache->rootArea.pArea,
pGlyph->info.width, pGlyph->info.height,
TRUE, (pointer) pGlyph);
}
if (pGlyphPriv->pArea)
{
glitz_surface_t *surface;
glitz_point_fixed_t p1, p2;
glitz_pixel_format_t pixel;
GLYPH_AREA_PRIV (pGlyphPriv->pArea);
pixel = pTexture->pixel;
pixel.bytes_per_line =
PixmapBytePad (pGlyph->info.width, pCache->depth);
surface = pTexture->pMask->pSourcePict->source.devPrivate.ptr;
glitz_set_pixels (surface,
pGlyphPriv->pArea->x,
pGlyphPriv->pArea->y,
pGlyph->info.width,
pGlyph->info.height,
&pixel,
buffer);
p1.x = pGlyphPriv->pArea->x << 16;
p1.y = pGlyphPriv->pArea->y << 16;
p2.x = (pGlyphPriv->pArea->x + pGlyph->info.width) << 16;
p2.y = (pGlyphPriv->pArea->y + pGlyph->info.height) << 16;
glitz_surface_translate_point (surface, &p1, &p1);
glitz_surface_translate_point (surface, &p2, &p2);
pAreaPriv->serial = glyphSerialNumber;
if (pTexture->geometryDataType)
{
pAreaPriv->u.box.fBox.x1 = FIXED_TO_FLOAT (p1.x);
pAreaPriv->u.box.fBox.y1 = FIXED_TO_FLOAT (p1.y);
pAreaPriv->u.box.fBox.x2 = FIXED_TO_FLOAT (p2.x);
pAreaPriv->u.box.fBox.y2 = FIXED_TO_FLOAT (p2.y);
}
else
{
pAreaPriv->u.box.sBox.x1 = p1.x >> 16;
pAreaPriv->u.box.sBox.y1 = p1.y >> 16;
pAreaPriv->u.box.sBox.x2 = p2.x >> 16;
pAreaPriv->u.box.sBox.y2 = p2.y >> 16;
}
}
glitz_buffer_destroy (buffer);
} else
pGlyphPriv->pArea = &zeroSizeArea;
}
return pGlyphPriv->pArea;
}
static void
xglUncachedGlyphs (CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
xglGlyphOpPtr pOp)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PicturePtr pPicture = NULL;
PixmapPtr pPixmap = NULL;
xglGlyphCachePtr pCache;
int depth = pOp->pLists->format->depth;
GlyphPtr glyph;
INT16 xOff, yOff;
xglGlyphPtr pGlyphPriv;
xglAreaPtr pArea;
Bool usingCache = !pOp->noCache;
XGL_SCREEN_PRIV (pScreen);
pCache = &pScreenPriv->glyphCache[depth];
if (usingCache)
{
if (!pCache->pScreen)
{
if (!xglInitGlyphCache (pCache, pScreen, pOp->pLists->format))
usingCache = FALSE;
}
}
while (pOp->nGlyphs)
{
glyph = *pOp->ppGlyphs;
if (!pOp->listLen)
{
pOp->pLists++;
pOp->listLen = pOp->pLists->len;
pOp->xOff += pOp->pLists->xOff;
pOp->yOff += pOp->pLists->yOff;
}
xOff = pOp->xOff;
yOff = pOp->yOff;
if (usingCache)
{
pGlyphPriv = XGL_GET_GLYPH_PRIV (pScreen, glyph);
pArea = pGlyphPriv->pArea;
if (pSrc)
{
if (!pArea)
pArea = xglCacheGlyph (pCache, glyph);
if (pArea)
break;
}
} else
pArea = NULL;
pOp->listLen--;
pOp->nGlyphs--;
pOp->ppGlyphs++;
pOp->xOff += glyph->info.xOff;
pOp->yOff += glyph->info.yOff;
if (pArea)
continue;
if (!pPicture)
{
XID componentAlpha;
int error;
pPixmap = GetScratchPixmapHeader (pScreen,
glyph->info.width,
glyph->info.height,
depth, depth,
0, (pointer) (glyph + 1));
if (!pPixmap)
return;
componentAlpha = NEEDS_COMPONENT (pOp->pLists->format->format);
pPicture = CreatePicture (0, &pPixmap->drawable,
pOp->pLists->format,
CPComponentAlpha, &componentAlpha,
serverClient, &error);
if (!pPicture)
{
FreeScratchPixmapHeader (pPixmap);
return;
}
}
(*pScreen->ModifyPixmapHeader) (pPixmap,
glyph->info.width, glyph->info.height,
0, 0, -1, (pointer) (glyph + 1));
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
if (pSrc)
CompositePicture (op,
pSrc,
pPicture,
pDst,
xSrc + (xOff - glyph->info.x),
ySrc + (yOff - glyph->info.y),
0, 0,
xOff - glyph->info.x,
yOff - glyph->info.y,
glyph->info.width,
glyph->info.height);
else
CompositePicture (PictOpAdd,
pPicture,
NULL,
pDst,
0, 0,
0, 0,
xOff - glyph->info.x,
yOff - glyph->info.y,
glyph->info.width,
glyph->info.height);
}
if (pPicture)
{
FreeScratchPixmapHeader (pPixmap);
FreePicture ((pointer) pPicture, 0);
}
}
static Bool
xglCachedGlyphs (CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
xglGlyphOpPtr pOp)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
xglGlyphOpRec opSave = *pOp;
xglGlyphCachePtr pCache;
xglGlyphVertexDataRec vData;
xglGeometryPtr pGeometry;
GlyphPtr glyph;
xglGlyphPtr pGlyphPriv;
xglAreaPtr pArea;
xglGlyphAreaPtr pGlyphArea;
BoxRec extents;
INT16 xOff, yOff, x1, x2, y1, y2;
int depth = pOp->pLists->format->depth;
int i, remaining = pOp->nGlyphs;
int nGlyph = 0;
PicturePtr pMaskPicture = NULL;
XGL_SCREEN_PRIV (pScreen);
pCache = &pScreenPriv->glyphCache[depth];
if (!pCache->pScreen)
{
if (!xglInitGlyphCache (pCache, pScreen, pOp->pLists->format))
{
pOp->noCache = TRUE;
return 1;
}
}
/* update serial number for all glyphs already in cache so that
we don't accidentally replace one. */
for (i = 0; i < pOp->nGlyphs; i++)
{
pGlyphPriv = XGL_GET_GLYPH_PRIV (pScreen, pOp->ppGlyphs[i]);
pArea = pGlyphPriv->pArea;
if (pArea && pArea->width)
GLYPH_GET_AREA_PRIV (pArea)->serial = glyphSerialNumber;
}
for (i = 0; i < pOp->nGlyphs; i++)
{
pGlyphPriv = XGL_GET_GLYPH_PRIV (pScreen, pOp->ppGlyphs[i]);
pArea = pGlyphPriv->pArea;
if (!pArea)
pArea = xglCacheGlyph (pCache, pOp->ppGlyphs[i]);
if (pArea)
{
if (pArea->width)
nGlyph++;
}
else if (pSrc)
break;
}
if (nGlyph)
{
if (depth == 1)
{
glitz_multi_array_t *multiArray;
pGeometry = &pCache->u.geometry;
pGeometry->xOff = pGeometry->yOff = 0;
multiArray = glitz_multi_array_create (nGlyph);
if (!multiArray)
return 1;
GEOMETRY_SET_MULTI_ARRAY (pGeometry, multiArray);
glitz_multi_array_destroy (multiArray);
vData.array.lastX = 0;
vData.array.lastY = 0;
}
else
{
i = 4 * pCache->u.texture.format.vertex.bytes_per_vertex * nGlyph;
pGeometry = xglGetScratchGeometryWithSize (pScreen, i);
pGeometry->f = pCache->u.texture.format;
pGeometry->type = GLITZ_GEOMETRY_TYPE_VERTEX;
pMaskPicture = pCache->u.texture.pMask;
vData.list.s = glitz_buffer_map (pGeometry->buffer,
GLITZ_BUFFER_ACCESS_WRITE_ONLY);
}
} else
pGeometry = NULL;
extents.x1 = MAXSHORT;
extents.y1 = MAXSHORT;
extents.x2 = MINSHORT;
extents.y2 = MINSHORT;
while (pOp->nGlyphs)
{
glyph = *pOp->ppGlyphs;
if (!pOp->listLen)
{
pOp->pLists++;
pOp->listLen = pOp->pLists->len;
pOp->xOff += pOp->pLists->xOff;
pOp->yOff += pOp->pLists->yOff;
}
xOff = pOp->xOff;
yOff = pOp->yOff;
pGlyphPriv = XGL_GET_GLYPH_PRIV (pScreen, glyph);
pArea = pGlyphPriv->pArea;
if (!pArea && pSrc)
break;
pOp->listLen--;
pOp->nGlyphs--;
pOp->ppGlyphs++;
pOp->xOff += glyph->info.xOff;
pOp->yOff += glyph->info.yOff;
if (!pArea)
continue;
x1 = xOff - glyph->info.x;
x2 = x1 + glyph->info.width;
if (x1 < extents.x1)
extents.x1 = x1;
if (x2 > extents.x2)
extents.x2 = x2;
y1 = yOff - glyph->info.y;
y2 = y1 + glyph->info.height;
if (y1 < extents.y1)
extents.y1 = y1;
if (y2 > extents.y2)
extents.y2 = y2;
if (pArea->width)
{
pGlyphArea = GLYPH_GET_AREA_PRIV (pArea);
if (depth == 1)
{
glitz_multi_array_add (pGeometry->array,
pGlyphArea->u.range.first, 2,
pGlyphArea->u.range.count,
(x1 - vData.array.lastX) << 16,
(y1 - vData.array.lastY) << 16);
vData.array.lastX = x1;
vData.array.lastY = y1;
}
else
{
if (pCache->u.texture.geometryDataType)
{
WRITE_BOX (vData.list.f, x1, y1, x2, y2,
pGlyphArea->u.box.fBox);
}
else
{
WRITE_BOX (vData.list.s, x1, y1, x2, y2,
pGlyphArea->u.box.sBox);
}
}
}
remaining--;
}
NEXT_GLYPH_SERIAL_NUMBER;
if (nGlyph)
{
if (depth != 1)
{
glitz_buffer_unmap (pGeometry->buffer);
pGeometry->count = nGlyph * 4;
}
xSrc += extents.x1;
ySrc += extents.y1;
if (!pSrc)
{
op = PictOpAdd;
pSrc = pScreenPriv->pSolidAlpha;
if (remaining)
*pOp = opSave;
}
GEOMETRY_TRANSLATE (pGeometry,
pDst->pDrawable->x,
pDst->pDrawable->y);
if (xglCompositeGeneral (op,
pSrc,
pMaskPicture,
pDst,
pGeometry,
xSrc, ySrc,
0, 0,
pDst->pDrawable->x + extents.x1,
pDst->pDrawable->y + extents.y1,
extents.x2 - extents.x1,
extents.y2 - extents.y1))
{
xglAddCurrentBitDamage (pDst->pDrawable);
return remaining;
}
remaining = ~0;
*pOp = opSave;
pOp->noCache = TRUE;
}
else
{
if (remaining)
{
*pOp = opSave;
pOp->noCache = TRUE;
}
}
return remaining;
}
static Bool
xglGlyphExtents (PicturePtr pDst,
int nlist,
GlyphListPtr list,
GlyphPtr *glyphs,
BoxPtr extents)
{
GlyphPtr glyph;
BoxRec line;
int x1, x2, y1, y2;
int n;
int x;
int y;
Bool overlap = FALSE;
x = 0;
y = 0;
extents->x1 = MAXSHORT;
extents->x2 = MINSHORT;
extents->y1 = MAXSHORT;
extents->y2 = MINSHORT;
while (!list->len)
{
if (--nlist)
{
x += list->xOff;
y += list->yOff;
list++;
}
else
{
return FALSE;
}
}
glyph = *glyphs;
x1 = (x + list->xOff) - glyph->info.x;
if (x1 < MINSHORT)
x1 = MINSHORT;
y1 = (y + list->yOff) - glyph->info.y;
if (y1 < MINSHORT)
y1 = MINSHORT;
line.x1 = x1;
line.x2 = x1;
line.y1 = y1;
line.y2 = y1;
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 >= line.x2)
{
line.x2 = x2;
if (y1 < line.y1)
line.y1 = y1;
if (y2 > line.y2)
line.y2 = y2;
}
else if (x2 <= line.x1)
{
line.x1 = x1;
if (y1 < line.y1)
line.y1 = y1;
if (y2 > line.y2)
line.y2 = y2;
}
else
{
if (line.y1 >= extents->y2)
{
extents->y2 = line.y2;
if (line.y1 < extents->y1)
extents->y1 = line.y1;
}
else if (line.y2 <= extents->y1)
{
extents->y1 = line.y1;
if (line.y2 > extents->y2)
extents->y2 = line.y2;
}
else
{
if (line.y1 < extents->y1)
extents->y1 = line.y1;
if (line.y2 > extents->y2)
extents->y2 = line.y2;
overlap = TRUE;
}
if (line.x1 < extents->x1)
extents->x1 = line.x1;
if (line.x2 > extents->x2)
extents->x2 = line.x2;
line.x1 = x1;
line.y1 = y1;
line.x2 = x2;
line.y2 = y2;
}
x += glyph->info.xOff;
y += glyph->info.yOff;
}
}
if (line.y1 >= extents->y2)
{
extents->y2 = line.y2;
if (line.y1 < extents->y1)
extents->y1 = line.y1;
}
else if (line.y2 <= extents->y1)
{
extents->y1 = line.y1;
if (line.y2 > extents->y2)
extents->y2 = line.y2;
}
else
{
if (line.y1 < extents->y1)
extents->y1 = line.y1;
if (line.y2 > extents->y2)
extents->y2 = line.y2;
overlap = TRUE;
}
if (line.x1 < extents->x1)
extents->x1 = line.x1;
if (line.x2 > extents->x2)
extents->x2 = line.x2;
xglPictureClipExtents (pDst, extents);
return overlap;
}
/* returns 0 if all glyph lists don't have the same format */
static CARD32
xglGlyphListFormatId (GlyphListPtr list,
int nlist)
{
CARD32 id = list->format->id;
nlist--;
list++;
while (nlist--)
{
if (list->format->id != id)
return 0;
list++;
}
return id;
}
void
xglGlyphs (CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc,
int nlist,
GlyphListPtr list,
GlyphPtr *glyphs)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PicturePtr pMask = NULL, pSrcPicture, pDstPicture;
BoxRec extents;
xglGlyphOpRec glyphOp;
int xDst = list->xOff, yDst = list->yOff;
int overlap;
int target;
overlap = xglGlyphExtents (pDst, nlist, list, glyphs, &extents);
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
return;
target = xglPrepareTarget (pDst->pDrawable);
if (op != PictOpAdd && maskFormat &&
(!target || overlap || op != PictOpOver ||
xglGlyphListFormatId (list, nlist) != maskFormat->id))
{
PixmapPtr pPixmap;
XID componentAlpha;
GCPtr pGC;
xRectangle rect;
int error;
rect.x = 0;
rect.y = 0;
rect.width = extents.x2 - extents.x1;
rect.height = extents.y2 - extents.y1;
pPixmap = (*pScreen->CreatePixmap) (pScreen,
rect.width, rect.height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pPixmap)
return;
componentAlpha = NEEDS_COMPONENT (maskFormat->format);
pMask = CreatePicture (0, &pPixmap->drawable,
maskFormat, CPComponentAlpha, &componentAlpha,
serverClient, &error);
if (!pMask)
{
(*pScreen->DestroyPixmap) (pPixmap);
return;
}
if (!target)
{
/* make sure we don't do accelerated drawing to mask */
xglSetPixmapVisual (pPixmap, NULL);
}
ValidatePicture (pMask);
pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
ValidateGC (&pPixmap->drawable, pGC);
(*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &rect);
FreeScratchGC (pGC);
(*pScreen->DestroyPixmap) (pPixmap);
target = xglPrepareTarget (pMask->pDrawable);
glyphOp.xOff = -extents.x1;
glyphOp.yOff = -extents.y1;
pSrcPicture = NULL;
pDstPicture = pMask;
}
else
{
glyphOp.xOff = 0;
glyphOp.yOff = 0;
pSrcPicture = pSrc;
pDstPicture = pDst;
}
glyphOp.ppGlyphs = glyphs;
glyphOp.noCache = !target;
while (nlist--)
{
glyphOp.xOff += list->xOff;
glyphOp.yOff += list->yOff;
glyphOp.listLen = list->len;
glyphOp.nGlyphs = list->len;
glyphOp.pLists = list++;
for (; nlist; nlist--, list++)
{
if (list->format->id != glyphOp.pLists->format->id)
break;
glyphOp.nGlyphs += list->len;
}
while (glyphOp.nGlyphs)
{
if (glyphOp.noCache || xglCachedGlyphs (op,
pSrcPicture,
pDstPicture,
xSrc - xDst, ySrc - yDst,
&glyphOp))
xglUncachedGlyphs (op,
pSrcPicture,
pDstPicture,
xSrc - xDst, ySrc - yDst,
&glyphOp);
}
}
if (pMask)
{
CompositePicture (op, pSrc, pMask, pDst,
xSrc + extents.x1 - xDst,
ySrc + extents.y1 - yDst,
0, 0,
extents.x1, extents.y1,
extents.x2 - extents.x1,
extents.y2 - extents.y1);
FreePicture ((pointer) pMask, (XID) 0);
}
}
#endif