4.4BSD/usr/src/contrib/X11R5-hp300/mit/server/ddx/hpbsd/hpFonts.c

/*

Copyright (c) 1986, 1987 by Hewlett-Packard Company
Copyright (c) 1986, 1987 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD
TO THIS SOFWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE.  Hewlett-Packard shall not be liable for errors 
contained herein or direct, indirect, special, incidental or 
consequential damages in connection with the furnishing, 
performance, or use of this material.

This software is not subject to any license of the American
Telephone and Telegraph Company or of the Regents of the
University of California.

*/
/***********************************************************************
 *  file: hpFonts.c
 *
 *  Font optimization/removal and text output routines
 *
 *		Hewlett Packard -- Corvallis Workstation Operation
 *		Project -- port of X11 to HP9000
 *		Harry Phinney -- MTS
 *
 *
 */

#include "Xmd.h"
#include "Xproto.h"
#include "misc.h"
#include "dixfontstr.h"
#include "fontstruct.h"
#include "scrnintstr.h"
#include "hpOScrnBuf.h"
#include "hpFonts.h"

#include "hppriv.h"

extern char *NameForAtom();	/* in dix/atom.c */

static int hpAllocFontMem();
static void hpStoreFont();

static int
lookUpProperty(pFont, pName)
     register FontRec *pFont;
     register char *pName;
{
    register int n = FONTINFONPROPS(pFont);
    register FontPropPtr pFP = FONTPROPS(pFont);

    for (;n--; pFP++)
    {
	register char *pPropString;
	if((pPropString = NameForAtom(pFP->name)) && !strcmp(pPropString, pName))
	    return (int) pFP->value;
    }
    return 0;
}


/************************************************************************
 *  Routine:	hpRealizeFont
 *		Optimize the font i.e. store it in offscreen memory
 *		This implementation (like our X10) only stores
 *		the characters defined by STARTCHAR thru LASTCHAR in
 *		offscreen.  It breaks them into offscreen chunks
 *		of CHARSPERCHUNK size
 *
 *  Inputs: pScreen points to the ScreenRec we'll try to optimize for
 *	    pFont points to the font we'll store in offscreen
 *  
 *  Returns: TRUE (always)
 *
 *  Side Effects:  sets pFont->devPriv[pScreen->myNum] to point to an
 *		hpFontRec which identifies the location of the font
 *		in offscreen.
 *
 */


Bool
hpRealizeFont(pScreen, pFont)
  ScreenPtr pScreen;
  FontRec *pFont;
{
#if 0
    int index = pScreen->myNum;
    CharInfoPtr pCI = pFont->pCI;
    unsigned int chDefault =  FONTDEFAULTCH(pFont);
    unsigned int firstCol = FONTFIRSTCOL(pFont);
    unsigned int lastCol = FONTLASTCOL(pFont);
    int glyphWidth = FONTMAXBOUNDS(pFont,rightSideBearing) -
	FONTMINBOUNDS(pFont,leftSideBearing);
    int glyphHeight = FONTMAXBOUNDS(pFont,ascent) +
	FONTMAXBOUNDS(pFont,descent);
    hpFontRec *pHpFrec;
    hpCharRange *pRange;
    int i, prop, startChar, lastChar;

    /*
     * if it's right-to-left, or if the
     * glyphs are bigger than 24 pixels wide,
     * then don't optimize it.
     */
    if (pFont->info.drawDirection || (glyphWidth > 24))
    {
	pFont->devPriv[index] = (pointer) NULL;
	return TRUE;
    }

    /*
     * allocate an hpFontRec
     */
    pHpFrec = (hpFontRec *) xalloc(sizeof (hpFontRec));
    if (!pHpFrec)
    {
	pFont->devPriv[index] = (pointer) NULL;
	return TRUE;
    }

    /*
     * allocate the space for stippling a character
     */
    if (!(pHpFrec->stippleChunk = hpBufAlloc(pScreen, glyphWidth, glyphHeight)))
    {
	xfree(pHpFrec);
	pFont->devPriv[index] = (pointer) NULL;
	return TRUE;
    }
  
    /*
     * Check to see if the font has properties telling which characters
     * to optimize
     */
    if (prop = lookUpProperty(pFont, "HPSTARTOPTIMIZE"))
	startChar = prop;
    else
	startChar = STARTCHAR;
    if (prop = lookUpProperty(pFont, "HPENDOPTIMIZE"))
	lastChar = prop;
    else
	lastChar = LASTCHAR;

    /*
     * allocate the offscreen, and put the chunk info in the hpFontRec
     */
    if (!hpAllocFontMem(pScreen, pFont, pHpFrec, startChar, 
			lastChar, CHARSPERCHUNK))
    {
	hpBufFree(pScreen, pHpFrec->stippleChunk);
	xfree(pHpFrec);
	pFont->devPriv[index] = (pointer) NULL;
	return TRUE;
    }

    /*
     * attach the hpFontRec to the devPriv field in the Font
     */
    pFont->devPriv[index] = (pointer) pHpFrec;

    pRange = pHpFrec->pRange;

    /*
     * store the font in the offscreen memory
     */
    for (i = 0; i < pHpFrec->NumChunks; i++)
    {
	hpStoreFont(pScreen, pFont, i, startChar + (i * CHARSPERCHUNK), 
		    CHARSPERCHUNK);
	pRange[i].startChar = startChar + (i * CHARSPERCHUNK);
	pRange[i].endChar = pRange[i].startChar + CHARSPERCHUNK - 1;
    }
    pHpFrec->maxWidth = glyphWidth;
    pHpFrec->maxHeight = glyphHeight;
    pHpFrec->firstChar = startChar;
    pHpFrec->lastChar = lastChar;

    /*
     * check for the existence of the default glyph.  If it exists, then
     * hpStoreFont will have put it in place of any nonexistent glyphs.
     * If it doesn't exist, then the text output routines have to skip
     * any non-existent character.
     */
    pHpFrec->fDefaultExists = !((chDefault < firstCol) || 
				(chDefault > lastCol) ||
				!pCI[chDefault - firstCol].exists);

#endif
    return TRUE;
}


