Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  gfxGDIFontList.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "mozilla/DebugOnly.h"
#include <algorithm>

#include "mozilla/Logging.h"
#include "mozilla/TextUtils.h"
#include "mozilla/Sprintf.h"

#include "gfxGDIFontList.h"
#include "gfxWindowsPlatform.h"
#include "gfxUserFontSet.h"
#include "gfxFontUtils.h"
#include "gfxGDIFont.h"

#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsUnicharUtils.h"

#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsPresContext.h"
#include "gfxFontConstants.h"

#include "mozilla/MemoryReporting.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/glean/GfxMetrics.h"

#include <usp10.h>

using namespace mozilla;
using namespace mozilla::gfx;

#define ROUND(x) floor((x) + 0.5)

#define LOG_FONTLIST(args) \
  MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
#define LOG_FONTLIST_ENABLED() \
  MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)

#define LOG_CMAPDATA_ENABLED() \
  MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), LogLevel::Debug)

static __inline void BuildKeyNameFromFontName(nsAString& aName) {
  if (aName.Length() >= LF_FACESIZE) aName.Truncate(LF_FACESIZE - 1);
  ToLowerCase(aName);
}

// Implementation of gfxPlatformFontList for Win32 GDI,
// using GDI font enumeration APIs to get the list of fonts

class WinUserFontData : public gfxUserFontData {
 public:
  explicit WinUserFontData(HANDLE aFontRef) : mFontRef(aFontRef) {}

  virtual ~WinUserFontData() {
    DebugOnly<BOOL> success;
    success = RemoveFontMemResourceEx(mFontRef);
#if DEBUG
    if (!success) {
      char buf[256];
      SprintfLiteral(
          buf,
          "error deleting font handle (%p) - RemoveFontMemResourceEx failed",
          mFontRef);
      NS_ASSERTION(success, buf);
    }
#endif
  }

  HANDLE mFontRef;
};

BYTE FontTypeToOutPrecision(uint8_t fontType) {
  BYTE ret;
  switch (fontType) {
    case GFX_FONT_TYPE_TT_OPENTYPE:
    case GFX_FONT_TYPE_TRUETYPE:
      ret = OUT_TT_ONLY_PRECIS;
      break;
    case GFX_FONT_TYPE_PS_OPENTYPE:
      ret = OUT_PS_ONLY_PRECIS;
      break;
    case GFX_FONT_TYPE_TYPE1:
      ret = OUT_OUTLINE_PRECIS;
      break;
    case GFX_FONT_TYPE_RASTER:
      ret = OUT_RASTER_PRECIS;
      break;
    case GFX_FONT_TYPE_DEVICE:
      ret = OUT_DEVICE_PRECIS;
      break;
    default:
      ret = OUT_DEFAULT_PRECIS;
  }
  return ret;
}

/***************************************************************
 *
 * GDIFontEntry
 *
 */


GDIFontEntry::GDIFontEntry(const nsACString& aFaceName,
                           gfxWindowsFontType aFontType, SlantStyleRange aStyle,
                           WeightRange aWeight, StretchRange aStretch,
                           gfxUserFontData* aUserFontData)
    : gfxFontEntry(aFaceName), mFontType(aFontType), mForceGDI(false) {
  mUserFontData.reset(aUserFontData);
  mStyleRange = aStyle;
  mWeightRange = aWeight;
  mStretchRange = aStretch;
  if (IsType1()) {
    mForceGDI = true;
  }
  mIsDataUserFont = aUserFontData != nullptr;

  InitLogFont(aFaceName, aFontType);
}

gfxFontEntry* GDIFontEntry::Clone() const {
  MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
  return new GDIFontEntry(Name(), mFontType, SlantStyle(), Weight(), Stretch(),
                          nullptr);
}

nsresult GDIFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
  AUTO_PROFILER_LABEL("GDIFontEntry::ReadCMAP", OTHER);

  // attempt this once, if errors occur leave a blank cmap
  if (mCharacterMap) {
    return NS_OK;
  }

  // skip non-SFNT fonts completely
  if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE &&
      mFontType != GFX_FONT_TYPE_TT_OPENTYPE &&
      mFontType != GFX_FONT_TYPE_TRUETYPE) {
    RefPtr<gfxCharacterMap> cmap = new gfxCharacterMap();
    cmap->mBuildOnTheFly = true;
    if (mCharacterMap.compareExchange(nullptr, cmap.get())) {
      Unused << cmap.forget();
    }
    return NS_ERROR_FAILURE;
  }

  RefPtr<gfxCharacterMap> charmap;
  nsresult rv;

  uint32_t uvsOffset = 0;
  if (aFontInfoData &&
      (charmap = GetCMAPFromFontInfo(aFontInfoData, uvsOffset))) {
    rv = NS_OK;
  } else {
    uint32_t kCMAP = TRUETYPE_TAG('c''m''a''p');
    charmap = new gfxCharacterMap();
    AutoTArray<uint8_t, 16384> cmap;
    rv = CopyFontTable(kCMAP, cmap);

    if (NS_SUCCEEDED(rv)) {
      rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), *charmap,
                                  uvsOffset);
    }
  }

  if (NS_SUCCEEDED(rv)) {
    gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
    charmap = pfl->FindCharMap(charmap);
    mHasCmapTable = true;
  } else {
    // if error occurred, initialize to null cmap
    charmap = new gfxCharacterMap();
    // For fonts where we failed to read the character map,
    // we can take a slow path to look up glyphs character by character
    charmap->mBuildOnTheFly = true;
  }
  if (mCharacterMap.compareExchange(nullptr, charmap.get())) {
    charmap.get()->AddRef();
  }

  LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zd hash: %8.8x%s\n",
                mName.get(), charmap->SizeOfIncludingThis(moz_malloc_size_of),
                charmap->mHash, mCharacterMap == charmap ? " new" : ""));
  if (LOG_CMAPDATA_ENABLED()) {
    char prefix[256];
    SprintfLiteral(prefix, "(cmapdata) name: %.220s", mName.get());
    charmap->Dump(prefix, eGfxLog_cmapdata);
  }

  return rv;
}

