Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsPh.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 "nsQuickSort.h"
00039 #include "nsIServiceManager.h"
00040 #include "nsFontMetricsPh.h"
00041 #include "nsPhGfxLog.h"
00042 #include "nsHashtable.h"
00043 #include "nsIPref.h"
00044 #include "nsReadableUtils.h"
00045 
00046 #include <errno.h>
00047 #include <string.h>
00048 
00049 // XXX many of these statics need to be freed at shutdown time
00050 static nsHashtable* gFontMetricsCache = nsnull;
00051 static nsCString **gFontNames = nsnull;
00052 static FontDetails *gFontDetails = nsnull;
00053 static int gnFonts = 0;
00054 static nsIPref* gPref = nsnull;
00055 
00056 #undef USER_DEFINED
00057 #define USER_DEFINED "x-user-def"
00058 
00059 static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
00060 
00061 nsFontMetricsPh::nsFontMetricsPh()
00062 {
00063        mDeviceContext = nsnull;
00064 
00065        mHeight = 0;
00066        mAscent = 0;
00067        mDescent = 0;
00068        mLeading = 0;
00069        mEmHeight = 0;
00070        mEmAscent = 0;
00071        mEmDescent = 0;
00072        mMaxHeight = 0;
00073        mMaxAscent = 0;
00074        mMaxDescent = 0;
00075        mMaxAdvance = 0;
00076        mXHeight = 0;
00077        mSuperscriptOffset = 0;
00078        mSubscriptOffset = 0;
00079        mStrikeoutSize = 0;
00080        mStrikeoutOffset = 0;
00081        mUnderlineSize = 0;
00082        mUnderlineOffset = 0;
00083        mSpaceWidth = 0;
00084        mAveCharWidth = 0;
00085 }
00086 
00087 static nsresult InitGlobals()
00088 {
00089   CallGetService(kPrefCID, &gPref);
00090   if (!gPref) return NS_ERROR_FAILURE;
00091 
00092        gFontMetricsCache = new nsHashtable();
00093        return NS_OK;
00094 }
00095 
00096 #if 0
00097 static PRBool FreeFontMetricsCache(nsHashKey* aKey, void* aData, void* aClosure)
00098 {
00099        FontQueryInfo * node = (FontQueryInfo*) aData;
00100        
00101        /* Use free() rather since we use calloc() in ::Init to alloc the node.  */
00102        if (node)
00103               free (node);
00104        
00105        return PR_TRUE;
00106 }
00107 static void FreeGlobals()
00108 {
00109        if (gFontMetricsCache)
00110        {
00111               gFontMetricsCache->Reset(FreeFontMetricsCache, nsnull);
00112               delete gFontMetricsCache;
00113               gFontMetricsCache = nsnull;
00114        }
00115 }
00116 #endif
00117 
00118 nsFontMetricsPh :: ~nsFontMetricsPh( )
00119 {
00120        if (mFontHandle)
00121           free (mFontHandle);
00122   if (mDeviceContext) {
00123     // Notify our device context that owns us so that it can update its font cache
00124     mDeviceContext->FontMetricsDeleted(this);
00125     mDeviceContext = nsnull;
00126   }
00127 }
00128 
00129 NS_IMPL_ISUPPORTS1( nsFontMetricsPh, nsIFontMetrics )
00130 
00131 NS_IMETHODIMP nsFontMetricsPh::Init ( const nsFont& aFont, nsIAtom* aLangGroup, nsIDeviceContext* aContext )
00132 {
00133        NS_ASSERTION(!(nsnull == aContext), "attempt to init fontmetrics with null device context");
00134        
00135        nsAutoString  firstFace;
00136        char          *str = nsnull;
00137        nsresult      result;
00138        PhRect_t      extent;
00139 
00140        if( !gFontMetricsCache ) {
00141               nsresult res = InitGlobals( );
00142               if( NS_FAILED(res) ) return res;
00143               }
00144        
00145        mFont = aFont;
00146        mLangGroup = aLangGroup;
00147        
00148        mDeviceContext = aContext;
00149        
00150        result = aContext->FirstExistingFont(aFont, firstFace);
00151 
00152        str = ToNewCString(firstFace);
00153 
00154 #ifdef DEBUG_Adrian
00155 printf( "\n\n\t\t\tIn nsFontMetricsPh::Init str=%s\n", str );
00156 #endif
00157 
00158        if( !str || !str[0] )
00159        {
00160               if( str ) free (str);
00161               str = strdup("serif");
00162        }
00163        
00164        const char *cstring;
00165        aLangGroup->GetUTF8String( &cstring );
00166        
00167        char prop[256];
00168        sprintf( prop, "font.name.%s.%s", str, cstring );
00169 
00170        char *font_default = NULL;
00171        gPref->CopyCharPref( prop, &font_default );
00172        if( font_default )
00173               {
00174               free (str);
00175               /* font_default was allocated. in CopyCharPref. */
00176               str = font_default;
00177               }
00178 
00179        float app2dev;
00180        app2dev = mDeviceContext->AppUnitsToDevUnits();
00181 
00182        PRInt32 sizePoints;
00183        if( mFont.systemFont == PR_TRUE )
00184               sizePoints = NSToIntRound( app2dev * mFont.size * 0.68 );
00185        else
00186               sizePoints = NSToIntRound( app2dev * mFont.size * 0.74 );
00187        
00188        char NSFullFontName[MAX_FONT_TAG];
00189 
00190        unsigned int uiFlags = 0L;
00191 
00192        if(aFont.weight > NS_FONT_WEIGHT_NORMAL)
00193           uiFlags |= PF_STYLE_BOLD;
00194 
00195        if(aFont.style & (NS_FONT_STYLE_ITALIC|NS_FONT_STYLE_OBLIQUE) )
00196           uiFlags |= PF_STYLE_ITALIC;
00197 
00198        PRInt32 antialias_pref = 0;
00199        gPref->GetIntPref("font.antialias_qnx", &antialias_pref);
00200        if(antialias_pref || aFont.style & NS_FONT_STYLE_ANTIALIAS)
00201               uiFlags |= PF_STYLE_ANTIALIAS;
00202 
00203        if( PfGenerateFontName( (char *)str, uiFlags, sizePoints, (char *)NSFullFontName ) == NULL )
00204          {
00205 #ifdef DEBUG_Adrian
00206 printf( "!!!!!!!!!!!! PfGenerateFontName failed\n" );
00207 #endif
00208                 PfGenerateFontName( "TextFont", uiFlags, sizePoints, (char *)NSFullFontName );
00209          }
00210 
00211        /* Once the Photon Font String is built get the attributes */
00212        FontQueryInfo *node;
00213 
00214        nsCStringKey key((char *)(NSFullFontName));
00215        node = (FontQueryInfo *) gFontMetricsCache->Get(&key);
00216 
00217 #ifdef DEBUG_Adrian
00218 printf( "\t\t\tThe generated font name is NSFullFontName=%s\n", NSFullFontName );
00219 if( node ) printf( "\t\t\t( cached ) The real font is desc=%s\n", node->desc );
00220 #endif
00221 
00222        if( !node )
00223          {
00224               node = (FontQueryInfo *)calloc(sizeof(FontQueryInfo), 1);
00225               PfQueryFont(NSFullFontName, node);
00226 
00227 #ifdef DEBUG_Adrian
00228 printf( "\t\t\t(not cached ) The real font is desc=%s\n", node->desc );
00229 printf( "\tCall PfLoadMetrics for NSFullFontName=%s\n", NSFullFontName );
00230 #endif
00231 
00232               gFontMetricsCache->Put(&key, node);
00233 
00234               PfLoadMetrics( NSFullFontName );
00235          }
00236 
00237        float dev2app;
00238        double height;
00239        nscoord onePixel;
00240 
00241        dev2app = mDeviceContext->DevUnitsToAppUnits();
00242        onePixel = NSToCoordRound(1 * dev2app);
00243        height = node->descender - node->ascender;
00244        PfExtent( &extent, NULL, NSFullFontName, 0L, 0L, " ", 1, PF_SIMPLE_METRICS, NULL );
00245        mSpaceWidth = NSToCoordRound((extent.lr.x - extent.ul.x + 1) * dev2app);
00246 
00247        mLeading = NSToCoordRound(0);
00248        mEmHeight = NSToCoordRound(height * dev2app);
00249        mEmAscent = NSToCoordRound(node->ascender * dev2app * -1.0);
00250        mEmDescent = NSToCoordRound(node->descender * dev2app);
00251        mHeight = mMaxHeight = NSToCoordRound(height * dev2app);
00252        mAscent = mMaxAscent = NSToCoordRound(node->ascender * dev2app * -1.0);
00253        mDescent = mMaxDescent = NSToCoordRound(node->descender * dev2app);
00254        mMaxAdvance = NSToCoordRound(node->width * dev2app);
00255        mAveCharWidth = mSpaceWidth;
00256 
00257        mXHeight = NSToCoordRound((float)node->ascender * dev2app * 0.56f * -1.0); // 56% of ascent, best guess for non-true type
00258        mSuperscriptOffset = mXHeight;     // XXX temporary code!
00259        mSubscriptOffset = mXHeight;     // XXX temporary code!
00260 
00261        mStrikeoutSize = onePixel; // XXX this is a guess
00262        mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0f); // 50% of xHeight
00263        mUnderlineSize = onePixel; // XXX this is a guess
00264        mUnderlineOffset = -NSToCoordRound((float)node->descender * dev2app * 0.30f); // 30% of descent
00265 
00266        if (mFontHandle)
00267           free (mFontHandle);
00268        mFontHandle = strdup(NSFullFontName);
00269 
00270        free (str);
00271        return NS_OK;
00272 }
00273 
00274 struct FontEnumData
00275 {
00276        FontEnumData(nsIDeviceContext* aContext, char* aFaceName)
00277          {
00278                 mContext = aContext;
00279                 mFaceName = aFaceName;
00280          }
00281        nsIDeviceContext* mContext;
00282        char* mFaceName;
00283 };
00284 
00285 void nsFontMetricsPh::RealizeFont()
00286 {
00287 #ifdef DEBUG_Adrian
00288 printf( "In RealizeFont\n" );
00289 #endif
00290 }
00291 
00292 struct nsFontFamily
00293 {
00294        NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
00295           PLHashTable* mCharSets;
00296 };
00297 
00298 // The Font Enumerator
00299 nsFontEnumeratorPh::nsFontEnumeratorPh()
00300 {
00301 }
00302 
00303 NS_IMPL_ISUPPORTS1(nsFontEnumeratorPh, nsIFontEnumerator)
00304 
00305 typedef struct EnumerateFamilyInfo
00306 {
00307        PRUnichar** mArray;
00308        int         mIndex;
00309 }
00310 EnumerateFamilyInfo;
00311 
00312 #if 0
00313 static PRIntn EnumerateFamily( PLHashEntry* he, PRIntn i, void* arg )
00314 {
00315        EnumerateFamilyInfo* info = (EnumerateFamilyInfo*) arg;
00316        PRUnichar** array = info->mArray;
00317        int j = info->mIndex;
00318        PRUnichar* str = ToNewUnicode(*NS_STATIC_CAST(const nsString*, he->key));
00319 
00320        if (!str)
00321          {
00322                 for (j = j - 1; j >= 0; j--)
00323                      {
00324                             nsMemory::Free(array[j]);
00325                      }
00326                 info->mIndex = 0;
00327                 return HT_ENUMERATE_STOP;
00328          }
00329        array[j] = str;
00330        info->mIndex++;
00331 
00332        return HT_ENUMERATE_NEXT;
00333 }
00334 #endif
00335 
00336 NS_IMETHODIMP nsFontEnumeratorPh::EnumerateFonts( const char* aLangGroup, const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult )
00337 {
00338 
00339        NS_ENSURE_ARG_POINTER(aResult);
00340        *aResult = nsnull;
00341        NS_ENSURE_ARG_POINTER(aCount);
00342        *aCount = 0;
00343 
00344        // aLangGroup=null or ""  means any (i.e., don't care)
00345        // aGeneric=null or ""  means any (i.e, don't care)
00346        const char* generic = nsnull;
00347        if (aGeneric && *aGeneric)
00348               generic = aGeneric;
00349 
00350        int i;
00351        if(!gFontDetails)
00352          {
00353                 gnFonts = PfQueryFonts('a', PHFONT_DONT_SHOW_LEGACY, NULL, 0);
00354                 if(gnFonts>0)
00355                      {
00356                             gFontDetails = new FontDetails[gnFonts];
00357                             if(gFontDetails)
00358                               {
00359                                    gFontNames = (nsCString**) nsMemory::Alloc(gnFonts * sizeof(nsCString*));
00360                                    PfQueryFonts('a', PHFONT_DONT_SHOW_LEGACY, gFontDetails, gnFonts);
00361 
00362                                    int total = 0;
00363                                    for(i=0;i<gnFonts;i++) {
00364                                           gFontNames[total++] = new nsCString(gFontDetails[i].desc);
00365                                           }
00366                                    gnFonts = total;
00367                               }
00368 
00369                      }
00370          }
00371 
00372        if( gnFonts > 0 )
00373          {
00374                 PRUnichar** array = (PRUnichar**) nsMemory::Alloc(gnFonts * sizeof(PRUnichar*));
00375                 if(!array)
00376                       return NS_ERROR_OUT_OF_MEMORY;
00377 
00378                 int nCount = 0;
00379                 for(i=0;i<gnFonts;i++)
00380                      {
00381                             if(!generic) /* select all fonts */
00382                               {
00383                                      if (gFontDetails[i].flags & PHFONT_INFO_PROP) /* always use proportional fonts */
00384                                           array[nCount++] = ToNewUnicode(*gFontNames[i]);
00385                               }
00386                             else if(stricmp(generic, "monospace") == 0)
00387                               {
00388                                      if(gFontDetails[i].flags & PHFONT_INFO_FIXED)
00389                                            array[nCount++] = ToNewUnicode(*gFontNames[i]);
00390                               }
00391                             /* other possible vallues for generic are: serif, sans-serif, cursive, fantasy */
00392                             else
00393                               {
00394                                      if (gFontDetails[i].flags & PHFONT_INFO_PROP) /* always use proportional fonts */
00395                                            array[nCount++] = ToNewUnicode(*gFontNames[i]);
00396                               }
00397                      }
00398                 *aCount = nCount;
00399                 *aResult = array;
00400                 return NS_OK;
00401          }
00402 
00403        return NS_OK;
00404 }