예제 #1
0
/**
 * Creates an appropriate picture for temp mask use.
 */
static PicturePtr
glamor_create_mask_picture(ScreenPtr screen,
                           PicturePtr dst,
                           PictFormatPtr pict_format,
                           CARD16 width, CARD16 height)
{
    PixmapPtr pixmap;
    PicturePtr picture;
    int error;

    if (!pict_format) {
        if (dst->polyEdge == PolyEdgeSharp)
            pict_format = PictureMatchFormat(screen, 1, PICT_a1);
        else
            pict_format = PictureMatchFormat(screen, 8, PICT_a8);
        if (!pict_format)
            return 0;
    }

    pixmap = glamor_create_pixmap(screen, 0, 0,
                                  pict_format->depth,
                                  GLAMOR_CREATE_PIXMAP_CPU);

    if (!pixmap)
        return 0;
    picture = CreatePicture(0, &pixmap->drawable, pict_format,
                            0, 0, serverClient, &error);
    glamor_destroy_pixmap(pixmap);
    return picture;
}
예제 #2
0
PicturePtr
miCreateAlphaPicture (ScreenPtr	    pScreen, 
		      PicturePtr    pDst,
		      PictFormatPtr pPictFormat,
		      CARD16	    width,
		      CARD16	    height)
{
    PixmapPtr	    pPixmap;
    PicturePtr	    pPicture;
    GCPtr	    pGC;
    int		    error;
    xRectangle	    rect;

    if (width > 32767 || height > 32767)
	return 0;

    if (!pPictFormat)
    {
	if (pDst->polyEdge == PolyEdgeSharp)
	    pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
	else
	    pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
	if (!pPictFormat)
	    return 0;
    }

    pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 
					pPictFormat->depth);
    if (!pPixmap)
	return 0;
    pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
    if (!pGC)
    {
	(*pScreen->DestroyPixmap) (pPixmap);
	return 0;
    }
    ValidateGC (&pPixmap->drawable, pGC);
    rect.x = 0;
    rect.y = 0;
    rect.width = width;
    rect.height = height;
    (*pGC->ops->PolyFillRect)(&pPixmap->drawable, pGC, 1, &rect);
    FreeScratchGC (pGC);
    pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
			      0, 0, serverClient, &error);
    (*pScreen->DestroyPixmap) (pPixmap);
    return pPicture;
}
예제 #3
0
/**
 * glamor_trapezoids will generate trapezoid mask accumulating in
 * system memory.
 */