gfxFont* GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) {
  return new gfxGDIFont(this, aFontStyle);
}

nsresult GDIFontEntry::CopyFontTable(uint32_t aTableTag,
                                     nsTArray<uint8_t>& aBuffer) {
  if (!IsTrueType()) {
    return NS_ERROR_FAILURE;
  }

  AutoDC dc;
  AutoSelectFont font(dc.GetDC(), &mLogFont);
  if (font.IsValid()) {
    uint32_t tableSize = ::GetFontData(
        dc.GetDC(), NativeEndian::swapToBigEndian(aTableTag), 0, nullptr, 0);
    if (tableSize != GDI_ERROR) {
      if (aBuffer.SetLength(tableSize, fallible)) {
        ::GetFontData(dc.GetDC(), NativeEndian::swapToBigEndian(aTableTag), 0,
                      aBuffer.Elements(), tableSize);
        return NS_OK;
      }
      return NS_ERROR_OUT_OF_MEMORY;
    }
  }
  return NS_ERROR_FAILURE;
}

already_AddRefed<UnscaledFontGDI> GDIFontEntry::LookupUnscaledFont(
    HFONT aFont) {
  RefPtr<UnscaledFontGDI> unscaledFont(mUnscaledFont);
  if (!unscaledFont) {
    LOGFONT lf;
    GetObject(aFont, sizeof(LOGFONT), &lf);
    unscaledFont = new UnscaledFontGDI(lf);
    mUnscaledFont = unscaledFont;
  }

  return unscaledFont.forget();
}

void GDIFontEntry::FillLogFont(LOGFONTW* aLogFont, LONG aWeight,
                               gfxFloat aSize) {
  memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));

  aLogFont->lfHeight = (LONG)-ROUND(aSize);

  if (aLogFont->lfHeight == 0) {
    aLogFont->lfHeight = -1;
  }

  // If a non-zero weight is passed in, use this to override the original
  // weight in the entry's logfont. This is used to control synthetic bolding
  // for installed families with no bold face, and for downloaded fonts
  // (but NOT for local user fonts, because it could cause a different,
  // glyph-incompatible face to be used)
  if (aWeight != 0) {
    aLogFont->lfWeight = aWeight;
  }

  // for non-local() user fonts, we never want to apply italics here;
  // if the face is described as italic, we should use it as-is,
  // and if it's not, but then the element is styled italic, we'll use
  // a cairo transform to create fake italic (oblique)
  if (mIsDataUserFont) {
    aLogFont->lfItalic = 0;
  }
}

#define MISSING_GLYPH \
  0x1F  // glyph index returned for missing characters
        // on WinXP with .fon fonts, but not Type1 (.pfb)

