| /* | |
| * PostScript driver font functions | |
| * | |
| * Copyright 1998 Huw D M Davies | |
| * | |
| */ | |
| #include <string.h> | |
| #include "winspool.h" | |
| #include "psdrv.h" | |
| #include "debugtools.h" | |
| #include "gdi.h" | |
| #include "winerror.h" | |
| DEFAULT_DEBUG_CHANNEL(psdrv); | |
| /*********************************************************************** | |
| * PSDRV_FONT_SelectObject | |
| */ | |
| HFONT16 PSDRV_FONT_SelectObject( DC * dc, HFONT16 hfont, | |
| FONTOBJ *font ) | |
| { | |
| HFONT16 prevfont = dc->hFont; | |
| PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | |
| LOGFONTW *lf = &(font->logfont); | |
| BOOL bd = FALSE, it = FALSE; | |
| AFMLISTENTRY *afmle; | |
| AFM *afm; | |
| FONTFAMILY *family; | |
| char FaceName[LF_FACESIZE]; | |
| TRACE("FaceName = %s Height = %ld Italic = %d Weight = %ld\n", | |
| debugstr_w(lf->lfFaceName), lf->lfHeight, lf->lfItalic, | |
| lf->lfWeight); | |
| dc->hFont = hfont; | |
| if(lf->lfItalic) | |
| it = TRUE; | |
| if(lf->lfWeight > 550) | |
| bd = TRUE; | |
| WideCharToMultiByte(CP_ACP, 0, lf->lfFaceName, -1, | |
| FaceName, sizeof(FaceName), NULL, NULL); | |
| 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; | |
| } | |
| } | |
| if (physDev->pi->FontSubTableSize != 0) | |
| { | |
| DWORD i; | |
| for (i = 0; i < physDev->pi->FontSubTableSize; ++i) | |
| { | |
| if (!strcasecmp (FaceName, | |
| physDev->pi->FontSubTable[i].pValueName)) | |
| { | |
| TRACE ("substituting facename '%s' for '%s'\n", | |
| (LPSTR) physDev->pi->FontSubTable[i].pData, FaceName); | |
| if (strlen ((LPSTR) physDev->pi->FontSubTable[i].pData) < | |
| LF_FACESIZE) | |
| strcpy (FaceName, | |
| (LPSTR) physDev->pi->FontSubTable[i].pData); | |
| else | |
| WARN ("Facename '%s' is too long; ignoring substitution\n", | |
| (LPSTR) physDev->pi->FontSubTable[i].pData); | |
| 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(!strcasecmp(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"); | |
| else if(!strcmp(FaceName, "Courier New")) | |
| strcpy(FaceName, "Courier"); | |
| 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 = INTERNAL_YWSTODS(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->devCaps->logPixelsY; | |
| physDev->font.tm.tmDigitizedAspectY = dc->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, TEXTMETRICW *metrics) | |
| { | |
| PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | |
| memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm)); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * PSDRV_UnicodeToANSI | |
| */ | |
| char PSDRV_UnicodeToANSI(int u) | |
| { | |
| if((u & 0xff) == u) | |
| return u; | |
| switch(u) { | |
| case 0x2013: /* endash */ | |
| return 0x96; | |
| case 0x2014: /* emdash */ | |
| return 0x97; | |
| case 0x2018: /* quoteleft */ | |
| return 0x91; | |
| case 0x2019: /* quoteright */ | |
| return 0x92; | |
| case 0x201c: /* quotedblleft */ | |
| return 0x93; | |
| case 0x201d: /* quotedblright */ | |
| return 0x94; | |
| case 0x2022: /* bullet */ | |
| return 0x95; | |
| default: | |
| WARN("Umapped unicode char U%04x\n", u); | |
| return 0xff; | |
| } | |
| } | |
| /*********************************************************************** | |
| * PSDRV_GetTextExtentPoint | |
| */ | |
| BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count, | |
| LPSIZE size ) | |
| { | |
| PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev; | |
| INT i; | |
| float width; | |
| width = 0.0; | |
| for(i = 0; i < count && str[i]; i++) { | |
| char c = PSDRV_UnicodeToANSI(str[i]); | |
| width += physDev->font.afm->CharWidths[(int)(unsigned char)c]; | |
| /* 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 = GDI_ROUND((FLOAT)width * dc->xformVport2World.eM11); | |
| size->cy = GDI_ROUND((FLOAT)physDev->font.tm.tmHeight * dc->xformVport2World.eM22); | |
| 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(HDC hdc, AFM *pafm, NEWTEXTMETRICEXW *pTM, | |
| ENUMLOGFONTEXW *pLF, INT16 size) | |
| { | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| float scale = size / (pafm->FullAscender - pafm->Descender); | |
| if (!dc) return FALSE; | |
| memset( pLF, 0, sizeof(*pLF) ); | |
| memset( pTM, 0, sizeof(*pTM) ); | |
| #define plf ((LPLOGFONTW)pLF) | |
| #define ptm ((LPNEWTEXTMETRICW)pTM) | |
| 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; | |
| MultiByteToWideChar(CP_ACP, 0, pafm->FamilyName, -1, | |
| plf->lfFaceName, 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->devCaps->logPixelsY; | |
| ptm->tmDigitizedAspectY = dc->devCaps->logPixelsX; | |
| *(INT*)&ptm->tmFirstChar = 32; | |
| GDI_ReleaseObj( hdc ); | |
| /* return font type */ | |
| return DEVICE_FONTTYPE; | |
| #undef ptm | |
| } | |
| /*********************************************************************** | |
| * PSDRV_EnumDeviceFonts | |
| */ | |
| BOOL PSDRV_EnumDeviceFonts( HDC hdc, LPLOGFONTW plf, | |
| DEVICEFONTENUMPROC proc, LPARAM lp ) | |
| { | |
| ENUMLOGFONTEXW lf; | |
| NEWTEXTMETRICEXW tm; | |
| BOOL b, bRet = 0; | |
| AFMLISTENTRY *afmle; | |
| FONTFAMILY *family; | |
| PSDRV_PDEVICE *physDev; | |
| char FaceName[LF_FACESIZE]; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if (!dc) return FALSE; | |
| physDev = (PSDRV_PDEVICE *)dc->physDev; | |
| /* FIXME!! should reevaluate dc->physDev after every callback */ | |
| GDI_ReleaseObj( hdc ); | |
| if( plf->lfFaceName[0] ) { | |
| WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1, | |
| FaceName, sizeof(FaceName), NULL, NULL); | |
| TRACE("lfFaceName = '%s'\n", FaceName); | |
| for(family = physDev->pi->Fonts; family; family = family->next) { | |
| if(!strncmp(FaceName, 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( hdc, 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( hdc, afmle->afm, &tm, &lf, 200 ), | |
| lp )) ) | |
| bRet = b; | |
| else break; | |
| } | |
| } | |
| return bRet; | |
| } |