void
glamor_trapezoids(CARD8 op,
                  PicturePtr src, PicturePtr dst,
                  PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
                  int ntrap, xTrapezoid *traps)
{
    ScreenPtr screen = dst->pDrawable->pScreen;
    BoxRec bounds;
    PicturePtr picture;
    INT16 x_dst, y_dst;
    INT16 x_rel, y_rel;
    int width, height, stride;
    PixmapPtr pixmap;
    pixman_image_t *image = NULL;

    /* If a mask format wasn't provided, we get to choose, but behavior should
     * be as if there was no temporary mask the traps were accumulated into.
     */
    if (!mask_format) {
        if (dst->polyEdge == PolyEdgeSharp)
            mask_format = PictureMatchFormat(screen, 1, PICT_a1);
        else
            mask_format = PictureMatchFormat(screen, 8, PICT_a8);
        for (; ntrap; ntrap--, traps++)
            glamor_trapezoids(op, src, dst, mask_format, x_src,
                              y_src, 1, traps);
        return;
    }

    miTrapezoidBounds(ntrap, traps, &bounds);

    if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
        return;

    x_dst = traps[0].left.p1.x >> 16;
    y_dst = traps[0].left.p1.y >> 16;

    width = bounds.x2 - bounds.x1;
    height = bounds.y2 - bounds.y1;
    stride = PixmapBytePad(width, mask_format->depth);

    picture = glamor_create_mask_picture(screen, dst, mask_format,
                                         width, height);
    if (!picture)
        return;

    image = pixman_image_create_bits(picture->format,
                                     width, height, NULL, stride);
    if (!image) {
        FreePicture(picture, 0);
        return;
    }

    for (; ntrap; ntrap--, traps++)
        pixman_rasterize_trapezoid(image,
                                   (pixman_trapezoid_t *) traps,
                                   -bounds.x1, -bounds.y1);

    pixmap = glamor_get_drawable_pixmap(picture->pDrawable);

    screen->ModifyPixmapHeader(pixmap, width, height,
                               mask_format->depth,
                               BitsPerPixel(mask_format->depth),
                               PixmapBytePad(width,
                                             mask_format->depth),
                               pixman_image_get_data(image));

    x_rel = bounds.x1 + x_src - x_dst;
    y_rel = bounds.y1 + y_src - y_dst;

    CompositePicture(op, src, picture, dst,
                     x_rel, y_rel,
                     0, 0,
                     bounds.x1, bounds.y1,
                     bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);

    if (image)
        pixman_image_unref(image);

    FreePicture(picture, 0);
}
예제 #4
0
파일: exa_glyphs.c 프로젝트: Agnesa/xserver
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);
    }
}
예제 #5
0
	miTrapezoidBounds (ntrap, traps, &bounds);
	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
	    return;
	pPicture = miCreateAlphaPicture (pScreen, pDst, maskFormat,
					 bounds.x2 - bounds.x1,
					 bounds.y2 - bounds.y1);
	if (!pPicture)
	    return;
	for (; ntrap; ntrap--, traps++)
	    (*ps->RasterizeTrapezoid) (pPicture, traps, 
				       -bounds.x1, -bounds.y1);
	xRel = bounds.x1 + xSrc - xDst;
	yRel = bounds.y1 + ySrc - yDst;
	CompositePicture (op, pSrc, pPicture, pDst,
			  xRel, yRel, 0, 0, bounds.x1, bounds.y1,
			  bounds.x2 - bounds.x1,
			  bounds.y2 - bounds.y1);
	FreePicture (pPicture, 0);
    }
    else
    {
	if (pDst->polyEdge == PolyEdgeSharp)
	    maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
	else
	    maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
	for (; ntrap; ntrap--, traps++)
	    miTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
    }
}
예제 #6
0
_X_EXPORT void
miCompositeRects (CARD8		op,
		  PicturePtr	pDst,
		  xRenderColor  *color,
		  int		nRect,
		  xRectangle    *rects)
{
    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
    
    if (color->alpha == 0xffff)
    {
	if (op == PictOpOver)
	    op = PictOpSrc;
    }
    if (op == PictOpClear)
	color->red = color->green = color->blue = color->alpha = 0;
    
    if (op == PictOpSrc || op == PictOpClear)
    {
	miColorRects (pDst, pDst, color, nRect, rects, 0, 0);
	if (pDst->alphaMap)
	    miColorRects (pDst->alphaMap, pDst,
			  color, nRect, rects,
			  pDst->alphaOrigin.x,
			  pDst->alphaOrigin.y);
    }
    else
    {
	PictFormatPtr	rgbaFormat;
	PixmapPtr	pPixmap;
	PicturePtr	pSrc;
	xRectangle	one;
	int		error;
	Pixel		pixel;
	GCPtr		pGC;
	CARD32		tmpval[2];

	rgbaFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
	if (!rgbaFormat)
	    goto bail1;
	
	pPixmap = (*pScreen->CreatePixmap) (pScreen, 1, 1,
					    rgbaFormat->depth);
	if (!pPixmap)
	    goto bail2;
	
	miRenderColorToPixel (rgbaFormat, color, &pixel);

	pGC = GetScratchGC (rgbaFormat->depth, pScreen);
	if (!pGC)
	    goto bail3;
	tmpval[0] = GXcopy;
	tmpval[1] = pixel;

	ChangeGC (pGC, GCFunction | GCForeground, tmpval);
	ValidateGC (&pPixmap->drawable, pGC);
	one.x = 0;
	one.y = 0;
	one.width = 1;
	one.height = 1;
	(*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &one);
	
	tmpval[0] = xTrue;
	pSrc = CreatePicture (0, &pPixmap->drawable, rgbaFormat,
			      CPRepeat, tmpval, 0, &error);
			      
	if (!pSrc)
	    goto bail4;

	while (nRect--)
	{
	    CompositePicture (op, pSrc, 0, pDst, 0, 0, 0, 0, 
			      rects->x,
			      rects->y,
			      rects->width,
			      rects->height);
	    rects++;
	}

	FreePicture ((pointer) pSrc, 0);
bail4:
	FreeScratchGC (pGC);
bail3:
	(*pScreen->DestroyPixmap) (pPixmap);
bail2:
bail1:
	;
    }
}
예제 #7
0
파일: exa_glyphs.c 프로젝트: Agnesa/xserver
/* 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;
}
예제 #8
0
static miDCCursorPtr
miDCRealize (ScreenPtr pScreen, CursorPtr pCursor)
{
    miDCCursorPtr   pPriv;
    GCPtr	    pGC;
    ChangeGCVal	    gcvals;

    pPriv = malloc(sizeof (miDCCursorRec));
    if (!pPriv)
	return NULL;
#ifdef ARGB_CURSOR
    if (pCursor->bits->argb)
    {
	PixmapPtr	pPixmap;
	PictFormatPtr	pFormat;
	int		error;
	
	pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
	if (!pFormat)
	{
	    free((pointer) pPriv);
	    return NULL;
	}
	
	pPriv->sourceBits = 0;
	pPriv->maskBits = 0;
	pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
					    pCursor->bits->height, 32,
					    CREATE_PIXMAP_USAGE_SCRATCH);
	if (!pPixmap)
	{
	    free((pointer) pPriv);
	    return NULL;
	}
	pGC = GetScratchGC (32, pScreen);
	if (!pGC)
	{
	    (*pScreen->DestroyPixmap) (pPixmap);
	    free((pointer) pPriv);
	    return NULL;
	}
	ValidateGC (&pPixmap->drawable, pGC);
	(*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
			       0, 0, pCursor->bits->width,
			       pCursor->bits->height,
			       0, ZPixmap, (char *) pCursor->bits->argb);
	FreeScratchGC (pGC);
	pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
					pFormat, 0, 0, serverClient, &error);
        (*pScreen->DestroyPixmap) (pPixmap);
	if (!pPriv->pPicture)
	{
	    free((pointer) pPriv);
	    return NULL;
	}
	dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv);
	return pPriv;
    }
    pPriv->pPicture = 0;
#endif
    pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
    if (!pPriv->sourceBits)
    {
	free((pointer) pPriv);
	return NULL;
    }
    pPriv->maskBits =  (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
    if (!pPriv->maskBits)
    {
	(*pScreen->DestroyPixmap) (pPriv->sourceBits);
	free((pointer) pPriv);
	return NULL;
    }
    dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv);

    /* create the two sets of bits, clipping as appropriate */

    pGC = GetScratchGC (1, pScreen);
    if (!pGC)
    {
	(void) miDCUnrealizeCursor (pScreen, pCursor);
	return NULL;
    }

    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
			   0, 0, pCursor->bits->width, pCursor->bits->height,
 			   0, XYPixmap, (char *)pCursor->bits->source);
    gcvals.val = GXand;
    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
			   0, 0, pCursor->bits->width, pCursor->bits->height,
 			   0, XYPixmap, (char *)pCursor->bits->mask);

    /* mask bits -- pCursor->mask & ~pCursor->source */
    gcvals.val = GXcopy;
    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
			   0, 0, pCursor->bits->width, pCursor->bits->height,
 			   0, XYPixmap, (char *)pCursor->bits->mask);
    gcvals.val = GXandInverted;
    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
			   0, 0, pCursor->bits->width, pCursor->bits->height,
 			   0, XYPixmap, (char *)pCursor->bits->source);
    FreeScratchGC (pGC);
    return pPriv;
}
예제 #9
0
파일: midispcur.c 프로젝트: Agnesa/xserver
static Bool
miDCRealize(ScreenPtr pScreen, CursorPtr pCursor)
{
    miDCScreenPtr pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miDCScreenKey);
    GCPtr pGC;
    ChangeGCVal gcvals;
    PixmapPtr   sourceBits, maskBits;

    if (pScreenPriv->pCursor == pCursor)
        return TRUE;