bool GDIFontEntry::TestCharacterMap(uint32_t aCh) {
  if (!mCharacterMap) {
    ReadCMAP();
    NS_ASSERTION(mCharacterMap, "failed to initialize a character map");
  }

  if (GetCharacterMap()->mBuildOnTheFly) {
    if (aCh > 0xFFFF) return false;

    // previous code was using the group style
    gfxFontStyle fakeStyle;
    if (!IsUpright()) {
      fakeStyle.style = FontSlantStyle::ITALIC;
    }
    fakeStyle.weight = Weight().Min();

    RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, nullptr);
    if (!tempFont || !tempFont->Valid()) return false;
    gfxGDIFont* font = static_cast<gfxGDIFont*>(tempFont.get());

    HDC dc = GetDC((HWND) nullptr);
    SetGraphicsMode(dc, GM_ADVANCED);
    HFONT hfont = font->GetHFONT();
    HFONT oldFont = (HFONT)SelectObject(dc, hfont);

    wchar_t str[1] = {(wchar_t)aCh};
    WORD glyph[1];

    bool hasGlyph = false;

    // Bug 573038 - in some cases GetGlyphIndicesW returns 0xFFFF for a
    // missing glyph or 0x1F in other cases to indicate the "invalid"
    // glyph.  Map both cases to "not found"
    if (IsType1() || mForceGDI) {
      // Type1 fonts and uniscribe APIs don't get along.
      // ScriptGetCMap will return E_HANDLE
      DWORD ret =
          GetGlyphIndicesW(dc, str, 1, glyph, GGI_MARK_NONEXISTING_GLYPHS);
      if (ret != GDI_ERROR && glyph[0] != 0xFFFF &&
          (IsType1() || glyph[0] != MISSING_GLYPH)) {
        hasGlyph = true;
      }
    } else {
      // ScriptGetCMap works better than GetGlyphIndicesW
      // for things like bitmap/vector fonts
      SCRIPT_CACHE sc = nullptr;
      HRESULT rv = ScriptGetCMap(dc, &sc, str, 1, 0, glyph);
      if (rv == S_OK) hasGlyph = true;
    }

    SelectObject(dc, oldFont);
    ReleaseDC(nullptr, dc);

    if (hasGlyph) {
      GetCharacterMap()->set(aCh);
      return true;
    }
  } else {
    // font had a cmap so simply check that
    return GetCharacterMap()->test(aCh);
  }

  return false;
}

void GDIFontEntry::InitLogFont(const nsACString& aName,
                               gfxWindowsFontType aFontType) {
#define CLIP_TURNOFF_FONTASSOCIATION 0x40

  mLogFont.lfHeight = -1;

  // Fill in logFont structure
  mLogFont.lfWidth = 0;
  mLogFont.lfEscapement = 0;
  mLogFont.lfOrientation = 0;
  mLogFont.lfUnderline = FALSE;
  mLogFont.lfStrikeOut = FALSE;
  mLogFont.lfCharSet = DEFAULT_CHARSET;
  mLogFont.lfOutPrecision = FontTypeToOutPrecision(aFontType);
  mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
  mLogFont.lfQuality = DEFAULT_QUALITY;
  mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  // always force lfItalic if we want it.  Font selection code will
  // do its best to give us an italic font entry, but if no face exists
  // it may give us a regular one based on weight.  Windows should
  // do fake italic for us in that case.
  mLogFont.lfItalic = !IsUpright();
  mLogFont.lfWeight = Weight().Min().ToIntRounded();

  NS_ConvertUTF8toUTF16 name(aName);
  int len = std::min<int>(name.Length(), LF_FACESIZE - 1);
  memcpy(&mLogFont.lfFaceName, name.BeginReading(), len * sizeof(char16_t));
  mLogFont.lfFaceName[len] = '\0';
}

GDIFontEntry* GDIFontEntry::CreateFontEntry(const nsACString& aName,
                                            gfxWindowsFontType aFontType,
                                            SlantStyleRange aStyle,
                                            WeightRange aWeight,
                                            StretchRange aStretch,
                                            gfxUserFontData* aUserFontData) {
  // jtdfix - need to set charset, pitch/family

  return new GDIFontEntry(aName, aFontType, aStyle, aWeight, aStretch,
                          aUserFontData);
}

void GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                          FontListSizes* aSizes) const {
  aSizes->mFontListSize += aMallocSizeOf(this);
  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
}

/***************************************************************
 *
 * GDIFontFamily
 *
 */


static bool ShouldIgnoreItalicStyle(const nsACString& aName) {
  // Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
  // non-italic style glyphs as Japanese characters.  However, using it
  // causes serious problem if web pages wants some elements to be
  // different style from others only with font-style.  For example,
  // <em> and <i> should be rendered as italic in the default style.
  return aName.EqualsLiteral("Meiryo") ||
         aName.EqualsLiteral(
             "\xe3\x83\xa1\xe3\x82\xa4\xe3\x83\xaa\xe3\x82\xaa");
}

