示例#1
0
/** Realize the font, \a pFont, on the back-end server associated with
 *  \a pScreen. */
Bool
dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
    dmxFontPrivPtr pFontPriv;

    if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) {
        FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
        pFontPriv = malloc(sizeof(dmxFontPrivRec));
        if (!pFontPriv)
            return FALSE;
        pFontPriv->font = NULL;
        MAXSCREENSALLOC(pFontPriv->font);
        if (!pFontPriv->font) {
            free(pFontPriv);
            return FALSE;
        }
        pFontPriv->refcnt = 0;
    }

    FontSetPrivate(pFont, dmxFontPrivateIndex, (void *) pFontPriv);

    if (dmxScreen->beDisplay) {
        if (!dmxBELoadFont(pScreen, pFont))
            return FALSE;

        pFontPriv->refcnt++;
    }
    else {
        pFontPriv->font[pScreen->myNum] = NULL;
    }

    return TRUE;
}
示例#2
0
static Bool
glamor_unrealize_font(ScreenPtr screen, FontPtr font)
{
    glamor_screen_private       *glamor_priv;
    glamor_font_t               *privates = FontGetPrivate(font, glamor_font_private_index);
    glamor_font_t               *glamor_font;
    int                         s;

    if (!privates)
        return TRUE;

    glamor_font = &privates[screen->myNum];

    if (!glamor_font->realized)
        return TRUE;

    /* Unrealize the font, freeing the allocated texture */
    glamor_font->realized = FALSE;

    glamor_priv = glamor_get_screen_private(screen);
    glamor_make_current(glamor_priv);
    glDeleteTextures(1, &glamor_font->texture_id);

    /* Check to see if all of the screens are  done with this font
     * and free the private when that happens
     */
    for (s = 0; s < glamor_font_screen_count; s++)
        if (privates[s].realized)
            return TRUE;

    free(privates);
    FontSetPrivate(font, glamor_font_private_index, NULL);
    return TRUE;
}
示例#3
0
Bool
xnestRealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
  pointer priv;
  Atom name_atom, value_atom;
  int nprops;
  FontPropPtr props;
  int i;
  char *name;

  FontSetPrivate(pFont, xnestFontPrivateIndex, NULL);

  if (requestingClient && XpClientIsPrintClient(requestingClient, NULL))
      return True;

  name_atom = MakeAtom("FONT", 4, True);
  value_atom = 0L;

  nprops = pFont->info.nprops;
  props = pFont->info.props;

  for (i = 0; i < nprops; i++)
    if (props[i].name == name_atom) {
      value_atom = props[i].value;
      break;
    }

  if (!value_atom) return False;

  name = (char *)NameForAtom(value_atom);

  if (!name) return False;

  priv = (pointer)xalloc(sizeof(xnestPrivFont));  
  FontSetPrivate(pFont, xnestFontPrivateIndex, priv);
  
  xnestFontPriv(pFont)->font_struct = XLoadQueryFont(xnestDisplay, name);

  if (!xnestFontStruct(pFont)) return False;
						     
  return True;
}
示例#4
0
Bool
xnestUnrealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
  if (xnestFontPriv(pFont)) {
    if (xnestFontStruct(pFont)) 
      XFreeFont(xnestDisplay, xnestFontStruct(pFont));
    xfree(xnestFontPriv(pFont));
    FontSetPrivate(pFont, xnestFontPrivateIndex, NULL);
  }
  return True;
}
示例#5
0
/** Unrealize the font, \a pFont, on the back-end server associated with
 *  \a pScreen. */
