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