File:  [WindowsNT SDKs] / ntddk / src / print / pscript / fonttree.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

//--------------------------------------------------------------------------
//
// Module Name:  FONTTREE
//
// Brief Description:  Device font tree querying routines
//
// Author:  Kent Settle (kentse)
// Created: 18-Apr-1991
//
// Copyright (C) 1991 - 1992 Microsoft Corporation.
//
// This module contains DrvQueryFontTree.
//
// History:
//   18-Apr-1991    -by-    Kent Settle       (kentse)
// Created.
//--------------------------------------------------------------------------

#include "pscript.h"
#include "enable.h"
#include "mapping.h"
#include <string.h>

#define MAX_MAPSUBTABLES    256
#define MAX_GLYPHTABLES     16
#define MAX_GLYPHS          16

PVOID BuildGLYPHSET(PDEVDATA, ULONG);
PVOID BuildKernPairs(PDEVDATA, ULONG);

//--------------------------------------------------------------------------
// PVOID DrvQueryFontTree (dhpdev,iFile,iFace,iMode)
// DHPDEV    dhpdev;
// ULONG     iFile;
// ULONG     iFace;
// ULONG     iMode;
// ULONG     *pid;
// 
// This function is used by GDI to obtain pointers to tree structures that
// define one of the following.
// 
//     1    The mapping from Unicode to glyph handles, including glyph 
//          variants; 
//     2    The mapping of ligatures and their variants to glyph handles; 
//     3    The mapping of kerning pairs to kerning handles.
// 
// Parameters:
//   dhpdev    
//     This is a PDEV handle returned from an earlier call to DrvEnablePDEV.
//   iFile
//     This identifies the font file (if device supports loading font files
//     using the DDI).
//   iFace
//     This is the index of the driver font.  The index of the first font
//     is one.  
//   iMode
//     This defines the type of information to be returned.  This may take
//     one of the following values:
// 
//       QFT_UNICODE GDI requests a pointer to a TREE_UNICODE structure 
//                   that defines the mappings from single Unicode characters
//                   to glyph handles.  This includes all glyph variants.
// 
//       QFT_LIGATURES GDI requests a pointer to a TREE_LIGATURES 
//                     structure that defines the mapping from strings 
//                     of Unicode characters to glyph handles.  This 
//                     includes all ligature variants.
// 
//       QFT_KERNPAIRS GDI requests a pointer to a TREE_KERNPAIRS 
//                     structure that define the mappings from pairs 
//                     of Unicode characters to kerning pair handles.  
//                     These kerning handles are later passed to
//                     DrvQueryFontData to obtain kerning corrections.
// 
// Returns:
//   The return value is a pointer to the requested structure. This 
//   structure is to remain unchanged during the lifetime of the 
//   associated PDEV.
//
// Note:  The following explanation was "borrowed" from lindsayh and the
//        Generic driver.
//
//   COMMENTS ON THE UNICODE TREE STRUCTURES:
//	The following is intended to help understand the strange operations
//  being done in the following function.  UNICODE is a sparse encoding,
//  so a tree structure is used to store the data.  The following function
//  produces a tree,  the leaves of which are the GLYPH HANDLES that the
//  engine passes to us to identify perticular glyphs.  These handles are
//  32 bits long,  contents up to the driver.  We need to allocate storage
//  for these and fill it in.  The first step is to determine how much
//  storage is needed.  This requires understanding how the tree is built.
//	The tree has 3 levels.  At the top level there is a MAPTABLE
//  structure.  This has as many as 256 sub trees.  These correspond to
//  the 8 MSBs of the unicode value.  This structure is folllowed by up to
//  256 PTRDIFFs (each a long).  The structure itself contains a 256 byte
//  array:  this is an index into the array of PTRDIFFs following.  Hence,
//  there only needs to be as many PTRDIFFs as there are subtrees (plus 1,
//  for the "no entry" value).  For example,  if there is only subtree,
//  there need be only 2 PTRDIFFs - the active one,  and a 0 entry.  The
//  byte array will mostly contain the index to the 0 entry,  but the
//  active entry will point at the other PTRDIFF.
//
//	Each of the above active PTRDIFFs points to a MAPSUBTABLE.  Each of
//  these can handle 16 sub trees.  It uses the same method as the MAPTABLE
//  to handle sparseness - i.e. there is a 16 byte array containing
//  indices into the array of PTRDIFFs following.  The 16 byte array
//  is indexed by the next 4 bits in the UNICODE value (i.e. the high
//  nibble of the low byte).  These PTRDIFFs point to GLYPHTABLEs,
//  the next lower level in the tree.
//
//	The final layer is the GLYPHTABLE data.  Each of these contains
//  up to 16 GLYPH HANDLEs,  and is indexed by the 4 LSBs of the UNICODE
//  value.  Like the MAPSUBTABLE,  there is a byte array containing
//  index values of the glyph handles following.
//
//   HOW MUCH MEMORY IS NEEDED??
//  The tricky part is now determining how much memory to allocate for
//  these structures.  The answer is:  a DWORD for each GLYPH HANDLE,
//  as many GLYPHTABLEs as there are groups defined by the high order
//  12 bits of the UNICODE value (i.e., up to 4096),  as many MAPSUBTABLES
//  as there are groups of 16 GLYPHTABLES (up to 256), plus a MAPTABLE
//  to amalgamate the top level.  As well,  the MAPTABLE and MAPSUBTABLE
//  require PTRDIFFs to the lower level - this is as many as there are
//  lower level entities.
//
//	Determining this is done as follows:  allocate a 64k BIT array,
//  considered as an array of 4096 WORDS (16 bits each).  For every
//  available glyph,  set the corresponding bit in the array,  and
//  increment a counter.  At the end of this stage,  we have a count of
//  the number of (non-zero) GLYPH HANDLES needed.  Now,  by scanning
//  the bit array by WORD,  count each non-zero word.  This tells us
//  how many GLYPHTABLEs are required.   A second bit array is also
//  updated at this time.  This array consists of 256 bits,  one for
//  each of the possible entries in the MAPTABLE.  Passing through the
//  WORD array,  we can also set bits in the 256 bit array corresponding
//  to the number of MAPTABLES required.  Finally,  counting the number
//  of set bits in the 256 bit array gives us the number of MAPTABLES
//  required.  Given this information,  it is possible to determine
//  the amount of storage required.  Note that it is necessary to allow
//  for a 0 entry in the PTRDIFF and HGLYPH arrays.
// 
//   If an error occurs, NULL should be returned and an error code should 
//   be logged.
//
// History:
//   18-Apr-1991    -by-    Kent Settle       (kentse)
// Wrote it.
//--------------------------------------------------------------------------

