예제 #1
0
파일: xfont.c 프로젝트: Agnesa/xserver
/*
** Make a single GL bitmap from a single X glyph
*/
static int
__glXMakeBitmapFromGlyph(FontPtr font, CharInfoPtr pci)
{
    int i, j;
    int widthPadded;            /* width of glyph in bytes, as padded by X */
    int allocBytes;             /* bytes to allocate to store bitmap */
    int w;                      /* width of glyph in bits */
    int h;                      /* height of glyph */
    register unsigned char *pglyph;
    register unsigned char *p;
    unsigned char *allocbuf;

#define __GL_CHAR_BUF_SIZE 2048
    unsigned char buf[__GL_CHAR_BUF_SIZE];

    w = GLYPHWIDTHPIXELS(pci);
    h = GLYPHHEIGHTPIXELS(pci);
    widthPadded = GLYPHWIDTHBYTESPADDED(pci);

    /*
     ** Use the local buf if possible, otherwise malloc.
     */
    allocBytes = widthPadded * h;
    if (allocBytes <= __GL_CHAR_BUF_SIZE) {
        p = buf;
        allocbuf = 0;
    }
    else {
        p = (unsigned char *) malloc(allocBytes);
        if (!p)
            return BadAlloc;
        allocbuf = p;
    }

    /*
     ** We have to reverse the picture, top to bottom
     */

    pglyph = FONTGLYPHBITS(FONTGLYPHS(font), pci) + (h - 1) * widthPadded;
    for (j = 0; j < h; j++) {
        for (i = 0; i < widthPadded; i++) {
            p[i] = pglyph[i];
        }
        pglyph -= widthPadded;
        p += widthPadded;
    }
    CALL_Bitmap(GET_DISPATCH(), (w, h, -pci->metrics.leftSideBearing,
                                 pci->metrics.descent,
                                 pci->metrics.characterWidth, 0,
                                 allocbuf ? allocbuf : buf));

    free(allocbuf);
    return Success;
#undef __GL_CHAR_BUF_SIZE
}
예제 #2
0
void
fbImageGlyphBlt(DrawablePtr pDrawable,
                GCPtr pGC,
                int x,
                int y,
                unsigned int nglyph, CharInfoPtr * ppciInit, pointer pglyphBase)
{
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);

    CharInfoPtr *ppci;

    CharInfoPtr pci;

    unsigned char *pglyph;      /* pointer bits in glyph */

    int gWidth, gHeight;        /* width and height of glyph */

    FbStride gStride;           /* stride of glyph */

    Bool opaque;

    int n;

    int gx, gy;

    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);

    FbBits *dst = 0;

    FbStride dstStride = 0;

    int dstBpp = 0;

    int dstXoff = 0, dstYoff = 0;

    glyph = 0;
    if (pPriv->and == 0) {
        fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
        switch (dstBpp) {
        case 8:
            glyph = fbGlyph8;
            break;
        case 16:
            glyph = fbGlyph16;
            break;
        case 24:
            glyph = fbGlyph24;
            break;
        case 32:
            glyph = fbGlyph32;
            break;
        }
    }

    x += pDrawable->x;
    y += pDrawable->y;

    if (TERMINALFONT(pGC->font)
        && !glyph
        ) {
        opaque = TRUE;
    }
    else {
        int xBack, widthBack;

        int yBack, heightBack;

        ppci = ppciInit;
        n = nglyph;
        widthBack = 0;
        while (n--)
            widthBack += (*ppci++)->metrics.characterWidth;

        xBack = x;
        if (widthBack < 0) {
            xBack += widthBack;
            widthBack = -widthBack;
        }
        yBack = y - FONTASCENT(pGC->font);
        heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
        fbSolidBoxClipped(pDrawable,
                          fbGetCompositeClip(pGC),
                          xBack,
                          yBack,
                          xBack + widthBack,
                          yBack + heightBack,
                          fbAnd(GXcopy, pPriv->bg, pPriv->pm),
                          fbXor(GXcopy, pPriv->bg, pPriv->pm));
        opaque = FALSE;
    }

    ppci = ppciInit;
    while (nglyph--) {
        pci = *ppci++;
        pglyph = FONTGLYPHBITS(pglyphBase, pci);
        gWidth = GLYPHWIDTHPIXELS(pci);
        gHeight = GLYPHHEIGHTPIXELS(pci);
        if (gWidth && gHeight) {
            gx = x + pci->metrics.leftSideBearing;
            gy = y - pci->metrics.ascent;
            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
                (*glyph) (dst + (gy + dstYoff) * dstStride,
                          dstStride,
                          dstBpp,
                          (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
            }
            else
            {
                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
                fbPutXYImage(pDrawable,
                             fbGetCompositeClip(pGC),
                             pPriv->fg,
                             pPriv->bg,
                             pPriv->pm,
                             GXcopy,
                             opaque,
                             gx,
                             gy,
                             gWidth, gHeight, (FbStip *) pglyph, gStride, 0);
            }
        }
        x += pci->metrics.characterWidth;
    }
}
예제 #3
0
void
fbPolyGlyphBlt(DrawablePtr pDrawable,
               GCPtr pGC,
               int x,
               int y,
               unsigned int nglyph, CharInfoPtr * ppci, pointer pglyphBase)
{
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);

    CharInfoPtr pci;

    unsigned char *pglyph;      /* pointer bits in glyph */

    int gx, gy;

    int gWidth, gHeight;        /* width and height of glyph */

    FbStride gStride;           /* stride of glyph */

    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);

    FbBits *dst = 0;

    FbStride dstStride = 0;

    int dstBpp = 0;

    int dstXoff = 0, dstYoff = 0;

    glyph = 0;
    if (pGC->fillStyle == FillSolid && pPriv->and == 0) {
        fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
        switch (dstBpp) {
        case 8:
            glyph = fbGlyph8;
            break;
        case 16:
            glyph = fbGlyph16;
            break;
        case 24:
            glyph = fbGlyph24;
            break;
        case 32:
            glyph = fbGlyph32;
            break;
        }
    }
    x += pDrawable->x;
    y += pDrawable->y;

    while (nglyph--) {
        pci = *ppci++;
        pglyph = FONTGLYPHBITS(pglyphBase, pci);
        gWidth = GLYPHWIDTHPIXELS(pci);
        gHeight = GLYPHHEIGHTPIXELS(pci);
        if (gWidth && gHeight) {
            gx = x + pci->metrics.leftSideBearing;
            gy = y - pci->metrics.ascent;
            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
                (*glyph) (dst + (gy + dstYoff) * dstStride,
                          dstStride,
                          dstBpp,
                          (FbStip *) pglyph, pPriv->xor, gx + dstXoff, gHeight);
            }
            else
            {
                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
                fbPushImage(pDrawable,
                            pGC,
                            (FbStip *) pglyph,
                            gStride, 0, gx, gy, gWidth, gHeight);
            }
        }
        x += pci->metrics.characterWidth;
    }
}
예제 #4
0
void
miPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
	       unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase)
{
    int width, height;
    PixmapPtr pPixmap;
    int nbyLine;			/* bytes per line of padded pixmap */
    FontPtr pfont;
    GCPtr pGCtmp;
    int i;
    int j;
    unsigned char *pbits;		/* buffer for PutImage */
    unsigned char *pb;		/* temp pointer into buffer */
    CharInfoPtr pci;		/* currect char info */
    unsigned char *pglyph;	/* pointer bits in glyph */
    int gWidth, gHeight;		/* width and height of glyph */
    int nbyGlyphWidth;		/* bytes per scanline of glyph */
    int nbyPadGlyph;			/* server padded line of glyph */

    XID gcvals[3];

    if (pGC->miTranslate)
    {
	x += pDrawable->x;
	y += pDrawable->y;
    }

    pfont = pGC->font;
    width = FONTMAXBOUNDS(pfont,rightSideBearing) - 
	    FONTMINBOUNDS(pfont,leftSideBearing);
    height = FONTMAXBOUNDS(pfont,ascent) +
	     FONTMAXBOUNDS(pfont,descent);

    pPixmap = (*pDrawable->pScreen->CreatePixmap)(pDrawable->pScreen,
						  width, height, 1);
    if (!pPixmap)
	return;

    pGCtmp = GetScratchGC(1, pDrawable->pScreen);
    if (!pGCtmp)
    {
	(*pDrawable->pScreen->DestroyPixmap)(pPixmap);
	return;
    }

    gcvals[0] = GXcopy;
    gcvals[1] = 1;
    gcvals[2] = 0;

    DoChangeGC(pGCtmp, GCFunction|GCForeground|GCBackground, gcvals, 0);

    nbyLine = BitmapBytePad(width);
    pbits = (unsigned char *)ALLOCATE_LOCAL(height*nbyLine);
    if (!pbits)
    {
	(*pDrawable->pScreen->DestroyPixmap)(pPixmap);
	FreeScratchGC(pGCtmp);
        return;
    }
    while(nglyph--)
    {
	pci = *ppci++;
	pglyph = FONTGLYPHBITS(pglyphBase, pci);
	gWidth = GLYPHWIDTHPIXELS(pci);
	gHeight = GLYPHHEIGHTPIXELS(pci);
	if (gWidth && gHeight)
	{
	    nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci);
	    nbyPadGlyph = BitmapBytePad(gWidth);

	    if (nbyGlyphWidth == nbyPadGlyph
#if GLYPHPADBYTES != 4
	        && (((int) pglyph) & 3) == 0
#endif
		)
	    {
		pb = pglyph;
	    }
	    else
	    {
		for (i=0, pb = pbits; i<gHeight; i++, pb = pbits+(i*nbyPadGlyph))
		    for (j = 0; j < nbyGlyphWidth; j++)
			*pb++ = *pglyph++;
		pb = pbits;
	    }

	    if ((pGCtmp->serialNumber) != (pPixmap->drawable.serialNumber))
		ValidateGC((DrawablePtr)pPixmap, pGCtmp);
	    (*pGCtmp->ops->PutImage)((DrawablePtr)pPixmap, pGCtmp,
				pPixmap->drawable.depth,
				0, 0, gWidth, gHeight, 
				0, XYBitmap, (char *)pb);

	    if ((pGC->serialNumber) != (pDrawable->serialNumber))
		ValidateGC(pDrawable, pGC);
	    (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable,
			       gWidth, gHeight,
			       x + pci->metrics.leftSideBearing,
			       y - pci->metrics.ascent);
	}
	x += pci->metrics.characterWidth;
    }
    (*pDrawable->pScreen->DestroyPixmap)(pPixmap);
    DEALLOCATE_LOCAL(pbits);
    FreeScratchGC(pGCtmp);
}
glamor_font_t *
glamor_font_get(ScreenPtr screen, FontPtr font)
{
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);

    glamor_font_t       *privates;
    glamor_font_t       *glamor_font;
    int                 overall_width, overall_height;
    int                 num_rows;
    int                 num_cols;
    int                 glyph_width_pixels;
    int                 glyph_width_bytes;
    int                 glyph_height;
    int                 row, col;
    unsigned char       c[2];
    CharInfoPtr         glyph;
    unsigned long       count;
    char                *bits;

    if (glamor_priv->glsl_version < 130)
        return NULL;

    privates = FontGetPrivate(font, glamor_font_private_index);
    if (!privates) {
        privates = calloc(glamor_font_screen_count, sizeof (glamor_font_t));
        if (!privates)
            return NULL;
        FontSetPrivate(font, glamor_font_private_index, privates);
    }

    glamor_font = &privates[screen->myNum];

    if (glamor_font->realized)
        return glamor_font;

    /* Figure out how many glyphs are in the font */
    num_cols = font->info.lastCol - font->info.firstCol + 1;
    num_rows = font->info.lastRow - font->info.firstRow + 1;

    /* Figure out the size of each glyph */
    glyph_width_pixels = font->info.maxbounds.rightSideBearing - font->info.minbounds.leftSideBearing;
    glyph_height = font->info.maxbounds.ascent + font->info.maxbounds.descent;

    glyph_width_bytes = (glyph_width_pixels + 7) >> 3;

    glamor_font->glyph_width_pixels = glyph_width_pixels;
    glamor_font->glyph_width_bytes = glyph_width_bytes;
    glamor_font->glyph_height = glyph_height;

    /*
     * Layout the font two blocks of columns wide.
     * This avoids a problem with some fonts that are too high to fit.
     */
    glamor_font->row_width = glyph_width_bytes * num_cols;

    if (num_rows > 1) {
       overall_width = glamor_font->row_width * 2;
       overall_height = glyph_height * ((num_rows + 1) / 2);
    } else {
       overall_width = glamor_font->row_width;
       overall_height = glyph_height;
    }

    if (overall_width > glamor_priv->max_fbo_size ||
        overall_height > glamor_priv->max_fbo_size) {
        /* fallback if we don't fit inside a texture */
        return NULL;
    }
    bits = malloc(overall_width * overall_height);
    if (!bits)
        return NULL;

    /* Check whether the font has a default character */
    c[0] = font->info.lastRow + 1;
    c[1] = font->info.lastCol + 1;
    (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);

    glamor_font->default_char = count ? glyph : NULL;
    glamor_font->default_row = font->info.defaultCh >> 8;
    glamor_font->default_col = font->info.defaultCh;

    glamor_priv = glamor_get_screen_private(screen);
    glamor_make_current(glamor_priv);

    glGenTextures(1, &glamor_font->texture_id);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    /* Paint all of the glyphs */
    for (row = 0; row < num_rows; row++) {
        for (col = 0; col < num_cols; col++) {
            c[0] = row + font->info.firstRow;
            c[1] = col + font->info.firstCol;

            (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);

            if (count) {
                char *dst;
                char *src = glyph->bits;
                unsigned y;

                dst = bits;
                /* get offset of start of first row */
                dst += (row / 2) * glyph_height * overall_width;
                /* add offset into second row */
                dst += (row & 1) ? glamor_font->row_width : 0;

                dst += col * glyph_width_bytes;
                for (y = 0; y < GLYPHHEIGHTPIXELS(glyph); y++) {
                    memcpy(dst, src, GLYPHWIDTHBYTES(glyph));
                    dst += overall_width;
                    src += GLYPHWIDTHBYTESPADDED(glyph);
                }
            }
        }
    }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glamor_priv->suppress_gl_out_of_memory_logging = true;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, overall_width, overall_height,
                 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bits);
    glamor_priv->suppress_gl_out_of_memory_logging = false;
    if (glGetError() == GL_OUT_OF_MEMORY)
        return NULL;

    free(bits);

    glamor_font->realized = TRUE;

    return glamor_font;
}
static Bool
glamor_poly_glyph_blt_gl(DrawablePtr drawable, GCPtr gc,
                         int start_x, int y, unsigned int nglyph,
                         CharInfoPtr *ppci, void *pglyph_base)
{
    ScreenPtr screen = drawable->pScreen;
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    glamor_pixmap_private *pixmap_priv;
    glamor_program *prog;
    RegionPtr clip = gc->pCompositeClip;
    int box_index;

    pixmap_priv = glamor_get_pixmap_private(pixmap);
    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
        goto bail;

    glamor_make_current(glamor_priv);

    prog = glamor_use_program_fill(pixmap, gc,
                                   &glamor_priv->poly_glyph_blt_progs,
                                   &glamor_facet_poly_glyph_blt);
    if (!prog)
        goto bail;

    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);

    start_x += drawable->x;
    y += drawable->y;

    glamor_pixmap_loop(pixmap_priv, box_index) {
        int x;
        int n;
        int num_points, max_points;
        INT16 *points = NULL;
        int off_x, off_y;
        char *vbo_offset;

        glamor_set_destination_drawable(drawable, box_index, FALSE, TRUE,
                                        prog->matrix_uniform, &off_x, &off_y);

        max_points = 500;
        num_points = 0;
        x = start_x;
        for (n = 0; n < nglyph; n++) {
            CharInfoPtr charinfo = ppci[n];
            int w = GLYPHWIDTHPIXELS(charinfo);
            int h = GLYPHHEIGHTPIXELS(charinfo);
            uint8_t *glyphbits = FONTGLYPHBITS(NULL, charinfo);

            if (w && h) {
                int glyph_x = x + charinfo->metrics.leftSideBearing;
                int glyph_y = y - charinfo->metrics.ascent;
                int glyph_stride = GLYPHWIDTHBYTESPADDED(charinfo);
                int xx, yy;

                for (yy = 0; yy < h; yy++) {
                    uint8_t *glyph = glyphbits;
                    for (xx = 0; xx < w; glyph += ((xx&7) == 7), xx++) {
                        int pt_x_i = glyph_x + xx;
                        int pt_y_i = glyph_y + yy;

                        if (!(*glyph & (1 << (xx & 7))))
                            continue;

                        if (!RegionContainsPoint(clip, pt_x_i, pt_y_i, NULL))
                            continue;

                        if (!num_points) {
                            points = glamor_get_vbo_space(screen,
                                                          max_points *
                                                          (2 * sizeof (INT16)),
                                                          &vbo_offset);

                            glVertexAttribPointer(GLAMOR_VERTEX_POS,
                                                  2, GL_SHORT,
                                                  GL_FALSE, 0, vbo_offset);
                        }

                        *points++ = pt_x_i;
                        *points++ = pt_y_i;
                        num_points++;

                        if (num_points == max_points) {
                            glamor_put_vbo_space(screen);
                            glDrawArrays(GL_POINTS, 0, num_points);
                            num_points = 0;
                        }
                    }
                    glyphbits += glyph_stride;
                }
            }
            x += charinfo->metrics.characterWidth;
        }

        if (num_points) {
            glamor_put_vbo_space(screen);
            glDrawArrays(GL_POINTS, 0, num_points);
        }
    }
