Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsPS.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1998
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00023  *   Ervin Yan <Ervin.Yan@sun.com>
00024  *   Christopher Blizzard <blizzard@mozilla.org>
00025  *   Jungshik Shin <jshin@mailaps.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "gfx-config.h"
00042 #include "nsFontMetricsPS.h"
00043 #include "nsDeviceContextPS.h"
00044 #include "nsRenderingContextPS.h"
00045 #include "nsIServiceManager.h"
00046 #include "nsGfxCIID.h"
00047 
00048 #include "nsIPref.h"
00049 #include "nsVoidArray.h"
00050 #include "nsReadableUtils.h"
00051 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00052 #include "nsType1.h"
00053 #endif
00054 #include "prlog.h"
00055 
00056 #ifdef MOZ_ENABLE_FREETYPE2
00057 #include "nsArray.h"
00058 #endif
00059 
00060 const PRUint16 nsPSFontGenerator::kSubFontSize = 255; 
00061 
00062 extern nsIAtom *gUsersLocale;
00063 #define NS_IS_BOLD(weight) ((weight) > 400 ? 1 : 0)
00064 
00065 #ifdef MOZ_ENABLE_XFT
00066 
00067 #include "nsFontConfigUtils.h"
00068 
00069 static nsFontPS* CreateFontPS(nsXftEntry*, const nsFont&,
00070                               nsFontMetricsPS*);
00071 
00072 #else
00073 #ifdef MOZ_ENABLE_FREETYPE2
00074 static nsFontPS* CreateFontPS(nsITrueTypeFontCatalogEntry*, const nsFont&,
00075                               nsFontMetricsPS*);
00076 
00077 static NS_DEFINE_CID(kFCSCID, NS_FONTCATALOGSERVICE_CID);
00078 #endif
00079 #endif
00080 
00081 #ifdef PR_LOGGING
00082 static PRLogModuleInfo *gFontMetricsPSM = PR_NewLogModule("FontMetricsPS");
00083 #endif
00084 
00089 nsFontMetricsPS :: nsFontMetricsPS()
00090 {
00091 }
00092 
00097 nsFontMetricsPS :: ~nsFontMetricsPS()
00098 {
00099   if (mFontsPS) {
00100     int i;
00101     for (i=0; i<mFontsPS->Count(); i++) {
00102       fontps *fontPS = (fontps *)mFontsPS->ElementAt(i);
00103       if (!fontPS)
00104         continue;
00105       if (fontPS->fontps)
00106         delete fontPS->fontps;
00107 #ifdef MOZ_ENABLE_XFT
00108       if (fontPS->entry)
00109         delete fontPS->entry;
00110       if (fontPS->charset)
00111         FcCharSetDestroy(fontPS->charset);
00112 #else
00113 #ifdef MOZ_ENABLE_FREETYPE2
00114       NS_IF_RELEASE(fontPS->entry);
00115       if (fontPS->ccmap)
00116         FreeCCMap(fontPS->ccmap);
00117 #endif
00118 #endif
00119       delete fontPS;
00120     }
00121     delete mFontsPS;
00122   }
00123 
00124   if (mFontsAlreadyLoaded) {
00125     delete mFontsAlreadyLoaded;
00126   }
00127 
00128   if (mDeviceContext) {
00129     // Notify our device context that owns us so that it can update its font cache
00130     mDeviceContext->FontMetricsDeleted(this);
00131     mDeviceContext = nsnull;
00132   }
00133 }
00134 
00135 NS_IMPL_ISUPPORTS1(nsFontMetricsPS, nsIFontMetrics)
00136 
00137 
00141 NS_IMETHODIMP
00142 nsFontMetricsPS :: Init(const nsFont& aFont, nsIAtom* aLangGroup,
00143   nsIDeviceContext *aContext)
00144 {
00145   mLangGroup = aLangGroup;
00146 
00147   mFont = aFont;
00148 
00149   //don't addref this to avoid circular refs
00150   mDeviceContext = (nsDeviceContextPS *)aContext;
00151 
00152   mFontsPS = new nsVoidArray();
00153   NS_ENSURE_TRUE(mFontsPS, NS_ERROR_OUT_OF_MEMORY);
00154   mFontsAlreadyLoaded = new nsHashtable();
00155   NS_ENSURE_TRUE(mFontsAlreadyLoaded, NS_ERROR_OUT_OF_MEMORY);
00156 
00157   // make sure we have at least one font
00158   nsFontPS *fontPS = nsFontPS::FindFont('a', aFont, this);
00159   NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
00160 
00161   RealizeFont();
00162   return NS_OK;
00163 }
00164 
00165 NS_IMETHODIMP
00166 nsFontMetricsPS :: Destroy()
00167 {
00168   mDeviceContext = nsnull;
00169   return NS_OK;
00170 }
00171 
00172 
00177 void
00178 nsFontMetricsPS::RealizeFont()
00179 {
00180   if (mDeviceContext) {
00181     float dev2app;
00182     dev2app = mDeviceContext->DevUnitsToAppUnits();
00183     fontps *font = (fontps*)mFontsPS->ElementAt(0);
00184 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00185     NS_ASSERTION(font && font->entry, "no font available");
00186     if (font && !font->fontps && font->entry)
00187       font->fontps = CreateFontPS(font->entry, mFont, this);
00188 #endif
00189     NS_ASSERTION(font && font->fontps, "no font available");
00190     if (font && font->fontps)
00191       font->fontps->RealizeFont(this, dev2app);
00192   }
00193 }
00194 
00199 NS_IMETHODIMP
00200 nsFontMetricsPS :: GetXHeight(nscoord& aResult)
00201 {
00202   aResult = mXHeight;
00203   return NS_OK;
00204 }
00205 
00210 NS_IMETHODIMP
00211 nsFontMetricsPS :: GetSuperscriptOffset(nscoord& aResult)
00212 {
00213   aResult = mSuperscriptOffset;
00214   return NS_OK;
00215 }
00216 
00221 NS_IMETHODIMP
00222 nsFontMetricsPS :: GetSubscriptOffset(nscoord& aResult)
00223 {
00224   aResult = mSubscriptOffset;
00225   return NS_OK;
00226 }
00227 
00232 NS_IMETHODIMP
00233 nsFontMetricsPS :: GetStrikeout(nscoord& aOffset, nscoord& aSize)
00234 {
00235   aOffset = mStrikeoutOffset;
00236   aSize = mStrikeoutSize;
00237   return NS_OK;
00238 }
00239 
00244 NS_IMETHODIMP
00245 nsFontMetricsPS :: GetUnderline(nscoord& aOffset, nscoord& aSize)
00246 {
00247   aOffset = mUnderlineOffset;
00248   aSize = mUnderlineSize;
00249   return NS_OK;
00250 }
00251 
00256 NS_IMETHODIMP
00257 nsFontMetricsPS :: GetHeight(nscoord &aHeight)
00258 {
00259   aHeight = mHeight;
00260   return NS_OK;
00261 }
00262 
00266 NS_IMETHODIMP
00267 nsFontMetricsPS :: GetNormalLineHeight(nscoord &aHeight)
00268 {
00269   aHeight = mEmHeight + mLeading;
00270   return NS_OK;
00271 }
00272 
00277 NS_IMETHODIMP
00278 nsFontMetricsPS :: GetLeading(nscoord &aLeading)
00279 {
00280   aLeading = mLeading;
00281   return NS_OK;
00282 }
00283 
00287 NS_IMETHODIMP
00288 nsFontMetricsPS :: GetEmHeight(nscoord &aHeight)
00289 {
00290   aHeight = mEmHeight;
00291   return NS_OK;
00292 }
00293 
00297 NS_IMETHODIMP
00298 nsFontMetricsPS :: GetEmAscent(nscoord &aAscent)
00299 {
00300   aAscent = mEmAscent;
00301   return NS_OK;
00302 }
00303 
00307 NS_IMETHODIMP
00308 nsFontMetricsPS :: GetEmDescent(nscoord &aDescent)
00309 {
00310   aDescent = mEmDescent;
00311   return NS_OK;
00312 }
00313 
00317 NS_IMETHODIMP
00318 nsFontMetricsPS :: GetMaxHeight(nscoord &aHeight)
00319 {
00320   aHeight = mMaxHeight;
00321   return NS_OK;
00322 }
00323 
00328 NS_IMETHODIMP
00329 nsFontMetricsPS :: GetMaxAscent(nscoord &aAscent)
00330 {
00331   aAscent = mMaxAscent;
00332   return NS_OK;
00333 }
00334 
00339 NS_IMETHODIMP
00340 nsFontMetricsPS :: GetMaxDescent(nscoord &aDescent)
00341 {
00342   aDescent = mMaxDescent;
00343   return NS_OK;
00344 }
00345 
00350 NS_IMETHODIMP
00351 nsFontMetricsPS :: GetMaxAdvance(nscoord &aAdvance)
00352 {
00353   aAdvance = mMaxAdvance;
00354   return NS_OK;
00355 }
00356 
00357 NS_IMETHODIMP
00358 nsFontMetricsPS :: GetAveCharWidth(nscoord &aAveCharWidth)
00359 {
00360   aAveCharWidth = mAveCharWidth;
00361   return NS_OK;
00362 }
00363 
00368 NS_IMETHODIMP
00369 nsFontMetricsPS :: GetSpaceWidth(nscoord &aSpaceWidth)
00370 {
00371   aSpaceWidth = mSpaceWidth;
00372   return NS_OK;
00373 }
00374 
00375 NS_IMETHODIMP
00376 nsFontMetricsPS :: GetLangGroup(nsIAtom** aLangGroup)
00377 {
00378   if (!aLangGroup) {
00379     return NS_ERROR_NULL_POINTER;
00380   }
00381 
00382   *aLangGroup = mLangGroup;
00383   NS_IF_ADDREF(*aLangGroup);
00384 
00385   return NS_OK;
00386 }
00387 
00392 NS_IMETHODIMP
00393 nsFontMetricsPS::GetFontHandle(nsFontHandle &aHandle)
00394 {
00395 
00396   return NS_OK;
00397 }
00398 
00403 NS_IMETHODIMP
00404 nsFontMetricsPS :: GetStringWidth(const char *aString,nscoord& aWidth,nscoord aLength)
00405 {
00406   aWidth = 0;
00407   if (aLength == 0)
00408     return NS_OK;
00409   nsFontPS* fontPS = nsFontPS::FindFont(aString[0], mFont, this);
00410   NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
00411 
00412   nscoord i, start = 0;
00413   for (i=0; i<aLength; i++) {
00414     nsFontPS* fontThisChar = nsFontPS::FindFont(aString[i], mFont, this);
00415     NS_ASSERTION(fontThisChar,"failed to find a font");
00416     NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
00417     if (fontThisChar != fontPS) {
00418       // measure text up to this point
00419       aWidth += fontPS->GetWidth(aString+start, i-start);
00420       start = i;
00421       fontPS = fontThisChar;
00422     }
00423   }
00424   // measure the last part
00425   if (aLength-start)
00426       aWidth += fontPS->GetWidth(aString+start, aLength-start);
00427 
00428   return NS_OK;
00429 }
00430 
00431 
00436 NS_IMETHODIMP
00437 nsFontMetricsPS :: GetStringWidth(const PRUnichar *aString,nscoord& aWidth,nscoord aLength)
00438 {
00439   aWidth = 0;
00440   if (aLength == 0)
00441     return NS_OK;
00442   nsFontPS* fontPS = nsFontPS::FindFont(aString[0], mFont, this);
00443   NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
00444 
00445   nscoord i, start = 0;
00446   for (i=0; i<aLength; i++) {
00447     nsFontPS* fontThisChar = nsFontPS::FindFont(aString[i], mFont, this);
00448     NS_ASSERTION(fontThisChar,"failed to find a font");
00449     NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
00450     if (fontThisChar != fontPS) {
00451       // measure text up to this point
00452       aWidth += fontPS->GetWidth(aString+start, i-start);
00453       start = i;
00454       fontPS = fontThisChar;
00455     }
00456   }
00457   // measure the last part
00458   if (aLength-start)
00459       aWidth += fontPS->GetWidth(aString+start, aLength-start);
00460 
00461   return NS_OK;
00462 }
00463 
00464 nsFontPS*
00465 nsFontPS::FindFont(char aChar, const nsFont& aFont, 
00466                    nsFontMetricsPS* aFontMetrics)
00467 {
00468   PRUnichar uc = (unsigned char)aChar;
00469   return FindFont(uc, aFont, aFontMetrics);
00470 }
00471 
00472 // nsFontPS
00473 nsFontPS*
00474 nsFontPS::FindFont(PRUnichar aChar, const nsFont& aFont, 
00475                    nsFontMetricsPS* aFontMetrics)
00476 {
00477   nsFontPS* fontPS;
00478 
00479 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00480   nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext();
00481   NS_ENSURE_TRUE(dc, nsnull);
00482   if (dc->mFTPEnable) {
00483 #ifdef MOZ_ENABLE_XFT
00484     fontPS = nsFontPSXft::FindFont(aChar, aFont, aFontMetrics);
00485 #else
00486     fontPS = nsFontPSFreeType::FindFont(aChar, aFont, aFontMetrics);
00487 #endif
00488     if (fontPS)
00489       return fontPS;
00490   }
00491 #endif
00492 
00493   /* Find in afm font */
00494   if (aFontMetrics->GetFontsPS()->Count() > 0) {
00495     fontps *fps = (fontps*)aFontMetrics->GetFontsPS()->ElementAt(0);
00496     NS_ENSURE_TRUE(fps, nsnull);
00497     fontPS = fps->fontps;
00498   }
00499   else {
00500     fontPS = nsFontPSAFM::FindFont(aFont, aFontMetrics);
00501     fontps *fps = new fontps;
00502     NS_ENSURE_TRUE(fps, nsnull);
00503     fps->fontps = fontPS;
00504 #if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_FREETYPE2) 
00505     fps->entry  = nsnull;
00506 #ifdef MOZ_ENABLE_XFT
00507     fps->charset = nsnull;
00508 #else
00509     fps->ccmap  = nsnull;
00510 #endif
00511 #endif
00512     aFontMetrics->GetFontsPS()->AppendElement(fps);
00513   }
00514   return fontPS;
00515 }
00516 
00517 nsFontPS::nsFontPS(const nsFont& aFont, nsFontMetricsPS* aFontMetrics)
00518 {
00519   mFont = new nsFont(aFont);
00520   if (!mFont) return;
00521   mFontMetrics = aFontMetrics;
00522 }
00523 
00524 nsFontPS::~nsFontPS()
00525 {
00526   if (mFont) {
00527     delete mFont;
00528     mFont = nsnull;
00529   }
00530 
00531   if (mCCMap) {
00532     FreeCCMap(mCCMap);
00533   }
00534 
00535   mFontMetrics = nsnull;
00536 }
00537 
00538 // nsFontPSAFM
00539 nsFontPS*
00540 nsFontPSAFM::FindFont(const nsFont& aFont, nsFontMetricsPS* aFontMetrics)
00541 {
00542   nsAFMObject* afmInfo = new nsAFMObject();
00543   if (!afmInfo) return nsnull;
00544   afmInfo->Init(aFont.size);
00545 
00546   PRInt16 fontIndex = afmInfo->CheckBasicFonts(aFont, PR_TRUE);
00547   if (fontIndex < 0) {
00548     if (!(afmInfo->AFM_ReadFile(aFont))) {
00549       fontIndex = afmInfo->CheckBasicFonts(aFont, PR_FALSE);
00550       if (fontIndex < 0) {
00551         fontIndex = afmInfo->CreateSubstituteFont(aFont);
00552       }
00553     }
00554   }
00555 
00556   nsFontPSAFM* fontPSAFM = nsnull;
00557   if (fontIndex < 0)
00558     delete afmInfo;
00559   else
00560     fontPSAFM = new nsFontPSAFM(aFont, afmInfo, fontIndex, aFontMetrics);
00561   return fontPSAFM;
00562 }
00563 
00564 nsFontPSAFM::nsFontPSAFM(const nsFont& aFont, nsAFMObject* aAFMInfo,
00565                          PRInt16 fontIndex, nsFontMetricsPS* aFontMetrics) :
00566 nsFontPS(aFont, aFontMetrics), mAFMInfo(aAFMInfo), mFontIndex(fontIndex)
00567 {
00568   if (!(mFont && mAFMInfo)) return;
00569   AppendASCIItoUTF16(mAFMInfo->mPSFontInfo->mFamilyName, mFamilyName);
00570 }
00571 
00572 nsFontPSAFM::~nsFontPSAFM()
00573 {
00574   if (mAFMInfo) {
00575     delete mAFMInfo;
00576     mAFMInfo = nsnull;
00577   }
00578 }
00579 
00580 nscoord
00581 nsFontPSAFM::GetWidth(const char* aString, PRUint32 aLength)
00582 {
00583   nscoord width = 0;
00584   if (mAFMInfo) {
00585     mAFMInfo->GetStringWidth(aString, width, aLength);
00586   }
00587   return width;
00588 }
00589 
00590 nscoord
00591 nsFontPSAFM::GetWidth(const PRUnichar* aString, PRUint32 aLength)
00592 {
00593   nscoord width = 0;
00594   if (mAFMInfo) {
00595     mAFMInfo->GetStringWidth(aString, width, aLength);
00596   }
00597   return width;
00598 }
00599 
00600 nscoord
00601 nsFontPSAFM::DrawString(nsRenderingContextPS* aContext,
00602                         nscoord aX, nscoord aY,
00603                         const char* aString, PRUint32 aLength)
00604 {
00605   NS_ENSURE_TRUE(aContext, 0);
00606   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
00607   NS_ENSURE_TRUE(psObj, 0);
00608 
00609   psObj->moveto(aX, aY);
00610   psObj->show(aString, aLength, "");
00611   return GetWidth(aString, aLength);
00612 }
00613 
00614 nscoord
00615 nsFontPSAFM::DrawString(nsRenderingContextPS* aContext,
00616                         nscoord aX, nscoord aY,
00617                         const PRUnichar* aString, PRUint32 aLength)
00618 {
00619   NS_ENSURE_TRUE(aContext, 0);
00620   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
00621   NS_ENSURE_TRUE(psObj, 0);
00622 
00623   psObj->moveto(aX, aY);
00624   psObj->show(aString, aLength, "", 0);
00625   return GetWidth(aString, aLength);
00626 }
00627 
00628 nsresult
00629 nsFontPSAFM::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app)
00630 {
00631   NS_ENSURE_ARG_POINTER(aFontMetrics);
00632 
00633   float fontSize;
00634   float offset;
00635 
00636   nscoord onePixel = NSToCoordRound(1 * dev2app);
00637 
00638   // convert the font size which is in twips to points
00639   fontSize = mFont->size / TWIPS_PER_POINT_FLOAT;
00640 
00641   offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mXHeight) / 1000.0f;
00642   nscoord xHeight = NSToCoordRound(offset);
00643   aFontMetrics->SetXHeight(xHeight);
00644   aFontMetrics->SetSuperscriptOffset(xHeight);
00645   aFontMetrics->SetSubscriptOffset(xHeight);
00646   aFontMetrics->SetStrikeout((nscoord)(xHeight / 2), onePixel);
00647 
00648   offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mUnderlinePosition) / 1000.0f;
00649   aFontMetrics->SetUnderline(NSToCoordRound(offset), onePixel);
00650 
00651   nscoord size = NSToCoordRound(fontSize * dev2app);
00652   aFontMetrics->SetHeight(size);
00653   aFontMetrics->SetEmHeight(size);
00654   aFontMetrics->SetMaxAdvance(size);
00655   aFontMetrics->SetMaxHeight(size);
00656 
00657   offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mAscender) / 1000.0f;
00658   nscoord ascent = NSToCoordRound(offset);
00659   aFontMetrics->SetAscent(ascent);
00660   aFontMetrics->SetEmAscent(ascent);
00661   aFontMetrics->SetMaxAscent(ascent);
00662 
00663   offset = NSFloatPointsToTwips(fontSize * mAFMInfo->mPSFontInfo->mDescender) / 1000.0f;
00664   nscoord descent = -(NSToCoordRound(offset));
00665   aFontMetrics->SetDescent(descent);
00666   aFontMetrics->SetEmDescent(descent);
00667   aFontMetrics->SetMaxDescent(descent);
00668 
00669   aFontMetrics->SetLeading(0);
00670 
00671   nscoord spaceWidth = GetWidth(" ", 1);
00672   aFontMetrics->SetSpaceWidth(spaceWidth);
00673 
00674   nscoord aveCharWidth = GetWidth("x", 1);
00675   aFontMetrics->SetAveCharWidth(aveCharWidth);
00676 
00677   return NS_OK;
00678 }
00679 
00680 nsresult
00681 nsFontPSAFM::SetupFont(nsRenderingContextPS* aContext)
00682 {
00683   NS_ENSURE_TRUE(aContext && mFontMetrics, 0);
00684   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
00685   NS_ENSURE_TRUE(psObj, 0);
00686 
00687   nscoord fontHeight = 0;
00688   mFontMetrics->GetHeight(fontHeight);
00689 
00690   psObj->setscriptfont(mFontIndex, mFamilyName,
00691                        fontHeight, mFont->style, mFont->variant,
00692                        mFont->weight, mFont->decorations);
00693   return NS_OK;
00694 }
00695 
00696 #ifdef MOZ_MATHML
00697 nsresult
00698 nsFontPSAFM::GetBoundingMetrics(const char*        aString,
00699                                 PRUint32           aLength,
00700                                 nsBoundingMetrics& aBoundingMetrics)
00701 {
00702   return NS_ERROR_NOT_IMPLEMENTED;
00703 }
00704 
00705 nsresult
00706 nsFontPSAFM::GetBoundingMetrics(const PRUnichar*   aString,
00707                                 PRUint32           aLength,
00708                                 nsBoundingMetrics& aBoundingMetrics)
00709 {
00710   return NS_ERROR_NOT_IMPLEMENTED;
00711 }
00712 #endif
00713 
00714 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00715 
00716 #define WIDEN_8_TO_16_BUF_SIZE 1024
00717 
00718 #ifdef MOZ_ENABLE_XFT
00719 
00720 nsXftEntry::nsXftEntry(FcPattern *aFontPattern)
00721 {
00722   mFace = nsnull;
00723   mFaceIndex = 0;
00724 
00725   char *fcResult;
00726   int fcIndex;
00727 
00728   if (FcPatternGetString(aFontPattern, FC_FILE, 0, (FcChar8 **) &fcResult)
00729       == FcResultMatch)     
00730     mFontFileName = fcResult;
00731 
00732   if (FcPatternGetString(aFontPattern, FC_FAMILY, 0, (FcChar8 **) &fcResult)
00733       == FcResultMatch)     
00734     mFamilyName = fcResult;
00735 
00736   if (FcPatternGetString(aFontPattern, FC_STYLE, 0, (FcChar8 **) &fcResult)
00737       == FcResultMatch)
00738     mStyleName = fcResult;
00739 
00740   if (FcPatternGetInteger(aFontPattern, FC_INDEX, 0, &fcIndex)
00741       == FcResultMatch)
00742     mFaceIndex = fcIndex;
00743 }
00744 
00745 
00746 static nsFontPS*
00747 CreateFontPS(nsXftEntry *aEntry, const nsFont& aFont,
00748              nsFontMetricsPS* aFontMetrics)
00749 {
00750   nsresult rv;
00751   nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext();
00752   NS_ENSURE_TRUE(dc, nsnull);
00753 
00754   nsCAutoString fileName(aEntry->mFontFileName);
00755   nsCAutoString familyName(aEntry->mFamilyName);
00756   nsCAutoString styleName(aEntry->mStyleName);
00757   ToLowerCase(familyName);
00758   ToLowerCase(styleName);
00759   
00760   nsCAutoString fontName;
00761   fontName.Append(familyName);
00762   fontName.Append("-");
00763   fontName.Append(styleName);
00764   nsCStringKey key(fontName);
00765 
00766   nsHashtable *psFGList = dc->GetPSFontGeneratorList();
00767   NS_ENSURE_TRUE(psFGList, nsnull);
00768   
00769   nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(&key);
00770   if (!psFontGen) {
00771     psFontGen = new nsXftType1Generator;
00772     NS_ENSURE_TRUE(psFontGen, nsnull);
00773     rv = ((nsXftType1Generator*)psFontGen)->Init(aEntry);
00774     if (NS_FAILED(rv)) {
00775       delete psFontGen;
00776       return nsnull;
00777     }
00778     psFGList->Put(&key, (void *) psFontGen);
00779   }
00780   nsFontPSXft* font = new nsFontPSXft(aFont, aFontMetrics);
00781   NS_ENSURE_TRUE(font, nsnull);
00782   rv = font->Init(aEntry, psFontGen);
00783   if (NS_FAILED(rv)) {
00784     delete font;
00785     return nsnull;
00786   }
00787   return font;
00788 }
00789 
00790 /* static */
00791 PRBool
00792 nsFontPSXft::CSSFontEnumCallback(const nsString& aFamily, PRBool aIsGeneric,
00793                                       void* aFpi)
00794 {
00795     fontPSInfo *fpi = (fontPSInfo *)aFpi;
00796 
00797 
00798     // fontconfig always returns family names in UTF-8 so that we
00799     // should do the same here.
00800     NS_ConvertUTF16toUTF8 name(aFamily);
00801 
00802     // The newest fontconfig does the full Unicode case folding so that 
00803     // we're being lazy here by calling |ToLowerCase| after converting
00804     // to UTF-8  assuming that in virtually all cases, we just have to
00805     // fold [A-Z].  (bug 223653). 
00806     ToLowerCase(name);
00807     fpi->mFontList.AppendCString(name);
00808     fpi->mFontIsGeneric.AppendElement((void *)aIsGeneric);
00809     if (aIsGeneric) {
00810         fpi->mGenericFont =
00811             fpi->mFontList.CStringAt(fpi->mFontList.Count() - 1);
00812         return PR_FALSE; // stop processing
00813     }
00814 
00815     return PR_TRUE; // keep processing
00816 }
00817 
00818 nsFontPS*
00819 nsFontPSXft::FindFont(PRUnichar aChar, const nsFont& aFont, 
00820                            nsFontMetricsPS* aFontMetrics)
00821 {
00822   PRBool inited = PR_FALSE;
00823   nsCOMPtr<nsIAtom> langGroup;
00824   fontPSInfo fpi;
00825   fpi.fontps = aFontMetrics->GetFontsPS();
00826   int i = 0;
00827 
00828   while (1) {
00829     //
00830     // see if it is already in the list of fonts
00831     //
00832     for (; i<fpi.fontps->Count(); i++) {
00833       fontps *fi = (fontps *)fpi.fontps->ElementAt(i);
00834       if (!fi->entry || !fi->charset) {
00835         NS_ASSERTION(fi->entry, "invalid entry");
00836         NS_ASSERTION(fi->charset, "invalid charset");
00837         continue;
00838       }
00839       if (FcCharSetHasChar(fi->charset, aChar)) {
00840         if (!fi->fontps) {
00841 #ifdef PR_LOGGING
00842           if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) {
00843             PR_LogPrint("CreateFontPS %s/%s\n",
00844                 fi->entry->mFamilyName.get(), fi->entry->mStyleName.get());
00845           }
00846 #endif
00847           fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics);
00848         }
00849         if (fi->fontps)
00850           return fi->fontps;
00851       }
00852     }
00853 
00854     // if already get all matched fonts and not found suitable
00855     // then return nsnull
00856     if (fpi.fontps->Count() > 0)
00857       return nsnull;
00858 
00859     //
00860     // it is not already in the list of fonts
00861     // so add more fonts to the list
00862     //
00863     if (inited)
00864       return nsnull;
00865  
00866     inited = PR_TRUE;
00867 
00868     fpi.nsfont = &aFont;
00869     fpi.alreadyLoaded = aFontMetrics->GetFontsAlreadyLoadedList();
00870     fpi.mGenericFont = nsnull;
00871 
00872     aFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
00873     if (!langGroup)
00874       langGroup = NS_NewAtom("x-western");
00875 
00876     // enumerate over the font names passed in
00877     aFont.EnumerateFamilies(nsFontPSXft::CSSFontEnumCallback, &fpi);
00878 
00879     nsCOMPtr<nsIPref> prefService;
00880     prefService = do_GetService(NS_PREF_CONTRACTID);
00881     if (!prefService)
00882       return nsnull;
00883 
00884     nsXPIDLCString value;
00885     nsCAutoString  defaultFont;
00886 
00887     nsAutoString langGroupStr;
00888     langGroup->ToString(langGroupStr);
00889 
00890     // Set up the default font name if it's not set
00891     if (!fpi.mGenericFont) {
00892       nsCAutoString name("font.default.");
00893       LossyAppendUTF16toASCII(langGroupStr, name);
00894       prefService->CopyCharPref(name.get(), getter_Copies(value));
00895 
00896       if (value.get())
00897         defaultFont = value.get();
00898       else
00899         defaultFont = "serif";
00900 
00901       fpi.mGenericFont = &defaultFont;
00902     }
00903 
00904     // If pattern is null, set up the base bits of it so we can
00905     // match.  If we need to match later we don't have to set it up
00906     // again.
00907     FcPattern *pattern = nsnull;
00908 
00909     pattern = FcPatternCreate();
00910     if (!pattern)
00911       return nsnull;
00912 
00913     // XXX need to add user defined family
00914 
00915     // Add CSS names - walk the list of fonts, adding the generic as
00916     // the last font
00917     for (int i=0; i < fpi.mFontList.Count(); ++i) {
00918       // if this was a generic name, break out of the loop since we
00919       // don't want to add it to the pattern yet
00920       if (fpi.mFontIsGeneric[i])
00921         break;;
00922 
00923       nsCString *familyName = fpi.mFontList.CStringAt(i);
00924       NS_AddFFRE(pattern, familyName, PR_FALSE);
00925     }
00926 
00927     // Add the language group.  Note that we do this before adding any
00928     // generics.  That's because the language is more important than
00929     // any generic font.
00930     NS_AddLangGroup(pattern, langGroup);
00931 
00932     // If there's a generic add a pref for the generic if there's one
00933     // set.
00934     if (fpi.mGenericFont && !aFont.systemFont) {
00935       NS_AddGenericFontFromPref(fpi.mGenericFont, langGroup, pattern,
00936 #ifdef PR_LOGGING
00937                                 gFontMetricsPSM); 
00938 #else 
00939                                 nsnull);
00940 #endif
00941     }
00942 
00943     // Add the generic if there is one.
00944     if (fpi.mGenericFont && !aFont.systemFont)
00945       NS_AddFFRE(pattern, fpi.mGenericFont, PR_FALSE);
00946 
00947     // Add the slant type
00948     FcPatternAddInteger(pattern, FC_SLANT, NS_CalculateSlant(aFont.style));
00949 
00950     // Add the weight
00951     FcPatternAddInteger(pattern, FC_WEIGHT, NS_CalculateWeight(aFont.weight));
00952 
00953     // Set up the default substitutions for this font
00954     FcConfigSubstitute(0, pattern, FcMatchPattern);
00955     FcDefaultSubstitute(pattern);
00956 
00957     FcResult   result;
00958     FcFontSet *set = FcFontSort(0, pattern, FcTrue, 0, &result);
00959     if (!set) {
00960        return nsnull;
00961     }
00962 
00963     // Create a list of new font objects based on the fonts returned
00964     // as part of the query
00965     for (int i=0; i < set->nfont; ++i) {
00966         FcBool fc_outline;
00967         FcChar8 *fc_family;
00968         FcChar8 *fc_style;
00969         FcCharSet *fc_charset;
00970 
00971         // skip if the fonts is not outline font files.
00972         result = FcPatternGetBool (set->fonts[i], FC_OUTLINE, 0, &fc_outline);
00973         if (!fc_outline)
00974           continue;
00975 
00976         result = FcPatternGetString (set->fonts[i], FC_FAMILY, 0, &fc_family);
00977         if (result != FcResultMatch || fc_family == nsnull)
00978           continue;
00979 
00980         result = FcPatternGetString (set->fonts[i], FC_STYLE, 0, &fc_style);
00981         if (result != FcResultMatch || fc_style == nsnull)
00982           continue;
00983 
00984         result = FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &fc_charset);
00985         if (result != FcResultMatch || fc_charset == nsnull)
00986           continue;
00987         // increment reference count
00988         fc_charset = FcCharSetCopy(fc_charset);
00989         if (fc_charset == nsnull)
00990           continue;
00991 
00992         nsXftEntry *xftEntry = new nsXftEntry(set->fonts[i]);
00993         if (!xftEntry)
00994           continue;
00995 
00996         fontps *fps = new fontps;
00997         fps->entry = xftEntry;
00998         fps->charset = fc_charset;
00999         fps->fontps = nsnull;
01000         fpi.fontps->AppendElement(fps);
01001     }
01002 
01003     // we're done with the set now
01004     FcFontSetDestroy(set);
01005 
01006     FcPatternDestroy(pattern);
01007   }
01008 
01009   return nsnull;
01010 }
01011 
01012 nsFontPSXft::nsFontPSXft(const nsFont& aFont,
01013                                    nsFontMetricsPS* aFontMetrics)
01014   :nsFontPS(aFont, aFontMetrics)
01015 {
01016 }
01017 
01018 nsresult
01019 nsFontPSXft::Init(nsXftEntry* aEntry,
01020                        nsPSFontGenerator* aPSFontGen)
01021 {
01022   NS_ENSURE_TRUE(aEntry && aPSFontGen, NS_ERROR_FAILURE);
01023   mEntry = aEntry;
01024   mPSFontGenerator = aPSFontGen;
01025 
01026   float app2dev;
01027   nsIDeviceContext* dc = mFontMetrics->GetDeviceContext();
01028   NS_ENSURE_TRUE(dc, NS_ERROR_NULL_POINTER);
01029   app2dev = dc->AppUnitsToDevUnits();
01030   
01031   mPixelSize = NSToIntRound(app2dev * mFont->size);
01032 
01033   FT_Error fterror; 
01034   fterror = FT_Init_FreeType(&mFreeTypeLibrary);
01035   if (fterror) {
01036     NS_ERROR("failed to initialize FreeType library");
01037     mFreeTypeLibrary = nsnull;
01038     return NS_ERROR_FAILURE;
01039   }
01040   return NS_OK;
01041 }
01042 
01043 nsFontPSXft::~nsFontPSXft()
01044 {
01045   if (mEntry->mFace) {
01046     FT_Done_Face(mEntry->mFace);
01047     mEntry->mFace = nsnull;
01048   }
01049 
01050   if (FT_Done_FreeType(mFreeTypeLibrary))
01051     return;
01052 
01053   mEntry = nsnull;
01054 }
01055 
01056 FT_Face
01057 nsFontPSXft::getFTFace()
01058 {
01059   FT_Face face = mEntry->mFace;
01060 
01061   if (face)
01062     return (face);
01063 
01064   if (FT_New_Face(mFreeTypeLibrary, mEntry->mFontFileName.get(), 
01065                   mEntry->mFaceIndex, &face) ||
01066       FT_Set_Pixel_Sizes(face, mPixelSize, 0))
01067     return nsnull;
01068 
01069   mEntry->mFace = face;
01070   return face;
01071 }
01072 
01073 nscoord
01074 nsFontPSXft::GetWidth(const char* aString, PRUint32 aLength)
01075 {
01076   return GetWidth(NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength);
01077 }
01078 
01079 nscoord
01080 nsFontPSXft::GetWidth(const PRUnichar* aString, PRUint32 aLength)
01081 {
01082   // get the face/size from the FreeType cache
01083   FT_Face face = getFTFace();
01084   NS_ASSERTION(face, "failed to get face/size");
01085   if (!face)
01086     return 0;
01087 
01088   // XXX : we might need some caching here
01089   double em_size = 1.0 * face->units_per_EM;
01090   double x_scale = face->size->metrics.x_ppem / em_size;
01091   double origin_x = 0;
01092   for (PRUint32 i=0; i<aLength; i++) {
01093     FT_UInt glyph_index = FT_Get_Char_Index((FT_Face)face, aString[i]);
01094     if (FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE ))
01095       origin_x += face->size->metrics.x_ppem/2 + 2;
01096     else
01097       origin_x += (face->glyph->advance.x) * x_scale;
01098   }
01099 
01100   NS_ENSURE_TRUE(mFontMetrics, 0);
01101 
01102   nsDeviceContextPS* dc = mFontMetrics->GetDeviceContext();
01103   NS_ENSURE_TRUE(dc, 0);
01104 
01105   origin_x *= dc->DevUnitsToAppUnits();
01106 
01107   return NSToCoordRound((nscoord)origin_x);
01108 }
01109 
01110 nscoord
01111 nsFontPSXft::DrawString(nsRenderingContextPS* aContext,
01112                         nscoord aX, nscoord aY,
01113                         const char* aString, PRUint32 aLength)
01114 {
01115   NS_ENSURE_TRUE(aContext, 0);
01116   return DrawString(aContext, aX, aY, 
01117                     NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength);
01118 }
01119 
01120 nscoord
01121 nsFontPSXft::DrawString(nsRenderingContextPS* aContext,
01122                         nscoord aX, nscoord aY,
01123                         const PRUnichar* aString, PRUint32 aLength)
01124 {
01125   NS_ENSURE_TRUE(aContext && aLength, 0);
01126   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
01127   NS_ENSURE_TRUE(psObj, 0);
01128 
01129   psObj->moveto(aX, aY);
01130 
01131   PRInt32 currSubFont, prevSubFont = -1;
01132   PRUint32 start = 0;
01133   PRUint32 i;
01134 
01135   // XXX : ignore surrogate pairs for now
01136   nsString *subSet = mPSFontGenerator->GetSubset();
01137   for (i = 0; i < aLength; ++i) {
01138     currSubFont = mPSFontGenerator->AddToSubset(aString[i]);
01139     if (prevSubFont != currSubFont) {
01140       if (prevSubFont != -1)
01141         psObj->show(&aString[start], i - start, *subSet, prevSubFont);
01142       NS_ASSERTION(!mFontNameBase.IsEmpty(),
01143                   "font base name shouldn't be empty");
01144       psObj->setfont(mFontNameBase, mHeight, currSubFont);
01145       prevSubFont = currSubFont;
01146       start = i;
01147     }
01148   }
01149 
01150   if (prevSubFont != -1)
01151     psObj->show(&aString[start], i - start, *subSet, prevSubFont); 
01152   
01153   return GetWidth(aString, aLength);
01154 }
01155 
01156 int
01157 nsFontPSXft::ascent()
01158 {
01159   FT_Face face = getFTFace();
01160   NS_ASSERTION(face, "failed to get face/size");
01161   NS_ENSURE_TRUE(face, 0);
01162   return FT_DESIGN_UNITS_TO_PIXELS(face->ascender, face->size->metrics.y_scale);
01163 }
01164 
01165 int
01166 nsFontPSXft::descent()
01167 {
01168   FT_Face face = getFTFace();
01169   NS_ASSERTION(face, "failed to get face/size");
01170   NS_ENSURE_TRUE(face, 0);
01171   return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale);
01172 }
01173 
01174 int
01175 nsFontPSXft::max_ascent()
01176 {
01177   FT_Face face = getFTFace();
01178   NS_ASSERTION(face, "failed to get face/size");
01179   NS_ENSURE_TRUE(face, 0);
01180   TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
01181   NS_ASSERTION(tt_os2, "unable to get OS2 table");
01182   if (tt_os2)
01183      return FT_DESIGN_UNITS_TO_PIXELS(tt_os2->sTypoAscender,
01184                                       face->size->metrics.y_scale);
01185   else
01186      return FT_DESIGN_UNITS_TO_PIXELS(face->bbox.yMax,
01187                                       face->size->metrics.y_scale);
01188 }
01189 
01190 int
01191 nsFontPSXft::max_descent()
01192 {
01193   FT_Face face = getFTFace();
01194   NS_ASSERTION(face, "failed to get face/size");
01195   NS_ENSURE_TRUE(face, 0);
01196   TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
01197   NS_ASSERTION(tt_os2, "unable to get OS2 table");
01198   if (tt_os2)
01199      return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender,
01200                                       face->size->metrics.y_scale);
01201   else
01202      return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin,
01203                                       face->size->metrics.y_scale);
01204 }
01205 
01206 int
01207 nsFontPSXft::max_width()
01208 {
01209   FT_Face face = getFTFace();
01210   NS_ASSERTION(face, "failed to get face/size");
01211   NS_ENSURE_TRUE(face, 0);
01212   return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width,
01213                                    face->size->metrics.x_scale);
01214 }
01215 
01216 PRBool
01217 nsFontPSXft::getXHeight(unsigned long &aVal)
01218 {
01219   FT_Face face = getFTFace();
01220   NS_ASSERTION(face, "failed to get face/size");
01221   if (!face || !aVal)
01222     return PR_FALSE;
01223   aVal = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale);
01224 
01225   return PR_TRUE;
01226 }
01227 
01228 PRBool
01229 nsFontPSXft::underlinePosition(long &aVal)
01230 {
01231   FT_Face face = getFTFace();
01232   NS_ASSERTION(face, "failed to get face/size");
01233   if (!face)
01234     return PR_FALSE;
01235   aVal = FT_DESIGN_UNITS_TO_PIXELS(-face->underline_position,
01236                                    face->size->metrics.y_scale);
01237   return PR_TRUE;
01238 }
01239 
01240 PRBool
01241 nsFontPSXft::underline_thickness(unsigned long &aVal)
01242 {
01243   FT_Face face = getFTFace();
01244   NS_ASSERTION(face, "failed to get face/size");
01245   if (!face)
01246     return PR_FALSE;
01247   aVal = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
01248                                    face->size->metrics.x_scale);
01249   return PR_TRUE;
01250 }
01251 
01252 PRBool
01253 nsFontPSXft::superscript_y(long &aVal)
01254 {
01255   aVal = 0;
01256   FT_Face face = getFTFace();
01257   NS_ASSERTION(face, "failed to get face/size");
01258   if (!face)
01259     return PR_FALSE;
01260 
01261   TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
01262   NS_ASSERTION(tt_os2, "unable to get OS2 table");
01263   if (!tt_os2)
01264     return PR_FALSE;
01265 
01266   aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset,
01267                                   face->size->metrics.y_scale);
01268   return PR_TRUE;
01269 }
01270 
01271 PRBool
01272 nsFontPSXft::subscript_y(long &aVal)
01273 {
01274   aVal = 0;
01275   FT_Face face = getFTFace();
01276   NS_ASSERTION(face, "failed to get face/size");
01277   if (!face)
01278     return PR_FALSE;
01279 
01280   TT_OS2 *tt_os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
01281   NS_ASSERTION(tt_os2, "unable to get OS2 table");
01282   if (!tt_os2)
01283     return PR_FALSE;
01284 
01285   aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset,
01286                                   face->size->metrics.y_scale);
01287 
01288   // some fonts have the sign wrong. it should be always positive.
01289   aVal = (aVal < 0) ? -aVal : aVal;
01290   return PR_TRUE;
01291 }
01292 
01293 nsresult
01294 nsFontPSXft::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app)
01295 {
01296  
01297   nscoord leading, emHeight, emAscent, emDescent;
01298   nscoord maxHeight, maxAscent, maxDescent, maxAdvance;
01299   nscoord xHeight, spaceWidth, aveCharWidth;
01300   nscoord underlineOffset, underlineSize, superscriptOffset, subscriptOffset;
01301   nscoord strikeoutOffset, strikeoutSize;
01302 
01303   int lineSpacing = ascent() + descent();
01304   if (lineSpacing > mPixelSize) {
01305     leading = nscoord((lineSpacing - mPixelSize) * dev2app);
01306   }
01307   else {
01308     leading = 0;
01309   }
01310   emHeight = PR_MAX(1, nscoord(mPixelSize * dev2app));
01311   emAscent = nscoord(ascent() * mPixelSize * dev2app / lineSpacing);
01312   emDescent = emHeight - emAscent;
01313 
01314   maxHeight  = nscoord((max_ascent() + max_descent()) * dev2app);
01315   maxAscent  = nscoord(max_ascent() * dev2app) ;
01316   maxDescent = nscoord(max_descent() * dev2app);
01317   maxAdvance = nscoord(max_width() * dev2app);
01318 
01319   // 56% of ascent, best guess for non-true type
01320   xHeight = NSToCoordRound((float)ascent()* dev2app * 0.56f);
01321 
01322   PRUnichar space = (PRUnichar)' ';
01323   spaceWidth = NSToCoordRound(GetWidth(&space, 1));
01324   PRUnichar averageX = (PRUnichar)'x';
01325   aveCharWidth = NSToCoordRound(GetWidth(&averageX, 1));
01326   
01327   unsigned long pr = 0;
01328   if (getXHeight(pr)) {
01329     xHeight = (nscoord(pr * dev2app));
01330   }
01331 
01332   float height;
01333   long val;
01334   
01335   height = ascent() + descent();
01336   underlineOffset = -NSToIntRound(
01337                     PR_MAX (1, floor (0.1 * height + 0.5)) * dev2app);
01338 
01339   if (underline_thickness(pr)) {
01340     /* this will only be provided from adobe .afm fonts */
01341     underlineSize = nscoord(PR_MAX(dev2app, NSToIntRound(pr * dev2app)));
01342   }
01343   else {
01344     height = ascent() + descent();
01345     underlineSize = NSToIntRound(
01346                     PR_MAX(1, floor (0.05 * height + 0.5)) * dev2app);
01347   }
01348 
01349   if (superscript_y(val)) {
01350     superscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app)));
01351   }
01352   else {
01353     superscriptOffset = xHeight;
01354   }
01355 
01356   if (subscript_y(val)) {
01357     subscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app)));
01358   }
01359   else {
01360    subscriptOffset = xHeight;
01361   }
01362 
01363   /* need better way to calculate this */
01364   strikeoutOffset = NSToCoordRound(xHeight / 2.0);
01365   strikeoutSize = underlineSize;
01366   
01367   // TODO: leading never used, does it equal to "Height"?
01368   aFontMetrics->SetHeight(emHeight);
01369   aFontMetrics->SetEmHeight(emHeight);
01370   aFontMetrics->SetEmAscent(emAscent);
01371   aFontMetrics->SetEmDescent(emDescent);
01372   aFontMetrics->SetMaxHeight(maxHeight);
01373   aFontMetrics->SetMaxAscent(maxAscent);
01374   aFontMetrics->SetMaxDescent(maxDescent);
01375   aFontMetrics->SetMaxAdvance(maxAdvance);
01376   aFontMetrics->SetXHeight(xHeight);
01377   aFontMetrics->SetSpaceWidth(spaceWidth);
01378   aFontMetrics->SetAveCharWidth(aveCharWidth);
01379   aFontMetrics->SetUnderline(underlineOffset, underlineSize);
01380   aFontMetrics->SetSuperscriptOffset(superscriptOffset);
01381   aFontMetrics->SetSubscriptOffset(subscriptOffset);
01382   aFontMetrics->SetStrikeout(strikeoutOffset, strikeoutSize);
01383 
01384   return NS_OK;
01385 }
01386 
01387 nsresult
01388 nsFontPSXft::SetupFont(nsRenderingContextPS* aContext)
01389 {
01390   NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE);
01391   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
01392   NS_ENSURE_TRUE(psObj, NS_ERROR_FAILURE);
01393 
01394   mFontMetrics->GetHeight(mHeight);
01395 
01396   if (mFontNameBase.IsEmpty()) {
01397     int wmode = 0;
01398     FT_Face face = getFTFace();
01399     NS_ENSURE_TRUE(face, NS_ERROR_NULL_POINTER);
01400     if (NS_FAILED(FT2ToType1FontName(face, wmode, mFontNameBase)))
01401       return NS_ERROR_FAILURE;
01402   }
01403 
01404   return NS_OK;
01405 }
01406 
01407 #ifdef MOZ_MATHML
01408 nsresult
01409 nsFontPSXft::GetBoundingMetrics(const char*        aString,
01410                                      PRUint32           aLength,
01411                                      nsBoundingMetrics& aBoundingMetrics)
01412 {
01413   return NS_ERROR_NOT_IMPLEMENTED;
01414 }
01415 
01416 nsresult
01417 nsFontPSXft::GetBoundingMetrics(const PRUnichar*   aString,
01418                                      PRUint32           aLength,
01419                                      nsBoundingMetrics& aBoundingMetrics)
01420 {
01421   return NS_ERROR_NOT_IMPLEMENTED;
01422 }
01423 #endif //MOZ_MATHML
01424 
01425 #else
01426 
01427 PRBool
01428 nsFontPSFreeType::CSSFontEnumCallback(const nsString& aFamily, PRBool aGeneric,
01429                                       void* aFpi)
01430 {
01431   fontPSInfo* fpi = (fontPSInfo*)aFpi;
01432   nsCAutoString familyname;
01433   if (aGeneric) {
01434     // need lang to lookup generic pref
01435     if (strlen(fpi->lang.get()) == 0) {
01436       return PR_TRUE; // keep trying
01437     }
01438     nsXPIDLCString value;
01439     nsresult rv;
01440     nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
01441     NS_ENSURE_SUCCESS(rv, PR_TRUE); // keep trying
01442     nsCAutoString name("font.name.");
01443     LossyAppendUTF16toASCII(aFamily, name);
01444     name.Append(char('.'));
01445     name.Append(fpi->lang);
01446     pref->CopyCharPref(name.get(), getter_Copies(value));
01447     if (!value.get())
01448       return PR_TRUE; // keep trying
01449     // strip down to just the family name
01450     PRInt32 startFamily = value.FindChar('-') + 1;
01451     if (startFamily < 0) // 1st '-' not found. Not FFRE but just familyName.
01452       familyname = value;
01453     else { 
01454       PRInt32 endFamily = value.FindChar('-', startFamily);
01455       if (endFamily < 0) // 2nd '-' not found
01456         familyname.Append(Substring(value, startFamily));
01457       else  // FFRE 
01458         familyname.Append(Substring(value, startFamily, endFamily - startFamily));
01459     }
01460     PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG,
01461         ("generic font \"%s\" -> \"%s\"\n", name.get(), familyname.get()));
01462   }
01463   else
01464     LossyAppendUTF16toASCII(aFamily, familyname);
01465 
01466   AddFontEntries(familyname, fpi->lang, fpi->weight, 
01467                  nsIFontCatalogService::kFCWidthAny, fpi->slant,
01468                  nsIFontCatalogService::kFCSpacingAny, fpi);
01469 
01470   return PR_TRUE;
01471 }
01472 
01473 PRBool
01474 nsFontPSFreeType::AddUserPref(nsIAtom *aLang, const nsFont& aFont,
01475                               fontPSInfo *aFpi)
01476 {
01477   nsCAutoString emptyStr;
01478   fontPSInfo *fpi = (fontPSInfo*)aFpi;
01479   nsresult rv = NS_OK;
01480   nsCAutoString fontName;
01481   nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
01482   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01483 
01484   nsXPIDLCString value;
01485   nsCAutoString name("font.default.");
01486   name.Append(fpi->lang);
01487   pref->CopyCharPref(name.get(), getter_Copies(value));
01488   if (!value.get())
01489     return PR_FALSE;
01490 
01491   name.Assign("font.name.");
01492   name.Append(value);
01493   name.Append(char('.'));
01494   name.Append(fpi->lang);
01495   pref->CopyCharPref(name.get(), getter_Copies(value));
01496 
01497   if (!value.get())
01498     return PR_FALSE;
01499 
01500   // strip down to just the family name
01501   PRInt32 startFamily = value.FindChar('-') + 1;
01502   if (startFamily < 0) // '-' not found. Not FFRE but just familyName 
01503     fontName = value;
01504   else {
01505     PRInt32 endFamily = value.FindChar('-', startFamily);
01506     if (endFamily < 0) // 2nd '-' not found
01507       fontName.Append(Substring(value, startFamily));
01508     else  // FFRE
01509       fontName.Append(Substring(value, startFamily, endFamily - startFamily));
01510   }
01511 
01512   AddFontEntries(fontName, fpi->lang, fpi->weight,
01513                  nsIFontCatalogService::kFCWidthAny, fpi->slant,
01514                  nsIFontCatalogService::kFCSpacingAny, fpi);
01515 
01516   // wildcard the language
01517   AddFontEntries(fontName, emptyStr, fpi->weight,
01518                  nsIFontCatalogService::kFCWidthAny, fpi->slant,
01519                  nsIFontCatalogService::kFCSpacingAny, fpi);
01520 
01521   return PR_TRUE;
01522 }
01523 
01524 static nsFontPS*
01525 CreateFontPS(nsITrueTypeFontCatalogEntry *aEntry, const nsFont& aFont,
01526              nsFontMetricsPS* aFontMetrics)
01527 {
01528   nsresult rv;
01529   nsDeviceContextPS* dc = aFontMetrics->GetDeviceContext();
01530   NS_ENSURE_TRUE(dc, nsnull);
01531 
01532   nsCAutoString familyName, styleName;
01533   aEntry->GetFamilyName(familyName);
01534   aEntry->GetStyleName(styleName);
01535   ToLowerCase(familyName);
01536   ToLowerCase(styleName);
01537   
01538   nsCAutoString fontName;
01539   fontName.Append(familyName);
01540   fontName.Append("-");
01541   fontName.Append(styleName);
01542   nsCStringKey key(fontName);
01543 
01544   nsHashtable *psFGList = dc->GetPSFontGeneratorList();
01545   NS_ENSURE_TRUE(psFGList, nsnull);
01546   
01547   nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(&key);
01548   if (!psFontGen) {
01549     psFontGen = new nsFT2Type1Generator;
01550     NS_ENSURE_TRUE(psFontGen, nsnull);
01551     rv = ((nsFT2Type1Generator*)psFontGen)->Init(aEntry);
01552     if (NS_FAILED(rv)) {
01553       delete psFontGen;
01554       return nsnull;
01555     }
01556     psFGList->Put(&key, (void *) psFontGen);
01557   }
01558   nsFontPSFreeType* font = new nsFontPSFreeType(aFont, aFontMetrics);
01559   NS_ENSURE_TRUE(font, nsnull);
01560   rv = font->Init(aEntry, psFontGen);
01561   if (NS_FAILED(rv)) {
01562     delete font;
01563     return nsnull;
01564   }
01565   return font;
01566 }
01567 
01568 nsFontPS*
01569 nsFontPSFreeType::FindFont(PRUnichar aChar, const nsFont& aFont, 
01570                            nsFontMetricsPS* aFontMetrics)
01571 {
01572   PRBool inited = PR_FALSE;
01573   int anyWeight  = nsIFontCatalogService::kFCWeightAny;
01574   int anyWidth   = nsIFontCatalogService::kFCWidthAny;
01575   int anySlant   = nsIFontCatalogService::kFCSlantAny;
01576   int anySpacing = nsIFontCatalogService::kFCSpacingAny;
01577   nsCOMPtr<nsIAtom> lang;
01578   nsCAutoString emptyStr;
01579   nsCAutoString locale;
01580   fontPSInfo fpi, fpi2;
01581   fpi.fontps = aFontMetrics->GetFontsPS();
01582 
01583   int i = 0;
01584   while (1) {
01585     //
01586     // see if it is already in the list of fonts
01587     //
01588     for (; i<fpi.fontps->Count(); i++) {
01589       fontps *fi = (fontps *)fpi.fontps->ElementAt(i);
01590       if (!fi->entry || !fi->ccmap) {
01591         NS_ASSERTION(fi->entry, "invalid entry");
01592         NS_ASSERTION(fi->ccmap, "invalid ccmap");
01593         continue;
01594       }
01595       if (CCMAP_HAS_CHAR(fi->ccmap, aChar)) {
01596         if (!fi->fontps) {
01597 #ifdef PR_LOGGING
01598           if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) {
01599             nsCAutoString familyName, styleName;
01600             fi->entry->GetFamilyName(familyName);
01601             fi->entry->GetStyleName(styleName);
01602             PR_LogPrint("CreateFontPS %s/%s\n",
01603                 familyName.get(), styleName.get());
01604           }
01605 #endif
01606           fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics);
01607         }
01608         if (fi->fontps)
01609           return fi->fontps;
01610       }
01611     }
01612 
01613     //
01614     // it is not already in the list of fonts
01615     // so add more fonts to the list
01616     //
01617 
01618     if (!inited) {
01619       fpi.nsfont = &aFont;
01620       fpi.alreadyLoaded = aFontMetrics->GetFontsAlreadyLoadedList();
01621       aFontMetrics->GetLangGroup(getter_AddRefs(lang));
01622       if (!lang)
01623         lang = NS_NewAtom("x-western");
01624       const char *langStr;
01625       lang->GetUTF8String(&langStr);
01626       if (langStr)
01627         fpi.lang.Append(langStr);
01628       gUsersLocale->GetUTF8String(&langStr);
01629       if (langStr)
01630         locale.Append(langStr);
01631       if (NS_IS_BOLD(fpi.nsfont->weight))
01632         fpi.weight = nsIFontCatalogService::kFCWeightBold;
01633       else
01634         fpi.weight = nsIFontCatalogService::kFCWeightMedium;
01635       if (fpi.nsfont->style == NS_FONT_STYLE_NORMAL)
01636         fpi.slant = nsIFontCatalogService::kFCSlantRoman;
01637       else
01638         fpi.slant = nsIFontCatalogService::kFCSlantItalic;
01639       inited = PR_TRUE;
01640     }
01641 
01642     //
01643     // Add fonts to the list following the CSS spec, user pref
01644     // After that slowly loosen the spec to enlarge the list
01645     //
01646     int state = aFontMetrics->GetFontPSState();
01647     aFontMetrics->IncrementFontPSState();
01648 
01649     switch (state) {
01650       case 0:
01651         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01652             "get the CSS specified entries for the element's language"));
01653         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi);
01654         break;
01655 
01656       case 1:
01657         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01658             "get the CSS specified entries for the user's locale"));
01659         fpi2 = fpi;
01660         fpi2.lang = locale;
01661         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01662         break;
01663 
01664       case 2:
01665         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01666             "get the CSS specified entries for any language"));
01667         fpi2 = fpi;
01668         fpi2.lang = emptyStr;
01669         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01670         break;
01671 
01672       case 3:
01673         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01674             "get the user pref for the element's language"));
01675         AddUserPref(lang, aFont, &fpi);
01676         break;
01677 
01678       case 4:
01679         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01680             "get the user pref for the user's locale"));
01681         fpi2 = fpi;
01682         fpi2.lang = locale;
01683         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01684         break;
01685 
01686       case 5:
01687         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01688             "get all the entries for this language/style"));
01689         AddFontEntries(emptyStr, fpi.lang, fpi.weight, anyWidth, fpi.slant,
01690                        anySpacing, &fpi);
01691         break;
01692 
01693       case 6:
01694         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01695             "get all the entries for the locale/style"));
01696         AddFontEntries(emptyStr, locale, fpi.weight, anyWidth, fpi.slant,
01697                        anySpacing, &fpi);
01698         break;
01699 
01700       case 7:
01701         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01702             "wildcard the slant/weight variations of CSS "
01703             "specified entries for the element's language"));
01704         fpi2 = fpi;
01705         fpi2.weight = anyWeight;
01706         fpi2.slant = 0;
01707         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01708         break;
01709 
01710       case 8:
01711         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01712             "wildcard the slant/weight variations of CSS "
01713             "specified entries for the user's locale"));
01714         fpi2 = fpi;
01715         fpi2.lang = locale;
01716         fpi2.weight = anyWeight;
01717         fpi2.slant = 0;
01718         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01719         break;
01720 
01721       case 9:
01722         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01723             "wildcard the slant/weight variations of CSS "
01724             "specified entries for any language"));
01725         fpi2 = fpi;
01726         fpi2.lang = emptyStr;
01727         fpi2.weight = anyWeight;
01728         fpi2.slant = 0;
01729         aFont.EnumerateFamilies(nsFontPSFreeType::CSSFontEnumCallback, &fpi2);
01730         break;
01731 
01732       case 10:
01733         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01734             "wildcard the slant/weight variations of the user pref"));
01735         fpi2 = fpi;
01736         fpi2.lang   = emptyStr;
01737         fpi2.weight = anyWeight;
01738         fpi2.slant  = 0;
01739         AddUserPref(lang, aFont, &fpi2);
01740         break;
01741 
01742       case 11:
01743         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01744             "wildcard the slant/weight variations for this language"));
01745         AddFontEntries(emptyStr, fpi.lang, anyWeight, anyWidth, anySlant,
01746                        anySpacing, &fpi);
01747         break;
01748 
01749       case 12:
01750         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n",
01751             "wildcard the slant/weight variations of the locale"));
01752         AddFontEntries(emptyStr, locale, anyWeight, anyWidth, anySlant,
01753                        anySpacing, &fpi);
01754         break;
01755 
01756       case 13:
01757         PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("%s\n", "get ALL font entries"));
01758         AddFontEntries(emptyStr, emptyStr, anyWeight, anyWidth, anySlant,
01759                        anySpacing, &fpi);
01760         break;
01761 
01762       default:
01763         // try to always return a font even if no font supports this char
01764         if (fpi.fontps->Count()) {
01765           PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG,
01766               ("failed to find a font supporting 0x%04x so "
01767               "returning 1st font in list\n", aChar));
01768           fontps *fi = (fontps *)fpi.fontps->ElementAt(0);
01769           if (!fi->fontps)
01770             fi->fontps = CreateFontPS(fi->entry, aFont, aFontMetrics);
01771           return fi->fontps;
01772         }
01773         PR_LOG(gFontMetricsPSM, PR_LOG_WARNING,
01774             ("failed to find a font supporting 0x%04x\n", aChar));
01775         return (nsnull);
01776     }
01777   }
01778 
01779   return nsnull;
01780 }
01781 
01782 nsresult
01783 nsFontPSFreeType::AddFontEntries(nsACString& aFamilyName, nsACString& aLanguage,
01784                                  PRUint16 aWeight, PRUint16 aWidth,
01785                                  PRUint16 aSlant, PRUint16 aSpacing,
01786                                  fontPSInfo* aFpi)
01787 {
01788   nsresult rv = NS_OK;
01789   nsCAutoString name(aFamilyName);
01790   nsCAutoString lang(aLanguage);
01791   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    family   = '%s'", name.get()));
01792   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    lang     = '%s'", lang.get()));
01793   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    aWeight  = %d", aWeight));
01794   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    aWidth   = %d", aWidth));
01795   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    aSlant   = %d", aSlant));
01796   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    aSpacing = %d", aSpacing));
01797 
01798   nsCOMPtr<nsIFontCatalogService> fcs(do_GetService(kFCSCID, &rv));
01799   NS_ENSURE_SUCCESS(rv, rv);
01800 
01801   nsCOMPtr<nsIArray> entryList;
01802   rv = fcs->GetFontCatalogEntries(aFamilyName, aLanguage,
01803                                   aWeight, aWidth, aSlant, aSpacing,
01804                                   getter_AddRefs(entryList));
01805   NS_ENSURE_SUCCESS(rv, rv);
01806 
01807   PRUint32 i, count = 0;
01808   NS_ENSURE_TRUE(entryList, NS_ERROR_FAILURE);
01809 
01810   rv = entryList->GetLength(&count);
01811   NS_ENSURE_SUCCESS(rv, rv);
01812   PR_LOG(gFontMetricsPSM, PR_LOG_DEBUG, ("    count    = %d", count));
01813 
01814   for (i=0; i<count; i++) {
01815     nsCOMPtr<nsITrueTypeFontCatalogEntry> entry = do_QueryElementAt(entryList,
01816                                                                     i, &rv);
01817     NS_ENSURE_SUCCESS(rv, rv);
01818 
01819     // check if already in list
01820     nsVoidKey key((void*)entry);
01821     PRBool loaded = aFpi->alreadyLoaded->Exists(&key);
01822 #ifdef PR_LOGGING
01823     if (PR_LOG_TEST(gFontMetricsPSM, PR_LOG_DEBUG)) {
01824       nsCAutoString fontname, stylename;
01825       entry->GetFamilyName(fontname);
01826       entry->GetStyleName(stylename);
01827       PR_LogPrint("    -- %s '%s/%s'\n", (loaded ? "already loaded" : "load"),
01828           fontname.get(), stylename.get());
01829     }
01830 #endif
01831     if (loaded)
01832       continue;
01833 
01834     PRUint16 *ccmap;
01835     PRUint32 size;
01836     entry->GetCCMap(&size, &ccmap);
01837     nsITrueTypeFontCatalogEntry *e = entry;
01838     NS_IF_ADDREF(e);
01839     fontps *fps = new fontps;
01840     NS_ENSURE_TRUE(fps, NS_ERROR_OUT_OF_MEMORY);
01841     fps->entry  = entry;
01842     fps->fontps = nsnull;
01843     fps->ccmap  = ccmap;
01844     aFpi->fontps->AppendElement(fps);
01845     aFpi->alreadyLoaded->Put(&key, (void*)1);
01846   }
01847 
01848   return rv;
01849 }
01850 
01851 nsFontPSFreeType::nsFontPSFreeType(const nsFont& aFont,
01852                                    nsFontMetricsPS* aFontMetrics)
01853   :nsFontPS(aFont, aFontMetrics)
01854 {
01855 }
01856 
01857 nsresult
01858 nsFontPSFreeType::Init(nsITrueTypeFontCatalogEntry* aEntry,
01859                        nsPSFontGenerator* aPSFontGen)
01860 {
01861   NS_ENSURE_TRUE(mFont && mFontMetrics, NS_ERROR_FAILURE);
01862   NS_ENSURE_TRUE(aEntry && aPSFontGen, NS_ERROR_FAILURE);
01863   mEntry = aEntry;
01864   mPSFontGenerator = aPSFontGen;
01865 
01866   float app2dev;
01867   nsIDeviceContext* dc = mFontMetrics->GetDeviceContext();
01868   NS_ENSURE_TRUE(dc, NS_ERROR_NULL_POINTER);
01869   app2dev = dc->AppUnitsToDevUnits();
01870   
01871   mPixelSize = NSToIntRound(app2dev * mFont->size);
01872 
01873   mImageDesc.font.face_id    = (void*)mEntry;
01874   mImageDesc.font.pix_width  = mPixelSize;
01875   mImageDesc.font.pix_height = mPixelSize;
01876   mImageDesc.image_type = 0;
01877 
01878   nsresult rv;
01879   mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
01880   if (NS_FAILED(rv)) {
01881     return NS_ERROR_FAILURE;
01882   }
01883   return NS_OK;
01884 }
01885 
01886 nsFontPSFreeType::~nsFontPSFreeType()
01887 {
01888   mEntry = nsnull;
01889 }
01890 
01891 nscoord
01892 nsFontPSFreeType::GetWidth(const char* aString, PRUint32 aLength)
01893 {
01894   return GetWidth(NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength);
01895 }
01896 
01897 nscoord
01898 nsFontPSFreeType::GetWidth(const PRUnichar* aString, PRUint32 aLength)
01899 {
01900   FT_UInt glyph_index;
01901   FT_Glyph glyph;
01902   double origin_x = 0;
01903 
01904   // get the face/size from the FreeType cache
01905   FT_Face face = getFTFace();
01906   NS_ASSERTION(face, "failed to get face/size");
01907   if (!face)
01908     return 0;
01909 
01910   FTC_Image_Cache iCache;
01911   nsresult rv = mFt2->GetImageCache(&iCache);
01912   if (NS_FAILED(rv)) {
01913     NS_ERROR("Failed to get Image Cache");
01914     return 0;
01915   }
01916 
01917   for (PRUint32 i=0; i<aLength; i++) {
01918     mFt2->GetCharIndex((FT_Face)face, aString[i], &glyph_index);
01919     nsresult rv = mFt2->ImageCacheLookup(iCache, &mImageDesc,
01920                                          glyph_index, &glyph);
01921     if (NS_FAILED(rv)) {
01922       origin_x += FT_REG_TO_16_16(face->size->metrics.x_ppem/2 + 2);
01923       continue;
01924     }
01925     origin_x += glyph->advance.x;
01926   }
01927 
01928   NS_ENSURE_TRUE(mFontMetrics, 0);
01929 
01930   nsDeviceContextPS* dc = mFontMetrics->GetDeviceContext();
01931   NS_ENSURE_TRUE(dc, 0);
01932 
01933   float dev2app;
01934   dev2app = dc->DevUnitsToAppUnits();
01935   origin_x *= dev2app;
01936   origin_x /= FT_REG_TO_16_16(1);
01937 
01938   return NSToCoordRound((nscoord)origin_x);
01939 }
01940 
01941 FT_Face
01942 nsFontPSFreeType::getFTFace()
01943 {
01944   FT_Face face = nsnull;
01945   
01946   FTC_Manager cManager;
01947   mFt2->GetFTCacheManager(&cManager);
01948   nsresult rv = mFt2->ManagerLookupSize(cManager, &mImageDesc.font,
01949                                         &face, nsnull);
01950   NS_ASSERTION(rv==0, "failed to get face/size");
01951   if (rv)
01952     return nsnull;
01953   return face;
01954 }
01955 
01956 nscoord
01957 nsFontPSFreeType::DrawString(nsRenderingContextPS* aContext,
01958                              nscoord aX, nscoord aY,
01959                              const char* aString, PRUint32 aLength)
01960 {
01961   NS_ENSURE_TRUE(aContext, 0);
01962   return DrawString(aContext, aX, aY, 
01963                     NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength);
01964 }
01965 
01966 nscoord
01967 nsFontPSFreeType::DrawString(nsRenderingContextPS* aContext,
01968                              nscoord aX, nscoord aY,
01969                              const PRUnichar* aString, PRUint32 aLength)
01970 {
01971   NS_ENSURE_TRUE(aContext && aLength, 0);
01972   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
01973   NS_ENSURE_TRUE(psObj, 0);
01974 
01975   psObj->moveto(aX, aY);
01976 
01977   PRInt32 currSubFont, prevSubFont = -1;
01978   PRUint32 start = 0;
01979   PRUint32 i;
01980 
01981   // XXX : ignore surrogate pairs for now
01982   nsString *subSet = mPSFontGenerator->GetSubset();
01983   for (i = 0; i < aLength; ++i) {
01984     currSubFont = mPSFontGenerator->AddToSubset(aString[i]);
01985     if (prevSubFont != currSubFont) {
01986       if (prevSubFont != -1)
01987         psObj->show(&aString[start], i - start, *subSet, prevSubFont); 
01988       NS_ASSERTION(!mFontNameBase.IsEmpty(),
01989                   "font base name shouldn't be empty");
01990       psObj->setfont(mFontNameBase, mHeight, currSubFont);
01991       prevSubFont = currSubFont;
01992       start = i;
01993     }
01994   }
01995 
01996   if (prevSubFont != -1)
01997     psObj->show(&aString[start], i - start, *subSet, prevSubFont);
01998   
01999   return GetWidth(aString, aLength);
02000 }
02001 
02002 int
02003 nsFontPSFreeType::ascent()
02004 {
02005   FT_Face face = getFTFace();
02006   NS_ASSERTION(face, "failed to get face/size");
02007   NS_ENSURE_TRUE(face, 0);
02008   return FT_DESIGN_UNITS_TO_PIXELS(face->ascender, face->size->metrics.y_scale);
02009 }
02010 
02011 int
02012 nsFontPSFreeType::descent()
02013 {
02014   FT_Face face = getFTFace();
02015   NS_ASSERTION(face, "failed to get face/size");
02016   NS_ENSURE_TRUE(face, 0);
02017   return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale);
02018 }
02019 
02020 int
02021 nsFontPSFreeType::max_ascent()
02022 {
02023   FT_Face face = getFTFace();
02024   NS_ASSERTION(face, "failed to get face/size");
02025   NS_ENSURE_TRUE(face, 0);
02026   void * p;
02027   mFt2->GetSfntTable(face, ft_sfnt_os2, &p);
02028   TT_OS2 * tt_os2 = (TT_OS2 *)p;
02029   NS_ASSERTION(tt_os2, "unable to get OS2 table");
02030   if (tt_os2)
02031      return FT_DESIGN_UNITS_TO_PIXELS(tt_os2->sTypoAscender,
02032                                       face->size->metrics.y_scale);
02033   else
02034      return FT_DESIGN_UNITS_TO_PIXELS(face->bbox.yMax,
02035                                       face->size->metrics.y_scale);
02036 }
02037 
02038 int
02039 nsFontPSFreeType::max_descent()
02040 {
02041   FT_Face face = getFTFace();
02042   NS_ASSERTION(face, "failed to get face/size");
02043   NS_ENSURE_TRUE(face, 0);
02044   void *p;
02045   mFt2->GetSfntTable(face, ft_sfnt_os2, &p);
02046   TT_OS2 *tt_os2 = (TT_OS2 *) p;
02047   NS_ASSERTION(tt_os2, "unable to get OS2 table");
02048   if (tt_os2)
02049      return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender,
02050                                       face->size->metrics.y_scale);
02051   else
02052      return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin,
02053                                       face->size->metrics.y_scale);
02054 }
02055 
02056 int
02057 nsFontPSFreeType::max_width()
02058 {
02059   FT_Face face = getFTFace();
02060   NS_ASSERTION(face, "failed to get face/size");
02061   NS_ENSURE_TRUE(face, 0);
02062   return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width,
02063                                    face->size->metrics.x_scale);
02064 }
02065 
02066 PRBool
02067 nsFontPSFreeType::getXHeight(unsigned long &aVal)
02068 {
02069   FT_Face face = getFTFace();
02070   NS_ASSERTION(face, "failed to get face/size");
02071   if (!face || !aVal)
02072     return PR_FALSE;
02073   aVal = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale);
02074 
02075   return PR_TRUE;
02076 }
02077 
02078 PRBool
02079 nsFontPSFreeType::underlinePosition(long &aVal)
02080 {
02081   FT_Face face = getFTFace();
02082   NS_ASSERTION(face, "failed to get face/size");
02083   if (!face)
02084     return PR_FALSE;
02085   aVal = FT_DESIGN_UNITS_TO_PIXELS(-face->underline_position,
02086                                    face->size->metrics.y_scale);
02087   return PR_TRUE;
02088 }
02089 
02090 PRBool
02091 nsFontPSFreeType::underline_thickness(unsigned long &aVal)
02092 {
02093   FT_Face face = getFTFace();
02094   NS_ASSERTION(face, "failed to get face/size");
02095   if (!face)
02096     return PR_FALSE;
02097   aVal = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
02098                                    face->size->metrics.x_scale);
02099   return PR_TRUE;
02100 }
02101 
02102 PRBool
02103 nsFontPSFreeType::superscript_y(long &aVal)
02104 {
02105   aVal = 0;
02106   FT_Face face = getFTFace();
02107   NS_ASSERTION(face, "failed to get face/size");
02108   if (!face)
02109     return PR_FALSE;
02110 
02111   TT_OS2 *tt_os2;
02112   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
02113   NS_ASSERTION(tt_os2, "unable to get OS2 table");
02114   if (!tt_os2)
02115     return PR_FALSE;
02116 
02117   aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset,
02118                                   face->size->metrics.y_scale);
02119   return PR_TRUE;
02120 }
02121 
02122 PRBool
02123 nsFontPSFreeType::subscript_y(long &aVal)
02124 {
02125   aVal = 0;
02126   FT_Face face = getFTFace();
02127   NS_ASSERTION(face, "failed to get face/size");
02128   if (!face)
02129     return PR_FALSE;
02130 
02131   TT_OS2 *tt_os2;
02132   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
02133   NS_ASSERTION(tt_os2, "unable to get OS2 table");
02134   if (!tt_os2)
02135     return PR_FALSE;
02136 
02137   aVal = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset,
02138                                   face->size->metrics.y_scale);
02139 
02140   // some fonts have the sign wrong. it should be always positive.
02141   aVal = (aVal < 0) ? -aVal : aVal;
02142   return PR_TRUE;
02143 }
02144 
02145 nsresult
02146 nsFontPSFreeType::RealizeFont(nsFontMetricsPS* aFontMetrics, float dev2app)
02147 {
02148  
02149   nscoord leading, emHeight, emAscent, emDescent;
02150   nscoord maxHeight, maxAscent, maxDescent, maxAdvance;
02151   nscoord xHeight, spaceWidth, aveCharWidth;
02152   nscoord underlineOffset, underlineSize, superscriptOffset, subscriptOffset;
02153   nscoord strikeoutOffset, strikeoutSize;
02154 
02155   int lineSpacing = ascent() + descent();
02156   if (lineSpacing > mPixelSize) {
02157     leading = nscoord((lineSpacing - mPixelSize) * dev2app);
02158   }
02159   else {
02160     leading = 0;
02161   }
02162   emHeight = PR_MAX(1, nscoord(mPixelSize * dev2app));
02163   emAscent = nscoord(ascent() * mPixelSize * dev2app / lineSpacing);
02164   emDescent = emHeight - emAscent;
02165 
02166   maxHeight  = nscoord((max_ascent() + max_descent()) * dev2app);
02167   maxAscent  = nscoord(max_ascent() * dev2app) ;
02168   maxDescent = nscoord(max_descent() * dev2app);
02169   maxAdvance = nscoord(max_width() * dev2app);
02170 
02171   // 56% of ascent, best guess for non-true type
02172   xHeight = NSToCoordRound((float)ascent()* dev2app * 0.56f);
02173 
02174   PRUnichar space = (PRUnichar)' ';
02175   spaceWidth = NSToCoordRound(GetWidth(&space, 1));
02176   PRUnichar averageX = (PRUnichar)'x';
02177   aveCharWidth = NSToCoordRound(GetWidth(&averageX, 1));
02178   
02179   unsigned long pr = 0;
02180   if (getXHeight(pr)) {
02181     xHeight = (nscoord(pr * dev2app));
02182   }
02183 
02184   float height;
02185   long val;
02186   
02187   height = ascent() + descent();
02188   underlineOffset = -NSToIntRound(
02189                     PR_MAX (1, floor (0.1 * height + 0.5)) * dev2app);
02190 
02191   if (underline_thickness(pr)) {
02192     /* this will only be provided from adobe .afm fonts */
02193     underlineSize = nscoord(PR_MAX(dev2app, NSToIntRound(pr * dev2app)));
02194   }
02195   else {
02196     height = ascent() + descent();
02197     underlineSize = NSToIntRound(
02198                     PR_MAX(1, floor (0.05 * height + 0.5)) * dev2app);
02199   }
02200 
02201   if (superscript_y(val)) {
02202     superscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app)));
02203   }
02204   else {
02205     superscriptOffset = xHeight;
02206   }
02207 
02208   if (subscript_y(val)) {
02209     subscriptOffset = nscoord(PR_MAX(dev2app, NSToIntRound(val * dev2app)));
02210   }
02211   else {
02212    subscriptOffset = xHeight;
02213   }
02214 
02215   /* need better way to calculate this */
02216   strikeoutOffset = NSToCoordRound(xHeight / 2.0);
02217   strikeoutSize = underlineSize;
02218   
02219   // TODO: leading never used, does it equal to "Height"?
02220   aFontMetrics->SetHeight(emHeight);
02221   aFontMetrics->SetEmHeight(emHeight);
02222   aFontMetrics->SetEmAscent(emAscent);
02223   aFontMetrics->SetEmDescent(emDescent);
02224   aFontMetrics->SetMaxHeight(maxHeight);
02225   aFontMetrics->SetMaxAscent(maxAscent);
02226   aFontMetrics->SetMaxDescent(maxDescent);
02227   aFontMetrics->SetMaxAdvance(maxAdvance);
02228   aFontMetrics->SetXHeight(xHeight);
02229   aFontMetrics->SetSpaceWidth(spaceWidth);
02230   aFontMetrics->SetAveCharWidth(aveCharWidth);
02231   aFontMetrics->SetUnderline(underlineOffset, underlineSize);
02232   aFontMetrics->SetSuperscriptOffset(superscriptOffset);
02233   aFontMetrics->SetSubscriptOffset(subscriptOffset);
02234   aFontMetrics->SetStrikeout(strikeoutOffset, strikeoutSize);
02235 
02236   return NS_OK;
02237 }
02238 
02239 nsresult
02240 nsFontPSFreeType::SetupFont(nsRenderingContextPS* aContext)
02241 {
02242   NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE);
02243   nsPostScriptObj* psObj = aContext->GetPostScriptObj();
02244   NS_ENSURE_TRUE(psObj, NS_ERROR_FAILURE);
02245 
02246   mFontMetrics->GetHeight(mHeight);
02247 
02248   if (mFontNameBase.IsEmpty()) {
02249     int wmode = 0;
02250     FT_Face face = getFTFace();
02251     NS_ENSURE_TRUE(face, NS_ERROR_NULL_POINTER);
02252     if (NS_FAILED(FT2ToType1FontName(face, wmode, mFontNameBase)))
02253       return NS_ERROR_FAILURE;
02254   }
02255   
02256   return NS_OK;
02257 }
02258 
02259 #ifdef MOZ_MATHML
02260 nsresult
02261 nsFontPSFreeType::GetBoundingMetrics(const char*        aString,
02262                                      PRUint32           aLength,
02263                                      nsBoundingMetrics& aBoundingMetrics)
02264 {
02265   return NS_ERROR_NOT_IMPLEMENTED;
02266 }
02267 
02268 nsresult
02269 nsFontPSFreeType::GetBoundingMetrics(const PRUnichar*   aString,
02270                                      PRUint32           aLength,
02271                                      nsBoundingMetrics& aBoundingMetrics)
02272 {
02273   return NS_ERROR_NOT_IMPLEMENTED;
02274 }
02275 #endif //MOZ_MATHML
02276 
02277 #endif //MOZ_ENABLE_FREETYPE2
02278 #endif //MOZ_ENABLE_XFT
02279 
02280 // Implementation of nsPSFontGenerator
02281 nsPSFontGenerator::nsPSFontGenerator()
02282 {
02283 }
02284 
02285 nsPSFontGenerator::~nsPSFontGenerator()
02286 {
02287 }
02288 
02289 void nsPSFontGenerator::GeneratePSFont(FILE* aFile)
02290 {
02291   NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont");
02292 }
02293 
02294 // Add a Unicode character to mSubset which will be divided into 
02295 // multiple chunks (subfonts) of 255 (kSubFontSize) characters each. 
02296 // Each chunk will be converted to a Type 1 font. Return the index of 
02297 // a subfont (chunk) this character belongs to.
02298 PRInt32
02299 nsPSFontGenerator::AddToSubset(PRUnichar aChar)
02300 {
02301   PRInt32 index = mSubset.FindChar(aChar);
02302   if (index == kNotFound) {
02303     mSubset.Append(aChar);
02304     index = mSubset.Length() - 1;
02305   }
02306   return index / kSubFontSize;
02307 }
02308 
02309 nsString *nsPSFontGenerator::GetSubset()
02310 {
02311   return &mSubset;
02312 }
02313 
02314 #ifdef MOZ_ENABLE_XFT
02315 nsXftType1Generator::nsXftType1Generator()
02316 {
02317 }
02318 
02319 nsresult
02320 nsXftType1Generator::Init(nsXftEntry* aEntry)
02321 {
02322   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
02323   mEntry = aEntry;
02324 
02325   FT_Error error = FT_Init_FreeType(&mFreeTypeLibrary);
02326   NS_ASSERTION(!error, "failed to initialize FreeType library");
02327   if (error) {
02328     mFreeTypeLibrary = nsnull;
02329     return NS_ERROR_FAILURE;
02330   }
02331 
02332   return NS_OK;
02333 }
02334 
02335 nsXftType1Generator::~nsXftType1Generator()
02336 {
02337   if (mEntry->mFace) {
02338     FT_Done_Face(mEntry->mFace);
02339     mEntry->mFace = nsnull;
02340   }
02341 
02342   if (FT_Done_FreeType(mFreeTypeLibrary))
02343     return;
02344 
02345   mEntry = nsnull;
02346 }
02347 
02348 void nsXftType1Generator::GeneratePSFont(FILE* aFile)
02349 {
02350   FT_Face face = mEntry->mFace;
02351 
02352   if (face == nsnull) {
02353     if (FT_New_Face(mFreeTypeLibrary, mEntry->mFontFileName.get(), mEntry->mFaceIndex, &face) ||
02354         face == nsnull /* || FT_Set_Pixel_Sizes(face, 16, 0) */) 
02355        return;
02356      mEntry->mFace = face;
02357   }
02358 
02359   int wmode = 0;
02360   if (!mSubset.IsEmpty())
02361     FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
02362 }
02363 
02364 #else
02365 #ifdef MOZ_ENABLE_FREETYPE2
02366 
02367 nsFT2Type1Generator::nsFT2Type1Generator()
02368 {
02369 }
02370 
02371 nsresult
02372 nsFT2Type1Generator::Init(nsITrueTypeFontCatalogEntry* aEntry)
02373 {
02374   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
02375   mEntry = aEntry;
02376   nsresult rv;
02377   mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
02378   if (NS_FAILED(rv)) {
02379     return NS_ERROR_FAILURE;
02380   }
02381   return NS_OK;
02382 }
02383 
02384 nsFT2Type1Generator::~nsFT2Type1Generator()
02385 {
02386   mEntry = nsnull;
02387 }
02388 
02389 void nsFT2Type1Generator::GeneratePSFont(FILE* aFile)
02390 {
02391   nsCAutoString fontName, styleName;
02392   mEntry->GetFamilyName(fontName);
02393   mEntry->GetStyleName(styleName);
02394   
02395   mImageDesc.font.face_id    = (void*)mEntry;
02396   // TT glyph has no relation to size
02397   mImageDesc.font.pix_width  = 16;
02398   mImageDesc.font.pix_height = 16;
02399   mImageDesc.image_type = 0;
02400   FT_Face face = nsnull;
02401   FTC_Manager cManager;
02402   mFt2->GetFTCacheManager(&cManager);
02403   nsresult rv = mFt2->ManagerLookupSize(cManager, &mImageDesc.font,
02404                                         &face, nsnull);
02405   if (NS_FAILED(rv))
02406     return;
02407  
02408   int wmode = 0;
02409   if (!mSubset.IsEmpty())
02410     FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
02411 }
02412 
02413 #endif //MOZ_ENABLE_FREETYPE2
02414 #endif //MOZ_ENABLE_XFT