PVOID DrvQueryFontTree (dhpdev,iFile,iFace,iMode,pid)
DHPDEV    dhpdev;
ULONG     iFile;
ULONG     iFace;
ULONG     iMode;
ULONG    *pid;
{
    PDEVDATA            pdev;

    UNREFERENCED_PARAMETER(iFile);

    // This can be used by the driver to flag or id the data returned.
    // May be useful for deletion of the data later by DrvFree().

    *pid = 0;           // don't need to use for this driver

    // get a pointer to our PDEV.

    pdev = (PDEVDATA)dhpdev;

    if (bValidatePDEV(pdev) == FALSE)
    {
	RIP("PSCRIPT!DrvQueryFontTree: invalid PDEV.");
	SetLastError(ERROR_INVALID_PARAMETER);
        return((PVOID)NULL);
    }

    // validate the iFace.  we should only be called for device fonts,
    // ie iFace >= 1.

    if ((iFace < 1) || (iFace > (pdev->cDeviceFonts + pdev->cSoftFonts)))
    {
	RIP("PSCRPT!BuildGLYPHSET: invalid iFace.\n");
	SetLastError(ERROR_INVALID_PARAMETER);
	return((PVOID)NULL);
    }

    switch (iMode)
    {
	case QFT_GLYPHSET:
	    return(BuildGLYPHSET(pdev, iFace));
	    break;

	case QFT_KERNPAIRS:
            return(BuildKernPairs(pdev, iFace));
	    break;

	default:
	    RIP("PSCRIPT!DrvQueryFontTree: invalid iMode.\n");
	    SetLastError(ERROR_INVALID_PARAMETER);
	    return((PVOID)NULL);
    }
}

