diff options
Diffstat (limited to 'xorg-server/fb/fbpict.c')
-rw-r--r-- | xorg-server/fb/fbpict.c | 153 |
1 files changed, 152 insertions, 1 deletions
diff --git a/xorg-server/fb/fbpict.c b/xorg-server/fb/fbpict.c index 097a1a6bd..2804ff481 100644 --- a/xorg-server/fb/fbpict.c +++ b/xorg-server/fb/fbpict.c @@ -70,6 +70,156 @@ fbComposite(CARD8 op, free_pixman_pict(pDst, dest); } +static pixman_glyph_cache_t *glyphCache; + +void +fbDestroyGlyphCache(void) +{ + if (glyphCache) + { + pixman_glyph_cache_destroy (glyphCache); + glyphCache = NULL; + } +} + +static void +fbUnrealizeGlyph(ScreenPtr pScreen, + GlyphPtr pGlyph) +{ + if (glyphCache) + pixman_glyph_cache_remove (glyphCache, pGlyph, NULL); +} + +static void +fbGlyphs(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ +#define N_STACK_GLYPHS 512 + ScreenPtr pScreen = pDst->pDrawable->pScreen; + pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; + pixman_glyph_t *pglyphs = stack_glyphs; + pixman_image_t *srcImage, *dstImage; + int srcXoff, srcYoff, dstXoff, dstYoff; + GlyphPtr glyph; + int n_glyphs; + int x, y; + int i, n; + int xDst = list->xOff, yDst = list->yOff; + + miCompositeSourceValidate(pSrc); + + n_glyphs = 0; + for (i = 0; i < nlist; ++i) + n_glyphs += list[i].len; + + if (!glyphCache) + glyphCache = pixman_glyph_cache_create(); + + pixman_glyph_cache_freeze (glyphCache); + + if (n_glyphs > N_STACK_GLYPHS) { + if (!(pglyphs = malloc (n_glyphs * sizeof (pixman_glyph_t)))) + goto out; + } + + i = 0; + x = y = 0; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + const void *g; + + glyph = *glyphs++; + + if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) { + pixman_image_t *glyphImage; + PicturePtr pPicture; + int xoff, yoff; + + pPicture = GetGlyphPicture(glyph, pScreen); + if (!pPicture) { + n_glyphs--; + goto next; + } + + if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff))) + goto out; + + g = pixman_glyph_cache_insert(glyphCache, glyph, NULL, + glyph->info.x, + glyph->info.y, + glyphImage); + + free_pixman_pict(pPicture, glyphImage); + + if (!g) + goto out; + } + + pglyphs[i].x = x; + pglyphs[i].y = y; + pglyphs[i].glyph = g; + i++; + + next: + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff))) + goto out; + + if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff))) + goto out_free_src; + + if (maskFormat) { + pixman_format_code_t format; + pixman_box32_t extents; + int x, y; + + format = maskFormat->format | (maskFormat->depth << 24); + + pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents); + + x = extents.x1; + y = extents.y1; + + pixman_composite_glyphs(op, srcImage, dstImage, format, + xSrc + srcXoff + xDst, ySrc + srcYoff + yDst, + x, y, + x + dstXoff, y + dstYoff, + extents.x2 - extents.x1, + extents.y2 - extents.y1, + glyphCache, n_glyphs, pglyphs); + } + else { + pixman_composite_glyphs_no_mask(op, srcImage, dstImage, + xSrc + srcXoff - xDst, ySrc + srcYoff - yDst, + dstXoff, dstYoff, + glyphCache, n_glyphs, pglyphs); + } + + free_pixman_pict(pDst, dstImage); + +out_free_src: + free_pixman_pict(pSrc, srcImage); + +out: + pixman_glyph_cache_thaw(glyphCache); + if (pglyphs != stack_glyphs) + free(pglyphs); +} + static pixman_image_t * create_solid_fill_image(PicturePtr pict) { @@ -357,7 +507,8 @@ fbPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) return FALSE; ps = GetPictureScreen(pScreen); ps->Composite = fbComposite; - ps->Glyphs = miGlyphs; + ps->Glyphs = fbGlyphs; + ps->UnrealizeGlyph = fbUnrealizeGlyph; ps->CompositeRects = miCompositeRects; ps->RasterizeTrapezoid = fbRasterizeTrapezoid; ps->Trapezoids = fbTrapezoids; |