/************************************************************************
 *  Routine:	hpUnrealizeFont
 *		If the font had been stored in offscreen memory
 *		then free all the associated memory.
 *
 *  Inputs: pScreen points to the ScreenRec the font was realized for
 *	    pFont points to the font we're unrealizing
 *  
 *  Returns: nothing of importance
 *
 *  Side Effects:  none
 *
 */

Bool
hpUnrealizeFont(pScreen, pFont)
     register ScreenPtr pScreen;
     register FontRec *pFont;
{
#if 0
    int index = pScreen->myNum;
    register hpFontRec *pHpFrec;
    register int i;

    /*
     * test to see if we ever optimized this font
     */
    if (! pFont->devPriv[index])
	return TRUE; 
    
    pHpFrec = (hpFontRec *) pFont->devPriv[index];

    /*
     * mark the font as unoptimized
     */
    pFont->devPriv[index] = (pointer) NULL;

    /*
     * free the offscreen chunks
     */
    for (i = 0; i < pHpFrec->NumChunks; i++)
	hpBufFree(pScreen, pHpFrec->ppChunk[i]);
    
    /*
     * free the stippleChunk
     */
    hpBufFree(pScreen, pHpFrec->stippleChunk);

    /*
     * free the chunk table
     */
    xfree(pHpFrec->ppChunk);

    /*
     * free the range array
     */
    xfree(pHpFrec->pRange);

    /*
     * finally, free the hpFontRec itself
     */
    xfree(pHpFrec);
#endif
    return TRUE;
}


/************************************************************************
 *  Routine:	hpAllocFontMem
 *		Get enough offscreen memory on the screen to optomize
 *		the font and store the locations in an hpFontRec
 *
 *  Inputs: pScreen points to the ScreenRec we'll get the memory on 
 *	    pFont points to the font we're allocating for
 *	    phpFontRec we fill out telling where the memory is alloc'd
 *	    first and last specify the first and last glyphs to allocate for
 *	    size specifies the size of each chunk in glyphs
 *  
 *  Returns: 1 for success, 0 for not enough offscreen memory
 *
 *  Side Effects:  none
 *
 */

