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