Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsMac.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsCarbonHelpers.h"
00039 
00040 #include "nsFontMetricsMac.h"
00041 #include "nsDeviceContextMac.h"
00042 #include "nsUnicodeFontMappingMac.h"
00043 #include "nsUnicodeMappingUtil.h"
00044 #include "nsGfxUtils.h"
00045 #include "nsFontUtils.h"
00046 
00047 
00048 nsFontMetricsMac :: nsFontMetricsMac()
00049 {
00050   mFontNum = BAD_FONT_NUM;
00051   mFontMapping = nsnull;
00052 }
00053   
00054 nsFontMetricsMac :: ~nsFontMetricsMac()
00055 {
00056   if (mContext) {
00057     // Notify our device context that owns us so that it can update its font cache
00058     mContext->FontMetricsDeleted(this);
00059     mContext = nsnull;
00060   }
00061   if (mFontMapping) {
00062     delete mFontMapping;
00063   }
00064 }
00065 
00066 //------------------------------------------------------------------------
00067 
00068 NS_IMPL_ISUPPORTS1(nsFontMetricsMac, nsIFontMetrics)
00069 
00070 
00071 NS_IMETHODIMP nsFontMetricsMac::Init(const nsFont& aFont, nsIAtom* aLangGroup, nsIDeviceContext* aCX)
00072 {
00073   NS_ASSERTION(!(nsnull == aCX), "attempt to init fontmetrics with null device context");
00074 
00075   mFont = aFont;
00076   mLangGroup = aLangGroup;
00077   mContext = aCX;
00078   RealizeFont();
00079        
00080        TextStyle            theStyle;
00081        nsFontUtils::GetNativeTextStyle(*this, *mContext, theStyle);
00082        
00083   StTextStyleSetter styleSetter(theStyle);
00084   
00085   FontInfo fInfo;
00086   GetFontInfo(&fInfo);
00087   
00088   float  dev2app;
00089   dev2app = mContext->DevUnitsToAppUnits();
00090 
00091   mLeading    = NSToCoordRound(float(fInfo.leading) * dev2app);
00092   mEmAscent   = NSToCoordRound(float(fInfo.ascent) * dev2app);
00093   mEmDescent  = NSToCoordRound(float(fInfo.descent) * dev2app);
00094   mEmHeight   = mEmAscent + mEmDescent;
00095 
00096   mMaxHeight  = mEmHeight;
00097   mMaxAscent  = mEmAscent;
00098   mMaxDescent = mEmDescent;
00099 
00100   float maxCharWidth = float(::CharWidth('M'));  // don't use fInfo.widMax here
00101   mMaxAdvance = NSToCoordRound(maxCharWidth * dev2app);
00102   // If we try to measure draw more than ~32767 pixels
00103   // in one operation, the string may not be drawn:
00104   mMaxStringLength = PR_MAX(1, (PRInt32)floor(32767.0 / maxCharWidth));
00105 
00106   mAveCharWidth = NSToCoordRound(float(::CharWidth('x')) * dev2app);  
00107   mSpaceWidth = NSToCoordRound(float(::CharWidth(' ')) * dev2app);
00108 
00109   Point frac;
00110   frac.h = frac.v = 1;
00111   unsigned char x = 'x';
00112   short ascent;
00113   if (noErr == ::OutlineMetrics(1, &x, frac, frac, &ascent, 0, 0, 0, 0))
00114     mXHeight = NSToCoordRound(float(ascent) * dev2app);
00115   else
00116     mXHeight = NSToCoordRound(float(mMaxAscent) * 0.71f); // 0.71 = 5 / 7
00117 
00118   return NS_OK;
00119 }
00120 
00121 nsUnicodeFontMappingMac* nsFontMetricsMac::GetUnicodeFontMapping()
00122 {
00123   if (!mFontMapping)
00124   {
00125        // we should pass the documentCharset from the nsIDocument level and
00126        // the lang attribute from the tag level to here.
00127        // XXX hard code to some value till peterl pass them down.
00128        nsAutoString langGroup;
00129        if (mLangGroup)
00130               mLangGroup->ToString(langGroup);
00131     else
00132       langGroup.AssignLiteral("ja");
00133       
00134        nsString lang;
00135     mFontMapping = new nsUnicodeFontMappingMac(&mFont, mContext, langGroup, lang);
00136   }
00137   
00138        return mFontMapping;
00139 }
00140 
00141 
00142 static void MapGenericFamilyToFont(const nsString& aGenericFamily, nsString& aFontFace, ScriptCode aScriptCode)
00143 {
00144   // the CSS generic names (conversions from the old Mac Mozilla code for now)
00145   nsUnicodeMappingUtil* unicodeMappingUtil = nsUnicodeMappingUtil::GetSingleton();
00146   if (unicodeMappingUtil)
00147   {
00148     nsString*   foundFont = unicodeMappingUtil->GenericFontNameForScript(
00149           aScriptCode,
00150           unicodeMappingUtil->MapGenericFontNameType(aGenericFamily));
00151     if (foundFont)
00152     {
00153       aFontFace = *foundFont;
00154       return;
00155     }
00156   }
00157   
00158   NS_ASSERTION(0, "Failed to find a font");
00159   aFontFace.AssignLiteral("Times");
00160        
00161   /*
00162   // fall back onto hard-coded font names
00163   if (aGenericFamily.LowerCaseEqualsLiteral("serif"))
00164   {
00165     aFontFace.AssignLiteral("Times");
00166   }
00167   else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif"))
00168   {
00169     aFontFace.AssignLiteral("Helvetica");
00170   }
00171   else if (aGenericFamily.LowerCaseEqualsLiteral("cursive"))
00172   {
00173      aFontFace.AssignLiteral("Apple Chancery");
00174   }
00175   else if (aGenericFamily.LowerCaseEqualsLiteral("fantasy"))
00176   {
00177     aFontFace.AssignLiteral("Gadget");
00178   }
00179   else if (aGenericFamily.LowerCaseEqualsLiteral("monospace"))
00180   {
00181     aFontFace.AssignLiteral("Courier");
00182   }
00183   else if (aGenericFamily.LowerCaseEqualsLiteral("-moz-fixed"))
00184   {
00185     aFontFace.AssignLiteral("Courier");
00186   }
00187   */
00188 }
00189 
00190 struct FontEnumData {
00191   FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName, ScriptCode aScriptCode)
00192     : mContext(aDC), mFaceName(aFaceName), mScriptCode(aScriptCode)
00193   {}
00194   nsIDeviceContext* mContext;
00195   nsString&         mFaceName;
00196   ScriptCode         mScriptCode;
00197 };
00198 
00199 static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
00200 {
00201   FontEnumData* data = (FontEnumData*)aData;
00202   if (aGeneric)
00203   {
00204     nsAutoString realFace;
00205     MapGenericFamilyToFont(aFamily, realFace, data->mScriptCode);
00206     data->mFaceName = realFace;
00207     return PR_FALSE;  // stop
00208   }
00209   else
00210   {
00211     nsAutoString realFace;
00212     PRBool  aliased;
00213     data->mContext->GetLocalFontName(aFamily, realFace, aliased);
00214     if (aliased || (NS_OK == data->mContext->CheckFontExistence(realFace)))
00215     {
00216        data->mFaceName = realFace;
00217       return PR_FALSE;  // stop
00218     }
00219   }
00220   return PR_TRUE;
00221 }
00222 
00223 void nsFontMetricsMac::RealizeFont()
00224 {
00225        nsAutoString  fontName;
00226        nsUnicodeMappingUtil *unicodeMappingUtil;
00227        ScriptCode                         theScriptCode;
00228 
00229        unicodeMappingUtil = nsUnicodeMappingUtil::GetSingleton ();
00230        if (unicodeMappingUtil)
00231        {
00232               nsAutoString  theLangGroupString;
00233 
00234               if (mLangGroup)
00235                      mLangGroup->ToString(theLangGroupString);
00236               else
00237                      theLangGroupString.AssignLiteral("ja");
00238 
00239               theScriptCode = unicodeMappingUtil->MapLangGroupToScriptCode(
00240                   NS_ConvertUCS2toUTF8(theLangGroupString).get());
00241 
00242        }
00243        else
00244               theScriptCode = GetScriptManagerVariable (smSysScript);
00245 
00246        FontEnumData  fontData(mContext, fontName, theScriptCode);
00247        mFont.EnumerateFamilies(FontEnumCallback, &fontData);
00248   
00249        nsDeviceContextMac::GetMacFontNumber(fontName, mFontNum);
00250 }
00251 
00252 
00253 NS_IMETHODIMP
00254 nsFontMetricsMac::Destroy()
00255 {
00256   mContext = nsnull;
00257   return NS_OK;
00258 }
00259 
00260 //------------------------------------------------------------------------
00261 
00262 NS_IMETHODIMP
00263 nsFontMetricsMac :: GetXHeight(nscoord& aResult)
00264 {
00265   aResult = mXHeight;
00266   return NS_OK;
00267 }
00268 
00269 NS_IMETHODIMP
00270 nsFontMetricsMac :: GetSuperscriptOffset(nscoord& aResult)
00271 {
00272   float  dev2app;
00273   dev2app = mContext->DevUnitsToAppUnits();
00274   aResult = NSToCoordRound(float(mMaxAscent / 2) - dev2app);
00275   return NS_OK;
00276 }
00277 
00278 NS_IMETHODIMP
00279 nsFontMetricsMac :: GetSubscriptOffset(nscoord& aResult)
00280 {
00281   float  dev2app;
00282   dev2app = mContext->DevUnitsToAppUnits();
00283   aResult = NSToCoordRound(float(mMaxAscent / 2) - dev2app);
00284   return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP
00288 nsFontMetricsMac :: GetStrikeout(nscoord& aOffset, nscoord& aSize)
00289 {
00290   float  dev2app;
00291   dev2app = mContext->DevUnitsToAppUnits();
00292   aOffset = NSToCoordRound(float(mMaxAscent / 2) - dev2app);
00293   aSize = NSToCoordRound(dev2app);
00294   return NS_OK;
00295 }
00296 
00297 NS_IMETHODIMP
00298 nsFontMetricsMac :: GetUnderline(nscoord& aOffset, nscoord& aSize)
00299 {
00300   float  dev2app;
00301   dev2app = mContext->DevUnitsToAppUnits();
00302   aOffset = -NSToCoordRound( dev2app );
00303   aSize   = NSToCoordRound( dev2app );
00304   return NS_OK;
00305 }
00306 
00307 NS_IMETHODIMP nsFontMetricsMac :: GetHeight(nscoord &aHeight)
00308 {
00309   aHeight = mMaxHeight;
00310   return NS_OK;
00311 }
00312 
00313 NS_IMETHODIMP nsFontMetricsMac :: GetNormalLineHeight(nscoord &aHeight)
00314 {
00315   aHeight = mEmHeight + mLeading; // Mac's leading is external leading
00316   return NS_OK;
00317 }
00318 
00319 NS_IMETHODIMP nsFontMetricsMac :: GetLeading(nscoord &aLeading)
00320 {
00321   aLeading = mLeading;
00322   return NS_OK;
00323 }
00324 
00325 NS_IMETHODIMP
00326 nsFontMetricsMac :: GetEmHeight(nscoord &aHeight)
00327 {
00328   aHeight = mEmHeight;
00329   return NS_OK;
00330 }
00331 
00332 NS_IMETHODIMP
00333 nsFontMetricsMac :: GetEmAscent(nscoord &aAscent)
00334 {
00335   aAscent = mEmAscent;
00336   return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP
00340 nsFontMetricsMac :: GetEmDescent(nscoord &aDescent)
00341 {
00342   aDescent = mEmDescent;
00343   return NS_OK;
00344 }
00345 
00346 NS_IMETHODIMP
00347 nsFontMetricsMac :: GetMaxHeight(nscoord &aHeight)
00348 {
00349   aHeight = mMaxHeight;
00350   return NS_OK;
00351 }
00352 
00353 NS_IMETHODIMP nsFontMetricsMac :: GetMaxAscent(nscoord &aAscent)
00354 {
00355   aAscent = mMaxAscent;
00356   return NS_OK;
00357 }
00358 
00359 NS_IMETHODIMP nsFontMetricsMac :: GetMaxDescent(nscoord &aDescent)
00360 {
00361   aDescent = mMaxDescent;
00362   return NS_OK;
00363 }
00364 
00365 NS_IMETHODIMP nsFontMetricsMac :: GetMaxAdvance(nscoord &aAdvance)
00366 {
00367   aAdvance = mMaxAdvance;
00368   return NS_OK;
00369 }
00370 
00371 NS_IMETHODIMP nsFontMetricsMac :: GetAveCharWidth(nscoord &aAveCharWidth)
00372 {
00373   aAveCharWidth = mAveCharWidth;
00374   return NS_OK;
00375 }
00376 
00377 PRInt32 nsFontMetricsMac::GetMaxStringLength()
00378 {
00379   return mMaxStringLength;
00380 }
00381 
00382 nsresult nsFontMetricsMac :: GetSpaceWidth(nscoord &aSpaceWidth)
00383 {
00384   aSpaceWidth = mSpaceWidth;
00385   return NS_OK;
00386 }
00387 
00388 NS_IMETHODIMP nsFontMetricsMac::GetLangGroup(nsIAtom** aLangGroup)
00389 {
00390   if (!aLangGroup) {
00391     return NS_ERROR_NULL_POINTER;
00392   }
00393 
00394   *aLangGroup = mLangGroup;
00395   NS_IF_ADDREF(*aLangGroup);
00396 
00397   return NS_OK;
00398 }
00399 
00400 
00401 NS_IMETHODIMP nsFontMetricsMac :: GetWidths(const nscoord *&aWidths)
00402 {
00403   return NS_ERROR_NOT_IMPLEMENTED; //XXX
00404 }
00405 
00406 NS_IMETHODIMP nsFontMetricsMac :: GetFontHandle(nsFontHandle &aHandle)
00407 {
00408        // NOTE: the name in the mFont may be a comma-separated list of
00409        // font names, like "Verdana, Arial, sans-serif"
00410        // If you want to do the conversion again to a Mac font, you'll
00411        // have to EnumerateFamilies() to resolve it to an installed
00412        // font again.
00413        NS_PRECONDITION(mFontNum != BAD_FONT_NUM, "Font metrics have not been initialized");
00414        
00415        // We have no 'font handles' on Mac like they have on Windows
00416        // so let's use it for the fontNum.
00417        aHandle = (nsFontHandle)mFontNum;
00418        return NS_OK;
00419 }
00420