windows-nt/Source/XPSP1/NT/shell/osshell/fontfldr/ole2map/elsepan.c
2020-09-26 16:20:57 +08:00

1743 lines
53 KiB
C

/***************************************************************************
* ELSEPAN.C - ElseWare PANOSE(tm) 1.0 Font Mapper routines.
*
* $keywords: elsepan.c 1.5 19-Jul-93 11:15:09 AM$
*
* Copyright (C) 1991-93 ElseWare Corporation. All rights reserved.
***************************************************************************/
#define ELSE_MAPPER_CORE
#include <windows.h>
#include "elsepan.h"
/* Sanity check: this is the poor man's way to make sure the mapstate
* we get is valid. We init this value during startup and check it upon
* entry to every API routine.
*
* Note it is a good idea to modify SANITY_VALUE every time you make a
* significant change to the software just in case the mapper ends up
* in an environment where there may be multiple copies of it running,
* or if client software tries to save the mapstate (which is a no-no: it
* should use the API to get and set the exposed mapstate variables).
*/
#ifndef NOELSEWEIGHTS
#define SANITY_VALUE 0xD0CACA12L
#else
#define SANITY_VALUE 0xD0CACA13L
#endif
#define M_SANE(lpMapState) \
(((lpMapState) != NULL) && ((lpMapState)->ulSanity == SANITY_VALUE))
#define M_lpjOFFS(lpDB, lOffs) (((EW_LPBYTE)(lpDB)) + (lOffs))
#ifndef M_ELSEMEMCPY
#define ELSELOCALMEMCPY
#define M_ELSEMEMCPY(dst, src, len) s_lpPANMemCpy((dst), (src), (len))
LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANMemCpy
ELSEARGS (( EW_LPBYTE lpDst, EW_LPBYTE lpSrc, EW_USHORT unLen ));
#endif
LOCAL EW_LPPIND_MEM EW_NEAR EW_PASCAL s_lpPANGetIndRec
ELSEARGS (( EW_LPPDICT_MEM lpPDB, EW_LPBYTE EW_FAR *lplpPanWant,
EW_LPBYTE EW_FAR *lplpPanThis ));
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC0
ELSEARGS (( EW_LPPIND_MEM lpPanIndRec, EW_LPPTBL_C0_MEM lpPC0,
EW_LPUSHORT lpunMatch, EW_USHORT unTblSize, EW_USHORT unAttrA,
EW_USHORT unAttrB ));
LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC1
ELSEARGS (( EW_USHORT unAttrA, EW_USHORT unAttrB ));
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC2
ELSEARGS (( EW_LPPIND_MEM lpPanIndRec, EW_LPBYTE lpPTbl,
EW_LPUSHORT lpunMatch, EW_USHORT unTblSize,
EW_USHORT unAttrA, EW_USHORT unAttrB ));
LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC4
ELSEARGS (( EW_LPPTBL_C4_MEM lpPC4, EW_USHORT unAttrA,
EW_USHORT unAttrB ));
LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANGetWeights
ELSEARGS (( EW_LPMAPSTATE lpMapState, EW_LPPDICT_MEM lpPDB,
EW_LPPIND_MEM lpPanIndRec ));
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANMatchDigits
ELSEARGS (( EW_LPPDICT_MEM lpPDB, EW_LPUSHORT lpunMatchTotal,
EW_LPPIND_MEM lpPanIndRec, EW_LPPTBL_MEM lpPTblRec, EW_USHORT unWt,
EW_USHORT unAttrA, EW_USHORT unAttrB ));
/***************************************************************************
* FUNCTION: nPANMapInit
*
* PURPOSE: Initialize the font mapper. Fill in the default settings.
*
* RETURNS: Return the size of the map-state struct if successful, or
* the negative size if the passed in struct was too small.
* The function returns zero if it failed to initialize.
***************************************************************************/
EW_SHORT EW_FAR EW_PASCAL nPANMapInit( EW_LPMAPSTATE lpMapState,
EW_USHORT unSizeMapState)
{
EW_USHORT i;
EW_LPPDICT_MEM lpPDB;
EW_LPBYTE lpPanDef;
EW_LPBYTE lpjWtA;
EW_LPBYTE lpjWtB;
//
// Simple version check: make sure we got the right size struct.
//
if( unSizeMapState < sizeof( EW_MAPSTATE ) )
{
if( unSizeMapState >= sizeof( EW_ULONG ) )
{
lpMapState->ulSanity = 0L;
}
return( -(EW_SHORT) sizeof( EW_MAPSTATE ) );
}
lpMapState->ulSanity = 0L;
//
// Attempt to allocate the penalty database. We keep the handle
// until the mapper is disabled.
//
if( !( lpMapState->ulhPan1Data = M_lAllocPAN1DATA( ) ) )
{
goto errout0;
}
//
// Make sure the penalty database is the right version and
// in the right byte ordering.
//
if( !( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
{
goto errout1;
}
if( ( lpPDB->unVersion != PANOSE_PENALTY_VERS ) ||
( lpPDB->unByteOrder != PTBL_BYTE_ORDER ) )
{
goto errout2;
}
M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
//
// Fill in defaults.
//
lpMapState->unThreshold = ELSEDEFTHRESHOLD;
lpMapState->unRelaxThresholdCount = 0;
lpMapState->bUseDef = TRUE;
//
// Initial default font is the PANOSE number for Courier.
//
lpPanDef = lpMapState->ajPanDef;
lpPanDef[PAN_IND_FAMILY] = FAMILY_LATTEXT;
lpPanDef[PAN_IND_SERIF] = SERIF_THIN;
lpPanDef[PAN_IND_WEIGHT] = WEIGHT_THIN;
lpPanDef[PAN_IND_PROPORTION] = PROPORTION_MONOSPACE;
lpPanDef[PAN_IND_CONTRAST] = CONTRAST_NONE;
lpPanDef[PAN_IND_STROKE] = STROKE_GRADVERT;
lpPanDef[PAN_IND_ARMSTYLE] = ARM_STRAIGHTSGLSERIF;
lpPanDef[PAN_IND_LTRFORM] = LTRFORM_NORMCONTACT;
lpPanDef[PAN_IND_MIDLINE] = MIDLINE_STDSERIFED;
lpPanDef[PAN_IND_XHEIGHT] = XHEIGHT_CONSTLARGE;
#ifndef NOELSEWEIGHTS
//
// Initialize the custom weights array.
//
for( i = 0, lpjWtA = lpMapState->ajWtRefA,
lpjWtB = lpMapState->ajWtRefB;
i < MAX_CUSTOM_WEIGHTS;
++i, *lpjWtA++ = PANOSE_ANY, *lpjWtB++ = PANOSE_ANY)
;
#endif
//
// This value is checked by all other functions, in an attempt
// to safeguard against a mapstate that we didn't initialize.
//
lpMapState->ulSanity = SANITY_VALUE;
//
// Normal return.
//
return( sizeof( EW_MAPSTATE ) );
errout2:
M_bUnlockPAN1DATA(lpMapState->ulhPan1Data);
errout1:
M_bFreePAN1DATA(lpMapState->ulhPan1Data);
errout0:
return( 0 );
}
/***************************************************************************
* FUNCTION: bPANMapClose
*
* PURPOSE: Free the penalty database and close the font mapper. Also
* clear the sanity value so we will not service any more calls
* on this mapstate.
*
* RETURNS: The function returns TRUE if the penalty database is
* successfully freed.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANMapClose( EW_LPMAPSTATE lpMapState )
{
if( M_SANE( lpMapState ) )
{
lpMapState->ulSanity = 0L;
return( M_bFreePAN1DATA( lpMapState->ulhPan1Data ) );
}
return( FALSE );
}
#ifndef NOELSEPICKFONTS
/***************************************************************************
* FUNCTION: nPANGetMapDefault
*
* PURPOSE: Fill in the passed-in PANOSE number structure with the
* default font.
*
* RETURNS: Return 0 if the default number was not copied (passed-in
* structure too small), or NUM_PAN_DIGITS if it was.
***************************************************************************/
EW_SHORT EW_FAR EW_PASCAL nPANGetMapDefault( EW_LPMAPSTATE lpMapState,
EW_LPBYTE lpPanDef,
EW_USHORT unSizePanDef)
{
//
// Sanity checks.
//
if( !M_SANE( lpMapState ) || ( unSizePanDef < SIZE_PAN1_NUM ) )
{
return( 0 );
}
//
// Copy the number.
//
M_ELSEMEMCPY( lpPanDef, lpMapState->ajPanDef, SIZE_PAN1_NUM );
return( NUM_PAN_DIGITS );
}
/***************************************************************************
* FUNCTION: nPANSetMapDefault
*
* PURPOSE: Make the passed-in PANOSE number the new default font. There
* is no sanity checking on the number.
*
* RETURNS: Return 0 if the default number was not copied (passed-in
* structure too small), or NUM_PAN_DIGITS if it was.
***************************************************************************/
EW_SHORT EW_FAR EW_PASCAL nPANSetMapDefault( EW_LPMAPSTATE lpMapState,
EW_LPBYTE lpPanDef,
EW_USHORT unSizePanDef)
{
//
// Sanity checks.
//
if( !M_SANE( lpMapState ) || ( unSizePanDef < SIZE_PAN1_NUM ) )
{
return( 0 );
}
//
// Copy the number.
//
M_ELSEMEMCPY( lpMapState->ajPanDef, lpPanDef, SIZE_PAN1_NUM );
return( NUM_PAN_DIGITS );
}
/***************************************************************************
* FUNCTION: bPANEnableMapDefault
*
* PURPOSE: Enable/disable usage of the default font.
*
* RETURNS: Return the previous usage state, or FALSE in the event of
* an error.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANEnableMapDefault( EW_LPMAPSTATE lpMapState,
EW_BOOL bEnable)
{
if( M_SANE( lpMapState ) )
{
EW_BOOL bPrev = lpMapState->bUseDef;
lpMapState->bUseDef = bEnable;
return( bPrev );
}
else
{
return( FALSE );
}
}
/***************************************************************************
* FUNCTION: bPANIsDefaultEnabled
*
* PURPOSE: This function gets the state of using the default font.
*
* RETURNS: Return TRUE if usage of the default font is enabled, and
* FALSE if it is not or an error occurred.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANIsDefaultEnabled( EW_LPMAPSTATE lpMapState )
{
return( M_SANE( lpMapState ) && lpMapState->bUseDef );
}
#endif /* ifndef NOELSEPICKFONTS */
#ifndef NOELSETHRESHOLD
/***************************************************************************
* FUNCTION: unPANGetMapThreshold
*
* PURPOSE: This function gets the state of using threshold checking
* in the mapper.
*
* RETURNS: Return the match threshold, or zero if an error occurred.
***************************************************************************/
EW_USHORT EW_FAR EW_PASCAL unPANGetMapThreshold( EW_LPMAPSTATE lpMapState )
{
return( M_SANE( lpMapState ) ? lpMapState->unThreshold : 0 );
}
/***************************************************************************
* FUNCTION: bPANSetMapThreshold
*
* PURPOSE: Change the match threshold.
*
* RETURNS: Return TRUE if the threshold is changed, FALSE if it is
* equal to the match error value and therefore rejected, or
* an error occurred.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANSetMapThreshold( EW_LPMAPSTATE lpMapState,
EW_USHORT unThreshold)
{
//
// Cannot set a threshold equal to the error value.
//
if( !M_SANE( lpMapState ) || ( unThreshold == PAN_MATCH_ERROR ) )
{
return( FALSE );
}
//
// Set new threshold.
//
lpMapState->unThreshold = unThreshold;
return( TRUE );
}
/***************************************************************************
* FUNCTION: bPANIsThresholdRelaxed
*
* PURPOSE: This function gets the state of using the threshold in
* mapping.
*
* RETURNS: Return TRUE if the match threshold is relaxed, or FALSE if
* it is not or an error occurred.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANIsThresholdRelaxed( EW_LPMAPSTATE lpMapState )
{
return( M_SANE( lpMapState ) &&( lpMapState->unRelaxThresholdCount > 0 ) );
}
/***************************************************************************
* FUNCTION: vPANRelaxThreshold
*
* PURPOSE: Temporarily relax the threshold variable so every font
* except the erroneous ones will return a match value.
*
* RETURNS: Nothing.
***************************************************************************/
EW_VOID EW_FAR EW_PASCAL vPANRelaxThreshold( EW_LPMAPSTATE lpMapState )
{
if( M_SANE( lpMapState ) )
{
++lpMapState->unRelaxThresholdCount;
}
}
/***************************************************************************
* FUNCTION: bPANRestoreThreshold
*
* PURPOSE: Restore mapping within a threshold.
*
* RETURNS: Return TRUE if the threshold is back in effect or an error
* occurred, FALSE if someone else has relaxed it too so it
* still is relaxed. We return TRUE on error in the event someone
* rights a 'for' loop restoring until TRUE is returned.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANRestoreThreshold( EW_LPMAPSTATE lpMapState )
{
if( M_SANE( lpMapState ) &&( lpMapState->unRelaxThresholdCount > 0 ) )
{
return( --lpMapState->unRelaxThresholdCount == 0 );
}
else
{
return( TRUE );
}
}
#endif /* ifndef NOELSETHRESHOLD */
#ifndef NOELSEWEIGHTS
/***************************************************************************
* FUNCTION: bPANGetMapWeights
*
* PURPOSE: Retrieve the mapper weight values for the passed-in family
* digits pair. The variable *lpbIsCustom is set if custom
* mapper weights have been set by the caller.
*
* The weights array is an array of 10 bytes corresponding to
* the 10 PANOSE digits. The first weight is ignored (and usually
* set to zero) because we never actually assess a weighted
* penalty on the family digit. We include it so the index
* constants may be used to access the values in the weights
* array.
*
* RETURNS: Return TRUE if mapper weights were retrieved/available (it is
* legal for the caller to pass in NULL for lpjWts), or FALSE
* if none exist.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANGetMapWeights( EW_LPMAPSTATE lpMapState,
EW_BYTE jFamilyA,
EW_BYTE jFamilyB,
EW_LPBYTE lpjWts,
EW_LPBOOL lpbIsCustom)
{
EW_USHORT i;
EW_BOOL bFound = FALSE;
EW_LPPDICT_MEM lpPDB;
EW_LPPIND_MEM lpPanIndRec;
EW_LPBYTE lpjWtA;
EW_LPBYTE lpjWtB;
//
// Sanity test on the family digits.
//
if( !M_SANE( lpMapState ) ||
( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
{
return( FALSE );
}
//
// Search for custom weights.
//
for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
!bFound && ( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
++i, ++lpjWtA, ++lpjWtB)
{
//
// If custom weights are found then set *lpbIsCustom to
// TRUE, copy the weights, and return success.
//
if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
{
if( lpjWts )
{
M_ELSEMEMCPY( lpjWts,
&lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
SIZE_PAN1_NUM );
}
if( lpbIsCustom )
{
*lpbIsCustom = TRUE;
}
bFound = TRUE;
}
}
//
// No custom weights available. Search the penalty database
// for default weights.
//
if( !bFound && ( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
{
for( i = 0, lpPanIndRec = lpPDB->pind;
!bFound && ( i < lpPDB->unNumDicts );
++i, ++lpPanIndRec )
{
if( ( (lpPanIndRec->jFamilyA == jFamilyA ) &&
( lpPanIndRec->jFamilyB == jFamilyB ) ) ||
( (lpPanIndRec->jFamilyA == jFamilyB ) &&
( lpPanIndRec->jFamilyB == jFamilyA ) ) )
{
if( lpPanIndRec->unOffsWts )
{
if( lpjWts )
{
M_ELSEMEMCPY( lpjWts,
M_lpjOFFS( lpPDB, lpPanIndRec->unOffsWts ),
SIZE_PAN1_NUM );
}
if( lpbIsCustom )
{
*lpbIsCustom = FALSE;
}
bFound = TRUE;
}
}
}
M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
}
//
// Return the result of the search.
//
return( bFound );
}
/***************************************************************************
* FUNCTION: bPANSetMapWeights
*
* PURPOSE: Set the mapper weight values for the passed-in family
* digits pair.
*
* The weights array is an array of 10 bytes corresponding to
* the 10 PANOSE digits. The first weight is ignored (and usually
* set to zero) because we never actually assess a weighted
* penalty on the family digit. We include it so the index
* constants may be used to access the values in the weights
* array.
*
* RETURNS: Return TRUE if mapper weights were set, or FALSE if this
* family pair is not supported by the mapper or there is no
* more room for custom mapper weights.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANSetMapWeights( EW_LPMAPSTATE lpMapState,
EW_BYTE jFamilyA,
EW_BYTE jFamilyB,
EW_LPBYTE lpjWts )
{
EW_USHORT i;
EW_BOOL bFound;
EW_LPPDICT_MEM lpPDB;
EW_LPPIND_MEM lpPanIndRec;
EW_LPBYTE lpjWtA;
EW_LPBYTE lpjWtB;
EW_LPBYTE lpjWtFam;
//
// Sanity test on the family digits.
//
if( !M_SANE( lpMapState ) || !lpjWts ||
( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
{
return( FALSE );
}
//
// First make sure this family pair exists in the penalty
// database (it does not make sense to store penalties for
// a family pair we'll never map against).
//
if( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) )
{
for( i = 0, bFound = FALSE, lpPanIndRec = lpPDB->pind;
i < lpPDB->unNumDicts; ++i, ++lpPanIndRec)
{
if( ( (lpPanIndRec->jFamilyA == jFamilyA ) &&
( lpPanIndRec->jFamilyB == jFamilyB ) ) ||
( (lpPanIndRec->jFamilyA == jFamilyB ) &&
( lpPanIndRec->jFamilyB == jFamilyA ) ) )
{
bFound = TRUE;
break;
}
}
M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
if( !bFound )
{
return( FALSE );
}
}
else
{
return( FALSE );
}
//
// Search for an existing entry.
//
for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
++i, ++lpjWtA, ++lpjWtB)
{
if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
{
break;
}
}
//
// Abort if the weights were not found and there are no free slots.
//
if( i >= MAX_CUSTOM_WEIGHTS )
{
return( FALSE );
}
//
// We either found the previous weights or have a free slot,
// in both cases copy the passed-in weights. For aesthetics,
// preserve zero for the family weight( it is not used ).
//
*lpjWtA = jFamilyA;
*lpjWtB = jFamilyB;
M_ELSEMEMCPY( lpjWtFam = &lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
lpjWts, SIZE_PAN1_NUM);
*lpjWtFam = 0;
//
// Return success.
//
return( TRUE );
}
/***************************************************************************
* FUNCTION: bPANClearMapWeights
*
* PURPOSE: Locate the custom mapper weights for the passed-in family
* digit pair and clear them, thus causing the mapper to revert
* back to using the default weights.
*
* RETURNS: Return TRUE if custom mapper weights were located and cleared,
* FALSE if there are no custom weights for the passed-in family
* digit pair.
***************************************************************************/
EW_BOOL EW_FAR EW_PASCAL bPANClearMapWeights( EW_LPMAPSTATE lpMapState,
EW_BYTE jFamilyA,
EW_BYTE jFamilyB )
{
EW_USHORT i;
EW_USHORT j;
EW_LPBYTE lpjWtA;
EW_LPBYTE lpjWtB;
//
// Sanity test on the family digits.
//
if( !M_SANE( lpMapState ) ||
( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
{
return( FALSE );
}
//
// Search for custom weights.
//
for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
++i, ++lpjWtA, ++lpjWtB)
{
//
// If custom weights are found then overwrite them by
// shifting other weights forward in the array.
//
if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
{
for( j = i + 1, ++lpjWtA, ++lpjWtB;
( j < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
++j, ++lpjWtA, ++lpjWtB)
{
lpjWtA[-1] = *lpjWtA;
lpjWtB[-1] = *lpjWtB;
}
lpjWtA[-1] = PANOSE_ANY;
lpjWtB[-1] = PANOSE_ANY;
if( i < ( j - 1 ) )
{
M_ELSEMEMCPY( &lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
&lpMapState->ajCustomWt[SIZE_PAN1_NUM * (i + 1)],
( SIZE_PAN1_NUM * (j - i - 1 ) ) );
}
return( TRUE );
}
}
//
// Custom weights matching this family digit pair were not
// found, return failure.
//
return( FALSE );
}
#endif /* ifndef NOELSEWEIGHTS */
/***************************************************************************
* FUNCTION: unPANMatchFonts
*
* PURPOSE: Match two PANOSE numbers.
*
* RETURNS: Return a match value if the fonts are successfully compared
* and are within range of the threshold, otherwise return
* PAN_MATCH_ERROR if there is an error or the fonts are out
* of range.
***************************************************************************/
EW_USHORT EW_FAR EW_PASCAL unPANMatchFonts( EW_LPMAPSTATE lpMapState,
EW_LPBYTE lpPanWant,
EW_ULONG ulSizeWant,
EW_LPBYTE lpPanThis,
EW_ULONG ulSizeThis,
EW_BYTE jMapToFamily )
{
EW_USHORT unMatch = PAN_MATCH_ERROR;
EW_USHORT unThreshold;
EW_USHORT i;
EW_USHORT j;
EW_LPPDICT_MEM lpPDB;
EW_LPPIND_MEM lpPanIndRec;
EW_LPPTBL_MEM lpPTblRec;
EW_LPBYTE lpjWts;
EW_LPATOB_MEM lpAtoBHead;
EW_LPATOB_ITEM_MEM lpAtoB;
//
// Sanity check on the PANOSE numbers. Both numbers must be
// valid PANOSE 1.0 numbers, and the 'this'( compared-to )
// number must match the map-to family.
//
if( !M_SANE( lpMapState ) ||
( ulSizeWant != SIZE_PAN1_NUM ) || ( ulSizeThis != SIZE_PAN1_NUM ) ||
( lpPanWant[PAN_IND_FAMILY] <= PANOSE_NOFIT ) ||
( lpPanWant[PAN_IND_FAMILY] > MAX_PAN1_FAMILY ) ||
( lpPanThis[PAN_IND_FAMILY] <= PANOSE_NOFIT ) ||
( lpPanThis[PAN_IND_FAMILY] > MAX_PAN1_FAMILY ) ||
( lpPanThis[PAN_IND_FAMILY] != jMapToFamily ) )
{
goto backout0;
}
//
// Lock the penalty database.
//
if( !(lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
{
goto backout0;
}
//
// Locate the index entry that points to the dictionary containing
// the penalty tables for this PANOSE number.
// This routine may flip what lpPanWant and lpPanThis point to so
// we can guarantee the 'FamilyA' from the penalty tables is always
// associated with lpPanWant and 'FamilyB' is associated with
// lpPanThis.
//
// Optimization for unsupported families: If we do not support this
// family, but the numbers are identical, then return an 'exact match'
// value of zero. Otherwise return the usual match error value.
//
if( !(lpPanIndRec = s_lpPANGetIndRec(lpPDB, &lpPanWant, &lpPanThis ) ) )
{
for( i = 0; ( i < NUM_PAN_DIGITS ) && ( *lpPanWant == *lpPanThis ) &&
( *lpPanWant != PANOSE_NOFIT );
++i, ++lpPanWant, ++lpPanThis)
;
if( i >= NUM_PAN_DIGITS )
{
unMatch = 0;
}
goto backout1;
}
//
// Get the array of mapper weights -- this could be a custom array
// supplied by the user, or the default array from the penalty
// database.
//
if( !( lpjWts = s_lpPANGetWeights( lpMapState, lpPDB, lpPanIndRec ) ) )
{
goto backout1;
}
//
// If we are NOT supposed to do threshold testing then just set
// it to the maximum integer.
//
if( lpMapState->unRelaxThresholdCount > 0 )
{
unThreshold = ELSEMAXSHORT;
}
else
{
unThreshold = lpMapState->unThreshold;
}
//
// Index the penalty table array.
//
lpPTblRec = (EW_LPPTBL_MEM) M_lpjOFFS( lpPDB, lpPanIndRec->unOffsPTbl );
//
// There are two flavors of walking the digits:
//
// 1. For cross-family matching, we walk an array of indices mapping
// digits from one family to the digits of another.
// 2. For normal( same family ) matching, we directly walk the digits.
//
// Test for an a-to-b array( cross-family matching ).
//
if( lpPanIndRec->unOffsAtoB )
{
//
// This is a cross-family mapping, get the a-to-b array head.
//
lpAtoBHead = (EW_LPATOB_MEM) M_lpjOFFS( lpPDB, lpPanIndRec->unOffsAtoB );
//
// Walk the a-to-b array.
//
for( i = unMatch = 0, j = lpAtoBHead->unNumAtoB,
lpAtoB = lpAtoBHead->AtoBItem;
i < j;
++i, ++lpPTblRec, ++lpjWts, ++lpAtoB)
{
//
// Compare the two digits. Abort if the test fails or the
// accumulated match value is greater than the threshold.
//
if( !s_bPANMatchDigits( lpPDB, &unMatch, lpPanIndRec,
lpPTblRec, *lpjWts, lpPanWant[lpAtoB->jAttrA],
lpPanThis[lpAtoB->jAttrB]) ||
( unMatch > unThreshold ) )
{
unMatch = PAN_MATCH_ERROR;
goto backout1;
}
}
}
else
{
//
// Normal match: comparing PANOSE numbers from the same
// families. Walk the digits accumulating the match result.
//
for( i = unMatch = 0, ++lpPanWant, ++lpPanThis;
i <( NUM_PAN_DIGITS - 1 );
++i, ++lpPTblRec, ++lpjWts, ++lpPanWant, ++lpPanThis )
{
//
// Compare the two digits. Abort if the test fails or the
// accumulated match value is greater than the threshold.
//
if( !s_bPANMatchDigits( lpPDB, &unMatch, lpPanIndRec,
lpPTblRec, *lpjWts, *lpPanWant, *lpPanThis) ||
( unMatch > unThreshold ) )
{
unMatch = PAN_MATCH_ERROR;
goto backout1;
}
}
}
//
// Return the match value. If it was out of range or an error
// occurred, then it will equal PAN_MATCH_ERROR.
//
backout1:
M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
backout0:
return( unMatch );
}
#ifndef NOELSEPICKFONTS
/***************************************************************************
* FUNCTION: unPANPickFonts
*
* PURPOSE: Walk an array of fonts ordering them by the closest to the
* requested font. If no font is within range of the threshold
* then look for the closest to the default font. If still
* no font is found then just pick the first font in the list.
*
* Implementation note: This proc assumes PANOSE 1.0 numbers.
* A future version of this proc will accept intermixed PANOSE
* 1.0 and 2.0 numbers, and will call a callback routine to
* supply each record, instead of presuming it can walk an
* array of fixed-length records.
*
* RETURNS: Return the number of fonts found to match the requested
* font, or zero if unNumInds == 0 or an error ocurred.
*
* If no close match was found but the default font is enabled,
* then one is returned and *lpMatchValues == PAN_MATCH_ERROR.
*
* If no suitable match was found and the default font is
* disabled, then zero is returned.
***************************************************************************/
EW_USHORT EW_FAR EW_PASCAL unPANPickFonts( EW_LPMAPSTATE lpMapState,
EW_LPUSHORT lpIndsBest,
EW_LPUSHORT lpMatchValues,
EW_LPBYTE lpPanWant,
EW_USHORT unNumInds,
EW_LPBYTE lpPanFirst,
EW_USHORT unNumAvail,
EW_SHORT nRecSize,
EW_BYTE jMapToFamily )
{
EW_USHORT i;
EW_USHORT j;
EW_USHORT k;
EW_USHORT unNumFound = 0;
EW_USHORT unMatchValue;
EW_USHORT unSavedThreshold;
EW_LPUSHORT lpMatches;
EW_LPUSHORT lpInds;
EW_LPBYTE lpPanThis;
//
// Sanity check.
//
if( !M_SANE( lpMapState ) || ( unNumInds == 0 ) || ( unNumAvail == 0 ) ||
( (nRecSize < 0 ) &&( nRecSize > -(EW_SHORT )SIZE_PAN1_NUM) ) ||
( (nRecSize > 0 ) &&( nRecSize < (EW_SHORT )SIZE_PAN1_NUM) ) )
{
return( 0 );
}
//
// This routine implements a 'quit early' algorithm by modifying
// the threshold to the worst acceptable value in the list (once
// the list is full). This has the effect of causing matchfonts
// to abort & return PAN_MATCH_ERROR whenever a penalty exceeds
// the threshold.
//
unSavedThreshold = lpMapState->unThreshold;
//
// Walk the PANOSE numbers ordering them from best to worst
// match. Walk the array with a byte pointer, advancing by
// the passed-in record size.
//
for( i = 0, lpPanThis = lpPanFirst; i < unNumAvail;
++i, lpPanThis += nRecSize)
{
//
// Get the match value.
//
if( ( unMatchValue = unPANMatchFonts( lpMapState,
lpPanWant, SIZE_PAN1_NUM, lpPanThis, SIZE_PAN1_NUM,
jMapToFamily ) ) != PAN_MATCH_ERROR )
{
//
// Find the slot in the array where this match value
// should reside.
//
for( j = 0, lpMatches = lpMatchValues;
( j < unNumFound ) &&( *lpMatches < unMatchValue );
++j, ++lpMatches)
;
//
// If this match value is better than one of the matches
// already in the array, then insert it. Notice that
// until the array is full everything goes in it. After
// that, we shuffle less close matches off the end.
//
if( j < unNumInds )
{
if( unNumFound < unNumInds )
{
++unNumFound;
}
for( lpInds = &lpIndsBest[k = unNumFound - 1],
lpMatches = &lpMatchValues[k];
k > j;
lpInds[0] = lpInds[-1], lpMatches[0] = lpMatches[-1],
--k, --lpInds, --lpMatches)
;
*lpInds = i;
*lpMatches = unMatchValue;
//
// If the list is full, then set the threshold equal
// to the last match value in the list. The matchfonts
// routine will abort & return PAN_MATCH_ERROR on any
// match greater than this value.
//
// Also, if the last value in the list is zero (exact
// match), then exit the loop because the list will
// not change.
//
if( unNumFound == unNumInds )
{
if( (k = lpMatchValues[unNumFound - 1] ) == 0)
{
break;
}
lpMapState->unThreshold = k;
}
}
}
}
//
// If no acceptable match was found, then attempt to find a match
// for the default font. We temporarily step off the threshold
// so we will definitely find something. At this point, we do
// not care if the default is not within the threshold, we just
// want to find it.
//
if( !unNumFound && lpMapState->bUseDef )
{
lpMapState->unThreshold = ELSEMAXSHORT;
for( i = 0, lpPanThis = lpPanFirst; i < unNumAvail;
++i, lpPanThis += nRecSize)
{
if( ( unMatchValue = unPANMatchFonts( lpMapState,
lpMapState->ajPanDef, SIZE_PAN1_NUM, lpPanThis, SIZE_PAN1_NUM,
lpMapState->ajPanDef[PAN_IND_FAMILY] ) ) != PAN_MATCH_ERROR )
{
if( unNumFound == 0 )
{
*lpIndsBest = i;
lpMapState->unThreshold = *lpMatchValues = unMatchValue;
++unNumFound;
}
else if( unMatchValue < *lpMatchValues )
{
*lpIndsBest = i;
lpMapState->unThreshold = *lpMatchValues = unMatchValue;
}
}
}
//
// We flag this match with the error so the caller can
// determine that the default font was substituted.
//
if( unNumFound > 0 )
{
*lpMatchValues = PAN_MATCH_ERROR;
}
}
//
// Restore the threshold.
//
lpMapState->unThreshold = unSavedThreshold;
//
// If still no match is found then just pick the first font.
//
if( !unNumFound )
{
*lpIndsBest = 0;
*lpMatchValues = PAN_MATCH_ERROR;
++unNumFound;
}
//
// Return the number of fonts found. It will be zero if we
// encountered an error or couldn't find a suitable match.
//
return( unNumFound );
}
#endif /* ifndef NOELSEPICKFONTS */
/***************************************************************************
* FUNCTION: vPANMakeDummy
*
* PURPOSE: Build a dummy PANOSE number with all attributes set to
* PANOSE_NOFIT.
*
* RETURNS: Nothing.
***************************************************************************/
EW_VOID EW_FAR EW_PASCAL vPANMakeDummy( EW_LPBYTE lpPanThis,
EW_USHORT unSize )
{
EW_USHORT i;
EW_USHORT j;
unSize /= sizeof( EW_BYTE );
for( i = j = 0; (i < NUM_PAN_DIGITS ) &&( j < unSize );
++i, j += sizeof( EW_BYTE ), *lpPanThis++ = PANOSE_NOFIT)
;
}
/***************************************************************************/
/************************** LOCAL SERVICE ROUTINES *************************/
/***************************************************************************/
/***************************************************************************
* FUNCTION: s_lpPANGetIndRec
*
* PURPOSE: Search the header of the database looking for a dictionary
* of penalty tables designed for this family pair.
*
* There is a similar search for the index rec in the routine
* bPANGetMapWeights. If you make a change here, also check in
* that routine.
*
* RETURNS: Return the pointer to the index record if a match is found,
* or NULL if one is not.
***************************************************************************/
LOCAL EW_LPPIND_MEM EW_NEAR EW_PASCAL s_lpPANGetIndRec(
EW_LPPDICT_MEM lpPDB,
EW_LPBYTE EW_FAR *lplpPanWant,
EW_LPBYTE EW_FAR *lplpPanThis )
{
EW_USHORT i;
EW_BYTE jFamilyA =( *lplpPanWant )[PAN_IND_FAMILY];
EW_BYTE jFamilyB =( *lplpPanThis )[PAN_IND_FAMILY];
EW_LPBYTE lpPanSwitch;
EW_LPPIND_MEM lpPanIndRec;
//
// Walk the index array in the penalty database looking for
// a matching family pair.
//
for( i = 0, lpPanIndRec = lpPDB->pind; i < lpPDB->unNumDicts;
++i, ++lpPanIndRec)
{
if( ( lpPanIndRec->jFamilyA == jFamilyA ) &&
( lpPanIndRec->jFamilyB == jFamilyB ) )
{
//
// Straight match. Return the index.
//
return( lpPanIndRec );
}
else if( ( lpPanIndRec->jFamilyA == jFamilyB ) &&
( lpPanIndRec->jFamilyB == jFamilyA ) )
{
//
// There is a match but the families are swapped. Swap
// the PANOSE numbers to match the order in the penalty
// database in the event it contains tables that are
// order-dependent (this can happen with cross-family
// mapping, C0-style/uncompressed/non-symmetric tables).
//
lpPanSwitch = *lplpPanWant;
*lplpPanWant = *lplpPanThis;
*lplpPanThis = lpPanSwitch;
return( lpPanIndRec );
}
}
//
// No match found, return an error.
//
return( NULL );
}
/***************************************************************************
* FUNCTION: s_bPANGetPenaltyC0
*
* PURPOSE: Compute the penalty between two PANOSE digits using 'C0'
* compression, where the entire table is provided (except
* the any and no-fit rows and columns).
*
* RETURNS: Return TRUE if the computed index is within range, and
* *lpunMatch is filled in with the penalty value, FALSE if
* it is out of range.
***************************************************************************/
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC0( EW_LPPIND_MEM lpPanIndRec,
EW_LPPTBL_C0_MEM lpPC0,
EW_LPUSHORT lpunMatch,
EW_USHORT unTblSize,
EW_USHORT unAttrA,
EW_USHORT unAttrB )
{
EW_USHORT unInd;
//
// Make sure each value is within range. Notice this may
// be a non-square table.
//
if( ( unAttrA > lpPC0->jARangeLast ) ||( unAttrB > lpPC0->jBRangeLast ) )
{
*lpunMatch = lpPanIndRec->jDefNoFitPenalty;
return( FALSE );
}
//
// Compute the table index.
//
if( ( unInd = ( (unAttrA - 2 ) *(lpPC0->jBRangeLast - 1 ) )
+ unAttrB - 2) >= unTblSize )
{
*lpunMatch = lpPanIndRec->jDefNoFitPenalty;
return( FALSE );
}
//
// Get the penalty.
//
*lpunMatch = lpPC0->jPenalties[unInd];
return( TRUE );
}
/***************************************************************************
* FUNCTION: s_unPANGetPenaltyC1
*
* PURPOSE: Compute the penalty between two PANOSE digits using 'C1'
* compression, which is a perfectly symmetrical table around
* the diagonal. Two digits on the diagonal are an exact match.
* A difference of 1 yields a penalty of 1, a difference of 2
* yields a penalty of 2, and so on.
*
* It is assumed the caller handled any, no-fit, and exact
* matches.
*
* RETURNS: Return the penalty from the table, the function cannot fail.
***************************************************************************/
LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC1( EW_USHORT unAttrA,
EW_USHORT unAttrB )
{
EW_SHORT nDiff;
//
// Compute the penalty, which is simply the absolute value
// of the difference between the two numbers.
//
if( ( nDiff = (EW_SHORT) unAttrA - (EW_SHORT) unAttrB ) < 0 )
{
nDiff = -nDiff;
}
return( nDiff );
}
/***************************************************************************
* FUNCTION: s_bPANGetPenaltyC2
*
* PURPOSE: Compute the penalty between two PANOSE digits using 'C2'
* compression, which is a table symmetrical about the
* diagonal, but not a smooth range from low to high, so the
* lower left corner of the table is provided. The unAttrA
* digit references the row and unAttrB references the column.
*
* It is assumed the caller handled any, no-fit, and exact
* matches.
*
* RETURNS: Return TRUE if the computed index is within range, and
* *lpunMatch is filled in with the penalty value, FALSE if
* it is out of range.
***************************************************************************/
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC2( EW_LPPIND_MEM lpPanIndRec,
EW_LPBYTE lpPTbl,
EW_LPUSHORT lpunMatch,
EW_USHORT unTblSize,
EW_USHORT unAttrA,
EW_USHORT unAttrB )
{
EW_USHORT unSwap;
EW_SHORT nInd;
//
// The formula we use assumes the lower left half of the
// penalty table, which means row > column. The table is
// symmetric about the diagonal, so if row < column we can
// just switch their values.
//
if( unAttrA < unAttrB )
{
unSwap = unAttrA;
unAttrA = unAttrB;
unAttrB = unSwap;
}
//
// The table is missing the any, no-fit, and exact match
// penalties as those are handled separately. Since the
// table is triangular shaped, we use the additive series
// to compute the row:
//
// n + ... + 3 + 2 + 1 == 1/2 * n *( n + 1 )
//
// Substituting n for row - 3, the first possible row, and
// adding the column offset, we get the following formula:
//
// ( 1/2 * (row - 3 ) *( row - 2 ) ) +( col - 2 )
//
// We know that row >= 3 and col >= 2 as we catch the other
// cases above.
//
if( ( nInd = M_ELSEMULDIV( unAttrA - 3, unAttrA - 2, 2 ) +
(EW_SHORT) unAttrB - 2) >= (EW_SHORT) unTblSize )
{
*lpunMatch = lpPanIndRec->jDefNoFitPenalty;
return( FALSE );
}
*lpunMatch = lpPTbl[nInd];
return( TRUE );
}
/***************************************************************************
* FUNCTION: s_unPANGetPenaltyC4
*
* PURPOSE: Compute the penalty between two PANOSE digits using 'C4'
* compression, which is almost identical to 'C1' compression
* except a start and increment value are supplied.
*
* It is assumed the caller handled any, no-fit, and exact
* matches.
*
* RETURNS: Return the penalty from the table, the function cannot fail.
***************************************************************************/
LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC4( EW_LPPTBL_C4_MEM lpPC4,
EW_USHORT unAttrA,
EW_USHORT unAttrB )
{
EW_SHORT nDiff;
//
// First compute the absolute value of the difference
// between the two numbers.
//
if( (nDiff = (EW_SHORT )unAttrA -( EW_SHORT )unAttrB) < 0)
{
nDiff = -nDiff;
}
//
// Then scale by the increment and start values.
//
if( nDiff > 0 )
{
nDiff = ( ( nDiff - 1 ) *(EW_SHORT) lpPC4->jIncrement ) +
(EW_SHORT) lpPC4->jStart;
}
return( nDiff );
}
/***************************************************************************
* FUNCTION: s_lpPANGetWeights
*
* PURPOSE: Check the mapstate record for a set of user-supplied custom
* weights. If none are present, then use the default weights
* from the mapping table.
*
* RETURNS: Return the pointer to the array of weight values.
***************************************************************************/
LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANGetWeights( EW_LPMAPSTATE lpMapState,
EW_LPPDICT_MEM lpPDB,
EW_LPPIND_MEM lpPanIndRec )
{
EW_USHORT i;
EW_LPBYTE lpjWtA;
EW_LPBYTE lpjWtB;
EW_BYTE jFamilyA = lpPanIndRec->jFamilyA;
EW_BYTE jFamilyB = lpPanIndRec->jFamilyB;
#ifndef NOELSEWEIGHTS
//
// Search for custom weights.
//
for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
++i, ++lpjWtA, ++lpjWtB )
{
//
// If custom weights are found then return a pointer into
// the mapstate struct. We store a weight value for the family
// digit but do not use it. The pointer points to the first
// digit after the family digit.
//
if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
{
return( &lpMapState->ajCustomWt[ ( SIZE_PAN1_NUM * i ) + 1] );
}
}
#endif
//
// If no custom weights were found then return the default
// weight from the penalty database.
//
if( lpPanIndRec->unOffsWts )
{
return( M_lpjOFFS(lpPDB, lpPanIndRec->unOffsWts + 1 ) );
}
else
{
return( NULL );
}
}
/***************************************************************************
* FUNCTION: s_bPANMatchDigits
*
* PURPOSE: Compute the match value between two PANOSE digits and add
* it to the passed in match total.
*
* RETURNS: Return TRUE if the match value is computed and added to
* *lpunMatchTotal. If an error occurs, return FALSE and
* set *lpunMatchTotal to the value PAN_MATCH_ERROR.
***************************************************************************/
LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANMatchDigits( EW_LPPDICT_MEM lpPDB,
EW_LPUSHORT lpunMatchTotal,
EW_LPPIND_MEM lpPanIndRec,
EW_LPPTBL_MEM lpPTblRec,
EW_USHORT unWt,
EW_USHORT unAttrA,
EW_USHORT unAttrB )
{
EW_USHORT unLast = lpPTblRec->jRangeLast;
EW_USHORT unMatch;
//
// First make sure the digit values are not out of range.
//
if( (unAttrA > unLast ) ||( unAttrB > unLast ) )
{
goto errout;
}
//
// Special case no-fit, any, or exact matches.
//
if( ( unAttrA == PANOSE_NOFIT ) || ( unAttrB == PANOSE_NOFIT ) )
{
if( lpPTblRec->jCompress != PAN_COMPRESS_C3 )
{
*lpunMatchTotal += lpPanIndRec->jDefNoFitPenalty * unWt;
return( TRUE );
}
}
else if( ( unAttrA == PANOSE_ANY ) || ( unAttrB == PANOSE_ANY ) )
{
*lpunMatchTotal += lpPanIndRec->jDefAnyPenalty * unWt;
return( TRUE );
}
else if( (unAttrA == unAttrB ) &&
( lpPTblRec->jCompress != PAN_COMPRESS_C0 ) )
{
*lpunMatchTotal += lpPanIndRec->jDefMatchPenalty * unWt;
return( TRUE );
}
//
// Compute the penalty depending on the kind of compression
// used for the table.
//
switch( lpPTblRec->jCompress )
{
case PAN_COMPRESS_C0:
if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize
|| !s_bPANGetPenaltyC0( lpPanIndRec,
(EW_LPPTBL_C0_MEM) M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ),
&unMatch, lpPTblRec->unTblSize, unAttrA, unAttrB ) )
{
goto errout;
}
*lpunMatchTotal += unMatch * unWt;
break;
case PAN_COMPRESS_C1:
*lpunMatchTotal += s_unPANGetPenaltyC1( unAttrA, unAttrB ) * unWt;
break;
case PAN_COMPRESS_C2:
if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize ||
!s_bPANGetPenaltyC2( lpPanIndRec,
M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ), &unMatch,
lpPTblRec->unTblSize, unAttrA, unAttrB ) )
{
goto errout;
}
*lpunMatchTotal += unMatch * unWt;
break;
case PAN_COMPRESS_C3:
if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize )
{
goto errout;
}
if( ( unAttrA == PANOSE_NOFIT ) || ( unAttrB == PANOSE_NOFIT ) )
{
unMatch = *M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl );
}
else if( !s_bPANGetPenaltyC2( lpPanIndRec,
M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl + 1 ), &unMatch,
(EW_USHORT) ( lpPTblRec->unTblSize - 1 ),
unAttrA, unAttrB ) )
{
goto errout;
}
*lpunMatchTotal += unMatch * unWt;
break;
case PAN_COMPRESS_C4:
if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize )
{
goto errout;
}
*lpunMatchTotal += s_unPANGetPenaltyC4(
(EW_LPPTBL_C4_MEM) M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ),
unAttrA, unAttrB) * unWt;
break;
}
//
// Match computed, successful return.
//
return( TRUE );
//
// An error occurred, return FALSE.
//
errout:
*lpunMatchTotal = PAN_MATCH_ERROR;
return( FALSE );
}
/***************************************************************************
* FUNCTION: s_lpPANMemCpy
*
* PURPOSE: Perform a memcpy operation.
*
* RETURNS: The function returns lpDst.
***************************************************************************/
#ifdef ELSELOCALMEMCPY
LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANMemCpy( EW_LPBYTE lpDst,
EW_LPBYTE lpSrc,
EW_USHORT unLen)
{
EW_LPBYTE lpRet = lpDst;
EW_USHORT i;
for( i = 0; i < unLen; ++i, *lpDst++ = *lpSrc++ )
;
return( lpRet );
}
#endif
/***************************************************************************
* Revision log:
*
* 31-Jan-93 msd PANOSE 1.0 mapper: 10-digit PANOSE.
* 2-Feb-93 msd Removed huge pointer stuff.
* 3-Feb-93 msd Removed ctrl-z at EOF. Added 'unused' pragmas.
* 3-Feb-93 msd Fixed bug caused by vcs check-in.
* 14-Feb-93 msd Removed extra restore-threshold call in pickfonts.
* 15-Feb-93 msd For extra security, bumped the sanity value from
* word to a long.
***************************************************************************/
/*
* $lgb$
* 1.0 17-Feb-93 msd New module created because of vcs problems.
* 1.1 17-Feb-93 msd Small doc change.
* 1.2 18-Feb-93 msd Added penalty table byte-ordering check, and C4 ptbl compression( new version of ptbl ). Modified internal routines so 'unused' pragmas are not necessary. Use EW_FAR.
* 1.3 23-Feb-93 msd On close session, kill the sanity value so subsequent mapper calls will fail.
* 1.4 25-Feb-93 msd Modified the default font search logic in pickfonts -- search by the default font's family, not by the requested family. Also use M_ELSEMEMCPY() in a few more places.
* 1.5 19-Jul-93 msd Added compilation flags to selectively disable mapper routines.
* $lge$
*/