//--------------------------------------------------------------------------
// PVOID BuildGLYPHSET(pdev, iFace)
// PDEVDATA    pdev;
// ULONG       iFace;
//
//   If an error occurs, NULL should be returned and an error code should 
//   be logged.
//
// History:
//   10-Feb-1992	  -by-	  Kent Settle	     (kentse)
// Borrowed some of if from RASDD, wrote the rest.
//--------------------------------------------------------------------------

PVOID BuildGLYPHSET(pdev, iFace)
PDEVDATA    pdev;
ULONG	    iFace;
{
    PNTFM	pntfm;		// pointer to font metrics.
    PUCMap	pmap;		// pointer to UNICODE<->PSCRIPT mapping table.
    PUCMap	pmapReset;	// place to save pointer.
    DWORD       i;              // loop counter.
    PBYTE	pCharCode;	// pointer to character code.
    PBYTE       pCharReset;     // place to save pointer.
    WCHAR	wchCurrent;	// current UNICODE value.
    WCHAR	wchPrevious;	// previous UNICODE value.
    DWORD       cGlyphs;        // count of glyph handles.
    DWORD       cRuns;          // count of runs within FD_GLYPHSET.
    DWORD	cbTotalMem;	// count of bytes needed for FD_GLYPHSET.
    HGLYPH     *phg;		// pointer to HGLYPH's.
    FD_GLYPHSET *pGLYPHSET;	// pointer to FD_GLYPHSET.
    WCRUN      *pWCRUN; 	// pointer to WCRUN.
    PULONG      pulUCTree;      // pointer to UNICODE tree.

    // get the font information for the given font.

    pntfm = pdev->pfmtable[iFace - 1].pntfm;

    // point to the appropriate mapping table in mapping.h.

    if (!strcmp((char *)pntfm + pntfm->loszFontName, "Symbol"))
        pmap = SymbolMap;

    else if (!strcmp((char *)pntfm + pntfm->loszFontName, "ZapfDingbats"))
        pmap = DingbatsMap;
    else
        pmap = LatinMap;

    pmapReset = pmap;

    // for every character in the mapping table, do a lookup in the NTFM
    // structure to find a matching PostScript character code.  For each
    // character found, we can extract the corresponding UNICODE value.
    // remember that the character codes are sitting in a BYTE array
    // which is sitting directly after a (USHORT) array of character
    // widths.

    pCharCode = ((PBYTE)pntfm + pntfm->loCharMetrics +
                       DWORDALIGN(pntfm->cCharacters * sizeof(USHORT)));

    // save the original pointer.

    pCharReset = pCharCode;

    cRuns = 1;  // there must be at least one run!
    cGlyphs = 0;

    // set wchPrevious equal to first UNICODE character code.

    wchPrevious = (WCHAR)pmap->usUCValue;

    while (pmap->szChar)
    {
        for (i = 0; i < (DWORD)pntfm->cCharacters; i++)
        {
            // search through all the characters in the NTFM structure,
            // looking for a matching PostScript character code. remember
            // that the high bit is used to indicate the font needs
            // to be remapped.  so ignore the high bit while checking
            // for a character match.

            if ((CHAR)*pCharCode == (CHAR)pmap->usPSValue)
            {
                // we have found the character, now get its UNICODE value
                // and set its BIT in the BIT array.  also, increment the
                // glyph count, if this UNICODE value has not yet been used.
                // since the mapping tables in mapping.h are sorted by
                // UNICODE values, we can simply check this value against
                // the one we found last time.  if it is the same, ignore 
                // it, if it is different, use it.

		wchCurrent = (WCHAR)pmap->usUCValue;

		if (wchCurrent != wchPrevious)
                {
		    cGlyphs++;

		    // see if we are starting new run.

                    if ((wchCurrent - wchPrevious) != 1)
                        cRuns++;
                }
                
		wchPrevious = wchCurrent;
                break;
            }

            pCharCode++;
        }
        
        // point back to start of character list in NTFM structure.

        pCharCode = pCharReset;

        // point to next character in mapping table.

        pmap++;
    }

    // allocate memory to build the FD_GLYPHSET structure in.  this
    // include space for the FD_GLYPHSET structure itself, as well
    // as space for all the glyph handles.

    cbTotalMem = (cGlyphs * sizeof(HGLYPH)) + (cRuns * sizeof(WCRUN)) +
		 sizeof(FD_GLYPHSET) - sizeof(WCRUN);

    // DWORD bound it.

    cbTotalMem = (cbTotalMem + 3) & ~3;

    // this memory is to be kept around until the pdev is destroyed, so
    // we don't have to free this memory until the heap is destroyed.

    phg = pulUCTree = (PVOID)HeapAlloc(pdev->hheap, 0, cbTotalMem);

    if (phg == NULL)
    {
	RIP("PSCRIPT!BuildGLYPHSET: HeapAlloc for phg failed.\n");
	return((PVOID)NULL);
    }

    // fill in the FD_GLYPHSET structure.

    pGLYPHSET = (FD_GLYPHSET *)phg;

    pGLYPHSET->cjThis = sizeof(FD_GLYPHSET) + (cRuns - 1) * sizeof(WCRUN);
    pGLYPHSET->flAccel = 0;		// no accelerators for us.
    pGLYPHSET->cGlyphsSupported = cGlyphs;
    pGLYPHSET->cRuns = cRuns;

    // now set the phg pointer to the first WCRUN structure.

    (BYTE *)phg += sizeof(FD_GLYPHSET) - sizeof(WCRUN);

    // point to first WCRUN in array.

    pWCRUN = (WCRUN *)phg;

    // point to data area for glyph handles.

    (BYTE *)phg += sizeof(WCRUN) * cRuns;

    // for every character in the font, do a lookup in the mapping
    // table in mapping.h to find the corresponding UNICODE value.
    // first point to the character codes in the NTFM structure.
    // remember that the character codes are sitting in a BYTE array
    // which is sitting directly after a (USHORT) array of character
    // widths.

    pCharCode = pCharReset;
    pmap = pmapReset;

    // locate the first glyph, and initialize the first WCRUN.

    for (i = 0; i < (DWORD)pntfm->cCharacters; i++)
    {
	// search for the matching code in mapping.h.	remember
	// that the high bit is used to indicate the font needs
	// to be remapped.  so ignore the high bit while checking
	// for a character match.

	if ((CHAR)*pCharCode == (CHAR)pmap->usPSValue)
	{
	    // we have found the character, now get its UNICODE value
	    // and set its BIT in the BIT array.  also, increment the
	    // glyph count, if this UNICODE value has not yet been used.
	    // since the mapping tables in mapping.h are sorted by
	    // UNICODE values, we can simply check this value against
	    // the one we found last time.  if it is the same, ignore
	    // it, if it is different, use it.

	    wchPrevious = (WCHAR)pmap->usUCValue;

	    pWCRUN->wcLow = wchPrevious;
	    pWCRUN->cGlyphs = 1;
	    pWCRUN->phg = phg;

	    // store the glyph handle, which we will store as the
	    // PostScript character code.

	    *phg++ = (HGLYPH)*pCharCode;

            break;
	}

        // point to the next character in the NTFM structure.

        pCharCode++;
    }

    // move to the second character in the mapping table.

    pmap++;

    while (pmap->szChar)
    {
        // reset pointer to start of character list in NTFM structure.
        
        pCharCode = pCharReset;

        for (i = 0; i < ((DWORD)pntfm->cCharacters - 1); i++)
        {
            // search for the matching code in mapping.h.  remember
            // that the high bit is used to indicate the font needs
            // to be remapped.  so ignore the high bit while checking
            // for a character match.

            if ((CHAR)*pCharCode == (CHAR)pmap->usPSValue)
            {
                // we have found the character, now get its UNICODE value
                // and set its BIT in the BIT array.  also, increment the
                // glyph count, if this UNICODE value has not yet been used.
                // since the mapping tables in mapping.h are sorted by
                // UNICODE values, we can simply check this value against
                // the one we found last time.  if it is the same, ignore 
                // it, if it is different, use it.

		wchCurrent = (WCHAR)pmap->usUCValue;

		if (wchCurrent != wchPrevious)
		{
		    // see if we are starting a new run.

		    if ((wchCurrent - wchPrevious) != 1)
		    {
			// start the new WCRUN.

			pWCRUN++;
			pWCRUN->wcLow = wchCurrent;
                        pWCRUN->cGlyphs = 0;
                        pWCRUN->phg = phg;
                    }

		    // fill in the glyph handle.

		    pWCRUN->cGlyphs++;
                    *phg++ = (HGLYPH)*pCharCode;
                }
                
		wchPrevious = wchCurrent;
                break;
            }

            pCharCode++;
        }

        // point to next character in mapping table.

        pmap++;
    }

    return(pulUCTree);
}


