gecko-dev/gfx/thebes/gfxMacPlatformFontList.mm
Zack Weinberg 95de3783f6 Bug 571989 part 3: Flatten directory structure below gfx/thebes.
--HG--
rename : gfx/thebes/src/GLContext.cpp => gfx/thebes/GLContext.cpp
rename : gfx/thebes/public/GLContext.h => gfx/thebes/GLContext.h
rename : gfx/thebes/public/GLContextProvider.h => gfx/thebes/GLContextProvider.h
rename : gfx/thebes/src/GLContextProviderCGL.mm => gfx/thebes/GLContextProviderCGL.mm
rename : gfx/thebes/src/GLContextProviderEGL.cpp => gfx/thebes/GLContextProviderEGL.cpp
rename : gfx/thebes/src/GLContextProviderGLX.cpp => gfx/thebes/GLContextProviderGLX.cpp
rename : gfx/thebes/src/GLContextProviderNull.cpp => gfx/thebes/GLContextProviderNull.cpp
rename : gfx/thebes/src/GLContextProviderOSMesa.cpp => gfx/thebes/GLContextProviderOSMesa.cpp
rename : gfx/thebes/src/GLContextProviderWGL.cpp => gfx/thebes/GLContextProviderWGL.cpp
rename : gfx/thebes/public/GLDefs.h => gfx/thebes/GLDefs.h
rename : gfx/thebes/public/GLXLibrary.h => gfx/thebes/GLXLibrary.h
rename : gfx/thebes/public/WGLLibrary.h => gfx/thebes/WGLLibrary.h
rename : gfx/thebes/src/cairo-gdk-utils.c => gfx/thebes/cairo-gdk-utils.c
rename : gfx/thebes/src/cairo-gdk-utils.h => gfx/thebes/cairo-gdk-utils.h
rename : gfx/thebes/src/cairo-xlib-utils.c => gfx/thebes/cairo-xlib-utils.c
rename : gfx/thebes/src/cairo-xlib-utils.h => gfx/thebes/cairo-xlib-utils.h
rename : gfx/thebes/src/genUnicodeScriptData.pl => gfx/thebes/genUnicodeScriptData.pl
rename : gfx/thebes/public/gfx3DMatrix.h => gfx/thebes/gfx3DMatrix.h
rename : gfx/thebes/src/gfxASurface.cpp => gfx/thebes/gfxASurface.cpp
rename : gfx/thebes/public/gfxASurface.h => gfx/thebes/gfxASurface.h
rename : gfx/thebes/src/gfxAlphaRecovery.cpp => gfx/thebes/gfxAlphaRecovery.cpp
rename : gfx/thebes/public/gfxAlphaRecovery.h => gfx/thebes/gfxAlphaRecovery.h
rename : gfx/thebes/src/gfxAndroidPlatform.cpp => gfx/thebes/gfxAndroidPlatform.cpp
rename : gfx/thebes/public/gfxAndroidPlatform.h => gfx/thebes/gfxAndroidPlatform.h
rename : gfx/thebes/src/gfxAtomList.h => gfx/thebes/gfxAtomList.h
rename : gfx/thebes/src/gfxAtoms.cpp => gfx/thebes/gfxAtoms.cpp
rename : gfx/thebes/src/gfxAtoms.h => gfx/thebes/gfxAtoms.h
rename : gfx/thebes/src/gfxBeOSPlatform.cpp => gfx/thebes/gfxBeOSPlatform.cpp
rename : gfx/thebes/public/gfxBeOSPlatform.h => gfx/thebes/gfxBeOSPlatform.h
rename : gfx/thebes/src/gfxBeOSSurface.cpp => gfx/thebes/gfxBeOSSurface.cpp
rename : gfx/thebes/public/gfxBeOSSurface.h => gfx/thebes/gfxBeOSSurface.h
rename : gfx/thebes/public/gfxColor.h => gfx/thebes/gfxColor.h
rename : gfx/thebes/src/gfxContext.cpp => gfx/thebes/gfxContext.cpp
rename : gfx/thebes/public/gfxContext.h => gfx/thebes/gfxContext.h
rename : gfx/thebes/src/gfxCoreTextShaper.cpp => gfx/thebes/gfxCoreTextShaper.cpp
rename : gfx/thebes/src/gfxCoreTextShaper.h => gfx/thebes/gfxCoreTextShaper.h
rename : gfx/thebes/src/gfxD2DSurface.cpp => gfx/thebes/gfxD2DSurface.cpp
rename : gfx/thebes/public/gfxD2DSurface.h => gfx/thebes/gfxD2DSurface.h
rename : gfx/thebes/src/gfxDDrawSurface.cpp => gfx/thebes/gfxDDrawSurface.cpp
rename : gfx/thebes/public/gfxDDrawSurface.h => gfx/thebes/gfxDDrawSurface.h
rename : gfx/thebes/src/gfxDWriteCommon.cpp => gfx/thebes/gfxDWriteCommon.cpp
rename : gfx/thebes/src/gfxDWriteCommon.h => gfx/thebes/gfxDWriteCommon.h
rename : gfx/thebes/src/gfxDWriteFontList.cpp => gfx/thebes/gfxDWriteFontList.cpp
rename : gfx/thebes/src/gfxDWriteFontList.h => gfx/thebes/gfxDWriteFontList.h
rename : gfx/thebes/src/gfxDWriteFonts.cpp => gfx/thebes/gfxDWriteFonts.cpp
rename : gfx/thebes/public/gfxDWriteFonts.h => gfx/thebes/gfxDWriteFonts.h
rename : gfx/thebes/src/gfxDWriteShaper.cpp => gfx/thebes/gfxDWriteShaper.cpp
rename : gfx/thebes/src/gfxDWriteShaper.h => gfx/thebes/gfxDWriteShaper.h
rename : gfx/thebes/src/gfxDWriteTextAnalysis.cpp => gfx/thebes/gfxDWriteTextAnalysis.cpp
rename : gfx/thebes/src/gfxDWriteTextAnalysis.h => gfx/thebes/gfxDWriteTextAnalysis.h
rename : gfx/thebes/src/gfxDirectFBSurface.cpp => gfx/thebes/gfxDirectFBSurface.cpp
rename : gfx/thebes/public/gfxDirectFBSurface.h => gfx/thebes/gfxDirectFBSurface.h
rename : gfx/thebes/src/gfxDllDeps.cpp => gfx/thebes/gfxDllDeps.cpp
rename : gfx/thebes/src/gfxFT2FontBase.cpp => gfx/thebes/gfxFT2FontBase.cpp
rename : gfx/thebes/public/gfxFT2FontBase.h => gfx/thebes/gfxFT2FontBase.h
rename : gfx/thebes/src/gfxFT2FontList.cpp => gfx/thebes/gfxFT2FontList.cpp
rename : gfx/thebes/src/gfxFT2FontList.h => gfx/thebes/gfxFT2FontList.h
rename : gfx/thebes/src/gfxFT2Fonts.cpp => gfx/thebes/gfxFT2Fonts.cpp
rename : gfx/thebes/public/gfxFT2Fonts.h => gfx/thebes/gfxFT2Fonts.h
rename : gfx/thebes/src/gfxFT2Utils.cpp => gfx/thebes/gfxFT2Utils.cpp
rename : gfx/thebes/src/gfxFT2Utils.h => gfx/thebes/gfxFT2Utils.h
rename : gfx/thebes/src/gfxFont.cpp => gfx/thebes/gfxFont.cpp
rename : gfx/thebes/public/gfxFont.h => gfx/thebes/gfxFont.h
rename : gfx/thebes/public/gfxFontConstants.h => gfx/thebes/gfxFontConstants.h
rename : gfx/thebes/src/gfxFontMissingGlyphs.cpp => gfx/thebes/gfxFontMissingGlyphs.cpp
rename : gfx/thebes/src/gfxFontMissingGlyphs.h => gfx/thebes/gfxFontMissingGlyphs.h
rename : gfx/thebes/src/gfxFontTest.cpp => gfx/thebes/gfxFontTest.cpp
rename : gfx/thebes/public/gfxFontTest.h => gfx/thebes/gfxFontTest.h
rename : gfx/thebes/src/gfxFontUtils.cpp => gfx/thebes/gfxFontUtils.cpp
rename : gfx/thebes/public/gfxFontUtils.h => gfx/thebes/gfxFontUtils.h
rename : gfx/thebes/src/gfxFontconfigUtils.cpp => gfx/thebes/gfxFontconfigUtils.cpp
rename : gfx/thebes/src/gfxFontconfigUtils.h => gfx/thebes/gfxFontconfigUtils.h
rename : gfx/thebes/src/gfxGDIFont.cpp => gfx/thebes/gfxGDIFont.cpp
rename : gfx/thebes/src/gfxGDIFont.h => gfx/thebes/gfxGDIFont.h
rename : gfx/thebes/src/gfxGDIFontList.cpp => gfx/thebes/gfxGDIFontList.cpp
rename : gfx/thebes/src/gfxGDIFontList.h => gfx/thebes/gfxGDIFontList.h
rename : gfx/thebes/src/gfxGDIShaper.cpp => gfx/thebes/gfxGDIShaper.cpp
rename : gfx/thebes/src/gfxGDIShaper.h => gfx/thebes/gfxGDIShaper.h
rename : gfx/thebes/src/gfxGdkNativeRenderer.cpp => gfx/thebes/gfxGdkNativeRenderer.cpp
rename : gfx/thebes/public/gfxGdkNativeRenderer.h => gfx/thebes/gfxGdkNativeRenderer.h
rename : gfx/thebes/public/gfxGlitzSurface.h => gfx/thebes/gfxGlitzSurface.h
rename : gfx/thebes/src/gfxHarfBuzzShaper.cpp => gfx/thebes/gfxHarfBuzzShaper.cpp
rename : gfx/thebes/src/gfxHarfBuzzShaper.h => gfx/thebes/gfxHarfBuzzShaper.h
rename : gfx/thebes/src/gfxImageSurface.cpp => gfx/thebes/gfxImageSurface.cpp
rename : gfx/thebes/public/gfxImageSurface.h => gfx/thebes/gfxImageSurface.h
rename : gfx/thebes/src/gfxMacFont.cpp => gfx/thebes/gfxMacFont.cpp
rename : gfx/thebes/src/gfxMacFont.h => gfx/thebes/gfxMacFont.h
rename : gfx/thebes/src/gfxMacPlatformFontList.h => gfx/thebes/gfxMacPlatformFontList.h
rename : gfx/thebes/src/gfxMacPlatformFontList.mm => gfx/thebes/gfxMacPlatformFontList.mm
rename : gfx/thebes/src/gfxMatrix.cpp => gfx/thebes/gfxMatrix.cpp
rename : gfx/thebes/public/gfxMatrix.h => gfx/thebes/gfxMatrix.h
rename : gfx/thebes/src/gfxOS2Fonts.cpp => gfx/thebes/gfxOS2Fonts.cpp
rename : gfx/thebes/public/gfxOS2Fonts.h => gfx/thebes/gfxOS2Fonts.h
rename : gfx/thebes/src/gfxOS2Platform.cpp => gfx/thebes/gfxOS2Platform.cpp
rename : gfx/thebes/public/gfxOS2Platform.h => gfx/thebes/gfxOS2Platform.h
rename : gfx/thebes/src/gfxOS2Surface.cpp => gfx/thebes/gfxOS2Surface.cpp
rename : gfx/thebes/public/gfxOS2Surface.h => gfx/thebes/gfxOS2Surface.h
rename : gfx/thebes/src/gfxPDFSurface.cpp => gfx/thebes/gfxPDFSurface.cpp
rename : gfx/thebes/public/gfxPDFSurface.h => gfx/thebes/gfxPDFSurface.h
rename : gfx/thebes/src/gfxPSSurface.cpp => gfx/thebes/gfxPSSurface.cpp
rename : gfx/thebes/public/gfxPSSurface.h => gfx/thebes/gfxPSSurface.h
rename : gfx/thebes/src/gfxPangoFonts.cpp => gfx/thebes/gfxPangoFonts.cpp
rename : gfx/thebes/public/gfxPangoFonts.h => gfx/thebes/gfxPangoFonts.h
rename : gfx/thebes/src/gfxPath.cpp => gfx/thebes/gfxPath.cpp
rename : gfx/thebes/public/gfxPath.h => gfx/thebes/gfxPath.h
rename : gfx/thebes/src/gfxPattern.cpp => gfx/thebes/gfxPattern.cpp
rename : gfx/thebes/public/gfxPattern.h => gfx/thebes/gfxPattern.h
rename : gfx/thebes/src/gfxPlatform.cpp => gfx/thebes/gfxPlatform.cpp
rename : gfx/thebes/public/gfxPlatform.h => gfx/thebes/gfxPlatform.h
rename : gfx/thebes/src/gfxPlatformFontList.cpp => gfx/thebes/gfxPlatformFontList.cpp
rename : gfx/thebes/src/gfxPlatformFontList.h => gfx/thebes/gfxPlatformFontList.h
rename : gfx/thebes/src/gfxPlatformGtk.cpp => gfx/thebes/gfxPlatformGtk.cpp
rename : gfx/thebes/public/gfxPlatformGtk.h => gfx/thebes/gfxPlatformGtk.h
rename : gfx/thebes/src/gfxPlatformMac.cpp => gfx/thebes/gfxPlatformMac.cpp
rename : gfx/thebes/public/gfxPlatformMac.h => gfx/thebes/gfxPlatformMac.h
rename : gfx/thebes/public/gfxPoint.h => gfx/thebes/gfxPoint.h
rename : gfx/thebes/src/gfxQPainterSurface.cpp => gfx/thebes/gfxQPainterSurface.cpp
rename : gfx/thebes/public/gfxQPainterSurface.h => gfx/thebes/gfxQPainterSurface.h
rename : gfx/thebes/src/gfxQtNativeRenderer.cpp => gfx/thebes/gfxQtNativeRenderer.cpp
rename : gfx/thebes/public/gfxQtNativeRenderer.h => gfx/thebes/gfxQtNativeRenderer.h
rename : gfx/thebes/src/gfxQtPlatform.cpp => gfx/thebes/gfxQtPlatform.cpp
rename : gfx/thebes/public/gfxQtPlatform.h => gfx/thebes/gfxQtPlatform.h
rename : gfx/thebes/src/gfxQuartzImageSurface.cpp => gfx/thebes/gfxQuartzImageSurface.cpp
rename : gfx/thebes/public/gfxQuartzImageSurface.h => gfx/thebes/gfxQuartzImageSurface.h
rename : gfx/thebes/src/gfxQuartzNativeDrawing.cpp => gfx/thebes/gfxQuartzNativeDrawing.cpp
rename : gfx/thebes/public/gfxQuartzNativeDrawing.h => gfx/thebes/gfxQuartzNativeDrawing.h
rename : gfx/thebes/src/gfxQuartzPDFSurface.cpp => gfx/thebes/gfxQuartzPDFSurface.cpp
rename : gfx/thebes/public/gfxQuartzPDFSurface.h => gfx/thebes/gfxQuartzPDFSurface.h
rename : gfx/thebes/src/gfxQuartzSurface.cpp => gfx/thebes/gfxQuartzSurface.cpp
rename : gfx/thebes/public/gfxQuartzSurface.h => gfx/thebes/gfxQuartzSurface.h
rename : gfx/thebes/src/gfxRect.cpp => gfx/thebes/gfxRect.cpp
rename : gfx/thebes/public/gfxRect.h => gfx/thebes/gfxRect.h
rename : gfx/thebes/src/gfxScriptItemizer.cpp => gfx/thebes/gfxScriptItemizer.cpp
rename : gfx/thebes/src/gfxScriptItemizer.h => gfx/thebes/gfxScriptItemizer.h
rename : gfx/thebes/src/gfxSharedImageSurface.cpp => gfx/thebes/gfxSharedImageSurface.cpp
rename : gfx/thebes/public/gfxSharedImageSurface.h => gfx/thebes/gfxSharedImageSurface.h
rename : gfx/thebes/src/gfxSkipChars.cpp => gfx/thebes/gfxSkipChars.cpp
rename : gfx/thebes/public/gfxSkipChars.h => gfx/thebes/gfxSkipChars.h
rename : gfx/thebes/src/gfxTextRunCache.cpp => gfx/thebes/gfxTextRunCache.cpp
rename : gfx/thebes/public/gfxTextRunCache.h => gfx/thebes/gfxTextRunCache.h
rename : gfx/thebes/src/gfxTextRunWordCache.cpp => gfx/thebes/gfxTextRunWordCache.cpp
rename : gfx/thebes/public/gfxTextRunWordCache.h => gfx/thebes/gfxTextRunWordCache.h
rename : gfx/thebes/public/gfxTypes.h => gfx/thebes/gfxTypes.h
rename : gfx/thebes/src/gfxUnicodeProperties.cpp => gfx/thebes/gfxUnicodeProperties.cpp
rename : gfx/thebes/src/gfxUnicodeProperties.h => gfx/thebes/gfxUnicodeProperties.h
rename : gfx/thebes/src/gfxUnicodePropertyData.cpp => gfx/thebes/gfxUnicodePropertyData.cpp
rename : gfx/thebes/src/gfxUniscribeShaper.cpp => gfx/thebes/gfxUniscribeShaper.cpp
rename : gfx/thebes/src/gfxUniscribeShaper.h => gfx/thebes/gfxUniscribeShaper.h
rename : gfx/thebes/src/gfxUserFontSet.cpp => gfx/thebes/gfxUserFontSet.cpp
rename : gfx/thebes/public/gfxUserFontSet.h => gfx/thebes/gfxUserFontSet.h
rename : gfx/thebes/src/gfxUtils.cpp => gfx/thebes/gfxUtils.cpp
rename : gfx/thebes/public/gfxUtils.h => gfx/thebes/gfxUtils.h
rename : gfx/thebes/src/gfxWindowsNativeDrawing.cpp => gfx/thebes/gfxWindowsNativeDrawing.cpp
rename : gfx/thebes/public/gfxWindowsNativeDrawing.h => gfx/thebes/gfxWindowsNativeDrawing.h
rename : gfx/thebes/src/gfxWindowsPlatform.cpp => gfx/thebes/gfxWindowsPlatform.cpp
rename : gfx/thebes/public/gfxWindowsPlatform.h => gfx/thebes/gfxWindowsPlatform.h
rename : gfx/thebes/src/gfxWindowsSurface.cpp => gfx/thebes/gfxWindowsSurface.cpp
rename : gfx/thebes/public/gfxWindowsSurface.h => gfx/thebes/gfxWindowsSurface.h
rename : gfx/thebes/src/gfxXlibNativeRenderer.cpp => gfx/thebes/gfxXlibNativeRenderer.cpp
rename : gfx/thebes/public/gfxXlibNativeRenderer.h => gfx/thebes/gfxXlibNativeRenderer.h
rename : gfx/thebes/src/gfxXlibSurface.cpp => gfx/thebes/gfxXlibSurface.cpp
rename : gfx/thebes/public/gfxXlibSurface.h => gfx/thebes/gfxXlibSurface.h
rename : gfx/thebes/src/ignorable.x-ccmap => gfx/thebes/ignorable.x-ccmap
rename : gfx/thebes/src/nsUnicodeRange.cpp => gfx/thebes/nsUnicodeRange.cpp
rename : gfx/thebes/src/nsUnicodeRange.h => gfx/thebes/nsUnicodeRange.h
rename : gfx/thebes/src/woff-private.h => gfx/thebes/woff-private.h
rename : gfx/thebes/src/woff.c => gfx/thebes/woff.c
rename : gfx/thebes/src/woff.h => gfx/thebes/woff.h
2010-06-28 10:37:23 -07:00

