зеркало из https://github.com/mozilla/gecko-dev.git
Rebuild the user font set when style sheets are enabled/disabled/added/removed, rules are modified/added/removed, or media changes change which style sheets apply. (Bug 457821) sr=bzbarsky r=jdaggett,bzbarsky a=blocking1.9.1+
This commit is contained in:
Родитель
f82a4ba107
Коммит
0b7f60a456
|
@ -1438,6 +1438,9 @@ nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
|
|||
// We must have been torn down. Nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
RebuildUserFontSet();
|
||||
|
||||
mShell->FrameConstructor()->RebuildAllStyleData(aExtraHint);
|
||||
}
|
||||
|
||||
|
@ -1693,40 +1696,130 @@ InsertFontFaceRule(nsCSSFontFaceRule *aRule, gfxUserFontSet* aFontSet)
|
|||
}
|
||||
}
|
||||
|
||||
gfxUserFontSet*
|
||||
gfxUserFontSet*
|
||||
nsPresContext::GetUserFontSet()
|
||||
{
|
||||
// We want to initialize the user font set lazily the first time the
|
||||
// user asks for it, rather than building it too early and forcing
|
||||
// rule cascade creation. Thus we try to enforce the invariant that
|
||||
// we *never* build the user font set until the first call to
|
||||
// GetUserFontSet. However, once it's been requested, we can't wait
|
||||
// for somebody to call GetUserFontSet in order to rebuild it (see
|
||||
// comments below in RebuildUserFontSet for why).
|
||||
if (mUserFontSetDirty) {
|
||||
NS_IF_RELEASE(mUserFontSet);
|
||||
// If this assertion fails, and there have actually been changes to
|
||||
// @font-face rules, then we will call StyleChangeReflow in
|
||||
// FlushUserFontSet. Since we're likely in the middle of reflow,
|
||||
// that's a bad thing to do.
|
||||
NS_ASSERTION(!mGetUserFontSetCalled,
|
||||
"FlushUserFontSet should have been called first");
|
||||
FlushUserFontSet();
|
||||
}
|
||||
|
||||
mGetUserFontSetCalled = PR_TRUE;
|
||||
return mUserFontSet;
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::FlushUserFontSet()
|
||||
{
|
||||
if (!mShell)
|
||||
return; // we've been torn down
|
||||
|
||||
if (mUserFontSetDirty) {
|
||||
if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
|
||||
nsRefPtr<gfxUserFontSet> oldUserFontSet = mUserFontSet;
|
||||
|
||||
nsTArray< nsRefPtr<nsCSSFontFaceRule> > rules;
|
||||
if (!mShell->StyleSet()->AppendFontFaceRules(this, rules))
|
||||
return nsnull;
|
||||
|
||||
if (rules.Length() > 0) {
|
||||
nsFontFaceLoaderContext *loaderCtx =
|
||||
new nsFontFaceLoaderContext(this);
|
||||
if (!loaderCtx)
|
||||
return nsnull;
|
||||
gfxUserFontSet *fs = new gfxUserFontSet(loaderCtx);
|
||||
// user font set owns loader context
|
||||
if (!fs) {
|
||||
delete loaderCtx;
|
||||
return nsnull;
|
||||
}
|
||||
mUserFontSet = fs;
|
||||
NS_ADDREF(mUserFontSet);
|
||||
return;
|
||||
|
||||
PRBool differ;
|
||||
if (rules.Length() == mFontFaceRules.Length()) {
|
||||
differ = PR_FALSE;
|
||||
for (PRUint32 i = 0, i_end = rules.Length(); i < i_end; ++i) {
|
||||
InsertFontFaceRule(rules[i], fs);
|
||||
if (rules[i] != mFontFaceRules[i]) {
|
||||
differ = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
differ = PR_TRUE;
|
||||
}
|
||||
|
||||
// Only rebuild things if the set of @font-face rules is different.
|
||||
if (differ) {
|
||||
NS_IF_RELEASE(mUserFontSet);
|
||||
|
||||
if (rules.Length() > 0) {
|
||||
nsFontFaceLoaderContext *loaderCtx =
|
||||
new nsFontFaceLoaderContext(this);
|
||||
if (!loaderCtx)
|
||||
return;
|
||||
gfxUserFontSet *fs = new gfxUserFontSet(loaderCtx);
|
||||
// user font set owns loader context
|
||||
if (!fs) {
|
||||
delete loaderCtx;
|
||||
return;
|
||||
}
|
||||
mUserFontSet = fs;
|
||||
NS_ADDREF(mUserFontSet);
|
||||
|
||||
for (PRUint32 i = 0, i_end = rules.Length(); i < i_end; ++i) {
|
||||
InsertFontFaceRule(rules[i], fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool success =
|
||||
#endif
|
||||
rules.SwapElements(mFontFaceRules);
|
||||
NS_ASSERTION(success, "should never fail given both are heap arrays");
|
||||
|
||||
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. This is the
|
||||
// same thing nsFontFaceLoader does when font downloads
|
||||
// complete. (However, without a reflow, nothing will happen
|
||||
// to start any downloads that are needed.)
|
||||
mShell->StyleChangeReflow();
|
||||
}
|
||||
}
|
||||
|
||||
mUserFontSetDirty = PR_FALSE;
|
||||
}
|
||||
return mUserFontSet;
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::RebuildUserFontSet()
|
||||
{
|
||||
if (!mGetUserFontSetCalled) {
|
||||
// We want to lazily build the user font set the first time it's
|
||||
// requested (so we don't force creation of rule cascades too
|
||||
// early), so don't do anything now.
|
||||
return;
|
||||
}
|
||||
|
||||
mUserFontSetDirty = PR_TRUE;
|
||||
|
||||
// Somebody has already asked for the user font set, so we need to
|
||||
// post an event to rebuild it. Setting the user font set to be dirty
|
||||
// and lazily rebuilding it isn't sufficient, since it is only the act
|
||||
// of rebuilding it that will trigger the style change reflow that
|
||||
// calls GetUserFontSet. (This reflow causes rebuilding of text runs,
|
||||
// which starts font loads, whose completion causes another style
|
||||
// change reflow).
|
||||
if (!mPostedFlushUserFontSet) {
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new nsRunnableMethod<nsPresContext>(this,
|
||||
&nsPresContext::HandleRebuildUserFontSet);
|
||||
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
|
||||
mPostedFlushUserFontSet = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
// This also pulls in gfxTypes.h, which we cannot include directly.
|
||||
#include "gfxRect.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsImageLoader;
|
||||
#ifdef IBMBIDI
|
||||
|
@ -93,6 +95,7 @@ struct nsStyleBackground;
|
|||
template <class T> class nsRunnableMethod;
|
||||
class nsIRunnable;
|
||||
class gfxUserFontSet;
|
||||
class nsCSSFontFaceRule;
|
||||
|
||||
#ifdef MOZ_REFLOW_PERF
|
||||
class nsIRenderingContext;
|
||||
|
@ -743,6 +746,8 @@ public:
|
|||
PRBool SupressingResizeReflow() const { return mSupressResizeReflow; }
|
||||
|
||||
gfxUserFontSet* GetUserFontSet();
|
||||
void FlushUserFontSet();
|
||||
void RebuildUserFontSet(); // asynchronously
|
||||
|
||||
void NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc);
|
||||
void FireDOMPaintEvent();
|
||||
|
@ -751,7 +756,7 @@ protected:
|
|||
friend class nsRunnableMethod<nsPresContext>;
|
||||
NS_HIDDEN_(void) ThemeChangedInternal();
|
||||
NS_HIDDEN_(void) SysColorChangedInternal();
|
||||
|
||||
|
||||
NS_HIDDEN_(void) SetImgAnimations(nsIContent *aParent, PRUint16 aMode);
|
||||
NS_HIDDEN_(void) GetDocumentColorPreferences();
|
||||
|
||||
|
@ -766,6 +771,11 @@ protected:
|
|||
|
||||
NS_HIDDEN_(void) UpdateCharSet(const nsAFlatCString& aCharSet);
|
||||
|
||||
void HandleRebuildUserFontSet() {
|
||||
mPostedFlushUserFontSet = PR_FALSE;
|
||||
FlushUserFontSet();
|
||||
}
|
||||
|
||||
// IMPORTANT: The ownership implicit in the following member variables
|
||||
// has been explicitly checked. If you add any members to this class,
|
||||
// please make the ownership explicit (pinkerton, scc).
|
||||
|
@ -812,6 +822,8 @@ protected:
|
|||
|
||||
// container for per-context fonts (downloadable, SVG, etc.)
|
||||
gfxUserFontSet* mUserFontSet;
|
||||
// The list of @font-face rules that we put into mUserFontSet
|
||||
nsTArray< nsRefPtr<nsCSSFontFaceRule> > mFontFaceRules;
|
||||
|
||||
PRInt32 mFontScaler;
|
||||
nscoord mMinimumFontSize;
|
||||
|
@ -870,7 +882,13 @@ protected:
|
|||
unsigned mPendingMediaFeatureValuesChanged : 1;
|
||||
unsigned mPrefChangePendingNeedsReflow : 1;
|
||||
unsigned mRenderedPositionVaryingContent : 1;
|
||||
|
||||
// Is the current mUserFontSet valid?
|
||||
unsigned mUserFontSetDirty : 1;
|
||||
// Has GetUserFontSet() been called?
|
||||
unsigned mGetUserFontSetCalled : 1;
|
||||
// Do we currently have an event posted to call FlushUserFontSet?
|
||||
unsigned mPostedFlushUserFontSet : 1;
|
||||
|
||||
// resize reflow is supressed when the only change has been to zoom
|
||||
// the document rather than to change the document's dimensions
|
||||
|
|
|
@ -4558,11 +4558,16 @@ PresShell::DoFlushPendingNotifications(mozFlushType aType,
|
|||
mFrameConstructor->ProcessPendingRestyles();
|
||||
}
|
||||
|
||||
|
||||
// There might be more pending constructors now, but we're not going to
|
||||
// worry about them. They can't be triggered during reflow, so we should
|
||||
// be good.
|
||||
|
||||
if (aType >= Flush_Layout && !mIsDestroying) {
|
||||
// Flush any pending update of the user font set, since that could
|
||||
// post a style change reflow.
|
||||
mPresContext->FlushUserFontSet();
|
||||
|
||||
mFrameConstructor->RecalcQuotesAndCounters();
|
||||
mViewManager->FlushDelayedResize();
|
||||
ProcessReflowCommands(aInterruptibleReflow);
|
||||
|
@ -4777,17 +4782,21 @@ nsIPresShell::ReconstructStyleDataInternal()
|
|||
{
|
||||
mStylesHaveChanged = PR_FALSE;
|
||||
|
||||
if (!mDidInitialReflow) {
|
||||
// Nothing to do here, since we have no frames yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDestroying) {
|
||||
// We don't want to mess with restyles at this point
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPresContext) {
|
||||
mPresContext->RebuildUserFontSet();
|
||||
}
|
||||
|
||||
nsIContent* root = mDocument->GetRootContent();
|
||||
if (!mDidInitialReflow) {
|
||||
// Nothing to do here, since we have no frames yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
// No content to restyle
|
||||
return;
|
||||
|
@ -6242,6 +6251,8 @@ PresShell::WillDoReflow()
|
|||
mCaret->UpdateCaretPosition();
|
||||
}
|
||||
|
||||
mPresContext->FlushUserFontSet();
|
||||
|
||||
mFrameConstructor->BeginUpdate();
|
||||
}
|
||||
|
||||
|
|
|
@ -2166,6 +2166,10 @@ nsCSSRuleProcessor::AppendFontFaceRules(
|
|||
nsresult
|
||||
nsCSSRuleProcessor::ClearRuleCascades()
|
||||
{
|
||||
// We rely on our caller (perhaps indirectly) to do something that
|
||||
// will rebuild style data and the user font set (either
|
||||
// nsIPresShell::ReconstructStyleData or
|
||||
// nsPresContext::RebuildAllStyleData).
|
||||
RuleCascadeData *data = mRuleCascades;
|
||||
mRuleCascades = nsnull;
|
||||
while (data) {
|
||||
|
|
|
@ -127,7 +127,12 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
|||
|
||||
nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
|
||||
if (ps) {
|
||||
// reflow async so that reflows coalesce
|
||||
// Update layout for the presence of the new font. Since this is
|
||||
// asynchronous, reflows will coalesce.
|
||||
// nsPresContext::FlushUserFontSet does the same thing when we
|
||||
// remove a user font set, for fonts becoming unavailable, or when
|
||||
// we add one, because if we change it dynamically we need to
|
||||
// trigger reflow to cause gfx to request the fonts.
|
||||
ps->StyleChangeReflow();
|
||||
LOG(("fontdownloader (%p) reflow\n", this));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче