| 
Commits:
621f7857
 by Pier Angelo Vendrame   at 2024-04-08T20:10:21+00:00 
 Bug 41901: Hardcode normalized FontSubstitutes.
Windows has a system to set font aliases through the registry.
This allows some customization that could be used as a fingerprinting
vector.
Moreover, this mechanism is used by Windows itself, and different SKUs
might have different default FontSubstitutes.
 
4 changed files:
Changes:
gfx/thebes/StandardFonts-win10.inc
 
| ... | ... | @@ -199,3 +199,68 @@ static const char* kLangPackFonts[] = { |  
| 199 | 199 |  //  "Rockwell Nova",  // Pan-European Supplemental Fonts - EXCLUDED
 |  
| 200 | 200 |  //  "Verdana Pro",  // Pan-European Supplemental Fonts - EXCLUDED
 |  
| 201 | 201 |  };
 |  
|  | 202 | +
 |  
|  | 203 | +struct FontSubstitute {
 |  
|  | 204 | +  const char *substituteName;
 |  
|  | 205 | +  const char *actualFontName;
 |  
|  | 206 | +};
 |  
|  | 207 | +
 |  
|  | 208 | +static const FontSubstitute kFontSubstitutes[] = {
 |  
|  | 209 | +  // Common substitutions
 |  
|  | 210 | +  {"Arabic Transparent", "Arial"},
 |  
|  | 211 | +  {"Arabic Transparent Bold", "Arial Bold"},
 |  
|  | 212 | +  {"Arial Baltic", "Arial"},
 |  
|  | 213 | +  {"Arial CE", "Arial"},
 |  
|  | 214 | +  {"Arial CYR", "Arial"},
 |  
|  | 215 | +  {"Arial Greek", "Arial"},
 |  
|  | 216 | +  {"Arial TUR", "Arial"},
 |  
|  | 217 | +  {"Courier New Baltic", "Courier New"},
 |  
|  | 218 | +  {"Courier New CE", "Courier New"},
 |  
|  | 219 | +  {"Courier New CYR", "Courier New"},
 |  
|  | 220 | +  {"Courier New Greek", "Courier New"},
 |  
|  | 221 | +  {"Courier New TUR", "Courier New"},
 |  
|  | 222 | +  {"Helv", "MS Sans Serif"},
 |  
|  | 223 | +  {"Helvetica", "Arial"},
 |  
|  | 224 | +  {"MS Shell Dlg 2", "Tahoma"},
 |  
|  | 225 | +  {"Tahoma Armenian", "Tahoma"},
 |  
|  | 226 | +  {"Times", "Times New Roman"},
 |  
|  | 227 | +  {"Times New Roman Baltic", "Times New Roman"},
 |  
|  | 228 | +  {"Times New Roman CE", "Times New Roman"},
 |  
|  | 229 | +  {"Times New Roman CYR", "Times New Roman"},
 |  
|  | 230 | +  {"Times New Roman Greek", "Times New Roman"},
 |  
|  | 231 | +  {"Times New Roman TUR", "Times New Roman"},
 |  
|  | 232 | +  {"Tms Rmn", "MS Serif"},
 |  
|  | 233 | +  // Common, except Japanese (which uses MS UI Gothic, instead)
 |  
|  | 234 | +  {"MS Shell Dlg", "Microsoft Sans Serif"},
 |  
|  | 235 | +  // Arabic
 |  
|  | 236 | +  {"Arial (Arabic)", "Arial"},
 |  
|  | 237 | +  {"Courier New (Arabic)", "Courier New"},
 |  
|  | 238 | +  {"Times New Roman (Arabic)", "Times New Roman"},
 |  
|  | 239 | +  // Cyrillic + Greek
 |  
|  | 240 | +  {"Courier", "Courier New"},
 |  
|  | 241 | +  // Greek
 |  
|  | 242 | +  {"Fixedsys Greek", "Fixedsys"},
 |  
|  | 243 | +  {"MS Serif Greek", "MS Serif"},
 |  
|  | 244 | +  {"MS Sans Serif Greek", "MS Sans Serif"},
 |  
|  | 245 | +  {"Small Fonts Greek", "Small Fonts"},
 |  
|  | 246 | +  {"System Greek", "System"},
 |  
|  | 247 | +  // Hebrew
 |  
|  | 248 | +  {"Arial (Hebrew)", "Arial"},
 |  
|  | 249 | +  {"Courier New (Hebrew)", "Courier New"},
 |  
|  | 250 | +  {"David Transparent", "David"},
 |  
|  | 251 | +  {"Fixed Miriam Transparent", "Miriam Fixed"},
 |  
|  | 252 | +  {"Miriam Transparent", "Miriam"},
 |  
|  | 253 | +  {"Rod Transparent", "Rod"},
 |  
|  | 254 | +  {"Times New Roman (Hebrew)", "Times New Roman"},
 |  
|  | 255 | +  // Japanese
 |  
|  | 256 | +  {"標準明朝", "MS 明朝"},
 |  
|  | 257 | +  {"標準ゴシック", "MS ゴシック"},
 |  
|  | 258 | +  {"ゴシック", "MS ゴシック"},
 |  
|  | 259 | +  {"ゴシック", "MS ゴシック"},
 |  
|  | 260 | +  {"クーリエ", "Courier"},
 |  
|  | 261 | +  {"タイムズロマン", "Times New Roman"},
 |  
|  | 262 | +  {"ヘルベチカ", "Arial"},
 |  
|  | 263 | +  // Simplified Chinese
 |  
|  | 264 | +  {"FangSong_GB2312", "FangSong"},
 |  
|  | 265 | +  {"KaiTi_GB2312", "KaiTi"},
 |  
|  | 266 | +}; |  gfx/thebes/gfxDWriteFontList.cpp
 
 
| ... | ... | @@ -1923,6 +1923,20 @@ static void RemoveCharsetFromFontSubstitute(nsACString& aName) { |  
| 1923 | 1923 |  #define MAX_VALUE_DATA 512
 |  
| 1924 | 1924 |  
 |  
| 1925 | 1925 |  nsresult gfxDWriteFontList::GetFontSubstitutes() {
 |  
|  | 1926 | +  if (nsContentUtils::ShouldResistFingerprinting(
 |  
|  | 1927 | +          "Ignore any fingerprintable user font customization and normalize "
 |  
|  | 1928 | +          "font substitutes across different Windows SKUs.",
 |  
|  | 1929 | +          RFPTarget::Unknown)) {
 |  
|  | 1930 | +    for (const FontSubstitute& fs : kFontSubstitutes) {
 |  
|  | 1931 | +      nsAutoCString substituteName(fs.substituteName);
 |  
|  | 1932 | +      nsAutoCString actualFontName(fs.actualFontName);
 |  
|  | 1933 | +      BuildKeyNameFromFontName(substituteName);
 |  
|  | 1934 | +      BuildKeyNameFromFontName(actualFontName);
 |  
|  | 1935 | +      AddSubstitute(substituteName, actualFontName);
 |  
|  | 1936 | +    }
 |  
|  | 1937 | +    return NS_OK;
 |  
|  | 1938 | +  }
 |  
|  | 1939 | +
 |  
| 1926 | 1940 |    HKEY hKey;
 |  
| 1927 | 1941 |    DWORD i, rv, lenAlias, lenActual, valueType;
 |  
| 1928 | 1942 |    WCHAR aliasName[MAX_VALUE_NAME];
 |  
| ... | ... | @@ -1957,39 +1971,46 @@ nsresult gfxDWriteFontList::GetFontSubstitutes() { |  
| 1957 | 1971 |      BuildKeyNameFromFontName(substituteName);
 |  
| 1958 | 1972 |      RemoveCharsetFromFontSubstitute(actualFontName);
 |  
| 1959 | 1973 |      BuildKeyNameFromFontName(actualFontName);
 |  
| 1960 |  | -    if (SharedFontList()) {
 |  
| 1961 |  | -      // Skip substitution if the original font is available, unless the option
 |  
| 1962 |  | -      // to apply substitutions unconditionally is enabled.
 |  
| 1963 |  | -      if (!StaticPrefs::gfx_windows_font_substitutes_always_AtStartup()) {
 |  
| 1964 |  | -        // Font substitutions are recorded for the canonical family names; we
 |  
| 1965 |  | -        // don't need FindFamily to consider localized aliases when searching.
 |  
| 1966 |  | -        if (SharedFontList()->FindFamily(substituteName,
 |  
| 1967 |  | -                                         /*aPrimaryNameOnly*/ true)) {
 |  
| 1968 |  | -          continue;
 |  
| 1969 |  | -        }
 |  
| 1970 |  | -      }
 |  
| 1971 |  | -      if (SharedFontList()->FindFamily(actualFontName,
 |  
|  | 1974 | +    AddSubstitute(substituteName, actualFontName);
 |  
|  | 1975 | +  }
 |  
|  | 1976 | +
 |  
|  | 1977 | +  return NS_OK;
 |  
|  | 1978 | +}
 |  
|  | 1979 | +
 |  
|  | 1980 | +void gfxDWriteFontList::AddSubstitute(const nsCString& substituteName,
 |  
|  | 1981 | +                                      const nsCString& actualFontName) {
 |  
|  | 1982 | +  if (SharedFontList()) {
 |  
|  | 1983 | +    // Skip substitution if the original font is available, unless the
 |  
|  | 1984 | +    // option to apply substitutions unconditionally is enabled.
 |  
|  | 1985 | +    if (!StaticPrefs::gfx_windows_font_substitutes_always_AtStartup()) {
 |  
|  | 1986 | +      // Font substitutions are recorded for the canonical family names;
 |  
|  | 1987 | +      // we don't need FindFamily to consider localized aliases when
 |  
|  | 1988 | +      // searching.
 |  
|  | 1989 | +      if (SharedFontList()->FindFamily(substituteName,
 |  
| 1972 | 1990 |                                         /*aPrimaryNameOnly*/ true)) {
 |  
| 1973 |  | -        mSubstitutions.InsertOrUpdate(substituteName,
 |  
| 1974 |  | -                                      MakeUnique<nsCString>(actualFontName));
 |  
| 1975 |  | -      } else if (mSubstitutions.Get(actualFontName)) {
 |  
| 1976 |  | -        mSubstitutions.InsertOrUpdate(
 |  
| 1977 |  | -            substituteName,
 |  
| 1978 |  | -            MakeUnique<nsCString>(*mSubstitutions.Get(actualFontName)));
 |  
| 1979 |  | -      } else {
 |  
| 1980 |  | -        mNonExistingFonts.AppendElement(substituteName);
 |  
|  | 1991 | +        return;
 |  
| 1981 | 1992 |        }
 |  
|  | 1993 | +    }
 |  
|  | 1994 | +    if (SharedFontList()->FindFamily(actualFontName,
 |  
|  | 1995 | +                                     /*aPrimaryNameOnly*/ true)) {
 |  
|  | 1996 | +      mSubstitutions.InsertOrUpdate(substituteName,
 |  
|  | 1997 | +                                    MakeUnique<nsCString>(actualFontName));
 |  
|  | 1998 | +    } else if (mSubstitutions.Get(actualFontName)) {
 |  
|  | 1999 | +      mSubstitutions.InsertOrUpdate(
 |  
|  | 2000 | +          substituteName,
 |  
|  | 2001 | +          MakeUnique<nsCString>(*mSubstitutions.Get(actualFontName)));
 |  
| 1982 | 2002 |      } else {
 |  
| 1983 |  | -      gfxFontFamily* ff;
 |  
| 1984 |  | -      if (!actualFontName.IsEmpty() &&
 |  
| 1985 |  | -          (ff = mFontFamilies.GetWeak(actualFontName))) {
 |  
| 1986 |  | -        mFontSubstitutes.InsertOrUpdate(substituteName, RefPtr{ff});
 |  
| 1987 |  | -      } else {
 |  
| 1988 |  | -        mNonExistingFonts.AppendElement(substituteName);
 |  
| 1989 |  | -      }
 |  
|  | 2003 | +      mNonExistingFonts.AppendElement(substituteName);
 |  
|  | 2004 | +    }
 |  
|  | 2005 | +  } else {
 |  
|  | 2006 | +    gfxFontFamily* ff;
 |  
|  | 2007 | +    if (!actualFontName.IsEmpty() &&
 |  
|  | 2008 | +        (ff = mFontFamilies.GetWeak(actualFontName))) {
 |  
|  | 2009 | +      mFontSubstitutes.InsertOrUpdate(substituteName, RefPtr{ff});
 |  
|  | 2010 | +    } else {
 |  
|  | 2011 | +      mNonExistingFonts.AppendElement(substituteName);
 |  
| 1990 | 2012 |      }
 |  
| 1991 | 2013 |    }
 |  
| 1992 |  | -  return NS_OK;
 |  
| 1993 | 2014 |  }
 |  
| 1994 | 2015 |  
 |  
| 1995 | 2016 |  struct FontSubstitution {
 |  gfx/thebes/gfxDWriteFontList.h
 
 
| ... | ... | @@ -466,6 +466,9 @@ class gfxDWriteFontList final : public gfxPlatformFontList { |  
| 466 | 466 |        const nsTArray<nsCString>* aForceClassicFams = nullptr)
 |  
| 467 | 467 |        MOZ_REQUIRES(mLock);
 |  
| 468 | 468 |  
 |  
|  | 469 | +  void AddSubstitute(const nsCString& substituteName,
 |  
|  | 470 | +                     const nsCString& actualFontName);
 |  
|  | 471 | +
 |  
| 469 | 472 |  #ifdef MOZ_BUNDLED_FONTS
 |  
| 470 | 473 |    already_AddRefed<IDWriteFontCollection> CreateBundledFontsCollection(
 |  
| 471 | 474 |        IDWriteFactory* aFactory);
 |  gfx/thebes/gfxGDIFontList.cpp
 
 
| ... | ... | @@ -31,6 +31,10 @@ |  
| 31 | 31 |  #include "mozilla/StaticPrefs_gfx.h"
 |  
| 32 | 32 |  #include "mozilla/Telemetry.h"
 |  
| 33 | 33 |  
 |  
|  | 34 | +#include "nsContentUtils.h"
 |  
|  | 35 | +
 |  
|  | 36 | +#include "StandardFonts-win10.inc"
 |  
|  | 37 | +
 |  
| 34 | 38 |  #include <usp10.h>
 |  
| 35 | 39 |  
 |  
| 36 | 40 |  using namespace mozilla;
 |  
| ... | ... | @@ -50,6 +54,10 @@ static __inline void BuildKeyNameFromFontName(nsAString& aName) { |  
| 50 | 54 |    if (aName.Length() >= LF_FACESIZE) aName.Truncate(LF_FACESIZE - 1);
 |  
| 51 | 55 |    ToLowerCase(aName);
 |  
| 52 | 56 |  }
 |  
|  | 57 | +static __inline void BuildKeyNameFromFontName(nsACString& aName) {
 |  
|  | 58 | +  if (aName.Length() >= LF_FACESIZE) aName.Truncate(LF_FACESIZE - 1);
 |  
|  | 59 | +  ToLowerCase(aName);
 |  
|  | 60 | +}
 |  
| 53 | 61 |  
 |  
| 54 | 62 |  // Implementation of gfxPlatformFontList for Win32 GDI,
 |  
| 55 | 63 |  // using GDI font enumeration APIs to get the list of fonts
 |  
| ... | ... | @@ -529,6 +537,26 @@ static void RemoveCharsetFromFontSubstitute(nsAString& aName) { |  
| 529 | 537 |  #define MAX_VALUE_DATA 512
 |  
| 530 | 538 |  
 |  
| 531 | 539 |  nsresult gfxGDIFontList::GetFontSubstitutes() {
 |  
|  | 540 | +  if (nsContentUtils::ShouldResistFingerprinting(
 |  
|  | 541 | +          "Ignore any fingerprintable user font customization and normalize "
 |  
|  | 542 | +          "font substitutes across different Windows SKUs.",
 |  
|  | 543 | +          RFPTarget::Unknown)) {
 |  
|  | 544 | +    for (const FontSubstitute& fs : kFontSubstitutes) {
 |  
|  | 545 | +      nsAutoCString substituteName(fs.substituteName);
 |  
|  | 546 | +      nsAutoCString actualFontName(fs.actualFontName);
 |  
|  | 547 | +      BuildKeyNameFromFontName(substituteName);
 |  
|  | 548 | +      BuildKeyNameFromFontName(actualFontName);
 |  
|  | 549 | +      gfxFontFamily* ff;
 |  
|  | 550 | +      if (!actualFontName.IsEmpty() &&
 |  
|  | 551 | +          (ff = mFontFamilies.GetWeak(actualFontName))) {
 |  
|  | 552 | +        mFontSubstitutes.InsertOrUpdate(substituteName, RefPtr{ff});
 |  
|  | 553 | +      } else {
 |  
|  | 554 | +        mNonExistingFonts.AppendElement(substituteName);
 |  
|  | 555 | +      }
 |  
|  | 556 | +    }
 |  
|  | 557 | +    return NS_OK;
 |  
|  | 558 | +  }
 |  
|  | 559 | +
 |  
| 532 | 560 |    HKEY hKey;
 |  
| 533 | 561 |    DWORD i, rv, lenAlias, lenActual, valueType;
 |  
| 534 | 562 |    WCHAR aliasName[MAX_VALUE_NAME];
 |  
 |