bug 467669 - pt 6 - provide the real font name rather than our internal identifier. r=roc

--HG--
extra : rebase_source : d548ab2be329058bde101b142607abf14dce7191
This commit is contained in:
Jonathan Kew 2011-06-15 20:17:54 +01:00
parent 08274c4304
commit 34ebc89623
10 changed files with 193 additions and 18 deletions

View File

@ -260,31 +260,42 @@ FontEntry::ReadCMAP()
// attempt this once, if errors occur leave a blank cmap
mCmapInitialized = PR_TRUE;
AutoFallibleTArray<PRUint8,16384> buffer;
nsresult rv = GetFontTable(TTAG_cmap, buffer);
if (NS_SUCCEEDED(rv)) {
PRPackedBool unicodeFont;
PRPackedBool symbolFont;
rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(),
mCharacterMap, mUVSOffset,
unicodeFont, symbolFont);
}
mHasCmapTable = NS_SUCCEEDED(rv);
return rv;
}
nsresult
FontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer)
{
// Ensure existence of mFTFace
CairoFontFace();
NS_ENSURE_TRUE(mFTFace, NS_ERROR_FAILURE);
FT_Error status;
FT_ULong len = 0;
status = FT_Load_Sfnt_Table(mFTFace, TTAG_cmap, 0, nsnull, &len);
status = FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nsnull, &len);
NS_ENSURE_TRUE(status == 0, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(len != 0, NS_ERROR_FAILURE);
AutoFallibleTArray<PRUint8,16384> buffer;
if (!buffer.AppendElements(len)) {
return NS_ERROR_FAILURE;
if (!aBuffer.SetLength(len)) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRUint8 *buf = buffer.Elements();
status = FT_Load_Sfnt_Table(mFTFace, TTAG_cmap, 0, buf, &len);
PRUint8 *buf = aBuffer.Elements();
status = FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, buf, &len);
NS_ENSURE_TRUE(status == 0, NS_ERROR_FAILURE);
PRPackedBool unicodeFont;
PRPackedBool symbolFont;
nsresult rv = gfxFontUtils::ReadCMAP(buf, len, mCharacterMap, mUVSOffset,
unicodeFont, symbolFont);
mHasCmapTable = NS_SUCCEEDED(rv);
return rv;
return NS_OK;
}
FontEntry *

View File

@ -112,6 +112,8 @@ public:
cairo_font_face_t *CairoFontFace();
nsresult ReadCMAP();
nsresult GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer);
FT_Face mFTFace;
cairo_font_face_t *mFontFace;

View File