int CALLBACK GDIFontFamily::FamilyAddStylesProc(
    const ENUMLOGFONTEXW* lpelfe, const NEWTEXTMETRICEXW* nmetrics,
    DWORD fontType, LPARAM data) MOZ_NO_THREAD_SAFETY_ANALYSIS {
  const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
  LOGFONTW logFont = lpelfe->elfLogFont;
  GDIFontFamily* ff = reinterpret_cast<GDIFontFamily*>(data);
  MOZ_ASSERT(ff->mLock.LockedForWritingByCurrentThread());

  if (logFont.lfItalic && ShouldIgnoreItalicStyle(ff->mName)) {
    return 1;
  }

  // Some fonts claim to support things > 900, but we don't so clamp the sizes
  logFont.lfWeight = std::clamp(logFont.lfWeight, LONG(100), LONG(900));

  gfxWindowsFontType feType =
      GDIFontEntry::DetermineFontType(metrics, fontType);

  GDIFontEntry* fe = nullptr;
  for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
    fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
    if (feType > fe->mFontType) {
      // if the new type is better than the old one, remove the old entries
      ff->mAvailableFonts.RemoveElementAt(i);
      --i;
    } else if (feType < fe->mFontType) {
      // otherwise if the new type is worse, skip it
      return 1;
    }
  }

  for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
    fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
    // check if we already know about this face
    if (fe->Weight().Min() == FontWeight::FromInt(int32_t(logFont.lfWeight)) &&
        fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
      // update the charset bit here since this could be different
      // XXX Can we still do this now that we store mCharset
      // on the font family rather than the font entry?
      ff->mCharset.set(metrics.tmCharSet);
      return 1;
    }
  }

  // We can't set the hasItalicFace flag correctly here,
  // because we might not have seen the family's italic face(s) yet.
  // So we'll set that flag for all members after loading all the faces.
  auto italicStyle = (logFont.lfItalic == 0xFF ? FontSlantStyle::ITALIC
                                               : FontSlantStyle::NORMAL);
  fe = GDIFontEntry::CreateFontEntry(
      NS_ConvertUTF16toUTF8(lpelfe->elfFullName), feType,
      SlantStyleRange(italicStyle),
      WeightRange(FontWeight::FromInt(int32_t(logFont.lfWeight))),
      StretchRange(FontStretch::NORMAL), nullptr);
  if (!fe) {
    return 1;
  }

  ff->AddFontEntryLocked(fe);

  if (LOG_FONTLIST_ENABLED()) {
    LOG_FONTLIST(
        ("(fontlist) added (%s) to family (%s)"
         " with style: %s weight: %ld stretch: normal",
         fe->Name().get(), ff->Name().get(),
         (logFont.lfItalic == 0xff) ? "italic" : "normal", logFont.lfWeight));
  }
  return 1;
}

void GDIFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
  if (mHasStyles) {
    return;
  }
  mHasStyles = true;

  HDC hdc = GetDC(nullptr);
  SetGraphicsMode(hdc, GM_ADVANCED);

  LOGFONTW logFont;
  memset(&logFont, 0, sizeof(LOGFONTW));
  logFont.lfCharSet = DEFAULT_CHARSET;
  logFont.lfPitchAndFamily = 0;
  NS_ConvertUTF8toUTF16 name(mName);
  uint32_t l = std::min<uint32_t>(name.Length(), LF_FACESIZE - 1);
  memcpy(logFont.lfFaceName, name.get(), l * sizeof(char16_t));

  EnumFontFamiliesExW(hdc, &logFont,
                      (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc,
                      (LPARAM)this, 0);
  if (LOG_FONTLIST_ENABLED() && mAvailableFonts.Length() == 0) {
    LOG_FONTLIST(
        ("(fontlist) no styles available in family \"%s\"", mName.get()));
  }

  ReleaseDC(nullptr, hdc);

  if (mIsBadUnderlineFamily) {
    SetBadUnderlineFonts();
  }

  CheckForSimpleFamily();
}

/***************************************************************
 *
 * gfxGDIFontList
 *
 */


gfxGDIFontList::gfxGDIFontList() : mFontSubstitutes(32) {
#ifdef MOZ_BUNDLED_FONTS
  if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
    auto timer = glean::fontlist::bundledfonts_activate.Measure();
    ActivateBundledFonts();
  }
#endif
}

static void RemoveCharsetFromFontSubstitute(nsAString& aName) {
  int32_t comma = aName.FindChar(char16_t(','));
  if (comma >= 0) aName.Truncate(comma);
}

#define MAX_VALUE_NAME 512
#define MAX_VALUE_DATA 512

nsresult gfxGDIFontList::GetFontSubstitutes() {
  HKEY hKey;
  DWORD i, rv, lenAlias, lenActual, valueType;
  WCHAR aliasName[MAX_VALUE_NAME];
  WCHAR actualName[MAX_VALUE_DATA];

  if (RegOpenKeyExW(
          HKEY_LOCAL_MACHINE,
          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
          0, KEY_READ, &hKey) != ERROR_SUCCESS) {
    return NS_ERROR_FAILURE;
  }

  for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
    aliasName[0] = 0;
    lenAlias = std::size(aliasName);
    actualName[0] = 0;
    lenActual = sizeof(actualName);
    rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
                       (LPBYTE)actualName, &lenActual);

    if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
      continue;
    }

    if (aliasName[0] == WCHAR('@')) {
      continue;
    }

    nsAutoString substituteName((char16_t*)aliasName);
    nsAutoString actualFontName((char16_t*)actualName);
    RemoveCharsetFromFontSubstitute(substituteName);
    BuildKeyNameFromFontName(substituteName);
    RemoveCharsetFromFontSubstitute(actualFontName);
    BuildKeyNameFromFontName(actualFontName);
    gfxFontFamily* ff;
    NS_ConvertUTF16toUTF8 substitute(substituteName);
    NS_ConvertUTF16toUTF8 actual(actualFontName);
    if (!actual.IsEmpty() && (ff = mFontFamilies.GetWeak(actual))) {
      mFontSubstitutes.InsertOrUpdate(substitute, RefPtr{ff});
    } else {
      mNonExistingFonts.AppendElement(substitute);
    }
  }

  // "Courier" on a default Windows install is an ugly bitmap font.
  // If there is no substitution for Courier in the registry
  // substitute "Courier" with "Courier New".
  nsAutoString substituteName;
  substituteName.AssignLiteral("Courier");
  BuildKeyNameFromFontName(substituteName);
  NS_ConvertUTF16toUTF8 substitute(substituteName);
  if (!mFontSubstitutes.GetWeak(substitute)) {
    gfxFontFamily* ff;
    nsAutoString actualFontName;
    actualFontName.AssignLiteral("Courier New");
    BuildKeyNameFromFontName(actualFontName);
    NS_ConvertUTF16toUTF8 actual(actualFontName);
    ff = mFontFamilies.GetWeak(actual);
    if (ff) {
      mFontSubstitutes.InsertOrUpdate(substitute, RefPtr{ff});
    }
  }
  return NS_OK;
}