//--------------------------------------------------------------------------
// PVOID BuildKernPairs(pdev, iFace)
// PDEVDATA    pdev;
// ULONG       iFace;
//
//  This routine returns a pointer to a zero terminated array of
//  FD_KERNINGPAIR structures.  They should be sorted in order such that
//  the first character is the most significant, and the second character
//  is the least.
//
//   If an error occurs, NULL should be returned and an error code should 
//   be logged.
//
// History:
//   12-Mar-1992	  -by-	  Kent Settle	     (kentse)
// Wrote it.
//--------------------------------------------------------------------------

PVOID BuildKernPairs(pdev, iFace)
PDEVDATA    pdev;
ULONG	    iFace;
{
    PNTFM	    pntfm;          // pointer to font metrics.
    FD_KERNINGPAIR *pKernPairs;     // pointer to FD_KERNINGPAIRs.
    FD_KERNINGPAIR *pKernPairsSave; // pointer to FD_KERNINGPAIRs.
    DWORD           cjMem;          // count of bytes.
    DWORD           cKernPairs;     // cound of kernpairs.
    FD_KERNINGPAIR *pkp;            // pointer to kernpair in ntfm struct.

    // get the font information for the given font.

    pntfm = pdev->pfmtable[iFace - 1].pntfm;

    // allocate enough memory to hold all the FD_KERNINGPAIR strutures.
    // remember to allocate room for the zero terminated structure.
    // NOTE!  the memory allocated here is never explicitly freed.  this
    // will happen when the pdev, and therefore the heap, is destroyed.
    // this is done, since this memory is supposed to remain here for
    // the engine until the pdev is destroyed.

    cKernPairs = (DWORD)pntfm->cKernPairs;
    cjMem = ((cKernPairs + 1) * sizeof(FD_KERNINGPAIR));

    if (!(pKernPairs = (FD_KERNINGPAIR *)HeapAlloc(pdev->hheap, 0, cjMem)))
    {
        RIP("PSCRIPT!BuildKernPairs:  HeapAlloc for pKernPairs failed.\n");
        return((PVOID)NULL);
    }

    // save a copy of the original pointer.

    pKernPairsSave = pKernPairs;

    // fill in the FD_KERNINGPAIR structure for each kerning pair.

    pkp = (FD_KERNINGPAIR *)((BYTE *)pntfm + pntfm->loKernPairs);

    while (cKernPairs--)
        *pKernPairs++ = *pkp++;

    // fill in the zero terminating FD_KERNINGPAIR structure.

    pKernPairs->wcFirst = (WCHAR)'\0';
    pKernPairs->wcSecond = (WCHAR)'\0';
    pKernPairs->fwdKern = (FWORD)0;

    return(pKernPairsSave);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.