/* -*- 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/. */
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;
}
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();
}
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) returnfalse;
// 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()) returnfalse;
gfxGDIFont* font = static_cast<gfxGDIFont*>(tempFont.get());
// 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;
}
// 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
staticbool 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");
}
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;
} elseif (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;
}
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();
}
// "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();
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();
}
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. staticbool 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; returntrue;
}
} returnfalse;
}
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;
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);
// 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));
}
// 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) {}
// 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;
// if found other names, insert them if (data.mOtherFamilyNames.Length() != 0) {
mOtherFamilyNames.InsertOrUpdate(aFamilyName, data.mOtherFamilyNames);
mLoadStats.othernames += data.mOtherFamilyNames.Length();
}
}
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.