#ifdef ARGB_CURSOR

    if (pCursor->bits->argb) {
        PixmapPtr pPixmap;
        PictFormatPtr pFormat;
        int error;
        PicturePtr  pPicture;

        pFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
        if (!pFormat)
            return FALSE;

        pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
                                            pCursor->bits->height, 32,
                                            CREATE_PIXMAP_USAGE_SCRATCH);
        if (!pPixmap)
            return FALSE;

        pGC = GetScratchGC(32, pScreen);
        if (!pGC) {
            (*pScreen->DestroyPixmap) (pPixmap);
            return FALSE;
        }
        ValidateGC(&pPixmap->drawable, pGC);
        (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
                               0, 0, pCursor->bits->width,
                               pCursor->bits->height,
                               0, ZPixmap, (char *) pCursor->bits->argb);
        FreeScratchGC(pGC);
        pPicture = CreatePicture(0, &pPixmap->drawable,
                                 pFormat, 0, 0, serverClient, &error);
        (*pScreen->DestroyPixmap) (pPixmap);
        if (!pPicture)
            return FALSE;

        miDCSwitchScreenCursor(pScreen, pCursor, NULL, NULL, pPicture);
        return TRUE;
    }
#endif
    sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
                                           pCursor->bits->height, 1, 0);
    if (!sourceBits)
        return FALSE;

    maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
                                         pCursor->bits->height, 1, 0);
    if (!maskBits) {
        (*pScreen->DestroyPixmap) (sourceBits);
        return FALSE;
    }

    /* create the two sets of bits, clipping as appropriate */

    pGC = GetScratchGC(1, pScreen);
    if (!pGC) {
        (*pScreen->DestroyPixmap) (sourceBits);
        (*pScreen->DestroyPixmap) (maskBits);
        return FALSE;
    }

    ValidateGC((DrawablePtr) sourceBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr) sourceBits, pGC, 1,
                           0, 0, pCursor->bits->width, pCursor->bits->height,
                           0, XYPixmap, (char *) pCursor->bits->source);
    gcvals.val = GXand;
    ChangeGC(NullClient, pGC, GCFunction, &gcvals);
    ValidateGC((DrawablePtr) sourceBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr) sourceBits, pGC, 1,
                           0, 0, pCursor->bits->width, pCursor->bits->height,
                           0, XYPixmap, (char *) pCursor->bits->mask);

    /* mask bits -- pCursor->mask & ~pCursor->source */
    gcvals.val = GXcopy;
    ChangeGC(NullClient, pGC, GCFunction, &gcvals);
    ValidateGC((DrawablePtr) maskBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr) maskBits, pGC, 1,
                           0, 0, pCursor->bits->width, pCursor->bits->height,
                           0, XYPixmap, (char *) pCursor->bits->mask);
    gcvals.val = GXandInverted;
    ChangeGC(NullClient, pGC, GCFunction, &gcvals);
    ValidateGC((DrawablePtr) maskBits, pGC);
    (*pGC->ops->PutImage) ((DrawablePtr) maskBits, pGC, 1,
                           0, 0, pCursor->bits->width, pCursor->bits->height,
                           0, XYPixmap, (char *) pCursor->bits->source);
    FreeScratchGC(pGC);

    miDCSwitchScreenCursor(pScreen, pCursor, sourceBits, maskBits, NULL);
    return TRUE;
}
static int
uxa_glyphs_via_mask(CARD8 op,
		    PicturePtr pSrc,
		    PicturePtr pDst,
		    PictFormatPtr maskFormat,
		    INT16 xSrc, INT16 ySrc,
		    int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	ScreenPtr screen = pDst->pDrawable->pScreen;
	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
	CARD32 component_alpha;
	PixmapPtr pixmap, white_pixmap;
	PicturePtr glyph_atlas, mask, white;
	int xDst = list->xOff, yDst = list->yOff;
	int x, y, width, height;
	int dst_off_x, dst_off_y;
	int n, error;
	BoxRec box;

	uxa_glyph_extents(nlist, list, glyphs, &box);
	if (box.x2 <= box.x1 || box.y2 <= box.y1)
		return 0;

	dst_off_x = box.x1;
	dst_off_y = box.y1;

	width  = box.x2 - box.x1;
	height = box.y2 - box.y1;
	x = -box.x1;
	y = -box.y1;

	if (maskFormat->depth == 1) {
		PictFormatPtr a8Format =
			PictureMatchFormat(screen, 8, PICT_a8);

		if (!a8Format)
			return -1;

		maskFormat = a8Format;
	}

	pixmap = screen->CreatePixmap(screen, width, height,
				      maskFormat->depth,
				      CREATE_PIXMAP_USAGE_SCRATCH);
	if (!pixmap)
		return 1;

	if (!uxa_pixmap_is_offscreen(pixmap)) {
		screen->DestroyPixmap(pixmap);
		return -1;
	}

	white_pixmap = NULL;
	white = create_white_solid(screen);
	if (white)
		white_pixmap = uxa_get_drawable_pixmap(white->pDrawable);
	if (!white_pixmap) {
		if (white)
			FreePicture(white, 0);
		screen->DestroyPixmap(pixmap);
		return -1;
	}

	uxa_clear_pixmap(screen, uxa_screen, pixmap);

	component_alpha = NeedsComponent(maskFormat->format);
	mask = CreatePicture(0, &pixmap->drawable,
			      maskFormat, CPComponentAlpha,
			      &component_alpha, serverClient, &error);
	screen->DestroyPixmap(pixmap);

	if (!mask) {
		FreePicture(white, 0);
		return 1;
	}

	ValidatePicture(mask);

	glyph_atlas = NULL;
	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr this_atlas;
			int glyph_x, glyph_y;
			struct uxa_glyph *priv;

			if (glyph->info.width == 0 || glyph->info.height == 0)
				goto next_glyph;

			priv = uxa_glyph_get_private(glyph);
			if (priv != NULL) {
				glyph_x = priv->x;
				glyph_y = priv->y;
				this_atlas = priv->cache->picture;
			} else {
				if (glyph_atlas) {
					uxa_screen->info->done_composite(pixmap);
					glyph_atlas = NULL;
				}
				this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
				if (this_atlas == NULL) {
					/* no cache for this glyph */
					this_atlas = GetGlyphPicture(glyph, screen);
					glyph_x = glyph_y = 0;
				}
			}

			if (this_atlas != glyph_atlas) {
				PixmapPtr glyph_pixmap;

				if (glyph_atlas)
					uxa_screen->info->done_composite(pixmap);

				glyph_pixmap =
					uxa_get_drawable_pixmap(this_atlas->pDrawable);
				if (!uxa_pixmap_is_offscreen(glyph_pixmap) ||
				    !uxa_screen->info->prepare_composite(PictOpAdd,
									 white, this_atlas, mask,
									 white_pixmap, glyph_pixmap, pixmap)) {
					FreePicture(white, 0);
					FreePicture(mask, 0);
					return -1;
				}

				glyph_atlas = this_atlas;
			}

			uxa_screen->info->composite(pixmap,
						    0, 0,
						    glyph_x, glyph_y,
						    x - glyph->info.x,
						    y - glyph->info.y,
						    glyph->info.width,
						    glyph->info.height);

next_glyph:
			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}
	if (glyph_atlas)
		uxa_screen->info->done_composite(pixmap);

	uxa_composite(op,
		      pSrc, mask, pDst,
		      dst_off_x + xSrc - xDst,
		      dst_off_y + ySrc - yDst,
		      0, 0,
		      dst_off_x, dst_off_y,
		      width, height);

	FreePicture(white, 0);
	FreePicture(mask, 0);
	return 0;
}
/* The most efficient thing to way to upload the glyph to the screen
 * is to use CopyArea; uxa pixmaps are always offscreen.
 */