@ -175,6 +175,21 @@ nsString gfxFontEntry::FamilyName() const
}
}
nsString
gfxFontEntry::RealFaceName()
{
FallibleTArray<PRUint8> nameTable;
nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
if (NS_SUCCEEDED(rv)) {
nsAutoString name;
rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
if (NS_SUCCEEDED(rv)) {
return name;
}
}
return Name();
}
already_AddRefed<gfxFont>
gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle, PRBool aNeedsBold)
{

View File

@ -221,9 +221,14 @@ public:
virtual ~gfxFontEntry();
// unique name for the face, *not* the family
// unique name for the face, *not* the family; not necessarily the
// "real" or user-friendly name, may be an internal identifier
const nsString& Name() const { return mName; }
// the "real" name of the face, if available from the font resource
// (may be expensive); returns Name() if nothing better is available
virtual nsString RealFaceName();
gfxFontFamily* Family() const { return mFamily; }
PRUint16 Weight() const { return mWeight; }

View File

@ -1434,6 +1434,80 @@ gfxFontUtils::RenameFont(const nsAString& aName, const PRUint8 *aFontData,
return NS_OK;
}
// This is only called after the basic validity of the downloaded sfnt
// data has been checked, so it should never fail to find the name table
// (though it might fail to read it, if memory isn't available);
// other checks here are just for extra paranoia.
nsresult
gfxFontUtils::GetFullNameFromSFNT(const PRUint8* aFontData, PRUint32 aLength,
nsAString& aFullName)
{
aFullName.AssignLiteral("(MISSING NAME)"); // should always get replaced
NS_ENSURE_TRUE(aLength >= sizeof(SFNTHeader), NS_ERROR_UNEXPECTED);
const SFNTHeader *sfntHeader =
reinterpret_cast<const SFNTHeader*>(aFontData);
const TableDirEntry *dirEntry =
reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
PRUint32 numTables = sfntHeader->numTables;
NS_ENSURE_TRUE(aLength >=
sizeof(SFNTHeader) + numTables * sizeof(TableDirEntry),
NS_ERROR_UNEXPECTED);
PRBool foundName = PR_FALSE;
for (PRUint32 i = 0; i < numTables; i++, dirEntry++) {
if (dirEntry->tag == TRUETYPE_TAG('n','a','m','e')) {
foundName = PR_TRUE;
break;
}
}
// should never fail, as we're only called after font validation succeeded
NS_ENSURE_TRUE(foundName, NS_ERROR_NOT_AVAILABLE);
PRUint32 len = dirEntry->length;
NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
NS_ERROR_UNEXPECTED);
FallibleTArray<PRUint8> nameTable;
if (!nameTable.SetLength(len)) {
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(nameTable.Elements(), aFontData + dirEntry->offset, len);
return GetFullNameFromTable(nameTable, aFullName);
}
nsresult
gfxFontUtils::GetFullNameFromTable(FallibleTArray<PRUint8>& aNameTable,
nsAString& aFullName)
{
nsAutoString name;
nsresult rv =
gfxFontUtils::ReadCanonicalName(aNameTable,
gfxFontUtils::NAME_ID_FULL,
name);
if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
aFullName = name;
return NS_OK;
}
rv = gfxFontUtils::ReadCanonicalName(aNameTable,
gfxFontUtils::NAME_ID_FAMILY,
name);
if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
nsAutoString styleName;
rv = gfxFontUtils::ReadCanonicalName(aNameTable,
gfxFontUtils::NAME_ID_STYLE,
styleName);
if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) {
name.AppendLiteral(" ");
name.Append(styleName);
aFullName = name;
}
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
enum {
#if defined(XP_MACOSX)
CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,

View File

@ -706,10 +706,26 @@ public:
DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength);
// checks for valid SFNT table structure, returns true if valid
// does *not* guarantee that all font data is valid
// does *not* guarantee that all font data is valid, though it does
// check that key tables such as 'name' are present and readable.
// XXX to be removed if/when we eliminate the option to disable OTS,
// which does more thorough validation.
static PRBool
ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength);
// Read the fullname from the sfnt data (used to save the original name
// prior to renaming the font for installation).
// This is called with sfnt data that has already been validated,
// so it should always succeed in finding the name table.
static nsresult
GetFullNameFromSFNT(const PRUint8* aFontData, PRUint32 aLength,
nsAString& aFullName);
// helper to get fullname from name table
static nsresult
GetFullNameFromTable(FallibleTArray<PRUint8>& aNameTable,
nsAString& aFullName);
// create a new name table and build a new font with that name table
// appended on the end, returns true on success
static nsresult

View File