Bool
dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
    dmxFontPrivPtr pFontPriv;

    if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) {
        /* In case the font failed to load properly */
        if (!pFontPriv->refcnt) {
            MAXSCREENSFREE(pFontPriv->font);
            free(pFontPriv);
            FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
        }
        else if (pFontPriv->font[pScreen->myNum]) {
            if (dmxScreen->beDisplay)
                dmxBEFreeFont(pScreen, pFont);

            /* The code below is non-obvious, so here's an explanation...
             *
             * When creating the default GC, the server opens up the
             * default font once for each screen, which in turn calls
             * the RealizeFont function pointer once for each screen.
             * During this process both dix's font refcnt and DMX's font
             * refcnt are incremented once for each screen.
             *
             * Later, when shutting down the X server, dix shuts down
             * each screen in reverse order.  During this shutdown
             * procedure, each screen's default GC is freed and then
             * that screen is closed by calling the CloseScreen function
             * pointer.  screenInfo.numScreens is then decremented after
             * closing each screen.  This procedure means that the dix's
             * font refcnt for the font used by the default GC's is
             * decremented once for each screen # greater than 0.
             * However, since dix's refcnt for the default font is not
             * yet 0 for each screen greater than 0, no call to the
             * UnrealizeFont function pointer is made for those screens.
             * Then, when screen 0 is being closed, dix's font refcnt
             * for the default GC's font is finally 0 and the font is
             * unrealized.  However, since screenInfo.numScreens has
             * been decremented already down to 1, only one call to
             * UnrealizeFont is made (for screen 0).  Thus, even though
             * RealizeFont was called once for each screen,
             * UnrealizeFont is only called for screen 0.
             *
             * This is a bug in dix.
             *
             * To avoid the memory leak of pFontPriv for each server
             * generation, we can also free pFontPriv if the refcnt is
             * not yet 0 but the # of screens is 1 -- i.e., the case
             * described in the dix bug above.  This is only a temporary
             * workaround until the bug in dix is solved.
             *
             * The other problem is that the font structure allocated by
             * XLoadQueryFont() above is not freed for screens > 0.
             * This problem cannot be worked around here since the back-
             * end displays for screens > 0 have already been closed by
             * the time this code is called from dix.
             *
             * When the bug in dix described above is fixed, then we can
             * remove the "|| screenInfo.numScreens == 1" code below and
             * the memory leaks will be eliminated.
             */
            if (--pFontPriv->refcnt == 0
#if 1
                /* Remove this code when the dix bug is fixed */
                || screenInfo.numScreens == 1
#endif
                ) {
                MAXSCREENSFREE(pFontPriv->font);
                free(pFontPriv);
                FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
            }
        }
    }

    return TRUE;
}
示例#6
0
static int
ProcXF86BigfontQueryFont(
    ClientPtr client)
{
    FontPtr pFont;
    REQUEST(xXF86BigfontQueryFontReq);
    CARD32 stuff_flags;
    xCharInfo* pmax;
    xCharInfo* pmin;
    int nCharInfos;
    int shmid;
#ifdef HAS_SHM
    ShmDescPtr pDesc;
#else
#define pDesc 0
#endif
    xCharInfo* pCI;
    CARD16* pIndex2UniqIndex;
    CARD16* pUniqIndex2Index;
    CARD32 nUniqCharInfos;

#if 0
    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
#else
    switch (client->req_len) {
	case 2: /* client with version 1.0 libX11 */
	    stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
	    break;
	case 3: /* client with version 1.1 libX11 */
	    stuff_flags = stuff->flags;
	    break;
	default:
	    return BadLength;
    }
#endif
    client->errorValue = stuff->id;		/* EITHER font or gc */
    pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
					    SecurityReadAccess);
    if (!pFont) {
	/* can't use VERIFY_GC because it might return BadGC */
	GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC,
						SecurityReadAccess);
        if (!pGC) {
	    client->errorValue = stuff->id;
            return BadFont;    /* procotol spec says only error is BadFont */
	}
	pFont = pGC->font;
    }

    pmax = FONTINKMAX(pFont);
    pmin = FONTINKMIN(pFont);
    nCharInfos =
       (pmax->rightSideBearing == pmin->rightSideBearing
        && pmax->leftSideBearing == pmin->leftSideBearing
        && pmax->descent == pmin->descent
        && pmax->ascent == pmin->ascent
        && pmax->characterWidth == pmin->characterWidth)
       ? 0 : N2dChars(pFont);
    shmid = -1;
    pCI = NULL;
    pIndex2UniqIndex = NULL;
    pUniqIndex2Index = NULL;
    nUniqCharInfos = 0;

    if (nCharInfos > 0) {
#ifdef HAS_SHM
	pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
	if (pDesc) {
	    pCI = (xCharInfo *) pDesc->attach_addr;
	    if (stuff_flags & XF86Bigfont_FLAGS_Shm)
		shmid = pDesc->shmid;
	} else {
	    if (stuff_flags & XF86Bigfont_FLAGS_Shm)
		pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
				 + sizeof(CARD32));
	    if (pDesc) {
		pCI = (xCharInfo *) pDesc->attach_addr;
		shmid = pDesc->shmid;
	    } else {
#endif
		pCI = (xCharInfo *)
		      ALLOCATE_LOCAL(nCharInfos * sizeof(xCharInfo));
		if (!pCI)
		    return BadAlloc;
#ifdef HAS_SHM
	    }
#endif
	    /* Fill nCharInfos starting at pCI. */
	    {
		xCharInfo* prCI = pCI;
		int ninfos = 0;
		int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
		int row;
		for (row = pFont->info.firstRow;
		     row <= pFont->info.lastRow && ninfos < nCharInfos;
		     row++) {
		    unsigned char chars[512];
		    xCharInfo* tmpCharInfos[256];
		    unsigned long count;
		    int col;
		    unsigned long i;
		    i = 0;
		    for (col = pFont->info.firstCol;
			 col <= pFont->info.lastCol;
			 col++) {
			chars[i++] = row;
			chars[i++] = col;
		    }
		    (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
					   &count, tmpCharInfos);
		    for (i = 0; i < count && ninfos < nCharInfos; i++) {
			*prCI++ = *tmpCharInfos[i];
			ninfos++;
		    }
		}
	    }
#ifdef HAS_SHM
	    if (pDesc) {
		*(CARD32 *)(pCI + nCharInfos) = signature;
		if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) {
		    shmdealloc(pDesc);
		    return BadAlloc;
		}
	    }
	}
