mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 935862 p3 - implement selective reflow for downloadable fonts. r=heycam
This commit is contained in:
parent
16051fe356
commit
af0ef7b9f2
@ -66,6 +66,7 @@
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "nsFontFaceUtils.h"
|
||||
|
||||
// Needed for Start/Stop of Image Animation
|
||||
#include "imgIContainer.h"
|
||||
@ -2145,24 +2146,47 @@ nsPresContext::RebuildUserFontSet()
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::UserFontSetUpdated()
|
||||
nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont)
|
||||
{
|
||||
if (!mShell)
|
||||
return;
|
||||
|
||||
// Changes to the set of available fonts can cause updates to layout by:
|
||||
//
|
||||
// 1. Changing the font used for text, which changes anything that
|
||||
// depends on text measurement, including line breaking and
|
||||
// intrinsic widths, and any other parts of layout that depend on
|
||||
// font metrics. This requires a style change reflow to update.
|
||||
//
|
||||
// 2. Changing the value of the 'ex' and 'ch' units in style data,
|
||||
// which also depend on font metrics. Updating this information
|
||||
// requires rebuilding the rule tree from the top, avoiding the
|
||||
// reuse of cached data even when no style rules have changed.
|
||||
bool usePlatformFontList = true;
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
usePlatformFontList = false;
|
||||
#endif
|
||||
|
||||
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
|
||||
// xxx - until the Linux platform font list is always used, use full
|
||||
// restyle to force updates with gfxPangoFontGroup usage
|
||||
// Note: this method is called without a font when rules in the userfont set
|
||||
// are updated, which may occur during reflow as a result of the lazy
|
||||
// initialization of the userfont set. It would be better to avoid a full
|
||||
// restyle but until this method is only called outside of reflow, schedule a
|
||||
// full restyle in these cases.
|
||||
if (!usePlatformFontList || !aUpdatedFont) {
|
||||
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case - if either the 'ex' or 'ch' units are used, these
|
||||
// depend upon font metrics. Updating this information requires
|
||||
// rebuilding the rule tree from the top, avoiding the reuse of cached
|
||||
// data even when no style rules have changed.
|
||||
|
||||
if (UsesExChUnits()) {
|
||||
// xxx - dbaron said this should work but get ex/ch related reftest failures
|
||||
// PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_ForceDescendants);
|
||||
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate over the frame tree looking for frames associated with the
|
||||
// downloadable font family in question. If a frame's nsStyleFont has
|
||||
// the name, check the font group associated with the metrics to see if
|
||||
// it contains that specific font (i.e. the one chosen within the family
|
||||
// given the weight, width, and slant from the nsStyleFont). If it does,
|
||||
// mark that frame dirty and skip inspecting its descendants.
|
||||
nsFontFaceUtils::MarkDirtyForFontChange(mShell->GetRootFrame(), aUpdatedFont);
|
||||
}
|
||||
|
||||
FontFaceSet*
|
||||
|
@ -56,6 +56,7 @@ class nsICSSPseudoComparator;
|
||||
struct nsStyleBackground;
|
||||
struct nsStyleBorder;
|
||||
class nsIRunnable;
|
||||
class gfxUserFontEntry;
|
||||
class gfxUserFontSet;
|
||||
class gfxTextPerfMetrics;
|
||||
struct nsFontFaceRuleContainer;
|
||||
@ -890,7 +891,7 @@ public:
|
||||
// Should be called whenever the set of fonts available in the user
|
||||
// font set changes (e.g., because a new font loads, or because the
|
||||
// user font set is changed and fonts become unavailable).
|
||||
void UserFontSetUpdated();
|
||||
void UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont = nullptr);
|
||||
|
||||
gfxMissingFontRecorder *MissingFontRecorder() { return mMissingFonts; }
|
||||
void NotifyMissingFonts();
|
||||
|
@ -141,6 +141,7 @@ UNIFIED_SOURCES += [
|
||||
'nsDOMCSSRGBColor.cpp',
|
||||
'nsDOMCSSValueList.cpp',
|
||||
'nsFontFaceLoader.cpp',
|
||||
'nsFontFaceUtils.cpp',
|
||||
'nsHTMLCSSStyleSheet.cpp',
|
||||
'nsHTMLStyleSheet.cpp',
|
||||
'nsLayoutStylesheetCache.cpp',
|
||||
|
@ -121,7 +121,7 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
NS_ASSERTION(ctx, "userfontset doesn't have a presContext?");
|
||||
if (ctx) {
|
||||
loader->mFontFaceSet->IncrementGeneration();
|
||||
ctx->UserFontSetUpdated();
|
||||
ctx->UserFontSetUpdated(loader->GetUserFontEntry());
|
||||
LOG(("userfonts (%p) timeout reflow\n", loader));
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,7 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
if (fontUpdate) {
|
||||
// Update layout for the presence of the new font. Since this is
|
||||
// asynchronous, reflows will coalesce.
|
||||
ctx->UserFontSetUpdated();
|
||||
ctx->UserFontSetUpdated(mUserFontEntry);
|
||||
LOG(("userfonts (%p) reflow\n", this));
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
|
||||
nsIURI* aTargetURI,
|
||||
nsISupports* aContext);
|
||||
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
|
||||
|
||||
protected:
|
||||
virtual ~nsFontFaceLoader();
|
||||
|
116
layout/style/nsFontFaceUtils.cpp
Normal file
116
layout/style/nsFontFaceUtils.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:ts=2:et:sw=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 "gfxUserFontSet.h"
|
||||
#include "nsFontFaceUtils.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
static bool StyleContextContainsFont(nsStyleContext* aStyleContext,
|
||||
const gfxUserFontSet* aUserFontSet,
|
||||
const gfxUserFontEntry* aFont)
|
||||
{
|
||||
// if the font is null, simply check to see whether fontlist includes
|
||||
// downloadable fonts
|
||||
if (!aFont) {
|
||||
const FontFamilyList& fontlist =
|
||||
aStyleContext->StyleFont()->mFont.fontlist;
|
||||
return aUserFontSet->ContainsUserFontSetFonts(fontlist);
|
||||
}
|
||||
|
||||
// first, check if the family name is in the fontlist
|
||||
const nsString& familyName = aFont->FamilyName();
|
||||
if (!aStyleContext->StyleFont()->mFont.fontlist.Contains(familyName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// family name is in the fontlist, check to see if the font group
|
||||
// associated with the frame includes the specific userfont
|
||||
nsRefPtr<nsFontMetrics> fm;
|
||||
nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext,
|
||||
getter_AddRefs(fm),
|
||||
1.0f);
|
||||
|
||||
if (fm->GetThebesFontGroup()->ContainsUserFont(aFont)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
FrameUsesFont(nsIFrame* aFrame, const gfxUserFontEntry* aFont)
|
||||
{
|
||||
// check the style context of the frame
|
||||
gfxUserFontSet* ufs = aFrame->PresContext()->GetUserFontSet();
|
||||
if (StyleContextContainsFont(aFrame->StyleContext(), ufs, aFont)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check additional style contexts
|
||||
int32_t contextIndex = 0;
|
||||
for (nsStyleContext* extraContext;
|
||||
(extraContext = aFrame->GetAdditionalStyleContext(contextIndex));
|
||||
++contextIndex) {
|
||||
if (StyleContextContainsFont(extraContext, ufs, aFont)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
|
||||
const gfxUserFontEntry* aFont)
|
||||
{
|
||||
nsAutoTArray<nsIFrame*, 4> subtrees;
|
||||
subtrees.AppendElement(aSubtreeRoot);
|
||||
|
||||
nsIPresShell* ps = aSubtreeRoot->PresContext()->PresShell();
|
||||
|
||||
// check descendants, iterating over subtrees that may include
|
||||
// additional subtrees associated with placeholders
|
||||
do {
|
||||
nsIFrame* subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
|
||||
subtrees.RemoveElementAt(subtrees.Length() - 1);
|
||||
|
||||
// Check all descendants to see if they use the font
|
||||
nsAutoTArray<nsIFrame*, 32> stack;
|
||||
stack.AppendElement(subtreeRoot);
|
||||
|
||||
do {
|
||||
nsIFrame* f = stack.ElementAt(stack.Length() - 1);
|
||||
stack.RemoveElementAt(stack.Length() - 1);
|
||||
|
||||
// if this frame uses the font, mark its descendants dirty
|
||||
// and skip checking its children
|
||||
if (FrameUsesFont(f, aFont)) {
|
||||
ps->FrameNeedsReflow(f, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
||||
} else {
|
||||
if (f->GetType() == nsGkAtoms::placeholderFrame) {
|
||||
nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
|
||||
if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
|
||||
// We have another distinct subtree we need to mark.
|
||||
subtrees.AppendElement(oof);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame::ChildListIterator lists(f);
|
||||
for (; !lists.IsDone(); lists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame* kid = childFrames.get();
|
||||
stack.AppendElement(kid);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!stack.IsEmpty());
|
||||
} while (!subtrees.IsEmpty());
|
||||
}
|
23
layout/style/nsFontFaceUtils.h
Normal file
23
layout/style/nsFontFaceUtils.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:ts=2:et:sw=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/. */
|
||||
|
||||
/* helper utilities for working with downloadable fonts */
|
||||
|
||||
#ifndef nsFontFaceUtils_h_
|
||||
#define nsFontFaceUtils_h_
|
||||
|
||||
class gfxUserFontEntry;
|
||||
class nsIFrame;
|
||||
|
||||
class nsFontFaceUtils
|
||||
{
|
||||
public:
|
||||
// mark dirty frames affected by a downloadable font
|
||||
static void MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
|
||||
const gfxUserFontEntry* aFont);
|
||||
};
|
||||
|
||||
#endif /* !defined(nsFontFaceUtils_h_) */
|
Loading…
Reference in New Issue
Block a user