LCOV - code coverage report
Current view: directory - gfx/thebes - gfxFontconfigUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 497 50 10.1 %
Date: 2012-06-02 Functions: 34 3 8.8 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Japan code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Japan.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2007
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      23                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
      24                 :  *   Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "mozilla/Util.h"
      41                 : 
      42                 : #include "gfxFontconfigUtils.h"
      43                 : #include "gfxFont.h"
      44                 : #include "gfxAtoms.h"
      45                 : 
      46                 : #include <locale.h>
      47                 : #include <fontconfig/fontconfig.h>
      48                 : 
      49                 : #include "nsServiceManagerUtils.h"
      50                 : #include "nsILanguageAtomService.h"
      51                 : #include "nsTArray.h"
      52                 : #include "mozilla/Preferences.h"
      53                 : 
      54                 : #include "nsIAtom.h"
      55                 : #include "nsCRT.h"
      56                 : 
      57                 : using namespace mozilla;
      58                 : 
      59                 : /* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nsnull;
      60                 : static nsILanguageAtomService* gLangService = nsnull;
      61                 : 
      62                 : /* static */ void
      63               3 : gfxFontconfigUtils::Shutdown() {
      64               3 :     if (sUtils) {
      65               3 :         delete sUtils;
      66               3 :         sUtils = nsnull;
      67                 :     }
      68               3 :     NS_IF_RELEASE(gLangService);
      69               3 : }
      70                 : 
      71                 : /* static */ PRUint8
      72               0 : gfxFontconfigUtils::FcSlantToThebesStyle(int aFcSlant)
      73                 : {
      74               0 :     switch (aFcSlant) {
      75                 :         case FC_SLANT_ITALIC:
      76               0 :             return FONT_STYLE_ITALIC;
      77                 :         case FC_SLANT_OBLIQUE:
      78               0 :             return FONT_STYLE_OBLIQUE;
      79                 :         default:
      80               0 :             return FONT_STYLE_NORMAL;
      81                 :     }
      82                 : }
      83                 : 
      84                 : /* static */ PRUint8
      85               0 : gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern)
      86                 : {
      87                 :     int slant;
      88               0 :     if (FcPatternGetInteger(aPattern, FC_SLANT, 0, &slant) != FcResultMatch) {
      89               0 :         return FONT_STYLE_NORMAL;
      90                 :     }
      91                 : 
      92               0 :     return FcSlantToThebesStyle(slant);
      93                 : }
      94                 : 
      95                 : /* static */ int
      96               0 : gfxFontconfigUtils::GetFcSlant(const gfxFontStyle& aFontStyle)
      97                 : {
      98               0 :     if (aFontStyle.style == FONT_STYLE_ITALIC)
      99               0 :         return FC_SLANT_ITALIC;
     100               0 :     if (aFontStyle.style == FONT_STYLE_OBLIQUE)
     101               0 :         return FC_SLANT_OBLIQUE;
     102                 : 
     103               0 :     return FC_SLANT_ROMAN;
     104                 : }
     105                 : 
     106                 : // OS/2 weight classes were introduced in fontconfig-2.1.93 (2003).
     107                 : #ifndef FC_WEIGHT_THIN 
     108                 : #define FC_WEIGHT_THIN              0 // 2.1.93
     109                 : #define FC_WEIGHT_EXTRALIGHT        40 // 2.1.93
     110                 : #define FC_WEIGHT_REGULAR           80 // 2.1.93
     111                 : #define FC_WEIGHT_EXTRABOLD         205 // 2.1.93
     112                 : #endif
     113                 : // book was introduced in fontconfig-2.2.90 (and so fontconfig-2.3.0 in 2005)
     114                 : #ifndef FC_WEIGHT_BOOK
     115                 : #define FC_WEIGHT_BOOK              75
     116                 : #endif
     117                 : // extra black was introduced in fontconfig-2.4.91 (2007)
     118                 : #ifndef FC_WEIGHT_EXTRABLACK
     119                 : #define FC_WEIGHT_EXTRABLACK        215
     120                 : #endif
     121                 : 
     122                 : /* static */ PRUint16
     123               0 : gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern)
     124                 : {
     125                 :     int weight;
     126               0 :     if (FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
     127               0 :         return FONT_WEIGHT_NORMAL;
     128                 : 
     129               0 :     if (weight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2)
     130               0 :         return 100;
     131               0 :     if (weight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2)
     132               0 :         return 200;
     133               0 :     if (weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2)
     134               0 :         return 300;
     135               0 :     if (weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2)
     136                 :         // This includes FC_WEIGHT_BOOK
     137               0 :         return 400;
     138               0 :     if (weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
     139               0 :         return 500;
     140               0 :     if (weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
     141               0 :         return 600;
     142               0 :     if (weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2)
     143               0 :         return 700;
     144               0 :     if (weight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2)
     145               0 :         return 800;
     146               0 :     if (weight <= FC_WEIGHT_BLACK)
     147               0 :         return 900;
     148                 : 
     149                 :     // including FC_WEIGHT_EXTRABLACK
     150               0 :     return 901;
     151                 : }
     152                 : 
     153                 : /* static */ int
     154               0 : gfxFontconfigUtils::FcWeightForBaseWeight(PRInt8 aBaseWeight)
     155                 : {
     156               0 :     NS_PRECONDITION(aBaseWeight >= 0 && aBaseWeight <= 10,
     157                 :                     "base weight out of range");
     158                 : 
     159               0 :     switch (aBaseWeight) {
     160                 :         case 2:
     161               0 :             return FC_WEIGHT_EXTRALIGHT;
     162                 :         case 3:
     163               0 :             return FC_WEIGHT_LIGHT;
     164                 :         case 4:
     165               0 :             return FC_WEIGHT_REGULAR;
     166                 :         case 5:
     167               0 :             return FC_WEIGHT_MEDIUM;
     168                 :         case 6:
     169               0 :             return FC_WEIGHT_DEMIBOLD;
     170                 :         case 7:
     171               0 :             return FC_WEIGHT_BOLD;
     172                 :         case 8:
     173               0 :             return FC_WEIGHT_EXTRABOLD;
     174                 :         case 9:
     175               0 :             return FC_WEIGHT_BLACK;
     176                 :     }
     177                 : 
     178                 :     // extremes
     179               0 :     return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK;
     180                 : }
     181                 : 
     182                 : /* static */ PRInt16
     183               0 : gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern)
     184                 : {
     185                 :     int width;
     186               0 :     if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
     187               0 :         return NS_FONT_STRETCH_NORMAL;
     188                 :     }
     189                 : 
     190               0 :     if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) {
     191               0 :         return NS_FONT_STRETCH_ULTRA_CONDENSED;
     192                 :     }
     193               0 :     if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) {
     194               0 :         return NS_FONT_STRETCH_EXTRA_CONDENSED;
     195                 :     }
     196               0 :     if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) {
     197               0 :         return NS_FONT_STRETCH_CONDENSED;
     198                 :     }
     199               0 :     if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) {
     200               0 :         return NS_FONT_STRETCH_SEMI_CONDENSED;
     201                 :     }
     202               0 :     if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) {
     203               0 :         return NS_FONT_STRETCH_NORMAL;
     204                 :     }
     205               0 :     if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) {
     206               0 :         return NS_FONT_STRETCH_SEMI_EXPANDED;
     207                 :     }
     208               0 :     if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) {
     209               0 :         return NS_FONT_STRETCH_EXPANDED;
     210                 :     }
     211               0 :     if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) {
     212               0 :         return NS_FONT_STRETCH_EXTRA_EXPANDED;
     213                 :     }
     214               0 :     return NS_FONT_STRETCH_ULTRA_EXPANDED;
     215                 : }
     216                 : 
     217                 : /* static */ int
     218               0 : gfxFontconfigUtils::FcWidthForThebesStretch(PRInt16 aStretch)
     219                 : {
     220               0 :     switch (aStretch) {
     221                 :         default: // this will catch "normal" (0) as well as out-of-range values
     222               0 :             return FC_WIDTH_NORMAL;
     223                 :         case NS_FONT_STRETCH_ULTRA_CONDENSED:
     224               0 :             return FC_WIDTH_ULTRACONDENSED;
     225                 :         case NS_FONT_STRETCH_EXTRA_CONDENSED:
     226               0 :             return FC_WIDTH_EXTRACONDENSED;
     227                 :         case NS_FONT_STRETCH_CONDENSED:
     228               0 :             return FC_WIDTH_CONDENSED;
     229                 :         case NS_FONT_STRETCH_SEMI_CONDENSED:
     230               0 :             return FC_WIDTH_SEMICONDENSED;
     231                 :         case NS_FONT_STRETCH_SEMI_EXPANDED:
     232               0 :             return FC_WIDTH_SEMIEXPANDED;
     233                 :         case NS_FONT_STRETCH_EXPANDED:
     234               0 :             return FC_WIDTH_EXPANDED;
     235                 :         case NS_FONT_STRETCH_EXTRA_EXPANDED:
     236               0 :             return FC_WIDTH_EXTRAEXPANDED;
     237                 :         case NS_FONT_STRETCH_ULTRA_EXPANDED:
     238               0 :             return FC_WIDTH_ULTRAEXPANDED;
     239                 :     }
     240                 : }
     241                 : 
     242                 : // This makes a guess at an FC_WEIGHT corresponding to a base weight and
     243                 : // offset (without any knowledge of which weights are available).
     244                 : 
     245                 : /* static */ int
     246               0 : GuessFcWeight(const gfxFontStyle& aFontStyle)
     247                 : {
     248                 :     /*
     249                 :      * weights come in two parts crammed into one
     250                 :      * integer -- the "base" weight is weight / 100,
     251                 :      * the rest of the value is the "offset" from that
     252                 :      * weight -- the number of steps to move to adjust
     253                 :      * the weight in the list of supported font weights,
     254                 :      * this value can be negative or positive.
     255                 :      */
     256               0 :     PRInt8 weight = aFontStyle.ComputeWeight();
     257                 : 
     258                 :     // ComputeWeight trimmed the range of weights for us
     259               0 :     NS_ASSERTION(weight >= 0 && weight <= 10,
     260                 :                  "base weight out of range");
     261                 : 
     262               0 :     return gfxFontconfigUtils::FcWeightForBaseWeight(weight);
     263                 : }
     264                 : 
     265                 : static void
     266               0 : AddString(FcPattern *aPattern, const char *object, const char *aString)
     267                 : {
     268                 :     FcPatternAddString(aPattern, object,
     269               0 :                        gfxFontconfigUtils::ToFcChar8(aString));
     270               0 : }
     271                 : 
     272                 : static void
     273               0 : AddWeakString(FcPattern *aPattern, const char *object, const char *aString)
     274                 : {
     275                 :     FcValue value;
     276               0 :     value.type = FcTypeString;
     277               0 :     value.u.s = gfxFontconfigUtils::ToFcChar8(aString);
     278                 : 
     279               0 :     FcPatternAddWeak(aPattern, object, value, FcTrue);
     280               0 : }
     281                 : 
     282                 : static void
     283               0 : AddLangGroup(FcPattern *aPattern, nsIAtom *aLangGroup)
     284                 : {
     285                 :     // Translate from mozilla's internal mapping into fontconfig's
     286               0 :     nsCAutoString lang;
     287               0 :     gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang);
     288                 : 
     289               0 :     if (!lang.IsEmpty()) {
     290               0 :         AddString(aPattern, FC_LANG, lang.get());
     291                 :     }
     292               0 : }
     293                 : 
     294                 : nsReturnRef<FcPattern>
     295               0 : gfxFontconfigUtils::NewPattern(const nsTArray<nsString>& aFamilies,
     296                 :                                const gfxFontStyle& aFontStyle,
     297                 :                                const char *aLang)
     298                 : {
     299                 :     static const char* sFontconfigGenerics[] =
     300                 :         { "sans-serif", "serif", "monospace", "fantasy", "cursive" };
     301                 : 
     302               0 :     nsAutoRef<FcPattern> pattern(FcPatternCreate());
     303               0 :     if (!pattern)
     304               0 :         return nsReturnRef<FcPattern>();
     305                 : 
     306               0 :     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size);
     307               0 :     FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle));
     308               0 :     FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle));
     309               0 :     FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch));
     310                 : 
     311               0 :     if (aLang) {
     312               0 :         AddString(pattern, FC_LANG, aLang);
     313                 :     }
     314                 : 
     315               0 :     bool useWeakBinding = false;
     316               0 :     for (PRUint32 i = 0; i < aFamilies.Length(); ++i) {
     317               0 :         NS_ConvertUTF16toUTF8 family(aFamilies[i]);
     318               0 :         if (!useWeakBinding) {
     319               0 :             AddString(pattern, FC_FAMILY, family.get());
     320                 : 
     321                 :             // fontconfig generic families are typically implemented with weak
     322                 :             // aliases (so that the preferred font depends on language).
     323                 :             // However, this would give them lower priority than subsequent
     324                 :             // non-generic families in the list.  To ensure that subsequent
     325                 :             // families do not have a higher priority, they are given weak
     326                 :             // bindings.
     327               0 :             for (PRUint32 g = 0;
     328               0 :                  g < ArrayLength(sFontconfigGenerics);
     329                 :                  ++g) {
     330               0 :                 if (0 == FcStrCmpIgnoreCase(ToFcChar8(sFontconfigGenerics[g]),
     331               0 :                                             ToFcChar8(family.get()))) {
     332               0 :                     useWeakBinding = true;
     333               0 :                     break;
     334                 :                 }
     335                 :             }
     336                 :         } else {
     337               0 :             AddWeakString(pattern, FC_FAMILY, family.get());
     338                 :         }
     339                 :     }
     340                 : 
     341               0 :     return pattern.out();
     342                 : }
     343                 : 
     344               3 : gfxFontconfigUtils::gfxFontconfigUtils()
     345               3 :     : mLastConfig(NULL)
     346                 : {
     347               3 :     mFontsByFamily.Init(50);
     348               3 :     mFontsByFullname.Init(50);
     349               3 :     mLangSupportTable.Init(20);
     350               3 :     UpdateFontListInternal();
     351               3 : }
     352                 : 
     353                 : nsresult
     354               0 : gfxFontconfigUtils::GetFontList(nsIAtom *aLangGroup,
     355                 :                                 const nsACString& aGenericFamily,
     356                 :                                 nsTArray<nsString>& aListOfFonts)
     357                 : {
     358               0 :     aListOfFonts.Clear();
     359                 : 
     360               0 :     nsTArray<nsCString> fonts;
     361               0 :     nsresult rv = GetFontListInternal(fonts, aLangGroup);
     362               0 :     if (NS_FAILED(rv))
     363               0 :         return rv;
     364                 : 
     365               0 :     for (PRUint32 i = 0; i < fonts.Length(); ++i) {
     366               0 :         aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(fonts[i]));
     367                 :     }
     368                 : 
     369               0 :     aListOfFonts.Sort();
     370                 : 
     371               0 :     PRInt32 serif = 0, sansSerif = 0, monospace = 0;
     372                 : 
     373                 :     // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and
     374                 :     // "monospace", slightly different from CSS's 5.
     375               0 :     if (aGenericFamily.IsEmpty())
     376               0 :         serif = sansSerif = monospace = 1;
     377               0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("serif"))
     378               0 :         serif = 1;
     379               0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif"))
     380               0 :         sansSerif = 1;
     381               0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("monospace"))
     382               0 :         monospace = 1;
     383               0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") ||
     384               0 :              aGenericFamily.LowerCaseEqualsLiteral("fantasy"))
     385               0 :         serif = sansSerif = 1;
     386                 :     else
     387               0 :         NS_NOTREACHED("unexpected CSS generic font family");
     388                 : 
     389                 :     // The first in the list becomes the default in
     390                 :     // gFontsDialog.readFontSelection() if the preference-selected font is not
     391                 :     // available, so put system configured defaults first.
     392               0 :     if (monospace)
     393               0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace"));
     394               0 :     if (sansSerif)
     395               0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif"));
     396               0 :     if (serif)
     397               0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif"));
     398                 : 
     399               0 :     return NS_OK;
     400                 : }
     401                 : 
     402                 : struct MozLangGroupData {
     403                 :     nsIAtom* const& mozLangGroup;
     404                 :     const char *defaultLang;
     405                 : };
     406                 : 
     407                 : const MozLangGroupData MozLangGroups[] = {
     408                 :     { gfxAtoms::x_western,      "en" },
     409                 :     { gfxAtoms::x_central_euro, "pl" },
     410                 :     { gfxAtoms::x_cyrillic,     "ru" },
     411                 :     { gfxAtoms::x_baltic,       "lv" },
     412                 :     { gfxAtoms::x_devanagari,   "hi" },
     413                 :     { gfxAtoms::x_tamil,        "ta" },
     414                 :     { gfxAtoms::x_armn,         "hy" },
     415                 :     { gfxAtoms::x_beng,         "bn" },
     416                 :     { gfxAtoms::x_cans,         "iu" },
     417                 :     { gfxAtoms::x_ethi,         "am" },
     418                 :     { gfxAtoms::x_geor,         "ka" },
     419                 :     { gfxAtoms::x_gujr,         "gu" },
     420                 :     { gfxAtoms::x_guru,         "pa" },
     421                 :     { gfxAtoms::x_khmr,         "km" },
     422                 :     { gfxAtoms::x_knda,         "kn" },
     423                 :     { gfxAtoms::x_mlym,         "ml" },
     424                 :     { gfxAtoms::x_orya,         "or" },
     425                 :     { gfxAtoms::x_sinh,         "si" },
     426                 :     { gfxAtoms::x_telu,         "te" },
     427                 :     { gfxAtoms::x_tibt,         "bo" },
     428                 :     { gfxAtoms::x_unicode,      0    },
     429                 :     { gfxAtoms::x_user_def,     0    }
     430                 : };
     431                 : 
     432                 : static bool
     433               0 : TryLangForGroup(const nsACString& aOSLang, nsIAtom *aLangGroup,
     434                 :                 nsACString *aFcLang)
     435                 : {
     436                 :     // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'.
     437                 :     // aOSLang is in the form "language[_territory][.codeset][@modifier]".
     438                 :     // fontconfig takes languages in the form "language-territory".
     439                 :     // nsILanguageAtomService takes languages in the form language-subtag,
     440                 :     // where subtag may be a territory.  fontconfig and nsILanguageAtomService
     441                 :     // handle case-conversion for us.
     442                 :     const char *pos, *end;
     443               0 :     aOSLang.BeginReading(pos);
     444               0 :     aOSLang.EndReading(end);
     445               0 :     aFcLang->Truncate();
     446               0 :     while (pos < end) {
     447               0 :         switch (*pos) {
     448                 :             case '.':
     449                 :             case '@':
     450               0 :                 end = pos;
     451               0 :                 break;
     452                 :             case '_':
     453               0 :                 aFcLang->Append('-');
     454               0 :                 break;
     455                 :             default:
     456               0 :                 aFcLang->Append(*pos);
     457                 :         }
     458               0 :         ++pos;
     459                 :     }
     460                 : 
     461                 :     nsIAtom *atom =
     462               0 :         gLangService->LookupLanguage(*aFcLang);
     463                 : 
     464               0 :     return atom == aLangGroup;
     465                 : }
     466                 : 
     467                 : /* static */ void
     468               0 : gfxFontconfigUtils::GetSampleLangForGroup(nsIAtom *aLangGroup,
     469                 :                                           nsACString *aFcLang)
     470                 : {
     471               0 :     NS_PRECONDITION(aFcLang != nsnull, "aFcLang must not be NULL");
     472                 : 
     473               0 :     const MozLangGroupData *langGroup = nsnull;
     474                 : 
     475               0 :     for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) {
     476               0 :         if (aLangGroup == MozLangGroups[i].mozLangGroup) {
     477               0 :             langGroup = &MozLangGroups[i];
     478               0 :             break;
     479                 :         }
     480                 :     }
     481                 : 
     482               0 :     if (!langGroup) {
     483                 :         // Not a special mozilla language group.
     484                 :         // Use aLangGroup as a language code.
     485               0 :         aLangGroup->ToUTF8String(*aFcLang);
     486               0 :         return;
     487                 :     }
     488                 : 
     489                 :     // Check the environment for the users preferred language that corresponds
     490                 :     // to this langGroup.
     491               0 :     if (!gLangService) {
     492               0 :         CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
     493                 :     }
     494                 : 
     495               0 :     if (gLangService) {
     496               0 :         const char *languages = getenv("LANGUAGE");
     497               0 :         if (languages) {
     498               0 :             const char separator = ':';
     499                 : 
     500               0 :             for (const char *pos = languages; true; ++pos) {
     501               0 :                 if (*pos == '\0' || *pos == separator) {
     502               0 :                     if (languages < pos &&
     503               0 :                         TryLangForGroup(Substring(languages, pos),
     504               0 :                                         aLangGroup, aFcLang))
     505               0 :                         return;
     506                 : 
     507               0 :                     if (*pos == '\0')
     508                 :                         break;
     509                 : 
     510               0 :                     languages = pos + 1;
     511                 :                 }
     512                 :             }
     513                 :         }
     514               0 :         const char *ctype = setlocale(LC_CTYPE, NULL);
     515               0 :         if (ctype &&
     516               0 :             TryLangForGroup(nsDependentCString(ctype), aLangGroup, aFcLang))
     517               0 :             return;
     518                 :     }
     519                 : 
     520               0 :     if (langGroup->defaultLang) {
     521               0 :         aFcLang->Assign(langGroup->defaultLang);
     522                 :     } else {
     523               0 :         aFcLang->Truncate();
     524                 :     }
     525                 : }
     526                 : 
     527                 : nsresult
     528               0 : gfxFontconfigUtils::GetFontListInternal(nsTArray<nsCString>& aListOfFonts,
     529                 :                                         nsIAtom *aLangGroup)
     530                 : {
     531               0 :     FcPattern *pat = NULL;
     532               0 :     FcObjectSet *os = NULL;
     533               0 :     FcFontSet *fs = NULL;
     534               0 :     nsresult rv = NS_ERROR_FAILURE;
     535                 : 
     536               0 :     aListOfFonts.Clear();
     537                 : 
     538               0 :     pat = FcPatternCreate();
     539               0 :     if (!pat)
     540               0 :         goto end;
     541                 : 
     542               0 :     os = FcObjectSetBuild(FC_FAMILY, NULL);
     543               0 :     if (!os)
     544               0 :         goto end;
     545                 : 
     546                 :     // take the pattern and add the lang group to it
     547               0 :     if (aLangGroup) {
     548               0 :         AddLangGroup(pat, aLangGroup);
     549                 :     }
     550                 : 
     551               0 :     fs = FcFontList(NULL, pat, os);
     552               0 :     if (!fs)
     553               0 :         goto end;
     554                 : 
     555               0 :     for (int i = 0; i < fs->nfont; i++) {
     556                 :         char *family;
     557                 : 
     558               0 :         if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0,
     559               0 :                                (FcChar8 **) &family) != FcResultMatch)
     560                 :         {
     561               0 :             continue;
     562                 :         }
     563                 : 
     564                 :         // Remove duplicates...
     565               0 :         nsCAutoString strFamily(family);
     566               0 :         if (aListOfFonts.Contains(strFamily))
     567               0 :             continue;
     568                 : 
     569               0 :         aListOfFonts.AppendElement(strFamily);
     570                 :     }
     571                 : 
     572               0 :     rv = NS_OK;
     573                 : 
     574                 :   end:
     575               0 :     if (NS_FAILED(rv))
     576               0 :         aListOfFonts.Clear();
     577                 : 
     578               0 :     if (pat)
     579               0 :         FcPatternDestroy(pat);
     580               0 :     if (os)
     581               0 :         FcObjectSetDestroy(os);
     582               0 :     if (fs)
     583               0 :         FcFontSetDestroy(fs);
     584                 : 
     585               0 :     return rv;
     586                 : }
     587                 : 
     588                 : nsresult
     589               0 : gfxFontconfigUtils::UpdateFontList()
     590                 : {
     591               0 :     return UpdateFontListInternal(true);
     592                 : }
     593                 : 
     594                 : nsresult
     595               3 : gfxFontconfigUtils::UpdateFontListInternal(bool aForce)
     596                 : {
     597               3 :     if (!aForce) {
     598                 :         // This checks periodically according to fontconfig's configured
     599                 :         // <rescan> interval.
     600               3 :         FcInitBringUptoDate();
     601               0 :     } else if (!FcConfigUptoDate(NULL)) { // check now with aForce
     602               0 :         mLastConfig = NULL;
     603               0 :         FcInitReinitialize();
     604                 :     }
     605                 : 
     606                 :     // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config
     607                 :     // before destroying the old config, so the only way that we'd miss an
     608                 :     // update is if fontconfig did more than one update and the memory for the
     609                 :     // most recent config happened to be at the same location as the original
     610                 :     // config.
     611               3 :     FcConfig *currentConfig = FcConfigGetCurrent();
     612               3 :     if (currentConfig == mLastConfig)
     613               0 :         return NS_OK;
     614                 : 
     615                 :     // This FcFontSet is owned by fontconfig
     616               3 :     FcFontSet *fontSet = FcConfigGetFonts(currentConfig, FcSetSystem);
     617                 : 
     618               3 :     mFontsByFamily.Clear();
     619               3 :     mFontsByFullname.Clear();
     620               3 :     mLangSupportTable.Clear();
     621               3 :     mAliasForMultiFonts.Clear();
     622                 : 
     623                 :     // Record the existing font families
     624             405 :     for (int f = 0; f < fontSet->nfont; ++f) {
     625             402 :         FcPattern *font = fontSet->fonts[f];
     626                 : 
     627                 :         FcChar8 *family;
     628            1662 :         for (int v = 0;
     629             831 :              FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch;
     630                 :              ++v) {
     631             429 :             FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family);
     632             429 :             if (entry) {
     633             429 :                 bool added = entry->AddFont(font);
     634                 : 
     635             429 :                 if (!entry->mKey) {
     636                 :                     // The reference to the font pattern keeps the pointer to
     637                 :                     // string for the key valid.  If adding the font failed
     638                 :                     // then the entry must be removed.
     639             102 :                     if (added) {
     640             102 :                         entry->mKey = family;
     641                 :                     } else {
     642               0 :                         mFontsByFamily.RawRemoveEntry(entry);
     643                 :                     }
     644                 :                 }
     645                 :             }
     646                 :         }
     647                 :     }
     648                 : 
     649                 :     // XXX we don't support all alias names.
     650                 :     // Because if we don't check whether the given font name is alias name,
     651                 :     // fontconfig converts the non existing font to sans-serif.
     652                 :     // This is not good if the web page specifies font-family
     653                 :     // that has Windows font name in the first.
     654               3 :     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
     655               6 :     nsAdoptingCString list = Preferences::GetCString("font.alias-list");
     656                 : 
     657               3 :     if (!list.IsEmpty()) {
     658               3 :         const char kComma = ',';
     659                 :         const char *p, *p_end;
     660               3 :         list.BeginReading(p);
     661               3 :         list.EndReading(p_end);
     662              18 :         while (p < p_end) {
     663              24 :             while (nsCRT::IsAsciiSpace(*p)) {
     664               0 :                 if (++p == p_end)
     665               0 :                     break;
     666                 :             }
     667              12 :             if (p == p_end)
     668               0 :                 break;
     669              12 :             const char *start = p;
     670              12 :             while (++p != p_end && *p != kComma)
     671                 :                 /* nothing */ ;
     672              24 :             nsCAutoString name(Substring(start, p));
     673              12 :             name.CompressWhitespace(false, true);
     674              12 :             mAliasForMultiFonts.AppendElement(name);
     675              12 :             p++;
     676                 :         }
     677                 :     }
     678                 : 
     679               3 :     mLastConfig = currentConfig;
     680               3 :     return NS_OK;
     681                 : }
     682                 : 
     683                 : nsresult
     684               0 : gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
     685                 : {
     686               0 :     aFamilyName.Truncate();
     687                 : 
     688                 :     // The fontconfig has generic family names in the font list.
     689               0 :     if (aFontName.EqualsLiteral("serif") ||
     690               0 :         aFontName.EqualsLiteral("sans-serif") ||
     691               0 :         aFontName.EqualsLiteral("monospace")) {
     692               0 :         aFamilyName.Assign(aFontName);
     693               0 :         return NS_OK;
     694                 :     }
     695                 : 
     696               0 :     nsresult rv = UpdateFontListInternal();
     697               0 :     if (NS_FAILED(rv))
     698               0 :         return rv;
     699                 : 
     700               0 :     NS_ConvertUTF16toUTF8 fontname(aFontName);
     701                 : 
     702                 :     // return empty string if no such family exists
     703               0 :     if (!IsExistingFamily(fontname))
     704               0 :         return NS_OK;
     705                 : 
     706               0 :     FcPattern *pat = NULL;
     707               0 :     FcObjectSet *os = NULL;
     708               0 :     FcFontSet *givenFS = NULL;
     709               0 :     nsTArray<nsCString> candidates;
     710               0 :     FcFontSet *candidateFS = NULL;
     711               0 :     rv = NS_ERROR_FAILURE;
     712                 : 
     713               0 :     pat = FcPatternCreate();
     714               0 :     if (!pat)
     715               0 :         goto end;
     716                 : 
     717               0 :     FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)fontname.get());
     718                 : 
     719               0 :     os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, NULL);
     720               0 :     if (!os)
     721               0 :         goto end;
     722                 : 
     723               0 :     givenFS = FcFontList(NULL, pat, os);
     724               0 :     if (!givenFS)
     725               0 :         goto end;
     726                 : 
     727                 :     // The first value associated with a FC_FAMILY property is the family
     728                 :     // returned by GetFontList(), so use this value if appropriate.
     729                 : 
     730                 :     // See if there is a font face with first family equal to the given family.
     731               0 :     for (int i = 0; i < givenFS->nfont; ++i) {
     732                 :         char *firstFamily;
     733               0 :         if (FcPatternGetString(givenFS->fonts[i], FC_FAMILY, 0,
     734               0 :                                (FcChar8 **) &firstFamily) != FcResultMatch)
     735               0 :             continue;
     736                 : 
     737               0 :         nsDependentCString first(firstFamily);
     738               0 :         if (!candidates.Contains(first)) {
     739               0 :             candidates.AppendElement(first);
     740                 : 
     741               0 :             if (fontname.Equals(first)) {
     742               0 :                 aFamilyName.Assign(aFontName);
     743               0 :                 rv = NS_OK;
     744                 :                 goto end;
     745                 :             }
     746                 :         }
     747                 :     }
     748                 : 
     749                 :     // See if any of the first family names represent the same set of font
     750                 :     // faces as the given family.
     751               0 :     for (PRUint32 j = 0; j < candidates.Length(); ++j) {
     752               0 :         FcPatternDel(pat, FC_FAMILY);
     753               0 :         FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)candidates[j].get());
     754                 : 
     755               0 :         candidateFS = FcFontList(NULL, pat, os);
     756               0 :         if (!candidateFS)
     757               0 :             goto end;
     758                 : 
     759               0 :         if (candidateFS->nfont != givenFS->nfont)
     760               0 :             continue;
     761                 : 
     762               0 :         bool equal = true;
     763               0 :         for (int i = 0; i < givenFS->nfont; ++i) {
     764               0 :             if (!FcPatternEqual(candidateFS->fonts[i], givenFS->fonts[i])) {
     765               0 :                 equal = false;
     766               0 :                 break;
     767                 :             }
     768                 :         }
     769               0 :         if (equal) {
     770               0 :             AppendUTF8toUTF16(candidates[j], aFamilyName);
     771               0 :             rv = NS_OK;
     772               0 :             goto end;
     773                 :         }
     774                 :     }
     775                 : 
     776                 :     // No match found; return empty string.
     777               0 :     rv = NS_OK;
     778                 : 
     779                 :   end:
     780               0 :     if (pat)
     781               0 :         FcPatternDestroy(pat);
     782               0 :     if (os)
     783               0 :         FcObjectSetDestroy(os);
     784               0 :     if (givenFS)
     785               0 :         FcFontSetDestroy(givenFS);
     786               0 :     if (candidateFS)
     787               0 :         FcFontSetDestroy(candidateFS);
     788                 : 
     789               0 :     return rv;
     790                 : }
     791                 : 
     792                 : nsresult
     793               0 : gfxFontconfigUtils::ResolveFontName(const nsAString& aFontName,
     794                 :                                     gfxPlatform::FontResolverCallback aCallback,
     795                 :                                     void *aClosure,
     796                 :                                     bool& aAborted)
     797                 : {
     798               0 :     aAborted = false;
     799                 : 
     800               0 :     nsresult rv = UpdateFontListInternal();
     801               0 :     if (NS_FAILED(rv))
     802               0 :         return rv;
     803                 : 
     804               0 :     NS_ConvertUTF16toUTF8 fontname(aFontName);
     805                 :     // Sometimes, the font has two or more names (e.g., "Sazanami Gothic" has
     806                 :     // Japanese localized name).  We should not resolve to a single name
     807                 :     // because different names sometimes have different behavior. e.g., with
     808                 :     // the default settings of "Sazanami" on Fedora Core 5, the non-localized
     809                 :     // name uses anti-alias, but the localized name uses it.  So, we should
     810                 :     // check just whether the font is existing, without resolving to regular
     811                 :     // name.
     812                 :     //
     813                 :     // The family names in mAliasForMultiFonts are names understood by
     814                 :     // fontconfig.  The actual font to which they resolve depends on the
     815                 :     // entire match pattern.  That info is not available here, but there
     816                 :     // will be a font so leave the resolving to the gfxFontGroup.
     817               0 :     if (IsExistingFamily(fontname) ||
     818               0 :         mAliasForMultiFonts.Contains(fontname, gfxIgnoreCaseCStringComparator()))
     819               0 :         aAborted = !(*aCallback)(aFontName, aClosure);
     820                 : 
     821               0 :     return NS_OK;
     822                 : }
     823                 : 
     824                 : bool
     825               0 : gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName)
     826                 : {
     827               0 :     return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nsnull;
     828                 : }
     829                 : 
     830                 : const nsTArray< nsCountedRef<FcPattern> >&
     831               0 : gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName)
     832                 : {
     833               0 :     FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName);
     834                 : 
     835               0 :     if (!entry)
     836               0 :         return mEmptyPatternArray;
     837                 : 
     838               0 :     return entry->GetFonts();
     839                 : }
     840                 : 
     841                 : // Fontconfig only provides a fullname property for fonts in formats with SFNT
     842                 : // wrappers.  For other font formats (including PCF and PS Type 1), a fullname
     843                 : // must be generated from the family and style properties.  Only the first
     844                 : // family and style is checked, but that should be OK, as I don't expect
     845                 : // non-SFNT fonts to have multiple families or styles.
     846                 : bool
     847               0 : gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(FcPattern *aFont,
     848                 :                                                   nsACString *aFullname)
     849                 : {
     850                 :     FcChar8 *family;
     851               0 :     if (FcPatternGetString(aFont, FC_FAMILY, 0, &family) != FcResultMatch)
     852               0 :         return false;
     853                 : 
     854               0 :     aFullname->Truncate();
     855               0 :     aFullname->Append(ToCString(family));
     856                 : 
     857                 :     FcChar8 *style;
     858               0 :     if (FcPatternGetString(aFont, FC_STYLE, 0, &style) == FcResultMatch &&
     859               0 :         strcmp(ToCString(style), "Regular") != 0) {
     860               0 :         aFullname->Append(' ');
     861               0 :         aFullname->Append(ToCString(style));
     862                 :     }
     863                 : 
     864               0 :     return true;
     865                 : }
     866                 : 
     867                 : bool
     868               0 : gfxFontconfigUtils::FontsByFullnameEntry::KeyEquals(KeyTypePointer aKey) const
     869                 : {
     870               0 :     const FcChar8 *key = mKey;
     871                 :     // If mKey is NULL, key comes from the style and family of the first font.
     872               0 :     nsCAutoString fullname;
     873               0 :     if (!key) {
     874               0 :         NS_ASSERTION(mFonts.Length(), "No font in FontsByFullnameEntry!");
     875               0 :         GetFullnameFromFamilyAndStyle(mFonts[0], &fullname);
     876                 : 
     877               0 :         key = ToFcChar8(fullname);
     878                 :     }
     879                 : 
     880               0 :     return FcStrCmpIgnoreCase(aKey, key) == 0;
     881                 : }
     882                 : 
     883                 : void
     884               0 : gfxFontconfigUtils::AddFullnameEntries()
     885                 : {
     886                 :     // This FcFontSet is owned by fontconfig
     887               0 :     FcFontSet *fontSet = FcConfigGetFonts(NULL, FcSetSystem);
     888                 : 
     889                 :     // Record the existing font families
     890               0 :     for (int f = 0; f < fontSet->nfont; ++f) {
     891               0 :         FcPattern *font = fontSet->fonts[f];
     892                 : 
     893               0 :         int v = 0;
     894                 :         FcChar8 *fullname;
     895               0 :         while (FcPatternGetString(font,
     896               0 :                                   FC_FULLNAME, v, &fullname) == FcResultMatch) {
     897               0 :             FontsByFullnameEntry *entry = mFontsByFullname.PutEntry(fullname);
     898               0 :             if (entry) {
     899                 :                 // entry always has space for one font, so the first AddFont
     900                 :                 // will always succeed, and so the entry will always have a
     901                 :                 // font from which to obtain the key.
     902               0 :                 bool added = entry->AddFont(font);
     903                 :                 // The key may be NULL either if this is the first font, or if
     904                 :                 // the first font does not have a fullname property, and so
     905                 :                 // the key is obtained from the font.  Set the key in both
     906                 :                 // cases.  The check that AddFont succeeded is required for
     907                 :                 // the second case.
     908               0 :                 if (!entry->mKey && added) {
     909               0 :                     entry->mKey = fullname;
     910                 :                 }
     911                 :             }
     912                 : 
     913               0 :             ++v;
     914                 :         }
     915                 : 
     916                 :         // Fontconfig does not provide a fullname property for all fonts.
     917               0 :         if (v == 0) {
     918               0 :             nsCAutoString name;
     919               0 :             if (!GetFullnameFromFamilyAndStyle(font, &name))
     920               0 :                 continue;
     921                 : 
     922                 :             FontsByFullnameEntry *entry =
     923               0 :                 mFontsByFullname.PutEntry(ToFcChar8(name));
     924               0 :             if (entry) {
     925               0 :                 entry->AddFont(font);
     926                 :                 // Either entry->mKey has been set for a previous font or it
     927                 :                 // remains NULL to indicate that the key is obtained from the
     928                 :                 // first font.
     929                 :             }
     930                 :         }
     931                 :     }
     932               0 : }
     933                 : 
     934                 : const nsTArray< nsCountedRef<FcPattern> >&
     935               0 : gfxFontconfigUtils::GetFontsForFullname(const FcChar8 *aFullname)
     936                 : {
     937               0 :     if (mFontsByFullname.Count() == 0) {
     938               0 :         AddFullnameEntries();
     939                 :     }
     940                 : 
     941               0 :     FontsByFullnameEntry *entry = mFontsByFullname.GetEntry(aFullname);
     942                 : 
     943               0 :     if (!entry)
     944               0 :         return mEmptyPatternArray;
     945                 : 
     946               0 :     return entry->GetFonts();
     947                 : }
     948                 : 
     949                 : static FcLangResult
     950               0 : CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) {
     951               0 :     FcLangResult result = FcLangDifferentLang;
     952               0 :     for (PRUint32 i = 0; ; ++i) {
     953               0 :         FcChar8 a = FcToLower(aLangA[i]);
     954               0 :         FcChar8 b = FcToLower(aLangB[i]);
     955                 : 
     956               0 :         if (a != b) {
     957               0 :             if ((a == '\0' && b == '-') || (a == '-' && b == '\0'))
     958               0 :                 return FcLangDifferentCountry;
     959                 : 
     960               0 :             return result;
     961                 :         }
     962               0 :         if (a == '\0')
     963               0 :             return FcLangEqual;
     964                 : 
     965               0 :         if (a == '-') {
     966               0 :             result = FcLangDifferentCountry;
     967                 :         }
     968                 :     }
     969                 : }
     970                 : 
     971                 : /* static */
     972                 : FcLangResult
     973               0 : gfxFontconfigUtils::GetLangSupport(FcPattern *aFont, const FcChar8 *aLang)
     974                 : {
     975                 :     // When fontconfig builds a pattern for a system font, it will set a
     976                 :     // single LangSet property value for the font.  That value may be removed
     977                 :     // and additional string values may be added through FcConfigSubsitute
     978                 :     // with FcMatchScan.  Values that are neither LangSet nor string are
     979                 :     // considered errors in fontconfig sort and match functions.
     980                 :     //
     981                 :     // If no string nor LangSet value is found, then either the font is a
     982                 :     // system font and the LangSet has been removed through FcConfigSubsitute,
     983                 :     // or the font is a web font and its language support is unknown.
     984                 :     // Returning FcLangDifferentLang for these fonts ensures that this font
     985                 :     // will not be assumed to satisfy the language, and so language will be
     986                 :     // prioritized in sorting fallback fonts.
     987                 :     FcValue value;
     988               0 :     FcLangResult best = FcLangDifferentLang;
     989               0 :     for (int v = 0;
     990               0 :          FcPatternGet(aFont, FC_LANG, v, &value) == FcResultMatch;
     991                 :          ++v) {
     992                 : 
     993                 :         FcLangResult support;
     994               0 :         switch (value.type) {
     995                 :             case FcTypeLangSet:
     996               0 :                 support = FcLangSetHasLang(value.u.l, aLang);
     997               0 :                 break;
     998                 :             case FcTypeString:
     999               0 :                 support = CompareLangString(value.u.s, aLang);
    1000               0 :                 break;
    1001                 :             default:
    1002                 :                 // error. continue to see if there is a useful value.
    1003               0 :                 continue;
    1004                 :         }
    1005                 : 
    1006               0 :         if (support < best) { // lower is better
    1007               0 :             if (support == FcLangEqual)
    1008               0 :                 return support;
    1009               0 :             best = support;
    1010                 :         }        
    1011                 :     }
    1012                 : 
    1013               0 :     return best;
    1014                 : }
    1015                 : 
    1016                 : gfxFontconfigUtils::LangSupportEntry *
    1017               0 : gfxFontconfigUtils::GetLangSupportEntry(const FcChar8 *aLang, bool aWithFonts)
    1018                 : {
    1019                 :     // Currently any unrecognized languages from documents will be converted
    1020                 :     // to x-unicode by nsILanguageAtomService, so there is a limit on the
    1021                 :     // langugages that will be added here.  Reconsider when/if document
    1022                 :     // languages are passed to this routine.
    1023                 : 
    1024               0 :     LangSupportEntry *entry = mLangSupportTable.PutEntry(aLang);
    1025               0 :     if (!entry)
    1026               0 :         return nsnull;
    1027                 : 
    1028               0 :     FcLangResult best = FcLangDifferentLang;
    1029                 : 
    1030               0 :     if (!entry->IsKeyInitialized()) {
    1031               0 :         entry->InitKey(aLang);
    1032                 :     } else {
    1033                 :         // mSupport is already initialized.
    1034               0 :         if (!aWithFonts)
    1035               0 :             return entry;
    1036                 : 
    1037               0 :         best = entry->mSupport;
    1038                 :         // If there is support for this language, an empty font list indicates
    1039                 :         // that the list hasn't been initialized yet.
    1040               0 :         if (best == FcLangDifferentLang || entry->mFonts.Length() > 0)
    1041               0 :             return entry;
    1042                 :     }
    1043                 : 
    1044                 :     // This FcFontSet is owned by fontconfig
    1045               0 :     FcFontSet *fontSet = FcConfigGetFonts(NULL, FcSetSystem);
    1046                 : 
    1047               0 :     nsAutoTArray<FcPattern*,100> fonts;
    1048                 : 
    1049               0 :     for (int f = 0; f < fontSet->nfont; ++f) {
    1050               0 :         FcPattern *font = fontSet->fonts[f];
    1051                 : 
    1052               0 :         FcLangResult support = GetLangSupport(font, aLang);
    1053                 : 
    1054               0 :         if (support < best) { // lower is better
    1055               0 :             best = support;
    1056               0 :             if (aWithFonts) {
    1057               0 :                 fonts.Clear();
    1058               0 :             } else if (best == FcLangEqual) {
    1059               0 :                 break;
    1060                 :             }
    1061                 :         }
    1062                 : 
    1063                 :         // The font list in the LangSupportEntry is expected to be used only
    1064                 :         // when no default fonts support the language.  There would be a large
    1065                 :         // number of fonts in entries for languages using Latin script but
    1066                 :         // these do not need to be created because default fonts already
    1067                 :         // support these languages.
    1068               0 :         if (aWithFonts && support != FcLangDifferentLang && support == best) {
    1069               0 :             fonts.AppendElement(font);
    1070                 :         }
    1071                 :     }
    1072                 : 
    1073               0 :     entry->mSupport = best;
    1074               0 :     if (aWithFonts) {
    1075               0 :         if (fonts.Length() != 0) {
    1076               0 :             entry->mFonts.AppendElements(fonts.Elements(), fonts.Length());
    1077               0 :         } else if (best != FcLangDifferentLang) {
    1078                 :             // Previously there was a font that supported this language at the
    1079                 :             // level of entry->mSupport, but it has now disappeared.  At least
    1080                 :             // entry->mSupport needs to be recalculated, but this is an
    1081                 :             // indication that the set of installed fonts has changed, so
    1082                 :             // update all caches.
    1083               0 :             mLastConfig = NULL; // invalidates caches
    1084               0 :             UpdateFontListInternal(true);
    1085               0 :             return GetLangSupportEntry(aLang, aWithFonts);
    1086                 :         }
    1087                 :     }
    1088                 : 
    1089               0 :     return entry;
    1090                 : }
    1091                 : 
    1092                 : FcLangResult
    1093               0 : gfxFontconfigUtils::GetBestLangSupport(const FcChar8 *aLang)
    1094                 : {
    1095               0 :     UpdateFontListInternal();
    1096                 : 
    1097               0 :     LangSupportEntry *entry = GetLangSupportEntry(aLang, false);
    1098               0 :     if (!entry)
    1099               0 :         return FcLangEqual;
    1100                 : 
    1101               0 :     return entry->mSupport;
    1102                 : }
    1103                 : 
    1104                 : const nsTArray< nsCountedRef<FcPattern> >&
    1105               0 : gfxFontconfigUtils::GetFontsForLang(const FcChar8 *aLang)
    1106                 : {
    1107               0 :     LangSupportEntry *entry = GetLangSupportEntry(aLang, true);
    1108               0 :     if (!entry)
    1109               0 :         return mEmptyPatternArray;
    1110                 : 
    1111               0 :     return entry->mFonts;
    1112                 : }
    1113                 : 
    1114                 : bool
    1115               0 : gfxFontNameList::Exists(nsAString& aName) {
    1116               0 :     for (PRUint32 i = 0; i < Length(); i++) {
    1117               0 :         if (aName.Equals(ElementAt(i)))
    1118               0 :             return true;
    1119                 :     }
    1120               0 :     return false;
    1121                 : }

Generated by: LCOV version 1.7