@ -194,6 +194,11 @@ public:
// gfxFcFontEntries in families; just read the name from fontconfig
virtual nsString FamilyName() const;
// override the gfxFontEntry impl to read the name from fontconfig
// instead of trying to get the 'name' table, as we don't implement
// GetFontTable() here
virtual nsString RealFaceName();
protected:
gfxFcFontEntry(const nsAString& aName)
: gfxFontEntry(aName),
@ -229,6 +234,29 @@ gfxFcFontEntry::FamilyName() const
return gfxFontEntry::FamilyName();
}
nsString
gfxFcFontEntry::RealFaceName()
{
FcChar8 *name;
if (!mPatterns.IsEmpty()) {
if (FcPatternGetString(mPatterns[0],
FC_FULLNAME, 0, &name) == FcResultMatch) {
return NS_ConvertUTF8toUTF16((const char*)name);
}
if (FcPatternGetString(mPatterns[0],
FC_FAMILY, 0, &name) == FcResultMatch) {
NS_ConvertUTF8toUTF16 result((const char*)name);
if (FcPatternGetString(mPatterns[0],
FC_STYLE, 0, &name) == FcResultMatch) {
result.AppendLiteral(" ");
AppendUTF8toUTF16((const char*)name, result);
}
return result;
}
}
return gfxFontEntry::RealFaceName();
}
PRBool
gfxFcFontEntry::ShouldUseHarfBuzz(PRInt32 aRunScript) {
if (mSkipHarfBuzz ||

View File

@ -374,6 +374,7 @@ SanitizeOpenTypeData(const PRUint8* aData, PRUint32 aLength,
static void
StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
const nsAString& aOriginalName,
nsTArray<PRUint8>* aMetadata, PRUint32 aMetaOrigLen)
{
if (!aFontEntry->mUserFontData) {
@ -388,6 +389,7 @@ StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
userFontData->mURI = src.mURI;
}
userFontData->mFormat = src.mFormatFlags;
userFontData->mRealName = aOriginalName;
if (aMetadata) {
userFontData->mMetadata.SwapElements(*aMetadata);
userFontData->mMetaOrigLen = aMetaOrigLen;
@ -468,6 +470,11 @@ gfxUserFontSet::OnLoadComplete(gfxProxyFontEntry *aProxy,
// Unwrap/decompress/sanitize or otherwise munge the downloaded data
// to make a usable sfnt structure.
// Because platform font activation code may replace the name table
// in the font with a synthetic one, we save the original name so that
// it can be reported via the nsIDOMFontFace API.
nsAutoString originalFullName;
if (gfxPlatform::GetPlatform()->SanitizeDownloadedFonts()) {
// Call the OTS sanitizer; this will also decode WOFF to sfnt
// if necessary. The original data in aFontData is left unchanged.
@ -484,6 +491,12 @@ gfxUserFontSet::OnLoadComplete(gfxProxyFontEntry *aProxy,
}
#endif
if (saneData) {
// The sanitizer ensures that we have a valid sfnt and a usable
// name table, so this should never fail unless we're out of
// memory, and GetFullNameFromSFNT is not directly exposed to
// arbitrary/malicious data from the web.
gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
originalFullName);
// Here ownership of saneData is passed to the platform,
// which will delete it when no longer required
fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
@ -501,6 +514,10 @@ gfxUserFontSet::OnLoadComplete(gfxProxyFontEntry *aProxy,
if (aFontData) {
if (gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
// ValidateSFNTHeaders has checked that we have a valid
// sfnt structure and a usable 'name' table
gfxFontUtils::GetFullNameFromSFNT(aFontData, aLength,
originalFullName);
// Here ownership of aFontData is passed to the platform,
// which will delete it when no longer required
fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
@ -525,7 +542,8 @@ gfxUserFontSet::OnLoadComplete(gfxProxyFontEntry *aProxy,
// newly-created font entry
fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
fe->mLanguageOverride = aProxy->mLanguageOverride;
StoreUserFontData(fe, aProxy, &metadata, metaOrigLen);
StoreUserFontData(fe, aProxy, originalFullName,
&metadata, metaOrigLen);
#ifdef PR_LOGGING
// must do this before ReplaceFontEntry() because that will
// clear the proxy's mFamily pointer!
@ -617,7 +635,7 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
PRUint32(mGeneration)));
fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
StoreUserFontData(fe, aProxyEntry, nsnull, 0);
StoreUserFontData(fe, aProxyEntry, nsString(), nsnull, 0);
ReplaceFontEntry(aProxyEntry, fe);
return STATUS_LOADED;
} else {

View File

@ -87,6 +87,7 @@ public:
nsTArray<PRUint8> mMetadata; // woff metadata block (compressed), if any
nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url()
nsString mLocalName; // font name used for the source, if local()
nsString mRealName; // original fullname from the font resource
PRUint32 mSrcIndex; // index in the rule's source list
PRUint32 mFormat; // format hint for the source used, if any
PRUint32 mMetaOrigLen; // length needed to decompress metadata

View File

@ -94,7 +94,12 @@ nsFontFace::GetFromSystemFallback(PRBool * aFromSystemFallback)
NS_IMETHODIMP
nsFontFace::GetName(nsAString & aName)
{
aName = mFontEntry->Name();
if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
aName = mFontEntry->mUserFontData->mRealName;
} else {
aName = mFontEntry->RealFaceName();
}
return NS_OK;
}