зеркало из https://github.com/mozilla/gecko-dev.git
bug 633299 - don't discard font entries for @font-face rules that haven't changed. r=dbaron
This commit is contained in:
Родитель
a9d26dac0b
Коммит
9765228219
|
@ -108,7 +108,7 @@ gfxUserFontSet::~gfxUserFontSet()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry*
|
||||
gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
PRUint32 aWeight,
|
||||
|
@ -118,6 +118,8 @@ gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
|
|||
const nsString& aLanguageOverride,
|
||||
gfxSparseBitSet *aUnicodeRanges)
|
||||
{
|
||||
gfxProxyFontEntry *proxyEntry = nsnull;
|
||||
|
||||
nsAutoString key(aFamilyName);
|
||||
ToLowerCase(key);
|
||||
|
||||
|
@ -135,29 +137,47 @@ gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
|
|||
}
|
||||
|
||||
// construct a new face and add it into the family
|
||||
if (family) {
|
||||
nsTArray<gfxFontFeature> featureSettings;
|
||||
gfxFontStyle::ParseFontFeatureSettings(aFeatureSettings,
|
||||
featureSettings);
|
||||
PRUint32 languageOverride =
|
||||
gfxFontStyle::ParseFontLanguageOverride(aLanguageOverride);
|
||||
gfxProxyFontEntry *proxyEntry =
|
||||
new gfxProxyFontEntry(aFontFaceSrcList, family, aWeight, aStretch,
|
||||
aItalicStyle,
|
||||
featureSettings,
|
||||
languageOverride,
|
||||
aUnicodeRanges);
|
||||
family->AddFontEntry(proxyEntry);
|
||||
nsTArray<gfxFontFeature> featureSettings;
|
||||
gfxFontStyle::ParseFontFeatureSettings(aFeatureSettings,
|
||||
featureSettings);
|
||||
PRUint32 languageOverride =
|
||||
gfxFontStyle::ParseFontLanguageOverride(aLanguageOverride);
|
||||
proxyEntry =
|
||||
new gfxProxyFontEntry(aFontFaceSrcList, family, aWeight, aStretch,
|
||||
aItalicStyle,
|
||||
featureSettings,
|
||||
languageOverride,
|
||||
aUnicodeRanges);
|
||||
family->AddFontEntry(proxyEntry);
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
|
||||
this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
|
||||
(aItalicStyle & FONT_STYLE_ITALIC ? "italic" :
|
||||
(aItalicStyle & FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
|
||||
aWeight, aStretch));
|
||||
}
|
||||
#endif
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
|
||||
this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
|
||||
(aItalicStyle & FONT_STYLE_ITALIC ? "italic" :
|
||||
(aItalicStyle & FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
|
||||
aWeight, aStretch));
|
||||
}
|
||||
#endif
|
||||
|
||||
return proxyEntry;
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
|
||||
gfxFontEntry *aFontEntry)
|
||||
{
|
||||
nsAutoString key(aFamilyName);
|
||||
ToLowerCase(key);
|
||||
|
||||
PRBool found;
|
||||
|
||||
gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
|
||||
if (!family) {
|
||||
family = new gfxMixedFontFamily(aFamilyName);
|
||||
mFontFamilies.Put(key, family);
|
||||
}
|
||||
|
||||
family->AddFontEntry(aFontEntry);
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
|
@ -541,7 +561,7 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
|
|||
fe->mFeatureSettings.AppendElements(pe->mFeatureSettings);
|
||||
fe->mLanguageOverride = pe->mLanguageOverride;
|
||||
|
||||
static_cast<gfxMixedFontFamily*>(pe->mFamily)->ReplaceFontEntry(pe, fe);
|
||||
ReplaceFontEntry(pe, fe);
|
||||
IncrementGeneration();
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
|
@ -630,7 +650,7 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
|
|||
PRUint32(mGeneration)));
|
||||
fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
|
||||
fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
|
||||
static_cast<gfxMixedFontFamily*>(aProxyEntry->mFamily)->ReplaceFontEntry(aProxyEntry, fe);
|
||||
ReplaceFontEntry(aProxyEntry, fe);
|
||||
return STATUS_LOADED;
|
||||
} else {
|
||||
LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
|
||||
|
|
|
@ -94,6 +94,7 @@ public:
|
|||
void AddFontEntry(gfxFontEntry *aFontEntry) {
|
||||
nsRefPtr<gfxFontEntry> fe = aFontEntry;
|
||||
mAvailableFonts.AppendElement(fe);
|
||||
aFontEntry->SetFamily(this);
|
||||
}
|
||||
|
||||
void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry)
|
||||
|
@ -103,6 +104,8 @@ public:
|
|||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (fe == aOldFontEntry) {
|
||||
mAvailableFonts[i] = aNewFontEntry;
|
||||
aOldFontEntry->SetFamily(nsnull);
|
||||
aNewFontEntry->SetFamily(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +117,7 @@ public:
|
|||
for (PRUint32 i = 0; i < numFonts; i++) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (fe == aFontEntry) {
|
||||
aFontEntry->SetFamily(nsnull);
|
||||
mAvailableFonts.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
|
@ -172,14 +176,17 @@ public:
|
|||
// weight, stretch - 0 == unknown, [1, 9] otherwise
|
||||
// italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
|
||||
// TODO: support for unicode ranges not yet implemented
|
||||
void AddFontFace(const nsAString& aFamilyName,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
PRUint32 aWeight,
|
||||
PRUint32 aStretch,
|
||||
PRUint32 aItalicStyle,
|
||||
const nsString& aFeatureSettings,
|
||||
const nsString& aLanguageOverride,
|
||||
gfxSparseBitSet *aUnicodeRanges = nsnull);
|
||||
gfxFontEntry *AddFontFace(const nsAString& aFamilyName,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
PRUint32 aWeight,
|
||||
PRUint32 aStretch,
|
||||
PRUint32 aItalicStyle,
|
||||
const nsString& aFeatureSettings,
|
||||
const nsString& aLanguageOverride,
|
||||
gfxSparseBitSet *aUnicodeRanges = nsnull);
|
||||
|
||||
// add in a font face for which we have the gfxFontEntry already
|
||||
void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry);
|
||||
|
||||
// Whether there is a face with this family name
|
||||
PRBool HasFamily(const nsAString& aFamilyName) const
|
||||
|
@ -209,6 +216,12 @@ public:
|
|||
const PRUint8 *aFontData, PRUint32 aLength,
|
||||
nsresult aDownloadStatus);
|
||||
|
||||
// Replace a proxy with a real fontEntry; this is implemented in
|
||||
// nsUserFontSet in order to keep track of the entry corresponding
|
||||
// to each @font-face rule.
|
||||
virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy,
|
||||
gfxFontEntry *aFontEntry) = 0;
|
||||
|
||||
// generation - each time a face is loaded, generation is
|
||||
// incremented so that the change can be recognized
|
||||
PRUint64 GetGeneration() { return mGeneration; }
|
||||
|
|
|
@ -1772,177 +1772,6 @@ nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask)
|
|||
UseDocumentColors());
|
||||
}
|
||||
|
||||
static void
|
||||
InsertFontFaceRule(nsCSSFontFaceRule *aRule, gfxUserFontSet* aFontSet,
|
||||
PRUint8 aSheetType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aRule->GetType() == nsICSSRule::FONT_FACE_RULE,
|
||||
"InsertFontFaceRule passed a non-fontface CSS rule");
|
||||
|
||||
// aRule->List();
|
||||
|
||||
nsAutoString fontfamily;
|
||||
nsCSSValue val;
|
||||
|
||||
PRUint32 unit;
|
||||
PRUint32 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
|
||||
PRUint32 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
|
||||
PRUint32 italicStyle = FONT_STYLE_NORMAL;
|
||||
nsString featureSettings, languageOverride;
|
||||
|
||||
// set up family name
|
||||
aRule->GetDesc(eCSSFontDesc_Family, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(fontfamily);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face family name has unexpected unit");
|
||||
// If there is no family name, this rule cannot contribute a
|
||||
// usable font, so there is no point in processing it further.
|
||||
return;
|
||||
}
|
||||
|
||||
// set up weight
|
||||
aRule->GetDesc(eCSSFontDesc_Weight, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
|
||||
weight = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
weight = NS_STYLE_FONT_WEIGHT_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face weight has unexpected unit");
|
||||
}
|
||||
|
||||
// set up stretch
|
||||
aRule->GetDesc(eCSSFontDesc_Stretch, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Enumerated) {
|
||||
stretch = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
stretch = NS_STYLE_FONT_STRETCH_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face stretch has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font style
|
||||
aRule->GetDesc(eCSSFontDesc_Style, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Enumerated) {
|
||||
italicStyle = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
italicStyle = FONT_STYLE_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face style has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font features
|
||||
aRule->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Normal) {
|
||||
// empty feature string
|
||||
} else if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(featureSettings);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face font-feature-settings has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font language override
|
||||
aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Normal) {
|
||||
// empty feature string
|
||||
} else if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(languageOverride);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face font-language-override has unexpected unit");
|
||||
}
|
||||
|
||||
// set up src array
|
||||
nsTArray<gfxFontFaceSrc> srcArray;
|
||||
|
||||
aRule->GetDesc(eCSSFontDesc_Src, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Array) {
|
||||
nsCSSValue::Array *srcArr = val.GetArrayValue();
|
||||
size_t numSrc = srcArr->Count();
|
||||
|
||||
for (size_t i = 0; i < numSrc; i++) {
|
||||
val = srcArr->Item(i);
|
||||
unit = val.GetUnit();
|
||||
gfxFontFaceSrc *face = srcArray.AppendElements(1);
|
||||
if (!face)
|
||||
return;
|
||||
|
||||
switch (unit) {
|
||||
|
||||
case eCSSUnit_Local_Font:
|
||||
val.GetStringValue(face->mLocalName);
|
||||
face->mIsLocal = PR_TRUE;
|
||||
face->mURI = nsnull;
|
||||
face->mFormatFlags = 0;
|
||||
break;
|
||||
case eCSSUnit_URL:
|
||||
face->mIsLocal = PR_FALSE;
|
||||
face->mURI = val.GetURLValue();
|
||||
NS_ASSERTION(face->mURI, "null url in @font-face rule");
|
||||
face->mReferrer = val.GetURLStructValue()->mReferrer;
|
||||
face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
|
||||
NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
|
||||
|
||||
// agent and user stylesheets are treated slightly differently,
|
||||
// the same-site origin check and access control headers are
|
||||
// enforced against the sheet principal rather than the document
|
||||
// principal to allow user stylesheets to include @font-face rules
|
||||
face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
|
||||
aSheetType == nsStyleSet::eAgentSheet);
|
||||
|
||||
face->mLocalName.Truncate();
|
||||
face->mFormatFlags = 0;
|
||||
while (i + 1 < numSrc && (val = srcArr->Item(i+1),
|
||||
val.GetUnit() == eCSSUnit_Font_Format)) {
|
||||
nsDependentString valueString(val.GetStringBufferValue());
|
||||
if (valueString.LowerCaseEqualsASCII("woff")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF;
|
||||
} else if (valueString.LowerCaseEqualsASCII("opentype")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE;
|
||||
} else if (valueString.LowerCaseEqualsASCII("truetype")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE;
|
||||
} else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT;
|
||||
} else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;
|
||||
} else if (valueString.LowerCaseEqualsASCII("svg")) {
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_SVG;
|
||||
} else {
|
||||
// unknown format specified, mark to distinguish from the
|
||||
// case where no format hints are specified
|
||||
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_UNKNOWN;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
|
||||
"strange unit type in font-face src array");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
|
||||
}
|
||||
|
||||
if (!fontfamily.IsEmpty() && srcArray.Length() > 0) {
|
||||
aFontSet->AddFontFace(fontfamily, srcArray, weight, stretch, italicStyle,
|
||||
featureSettings, languageOverride);
|
||||
}
|
||||
}
|
||||
|
||||
gfxUserFontSet*
|
||||
nsPresContext::GetUserFontSetInternal()
|
||||
{
|
||||
|
@ -1994,59 +1823,37 @@ nsPresContext::FlushUserFontSet()
|
|||
|
||||
if (mUserFontSetDirty) {
|
||||
if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
|
||||
nsRefPtr<gfxUserFontSet> oldUserFontSet = mUserFontSet;
|
||||
|
||||
nsTArray<nsFontFaceRuleContainer> rules;
|
||||
if (!mShell->StyleSet()->AppendFontFaceRules(this, rules))
|
||||
return;
|
||||
|
||||
PRBool differ;
|
||||
if (rules.Length() == mFontFaceRules.Length()) {
|
||||
differ = PR_FALSE;
|
||||
for (PRUint32 i = 0, i_end = rules.Length(); i < i_end; ++i) {
|
||||
if (rules[i].mRule != mFontFaceRules[i].mRule ||
|
||||
rules[i].mSheetType != mFontFaceRules[i].mSheetType) {
|
||||
differ = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
differ = PR_TRUE;
|
||||
}
|
||||
|
||||
// Only rebuild things if the set of @font-face rules is different.
|
||||
if (differ) {
|
||||
if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
|
||||
if (mUserFontSet) {
|
||||
mUserFontSet->Destroy();
|
||||
NS_RELEASE(mUserFontSet);
|
||||
}
|
||||
|
||||
if (rules.Length() > 0) {
|
||||
nsUserFontSet *fs = new nsUserFontSet(this);
|
||||
if (!fs)
|
||||
return;
|
||||
mUserFontSet = fs;
|
||||
NS_ADDREF(mUserFontSet);
|
||||
|
||||
for (PRUint32 i = 0, i_end = rules.Length(); i < i_end; ++i) {
|
||||
InsertFontFaceRule(rules[i].mRule, fs, rules[i].mSheetType);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool success =
|
||||
#endif
|
||||
rules.SwapElements(mFontFaceRules);
|
||||
NS_ASSERTION(success, "should never fail given both are heap arrays");
|
||||
PRBool changed = PR_FALSE;
|
||||
|
||||
if (mGetUserFontSetCalled && oldUserFontSet != mUserFontSet) {
|
||||
// If we've changed, created, or destroyed a user font set, we
|
||||
// need to trigger a style change reflow.
|
||||
// We need to enqueue a style change reflow (for later) to
|
||||
// reflect that we're dropping @font-face rules. (However,
|
||||
// without a reflow, nothing will happen to start any downloads
|
||||
// that are needed.)
|
||||
if (rules.Length() == 0) {
|
||||
if (mUserFontSet) {
|
||||
mUserFontSet->Destroy();
|
||||
NS_RELEASE(mUserFontSet);
|
||||
}
|
||||
changed = PR_TRUE;
|
||||
} else if (!mUserFontSet) {
|
||||
mUserFontSet = new nsUserFontSet(this);
|
||||
NS_ADDREF(mUserFontSet);
|
||||
}
|
||||
|
||||
if (mUserFontSet) {
|
||||
changed = mUserFontSet->UpdateRules(rules);
|
||||
}
|
||||
|
||||
// We need to enqueue a style change reflow (for later) to
|
||||
// reflect that we're modifying @font-face rules. (However,
|
||||
// without a reflow, nothing will happen to start any downloads
|
||||
// that are needed.)
|
||||
if (changed) {
|
||||
UserFontSetUpdated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1109,8 +1109,6 @@ protected:
|
|||
|
||||
// container for per-context fonts (downloadable, SVG, etc.)
|
||||
nsUserFontSet* mUserFontSet;
|
||||
// The list of @font-face rules that we put into mUserFontSet
|
||||
nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
|
||||
|
||||
PRInt32 mFontScaler;
|
||||
nscoord mMinimumFontSizePref;
|
||||
|
|
|
@ -73,6 +73,8 @@
|
|||
#include "nsIChannelPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
|
||||
#include "nsStyleSet.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *gFontDownloaderLog = PR_NewLogModule("fontdownloader");
|
||||
#endif /* PR_LOGGING */
|
||||
|
@ -436,3 +438,246 @@ nsUserFontSet::StartLoad(gfxFontEntry *aFontToLoad,
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsUserFontSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
|
||||
{
|
||||
nsTArray<FontFaceRuleRecord> oldRules;
|
||||
mRules.SwapElements(oldRules);
|
||||
|
||||
// destroy the font family records; we need to re-create them
|
||||
// because we might end up with faces in a different order,
|
||||
// even if they're the same font entries as before
|
||||
mFontFamilies.Clear();
|
||||
|
||||
PRBool modified = PR_FALSE;
|
||||
|
||||
for (PRUint32 i = 0, i_end = aRules.Length(); i < i_end; ++i) {
|
||||
// insert each rule into our list, migrating old font entries if possible
|
||||
// rather than creating new ones; set modified to true if we detect
|
||||
// that rule ordering has changed, or if a new entry is created
|
||||
InsertRule(aRules[i].mRule, aRules[i].mSheetType, oldRules, modified);
|
||||
}
|
||||
|
||||
// if any rules are left in the old list, note that the set has changed
|
||||
if (oldRules.Length() > 0) {
|
||||
modified = PR_TRUE;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void
|
||||
nsUserFontSet::InsertRule(nsCSSFontFaceRule *aRule, PRUint8 aSheetType,
|
||||
nsTArray<FontFaceRuleRecord>& oldRules,
|
||||
PRBool& aFontSetModified)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aRule->GetType() == nsICSSRule::FONT_FACE_RULE,
|
||||
"InsertRule passed a non-fontface CSS rule");
|
||||
|
||||
// set up family name
|
||||
nsAutoString fontfamily;
|
||||
nsCSSValue val;
|
||||
PRUint32 unit;
|
||||
|
||||
aRule->GetDesc(eCSSFontDesc_Family, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(fontfamily);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face family name has unexpected unit");
|
||||
}
|
||||
if (fontfamily.IsEmpty()) {
|
||||
// If there is no family name, this rule cannot contribute a
|
||||
// usable font, so there is no point in processing it further.
|
||||
return;
|
||||
}
|
||||
|
||||
// first, we check in oldRules; if the rule exists there, just move it
|
||||
// to the new rule list, and put the entry into the appropriate family
|
||||
for (PRUint32 i = 0; i < oldRules.Length(); ++i) {
|
||||
const FontFaceRuleRecord& ruleRec = oldRules[i];
|
||||
if (ruleRec.mContainer.mRule == aRule &&
|
||||
ruleRec.mContainer.mSheetType == aSheetType) {
|
||||
AddFontFace(fontfamily, ruleRec.mFontEntry);
|
||||
mRules.AppendElement(ruleRec);
|
||||
oldRules.RemoveElementAt(i);
|
||||
// note the set has been modified if an old rule was skipped to find
|
||||
// this one - something has been dropped, or ordering changed
|
||||
if (i > 0) {
|
||||
aFontSetModified = PR_TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// this is a new rule:
|
||||
|
||||
PRUint32 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
|
||||
PRUint32 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
|
||||
PRUint32 italicStyle = FONT_STYLE_NORMAL;
|
||||
nsString featureSettings, languageOverride;
|
||||
|
||||
// set up weight
|
||||
aRule->GetDesc(eCSSFontDesc_Weight, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
|
||||
weight = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
weight = NS_STYLE_FONT_WEIGHT_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face weight has unexpected unit");
|
||||
}
|
||||
|
||||
// set up stretch
|
||||
aRule->GetDesc(eCSSFontDesc_Stretch, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Enumerated) {
|
||||
stretch = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
stretch = NS_STYLE_FONT_STRETCH_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face stretch has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font style
|
||||
aRule->GetDesc(eCSSFontDesc_Style, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Enumerated) {
|
||||
italicStyle = val.GetIntValue();
|
||||
} else if (unit == eCSSUnit_Normal) {
|
||||
italicStyle = FONT_STYLE_NORMAL;
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face style has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font features
|
||||
aRule->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Normal) {
|
||||
// empty feature string
|
||||
} else if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(featureSettings);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face font-feature-settings has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font language override
|
||||
aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Normal) {
|
||||
// empty feature string
|
||||
} else if (unit == eCSSUnit_String) {
|
||||
val.GetStringValue(languageOverride);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face font-language-override has unexpected unit");
|
||||
}
|
||||
|
||||
// set up src array
|
||||
nsTArray<gfxFontFaceSrc> srcArray;
|
||||
|
||||
aRule->GetDesc(eCSSFontDesc_Src, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Array) {
|
||||
nsCSSValue::Array *srcArr = val.GetArrayValue();
|
||||
size_t numSrc = srcArr->Count();
|
||||
|
||||
for (size_t i = 0; i < numSrc; i++) {
|
||||
val = srcArr->Item(i);
|
||||
unit = val.GetUnit();
|
||||
gfxFontFaceSrc *face = srcArray.AppendElements(1);
|
||||
if (!face)
|
||||
return;
|
||||
|
||||
switch (unit) {
|
||||
|
||||
case eCSSUnit_Local_Font:
|
||||
val.GetStringValue(face->mLocalName);
|
||||
face->mIsLocal = PR_TRUE;
|
||||
face->mURI = nsnull;
|
||||
face->mFormatFlags = 0;
|
||||
break;
|
||||
case eCSSUnit_URL:
|
||||
face->mIsLocal = PR_FALSE;
|
||||
face->mURI = val.GetURLValue();
|
||||
NS_ASSERTION(face->mURI, "null url in @font-face rule");
|
||||
face->mReferrer = val.GetURLStructValue()->mReferrer;
|
||||
face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
|
||||
NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
|
||||
|
||||
// agent and user stylesheets are treated slightly differently,
|
||||
// the same-site origin check and access control headers are
|
||||
// enforced against the sheet principal rather than the document
|
||||
// principal to allow user stylesheets to include @font-face rules
|
||||
face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
|
||||
aSheetType == nsStyleSet::eAgentSheet);
|
||||
|
||||
face->mLocalName.Truncate();
|
||||
face->mFormatFlags = 0;
|
||||
while (i + 1 < numSrc && (val = srcArr->Item(i+1),
|
||||
val.GetUnit() == eCSSUnit_Font_Format)) {
|
||||
nsDependentString valueString(val.GetStringBufferValue());
|
||||
if (valueString.LowerCaseEqualsASCII("woff")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_WOFF;
|
||||
} else if (valueString.LowerCaseEqualsASCII("opentype")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_OPENTYPE;
|
||||
} else if (valueString.LowerCaseEqualsASCII("truetype")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_TRUETYPE;
|
||||
} else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_TRUETYPE_AAT;
|
||||
} else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_EOT;
|
||||
} else if (valueString.LowerCaseEqualsASCII("svg")) {
|
||||
face->mFormatFlags |= FLAG_FORMAT_SVG;
|
||||
} else {
|
||||
// unknown format specified, mark to distinguish from the
|
||||
// case where no format hints are specified
|
||||
face->mFormatFlags |= FLAG_FORMAT_UNKNOWN;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
|
||||
"strange unit type in font-face src array");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
|
||||
}
|
||||
|
||||
if (srcArray.Length() > 0) {
|
||||
FontFaceRuleRecord ruleRec;
|
||||
ruleRec.mContainer.mRule = aRule;
|
||||
ruleRec.mContainer.mSheetType = aSheetType;
|
||||
ruleRec.mFontEntry = AddFontFace(fontfamily, srcArray,
|
||||
weight, stretch, italicStyle,
|
||||
featureSettings, languageOverride);
|
||||
if (ruleRec.mFontEntry) {
|
||||
mRules.AppendElement(ruleRec);
|
||||
}
|
||||
// this was a new rule and fontEntry, so note that the set was modified
|
||||
aFontSetModified = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsUserFontSet::ReplaceFontEntry(gfxProxyFontEntry *aProxy,
|
||||
gfxFontEntry *aFontEntry)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mRules.Length(); ++i) {
|
||||
if (mRules[i].mFontEntry == aProxy) {
|
||||
mRules[i].mFontEntry = aFontEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
static_cast<gfxMixedFontFamily*>(aProxy->Family())->
|
||||
ReplaceFontEntry(aProxy, aFontEntry);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "gfxUserFontSet.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsCSSRules.h"
|
||||
|
||||
class nsIRequest;
|
||||
class nsISupports;
|
||||
|
@ -57,6 +58,7 @@ class nsPresContext;
|
|||
class nsIPrincipal;
|
||||
|
||||
class nsFontFaceLoader;
|
||||
class nsCSSFontFaceRule;
|
||||
|
||||
// nsUserFontSet - defines the loading mechanism for downloadable fonts
|
||||
class nsUserFontSet : public gfxUserFontSet
|
||||
|
@ -77,15 +79,35 @@ public:
|
|||
// It's removed from the mLoaders set.
|
||||
void RemoveLoader(nsFontFaceLoader *aLoader);
|
||||
|
||||
PRBool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
|
||||
|
||||
nsPresContext *GetPresContext() { return mPresContext; }
|
||||
|
||||
virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy,
|
||||
gfxFontEntry *aFontEntry);
|
||||
|
||||
protected:
|
||||
// The font-set keeps track of the collection of rules, and their
|
||||
// corresponding font entries (whether proxies or real entries),
|
||||
// so that we can update the set without having to throw away
|
||||
// all the existing fonts.
|
||||
struct FontFaceRuleRecord {
|
||||
nsRefPtr<gfxFontEntry> mFontEntry;
|
||||
nsFontFaceRuleContainer mContainer;
|
||||
};
|
||||
|
||||
void InsertRule(nsCSSFontFaceRule *aRule, PRUint8 aSheetType,
|
||||
nsTArray<FontFaceRuleRecord>& oldRules,
|
||||
PRBool& aFontSetModified);
|
||||
|
||||
nsPresContext *mPresContext; // weak reference
|
||||
|
||||
// Set of all loaders pointing to us. These are not strong pointers,
|
||||
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
|
||||
// us before it dies (unless we die first).
|
||||
nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
|
||||
|
||||
nsTArray<FontFaceRuleRecord> mRules;
|
||||
};
|
||||
|
||||
class nsFontFaceLoader : public nsIStreamLoaderObserver
|
||||
|
|
Загрузка…
Ссылка в новой задаче