static int
hpAllocFontMem(pScn, pFnt, pHpFrec, first, last, size)
     ScreenPtr pScn;
     FontRec *pFnt;
     hpFontRec *pHpFrec;
     int first, last, size;
{
    int i;
    int width, height; /* width & height of each chunk */
    int total = last - first + 1; /* total num chars to allocate for */
    int num_chunks = total/size;

    if (total%size) num_chunks++;

    pHpFrec->ppChunk = (hpChunk **) xalloc(sizeof(hpChunk *) * num_chunks);
    if (!(pHpFrec->ppChunk))
	return 0;  
    pHpFrec->NumChunks = num_chunks;

    pHpFrec->pRange = (hpCharRange *) xalloc(sizeof(hpCharRange) * num_chunks);
    if (!(pHpFrec->pRange))
	return 0;  

    /*
     * figure out how much memory we need
     * allocates enough memory to contain "total"
     * number of maximum-sized glyphs
     */
    width = (FONTMAXBOUNDS(pFnt,rightSideBearing) -
	     FONTMINBOUNDS(pFnt,leftSideBearing)) * size;
  
    height = FONTMAXBOUNDS(pFnt,ascent) + FONTMAXBOUNDS(pFnt,descent);

    for (i = 0; i < num_chunks; i++)
    {

	/*
	 * get offscreen memory
	 */
	if ((pHpFrec->ppChunk[i] = hpBufAlloc(pScn, width, height)) == NULL)
	{
	    /*
	     * if it fails, we've gotta free up all the data structures
	     */
	    while(i)
		hpBufFree(pScn, pHpFrec->ppChunk[--i]);
	    pHpFrec->NumChunks = 0;
	    xfree(pHpFrec->ppChunk);
	    pHpFrec->ppChunk = (hpChunk **) NULL;
	    xfree(pHpFrec->pRange);
	    pHpFrec->pRange = (hpCharRange *) NULL;
	    return 0;
	}
    }
    return 1;
}


/************************************************************************
 *  Routine:	hpStoreFont
 *		Write font glyphs into previously allocated offscreen memory
 *		Stores a contiguous range of glyphs e.g. 32-63
 *		Calls hpWholeGlyph (LIE) to put the bits in the framebuffer
 *		with no clipping
 *
 *  Inputs: pScreen points to the ScreenRec whose memory we write to
 *	    pFont points to the font we'll store in offscreen
 *	    index gets us to the chunk to store the glyphs in
 *	    start and num define the range of glyphs to store
 *  
 *  Returns: nothing of importance
 *
 *  Side Effects:  none
 *
 */

static void
hpStoreFont(pScn, pFnt, chunkNum, startGlyph, numGlyphs)
     ScreenPtr pScn;
     register FontRec *pFnt;
     int chunkNum; /* index into array of chunks */
     int startGlyph;
     register numGlyphs;
{
#if 0
    int glyphNum = startGlyph;
    char *pCurrentGlyph;
    register CharInfoPtr pCi;
    int cellWidth = FONTMAXBOUNDS(pFnt,rightSideBearing) -
	FONTMINBOUNDS(pFnt,leftSideBearing);
    int defaultChar = FONTDEFAULTCH(pFnt);
    hpChunk *pChunk = ((hpFontRec *)pFnt->devPriv[pScn->myNum])->
	ppChunk[chunkNum];
    hpPrivScreenPtr pPrivScn = getPrivScreenPtr(pScn);
    register x;
    int y;
    unsigned int firstCol = FONTFIRSTCOL(pFnt);
    unsigned int lastCol = FONTLASTCOL(pFnt);
    CharInfoPtr pDefaultCi = (CharInfoPtr) &(pFnt->pCI[defaultChar - firstCol]);
    char *pDefaultGlyph = FONTGLYPHS(pFnt) + pDefaultCi->byteOffset;
    int fDefaultExists = !((defaultChar < firstCol) ||
			   (defaultChar > lastCol) ||
			   !pDefaultCi->exists);

    x = pChunk->x;
    y = pChunk->y;

    while (numGlyphs--)
    {
	if (glyphNum > lastCol) break;

	pCi = &(pFnt->pCI[glyphNum - firstCol]);
	if ((glyphNum >= firstCol) && pCi->exists)
	{
	    pCurrentGlyph = FONTGLYPHS(pFnt) + pCi->byteOffset;
	    (*pPrivScn->WholeGlyph)(pScn, pCurrentGlyph, pCi, x, y,
				    GXcopy, ~0, 0, pPrivScn->planesMask);
	}
	else
	{
	    if (fDefaultExists)
		(*pPrivScn->WholeGlyph)(pScn, pDefaultGlyph, pDefaultCi, x, y,
					GXcopy, ~0, 0, pPrivScn->planesMask);
	}
	glyphNum++;
	x += cellWidth;
	pCi++;
    }
#endif
}