#endif
	if (shmid == -1) {
	    /* Cannot use shared memory, so remove-duplicates the xCharInfos
	       using a temporary hash table. */
	    /* Note that CARD16 is suitable as index type, because
	       nCharInfos <= 0x10000. */
	    CARD32 hashModulus;
	    CARD16* pHash2UniqIndex;
	    CARD16* pUniqIndex2NextUniqIndex;
	    CARD32 NextIndex;
	    CARD32 NextUniqIndex;
	    CARD16* tmp;
	    CARD32 i, j;

	    hashModulus = 67;
	    if (hashModulus > nCharInfos+1)
		hashModulus = nCharInfos+1;

	    tmp = (CARD16*)
		  ALLOCATE_LOCAL((4*nCharInfos+1) * sizeof(CARD16));
	    if (!tmp) {
		if (!pDesc) DEALLOCATE_LOCAL(pCI);
		return BadAlloc;
	    }
	    pIndex2UniqIndex = tmp;
		/* nCharInfos elements */
	    pUniqIndex2Index = tmp + nCharInfos;
		/* max. nCharInfos elements */
	    pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos;
		/* max. nCharInfos elements */
	    pHash2UniqIndex = tmp + 3*nCharInfos;
		/* hashModulus (<= nCharInfos+1) elements */

	    /* Note that we can use 0xffff as end-of-list indicator, because
	       even if nCharInfos = 0x10000, 0xffff can not occur as valid
	       entry before the last element has been inserted. And once the
	       last element has been inserted, we don't need the hash table
	       any more. */
	    for (j = 0; j < hashModulus; j++)
		pHash2UniqIndex[j] = (CARD16)(-1);

	    NextUniqIndex = 0;
	    for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
		xCharInfo* p = &pCI[NextIndex];
		CARD32 hashCode = hashCI(p) % hashModulus;
		for (i = pHash2UniqIndex[hashCode];
		     i != (CARD16)(-1);
		     i = pUniqIndex2NextUniqIndex[i]) {
		    j = pUniqIndex2Index[i];
		    if (pCI[j].leftSideBearing == p->leftSideBearing
			&& pCI[j].rightSideBearing == p->rightSideBearing
			&& pCI[j].characterWidth == p->characterWidth
			&& pCI[j].ascent == p->ascent
			&& pCI[j].descent == p->descent
			&& pCI[j].attributes == p->attributes)
			break;
		}
		if (i != (CARD16)(-1)) {
		    /* Found *p at Index j, UniqIndex i */
		    pIndex2UniqIndex[NextIndex] = i;
		} else {
		    /* Allocate a new entry in the Uniq table */
		    if (hashModulus <= 2*NextUniqIndex
			&& hashModulus < nCharInfos+1) {
			/* Time to increate hash table size */
			hashModulus = 2*hashModulus+1;
			if (hashModulus > nCharInfos+1)
			    hashModulus = nCharInfos+1;
			for (j = 0; j < hashModulus; j++)
			    pHash2UniqIndex[j] = (CARD16)(-1);
			for (i = 0; i < NextUniqIndex; i++)
			    pUniqIndex2NextUniqIndex[i] = (CARD16)(-1);
			for (i = 0; i < NextUniqIndex; i++) {
			    j = pUniqIndex2Index[i];
			    p = &pCI[j];
			    hashCode = hashCI(p) % hashModulus;
			    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
			    pHash2UniqIndex[hashCode] = i;
			}
			p = &pCI[NextIndex];
			hashCode = hashCI(p) % hashModulus;
		    }
		    i = NextUniqIndex++;
		    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
		    pHash2UniqIndex[hashCode] = i;
		    pUniqIndex2Index[i] = NextIndex;
		    pIndex2UniqIndex[NextIndex] = i;
		}
	    }
	    nUniqCharInfos = NextUniqIndex;
	    /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */
	}
    }

    {
	int nfontprops = pFont->info.nprops;
	int rlength =
	   sizeof(xXF86BigfontQueryFontReply)
	   + nfontprops * sizeof(xFontProp)
	   + (nCharInfos > 0 && shmid == -1
	      ? nUniqCharInfos * sizeof(xCharInfo)
	        + (nCharInfos+1)/2 * 2 * sizeof(CARD16)
	      : 0);
	xXF86BigfontQueryFontReply* reply =
	   (xXF86BigfontQueryFontReply *) ALLOCATE_LOCAL(rlength);
	char* p;
	if (!reply) {
	    if (nCharInfos > 0) {
		if (shmid == -1) DEALLOCATE_LOCAL(pIndex2UniqIndex);
		if (!pDesc) DEALLOCATE_LOCAL(pCI);
	    }
	    return BadAlloc;
	}
	reply->type = X_Reply;
	reply->length = (rlength - sizeof(xGenericReply)) >> 2;
	reply->sequenceNumber = client->sequence;
	reply->minBounds = pFont->info.ink_minbounds;
	reply->maxBounds = pFont->info.ink_maxbounds;
	reply->minCharOrByte2 = pFont->info.firstCol;
	reply->maxCharOrByte2 = pFont->info.lastCol;
	reply->defaultChar = pFont->info.defaultCh;
	reply->nFontProps = pFont->info.nprops;
	reply->drawDirection = pFont->info.drawDirection;
	reply->minByte1 = pFont->info.firstRow;
	reply->maxByte1 = pFont->info.lastRow;
	reply->allCharsExist = pFont->info.allExist;
	reply->fontAscent = pFont->info.fontAscent;
	reply->fontDescent = pFont->info.fontDescent;
	reply->nCharInfos = nCharInfos;
        reply->nUniqCharInfos = nUniqCharInfos;
	reply->shmid = shmid;
	reply->shmsegoffset = 0;
	if (client->swapped) {
	    char tmp;
	    swaps(&reply->sequenceNumber, tmp);
	    swapl(&reply->length, tmp);
	    swapCharInfo(&reply->minBounds);
	    swapCharInfo(&reply->maxBounds);
	    swaps(&reply->minCharOrByte2, tmp);
	    swaps(&reply->maxCharOrByte2, tmp);
	    swaps(&reply->defaultChar, tmp);
	    swaps(&reply->nFontProps, tmp);
	    swaps(&reply->fontAscent, tmp);
	    swaps(&reply->fontDescent, tmp);
	    swapl(&reply->nCharInfos, tmp);
	    swapl(&reply->nUniqCharInfos, tmp);
	    swapl(&reply->shmid, tmp);
	    swapl(&reply->shmsegoffset, tmp);
	}
	p = (char*) &reply[1];
	{
	    FontPropPtr pFP;
	    xFontProp* prFP;
	    int i;
	    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
		 i < nfontprops;
		 i++, pFP++, prFP++) {
		prFP->name = pFP->name;
		prFP->value = pFP->value;
		if (client->swapped) {
		    char tmp;
		    swapl(&prFP->name, tmp);
		    swapl(&prFP->value, tmp);
		}
	    }
	    p = (char*) prFP;
	}
	if (nCharInfos > 0 && shmid == -1) {
	    xCharInfo* pci;
	    CARD16* ps;
	    int i, j;
	    pci = (xCharInfo*) p;
	    for (i = 0; i < nUniqCharInfos; i++, pci++) {
		*pci = pCI[pUniqIndex2Index[i]];
		if (client->swapped)
		    swapCharInfo(pci);
	    }
	    ps = (CARD16*) pci;
	    for (j = 0; j < nCharInfos; j++, ps++) {
		*ps = pIndex2UniqIndex[j];
		if (client->swapped) {
		    char tmp;
		    swaps(ps, tmp);
		}
	    }
	}
	WriteToClient(client, rlength, (char *)reply);
	DEALLOCATE_LOCAL(reply);
	if (nCharInfos > 0) {
	    if (shmid == -1) DEALLOCATE_LOCAL(pIndex2UniqIndex);
	    if (!pDesc) DEALLOCATE_LOCAL(pCI);
	}
	return (client->noClientException);
    }
}
示例#7
0
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;


    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;

    glamor_font->realized = TRUE;

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

    overall_width = glyph_width_bytes * num_cols;
    overall_height = glyph_height * num_rows;

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

    /* Allocate storage */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, overall_width, overall_height,
                 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    /* 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)
                glTexSubImage2D(GL_TEXTURE_2D, 0, col * glyph_width_bytes, row * glyph_height,
                                GLYPHWIDTHBYTES(glyph), GLYPHHEIGHTPIXELS(glyph),
                                GL_RED_INTEGER, GL_UNSIGNED_BYTE, glyph->bits);
        }
    }

    return glamor_font;
}
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;
}