nsresult gfxGDIFontList::InitFontListForPlatform() {
  auto timer = glean::fontlist::gdi_init_total.Measure();

  mFontSubstitutes.Clear();
  mNonExistingFonts.Clear();

  // iterate over available families
  LOGFONTW logfont;
  memset(&logfont, 0, sizeof(logfont));
  logfont.lfCharSet = DEFAULT_CHARSET;

  AutoDC hdc;
  (void)EnumFontFamiliesExW(hdc.GetDC(), &logfont,
                            (FONTENUMPROCW)&EnumFontFamExProc, 0, 0);

  GetFontSubstitutes();

  GetPrefsAndStartLoader();

  return NS_OK;
}

int CALLBACK gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW* lpelfe,
                                               NEWTEXTMETRICEXW* lpntme,
                                               DWORD fontType, LPARAM lParam) {
  const NEWTEXTMETRICW& metrics = lpntme->ntmTm;
  const LOGFONTW& lf = lpelfe->elfLogFont;

  if (lf.lfFaceName[0] == '@') {
    return 1;
  }

  nsAutoString name(lf.lfFaceName);
  BuildKeyNameFromFontName(name);

  NS_ConvertUTF16toUTF8 key(name);

  gfxGDIFontList* fontList = PlatformFontList();
  fontList->mLock.AssertCurrentThreadIn();

  if (!fontList->mFontFamilies.Contains(key)) {
    NS_ConvertUTF16toUTF8 faceName(lf.lfFaceName);
    FontVisibility visibility = FontVisibility::Unknown;  // TODO
    RefPtr<GDIFontFamily> family = new GDIFontFamily(faceName, visibility);
    fontList->mFontFamilies.InsertOrUpdate(key, RefPtr{family});

    // if locale is such that CJK font names are the default coming from
    // GDI, then if a family name is non-ASCII immediately read in other
    // family names.  This assures that MS Gothic, MS Mincho are all found
    // before lookups begin.
    if (!IsAscii(faceName)) {
      family->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());
    }

    if (fontList->mBadUnderlineFamilyNames.ContainsSorted(key)) {
      family->SetBadUnderlineFamily();
    }

    family->mWindowsFamily = lf.lfPitchAndFamily & 0xF0;
    family->mWindowsPitch = lf.lfPitchAndFamily & 0x0F;

    // mark the charset bit
    family->mCharset.set(metrics.tmCharSet);
  }

  return 1;
}

gfxFontEntry* gfxGDIFontList::LookupLocalFont(nsPresContext* aPresContext,
                                              const nsACString& aFontName,
                                              WeightRange aWeightForEntry,
                                              StretchRange aStretchForEntry,
                                              SlantStyleRange aStyleForEntry) {
  AutoLock lock(mLock);

  gfxFontEntry* lookup = LookupInFaceNameLists(aFontName);
  if (!lookup) {
    return nullptr;
  }

  bool isCFF = false;  // jtdfix -- need to determine this

  // use the face name from the lookup font entry, which will be the localized
  // face name which GDI mapping tables use (e.g. with the system locale set to
  // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
  // 'Arial Vet' which can be used as a key in GDI font lookups).
  GDIFontEntry* fe = GDIFontEntry::CreateFontEntry(
      lookup->Name(),
      gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE
                               : GFX_FONT_TYPE_TRUETYPE) /*type*/,
      lookup->SlantStyle(), lookup->Weight(), aStretchForEntry, nullptr);

  if (!fe) return nullptr;

  fe->mIsLocalUserFont = true;

  // make the new font entry match the userfont entry style characteristics
  fe->mWeightRange = aWeightForEntry;
  fe->mStyleRange = aStyleForEntry;
  fe->mStretchRange = aStretchForEntry;

  return fe;
}

