/* Win32FontInfo - Implements font enumerator for MSWindows Copyright (C) 2002 Free Software Foundation, Inc. Written by: Fred Kiefer Date: March 2002 This file is part of the GNU Objective C User Interface Library. 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 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; see the file COPYING.LIB. If not, see or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "winlib/WIN32FontInfo.h" int win32_font_weight(LONG tmWeight); NSString *win32_font_family(NSString *fontName); @interface WIN32FontInfo (Private) - (BOOL) setupAttributes; @end @implementation WIN32FontInfo - initWithFontName: (NSString*)name matrix: (const float *)fmatrix screenFont: (BOOL)screenFont { if (screenFont) { RELEASE(self); return nil; } [super init]; ASSIGN(fontName, name); memcpy(matrix, fmatrix, sizeof(matrix)); if (![self setupAttributes]) { RELEASE(self); return nil; } return self; } - (void) dealloc { if (hFont) { DeleteObject(hFont); hFont = NULL; } [super dealloc]; } - (float) widthOfString: (NSString*)string { SIZE size; HDC hdc; HFONT old; hdc = CreateCompatibleDC(NULL); old = SelectObject(hdc, hFont); GetTextExtentPoint32W(hdc, (const unichar*)[string cStringUsingEncoding: NSUnicodeStringEncoding], [string length], &size); SelectObject(hdc, old); DeleteDC(hdc); return size.cx; } - (NSMultibyteGlyphPacking)glyphPacking { return NSOneByteGlyphPacking; } - (NSSize) advancementForGlyph: (NSGlyph)glyph { unichar u = (unichar)glyph; HDC hdc; float w; ABCFLOAT abc; HFONT old; hdc = CreateCompatibleDC(NULL); old = SelectObject(hdc, hFont); // FIXME ... currently a gnustep glyph is a unichar ... what if that changes. GetCharABCWidthsFloatW(hdc, u, u, &abc); SelectObject(hdc, old); DeleteDC(hdc); //NSLog(@"Width for %d is %f or %f", glyph, w, (abc.abcfA + abc.abcfB + abc.abcfC)); w = abc.abcfA + abc.abcfB + abc.abcfC; return NSMakeSize(w, 0); } - (NSRect) boundingRectForGlyph: (NSGlyph)glyph { WORD c = (WORD)glyph; WORD windowsGlyph; HDC hdc; HFONT old; GLYPHMETRICS gm; NSRect rect; hdc = CreateCompatibleDC(NULL); old = SelectObject(hdc, hFont); // Convert from GNUstep glyph (unichar) to windows glyph. if (GetGlyphIndicesW(hdc, &c, 1, &windowsGlyph, 0) == GDI_ERROR) { SelectObject(hdc, old); DeleteDC(hdc); NSLog(@"No glyph for U%d", c); return NSMakeRect(0, 0, 0, 0); // No such glyph } if (GDI_ERROR != GetGlyphOutlineW(hdc, windowsGlyph, GGO_METRICS, // || GGO_GLYPH_INDEX &gm, 0, NULL, NULL)) { rect = NSMakeRect(gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY); } else { rect = NSMakeRect(0, 0, 0, 0); } SelectObject(hdc, old); DeleteDC(hdc); return rect; } - (BOOL) glyphIsEncoded: (NSGlyph)glyph { WORD c = (WORD)glyph; WORD windowsGlyph; HDC hdc; HFONT old; BOOL result = YES; hdc = CreateCompatibleDC(NULL); old = SelectObject(hdc, hFont); // Convert from GNUstep glyph (unichar) to windows glyph. if ((GetGlyphIndicesW(hdc, &c, 1, &windowsGlyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) || (windowsGlyph == 0xFFFF)) { result = NO; } SelectObject(hdc, old); DeleteDC(hdc); return result; } - (NSGlyph) glyphWithName: (NSString*)glyphName { return 0; } - (NSPoint) positionOfGlyph: (NSGlyph)curGlyph precededByGlyph: (NSGlyph)prevGlyph isNominal: (BOOL*)nominal { return NSMakePoint(0, 0); } - (NSCharacterSet*) coveredCharacterSet { if (coveredCharacterSet == nil) { NSMutableCharacterSet *ms; unsigned count; GLYPHSET *gs = 0; HDC hdc; HFONT old; ms = [NSMutableCharacterSet new]; if (!ms) return nil; hdc = CreateCompatibleDC(NULL); old = SelectObject(hdc, hFont); count = (unsigned)GetFontUnicodeRanges(hdc, 0); if (count > 0) { gs = (GLYPHSET*)objc_malloc(count); if (!gs) { SelectObject(hdc, old); DeleteDC(hdc); RELEASE(ms); return nil; } gs->cbThis = count; if ((unsigned)GetFontUnicodeRanges(hdc, gs) == count) { numberOfGlyphs = gs->cGlyphsSupported; if (gs->flAccel == 1 /* GS_8BIT_INDICES */) { for (count = 0; count < gs->cRanges; count++) { NSRange range; range.location = gs->ranges[count].wcLow & 0xff; range.length = gs->ranges[count].cGlyphs; [ms addCharactersInRange: range]; } } else { for (count = 0; count < gs->cRanges; count++) { NSRange range; range.location = gs->ranges[count].wcLow; range.length = gs->ranges[count].cGlyphs; [ms addCharactersInRange: range]; } } } objc_free(gs); } SelectObject(hdc, old); DeleteDC(hdc); coveredCharacterSet = [ms copy]; RELEASE(ms); } return coveredCharacterSet; } - (void) drawString: (NSString*)string onDC: (HDC)hdc at: (POINT)p { HFONT old; old = SelectObject(hdc, hFont); TextOutW(hdc, p.x, p.y - ascender, (const unichar*)[string cStringUsingEncoding: NSUnicodeStringEncoding], [string length]); SelectObject(hdc, old); } - (void) draw:(const char*)s length: (int)len onDC: (HDC)hdc at: (POINT)p { HFONT old; old = SelectObject(hdc, hFont); TextOut(hdc, p.x, p.y - ascender, s, len); SelectObject(hdc, old); } - (void) drawGlyphs: (const NSGlyph*)s length: (int)len onDC: (HDC)hdc at: (POINT)p { WORD buf[len]; HFONT old; int i; old = SelectObject(hdc, hFont); /* * For now, assume that a glyph is a unicode character and can be * stored in a windows WORD */ for (i = 0; i < len; i++) { buf[i] = (WORD)s[i]; } TextOutW(hdc, p.x, p.y - ascender, buf, len); SelectObject(hdc, old); } - (unsigned) numberOfglyphs { if (coveredCharacterSet == nil) { [self coveredCharacterSet]; } return numberOfGlyphs; } - (void) appendBezierPathWithGlyphs: (NSGlyph *)glyphs count: (int)length toBezierPath: (NSBezierPath *)path { WORD buf[length]; int i; SIZE sBoundBox; int h; int iPoints; POINT *ptPoints; BYTE *bTypes; NSPoint startPoint; HDC hDC = CreateCompatibleDC(NULL); if (!hDC) { NSDebugLLog(@"WIN32FontInfo", @"Problem creating HDC for appendBezierPathWithGlyphs:"); return; } SetGraphicsMode(hDC, GM_ADVANCED); SetMapMode(hDC, MM_ANISOTROPIC); SetWindowExtEx(hDC, 1, 1, NULL); SetViewportExtEx(hDC, 1, -1, NULL); SetViewportOrgEx(hDC, 0, 0, NULL); /* * For now, assume that a glyph is a unicode character and can be * stored in a windows WORD */ for (i = 0; i < length; i++) { buf[i] = glyphs[i]; } SelectObject(hDC, hFont); GetTextExtentPoint32W(hDC, buf, length, &sBoundBox); h = sBoundBox.cy; if ([path elementCount] > 0) { startPoint = [path currentPoint]; } else { startPoint = NSZeroPoint; } SetBkMode(hDC, TRANSPARENT); BeginPath(hDC); SetTextAlign(hDC, TA_LEFT | TA_TOP); TextOutW(hDC, startPoint.x, -startPoint.y, buf, length); EndPath(hDC); iPoints = GetPath(hDC, NULL, NULL, 0); if (iPoints == 0) { DeleteDC(hDC); return; } ptPoints = objc_malloc(sizeof(POINT) * iPoints); if (!ptPoints) { DeleteDC(hDC); return; } bTypes = objc_malloc(sizeof(BYTE) * iPoints); if (!bTypes) { objc_free(ptPoints); DeleteDC(hDC); return; } GetPath(hDC, ptPoints, bTypes, iPoints); // Now append the glyphs to the path i = 0; while (i < iPoints) { if (bTypes[i] == PT_MOVETO) { [path moveToPoint: NSMakePoint(ptPoints[i].x, h - ptPoints[i].y)]; i++; } else if (bTypes[i] & PT_LINETO) { [path lineToPoint: NSMakePoint(ptPoints[i].x, h - ptPoints[i].y)]; if (bTypes[i] & PT_CLOSEFIGURE) [path closePath]; i++; } else if (bTypes[i] & PT_BEZIERTO) { // FIXME: We assume windows isn't lying here about the bezier points [path curveToPoint: NSMakePoint(ptPoints[i+2].x, h - ptPoints[i+2].y) controlPoint1: NSMakePoint(ptPoints[i].x, h - ptPoints[i].y) controlPoint2: NSMakePoint(ptPoints[i+1].x, h - ptPoints[i+1].y)]; if ((bTypes[i] & PT_CLOSEFIGURE) || (bTypes[i+1] & PT_CLOSEFIGURE) || (bTypes[i+2] & PT_CLOSEFIGURE)) [path closePath]; i += 3; } } objc_free(bTypes); objc_free(ptPoints); DeleteDC(hDC); } @end @implementation WIN32FontInfo (Private) - (BOOL) setupAttributes { HDC hdc; TEXTMETRICW metric; HFONT old; LOGFONTW logfont; NSRange range; //NSLog(@"Creating Font %@ of size %f", fontName, matrix[0]); ASSIGN(familyName, win32_font_family(fontName)); memset(&logfont, 0, sizeof(LOGFONT)); hdc = CreateCompatibleDC(NULL); // FIXME This hack gets the font size about right, but what is the real solution? logfont.lfHeight = (int)(matrix[0] * 4 / 3); //logfont.lfHeight = -MulDiv(matrix[0], GetDeviceCaps(hdc, LOGPIXELSY), 72); range = [fontName rangeOfString: @"Bold"]; if (range.length) logfont.lfWeight = FW_BOLD; range = [fontName rangeOfString: @"Italic"]; if (range.length) logfont.lfItalic = 1; logfont.lfQuality = ANTIALIASED_QUALITY; wcsncpy(logfont.lfFaceName, (const unichar*)[familyName cStringUsingEncoding: NSUnicodeStringEncoding], LF_FACESIZE); hFont = CreateFontIndirectW(&logfont); if (!hFont) { NSLog(@"Could not create font %@", fontName); DeleteDC(hdc); return NO; } old = SelectObject(hdc, hFont); GetTextMetricsW(hdc, &metric); SelectObject(hdc, old); DeleteDC(hdc); // Fill the ivars isFixedPitch = TMPF_FIXED_PITCH & metric.tmPitchAndFamily; isBaseFont = NO; ascender = metric.tmAscent; //NSLog(@"Resulted in height %d and ascent %d", metric.tmHeight, metric.tmAscent); descender = -metric.tmDescent; /* TODO */ xHeight = ascender * 0.5; maximumAdvancement = NSMakeSize((float)metric.tmMaxCharWidth, 0.0); fontBBox = NSMakeRect((float)(0), (float)(0 - metric.tmAscent), (float)metric.tmMaxCharWidth, (float)metric.tmHeight); weight = win32_font_weight(metric.tmWeight); traits = 0; if (weight >= 9) traits |= NSBoldFontMask; else traits |= NSUnboldFontMask; if (metric.tmItalic) traits |= NSItalicFontMask; else traits |= NSUnitalicFontMask; // FIXME Should come from metric.tmCharSet mostCompatibleStringEncoding = NSISOLatin1StringEncoding; return YES; } @end