|  | /* | 
|  | *	PostScript driver font functions | 
|  | * | 
|  | *	Copyright 1998  Huw D M Davies | 
|  | * | 
|  | */ | 
|  | #include <string.h> | 
|  | #include "winspool.h" | 
|  | #include "psdrv.h" | 
|  | #include "debugtools.h" | 
|  |  | 
|  | DEFAULT_DEBUG_CHANNEL(psdrv) | 
|  |  | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_FONT_SelectObject | 
|  | */ | 
|  | HFONT16 PSDRV_FONT_SelectObject( DC * dc, HFONT16 hfont, | 
|  | FONTOBJ *font ) | 
|  | { | 
|  | HFONT16 prevfont = dc->w.hFont; | 
|  | PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  | LOGFONT16 *lf = &(font->logfont); | 
|  | BOOL bd = FALSE, it = FALSE; | 
|  | AFMLISTENTRY *afmle; | 
|  | AFM *afm; | 
|  | FONTFAMILY *family; | 
|  | char FaceName[LF_FACESIZE]; | 
|  |  | 
|  |  | 
|  | TRACE("FaceName = '%s' Height = %d Italic = %d Weight = %d\n", | 
|  | lf->lfFaceName, lf->lfHeight, lf->lfItalic, lf->lfWeight); | 
|  |  | 
|  | dc->w.hFont = hfont; | 
|  |  | 
|  | if(lf->lfItalic) | 
|  | it = TRUE; | 
|  | if(lf->lfWeight > 550) | 
|  | bd = TRUE; | 
|  | strcpy(FaceName, lf->lfFaceName); | 
|  |  | 
|  | if(FaceName[0] == '\0') { | 
|  | switch(lf->lfPitchAndFamily & 0xf0) { | 
|  | case FF_DONTCARE: | 
|  | break; | 
|  | case FF_ROMAN: | 
|  | case FF_SCRIPT: | 
|  | strcpy(FaceName, "Times"); | 
|  | break; | 
|  | case FF_SWISS: | 
|  | strcpy(FaceName, "Helvetica"); | 
|  | break; | 
|  | case FF_MODERN: | 
|  | strcpy(FaceName, "Courier"); | 
|  | break; | 
|  | case FF_DECORATIVE: | 
|  | strcpy(FaceName, "Symbol"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(FaceName[0] == '\0') { | 
|  | switch(lf->lfPitchAndFamily & 0x0f) { | 
|  | case VARIABLE_PITCH: | 
|  | strcpy(FaceName, "Times"); | 
|  | break; | 
|  | default: | 
|  | strcpy(FaceName, "Courier"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE("Trying to find facename '%s'\n", FaceName); | 
|  |  | 
|  | /* Look for a matching font family */ | 
|  | for(family = physDev->pi->Fonts; family; family = family->next) { | 
|  | if(!strcmp(FaceName, family->FamilyName)) | 
|  | break; | 
|  | } | 
|  | if(!family) { | 
|  | /* Fallback for Window's font families to common PostScript families */ | 
|  | if(!strcmp(FaceName, "Arial")) | 
|  | strcpy(FaceName, "Helvetica"); | 
|  | else if(!strcmp(FaceName, "System")) | 
|  | strcpy(FaceName, "Helvetica"); | 
|  | else if(!strcmp(FaceName, "Times New Roman")) | 
|  | strcpy(FaceName, "Times"); | 
|  | for(family = physDev->pi->Fonts; family; family = family->next) { | 
|  | if(!strcmp(FaceName, family->FamilyName)) | 
|  | break; | 
|  | } | 
|  | } | 
|  | /* If all else fails, use the first font defined for the printer */ | 
|  | if(!family) | 
|  | family = physDev->pi->Fonts; | 
|  |  | 
|  | TRACE("Got family '%s'\n", family->FamilyName); | 
|  |  | 
|  | for(afmle = family->afmlist; afmle; afmle = afmle->next) { | 
|  | if( (bd == (afmle->afm->Weight == FW_BOLD)) && | 
|  | (it == (afmle->afm->ItalicAngle != 0.0)) ) | 
|  | break; | 
|  | } | 
|  | if(!afmle) | 
|  | afmle = family->afmlist; /* not ideal */ | 
|  |  | 
|  | afm = afmle->afm; | 
|  |  | 
|  | physDev->font.afm = afm; | 
|  | physDev->font.tm.tmHeight = YLSTODS(dc, lf->lfHeight); | 
|  | if(physDev->font.tm.tmHeight < 0) { | 
|  | physDev->font.tm.tmHeight *= - (afm->FullAscender - afm->Descender) / | 
|  | (afm->Ascender - afm->Descender); | 
|  | TRACE("Fixed -ve height to %ld\n", physDev->font.tm.tmHeight); | 
|  | } | 
|  | physDev->font.size = physDev->font.tm.tmHeight * 1000.0 / | 
|  | (afm->FullAscender - afm->Descender); | 
|  | physDev->font.scale = physDev->font.size / 1000.0; | 
|  | physDev->font.escapement = lf->lfEscapement; | 
|  | physDev->font.tm.tmAscent = afm->FullAscender * physDev->font.scale; | 
|  | physDev->font.tm.tmDescent = -afm->Descender * physDev->font.scale; | 
|  | physDev->font.tm.tmInternalLeading = (afm->FullAscender - afm->Ascender) | 
|  | * physDev->font.scale; | 
|  | physDev->font.tm.tmExternalLeading = (1000.0 - afm->FullAscender) | 
|  | * physDev->font.scale; /* ?? */ | 
|  | physDev->font.tm.tmAveCharWidth = afm->CharWidths[120] * /* x */ | 
|  | physDev->font.scale; | 
|  | physDev->font.tm.tmMaxCharWidth = afm->CharWidths[77] * /* M */ | 
|  | physDev->font.scale; | 
|  | physDev->font.tm.tmWeight = afm->Weight; | 
|  | physDev->font.tm.tmItalic = afm->ItalicAngle != 0.0; | 
|  | physDev->font.tm.tmUnderlined = lf->lfUnderline; | 
|  | physDev->font.tm.tmStruckOut = lf->lfStrikeOut; | 
|  | physDev->font.tm.tmFirstChar = 32; | 
|  | physDev->font.tm.tmLastChar = 251; | 
|  | physDev->font.tm.tmDefaultChar = 128; | 
|  | physDev->font.tm.tmBreakChar = 32; | 
|  | physDev->font.tm.tmPitchAndFamily = afm->IsFixedPitch ? 0 : | 
|  | TMPF_FIXED_PITCH; | 
|  | physDev->font.tm.tmPitchAndFamily |= TMPF_DEVICE; | 
|  | physDev->font.tm.tmCharSet = ANSI_CHARSET; | 
|  | physDev->font.tm.tmOverhang = 0; | 
|  | physDev->font.tm.tmDigitizedAspectX = dc->w.devCaps->logPixelsY; | 
|  | physDev->font.tm.tmDigitizedAspectY = dc->w.devCaps->logPixelsX; | 
|  |  | 
|  | physDev->font.set = FALSE; | 
|  |  | 
|  | TRACE("Selected PS font '%s' size %d weight %ld.\n", | 
|  | physDev->font.afm->FontName, physDev->font.size, | 
|  | physDev->font.tm.tmWeight ); | 
|  | TRACE("H = %ld As = %ld Des = %ld IL = %ld EL = %ld\n", | 
|  | physDev->font.tm.tmHeight, physDev->font.tm.tmAscent, | 
|  | physDev->font.tm.tmDescent, physDev->font.tm.tmInternalLeading, | 
|  | physDev->font.tm.tmExternalLeading); | 
|  |  | 
|  | return prevfont; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetTextMetrics | 
|  | */ | 
|  | BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics) | 
|  | { | 
|  | PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  |  | 
|  | memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm)); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetTextExtentPoint | 
|  | */ | 
|  | BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count, | 
|  | LPSIZE size ) | 
|  | { | 
|  | PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  | INT i; | 
|  | float width; | 
|  |  | 
|  | size->cy = YDSTOLS(dc, physDev->font.tm.tmHeight); | 
|  | width = 0.0; | 
|  |  | 
|  | for(i = 0; i < count && str[i]; i++) { | 
|  | width += physDev->font.afm->CharWidths[ *((unsigned char *)str + i) ]; | 
|  | /*	TRACE(psdrv, "Width after %dth char '%c' = %f\n", i, str[i], width);*/ | 
|  | } | 
|  | width *= physDev->font.scale; | 
|  | TRACE("Width after scale (%f) is %f\n", physDev->font.scale, width); | 
|  | size->cx = XDSTOLS(dc, width); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetCharWidth | 
|  | */ | 
|  | BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar, | 
|  | LPINT buffer ) | 
|  | { | 
|  | PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  | UINT i; | 
|  |  | 
|  | TRACE("first = %d last = %d\n", firstChar, lastChar); | 
|  |  | 
|  | if(lastChar > 0xff) return FALSE; | 
|  | for( i = firstChar; i <= lastChar; i++ ) | 
|  | *buffer++ = physDev->font.afm->CharWidths[i] * physDev->font.scale; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_SetFont | 
|  | */ | 
|  | BOOL PSDRV_SetFont( DC *dc ) | 
|  | { | 
|  | PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  | BOOL ReEncode = FALSE; | 
|  |  | 
|  | PSDRV_WriteSetColor(dc, &physDev->font.color); | 
|  | if(physDev->font.set) return TRUE; | 
|  |  | 
|  | if(physDev->font.afm->EncodingScheme && | 
|  | !strcmp(physDev->font.afm->EncodingScheme, "AdobeStandardEncoding")) | 
|  | ReEncode = TRUE; | 
|  | if(ReEncode) | 
|  | PSDRV_WriteReencodeFont(dc); | 
|  | PSDRV_WriteSetFont(dc, ReEncode); | 
|  | physDev->font.set = TRUE; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetFontMetric | 
|  | */ | 
|  | static UINT PSDRV_GetFontMetric(DC *dc, AFM *pafm, NEWTEXTMETRIC16 *pTM, | 
|  | ENUMLOGFONTEX16 *pLF, INT16 size) | 
|  |  | 
|  | { | 
|  | float scale = size / (pafm->FullAscender - pafm->Descender); | 
|  | memset( pLF, 0, sizeof(*pLF) ); | 
|  | memset( pTM, 0, sizeof(*pTM) ); | 
|  |  | 
|  | #define plf ((LPLOGFONT16)pLF) | 
|  | plf->lfHeight    = pTM->tmHeight       = size; | 
|  | plf->lfWidth     = pTM->tmAveCharWidth = pafm->CharWidths[120] * scale; | 
|  | plf->lfWeight    = pTM->tmWeight       = pafm->Weight; | 
|  | plf->lfItalic    = pTM->tmItalic       = pafm->ItalicAngle != 0.0; | 
|  | plf->lfUnderline = pTM->tmUnderlined   = 0; | 
|  | plf->lfStrikeOut = pTM->tmStruckOut    = 0; | 
|  | plf->lfCharSet   = pTM->tmCharSet      = ANSI_CHARSET; | 
|  |  | 
|  | /* convert pitch values */ | 
|  |  | 
|  | pTM->tmPitchAndFamily = pafm->IsFixedPitch ? 0 : TMPF_FIXED_PITCH; | 
|  | pTM->tmPitchAndFamily |= TMPF_DEVICE; | 
|  | plf->lfPitchAndFamily = 0; | 
|  |  | 
|  | strncpy( plf->lfFaceName, pafm->FamilyName, LF_FACESIZE ); | 
|  | #undef plf | 
|  |  | 
|  | pTM->tmAscent = pafm->FullAscender * scale; | 
|  | pTM->tmDescent = -pafm->Descender * scale; | 
|  | pTM->tmInternalLeading = (pafm->FullAscender - pafm->Ascender) * scale; | 
|  | pTM->tmMaxCharWidth = pafm->CharWidths[77] * scale; | 
|  | pTM->tmDigitizedAspectX = dc->w.devCaps->logPixelsY; | 
|  | pTM->tmDigitizedAspectY = dc->w.devCaps->logPixelsX; | 
|  |  | 
|  | *(INT*)&pTM->tmFirstChar = 32; | 
|  |  | 
|  | /* return font type */ | 
|  |  | 
|  | return DEVICE_FONTTYPE; | 
|  |  | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_EnumDeviceFonts | 
|  | */ | 
|  | BOOL PSDRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf, | 
|  | DEVICEFONTENUMPROC proc, LPARAM lp ) | 
|  | { | 
|  | ENUMLOGFONTEX16	lf; | 
|  | NEWTEXTMETRIC16	tm; | 
|  | BOOL	  	b, bRet = 0; | 
|  | AFMLISTENTRY	*afmle; | 
|  | FONTFAMILY		*family; | 
|  | PSDRV_PDEVICE	*physDev = (PSDRV_PDEVICE *)dc->physDev; | 
|  |  | 
|  | if( plf->lfFaceName[0] ) { | 
|  | TRACE("lfFaceName = '%s'\n", plf->lfFaceName); | 
|  | for(family = physDev->pi->Fonts; family; family = family->next) { | 
|  | if(!strncmp(plf->lfFaceName, family->FamilyName, | 
|  | strlen(family->FamilyName))) | 
|  | break; | 
|  | } | 
|  | if(family) { | 
|  | for(afmle = family->afmlist; afmle; afmle = afmle->next) { | 
|  | TRACE("Got '%s'\n", afmle->afm->FontName); | 
|  | if( (b = (*proc)( &lf, &tm, | 
|  | PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ), | 
|  | lp )) ) | 
|  | bRet = b; | 
|  | else break; | 
|  | } | 
|  | } | 
|  | } else { | 
|  |  | 
|  | TRACE("lfFaceName = NULL\n"); | 
|  | for(family = physDev->pi->Fonts; family; family = family->next) { | 
|  | afmle = family->afmlist; | 
|  | TRACE("Got '%s'\n", afmle->afm->FontName); | 
|  | if( (b = (*proc)( &lf, &tm, | 
|  | PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ), | 
|  | lp )) ) | 
|  | bRet = b; | 
|  | else break; | 
|  | } | 
|  | } | 
|  | return bRet; | 
|  | } |