aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xgl/xglglyph.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xgl/xglglyph.c')
-rw-r--r--xorg-server/hw/xgl/xglglyph.c1170
1 files changed, 1170 insertions, 0 deletions
diff --git a/xorg-server/hw/xgl/xglglyph.c b/xorg-server/hw/xgl/xglglyph.c
new file mode 100644
index 000000000..c1a484ac0
--- /dev/null
+++ b/xorg-server/hw/xgl/xglglyph.c
@@ -0,0 +1,1170 @@
+/*
+ * 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