|  | /* | 
|  | *	Font metric functions common to Type 1 (AFM) and TrueType font files. | 
|  | *  	Functions specific to Type 1 and TrueType fonts are in type1afm.c and | 
|  | *  	truetype.c respectively. | 
|  | * | 
|  | *	Copyright 1998  Huw D M Davies | 
|  | *  	Copyright 2001  Ian Pilcher | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | #include "psdrv.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(psdrv); | 
|  |  | 
|  | /* ptr to fonts for which we have afm files */ | 
|  | DECLSPEC_HIDDEN FONTFAMILY *PSDRV_AFMFontList = NULL; | 
|  |  | 
|  |  | 
|  | /*********************************************************** | 
|  | * | 
|  | *	PSDRV_FreeAFMList | 
|  | * | 
|  | * Frees the family and afmlistentry structures in list head | 
|  | */ | 
|  | void PSDRV_FreeAFMList( FONTFAMILY *head ) | 
|  | { | 
|  | AFMLISTENTRY *afmle, *nexta; | 
|  | FONTFAMILY *family, *nextf; | 
|  |  | 
|  | for(nextf = family = head; nextf; family = nextf) { | 
|  | for(nexta = afmle = family->afmlist; nexta; afmle = nexta) { | 
|  | nexta = afmle->next; | 
|  | HeapFree( PSDRV_Heap, 0, afmle ); | 
|  | } | 
|  | nextf = family->next; | 
|  | HeapFree( PSDRV_Heap, 0, family ); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************** | 
|  | * | 
|  | *	PSDRV_FindAFMinList | 
|  | * Returns ptr to an AFM if name (which is a PS font name) exists in list | 
|  | * headed by head. | 
|  | */ | 
|  | const AFM *PSDRV_FindAFMinList(FONTFAMILY *head, LPCSTR name) | 
|  | { | 
|  | FONTFAMILY *family; | 
|  | AFMLISTENTRY *afmle; | 
|  |  | 
|  | for(family = head; family; family = family->next) { | 
|  | for(afmle = family->afmlist; afmle; afmle = afmle->next) { | 
|  | if(!strcmp(afmle->afm->FontName, name)) | 
|  | return afmle->afm; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /*********************************************************** | 
|  | * | 
|  | *	PSDRV_AddAFMtoList | 
|  | * | 
|  | *  Adds an afm to the list whose head is pointed to by head. Creates new | 
|  | *  family node if necessary and always creates a new AFMLISTENTRY. | 
|  | * | 
|  | *  Returns FALSE for memory allocation error; returns TRUE, but sets *p_added | 
|  | *  to FALSE, for duplicate. | 
|  | */ | 
|  | BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm, BOOL *p_added) | 
|  | { | 
|  | FONTFAMILY *family = *head; | 
|  | FONTFAMILY **insert = head; | 
|  | AFMLISTENTRY *tmpafmle, *newafmle; | 
|  |  | 
|  | newafmle = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, | 
|  | sizeof(*newafmle)); | 
|  | if (newafmle == NULL) | 
|  | return FALSE; | 
|  |  | 
|  | newafmle->afm = afm; | 
|  |  | 
|  | while(family) { | 
|  | if(!strcmp(family->FamilyName, afm->FamilyName)) | 
|  | break; | 
|  | insert = &(family->next); | 
|  | family = family->next; | 
|  | } | 
|  |  | 
|  | if(!family) { | 
|  | family = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, | 
|  | sizeof(*family)); | 
|  | if (family == NULL) { | 
|  | HeapFree(PSDRV_Heap, 0, newafmle); | 
|  | return FALSE; | 
|  | } | 
|  | *insert = family; | 
|  | if (!(family->FamilyName = HeapAlloc(PSDRV_Heap, 0, strlen(afm->FamilyName)+1 ))) { | 
|  | HeapFree(PSDRV_Heap, 0, family); | 
|  | HeapFree(PSDRV_Heap, 0, newafmle); | 
|  | return FALSE; | 
|  | } | 
|  | strcpy( family->FamilyName, afm->FamilyName ); | 
|  | family->afmlist = newafmle; | 
|  | *p_added = TRUE; | 
|  | return TRUE; | 
|  | } | 
|  | else { | 
|  | tmpafmle = family->afmlist; | 
|  | while (tmpafmle) { | 
|  | if (!strcmp(tmpafmle->afm->FontName, afm->FontName)) { | 
|  | WARN("Ignoring duplicate FontName '%s'\n", afm->FontName); | 
|  | HeapFree(PSDRV_Heap, 0, newafmle); | 
|  | *p_added = FALSE; | 
|  | return TRUE;	    	    	    /* not a fatal error */ | 
|  | } | 
|  | tmpafmle = tmpafmle->next; | 
|  | } | 
|  | } | 
|  |  | 
|  | tmpafmle = family->afmlist; | 
|  | while(tmpafmle->next) | 
|  | tmpafmle = tmpafmle->next; | 
|  |  | 
|  | tmpafmle->next = newafmle; | 
|  |  | 
|  | *p_added = TRUE; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************** | 
|  | * | 
|  | *	PSDRV_DumpFontList | 
|  | * | 
|  | */ | 
|  | static void PSDRV_DumpFontList(void) | 
|  | { | 
|  | FONTFAMILY      *family; | 
|  | AFMLISTENTRY    *afmle; | 
|  |  | 
|  | for(family = PSDRV_AFMFontList; family; family = family->next) { | 
|  | TRACE("Family '%s'\n", family->FamilyName); | 
|  | for(afmle = family->afmlist; afmle; afmle = afmle->next) | 
|  | { | 
|  | #if 0 | 
|  | INT i; | 
|  | #endif | 
|  |  | 
|  | TRACE("\tFontName '%s' (%i glyphs) - '%s' encoding:\n", | 
|  | afmle->afm->FontName, afmle->afm->NumofMetrics, | 
|  | afmle->afm->EncodingScheme); | 
|  |  | 
|  | /* Uncomment to regenerate font data; see afm2c.c */ | 
|  |  | 
|  | /* PSDRV_AFM2C(afmle->afm); */ | 
|  |  | 
|  | #if 0 | 
|  | for (i = 0; i < afmle->afm->NumofMetrics; ++i) | 
|  | { | 
|  | TRACE("\t\tU+%.4lX; C %i; N '%s'\n", afmle->afm->Metrics[i].UV, | 
|  | afmle->afm->Metrics[i].C, afmle->afm->Metrics[i].N->sz); | 
|  | } | 
|  | #endif | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | *  PSDRV_CalcAvgCharWidth | 
|  | * | 
|  | *  Calculate WinMetrics.sAvgCharWidth for a Type 1 font.  Can also be used on | 
|  | *  TrueType fonts, if font designer set OS/2:xAvgCharWidth to zero. | 
|  | * | 
|  | *  Tries to use formula in TrueType specification; falls back to simple mean | 
|  | *  if any lowercase latin letter (or space) is not present. | 
|  | */ | 
|  | static inline SHORT MeanCharWidth(const AFM *afm) | 
|  | { | 
|  | float   w = 0.0; | 
|  | int     i; | 
|  |  | 
|  | for (i = 0; i < afm->NumofMetrics; ++i) | 
|  | w += afm->Metrics[i].WX; | 
|  |  | 
|  | w /= afm->NumofMetrics; | 
|  |  | 
|  | return (SHORT)(w + 0.5); | 
|  | } | 
|  |  | 
|  | static const struct { LONG UV; int weight; } UVweight[27] = | 
|  | { | 
|  | { 0x0061,  64 }, { 0x0062,  14 }, { 0x0063,  27 }, { 0x0064,  35 }, | 
|  | { 0x0065, 100 }, { 0x0066,  20 }, { 0x0067,  14 }, { 0x0068,  42 }, | 
|  | { 0x0069,  63 }, { 0x006a,   3 }, { 0x006b,   6 }, { 0x006c,  35 }, | 
|  | { 0x006d,  20 }, { 0x006e,  56 }, { 0x006f,  56 }, { 0x0070,  17 }, | 
|  | { 0x0071,   4 }, { 0x0072,  49 }, { 0x0073,  56 }, { 0x0074,  71 }, | 
|  | { 0x0075,  31 }, { 0x0076,  10 }, { 0x0077,  18 }, { 0x0078,   3 }, | 
|  | { 0x0079,  18 }, { 0x007a,   2 }, { 0x0020, 166 } | 
|  | }; | 
|  |  | 
|  | SHORT PSDRV_CalcAvgCharWidth(const AFM *afm) | 
|  | { | 
|  | float   w = 0.0; | 
|  | int     i; | 
|  |  | 
|  | for (i = 0; i < 27; ++i) | 
|  | { | 
|  | const AFMMETRICS    *afmm; | 
|  |  | 
|  | afmm = PSDRV_UVMetrics(UVweight[i].UV, afm); | 
|  | if (afmm->UV != UVweight[i].UV)     /* UVMetrics returns first glyph */ | 
|  | return MeanCharWidth(afm);	    /*   in font if UV is missing    */ | 
|  |  | 
|  | w += afmm->WX * (float)(UVweight[i].weight); | 
|  | } | 
|  |  | 
|  | w /= 1000.0; | 
|  |  | 
|  | return (SHORT)(w + 0.5); | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | *  AddBuiltinAFMs | 
|  | * | 
|  | */ | 
|  |  | 
|  | static BOOL AddBuiltinAFMs(void) | 
|  | { | 
|  | const AFM *const	*afm = PSDRV_BuiltinAFMs; | 
|  |  | 
|  | while (*afm != NULL) | 
|  | { | 
|  | BOOL	added; | 
|  |  | 
|  | if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, *afm, &added) == FALSE) | 
|  | return FALSE; | 
|  |  | 
|  | if (added == FALSE) | 
|  | TRACE("Ignoring built-in font %s\n", (*afm)->FontName); | 
|  |  | 
|  | ++afm; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************** | 
|  | * | 
|  | *	PSDRV_GetFontMetrics | 
|  | * | 
|  | * Parses all afm files listed in the | 
|  | * HKEY_CURRENT_USER\\Software\\Wine\\Fonts registry key. | 
|  | * Adds built-in data last, so it can be overridden by | 
|  | * user-supplied AFM or TTF files. | 
|  | * | 
|  | * If this function fails, PSDRV_Init will destroy PSDRV_Heap, so don't worry | 
|  | * about freeing all the memory that's been allocated. | 
|  | */ | 
|  |  | 
|  | BOOL PSDRV_GetFontMetrics(void) | 
|  | { | 
|  | if (PSDRV_GlyphListInit() != 0) | 
|  | return FALSE; | 
|  |  | 
|  | if (PSDRV_GetType1Metrics() == FALSE) | 
|  | return FALSE; | 
|  |  | 
|  | if (AddBuiltinAFMs() == FALSE) | 
|  | return FALSE; | 
|  |  | 
|  | PSDRV_IndexGlyphList(); 	    /* Enable fast searching of glyph names */ | 
|  |  | 
|  | PSDRV_DumpFontList(); | 
|  |  | 
|  | return TRUE; | 
|  | } |