986 lines
34 KiB
Plaintext

/* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: BSD
*
* Copyright (C) 2006-2009 Mozilla Corporation. All rights reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
#include <Carbon/Carbon.h>
#import <AppKit/AppKit.h>
#include "gfxPlatformMac.h"
#include "gfxMacPlatformFontList.h"
#include "gfxMacFont.h"
#include "gfxUserFontSet.h"
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include <unistd.h>
#include <time.h>
class nsAutoreleasePool {
public:
nsAutoreleasePool()
{
mLocalPool = [[NSAutoreleasePool alloc] init];
}
~nsAutoreleasePool()
{
[mLocalPool release];
}
private:
NSAutoreleasePool *mLocalPool;
};
// font info loader constants
static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
// indexes into the NSArray objects that the Cocoa font manager returns
// as the available members of a family
#define INDEX_FONT_POSTSCRIPT_NAME 0
#define INDEX_FONT_FACE_NAME 1
#define INDEX_FONT_WEIGHT 2
#define INDEX_FONT_TRAITS 3
static const int kAppleMaxWeight = 14;
static const int kAppleExtraLightWeight = 3;
static const int kAppleUltraLightWeight = 2;
static const int gAppleWeightToCSSWeight[] = {
0,
1, // 1.
1, // 2. W1, ultralight
2, // 3. W2, extralight
3, // 4. W3, light
4, // 5. W4, semilight
5, // 6. W5, medium
6, // 7.
6, // 8. W6, semibold
7, // 9. W7, bold
8, // 10. W8, extrabold
8, // 11.
9, // 12. W9, ultrabold
9, // 13
9 // 14
};
// cache Cocoa's "shared font manager" for performance
static NSFontManager *sFontManager;
static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
{
aDist.SetLength([aSrc length]);
[aSrc getCharacters:aDist.BeginWriting()];
}
static NSString* GetNSStringForString(const nsAString& aSrc)
{
return [NSString stringWithCharacters:aSrc.BeginReading()
length:aSrc.Length()];
}
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
#endif /* PR_LOGGING */
#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
/* MacOSFontEntry */
#pragma mark-
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
PRInt32 aWeight,
gfxFontFamily *aFamily,
PRBool aIsStandardFace)
: gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace),
mATSFontRef(0),
mATSFontRefInitialized(PR_FALSE)
{
mWeight = aWeight;
}
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef,
PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
gfxUserFontData *aUserFontData)
: gfxFontEntry(aPostscriptName),
mATSFontRef(aFontRef),
mATSFontRefInitialized(PR_TRUE)
{
// xxx - stretch is basically ignored for now
mUserFontData = aUserFontData;
mWeight = aWeight;
mStretch = aStretch;
mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
mIsUserFont = aUserFontData != nsnull;
}
ATSFontRef
MacOSFontEntry::GetFontRef()
{
if (!mATSFontRefInitialized) {
mATSFontRefInitialized = PR_TRUE;
NSString *psname = GetNSStringForString(mName);
mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname),
kATSOptionFlagsDefault);
}
return mATSFontRef;
}
// ATSUI requires AAT-enabled fonts to render complex scripts correctly.
// For now, simple clear out the cmap codepoints for fonts that have
// codepoints for complex scripts. (Bug 361986)
// Core Text is similar, but can render Arabic using OpenType fonts as well.
enum eComplexScript {
eComplexScriptArabic,
eComplexScriptIndic,
eComplexScriptTibetan
};
struct ScriptRange {
eComplexScript script;
PRUint32 rangeStart;
PRUint32 rangeEnd;
};
const ScriptRange gScriptsThatRequireShaping[] = {
{ eComplexScriptArabic, 0x0600, 0x077F }, // Basic Arabic and Arabic Supplement
{ eComplexScriptIndic, 0x0900, 0x0D7F }, // Indic scripts - Devanagari, Bengali, ..., Malayalam
{ eComplexScriptTibetan, 0x0F00, 0x0FFF } // Tibetan
// Thai seems to be "renderable" without AAT morphing tables
// xxx - Lao, Khmer?
};
nsresult
MacOSFontEntry::ReadCMAP()
{
OSStatus status;
ByteCount size;
// attempt this once, if errors occur leave a blank cmap
if (mCmapInitialized)
return NS_OK;
mCmapInitialized = PR_TRUE;
PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
nsAutoTArray<PRUint8,16384> cmap;
if (GetFontTable(kCMAP, cmap) != NS_OK)
return NS_ERROR_FAILURE;
PRPackedBool unicodeFont, symbolFont; // currently ignored
nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
mCharacterMap, mUVSOffset, unicodeFont, symbolFont);
if (NS_FAILED(rv)) {
mCharacterMap.reset();
return rv;
}
mHasCmapTable = PR_TRUE;
// for complex scripts, check for the presence of mort/morx
PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
ATSFontRef fontRef = GetFontRef();
PRUint32 s, numScripts = sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
for (s = 0; s < numScripts; s++) {
eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
// check to see if the cmap includes complex script codepoints
if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd)) {
PRBool omitRange = PR_TRUE;
// check for mort/morx table, if haven't already
if (!checkedForMorphTable) {
status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','x'), 0, 0, 0, &size);
if (status == noErr) {
checkedForMorphTable = PR_TRUE;
hasMorphTable = PR_TRUE;
} else {
// check for a mort table
status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','t'), 0, 0, 0, &size);
checkedForMorphTable = PR_TRUE;
if (status == noErr) {
hasMorphTable = PR_TRUE;
}
}
}
if (hasMorphTable) {
omitRange = PR_FALSE;
}
// special-cases for Arabic:
if (whichScript == eComplexScriptArabic) {
// even if there's no morph table, CoreText can shape Arabic
// if there's GSUB support
status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('G','S','U','B'), 0, 0, 0, &size);
if (status == noErr) {
// TODO: to be really thorough, we could check that the GSUB table
// actually supports the 'arab' script tag.
omitRange = PR_FALSE;
}
// rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but
// lack the proper info for shaping Arabic, so exclude explicitly, ick
if (mName.CharAt(0) == 'S' && mName.CharAt(1) == 'T') {
omitRange = PR_TRUE;
}
}
if (omitRange) {
mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart,
gScriptsThatRequireShaping[s].rangeEnd);
}
}
}
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
return rv;
}
nsresult
MacOSFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
{
nsAutoreleasePool localPool;
ATSFontRef fontRef = GetFontRef();
if (fontRef == (ATSFontRef)kATSUInvalidFontID) {
return NS_ERROR_FAILURE;
}
ByteCount dataLength;
OSStatus status = ::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &dataLength);
if (status != noErr) {
return NS_ERROR_FAILURE;
}
if (!aBuffer.AppendElements(dataLength)) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRUint8 *dataPtr = aBuffer.Elements();
status = ::ATSFontGetTable(fontRef, aTableTag, 0, dataLength, dataPtr, &dataLength);
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
return NS_OK;
}
gfxFont*
MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold)
{
return new gfxMacFont(this, aFontStyle, aNeedsBold);
}
/* gfxMacFontFamily */
#pragma mark-
class gfxMacFontFamily : public gfxFontFamily
{
public:
gfxMacFontFamily(nsAString& aName) :
gfxFontFamily(aName)
{}
virtual ~gfxMacFontFamily() {}
virtual void LocalizedName(nsAString& aLocalizedName);
virtual void FindStyleVariations();
void EliminateDuplicateFaces();
};
void
gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName)
{
nsAutoreleasePool localPool;
if (!HasOtherFamilyNames()) {
aLocalizedName = mName;
return;
}
NSString *family = GetNSStringForString(mName);
NSString *localized = [sFontManager
localizedNameForFamily:family
face:nil];
if (localized) {
GetStringForNSString(localized, aLocalizedName);
return;
}
// failed to get localized name, just use the canonical one
aLocalizedName = mName;
}
void
gfxMacFontFamily::FindStyleVariations()
{
if (mHasStyles)
return;
nsAutoreleasePool localPool;
NSString *family = GetNSStringForString(mName);
// create a font entry for each face
NSArray *fontfaces = [sFontManager
availableMembersOfFontFamily:family]; // returns an array of [psname, style name, weight, traits] elements, goofy api
int faceCount = [fontfaces count];
int faceIndex;
// Bug 420981 - under 10.5, UltraLight and Light have the same weight value
PRBool needToCheckLightFaces =
(gfxPlatformMac::GetPlatform()->OSXVersion() >= MAC_OS_X_VERSION_10_5_HEX);
for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
NSArray *face = [fontfaces objectAtIndex:faceIndex];
NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
PRInt32 appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
PRUint32 macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
NSString *facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
PRBool isStandardFace = PR_FALSE;
if (needToCheckLightFaces && appKitWeight == kAppleExtraLightWeight) {
// if the facename contains UltraLight, set the weight to the ultralight weight value
NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
appKitWeight = kAppleUltraLightWeight;
}
}
PRInt32 cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight) * 100;
// make a nsString
nsAutoString postscriptFontName;
GetStringForNSString(psname, postscriptFontName);
if ([facename isEqualToString:@"Regular"] ||
[facename isEqualToString:@"Bold"] ||
[facename isEqualToString:@"Italic"] ||
[facename isEqualToString:@"Oblique"] ||
[facename isEqualToString:@"Bold Italic"] ||
[facename isEqualToString:@"Bold Oblique"])
{
isStandardFace = PR_TRUE;
}
// create a font entry
MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName,
cssWeight, this, isStandardFace);
if (!fontEntry) break;
// set additional properties based on the traits reported by Cocoa
if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
fontEntry->mStretch = NS_FONT_STRETCH_CONDENSED;
} else if (macTraits & NSExpandedFontMask) {
fontEntry->mStretch = NS_FONT_STRETCH_EXPANDED;
}
if (macTraits & NSItalicFontMask) {
fontEntry->mItalic = PR_TRUE;
}
if (macTraits & NSFixedPitchFontMask) {
fontEntry->mFixedPitch = PR_TRUE;
}
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("(fontinit) added (%s) to family (%s)"
" with style: %s weight: %d stretch: %d"
" (apple-weight: %d macTraits: %8.8x)",
NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
NS_ConvertUTF16toUTF8(Name()).get(),
fontEntry->IsItalic() ? "italic" : "normal",
cssWeight, fontEntry->Stretch(),
appKitWeight, macTraits));
}
#endif
// insert into font entry array of family
AddFontEntry(fontEntry);
}
SortAvailableFonts();
SetHasStyles(PR_TRUE);
if (mIsBadUnderlineFamily) {
SetBadUnderlineFonts();
}
}
void
gfxMacFontFamily::EliminateDuplicateFaces()
{
PRUint32 i, bold, numFonts, italicIndex;
MacOSFontEntry *italic, *nonitalic;
FindStyleVariations();
// if normal and italic have the same ATS font ref, delete italic
// if bold and bold-italic have the same ATS font ref, delete bold-italic
// two iterations, one for normal, one for bold
for (bold = 0; bold < 2; bold++) {
numFonts = mAvailableFonts.Length();
// find the non-italic face
nonitalic = nsnull;
for (i = 0; i < numFonts; i++) {
if ((mAvailableFonts[i]->IsBold() == (bold == 1)) &&
!mAvailableFonts[i]->IsItalic()) {
nonitalic = static_cast<MacOSFontEntry*>(mAvailableFonts[i].get());
break;
}
}
// find the italic face
if (nonitalic) {
italic = nsnull;
for (i = 0; i < numFonts; i++) {
if ((mAvailableFonts[i]->IsBold() == (bold == 1)) &&
mAvailableFonts[i]->IsItalic()) {
italic = static_cast<MacOSFontEntry*>(mAvailableFonts[i].get());
italicIndex = i;
break;
}
}
// if italic face and non-italic face have matching ATS refs,
// or if the italic returns 0 rather than an actual ATSFontRef,
// then the italic face is bogus so remove it
if (italic && (italic->GetFontRef() == 0 ||
italic->GetFontRef() == nonitalic->GetFontRef())) {
mAvailableFonts.RemoveElementAt(italicIndex);
}
}
}
}
/* gfxSingleFaceMacFontFamily */
#pragma mark-
class gfxSingleFaceMacFontFamily : public gfxFontFamily
{
public:
gfxSingleFaceMacFontFamily(nsAString& aName) :
gfxFontFamily(aName)
{}
virtual ~gfxSingleFaceMacFontFamily() {}
virtual void LocalizedName(nsAString& aLocalizedName);
virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
};
void
gfxSingleFaceMacFontFamily::LocalizedName(nsAString& aLocalizedName)
{
nsAutoreleasePool localPool;
if (!HasOtherFamilyNames()) {
aLocalizedName = mName;
return;
}
gfxFontEntry *fe = mAvailableFonts[0];
NSFont *font = [NSFont fontWithName:GetNSStringForString(fe->Name())
size:0.0];
if (font) {
NSString *localized = [font displayName];
if (localized) {
GetStringForNSString(localized, aLocalizedName);
return;
}
}
// failed to get localized name, just use the canonical one
aLocalizedName = mName;
}
void
gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
{
if (mOtherFamilyNamesInitialized)
return;
gfxFontEntry *fe = mAvailableFonts[0];
if (!fe)
return;
const PRUint32 kNAME = TRUETYPE_TAG('n','a','m','e');
nsAutoTArray<PRUint8,8192> buffer;
if (fe->GetFontTable(kNAME, buffer) != NS_OK)
return;
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
buffer,
PR_TRUE);
mOtherFamilyNamesInitialized = PR_TRUE;
}
/* gfxMacPlatformFontList */
#pragma mark-
gfxMacPlatformFontList::gfxMacPlatformFontList() :
gfxPlatformFontList(PR_FALSE), mATSGeneration(PRUint32(kATSGenerationInitial))
{
::ATSFontNotificationSubscribe(ATSNotification,
kATSFontNotifyOptionDefault,
(void*)this, nsnull);
// this should always be available (though we won't actually fail if it's missing,
// we'll just end up doing a search and then caching the new result instead)
mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
// cache this in a static variable so that MacOSFontFamily objects
// don't have to repeatedly look it up
sFontManager = [NSFontManager sharedFontManager];
}
void
gfxMacPlatformFontList::InitFontList()
{
nsAutoreleasePool localPool;
ATSGeneration currentGeneration = ::ATSGetGeneration();
// need to ignore notifications after adding each font
if (mATSGeneration == currentGeneration)
return;
mATSGeneration = currentGeneration;
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
// reset font lists
gfxPlatformFontList::InitFontList();
// iterate over available families
NSEnumerator *families = [[sFontManager availableFontFamilies]
objectEnumerator]; // returns "canonical", non-localized family name
nsAutoString availableFamilyName;
NSString *availableFamily = nil;
while ((availableFamily = [families nextObject])) {
// make a nsString
GetStringForNSString(availableFamily, availableFamilyName);
// create a family entry
gfxFontFamily *familyEntry = new gfxMacFontFamily(availableFamilyName);
if (!familyEntry) break;
// add the family entry to the hash table
ToLowerCase(availableFamilyName);
mFontFamilies.Put(availableFamilyName, familyEntry);
// check the bad underline blacklist
if (mBadUnderlineFamilyNames.Contains(availableFamilyName))
familyEntry->SetBadUnderlineFamily();
}
InitSingleFaceList();
// to avoid full search of font name tables, seed the other names table with localized names from
// some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
// a font lookup miss earlier. this is a simple optimization, it's not required for correctness
PreloadNamesList();
// clean up various minor 10.4 font problems for specific fonts
if (gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_5_HEX) {
// Cocoa calls report that italic faces exist for Courier and Helvetica,
// even though only bold faces exist so test for this using ATS font refs (10.5 has proper faces)
EliminateDuplicateFaces(NS_LITERAL_STRING("Courier"));
EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica"));
// Cocoa reports that Courier and Monaco are not fixed-pitch fonts
// so explicitly tweak these settings
SetFixedPitch(NS_LITERAL_STRING("Courier"));
SetFixedPitch(NS_LITERAL_STRING("Monaco"));
}
// start the delayed cmap loader
StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
}
void
gfxMacPlatformFontList::InitSingleFaceList()
{
nsAutoTArray<nsString, 10> singleFaceFonts;
gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
PRUint32 numFonts = singleFaceFonts.Length();
for (PRUint32 i = 0; i < numFonts; i++) {
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) face name: %s\n",
NS_ConvertUTF16toUTF8(singleFaceFonts[i]).get()));
gfxFontEntry *fontEntry = LookupLocalFont(nsnull, singleFaceFonts[i]);
if (fontEntry) {
nsAutoString familyName, key;
familyName = singleFaceFonts[i];
GenerateFontListKey(familyName, key);
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) family name: %s, key: %s\n",
NS_ConvertUTF16toUTF8(familyName).get(), NS_ConvertUTF16toUTF8(key).get()));
// add only if doesn't exist already
PRBool found;
gfxFontFamily *familyEntry;
if (!(familyEntry = mFontFamilies.GetWeak(key, &found))) {
familyEntry = new gfxSingleFaceMacFontFamily(familyName);
familyEntry->AddFontEntry(fontEntry);
familyEntry->SetHasStyles(PR_TRUE);
mFontFamilies.Put(key, familyEntry);
fontEntry->mFamily = familyEntry;
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) added new family\n",
NS_ConvertUTF16toUTF8(familyName).get(), NS_ConvertUTF16toUTF8(key).get()));
}
}
}
}
void
gfxMacPlatformFontList::EliminateDuplicateFaces(const nsAString& aFamilyName)
{
gfxMacFontFamily *family =
static_cast<gfxMacFontFamily*>(FindFamily(aFamilyName));
if (family)
family->EliminateDuplicateFaces();
}
PRBool
gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
gfxFontFamily *family = FindFamily(aFontName);
if (family) {
family->LocalizedName(aFamilyName);
return PR_TRUE;
}
// Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
// names. Try to resolve based on these names, in case this is stored in an old profile
// 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura"
// convert the name to a Pascal-style Str255 to try as Quickdraw name
Str255 qdname;
NS_ConvertUTF16toUTF8 utf8name(aFontName);
qdname[0] = PR_MAX(255, strlen(utf8name.get()));
memcpy(&qdname[1], utf8name.get(), qdname[0]);
// look up the Quickdraw name
ATSFontFamilyRef atsFamily = ::ATSFontFamilyFindFromQuickDrawName(qdname);
if (atsFamily == (ATSFontFamilyRef)kInvalidFontFamily) {
return PR_FALSE;
}
// if we found a family, get its ATS name
CFStringRef cfName;
OSStatus status = ::ATSFontFamilyGetName(atsFamily, kATSOptionFlagsDefault, &cfName);
if (status != noErr) {
return PR_FALSE;
}
// then use this to locate the family entry and retrieve its localized name
nsAutoString familyName;
GetStringForNSString((const NSString*)cfName, familyName);
::CFRelease(cfName);
family = FindFamily(familyName);
if (family) {
family->LocalizedName(aFamilyName);
return PR_TRUE;
}
return PR_FALSE;
}
void
gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
void* aUserArg)
{
// xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
gfxMacPlatformFontList *qfc = (gfxMacPlatformFontList*)aUserArg;
qfc->UpdateFontList();
}
gfxFontEntry*
gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
{
nsAutoreleasePool localPool;
NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
nsAutoString familyName;
GetStringForNSString(defaultFamily, familyName);
return FindFontForFamily(familyName, aStyle, aNeedsBold);
}
PRInt32
gfxMacPlatformFontList::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
{
if (aAppleWeight < 1)
aAppleWeight = 1;
else if (aAppleWeight > kAppleMaxWeight)
aAppleWeight = kAppleMaxWeight;
return gAppleWeightToCSSWeight[aAppleWeight];
}
gfxFontEntry*
gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName)
{
nsAutoreleasePool localPool;
NSString *faceName = GetNSStringForString(aFontName);
// first lookup a single face based on postscript name
ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName),
kATSOptionFlagsDefault);
// if not found, lookup using full font name
if (fontRef == kInvalidFont)
fontRef = ::ATSFontFindFromName(CFStringRef(faceName),
kATSOptionFlagsDefault);
// not found
if (fontRef == kInvalidFont)
return nsnull;
MacOSFontEntry *newFontEntry;
if (aProxyEntry) {
PRUint16 w = aProxyEntry->mWeight;
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
newFontEntry =
new MacOSFontEntry(aFontName, fontRef,
w, aProxyEntry->mStretch,
aProxyEntry->mItalic ?
FONT_STYLE_ITALIC : FONT_STYLE_NORMAL,
nsnull);
} else {
newFontEntry =
new MacOSFontEntry(aFontName, fontRef,
400, 0, FONT_STYLE_NORMAL, nsnull);
}
return newFontEntry;
}
// grumble, another non-publised Apple API dependency (found in Webkit code)
// activated with this value, font will not be found via system lookup routines
// it can only be used via the created ATSFontRef
// needed to prevent one doc from finding a font used in a separate doc
enum {
kPrivateATSFontContextPrivate = 3
};
class MacOSUserFontData : public gfxUserFontData {
public:
MacOSUserFontData(ATSFontContainerRef aContainerRef)
: mContainerRef(aContainerRef)
{ }
virtual ~MacOSUserFontData()
{
// deactivate font
if (mContainerRef)
::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
}
ATSFontContainerRef mContainerRef;
};
gfxFontEntry*
gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
OSStatus err;
NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
// MakePlatformFont is responsible for deleting the font data with NS_Free
// so we set up a stack object to ensure it is freed even if we take an
// early exit
struct FontDataDeleter {
FontDataDeleter(const PRUint8 *aFontData)
: mFontData(aFontData) { }
~FontDataDeleter() { NS_Free((void*)mFontData); }
const PRUint8 *mFontData;
};
FontDataDeleter autoDelete(aFontData);
ATSFontRef fontRef;
ATSFontContainerRef containerRef;
// we get occasional failures when multiple fonts are activated in quick succession
// if the ATS font cache is damaged; to work around this, we can retry the activation
const PRUint32 kMaxRetries = 3;
PRUint32 retryCount = 0;
while (retryCount++ < kMaxRetries) {
err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
kPrivateATSFontContextPrivate,
kATSFontFormatUnspecified,
NULL,
kATSOptionFlagsDoNotNotify,
&containerRef);
mATSGeneration = ::ATSGetGeneration();
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
return nsnull;
}
// ignoring containers with multiple fonts, use the first face only for now
err = ::ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
&fontRef, NULL);
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
// now lookup the Postscript name; this may fail if the font cache is bad
OSStatus err;
NSString *psname = NULL;
err = ::ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
if (err == noErr) {
[psname release];
} else {
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), retryCount);
NS_WARNING(warnBuf);
#endif
::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
// retry the activation a couple of times if this fails
// (may be a transient failure due to ATS font cache issues)
continue;
}
// font entry will own this
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
if (!userFontData) {
::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
PRUint16 w = aProxyEntry->mWeight;
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
// create the font entry
nsAutoString uniqueName;
nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
if (NS_FAILED(rv)) {
delete userFontData;
return nsnull;
}
MacOSFontEntry *newFontEntry =
new MacOSFontEntry(uniqueName,
fontRef,
w, aProxyEntry->mStretch,
aProxyEntry->mItalic ?
FONT_STYLE_ITALIC : FONT_STYLE_NORMAL,
userFontData);
if (!newFontEntry) {
delete userFontData;
return nsnull;
}
// if succeeded and font cmap is good, return the new font
if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP()))
return newFontEntry;
// if something is funky about this font, delete immediately
#if DEBUG
char warnBuf[1024];
sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
delete newFontEntry;
// We don't retry from here; the ATS font cache issue would have caused failure earlier
// so if we get here, there's something else bad going on within our font data structures.
// Currently, there should be no way to reach here, as fontentry creation cannot fail
// except by memory allocation failure.
NS_WARNING("invalid font entry for a newly activated font");
break;
}
// if we get here, the activation failed (even with possible retries); can't use this font
return nsnull;
}