예제 #7
0
void
fbImageGlyphBlt(DrawablePtr drawable, GCPtr gc,
                int x, int y,
                unsigned int nglyph, CharInfoPtr * ppciInit, pointer glyphs)
{
	FbGCPrivPtr pgc = fb_gc(gc);
	CharInfoPtr *ppci;
	CharInfoPtr pci;
	unsigned char *pglyph;      /* pointer bits in glyph */
	int gWidth, gHeight;        /* width and height of glyph */
	FbStride gStride;           /* stride of glyph */
	bool opaque;
	int n;
	int gx, gy;
	void (*raster)(FbBits *, FbStride, int, FbStip *, FbBits, int, int);
	FbBits *dst = 0;
	FbStride dstStride = 0;
	int dstBpp = 0;
	int dstXoff = 0, dstYoff = 0;

	DBG(("%s x %d\n", __FUNCTION__, nglyph));

	raster = 0;
	if (pgc->and == 0) {
		dstBpp = drawable->bitsPerPixel;
		switch (dstBpp) {
		case 8:
			raster = fbGlyph8;
			break;
		case 16:
			raster = fbGlyph16;
			break;
		case 32:
			raster = fbGlyph32;
			break;
		}
	}

	x += drawable->x;
	y += drawable->y;

	if (TERMINALFONT(gc->font) && !raster) {
		opaque = TRUE;
	} else {
		int xBack, widthBack;
		int yBack, heightBack;

		ppci = ppciInit;
		n = nglyph;
		widthBack = 0;
		while (n--)
			widthBack += (*ppci++)->metrics.characterWidth;

		xBack = x;
		if (widthBack < 0) {
			xBack += widthBack;
			widthBack = -widthBack;
		}
		yBack = y - FONTASCENT(gc->font);
		heightBack = FONTASCENT(gc->font) + FONTDESCENT(gc->font);
		fbSolidBoxClipped(drawable, gc,
				  xBack, yBack,
				  xBack + widthBack,
				  yBack + heightBack);
		opaque = FALSE;
	}

	ppci = ppciInit;
	while (nglyph--) {
		pci = *ppci++;
		pglyph = FONTGLYPHBITS(glyphs, pci);
		gWidth = GLYPHWIDTHPIXELS(pci);
		gHeight = GLYPHHEIGHTPIXELS(pci);
		if (gWidth && gHeight) {
			gx = x + pci->metrics.leftSideBearing;
			gy = y - pci->metrics.ascent;
			if (raster && gWidth <= sizeof(FbStip) * 8 &&
			    fbGlyphIn(gc, gx, gy, gWidth, gHeight)) {
				fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff,
					      dstYoff);
				raster(dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
				       (FbStip *) pglyph, pgc->fg, gx + dstXoff, gHeight);
			} else {
				gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
				fbPutXYImage(drawable, gc,
					     pgc->fg, pgc->bg, pgc->pm,
					     GXcopy, opaque,
					     gx, gy, gWidth, gHeight,
					     (FbStip *) pglyph, gStride, 0);
			}
		}
		x += pci->metrics.characterWidth;
	}
}
예제 #8
0
void
fbPolyGlyphBlt(DrawablePtr drawable, GCPtr gc,
               int x, int y,
               unsigned int nglyph, CharInfoPtr * ppci, pointer glyphs)
{
	FbGCPrivPtr pgc = fb_gc(gc);
	CharInfoPtr pci;
	unsigned char *pglyph;      /* pointer bits in glyph */
	int gx, gy;
	int gWidth, gHeight;        /* width and height of glyph */
	FbStride gStride;           /* stride of glyph */
	void (*raster) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
	FbBits *dst = 0;
	FbStride dstStride = 0;
	int dstBpp = 0;
	int dstXoff = 0, dstYoff = 0;

	DBG(("%s x %d\n", __FUNCTION__, nglyph));

	raster = 0;
	if (gc->fillStyle == FillSolid && pgc->and == 0) {
		dstBpp = drawable->bitsPerPixel;
		switch (dstBpp) {
		case 8:
			raster = fbGlyph8;
			break;
		case 16:
			raster = fbGlyph16;
			break;
		case 32:
			raster = fbGlyph32;
			break;
		}
	}
	x += drawable->x;
	y += drawable->y;

	while (nglyph--) {
		pci = *ppci++;
		pglyph = FONTGLYPHBITS(glyphs, pci);
		gWidth = GLYPHWIDTHPIXELS(pci);
		gHeight = GLYPHHEIGHTPIXELS(pci);
		if (gWidth && gHeight) {
			gx = x + pci->metrics.leftSideBearing;
			gy = y - pci->metrics.ascent;
			if (raster && gWidth <= sizeof(FbStip) * 8 &&
			    fbGlyphIn(gc, gx, gy, gWidth, gHeight)) {
				fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff,
					      dstYoff);
				raster(dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
					  (FbStip *) pglyph, pgc->xor, gx + dstXoff, gHeight);
			} else {
				gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
				fbPushImage(drawable, gc,
					    (FbStip *)pglyph,
					    gStride, 0, gx, gy, gWidth, gHeight);
			}
		}
		x += pci->metrics.characterWidth;
	}
}