示例#1
0
void
CompositeGlyphs(CARD8 op,
                PicturePtr pSrc,
                PicturePtr pDst,
                PictFormatPtr maskFormat,
                INT16 xSrc,
                INT16 ySrc, int nlist, GlyphListPtr lists, GlyphPtr * glyphs)
{
    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);

    ValidatePicture(pSrc);
    ValidatePicture(pDst);
    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists,
                   glyphs);
}
示例#2
0
文件: cw_render.c 项目: csulmone/X11
static void
cwValidatePicture(PicturePtr pPicture, Mask mask)
{
    DrawablePtr pDrawable = pPicture->pDrawable;
    ScreenPtr pScreen = pDrawable->pScreen;

    cwPsDecl(pScreen);
    cwPicturePrivate;

    cwPsUnwrap(ValidatePicture);

    /*
     * Must call ValidatePicture to ensure pPicture->pCompositeClip is valid
     */
    (*ps->ValidatePicture) (pPicture, mask);

    if (!cwDrawableIsRedirWindow(pDrawable)) {
        if (pPicturePrivate)
            cwDestroyPicturePrivate(pPicture);
    }
    else {
        PicturePtr pBackingPicture;
        DrawablePtr pBackingDrawable;
        int x_off, y_off;

        pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);

        if (pPicturePrivate &&
            pPicturePrivate->pBackingPicture->pDrawable != pBackingDrawable) {
            cwDestroyPicturePrivate(pPicture);
            pPicturePrivate = 0;
        }

        if (!pPicturePrivate) {
            pPicturePrivate = cwCreatePicturePrivate(pPicture);
            if (!pPicturePrivate) {
                cwPsWrap(ValidatePicture, cwValidatePicture);
                return;
            }
        }

        pBackingPicture = pPicturePrivate->pBackingPicture;

        /*
         * Always copy transform and filters because there's no
         * indication of when they've changed
         */
        SetPictureTransform(pBackingPicture, pPicture->transform);

        if (pBackingPicture->filter != pPicture->filter ||
            pPicture->filter_nparams > 0) {
            char *filter = PictureGetFilterName(pPicture->filter);

            SetPictureFilter(pBackingPicture,
                             filter, strlen(filter),
                             pPicture->filter_params, pPicture->filter_nparams);
        }

        pPicturePrivate->stateChanges |= mask;

        if (pPicturePrivate->serialNumber != pDrawable->serialNumber ||
            (pPicturePrivate->
             stateChanges & (CPClipXOrigin | CPClipYOrigin | CPClipMask))) {
            SetPictureClipRegion(pBackingPicture, x_off - pDrawable->x,
                                 y_off - pDrawable->y,
                                 pPicture->pCompositeClip);

            pPicturePrivate->serialNumber = pDrawable->serialNumber;
            pPicturePrivate->stateChanges &=
                ~(CPClipXOrigin | CPClipYOrigin | CPClipMask);
        }

        CopyPicture(pPicture, pPicturePrivate->stateChanges, pBackingPicture);

        ValidatePicture(pBackingPicture);
    }
    cwPsWrap(ValidatePicture, cwValidatePicture);
}
void
uxa_glyphs(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);

	if (uxa_screen->info->flags & UXA_USE_GLAMOR) {
		int ok;

		uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW);
		uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO);
		ok = glamor_glyphs_nf(op,
				     pSrc, pDst, maskFormat,
				     xSrc, ySrc, nlist, list, glyphs);
		uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO);
		uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW);

		if (!ok)
			goto fallback;

		return;
	}

	if (!uxa_screen->info->prepare_composite ||
	    uxa_screen->force_fallback ||
	    !uxa_drawable_is_offscreen(pDst->pDrawable) ||
	    pDst->alphaMap || pSrc->alphaMap ||
	    /* XXX we fail to handle (rare) non-solid sources correctly. */
	    !is_solid(pSrc)) {
fallback:
	    uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
	    return;
	}

	/* basic sanity check */
	if (uxa_screen->info->check_composite &&
	    !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) {
		goto fallback;
	}

	ValidatePicture(pSrc);
	ValidatePicture(pDst);

	if (!maskFormat) {
		/* If we don't have a mask format but all the glyphs have the same format,
		 * require ComponentAlpha and don't intersect, use the glyph format as mask
		 * format for the full benefits of the glyph cache.
		 */
		if (NeedsComponent(list[0].format->format)) {
			Bool sameFormat = TRUE;
			int i;

			maskFormat = list[0].format;

			for (i = 0; i < nlist; i++) {
				if (maskFormat->format != list[i].format->format) {
					sameFormat = FALSE;
					break;
				}
			}

			if (!sameFormat ||
			    uxa_glyphs_intersect(nlist, list, glyphs))
				maskFormat = NULL;
		}
	}

	if (!maskFormat) {
		if (uxa_glyphs_to_dst(op, pSrc, pDst,
				      xSrc, ySrc,
				      nlist, list, glyphs))
			goto fallback;
	} else {
		if (uxa_glyphs_via_mask(op,
					pSrc, pDst, maskFormat,
					xSrc, ySrc,
					nlist, list, glyphs))
			goto fallback;
	}
}
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;
}
static void
uxa_check_glyphs(CARD8 op,
		 PicturePtr src,
		 PicturePtr dst,
		 PictFormatPtr maskFormat,
		 INT16 xSrc,
		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	pixman_image_t *image;
	PixmapPtr scratch;
	PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL;
	int width = 0, height = 0;
	int x, y, n;
	int xDst = list->xOff, yDst = list->yOff;
	BoxRec extents = { 0, 0, 0, 0 };
	CARD8 mask_op = 0;

	if (maskFormat) {
		pixman_format_code_t format;
		CARD32 component_alpha;
		xRenderColor color;
		int error;

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

		width = extents.x2 - extents.x1;
		height = extents.y2 - extents.y1;

		format = maskFormat->format |
			(BitsPerPixel(maskFormat->depth) << 24);
		image =
			pixman_image_create_bits(format, width, height, NULL, 0);
		if (!image)
			return;

		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
						 PIXMAN_FORMAT_DEPTH(format),
						 PIXMAN_FORMAT_BPP(format),
						 pixman_image_get_stride(image),
						 pixman_image_get_data(image));

		if (!scratch) {
			pixman_image_unref(image);
			return;
		}

		component_alpha = NeedsComponent(maskFormat->format);
		mask = CreatePicture(0, &scratch->drawable,
				     maskFormat, CPComponentAlpha,
				     &component_alpha, serverClient, &error);
		if (!mask) {
			FreeScratchPixmapHeader(scratch);
			pixman_image_unref(image);
			return;
		}
		ValidatePicture(mask);

		x = -extents.x1;
		y = -extents.y1;

		color.red = color.green = color.blue = color.alpha = 0xffff;
		white = CreateSolidPicture(0, &color, &error);

		mask_op = op;
		op = PictOpAdd;

		mask_src = src;
		src = white;

		mask_dst = dst;
		dst = mask;
	} else {
		mask = dst;
		x = 0;
		y = 0;
	}

	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
			if (g) {
				CompositePicture(op, src, g, dst,
						 xSrc + (x - glyph->info.x) - xDst,
						 ySrc + (y - glyph->info.y) - yDst,
						 0, 0,
						 x - glyph->info.x,
						 y - glyph->info.y,
						 glyph->info.width,
						 glyph->info.height);
			}

			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}

	if (white)
		FreePicture(white, 0);

	if (maskFormat) {
		x = extents.x1;
		y = extents.y1;
		CompositePicture(mask_op, mask_src, mask, mask_dst,
				 xSrc + x - xDst,
				 ySrc + y - yDst,
				 0, 0,
				 x, y,
				 width, height);
		FreePicture(mask, 0);
		FreeScratchPixmapHeader(scratch);
		pixman_image_unref(image);
	}
}
/* 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;
}