// If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
// we modify the subtable header to mark it as Unicode instead, because
// otherwise GDI will refuse to load the font.
// NOTE that this function does not bounds-check every access to the font data.
// This is OK because we only use it on data that has already been validated
// by OTS, and therefore we will not hit out-of-bounds accesses here.
static bool FixupSymbolEncodedFont(uint8_t* aFontData, uint32_t aLength) {
  struct CmapHeader {
    AutoSwap_PRUint16 version;
    AutoSwap_PRUint16 numTables;
  };
  struct CmapEncodingRecord {
    AutoSwap_PRUint16 platformID;
    AutoSwap_PRUint16 encodingID;
    AutoSwap_PRUint32 offset;
  };
  const uint32_t kCMAP = TRUETYPE_TAG('c''m''a''p');
  const TableDirEntry* dir = gfxFontUtils::FindTableDirEntry(aFontData, kCMAP);
  if (dir && uint32_t(dir->length) >= sizeof(CmapHeader)) {
    CmapHeader* cmap =
        reinterpret_cast<CmapHeader*>(aFontData + uint32_t(dir->offset));
    CmapEncodingRecord* encRec =
        reinterpret_cast<CmapEncodingRecord*>(cmap + 1);
    int32_t symbolSubtable = -1;
    for (uint32_t i = 0; i < (uint16_t)cmap->numTables; ++i) {
      if (uint16_t(encRec[i].platformID) !=
          gfxFontUtils::PLATFORM_ID_MICROSOFT) {
        continue;  // only interested in MS platform
      }
      if (uint16_t(encRec[i].encodingID) ==
          gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP) {
        // We've got a Microsoft/Unicode table, so don't interfere.
        symbolSubtable = -1;
        break;
      }
      if (uint16_t(encRec[i].encodingID) ==
          gfxFontUtils::ENCODING_ID_MICROSOFT_SYMBOL) {
        // Found a symbol subtable; remember it for possible fixup,
        // but if we subsequently find a Microsoft/Unicode subtable,
        // we'll cancel this.
        symbolSubtable = i;
      }
    }
    if (symbolSubtable != -1) {
      // We found a windows/symbol cmap table, and no windows/unicode one;
      // change the encoding ID so that AddFontMemResourceEx will accept it
      encRec[symbolSubtable].encodingID =
          gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP;
      return true;
    }
  }
  return false;
}

gfxFontEntry* gfxGDIFontList::MakePlatformFont(const nsACString& aFontName,
                                               WeightRange aWeightForEntry,
                                               StretchRange aStretchForEntry,
                                               SlantStyleRange aStyleForEntry,
                                               const uint8_t* aFontData,
                                               uint32_t aLength) {
  // MakePlatformFont is responsible for deleting the font data with free
  // so we set up a stack object to ensure it is freed even if we take an
  // early exit
  struct FontDataDeleter {
    explicit FontDataDeleter(const uint8_t* aFontData) : mFontData(aFontData) {}
    ~FontDataDeleter() { free((void*)mFontData); }
    const uint8_t* mFontData;
  };
  FontDataDeleter autoDelete(aFontData);

  bool isCFF = gfxFontUtils::IsCffFont(aFontData);

  nsresult rv;
  HANDLE fontRef = nullptr;

  nsAutoString uniqueName;
  rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
  if (NS_FAILED(rv)) return nullptr;

  FallibleTArray<uint8_t> newFontData;

  rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);

  if (NS_FAILED(rv)) return nullptr;

  DWORD numFonts = 0;

  uint8_t* fontData = reinterpret_cast<uint8_t*>(newFontData.Elements());
  uint32_t fontLength = newFontData.Length();
  NS_ASSERTION(fontData, "null font data after renaming");

  // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
  // "A font that is added by AddFontMemResourceEx is always private
  //  to the process that made the call and is not enumerable."
  fontRef =
      AddFontMemResourceEx(fontData, fontLength, 0 /* reserved */, &numFonts);
  if (!fontRef) {
    if (FixupSymbolEncodedFont(fontData, fontLength)) {
      fontRef = AddFontMemResourceEx(fontData, fontLength, 0, &numFonts);
    }
  }
  if (!fontRef) {
    return nullptr;
  }

  // only load fonts with a single face contained in the data
  // AddFontMemResourceEx generates an additional face name for
  // vertical text if the font supports vertical writing but since
  // the font is referenced via the name this can be ignored
  if (fontRef && numFonts > 2) {
    RemoveFontMemResourceEx(fontRef);
    return nullptr;
  }

  // make a new font entry using the unique name
  WinUserFontData* winUserFontData = new WinUserFontData(fontRef);
  GDIFontEntry* fe = GDIFontEntry::CreateFontEntry(
      NS_ConvertUTF16toUTF8(uniqueName),
      gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE
                               : GFX_FONT_TYPE_TRUETYPE) /*type*/,
      aStyleForEntry, aWeightForEntry, aStretchForEntry, winUserFontData);

  if (fe) {
    fe->mIsDataUserFont = true;
  }

  return fe;
}

