/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Roland Mainz * Ervin Yan * Christopher Blizzard * Jungshik Shin * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "gfx-config.h" #include "nsFontMetricsPS.h" #include "nsDeviceContextPS.h" #include "nsRenderingContextPS.h" #include "nsIServiceManager.h" #include "nsGfxCIID.h" #include "nsIPref.h" #include "nsVoidArray.h" #include "nsReadableUtils.h" #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) #include "nsType1.h" #endif #include "prlog.h" #ifdef MOZ_ENABLE_FREETYPE2 #include "nsArray.h" #endif const PRUint16 nsPSFontGenerator::kSubFontSize = 255; extern nsIAtom *gUsersLocale; #define NS_IS_BOLD(weight) ((weight) > 400 ? 1 : 0) #ifdef MOZ_ENABLE_XFT #include "nsFontConfigUtils.h" static nsFontPS* CreateFontPS(nsXftEntry*, const nsFont&, nsFontMetricsPS*); #else #ifdef MOZ_ENABLE_FREETYPE2 static nsFontPS* CreateFontPS(nsITrueTypeFontCatalogEntry*, const nsFont&, nsFontMetricsPS*); static NS_DEFINE_CID(kFCSCID, NS_FONTCATALOGSERVICE_CID); #endif #endif #ifdef PR_LOGGING static PRLogModuleInfo *gFontMetricsPSM = PR_NewLogModule("FontMetricsPS"); #endif /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ nsFontMetricsPS :: nsFontMetricsPS() { } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ nsFontMetricsPS :: ~nsFontMetricsPS() { if (mFontsPS) { int i; for (i=0; iCount(); i++) { fontps *fontPS = (fontps *)mFontsPS->ElementAt(i); if (!fontPS) continue; if (fontPS->fontps) delete fontPS->fontps; #ifdef MOZ_ENABLE_XFT if (fontPS->entry) delete fontPS->entry; if (fontPS->charset) FcCharSetDestroy(fontPS->charset); #else #ifdef MOZ_ENABLE_FREETYPE2 NS_IF_RELEASE(fontPS->entry); if (fontPS->ccmap) FreeCCMap(fontPS->ccmap); #endif #endif delete fontPS; } delete mFontsPS; } if (mFontsAlreadyLoaded) { delete mFontsAlreadyLoaded; } if (mDeviceContext) { // Notify our device context that owns us so that it can update its font cache mDeviceContext->FontMetricsDeleted(this); mDeviceContext = nsnull; } } NS_IMPL_ISUPPORTS1(nsFontMetricsPS, nsIFontMetrics) /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: Init(const nsFont& aFont, nsIAtom* aLangGroup, nsIDeviceContext *aContext) { mLangGroup = aLangGroup; mFont = aFont; //don't addref this to avoid circular refs mDeviceContext = (nsDeviceContextPS *)aContext; mFontsPS = new nsVoidArray(); NS_ENSURE_TRUE(mFontsPS, NS_ERROR_OUT_OF_MEMORY); mFontsAlreadyLoaded = new nsHashtable(); NS_ENSURE_TRUE(mFontsAlreadyLoaded, NS_ERROR_OUT_OF_MEMORY); // make sure we have at least one font nsFontPS *fontPS = nsFontPS::FindFont('a', aFont, this); NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); RealizeFont(); return NS_OK; } NS_IMETHODIMP nsFontMetricsPS :: Destroy() { mDeviceContext = nsnull; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ void nsFontMetricsPS::RealizeFont() { if (mDeviceContext) { float dev2app; dev2app = mDeviceContext->DevUnitsToAppUnits(); fontps *font = (fontps*)mFontsPS->ElementAt(0); #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) NS_ASSERTION(font && font->entry, "no font available"); if (font && !font->fontps && font->entry) font->fontps = CreateFontPS(font->entry, mFont, this); #endif NS_ASSERTION(font && font->fontps, "no font available"); if (font && font->fontps) font->fontps->RealizeFont(this, dev2app); } } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetXHeight(nscoord& aResult) { aResult = mXHeight; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetSuperscriptOffset(nscoord& aResult) { aResult = mSuperscriptOffset; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetSubscriptOffset(nscoord& aResult) { aResult = mSubscriptOffset; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetStrikeout(nscoord& aOffset, nscoord& aSize) { aOffset = mStrikeoutOffset; aSize = mStrikeoutSize; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetUnderline(nscoord& aOffset, nscoord& aSize) { aOffset = mUnderlineOffset; aSize = mUnderlineSize; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetHeight(nscoord &aHeight) { aHeight = mHeight; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h */ NS_IMETHODIMP nsFontMetricsPS :: GetNormalLineHeight(nscoord &aHeight) { aHeight = mEmHeight + mLeading; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetLeading(nscoord &aLeading) { aLeading = mLeading; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h */ NS_IMETHODIMP nsFontMetricsPS :: GetEmHeight(nscoord &aHeight) { aHeight = mEmHeight; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h */ NS_IMETHODIMP nsFontMetricsPS :: GetEmAscent(nscoord &aAscent) { aAscent = mEmAscent; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h */ NS_IMETHODIMP nsFontMetricsPS :: GetEmDescent(nscoord &aDescent) { aDescent = mEmDescent; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h */ NS_IMETHODIMP nsFontMetricsPS :: GetMaxHeight(nscoord &aHeight) { aHeight = mMaxHeight; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetMaxAscent(nscoord &aAscent) { aAscent = mMaxAscent; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetMaxDescent(nscoord &aDescent) { aDescent = mMaxDescent; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetMaxAdvance(nscoord &aAdvance) { aAdvance = mMaxAdvance; return NS_OK; } NS_IMETHODIMP nsFontMetricsPS :: GetAveCharWidth(nscoord &aAveCharWidth) { aAveCharWidth = mAveCharWidth; return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetSpaceWidth(nscoord &aSpaceWidth) { aSpaceWidth = mSpaceWidth; return NS_OK; } NS_IMETHODIMP nsFontMetricsPS :: GetLangGroup(nsIAtom** aLangGroup) { if (!aLangGroup) { return NS_ERROR_NULL_POINTER; } *aLangGroup = mLangGroup; NS_IF_ADDREF(*aLangGroup); return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS::GetFontHandle(nsFontHandle &aHandle) { return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetStringWidth(const char *aString,nscoord& aWidth,nscoord aLength) { aWidth = 0; if (aLength == 0) return NS_OK; nsFontPS* fontPS = nsFontPS::FindFont(aString[0], mFont, this); NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); nscoord i, start = 0; for (i=0; iGetWidth(aString+start, i-start); start = i; fontPS = fontThisChar; } } // measure the last part if (aLength-start) aWidth += fontPS->GetWidth(aString+start, aLength-start); return NS_OK; } /** --------------------------------------------------- * See documentation in nsFontMetricsPS.h * @update 2/26/99 dwc */ NS_IMETHODIMP nsFontMetricsPS :: GetStringWidth(const PRUnichar *aString,nscoord& aWidth,nscoord aLength) { aWidth = 0; if (aLength == 0) return NS_OK; nsFontPS* fontPS = nsFontPS::FindFont(aString[0], mFont, this); NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); nscoord i, start = 0; for (i=0; iGetWidth(aString+start, i-start); start = i; fontPS = fontThisChar; } } // measure the last part if (aLength-start) aWidth += fontPS->GetWidth(aString+start, aLength-start); return NS_OK; } nsFontPS* nsFontPS::FindFont(char aChar, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { PRUnichar uc = (unsigned char)aChar; return FindFont(uc, aFont, aFontMetrics); } // nsFontPS nsFontPS* nsFontPS::FindFont(PRUnichar aChar, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { nsFontPS* fontPS; #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, nsnull); if (dc->mFTPEnable) { #ifdef MOZ_ENABLE_XFT fontPS = nsFontPSXft::FindFont(aChar, aFont, aFontMetrics); #else fontPS = nsFontPSFreeType::FindFont(aChar, aFont, aFontMetrics); #endif if (fontPS) return fontPS; } #endif /* Find in afm font */ if (aFontMetrics->GetFontsPS()->Count() > 0) { fontps *fps = (fontps*)aFontMetrics->GetFontsPS()->ElementAt(0); NS_ENSURE_TRUE(fps, nsnull); fontPS = fps->fontps; } else { fontPS = nsFontPSAFM::FindFont(aFont, aFontMetrics); fontps *fps = new fontps; NS_ENSURE_TRUE(fps, nsnull); fps->fontps = fontPS; #if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_FREETYPE2) fps->entry = nsnull; #ifdef MOZ_ENABLE_XFT fps->charset = nsnull; #else fps->ccmap = nsnull; #endif #endif aFontMetrics->GetFontsPS()->AppendElement(fps); } return fontPS; } nsFontPS::nsFontPS(const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { mFont = new nsFont(aFont); if (!mFont) return; mFontMetrics = aFontMetrics; } nsFontPS::~nsFontPS() { if (mFont) { delete mFont; mFont = nsnull; } if (mCCMap) { FreeCCMap(mCCMap); } mFontMetrics = nsnull; } // nsFontPSAFM nsFontPS* nsFontPSAFM::FindFont(const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { nsAFMObject* afmInfo = new nsAFMObject(); if (!afmInfo) return nsnull; afmInfo->Init(aFont.size); PRInt16 fontIndex = afmInfo->CheckBasicFonts(aFont, PR_TRUE); if (fontIndex < 0) { if (!(afmInfo->AFM_ReadFile(aFont))) { fontIndex = afmInfo->CheckBasicFonts(aFont, PR_FALSE); if (fontIndex < 0) { fontIndex = afmInfo->CreateSubstituteFont(aFont); } } } nsFontPSAFM* fontPSAFM = nsnull; if (fontIndex < 0) delete afmInfo; else fontPSAFM = new nsFontPSAFM(aFont, afmInfo, fontIndex, aFontMetrics); return fontPSAFM; } nsFontPSAFM::nsFontPSAFM(const nsFont& aFont, nsAFMObject* aAFMInfo, PRInt16 fontIndex, nsFontMetricsPS* aFontMetrics) : nsFontPS(aFont, aFontMetrics), mAFMInfo(aAFMInfo), mFontIndex(fontIndex) { if (!(mFont && mAFMInfo)) return; AppendASCIItoUTF16(mAFMInfo->mPSFontInfo->mFamilyName, mFamilyName); } nsFontPSAFM::~nsFontPSAFM() { if (mAFMInfo) { delete mAFMInfo; mAFMInfo = nsnull; } } nscoord nsFontPSAFM::GetWidth(const char* aString, PRUint32 aLength) { nscoord width = 0; if (mAFMInfo) { mAFMInfo->GetStringWidth(aString, width, aLength); } return width; } nscoord nsFontPSAFM::GetWidth(const PRUnichar* aString, PRUint32 aLength) { nscoord width = 0; if (mAFMInfo) { mAFMInfo->GetStringWidth(aString, width, aLength); } return width; } nscoord nsFontPSAFM::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const char* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext, 0); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, 0); psObj->moveto(aX, aY); psObj->show(aString, aLength, ""); return GetWidth(aString, aLength); } nscoord nsFontPSAFM::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const PRUnichar* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext, 0); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, 0); psObj->moveto(aX, aY); psObj->show(aString, aLength, "", 0); return GetWidth(aString, aLength); } nsresult nsFontPSAFM::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app) { NS_ENSURE_ARG_POINTER(aFontMetrics); float fontSize; float offset; nscoord onePixel = NSToCoordRound(1 * dev2app); // convert the font size which is in twips to points fontSize = mFont->size / TWIPS_PER_POINT_FLOAT; offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mXHeight) / 1000.0f; nscoord xHeight = NSToCoordRound(offset); aFontMetrics->SetXHeight(xHeight); aFontMetrics->SetSuperscriptOffset(xHeight); aFontMetrics->SetSubscriptOffset(xHeight); aFontMetrics->SetStrikeout((nscoord)(xHeight / 2), onePixel); offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mUnderlinePosition) / 1000.0f; aFontMetrics->SetUnderline(NSToCoordRound(offset), onePixel); nscoord size = NSToCoordRound(fontSize * dev2app); aFontMetrics->SetHeight(size); aFontMetrics->SetEmHeight(size); aFontMetrics->SetMaxAdvance(size); aFontMetrics->SetMaxHeight(size); offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mAscender) / 1000.0f; nscoord ascent = NSToCoordRound(offset); aFontMetrics->SetAscent(ascent); aFontMetrics->SetEmAscent(ascent); aFontMetrics->SetMaxAscent(ascent); offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mDescender) / 1000.0f; nscoord descent = -(NSToCoordRound(offset)); aFontMetrics->SetDescent(descent); aFontMetrics->SetEmDescent(descent); aFontMetrics->SetMaxDescent(descent); aFontMetrics->SetLeading(0); nscoord spaceWidth = GetWidth(" ", 1); aFontMetrics->SetSpaceWidth(spaceWidth); nscoord aveCharWidth = GetWidth("x", 1); aFontMetrics->SetAveCharWidth(aveCharWidth); return NS_OK; } nsresult nsFontPSAFM::SetupFont(nsRenderingContextPS* aContext) { NS_ENSURE_TRUE(aContext && mFontMetrics, 0); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, 0); nscoord fontHeight = 0; mFontMetrics->GetHeight(fontHeight); psObj->setscriptfont(mFontIndex, mFamilyName, fontHeight, mFont->style, mFont->variant, mFont->weight, mFont->decorations); return NS_OK; } #ifdef MOZ_MATHML nsresult nsFontPSAFM::GetBoundingMetrics(const char* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsFontPSAFM::GetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } #endif #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) #define WIDEN_8_TO_16_BUF_SIZE 1024 #ifdef MOZ_ENABLE_XFT nsXftEntry::nsXftEntry(FcPattern *aFontPattern) { mFace = nsnull; mFaceIndex = 0; char *fcResult; int fcIndex; if (FcPatternGetString(aFontPattern, FC_FILE, 0, (FcChar8 **) &fcResult) == FcResultMatch) mFontFileName = fcResult; if (FcPatternGetString(aFontPattern, FC_FAMILY, 0, (FcChar8 **) &fcResult) == FcResultMatch) mFamilyName = fcResult; if (FcPatternGetString(aFontPattern, FC_STYLE, 0, (FcChar8 **) &fcResult) == FcResultMatch) mStyleName = fcResult; if (FcPatternGetInteger(aFontPattern, FC_INDEX, 0, &fcIndex) == FcResultMatch) mFaceIndex = fcIndex; } static nsFontPS* CreateFontPS(nsXftEntry *aEntry, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { nsresult rv; nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, nsnull); nsCAutoString fileName(aEntry->mFontFileName); nsCAutoString familyName(aEntry->mFamilyName); nsCAutoString styleName(aEntry->mStyleName); ToLowerCase(familyName); ToLowerCase(styleName); nsCAutoString fontName; fontName.Append(familyName); fontName.Append("-"); fontName.Append(styleName); nsCStringKey key(fontName); nsHashtable *psFGList = dc->GetPSFontGeneratorList(); NS_ENSURE_TRUE(psFGList, nsnull); nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(&key); if (!psFontGen) { psFontGen = new nsXftType1Generator; NS_ENSURE_TRUE(psFontGen, nsnull); rv = ((nsXftType1Generator*)psFontGen)->Init(aEntry); if (NS_FAILED(rv)) { delete psFontGen; return nsnull; } psFGList->Put(&key, (void *) psFontGen); } nsFontPSXft* font = new nsFontPSXft(aFont, aFontMetrics); NS_ENSURE_TRUE(font, nsnull); rv = font->Init(aEntry, psFontGen); if (NS_FAILED(rv)) { delete font; return nsnull; } return font; } /* static */ PRBool nsFontPSXft::CSSFontEnumCallback(const nsString& aFamily, PRBool aIsGeneric, void* aFpi) { fontPSInfo *fpi = (fontPSInfo *)aFpi; // fontconfig always returns family names in UTF-8 so that we // should do the same here. NS_ConvertUTF16toUTF8 name(aFamily); // The newest fontconfig does the full Unicode case folding so that // we're being lazy here by calling |ToLowerCase| after converting // to UTF-8 assuming that in virtually all cases, we just have to // fold [A-Z]. (bug 223653). ToLowerCase(name); fpi->mFontList.AppendCString(name); fpi->mFontIsGeneric.AppendElement((void *)aIsGeneric); if (aIsGeneric) { fpi->mGenericFont = fpi->mFontList.CStringAt(fpi->mFontList.Count() - 1); return PR_FALSE; // stop processing } return PR_TRUE; // keep processing } nsFontPS* nsFontPSXft::FindFont(PRUnichar aChar, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { PRBool inited = PR_FALSE; nsCOMPtr langGroup; fontPSInfo fpi; fpi.fontps = aFontMetrics->GetFontsPS(); int i = 0; while (1) { // // see if it is already in the list of fonts // for (; iCount(); i++) { fontps *fi = (fontps *)fpi.fontps->ElementAt(i); if (!fi->entry || !fi->charset) { NS_ASSERTION(fi->entry, "invalid entry"); NS_ASSERTION(fi->charset, "invalid charset"); continue; } if (FcCharSetHasChar(fi->charset, aChar)) { if (!fi->fontps) { #ifdef PR_LOGGING if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) { PR_LogPrint("CreateFontPS %s/%s\n", fi->entry->mFamilyName.get(), fi->entry->mStyleName.get()); } #endif fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics); } if (fi->fontps) return fi->fontps; } } // if already get all matched fonts and not found suitable // then return nsnull if (fpi.fontps->Count() > 0) return nsnull; // // it is not already in the list of fonts // so add more fonts to the list // if (inited) return nsnull; inited = PR_TRUE; fpi.nsfont = &aFont; fpi.alreadyLoaded = aFontMetrics->GetFontsAlreadyLoadedList(); fpi.mGenericFont = nsnull; aFontMetrics->GetLangGroup(getter_AddRefs(langGroup)); if (!langGroup) langGroup = NS_NewAtom("x-western"); // enumerate over the font names passed in aFont.EnumerateFamilies(nsFontPSXft::CSSFontEnumCallback, &fpi); nsCOMPtr prefService; prefService = do_GetService(NS_PREF_CONTRACTID); if (!prefService) return nsnull; nsXPIDLCString value; nsCAutoString defaultFont; nsAutoString langGroupStr; langGroup->ToString(langGroupStr); // Set up the default font name if it's not set if (!fpi.mGenericFont) { nsCAutoString name("font.default."); LossyAppendUTF16toASCII(langGroupStr, name); prefService->CopyCharPref(name.get(), getter_Copies(value)); if (value.get()) defaultFont = value.get(); else defaultFont = "serif"; fpi.mGenericFont = &defaultFont; } // If pattern is null, set up the base bits of it so we can // match. If we need to match later we don't have to set it up // again. FcPattern *pattern = nsnull; pattern = FcPatternCreate(); if (!pattern) return nsnull; // XXX need to add user defined family // Add CSS names - walk the list of fonts, adding the generic as // the last font for (int i=0; i < fpi.mFontList.Count(); ++i) { // if this was a generic name, break out of the loop since we // don't want to add it to the pattern yet if (fpi.mFontIsGeneric[i]) break;; nsCString *familyName = fpi.mFontList.CStringAt(i); NS_AddFFRE(pattern, familyName, PR_FALSE); } // Add the language group. Note that we do this before adding any // generics. That's because the language is more important than // any generic font. NS_AddLangGroup(pattern, langGroup); // If there's a generic add a pref for the generic if there's one // set. if (fpi.mGenericFont && !aFont.systemFont) { NS_AddGenericFontFromPref(fpi.mGenericFont, langGroup, pattern, #ifdef PR_LOGGING gFontMetricsPSM); #else nsnull); #endif } // Add the generic if there is one. if (fpi.mGenericFont && !aFont.systemFont) NS_AddFFRE(pattern, fpi.mGenericFont, PR_FALSE); // Add the slant type FcPatternAddInteger(pattern, FC_SLANT, NS_CalculateSlant(aFont.style)); // Add the weight FcPatternAddInteger(pattern, FC_WEIGHT, NS_CalculateWeight(aFont.weight)); // Set up the default substitutions for this font FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcFontSet *set = FcFontSort(0, pattern, FcTrue, 0, &result); if (!set) { return nsnull; } // Create a list of new font objects based on the fonts returned // as part of the query for (int i=0; i < set->nfont; ++i) { FcBool fc_outline; FcChar8 *fc_family; FcChar8 *fc_style; FcCharSet *fc_charset; // skip if the fonts is not outline font files. result = FcPatternGetBool (set->fonts[i], FC_OUTLINE, 0, &fc_outline); if (!fc_outline) continue; result = FcPatternGetString (set->fonts[i], FC_FAMILY, 0, &fc_family); if (result != FcResultMatch || fc_family == nsnull) continue; result = FcPatternGetString (set->fonts[i], FC_STYLE, 0, &fc_style); if (result != FcResultMatch || fc_style == nsnull) continue; result = FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &fc_charset); if (result != FcResultMatch || fc_charset == nsnull) continue; // increment reference count fc_charset = FcCharSetCopy(fc_charset); if (fc_charset == nsnull) continue; nsXftEntry *xftEntry = new nsXftEntry(set->fonts[i]); if (!xftEntry) continue; fontps *fps = new fontps; fps->entry = xftEntry; fps->charset = fc_charset; fps->fontps = nsnull; fpi.fontps->AppendElement(fps); } // we're done with the set now FcFontSetDestroy(set); FcPatternDestroy(pattern); } return nsnull; } nsFontPSXft::nsFontPSXft(const nsFont& aFont, nsFontMetricsPS* aFontMetrics) :nsFontPS(aFont, aFontMetrics) { } nsresult nsFontPSXft::Init(nsXftEntry* aEntry, nsPSFontGenerator* aPSFontGen) { NS_ENSURE_TRUE(aEntry && aPSFontGen, NS_ERROR_FAILURE); mEntry = aEntry; mPSFontGenerator = aPSFontGen; float app2dev; nsIDeviceContext* dc = mFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, NS_ERROR_NULL_POINTER); app2dev = dc->AppUnitsToDevUnits(); mPixelSize = NSToIntRound(app2dev * mFont->size); FT_Error fterror; fterror = FT_Init_FreeType(&mFreeTypeLibrary); if (fterror) { NS_ERROR("failed to initialize FreeType library"); mFreeTypeLibrary = nsnull; return NS_ERROR_FAILURE; } return NS_OK; } nsFontPSXft::~nsFontPSXft() { if (mEntry->mFace) { FT_Done_Face(mEntry->mFace); mEntry->mFace = nsnull; } if (FT_Done_FreeType(mFreeTypeLibrary)) return; mEntry = nsnull; } FT_Face nsFontPSXft::getFTFace() { FT_Face face = mEntry->mFace; if (face) return (face); if (FT_New_Face(mFreeTypeLibrary, mEntry->mFontFileName.get(), mEntry->mFaceIndex, &face) || FT_Set_Pixel_Sizes(face, mPixelSize, 0)) return nsnull; mEntry->mFace = face; return face; } nscoord nsFontPSXft::GetWidth(const char* aString, PRUint32 aLength) { return GetWidth(NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength); } nscoord nsFontPSXft::GetWidth(const PRUnichar* aString, PRUint32 aLength) { // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; // XXX : we might need some caching here double em_size = 1.0 * face->units_per_EM; double x_scale = face->size->metrics.x_ppem / em_size; double origin_x = 0; for (PRUint32 i=0; isize->metrics.x_ppem/2 + 2; else origin_x += (face->glyph->advance.x) * x_scale; } NS_ENSURE_TRUE(mFontMetrics, 0); nsDeviceContextPS* dc = mFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, 0); origin_x *= dc->DevUnitsToAppUnits(); return NSToCoordRound((nscoord)origin_x); } nscoord nsFontPSXft::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const char* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext, 0); return DrawString(aContext, aX, aY, NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength); } nscoord nsFontPSXft::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const PRUnichar* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext && aLength, 0); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, 0); psObj->moveto(aX, aY); PRInt32 currSubFont, prevSubFont = -1; PRUint32 start = 0; PRUint32 i; // XXX : ignore surrogate pairs for now nsString *subSet = mPSFontGenerator->GetSubset(); for (i = 0; i < aLength; ++i) { currSubFont = mPSFontGenerator->AddToSubset(aString[i]); if (prevSubFont != currSubFont) { if (prevSubFont != -1) psObj->show(&aString[start], i - start, *subSet, prevSubFont); NS_ASSERTION(!mFontNameBase.IsEmpty(), "font base name shouldn't be empty"); psObj->setfont(mFontNameBase, mHeight, currSubFont); prevSubFont = currSubFont; start = i; } } if (prevSubFont != -1) psObj->show(&aString[start], i - start, *subSet, prevSubFont); return GetWidth(aString, aLength); } int nsFontPSXft::ascent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(face->ascender, face->size->metrics.y_scale); } int nsFontPSXft::descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale); } int nsFontPSXft::max_ascent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (tt_os2) return FT_DESIGN_UNITS_TO_PIXELS(tt_os2->sTypoAscender, face->size->metrics.y_scale); else return FT_DESIGN_UNITS_TO_PIXELS(face->bbox.yMax, face->size->metrics.y_scale); } int nsFontPSXft::max_descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (tt_os2) return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender, face->size->metrics.y_scale); else return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin, face->size->metrics.y_scale); } int nsFontPSXft::max_width() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width, face->size->metrics.x_scale); } PRBool nsFontPSXft::getXHeight(unsigned long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face || !aVal) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSXft::underlinePosition(long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(-face->underline_position, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSXft::underline_thickness(unsigned long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness, face->size->metrics.x_scale); return PR_TRUE; } PRBool nsFontPSXft::superscript_y(long &aVal) { aVal = 0; FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSXft::subscript_y(long &aVal) { aVal = 0; FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset, face->size->metrics.y_scale); // some fonts have the sign wrong. it should be always positive. aVal = (aVal < 0) ? -aVal : aVal; return PR_TRUE; } nsresult nsFontPSXft::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app) { nscoord leading, emHeight, emAscent, emDescent; nscoord maxHeight, maxAscent, maxDescent, maxAdvance; nscoord xHeight, spaceWidth, aveCharWidth; nscoord underlineOffset, underlineSize, superscriptOffset, subscriptOffset; nscoord strikeoutOffset, strikeoutSize; int lineSpacing = ascent() + descent(); if (lineSpacing > mPixelSize) { leading = nscoord((lineSpacing - mPixelSize) * dev2app); } else { leading = 0; } emHeight = PR_MAX(1, nscoord(mPixelSize * dev2app)); emAscent = nscoord(ascent() * mPixelSize * dev2app / lineSpacing); emDescent = emHeight - emAscent; maxHeight = nscoord((max_ascent() + max_descent()) * dev2app); maxAscent = nscoord(max_ascent() * dev2app) ; maxDescent = nscoord(max_descent() * dev2app); maxAdvance = nscoord(max_width() * dev2app); // 56% of ascent, best guess for non-true type xHeight = NSToCoordRound((float)ascent()* dev2app * 0.56f); PRUnichar space = (PRUnichar)' '; spaceWidth = NSToCoordRound(GetWidth(&space, 1)); PRUnichar averageX = (PRUnichar)'x'; aveCharWidth = NSToCoordRound(GetWidth(&averageX, 1)); unsigned long pr = 0; if (getXHeight(pr)) { xHeight = (nscoord(pr * dev2app)); } float height; long val; height = ascent() + descent(); underlineOffset = -NSToIntRound( PR_MAX (1, floor (0.1 * height + 0.5)) * dev2app); if (underline_thickness(pr)) { /* this will only be provided from adobe .afm fonts */ underlineSize = nscoord(PR_MAX(dev2app, NSToIntRound(pr * dev2app))); } else { height = ascent() + descent(); underlineSize = NSToIntRound( PR_MAX(1, floor (0.05 * height + 0.5)) * dev2app); } if (superscript_y(val)) { superscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app))); } else { superscriptOffset = xHeight; } if (subscript_y(val)) { subscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app))); } else { subscriptOffset = xHeight; } /* need better way to calculate this */ strikeoutOffset = NSToCoordRound(xHeight / 2.0); strikeoutSize = underlineSize; // TODO: leading never used, does it equal to "Height"? aFontMetrics->SetHeight(emHeight); aFontMetrics->SetEmHeight(emHeight); aFontMetrics->SetEmAscent(emAscent); aFontMetrics->SetEmDescent(emDescent); aFontMetrics->SetMaxHeight(maxHeight); aFontMetrics->SetMaxAscent(maxAscent); aFontMetrics->SetMaxDescent(maxDescent); aFontMetrics->SetMaxAdvance(maxAdvance); aFontMetrics->SetXHeight(xHeight); aFontMetrics->SetSpaceWidth(spaceWidth); aFontMetrics->SetAveCharWidth(aveCharWidth); aFontMetrics->SetUnderline(underlineOffset, underlineSize); aFontMetrics->SetSuperscriptOffset(superscriptOffset); aFontMetrics->SetSubscriptOffset(subscriptOffset); aFontMetrics->SetStrikeout(strikeoutOffset, strikeoutSize); return NS_OK; } nsresult nsFontPSXft::SetupFont(nsRenderingContextPS* aContext) { NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, NS_ERROR_FAILURE); mFontMetrics->GetHeight(mHeight); if (mFontNameBase.IsEmpty()) { int wmode = 0; FT_Face face = getFTFace(); NS_ENSURE_TRUE(face, NS_ERROR_NULL_POINTER); if (NS_FAILED(FT2ToType1FontName(face, wmode, mFontNameBase))) return NS_ERROR_FAILURE; } return NS_OK; } #ifdef MOZ_MATHML nsresult nsFontPSXft::GetBoundingMetrics(const char* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsFontPSXft::GetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } #endif //MOZ_MATHML #else PRBool nsFontPSFreeType::CSSFontEnumCallback(const nsString& aFamily, PRBool aGeneric, void* aFpi) { fontPSInfo* fpi = (fontPSInfo*)aFpi; nsCAutoString familyname; if (aGeneric) { // need lang to lookup generic pref if (strlen(fpi->lang.get()) == 0) { return PR_TRUE; // keep trying } nsXPIDLCString value; nsresult rv; nsCOMPtr pref(do_GetService(NS_PREF_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, PR_TRUE); // keep trying nsCAutoString name("font.name."); LossyAppendUTF16toASCII(aFamily, name); name.Append(char('.')); name.Append(fpi->lang); pref->CopyCharPref(name.get(), getter_Copies(value)); if (!value.get()) return PR_TRUE; // keep trying // strip down to just the family name PRInt32 startFamily = value.FindChar('-') + 1; if (startFamily < 0) // 1st '-' not found. Not FFRE but just familyName. familyname = value; else { PRInt32 endFamily = value.FindChar('-', startFamily); if (endFamily < 0) // 2nd '-' not found familyname.Append(Substring(value, startFamily)); else // FFRE familyname.Append(Substring(value, startFamily, endFamily - startFamily)); } PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("generic font \"%s\" -> \"%s\"\n", name.get(), familyname.get())); } else LossyAppendUTF16toASCII(aFamily, familyname); AddFontEntries(familyname, fpi->lang, fpi->weight, nsIFontCatalogService::kFCWidthAny, fpi->slant, nsIFontCatalogService::kFCSpacingAny, fpi); return PR_TRUE; } PRBool nsFontPSFreeType::AddUserPref(nsIAtom *aLang, const nsFont& aFont, fontPSInfo *aFpi) { nsCAutoString emptyStr; fontPSInfo *fpi = (fontPSInfo*)aFpi; nsresult rv = NS_OK; nsCAutoString fontName; nsCOMPtr pref(do_GetService(NS_PREF_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, PR_FALSE); nsXPIDLCString value; nsCAutoString name("font.default."); name.Append(fpi->lang); pref->CopyCharPref(name.get(), getter_Copies(value)); if (!value.get()) return PR_FALSE; name.Assign("font.name."); name.Append(value); name.Append(char('.')); name.Append(fpi->lang); pref->CopyCharPref(name.get(), getter_Copies(value)); if (!value.get()) return PR_FALSE; // strip down to just the family name PRInt32 startFamily = value.FindChar('-') + 1; if (startFamily < 0) // '-' not found. Not FFRE but just familyName fontName = value; else { PRInt32 endFamily = value.FindChar('-', startFamily); if (endFamily < 0) // 2nd '-' not found fontName.Append(Substring(value, startFamily)); else // FFRE fontName.Append(Substring(value, startFamily, endFamily - startFamily)); } AddFontEntries(fontName, fpi->lang, fpi->weight, nsIFontCatalogService::kFCWidthAny, fpi->slant, nsIFontCatalogService::kFCSpacingAny, fpi); // wildcard the language AddFontEntries(fontName, emptyStr, fpi->weight, nsIFontCatalogService::kFCWidthAny, fpi->slant, nsIFontCatalogService::kFCSpacingAny, fpi); return PR_TRUE; } static nsFontPS* CreateFontPS(nsITrueTypeFontCatalogEntry *aEntry, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { nsresult rv; nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, nsnull); nsCAutoString familyName, styleName; aEntry->GetFamilyName(familyName); aEntry->GetStyleName(styleName); ToLowerCase(familyName); ToLowerCase(styleName); nsCAutoString fontName; fontName.Append(familyName); fontName.Append("-"); fontName.Append(styleName); nsCStringKey key(fontName); nsHashtable *psFGList = dc->GetPSFontGeneratorList(); NS_ENSURE_TRUE(psFGList, nsnull); nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(&key); if (!psFontGen) { psFontGen = new nsFT2Type1Generator; NS_ENSURE_TRUE(psFontGen, nsnull); rv = ((nsFT2Type1Generator*)psFontGen)->Init(aEntry); if (NS_FAILED(rv)) { delete psFontGen; return nsnull; } psFGList->Put(&key, (void *) psFontGen); } nsFontPSFreeType* font = new nsFontPSFreeType(aFont, aFontMetrics); NS_ENSURE_TRUE(font, nsnull); rv = font->Init(aEntry, psFontGen); if (NS_FAILED(rv)) { delete font; return nsnull; } return font; } nsFontPS* nsFontPSFreeType::FindFont(PRUnichar aChar, const nsFont& aFont, nsFontMetricsPS* aFontMetrics) { PRBool inited = PR_FALSE; int anyWeight = nsIFontCatalogService::kFCWeightAny; int anyWidth = nsIFontCatalogService::kFCWidthAny; int anySlant = nsIFontCatalogService::kFCSlantAny; int anySpacing = nsIFontCatalogService::kFCSpacingAny; nsCOMPtr lang; nsCAutoString emptyStr; nsCAutoString locale; fontPSInfo fpi, fpi2; fpi.fontps = aFontMetrics->GetFontsPS(); int i = 0; while (1) { // // see if it is already in the list of fonts // for (; iCount(); i++) { fontps *fi = (fontps *)fpi.fontps->ElementAt(i); if (!fi->entry || !fi->ccmap) { NS_ASSERTION(fi->entry, "invalid entry"); NS_ASSERTION(fi->ccmap, "invalid ccmap"); continue; } if (CCMAP_HAS_CHAR(fi->ccmap, aChar)) { if (!fi->fontps) { #ifdef PR_LOGGING if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) { nsCAutoString familyName, styleName; fi->entry->GetFamilyName(familyName); fi->entry->GetStyleName(styleName); PR_LogPrint("CreateFontPS %s/%s\n", familyName.get(), styleName.get()); } #endif fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics); } if (fi->fontps) return fi->fontps; } } // // it is not already in the list of fonts // so add more fonts to the list // if (!inited) { fpi.nsfont = &aFont; fpi.alreadyLoaded = aFontMetrics->GetFontsAlreadyLoadedList(); aFontMetrics->GetLangGroup(getter_AddRefs(lang)); if (!lang) lang = NS_NewAtom("x-western"); const char *langStr; lang->GetUTF8String(&langStr); if (langStr) fpi.lang.Append(langStr); gUsersLocale->GetUTF8String(&langStr); if (langStr) locale.Append(langStr); if (NS_IS_BOLD(fpi.nsfont->weight)) fpi.weight = nsIFontCatalogService::kFCWeightBold; else fpi.weight = nsIFontCatalogService::kFCWeightMedium; if (fpi.nsfont->style == NS_FONT_STYLE_NORMAL) fpi.slant = nsIFontCatalogService::kFCSlantRoman; else fpi.slant = nsIFontCatalogService::kFCSlantItalic; inited = PR_TRUE; } // // Add fonts to the list following the CSS spec, user pref // After that slowly loosen the spec to enlarge the list // int state = aFontMetrics->GetFontPSState(); aFontMetrics->IncrementFontPSState(); switch (state) { case 0: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get the CSS specified entries for the element's language")); aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi); break; case 1: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get the CSS specified entries for the user's locale")); fpi2 = fpi; fpi2.lang = locale; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 2: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get the CSS specified entries for any language")); fpi2 = fpi; fpi2.lang = emptyStr; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 3: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get the user pref for the element's language")); AddUserPref(lang, aFont, &fpi); break; case 4: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get the user pref for the user's locale")); fpi2 = fpi; fpi2.lang = locale; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 5: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get all the entries for this language/style")); AddFontEntries(emptyStr, fpi.lang, fpi.weight, anyWidth, fpi.slant, anySpacing, &fpi); break; case 6: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get all the entries for the locale/style")); AddFontEntries(emptyStr, locale, fpi.weight, anyWidth, fpi.slant, anySpacing, &fpi); break; case 7: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations of CSS " "specified entries for the element's language")); fpi2 = fpi; fpi2.weight = anyWeight; fpi2.slant = 0; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 8: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations of CSS " "specified entries for the user's locale")); fpi2 = fpi; fpi2.lang = locale; fpi2.weight = anyWeight; fpi2.slant = 0; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 9: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations of CSS " "specified entries for any language")); fpi2 = fpi; fpi2.lang = emptyStr; fpi2.weight = anyWeight; fpi2.slant = 0; aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2); break; case 10: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations of the user pref")); fpi2 = fpi; fpi2.lang = emptyStr; fpi2.weight = anyWeight; fpi2.slant = 0; AddUserPref(lang, aFont, &fpi2); break; case 11: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations for this language")); AddFontEntries(emptyStr, fpi.lang, anyWeight, anyWidth, anySlant, anySpacing, &fpi); break; case 12: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "wildcard the slant/weight variations of the locale")); AddFontEntries(emptyStr, locale, anyWeight, anyWidth, anySlant, anySpacing, &fpi); break; case 13: PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get ALL font entries")); AddFontEntries(emptyStr, emptyStr, anyWeight, anyWidth, anySlant, anySpacing, &fpi); break; default: // try to always return a font even if no font supports this char if (fpi.fontps->Count()) { PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("failed to find a font supporting 0x%04x so " "returning 1st font in list\n", aChar)); fontps *fi = (fontps *)fpi.fontps->ElementAt(0); if (!fi->fontps) fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics); return fi->fontps; } PR_LOG(gFontMetricsPSM, PR_LOG_WARNING, ("failed to find a font supporting 0x%04x\n", aChar)); return (nsnull); } } return nsnull; } nsresult nsFontPSFreeType::AddFontEntries(nsACString& aFamilyName, nsACString& aLanguage, PRUint16 aWeight, PRUint16 aWidth, PRUint16 aSlant, PRUint16 aSpacing, fontPSInfo* aFpi) { nsresult rv = NS_OK; nsCAutoString name(aFamilyName); nsCAutoString lang(aLanguage); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" family = '%s'", name.get())); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" lang = '%s'", lang.get())); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" aWeight = %d", aWeight)); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" aWidth = %d", aWidth)); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" aSlant = %d", aSlant)); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" aSpacing = %d", aSpacing)); nsCOMPtr fcs(do_GetService(kFCSCID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr entryList; rv = fcs->GetFontCatalogEntries(aFamilyName, aLanguage, aWeight, aWidth, aSlant, aSpacing, getter_AddRefs(entryList)); NS_ENSURE_SUCCESS(rv, rv); PRUint32 i, count = 0; NS_ENSURE_TRUE(entryList, NS_ERROR_FAILURE); rv = entryList->GetLength(&count); NS_ENSURE_SUCCESS(rv, rv); PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, (" count = %d", count)); for (i=0; i entry = do_QueryElementAt(entryList, i, &rv); NS_ENSURE_SUCCESS(rv, rv); // check if already in list nsVoidKey key((void*)entry); PRBool loaded = aFpi->alreadyLoaded->Exists(&key); #ifdef PR_LOGGING if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) { nsCAutoString fontname, stylename; entry->GetFamilyName(fontname); entry->GetStyleName(stylename); PR_LogPrint(" -- %s '%s/%s'\n", (loaded ? "already loaded" : "load"), fontname.get(), stylename.get()); } #endif if (loaded) continue; PRUint16 *ccmap; PRUint32 size; entry->GetCCMap(&size, &ccmap); nsITrueTypeFontCatalogEntry *e = entry; NS_IF_ADDREF(e); fontps *fps = new fontps; NS_ENSURE_TRUE(fps, NS_ERROR_OUT_OF_MEMORY); fps->entry = entry; fps->fontps = nsnull; fps->ccmap = ccmap; aFpi->fontps->AppendElement(fps); aFpi->alreadyLoaded->Put(&key, (void*)1); } return rv; } nsFontPSFreeType::nsFontPSFreeType(const nsFont& aFont, nsFontMetricsPS* aFontMetrics) :nsFontPS(aFont, aFontMetrics) { } nsresult nsFontPSFreeType::Init(nsITrueTypeFontCatalogEntry* aEntry, nsPSFontGenerator* aPSFontGen) { NS_ENSURE_TRUE(mFont && mFontMetrics, NS_ERROR_FAILURE); NS_ENSURE_TRUE(aEntry && aPSFontGen, NS_ERROR_FAILURE); mEntry = aEntry; mPSFontGenerator = aPSFontGen; float app2dev; nsIDeviceContext* dc = mFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, NS_ERROR_NULL_POINTER); app2dev = dc->AppUnitsToDevUnits(); mPixelSize = NSToIntRound(app2dev * mFont->size); mImageDesc.font.face_id = (void*)mEntry; mImageDesc.font.pix_width = mPixelSize; mImageDesc.font.pix_height = mPixelSize; mImageDesc.image_type = 0; nsresult rv; mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } return NS_OK; } nsFontPSFreeType::~nsFontPSFreeType() { mEntry = nsnull; } nscoord nsFontPSFreeType::GetWidth(const char* aString, PRUint32 aLength) { return GetWidth(NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength); } nscoord nsFontPSFreeType::GetWidth(const PRUnichar* aString, PRUint32 aLength) { FT_UInt glyph_index; FT_Glyph glyph; double origin_x = 0; // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; FTC_Image_Cache iCache; nsresult rv = mFt2->GetImageCache(&iCache); if (NS_FAILED(rv)) { NS_ERROR("Failed to get Image Cache"); return 0; } for (PRUint32 i=0; iGetCharIndex((FT_Face)face, aString[i], &glyph_index); nsresult rv = mFt2->ImageCacheLookup(iCache, &mImageDesc, glyph_index, &glyph); if (NS_FAILED(rv)) { origin_x += FT_REG_TO_16_16(face->size->metrics.x_ppem/2 + 2); continue; } origin_x += glyph->advance.x; } NS_ENSURE_TRUE(mFontMetrics, 0); nsDeviceContextPS* dc = mFontMetrics->GetDeviceContext(); NS_ENSURE_TRUE(dc, 0); float dev2app; dev2app = dc->DevUnitsToAppUnits(); origin_x *= dev2app; origin_x /= FT_REG_TO_16_16(1); return NSToCoordRound((nscoord)origin_x); } FT_Face nsFontPSFreeType::getFTFace() { FT_Face face = nsnull; FTC_Manager cManager; mFt2->GetFTCacheManager(&cManager); nsresult rv = mFt2->ManagerLookupSize(cManager, &mImageDesc.font, &face, nsnull); NS_ASSERTION(rv==0, "failed to get face/size"); if (rv) return nsnull; return face; } nscoord nsFontPSFreeType::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const char* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext, 0); return DrawString(aContext, aX, aY, NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength); } nscoord nsFontPSFreeType::DrawString(nsRenderingContextPS* aContext, nscoord aX, nscoord aY, const PRUnichar* aString, PRUint32 aLength) { NS_ENSURE_TRUE(aContext && aLength, 0); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, 0); psObj->moveto(aX, aY); PRInt32 currSubFont, prevSubFont = -1; PRUint32 start = 0; PRUint32 i; // XXX : ignore surrogate pairs for now nsString *subSet = mPSFontGenerator->GetSubset(); for (i = 0; i < aLength; ++i) { currSubFont = mPSFontGenerator->AddToSubset(aString[i]); if (prevSubFont != currSubFont) { if (prevSubFont != -1) psObj->show(&aString[start], i - start, *subSet, prevSubFont); NS_ASSERTION(!mFontNameBase.IsEmpty(), "font base name shouldn't be empty"); psObj->setfont(mFontNameBase, mHeight, currSubFont); prevSubFont = currSubFont; start = i; } } if (prevSubFont != -1) psObj->show(&aString[start], i - start, *subSet, prevSubFont); return GetWidth(aString, aLength); } int nsFontPSFreeType::ascent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(face->ascender, face->size->metrics.y_scale); } int nsFontPSFreeType::descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale); } int nsFontPSFreeType::max_ascent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); void * p; mFt2->GetSfntTable(face, ft_sfnt_os2, &p); TT_OS2 * tt_os2 = (TT_OS2 *)p; NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (tt_os2) return FT_DESIGN_UNITS_TO_PIXELS(tt_os2->sTypoAscender, face->size->metrics.y_scale); else return FT_DESIGN_UNITS_TO_PIXELS(face->bbox.yMax, face->size->metrics.y_scale); } int nsFontPSFreeType::max_descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); void *p; mFt2->GetSfntTable(face, ft_sfnt_os2, &p); TT_OS2 *tt_os2 = (TT_OS2 *) p; NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (tt_os2) return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender, face->size->metrics.y_scale); else return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin, face->size->metrics.y_scale); } int nsFontPSFreeType::max_width() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); NS_ENSURE_TRUE(face, 0); return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width, face->size->metrics.x_scale); } PRBool nsFontPSFreeType::getXHeight(unsigned long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face || !aVal) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSFreeType::underlinePosition(long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(-face->underline_position, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSFreeType::underline_thickness(unsigned long &aVal) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness, face->size->metrics.x_scale); return PR_TRUE; } PRBool nsFontPSFreeType::superscript_y(long &aVal) { aVal = 0; FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2; mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset, face->size->metrics.y_scale); return PR_TRUE; } PRBool nsFontPSFreeType::subscript_y(long &aVal) { aVal = 0; FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2; mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset, face->size->metrics.y_scale); // some fonts have the sign wrong. it should be always positive. aVal = (aVal < 0) ? -aVal : aVal; return PR_TRUE; } nsresult nsFontPSFreeType::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app) { nscoord leading, emHeight, emAscent, emDescent; nscoord maxHeight, maxAscent, maxDescent, maxAdvance; nscoord xHeight, spaceWidth, aveCharWidth; nscoord underlineOffset, underlineSize, superscriptOffset, subscriptOffset; nscoord strikeoutOffset, strikeoutSize; int lineSpacing = ascent() + descent(); if (lineSpacing > mPixelSize) { leading = nscoord((lineSpacing - mPixelSize) * dev2app); } else { leading = 0; } emHeight = PR_MAX(1, nscoord(mPixelSize * dev2app)); emAscent = nscoord(ascent() * mPixelSize * dev2app / lineSpacing); emDescent = emHeight - emAscent; maxHeight = nscoord((max_ascent() + max_descent()) * dev2app); maxAscent = nscoord(max_ascent() * dev2app) ; maxDescent = nscoord(max_descent() * dev2app); maxAdvance = nscoord(max_width() * dev2app); // 56% of ascent, best guess for non-true type xHeight = NSToCoordRound((float)ascent()* dev2app * 0.56f); PRUnichar space = (PRUnichar)' '; spaceWidth = NSToCoordRound(GetWidth(&space, 1)); PRUnichar averageX = (PRUnichar)'x'; aveCharWidth = NSToCoordRound(GetWidth(&averageX, 1)); unsigned long pr = 0; if (getXHeight(pr)) { xHeight = (nscoord(pr * dev2app)); } float height; long val; height = ascent() + descent(); underlineOffset = -NSToIntRound( PR_MAX (1, floor (0.1 * height + 0.5)) * dev2app); if (underline_thickness(pr)) { /* this will only be provided from adobe .afm fonts */ underlineSize = nscoord(PR_MAX(dev2app, NSToIntRound(pr * dev2app))); } else { height = ascent() + descent(); underlineSize = NSToIntRound( PR_MAX(1, floor (0.05 * height + 0.5)) * dev2app); } if (superscript_y(val)) { superscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app))); } else { superscriptOffset = xHeight; } if (subscript_y(val)) { subscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app))); } else { subscriptOffset = xHeight; } /* need better way to calculate this */ strikeoutOffset = NSToCoordRound(xHeight / 2.0); strikeoutSize = underlineSize; // TODO: leading never used, does it equal to "Height"? aFontMetrics->SetHeight(emHeight); aFontMetrics->SetEmHeight(emHeight); aFontMetrics->SetEmAscent(emAscent); aFontMetrics->SetEmDescent(emDescent); aFontMetrics->SetMaxHeight(maxHeight); aFontMetrics->SetMaxAscent(maxAscent); aFontMetrics->SetMaxDescent(maxDescent); aFontMetrics->SetMaxAdvance(maxAdvance); aFontMetrics->SetXHeight(xHeight); aFontMetrics->SetSpaceWidth(spaceWidth); aFontMetrics->SetAveCharWidth(aveCharWidth); aFontMetrics->SetUnderline(underlineOffset, underlineSize); aFontMetrics->SetSuperscriptOffset(superscriptOffset); aFontMetrics->SetSubscriptOffset(subscriptOffset); aFontMetrics->SetStrikeout(strikeoutOffset, strikeoutSize); return NS_OK; } nsresult nsFontPSFreeType::SetupFont(nsRenderingContextPS* aContext) { NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE); nsPostScriptObj* psObj = aContext->GetPostScriptObj(); NS_ENSURE_TRUE(psObj, NS_ERROR_FAILURE); mFontMetrics->GetHeight(mHeight); if (mFontNameBase.IsEmpty()) { int wmode = 0; FT_Face face = getFTFace(); NS_ENSURE_TRUE(face, NS_ERROR_NULL_POINTER); if (NS_FAILED(FT2ToType1FontName(face, wmode, mFontNameBase))) return NS_ERROR_FAILURE; } return NS_OK; } #ifdef MOZ_MATHML nsresult nsFontPSFreeType::GetBoundingMetrics(const char* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsFontPSFreeType::GetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics) { return NS_ERROR_NOT_IMPLEMENTED; } #endif //MOZ_MATHML #endif //MOZ_ENABLE_FREETYPE2 #endif //MOZ_ENABLE_XFT // Implementation of nsPSFontGenerator nsPSFontGenerator::nsPSFontGenerator() { } nsPSFontGenerator::~nsPSFontGenerator() { } void nsPSFontGenerator::GeneratePSFont(FILE* aFile) { NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont"); } // Add a Unicode character to mSubset which will be divided into // multiple chunks (subfonts) of 255 (kSubFontSize) characters each. // Each chunk will be converted to a Type 1 font. Return the index of // a subfont (chunk) this character belongs to. PRInt32 nsPSFontGenerator::AddToSubset(PRUnichar aChar) { PRInt32 index = mSubset.FindChar(aChar); if (index == kNotFound) { mSubset.Append(aChar); index = mSubset.Length() - 1; } return index / kSubFontSize; } nsString *nsPSFontGenerator::GetSubset() { return &mSubset; } #ifdef MOZ_ENABLE_XFT nsXftType1Generator::nsXftType1Generator() { } nsresult nsXftType1Generator::Init(nsXftEntry* aEntry) { NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE); mEntry = aEntry; FT_Error error = FT_Init_FreeType(&mFreeTypeLibrary); NS_ASSERTION(!error, "failed to initialize FreeType library"); if (error) { mFreeTypeLibrary = nsnull; return NS_ERROR_FAILURE; } return NS_OK; } nsXftType1Generator::~nsXftType1Generator() { if (mEntry->mFace) { FT_Done_Face(mEntry->mFace); mEntry->mFace = nsnull; } if (FT_Done_FreeType(mFreeTypeLibrary)) return; mEntry = nsnull; } void nsXftType1Generator::GeneratePSFont(FILE* aFile) { FT_Face face = mEntry->mFace; if (face == nsnull) { if (FT_New_Face(mFreeTypeLibrary, mEntry->mFontFileName.get(), mEntry->mFaceIndex, &face) || face == nsnull /* || FT_Set_Pixel_Sizes(face, 16, 0) */) return; mEntry->mFace = face; } int wmode = 0; if (!mSubset.IsEmpty()) FT2SubsetToType1FontSet(face, mSubset, wmode, aFile); } #else #ifdef MOZ_ENABLE_FREETYPE2 nsFT2Type1Generator::nsFT2Type1Generator() { } nsresult nsFT2Type1Generator::Init(nsITrueTypeFontCatalogEntry* aEntry) { NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE); mEntry = aEntry; nsresult rv; mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } return NS_OK; } nsFT2Type1Generator::~nsFT2Type1Generator() { mEntry = nsnull; } void nsFT2Type1Generator::GeneratePSFont(FILE* aFile) { nsCAutoString fontName, styleName; mEntry->GetFamilyName(fontName); mEntry->GetStyleName(styleName); mImageDesc.font.face_id = (void*)mEntry; // TT glyph has no relation to size mImageDesc.font.pix_width = 16; mImageDesc.font.pix_height = 16; mImageDesc.image_type = 0; FT_Face face = nsnull; FTC_Manager cManager; mFt2->GetFTCacheManager(&cManager); nsresult rv = mFt2->ManagerLookupSize(cManager, &mImageDesc.font, &face, nsnull); if (NS_FAILED(rv)) return; int wmode = 0; if (!mSubset.IsEmpty()) FT2SubsetToType1FontSet(face, mSubset, wmode, aFile); } #endif //MOZ_ENABLE_FREETYPE2 #endif //MOZ_ENABLE_XFT