static void
uxa_glyph_cache_upload_glyph(ScreenPtr screen,
			     uxa_glyph_cache_t * cache,
			     GlyphPtr glyph,
			     int x, int y)
{
	PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen);
	PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
	PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
	PixmapPtr scratch;
	GCPtr gc;

	gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
	if (!gc)
		return;

	ValidateGC(&pCachePixmap->drawable, gc);

	scratch = pGlyphPixmap;
	/* Create a temporary bo to stream the updates to the cache */
	if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
	    !uxa_pixmap_is_offscreen(scratch)) {
		scratch = screen->CreatePixmap(screen,
					       glyph->info.width,
					       glyph->info.height,
					       pCachePixmap->drawable.depth,
					       UXA_CREATE_PIXMAP_FOR_MAP);
		if (scratch) {
			if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
				PicturePtr picture;
				int error;

				picture = CreatePicture(0, &scratch->drawable,
							PictureMatchFormat(screen,
									   pCachePixmap->drawable.depth,
									   cache->picture->format),
							0, NULL,
							serverClient, &error);
				if (picture) {
					ValidatePicture(picture);
					uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
						      0, 0,
						      0, 0,
						      0, 0,
						      glyph->info.width, glyph->info.height);
					FreePicture(picture, 0);
				}
			} else {
				uxa_copy_area(&pGlyphPixmap->drawable,
					      &scratch->drawable,
					      gc,
					      0, 0,
					      glyph->info.width, glyph->info.height,
					      0, 0);
			}
		} else {
			scratch = pGlyphPixmap;
		}
	}

	uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
		      0, 0,
		      glyph->info.width, glyph->info.height,
		      x, y);

	if (scratch != pGlyphPixmap)
		screen->DestroyPixmap(scratch);

	FreeScratchGC(gc);
}
/* 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 source 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 uxa_realize_glyph_caches(ScreenPtr pScreen)
{
	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
	unsigned int formats[] = {
		PIXMAN_a8,
		PIXMAN_a8r8g8b8,
	};
	int i;

	if (uxa_screen->glyph_cache_initialized)
		return TRUE;

	uxa_screen->glyph_cache_initialized = TRUE;
	memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));

	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
		PixmapPtr pixmap;
		PicturePtr picture;
		CARD32 component_alpha;
		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
		int error;
		PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]);
		if (!pPictFormat)
			goto bail;

		/* Now allocate the pixmap and picture */
		pixmap = pScreen->CreatePixmap(pScreen,
					       CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth,
					       INTEL_CREATE_PIXMAP_TILING_X);
		if (!pixmap)
			goto bail;
		if (!uxa_pixmap_is_offscreen(pixmap)) {
			/* Presume shadow is in-effect */
			pScreen->DestroyPixmap(pixmap);
			uxa_unrealize_glyph_caches(pScreen);
			return TRUE;
		}

		component_alpha = NeedsComponent(pPictFormat->format);
		picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
					CPComponentAlpha, &component_alpha,
					serverClient, &error);

		pScreen->DestroyPixmap(pixmap);

		if (!picture)
			goto bail;

		ValidatePicture(picture);

		cache->picture = picture;
		cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
		if (!cache->glyphs)
			goto bail;

		cache->evict = rand() % GLYPH_CACHE_SIZE;
	}
	assert(i == UXA_NUM_GLYPH_CACHE_FORMATS);

	return TRUE;

bail:
	uxa_unrealize_glyph_caches(pScreen);
	return FALSE;
}