|  | /* | 
|  | *	PostScript driver builtin font functions | 
|  | * | 
|  | *	Copyright 2002  Huw D M Davies for CodeWeavers | 
|  | * | 
|  | * 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 <stdarg.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <math.h> | 
|  | #include <assert.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "wingdi.h" | 
|  |  | 
|  | #include "psdrv.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(psdrv); | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           is_stock_font | 
|  | */ | 
|  | static inline BOOL is_stock_font( HFONT font ) | 
|  | { | 
|  | int i; | 
|  | for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++) | 
|  | { | 
|  | if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | *  ScaleFont | 
|  | * | 
|  | *  Scale builtin font to requested lfHeight | 
|  | * | 
|  | */ | 
|  | static inline float Round(float f) | 
|  | { | 
|  | return (f > 0) ? (f + 0.5) : (f - 0.5); | 
|  | } | 
|  |  | 
|  | static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font, | 
|  | TEXTMETRICW *tm) | 
|  | { | 
|  | const WINMETRICS	*wm = &(afm->WinMetrics); | 
|  | USHORT  	    	usUnitsPerEm, usWinAscent, usWinDescent; | 
|  | SHORT   	    	sAscender, sDescender, sLineGap, sAvgCharWidth; | 
|  |  | 
|  | TRACE("'%s' %i\n", afm->FontName, lfHeight); | 
|  |  | 
|  | if (lfHeight < 0)   	    	    	    	/* match em height */ | 
|  | { | 
|  | font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm)); | 
|  | } | 
|  | else    	    	    	    	    	    	/* match cell height */ | 
|  | { | 
|  | font->fontinfo.Builtin.scale = (float)lfHeight / | 
|  | (float)(wm->usWinAscent + wm->usWinDescent); | 
|  | } | 
|  |  | 
|  | font->size = (INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm); | 
|  |  | 
|  | usUnitsPerEm = (USHORT)Round((float)(wm->usUnitsPerEm) * font->fontinfo.Builtin.scale); | 
|  | sAscender = (SHORT)Round((float)(wm->sAscender) * font->fontinfo.Builtin.scale); | 
|  | sDescender = (SHORT)Round((float)(wm->sDescender) * font->fontinfo.Builtin.scale); | 
|  | sLineGap = (SHORT)Round((float)(wm->sLineGap) * font->fontinfo.Builtin.scale); | 
|  | usWinAscent = (USHORT)Round((float)(wm->usWinAscent) * font->fontinfo.Builtin.scale); | 
|  | usWinDescent = (USHORT)Round((float)(wm->usWinDescent) * font->fontinfo.Builtin.scale); | 
|  | sAvgCharWidth = (SHORT)Round((float)(wm->sAvgCharWidth) * font->fontinfo.Builtin.scale); | 
|  |  | 
|  | tm->tmAscent = (LONG)usWinAscent; | 
|  | tm->tmDescent = (LONG)usWinDescent; | 
|  | tm->tmHeight = tm->tmAscent + tm->tmDescent; | 
|  |  | 
|  | tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm; | 
|  | if (tm->tmInternalLeading < 0) | 
|  | tm->tmInternalLeading = 0; | 
|  |  | 
|  | tm->tmExternalLeading = | 
|  | (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight; | 
|  | if (tm->tmExternalLeading < 0) | 
|  | tm->tmExternalLeading = 0; | 
|  |  | 
|  | tm->tmAveCharWidth = (LONG)sAvgCharWidth; | 
|  |  | 
|  | tm->tmWeight = afm->Weight; | 
|  | tm->tmItalic = (afm->ItalicAngle != 0.0); | 
|  | tm->tmUnderlined = 0; | 
|  | tm->tmStruckOut = 0; | 
|  | tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV); | 
|  | tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV); | 
|  | tm->tmDefaultChar = 0x001f;     	/* Win2K does this - FIXME? */ | 
|  | tm->tmBreakChar = tm->tmFirstChar;	    	/* should be 'space' */ | 
|  |  | 
|  | tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR; | 
|  | if (!afm->IsFixedPitch) | 
|  | tm->tmPitchAndFamily |= TMPF_FIXED_PITCH;   /* yes, it's backwards */ | 
|  | if (wm->usUnitsPerEm != 1000) | 
|  | tm->tmPitchAndFamily |= TMPF_TRUETYPE; | 
|  |  | 
|  | tm->tmCharSet = ANSI_CHARSET;   	/* FIXME */ | 
|  | tm->tmOverhang = 0; | 
|  |  | 
|  | /* | 
|  | *	This is kludgy.  font->scale is used in several places in the driver | 
|  | *	to adjust PostScript-style metrics.  Since these metrics have been | 
|  | *	"normalized" to an em-square size of 1000, font->scale needs to be | 
|  | *	similarly adjusted.. | 
|  | */ | 
|  |  | 
|  | font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0; | 
|  |  | 
|  | tm->tmMaxCharWidth = (LONG)Round( | 
|  | (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale); | 
|  |  | 
|  | font->underlinePosition = afm->UnderlinePosition * font->fontinfo.Builtin.scale; | 
|  | font->underlineThickness = afm->UnderlineThickness * font->fontinfo.Builtin.scale; | 
|  | font->strikeoutPosition = tm->tmAscent / 2; | 
|  | font->strikeoutThickness = font->underlineThickness; | 
|  |  | 
|  | TRACE("Selected PS font '%s' size %d weight %d.\n", afm->FontName, | 
|  | font->size, tm->tmWeight ); | 
|  | TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", tm->tmHeight, | 
|  | tm->tmAscent, tm->tmDescent, tm->tmInternalLeading, | 
|  | tm->tmExternalLeading); | 
|  | } | 
|  |  | 
|  |  | 
|  | /**************************************************************************** | 
|  | *  PSDRV_SelectBuiltinFont | 
|  | * | 
|  | *  Set up physDev->font for a builtin font | 
|  | * | 
|  | */ | 
|  | BOOL PSDRV_SelectBuiltinFont(PSDRV_PDEVICE *physDev, HFONT hfont, | 
|  | LOGFONTW *plf, LPSTR FaceName) | 
|  | { | 
|  | AFMLISTENTRY *afmle; | 
|  | FONTFAMILY *family; | 
|  | BOOL bd = FALSE, it = FALSE; | 
|  | LONG height; | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if(plf->lfItalic) | 
|  | it = TRUE; | 
|  | if(plf->lfWeight > 550) | 
|  | bd = TRUE; | 
|  |  | 
|  | 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 */ | 
|  |  | 
|  | TRACE("Got font '%s'\n", afmle->afm->FontName); | 
|  |  | 
|  | physDev->font.fontloc = Builtin; | 
|  | physDev->font.fontinfo.Builtin.afm = afmle->afm; | 
|  |  | 
|  | height = plf->lfHeight; | 
|  | /* stock fonts ignore the mapping mode */ | 
|  | if (!is_stock_font( hfont )) { | 
|  | POINT pts[2]; | 
|  | pts[0].x = pts[0].y = pts[1].x = 0; | 
|  | pts[1].y = height; | 
|  | LPtoDP(physDev->hdc, pts, 2); | 
|  | height = pts[1].y - pts[0].y; | 
|  | } | 
|  | ScaleFont(physDev->font.fontinfo.Builtin.afm, height, | 
|  | &(physDev->font), &(physDev->font.fontinfo.Builtin.tm)); | 
|  |  | 
|  |  | 
|  | /* Does anyone know if these are supposed to be reversed like this? */ | 
|  |  | 
|  | physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY; | 
|  | physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | BOOL PSDRV_WriteSetBuiltinFont(PSDRV_PDEVICE *physDev) | 
|  | { | 
|  | return PSDRV_WriteSetFont(physDev, | 
|  | physDev->font.fontinfo.Builtin.afm->FontName, | 
|  | physDev->font.size, physDev->font.escapement); | 
|  | } | 
|  |  | 
|  | BOOL PSDRV_WriteBuiltinGlyphShow(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count) | 
|  | { | 
|  | int i; | 
|  | LPCSTR name; | 
|  |  | 
|  | for (i = 0; i < count; ++i) | 
|  | { | 
|  | name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz; | 
|  |  | 
|  | PSDRV_WriteGlyphShow(physDev, name); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetTextMetrics | 
|  | */ | 
|  | BOOL CDECL PSDRV_GetTextMetrics(PSDRV_PDEVICE *physDev, TEXTMETRICW *metrics) | 
|  | { | 
|  | assert(physDev->font.fontloc == Builtin); | 
|  |  | 
|  | memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm), | 
|  | sizeof(physDev->font.fontinfo.Builtin.tm)); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *  	PSDRV_UVMetrics | 
|  | * | 
|  | *  Find the AFMMETRICS for a given UV.  Returns first glyph in the font | 
|  | *  (space?) if the font does not have a glyph for the given UV. | 
|  | */ | 
|  | static int MetricsByUV(const void *a, const void *b) | 
|  | { | 
|  | return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV); | 
|  | } | 
|  |  | 
|  | const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm) | 
|  | { | 
|  | AFMMETRICS	    	key; | 
|  | const AFMMETRICS	*needle; | 
|  |  | 
|  | /* | 
|  | *	Ugly work-around for symbol fonts.  Wine is sending characters which | 
|  | *	belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII | 
|  | *	characters (U+0020 - U+00FF). | 
|  | */ | 
|  |  | 
|  | if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100) | 
|  | UV |= 0xf000; | 
|  |  | 
|  | key.UV = UV; | 
|  |  | 
|  | needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS), | 
|  | MetricsByUV); | 
|  |  | 
|  | if (needle == NULL) | 
|  | { | 
|  | WARN("No glyph for U+%.4X in %s\n", UV, afm->FontName); | 
|  | needle = afm->Metrics; | 
|  | } | 
|  |  | 
|  | return needle; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetTextExtentExPoint | 
|  | */ | 
|  | BOOL CDECL PSDRV_GetTextExtentExPoint(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count, | 
|  | INT maxExt, LPINT lpnFit, LPINT alpDx, LPSIZE size) | 
|  | { | 
|  | int     	    nfit = 0; | 
|  | int     	    i; | 
|  | float   	    width = 0.0; | 
|  | float   	    scale; | 
|  |  | 
|  | assert(physDev->font.fontloc == Builtin); | 
|  |  | 
|  | TRACE("%s %i\n", debugstr_wn(str, count), count); | 
|  |  | 
|  | scale = physDev->font.fontinfo.Builtin.scale; | 
|  | for (i = 0; i < count && str[i] != '\0'; ++i) | 
|  | { | 
|  | float scaled_width; | 
|  | width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX; | 
|  | scaled_width = width * scale; | 
|  | if (alpDx) | 
|  | alpDx[i] = scaled_width; | 
|  | if (scaled_width <= maxExt) | 
|  | ++nfit; | 
|  | } | 
|  |  | 
|  | size->cx = width * physDev->font.fontinfo.Builtin.scale; | 
|  | size->cy = physDev->font.fontinfo.Builtin.tm.tmHeight; | 
|  |  | 
|  | if (lpnFit) | 
|  | *lpnFit = nfit; | 
|  |  | 
|  | TRACE("cx=%i cy=%i\n", size->cx, size->cy); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetCharWidth | 
|  | */ | 
|  | BOOL CDECL PSDRV_GetCharWidth(PSDRV_PDEVICE *physDev, UINT firstChar, UINT lastChar, LPINT buffer) | 
|  | { | 
|  | UINT    	    i; | 
|  |  | 
|  | assert(physDev->font.fontloc == Builtin); | 
|  |  | 
|  | TRACE("U+%.4X U+%.4X\n", firstChar, lastChar); | 
|  |  | 
|  | if (lastChar > 0xffff || firstChar > lastChar) | 
|  | { | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | for (i = firstChar; i <= lastChar; ++i) | 
|  | { | 
|  | *buffer = floor( PSDRV_UVMetrics(i, physDev->font.fontinfo.Builtin.afm)->WX | 
|  | * physDev->font.fontinfo.Builtin.scale + 0.5 ); | 
|  | TRACE("U+%.4X: %i\n", i, *buffer); | 
|  | ++buffer; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_GetFontMetric | 
|  | */ | 
|  | static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm, | 
|  | NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx) | 
|  | { | 
|  | /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */ | 
|  |  | 
|  | TEXTMETRICW     *tm = (TEXTMETRICW *)&(ntmx->ntmTm); | 
|  | LOGFONTW	    *lf = &(elfx->elfLogFont); | 
|  | PSFONT  	    font; | 
|  |  | 
|  | memset(ntmx, 0, sizeof(*ntmx)); | 
|  | memset(elfx, 0, sizeof(*elfx)); | 
|  |  | 
|  | ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm); | 
|  |  | 
|  | lf->lfHeight = tm->tmHeight; | 
|  | lf->lfWidth = tm->tmAveCharWidth; | 
|  | lf->lfWeight = tm->tmWeight; | 
|  | lf->lfItalic = tm->tmItalic; | 
|  | lf->lfCharSet = tm->tmCharSet; | 
|  |  | 
|  | lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH; | 
|  |  | 
|  | MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName, | 
|  | LF_FACESIZE); | 
|  |  | 
|  | return DEVICE_FONTTYPE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PSDRV_EnumDeviceFonts | 
|  | */ | 
|  | BOOL CDECL PSDRV_EnumDeviceFonts( PSDRV_PDEVICE *physDev, LPLOGFONTW plf, | 
|  | FONTENUMPROCW proc, LPARAM lp ) | 
|  | { | 
|  | ENUMLOGFONTEXW	lf; | 
|  | NEWTEXTMETRICEXW	tm; | 
|  | BOOL	  	b, bRet = 0; | 
|  | AFMLISTENTRY	*afmle; | 
|  | FONTFAMILY		*family; | 
|  | char                FaceName[LF_FACESIZE]; | 
|  |  | 
|  | if( plf && 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) { | 
|  | UINT fm; | 
|  |  | 
|  | TRACE("Got '%s'\n", afmle->afm->FontName); | 
|  | fm = PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ); | 
|  | if( (b = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )) ) | 
|  | bRet = b; | 
|  | else break; | 
|  | } | 
|  | } | 
|  | } else { | 
|  |  | 
|  | TRACE("lfFaceName = NULL\n"); | 
|  | for(family = physDev->pi->Fonts; family; family = family->next) { | 
|  | UINT fm; | 
|  |  | 
|  | afmle = family->afmlist; | 
|  | TRACE("Got '%s'\n", afmle->afm->FontName); | 
|  | fm = PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ); | 
|  | if( (b = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )) ) | 
|  | bRet = b; | 
|  | else break; | 
|  | } | 
|  | } | 
|  | return bRet; | 
|  | } |