bool gfxGDIFontList::FindAndAddFamiliesLocked(
    nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
    const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
    FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
    gfxFloat aDevToCssSize) {
  NS_ConvertUTF8toUTF16 key16(aFamily);
  BuildKeyNameFromFontName(key16);
  NS_ConvertUTF16toUTF8 keyName(key16);

  gfxFontFamily* ff = mFontSubstitutes.GetWeak(keyName);
  FontVisibility level =
      aPresContext ? aPresContext->GetFontVisibility() : FontVisibility::User;
  if (ff && IsVisibleToCSS(*ff, level)) {
    aOutput->AppendElement(FamilyAndGeneric(ff, aGeneric));
    return true;
  }

  if (mNonExistingFonts.Contains(keyName)) {
    return false;
  }

  return gfxPlatformFontList::FindAndAddFamiliesLocked(
      aPresContext, aGeneric, aFamily, aOutput, aFlags, aStyle, aLanguage,
      aDevToCssSize);
}

nsTArray<std::pair<const char**, uint32_t>>
gfxGDIFontList::GetFilteredPlatformFontLists() {
  nsTArray<std::pair<const char**, uint32_t>> fontLists;

  return fontLists;
}

FontFamily gfxGDIFontList::GetDefaultFontForPlatform(
    nsPresContext* aPresContext, const gfxFontStyle* aStyle,
    nsAtom* aLanguage) {
  FontFamily ff;

  // this really shouldn't fail to find a font....
  NONCLIENTMETRICSW ncm;
  ncm.cbSize = sizeof(ncm);
  BOOL status =
      ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  if (status) {
    ff = FindFamily(aPresContext,
                    NS_ConvertUTF16toUTF8(ncm.lfMessageFont.lfFaceName));
    if (!ff.IsNull()) {
      return ff;
    }
  }

  // ...but just in case, try another (long-deprecated) approach as well
  HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
  LOGFONTW logFont;
  if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
    ff = FindFamily(aPresContext, NS_ConvertUTF16toUTF8(logFont.lfFaceName));
  }

  return ff;
}

void gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                            FontListSizes* aSizes) const {
  gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);

  AutoLock lock(mLock);

  aSizes->mFontListSize +=
      SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
  aSizes->mFontListSize +=
      mNonExistingFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
  for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
    aSizes->mFontListSize +=
        mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  }
}

void gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                            FontListSizes* aSizes) const {
  aSizes->mFontListSize += aMallocSizeOf(this);
  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
}

// used to load system-wide font info on off-main thread
class GDIFontInfo : public FontInfoData {
 public:
  GDIFontInfo(bool aLoadOtherNames, bool aLoadFaceNames, bool aLoadCmaps)
      : FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps) {}

  virtual ~GDIFontInfo() = default;

  virtual void Load() {
    mHdc = GetDC(nullptr);
    SetGraphicsMode(mHdc, GM_ADVANCED);
    FontInfoData::Load();
    ReleaseDC(nullptr, mHdc);
  }

  // loads font data for all members of a given family
  virtual void LoadFontFamilyData(const nsACString& aFamilyName);

  // callback for GDI EnumFontFamiliesExW call
  static int CALLBACK EnumerateFontsForFamily(const ENUMLOGFONTEXW* lpelfe,
                                              const NEWTEXTMETRICEXW* nmetrics,
                                              DWORD fontType, LPARAM data);

  HDC mHdc;
};

struct EnumerateFontsForFamilyData {
  EnumerateFontsForFamilyData(const nsACString& aFamilyName,
                              GDIFontInfo& aFontInfo)
      : mFamilyName(aFamilyName), mFontInfo(aFontInfo) {}

  nsCString mFamilyName;
  nsTArray<nsCString> mOtherFamilyNames;
  GDIFontInfo& mFontInfo;
  nsCString mPreviousFontName;
};

