Back to index

lightning-sunbird  0.9+nobinonly
nsFT2FontNode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Stell <bstell@netscape.com>
00025  *   Louie Zhao  <louie.zhao@sun.com>
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 "nsFT2FontNode.h"
00043 #include "nsFontDebug.h"
00044 
00045 #if (!defined(MOZ_ENABLE_FREETYPE2))
00046 
00047 void nsFT2FontNode::FreeGlobals() {}
00048 
00049 nsresult nsFT2FontNode::InitGlobals()
00050 {
00051   FREETYPE_FONT_PRINTF(("freetype not compiled in"));
00052   NS_WARNING("freetype not compiled in");
00053   return NS_OK;
00054 }
00055 
00056 void nsFT2FontNode::GetFontNames(const char* aPattern,
00057                                  nsFontNodeArray* aNodes) {}
00058 
00059 #else
00060 
00061 #include "nsFreeType.h"
00062 #include "nsFontFreeType.h"
00063 #include "nsIServiceManager.h"
00064 #include "nsArray.h"
00065 
00066 nsHashtable* nsFT2FontNode::mFreeTypeNodes = nsnull;
00067 PRBool       nsFT2FontNode::sInited = PR_FALSE;
00068 nsIFontCatalogService* nsFT2FontNode::sFcs = nsnull;
00069 
00070 void
00071 nsFT2FontNode::FreeGlobals()
00072 {
00073   NS_IF_RELEASE(sFcs);
00074 
00075   if (mFreeTypeNodes) {
00076     mFreeTypeNodes->Reset(FreeNode, nsnull);
00077     delete mFreeTypeNodes;
00078     mFreeTypeNodes = nsnull;
00079   }
00080   sInited = PR_FALSE;
00081 }
00082 
00083 nsresult
00084 nsFT2FontNode::InitGlobals()
00085 {
00086   NS_ASSERTION(sInited==PR_FALSE,
00087                "nsFT2FontNode::InitGlobals called more than once");
00088   
00089   sInited = PR_TRUE;
00090 
00091   nsresult rv = ::CallGetService("@mozilla.org/gfx/xfontcatalogservice;1",
00092                                  &sFcs);
00093 
00094   if (NS_FAILED(rv)) {
00095     NS_ERROR("Font Catalog Service init failed\n");
00096     return NS_ERROR_FAILURE;
00097   }
00098 
00099   mFreeTypeNodes = new nsHashtable();
00100   if (!mFreeTypeNodes)
00101     return NS_ERROR_FAILURE;
00102   
00103   LoadNodeTable();
00104   WeightTableInitCorrection(nsFreeTypeFont::sLinearWeightTable,
00105                             nsFreeType2::gAATTDarkTextMinValue,
00106                             nsFreeType2::gAATTDarkTextGain);
00107   
00108   return NS_OK;
00109 }
00110 
00111 void
00112 nsFT2FontNode::GetFontNames(const char* aPattern, nsFontNodeArray* aNodes)
00113 {
00114   int j;
00115   PRBool rslt;
00116   PRUint32 count, i;
00117   char *pattern, *foundry, *family, *charset, *encoding;
00118   const char *charSetName;
00119   nsFontNode *node;
00120   nsCOMPtr<nsIArray> arrayFC;
00121   nsCAutoString familyTmp, languageTmp;
00122 
00123   FONT_CATALOG_PRINTF(("looking for FreeType font matching %s", aPattern));
00124   nsCAutoString patt(aPattern);
00125   ToLowerCase(patt);
00126   pattern = strdup(patt.get());
00127   NS_ASSERTION(pattern, "failed to copy pattern");
00128   if (!pattern)
00129     goto cleanup_and_return;
00130 
00131   rslt = ParseXLFD(pattern, &foundry, &family, &charset, &encoding);
00132   if (!rslt)
00133     goto cleanup_and_return;
00134 
00135   // unable to handle "name-charset-*"
00136   if (charset && !encoding) {
00137     goto cleanup_and_return;
00138   }
00139 
00140   if (family)
00141     familyTmp.Assign(family);
00142 
00143   sFcs->GetFontCatalogEntries(familyTmp, languageTmp, 0, 0, 0, 0,
00144                               getter_AddRefs(arrayFC));
00145   if (!arrayFC)
00146     goto cleanup_and_return;
00147   arrayFC->GetLength(&count);
00148   for (i = 0; i < count; i++) {
00149     nsCOMPtr<nsITrueTypeFontCatalogEntry> fce = do_QueryElementAt(arrayFC, i);
00150     if (!fce)
00151       continue;
00152     nsCAutoString foundryName, familyName;
00153     PRUint32 flags, codePageRange1, codePageRange2;
00154     PRUint16 weight, width;
00155     fce->GetFamilyName(familyName);
00156     fce->GetFlags(&flags);
00157     fce->GetWidth(&width);
00158     fce->GetWeight(&weight);
00159     fce->GetCodePageRange1(&codePageRange1);
00160     fce->GetCodePageRange2(&codePageRange2);
00161     if (!charset) { // get all encoding
00162       FONT_CATALOG_PRINTF(("found FreeType %s-%s-*-*", foundryName.get(),
00163                            familyName.get()));
00164       for (j=0; j<32; j++) {
00165         unsigned long bit = 1 << j;
00166         if (bit & codePageRange1) {
00167           charSetName = nsFreeType2::GetRange1CharSetName(bit);
00168           NS_ASSERTION(charSetName, "failed to get charset name");
00169           if (!charSetName)
00170             continue;
00171           node = LoadNode(fce, charSetName, aNodes);
00172         }
00173         if (bit & codePageRange2) {
00174           charSetName = nsFreeType2::GetRange2CharSetName(bit);
00175           if (!charSetName)
00176             continue;
00177           LoadNode(fce, charSetName, aNodes);
00178         }
00179       }
00180       if (foundryName.IsEmpty() && !familyName.IsEmpty() && flags&FCE_FLAGS_SYMBOL) {
00181         // the "registry-encoding" is not used but LoadNode will fail without
00182         // some value for this
00183         LoadNode(fce, "symbol-fontspecific", aNodes);
00184       }
00185     }
00186 
00187     if (charset && encoding) { // get this specific encoding
00188       PRUint32 cpr1_bits, cpr2_bits;
00189       nsCAutoString charsetName(charset);
00190       charsetName.Append('-');
00191       charsetName.Append(encoding);
00192       CharSetNameToCodeRangeBits(charsetName.get(), &cpr1_bits, &cpr2_bits);
00193       if (!(cpr1_bits & codePageRange1)
00194           && !(cpr2_bits & codePageRange2))
00195         continue;
00196       FONT_CATALOG_PRINTF(("found FreeType -%s-%s-%s",
00197                            familyName.get(),charset,encoding));
00198       LoadNode(fce, charsetName.get(), aNodes);
00199     }
00200   }
00201 
00202   FREE_IF(pattern);
00203   return;
00204 
00205 cleanup_and_return:
00206   FONT_CATALOG_PRINTF(("nsFT2FontNode::GetFontNames failed"));
00207   FREE_IF(pattern);
00208   return;
00209 }
00210 
00211 nsFontNode*
00212 nsFT2FontNode::LoadNode(nsITrueTypeFontCatalogEntry *aFce,
00213                         const char *aCharSetName,
00214                         nsFontNodeArray* aNodes)
00215 {
00216   nsFontCharSetMap *charSetMap = GetCharSetMap(aCharSetName);
00217   if (!charSetMap->mInfo) {
00218     return nsnull;
00219   }
00220   nsCAutoString nodeName, familyName;
00221   aFce->GetVendorID(nodeName);
00222   aFce->GetFamilyName(familyName);
00223 
00224   nodeName.Append('-');
00225   nodeName.Append(familyName);
00226   nodeName.Append('-');
00227   nodeName.Append(aCharSetName);
00228   nsCStringKey key(nodeName);
00229   nsFontNode* node = (nsFontNode*) mFreeTypeNodes->Get(&key);
00230   if (!node) {
00231     node = new nsFontNode;
00232     if (!node) {
00233       return nsnull;
00234     }
00235     mFreeTypeNodes->Put(&key, node);
00236     node->mName = nodeName;
00237     nsFontCharSetMap *charSetMap = GetCharSetMap(aCharSetName);
00238     node->mCharSetInfo = charSetMap->mInfo;
00239   }
00240 
00241   PRInt64 styleFlags;
00242   PRUint16 fceWeight, fceWidth;
00243   aFce->GetStyleFlags(&styleFlags);
00244   aFce->GetWidth(&fceWidth);
00245   aFce->GetWeight(&fceWeight);
00246 
00247   int styleIndex;
00248   if (styleFlags & FT_STYLE_FLAG_ITALIC)
00249     styleIndex = NS_FONT_STYLE_ITALIC;
00250   else
00251     styleIndex = NS_FONT_STYLE_NORMAL;
00252   nsFontStyle* style = node->mStyles[styleIndex];
00253   if (!style) {
00254     style = new nsFontStyle;
00255     if (!style) {
00256       return nsnull;
00257     }
00258     node->mStyles[styleIndex] = style;
00259   }
00260 
00261   int weightIndex = WEIGHT_INDEX(fceWeight);
00262   nsFontWeight* weight = style->mWeights[weightIndex];
00263   if (!weight) {
00264     weight = new nsFontWeight;
00265     if (!weight) {
00266       return nsnull;
00267     }
00268     style->mWeights[weightIndex] = weight;
00269   }
00270 
00271   nsFontStretch* stretch = weight->mStretches[fceWidth];
00272   if (!stretch) {
00273     stretch = new nsFontStretch;
00274     if (!stretch) {
00275       return nsnull;
00276     }
00277     weight->mStretches[fceWidth] = stretch;
00278   }
00279   if (!stretch->mFreeTypeFaceID) {
00280     stretch->mFreeTypeFaceID = aFce;
00281   }
00282   if (aNodes) {
00283     int i, n, found = 0;
00284     n = aNodes->Count();
00285     for (i=0; i<n; i++) {
00286       if (aNodes->GetElement(i) == node) {
00287         found = 1;
00288       }
00289     }
00290     if (!found) {
00291       aNodes->AppendElement(node);
00292     }
00293   }
00294   return node;
00295 }
00296 
00297 PRBool
00298 nsFT2FontNode::LoadNodeTable()
00299 {
00300   int j;
00301   nsCOMPtr<nsIArray> arrayFC;
00302   nsCAutoString family, language;
00303   sFcs->GetFontCatalogEntries(family, language, 0, 0, 0, 0,
00304                               getter_AddRefs(arrayFC));
00305   if (!arrayFC)
00306     return PR_FALSE;
00307   PRUint32 count, i;
00308   arrayFC->GetLength(&count);
00309   for (i = 0; i < count; i++) {
00310     const char *charsetName;
00311     nsCOMPtr<nsITrueTypeFontCatalogEntry> fce = do_QueryElementAt(arrayFC, i);
00312     if (!fce)
00313       continue;
00314     PRUint32 flags, codePageRange1, codePageRange2;
00315     PRUint16 weight, width;
00316     fce->GetFlags(&flags);
00317     fce->GetWidth(&width);
00318     fce->GetWeight(&weight);
00319     fce->GetCodePageRange1(&codePageRange1);
00320     fce->GetCodePageRange2(&codePageRange2);
00321     if ((!flags&FCE_FLAGS_ISVALID)
00322         || (weight < 100) || (weight > 900) || (width > 8))
00323       continue;
00324     for (j=0; j<32; j++) {
00325       unsigned long bit = 1 << j;
00326       if (!(bit & codePageRange1))
00327         continue;
00328       charsetName = nsFreeType2::GetRange1CharSetName(bit);
00329       NS_ASSERTION(charsetName, "failed to get charset name");
00330       if (!charsetName)
00331         continue;
00332       LoadNode(fce, charsetName, nsnull);
00333     }
00334     for (j=0; j<32; j++) {
00335       unsigned long bit = 1 << j;
00336       if (!(bit & codePageRange2))
00337         continue;
00338       charsetName = nsFreeType2::GetRange2CharSetName(bit);
00339       if (!charsetName)
00340         continue;
00341       LoadNode(fce, charsetName, nsnull);
00342     }
00343   }
00344   return PR_TRUE;
00345 }
00346 
00347 //
00348 // Parse XLFD
00349 // The input is a typical XLFD string.
00350 //
00351 // the XLFD entries look like this:
00352 //  -adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1
00353 //  -adobe-courier-medium-r-*-*-12-*-*-*-*-*-*-*
00354 //
00355 // the fields are:
00356 // -foundry-family-weight-slant-width-style-pixelsize-pointsize-
00357 //    resolution_x-resolution_y-spacing-avg_width-registry-encoding
00358 //
00359 // see ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/XLFD
00360 //
00361 PRBool
00362 nsFT2FontNode::ParseXLFD(char *aPattern, char** aFoundry, char** aFamily,
00363                          char** aCharset, char** aEncoding)
00364 {
00365   char *p;
00366   int i;
00367 
00368   *aFoundry  = nsnull;
00369   *aFamily   = nsnull;
00370   *aCharset  = nsnull;
00371   *aEncoding = nsnull;
00372 
00373   // start of pattern
00374   p = aPattern;
00375   NS_ASSERTION(*p == '-',"garbled pattern: does not start with a '-'");
00376   if (*p++ != '-')
00377     return PR_FALSE;
00378 
00379   // foundry
00380   NS_ASSERTION(*p,"garbled pattern: unexpected end of pattern");
00381   if (!*p)
00382     return PR_FALSE;
00383   if (*p == '*')
00384     *aFoundry = nsnull;
00385   else
00386     *aFoundry = p;
00387   while (*p && (*p!='-'))
00388     p++;
00389   if (!*p)
00390     return PR_TRUE; // short XLFD
00391   NS_ASSERTION(*p == '-',"garbled pattern: cannot find end of foundry");
00392   *p++ = '\0';
00393 
00394   // family
00395   if (!*p)
00396     return PR_TRUE; // short XLFD
00397   if (*p == '*')
00398     *aFamily = nsnull;
00399   else
00400     *aFamily = p;
00401   while (*p && (*p!='-'))
00402     p++;
00403   if (!*p)
00404     return PR_TRUE; // short XLFD
00405   NS_ASSERTION(*p == '-',"garbled pattern: cannot find end of family");
00406   *p++ = '\0';
00407 
00408   // skip forward to charset
00409   for (i=0; i<10; i++) {
00410     while (*p && (*p!='-'))
00411       p++;
00412     if (!*p)
00413       return PR_TRUE; // short XLFD
00414     *p++ = '\0';
00415   }
00416 
00417   // charset
00418   NS_ASSERTION(*p,"garbled pattern: unexpected end of pattern");
00419   if (!*p)
00420     return PR_FALSE;
00421   if (*p == '*')
00422     *aCharset = nsnull;
00423   else
00424     *aCharset = p;
00425   while (*p && (*p!='-'))
00426     p++;
00427   if (!*p)
00428     return PR_TRUE; // short XLFD
00429   NS_ASSERTION(*p == '-',"garbled pattern: cannot find end of charset");
00430   *p++ = '\0';
00431 
00432   // encoding
00433   NS_ASSERTION(*p,"garbled pattern: unexpected end of pattern");
00434   if (!*p)
00435     return PR_FALSE;
00436   if (*p == '*')
00437     *aEncoding = nsnull;
00438   else
00439     *aEncoding = p;
00440   while (*p && (*p!='-'))
00441     p++;
00442   if (*p)
00443     return PR_TRUE; // short XLFD
00444   return PR_TRUE;
00445 }
00446 
00447 #endif
00448