int CALLBACK GDIFontInfo::EnumerateFontsForFamily(
    const ENUMLOGFONTEXW* lpelfe, const NEWTEXTMETRICEXW* nmetrics,
    DWORD fontType, LPARAM data) {
  EnumerateFontsForFamilyData* famData =
      reinterpret_cast<EnumerateFontsForFamilyData*>(data);
  HDC hdc = famData->mFontInfo.mHdc;
  LOGFONTW logFont = lpelfe->elfLogFont;
  const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;

  AutoSelectFont font(hdc, &logFont);
  if (!font.IsValid()) {
    return 1;
  }

  FontFaceData fontData;
  NS_ConvertUTF16toUTF8 fontName(lpelfe->elfFullName);

  // callback called for each style-charset so return if style already seen
  if (fontName.Equals(famData->mPreviousFontName)) {
    return 1;
  }
  famData->mPreviousFontName = fontName;
  famData->mFontInfo.mLoadStats.fonts++;

  // read name table info
  bool nameDataLoaded = false;
  if (famData->mFontInfo.mLoadFaceNames || famData->mFontInfo.mLoadOtherNames) {
    uint32_t kNAME =
        NativeEndian::swapToBigEndian(TRUETYPE_TAG('n''a''m''e'));
    uint32_t nameSize;
    AutoTArray<uint8_t, 1024> nameData;

    nameSize = ::GetFontData(hdc, kNAME, 0, nullptr, 0);
    if (nameSize != GDI_ERROR && nameSize > 0 &&
        nameData.SetLength(nameSize, fallible)) {
      ::GetFontData(hdc, kNAME, 0, nameData.Elements(), nameSize);

      // face names
      if (famData->mFontInfo.mLoadFaceNames) {
        gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()),
                                        nameSize, gfxFontUtils::NAME_ID_FULL,
                                        fontData.mFullName);
        gfxFontUtils::ReadCanonicalName(
            (const char*)(nameData.Elements()), nameSize,
            gfxFontUtils::NAME_ID_POSTSCRIPT, fontData.mPostscriptName);
        nameDataLoaded = true;
        famData->mFontInfo.mLoadStats.facenames++;
      }

      // other family names
      if (famData->mFontInfo.mLoadOtherNames) {
        gfxFontUtils::ReadOtherFamilyNamesForFace(
            famData->mFamilyName, (const char*)(nameData.Elements()), nameSize,
            famData->mOtherFamilyNames, false);
      }
    }
  }

  // read cmap
  bool cmapLoaded = false;
  gfxWindowsFontType feType =
      GDIFontEntry::DetermineFontType(metrics, fontType);
  if (famData->mFontInfo.mLoadCmaps && (feType == GFX_FONT_TYPE_PS_OPENTYPE ||
                                        feType == GFX_FONT_TYPE_TT_OPENTYPE ||
                                        feType == GFX_FONT_TYPE_TRUETYPE)) {
    uint32_t kCMAP =
        NativeEndian::swapToBigEndian(TRUETYPE_TAG('c''m''a''p'));
    uint32_t cmapSize;
    AutoTArray<uint8_t, 1024> cmapData;

    cmapSize = ::GetFontData(hdc, kCMAP, 0, nullptr, 0);
    if (cmapSize != GDI_ERROR && cmapSize > 0 &&
        cmapData.SetLength(cmapSize, fallible)) {
      ::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize);
      RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
      uint32_t offset;

      if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(), cmapSize,
                                              *charmap, offset))) {
        fontData.mCharacterMap = charmap;
        fontData.mUVSOffset = offset;
        cmapLoaded = true;
        famData->mFontInfo.mLoadStats.cmaps++;
      }
    }
  }

  if (cmapLoaded || nameDataLoaded) {
    famData->mFontInfo.mFontFaceData.InsertOrUpdate(fontName, fontData);
  }

  return famData->mFontInfo.mCanceled ? 0 : 1;
}

void GDIFontInfo::LoadFontFamilyData(const nsACString& aFamilyName) {
  // iterate over the family
  LOGFONTW logFont;
  memset(&logFont, 0, sizeof(LOGFONTW));
  logFont.lfCharSet = DEFAULT_CHARSET;
  logFont.lfPitchAndFamily = 0;
  NS_ConvertUTF8toUTF16 name(aFamilyName);
  uint32_t l = std::min<uint32_t>(name.Length(), LF_FACESIZE - 1);
  memcpy(logFont.lfFaceName, name.BeginReading(), l * sizeof(char16_t));

  EnumerateFontsForFamilyData data(aFamilyName, *this);

  EnumFontFamiliesExW(mHdc, &logFont,
                      (FONTENUMPROCW)GDIFontInfo::EnumerateFontsForFamily,
                      (LPARAM)(&data), 0);

  // if found other names, insert them
  if (data.mOtherFamilyNames.Length() != 0) {
    mOtherFamilyNames.InsertOrUpdate(aFamilyName, data.mOtherFamilyNames);
    mLoadStats.othernames += data.mOtherFamilyNames.Length();
  }
}

already_AddRefed<FontInfoData> gfxGDIFontList::CreateFontInfoData() {
  bool loadCmaps = !UsesSystemFallback() ||
                   gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();

  RefPtr<GDIFontInfo> fi =
      new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);

  return fi.forget();
}

gfxFontFamily* gfxGDIFontList::CreateFontFamily(
    const nsACString& aName, FontVisibility aVisibility) const {
  return new GDIFontFamily(aName, aVisibility);
}

#ifdef MOZ_BUNDLED_FONTS

void gfxGDIFontList::ActivateBundledFonts() {
  nsCOMPtr<nsIFile> localDir;
  nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
  if (NS_FAILED(rv)) {
    return;
  }
  if (NS_FAILED(localDir->Append(u"fonts"_ns))) {
    return;
  }
  bool isDir;
  if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
    return;
  }

  nsCOMPtr<nsIDirectoryEnumerator> e;
  rv = localDir->GetDirectoryEntries(getter_AddRefs(e));
  if (NS_FAILED(rv)) {
    return;
  }

  nsCOMPtr<nsIFile> file;
  while (NS_SUCCEEDED(e->GetNextFile(getter_AddRefs(file))) && file) {
    nsAutoString path;
    if (NS_FAILED(file->GetPath(path))) {
      continue;
    }
    AddFontResourceExW(path.get(), FR_PRIVATE, nullptr);
  }
}

#endif

97%


¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge