Bug 1370734 - Part 2: stylo: Prefill default font when a single generic is set; r?heycam
MozReview-Commit-ID: LooD1QCqrct
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -84,33 +84,32 @@ using namespace mozilla::dom;
static Mutex* sServoFontMetricsLock = nullptr;
static RWLock* sServoLangFontPrefsLock = nullptr;
static
const nsFont*
-ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext, nsIAtom* aLanguage)
+ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext,
+ nsIAtom* aLanguage, uint8_t aGenericId)
{
bool needsCache = false;
const nsFont* retval;
{
AutoReadLock guard(*sServoLangFontPrefsLock);
- retval = aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
- aLanguage, &needsCache);
+ retval = aPresContext->GetDefaultFont(aGenericId, aLanguage, &needsCache);
}
if (!needsCache) {
return retval;
}
{
AutoWriteLock guard(*sServoLangFontPrefsLock);
- retval = aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
- aLanguage, nullptr);
+ retval = aPresContext->GetDefaultFont(aGenericId, aLanguage, nullptr);
}
return retval;
}
void
AssertIsMainThreadOrServoLangFontPrefsCacheLocked()
{
MOZ_ASSERT(NS_IsMainThread() || sServoLangFontPrefsLock->LockedForWritingByCurrentThread());
@@ -1156,17 +1155,18 @@ Gecko_CopyFontFamilyFrom(nsFont* dst, co
dst->fontlist = src->fontlist;
}
void
Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
const nsStyleFont* aFont, RawGeckoPresContextBorrowed aPresContext)
{
MutexAutoLock lock(*sServoFontMetricsLock);
- const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage);
+ const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+ kPresContext_DefaultVariableFont_ID);
// We have passed uninitialized memory to this function,
// initialize it. We can't simply return an nsFont because then
// we need to know its size beforehand. Servo cannot initialize nsFont
// itself, so this will do.
nsFont* system = new (aDest) nsFont(*defaultVariableFont);
MOZ_RELEASE_ASSERT(system);
@@ -2058,22 +2058,33 @@ Gecko_nsStyleFont_CopyLangFrom(nsStyleFo
{
aFont->mLanguage = aSource->mLanguage;
}
void
Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* aFont,
RawGeckoPresContextBorrowed aPresContext)
{
- const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage);
+ const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+ kPresContext_DefaultVariableFont_ID);
nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
aFont->mGenericID, defaultVariableFont);
}
void
+Gecko_nsStyleFont_PrefillDefaultForGeneric(nsStyleFont* aFont,
+ RawGeckoPresContextBorrowed aPresContext,
+ uint8_t aGenericId)
+{
+ const nsFont* defaultFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+ aGenericId);
+ aFont->mFont.fontlist = defaultFont->fontlist;
+}
+
+void
Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* aFont,
RawGeckoPresContextBorrowed aPresContext)
{
nscoord minFontSize;
bool needsCache = false;
{
AutoReadLock guard(*sServoLangFontPrefsLock);
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -511,16 +511,19 @@ void Gecko_CSSValue_SetPairList(nsCSSVal
void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
bool Gecko_PropertyId_IsPrefEnabled(nsCSSPropertyID id);
void Gecko_nsStyleFont_SetLang(nsStyleFont* font, nsIAtom* atom);
void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource);
void Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* font,
RawGeckoPresContextBorrowed pres_context);
+void Gecko_nsStyleFont_PrefillDefaultForGeneric(nsStyleFont* font,
+ RawGeckoPresContextBorrowed pres_context,
+ uint8_t generic_id);
void Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* font,
RawGeckoPresContextBorrowed pres_context);
FontSizePrefs Gecko_GetBaseSize(nsIAtom* lang);
struct GeckoFontMetrics
{
nscoord mChSize;
nscoord mXSize;
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1333,16 +1333,22 @@ extern "C" {
aSource: *const nsStyleFont);
}
extern "C" {
pub fn Gecko_nsStyleFont_FixupNoneGeneric(font: *mut nsStyleFont,
pres_context:
RawGeckoPresContextBorrowed);
}
extern "C" {
+ pub fn Gecko_nsStyleFont_PrefillDefaultForGeneric(font: *mut nsStyleFont,
+ pres_context:
+ RawGeckoPresContextBorrowed,
+ generic_id: u8);
+}
+extern "C" {
pub fn Gecko_nsStyleFont_FixupMinFontSize(font: *mut nsStyleFont,
pres_context:
RawGeckoPresContextBorrowed);
}
extern "C" {
pub fn Gecko_GetBaseSize(lang: *mut nsIAtom) -> FontSizePrefs;
}
extern "C" {
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2741,39 +2741,88 @@ pub fn apply_declarations<'a, F, I>(devi
&mut cacheable,
&mut cascade_info,
error_reporter);
}
% if category_to_cascade_now == "early":
let writing_mode = get_writing_mode(context.style.get_inheritedbox());
context.style.writing_mode = writing_mode;
+ let mut _skip_font_family = false;
+
+ % if product == "gecko":
+ // Whenever a single generic value is specified, gecko will do a bunch of
+ // recalculation walking up the rule tree, including handling the font-size stuff.
+ // It basically repopulates the font struct with the default font for a given
+ // generic and language. We handle the font-size stuff separately, so this boils
+ // down to just copying over the font-family lists (no other aspect of the default
+ // font can be configured).
+
+ if seen.contains(LonghandId::XLang) || font_family.is_some() {
+ // if just the language changed, the inherited generic is all we need
+ let mut generic = inherited_style.get_font().gecko().mGenericID;
+ if let Some(declaration) = font_family {
+ if let PropertyDeclaration::FontFamily(ref fam) = *declaration {
+ if let Some(id) = fam.single_generic() {
+ generic = id;
+ // In case of a specified font family with a single generic, we will
+ // end up setting font family below, but its value would get
+ // overwritten later in the pipeline when cascading.
+ //
+ // We instead skip cascading font-family in that case.
+ //
+ // In case of the language changing, we wish for a specified font-
+ // family to override this, so we do not skip cascading then.
+ _skip_font_family = true;
+ }
+ }
+ }
+
+ // In case of just the language changing, the parent could have had no generic,
+ // which Gecko just does regular cascading with. Do the same.
+ // This can only happen in the case where the language changed but the family did not
+ if generic != structs::kGenericFont_NONE {
+ let pres_context = context.device.pres_context;
+ let gecko_font = context.mutate_style().mutate_font().gecko_mut();
+ gecko_font.mGenericID = generic;
+ unsafe {
+ bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(gecko_font,
+ &*pres_context,
+ generic);
+ }
+ }
+ }
+ % endif
+
// It is important that font_size is computed before
// the late properties (for em units), but after font-family
// (for the base-font-size dependence for default and keyword font-sizes)
// Additionally, when we support system fonts they will have to be
// computed early, and *before* font_family, so I'm including
// font_family here preemptively instead of keeping it within
// the early properties.
//
// To avoid an extra iteration, we just pull out the property
// during the early iteration and cascade them in order
// after it.
- if let Some(declaration) = font_family {
- let discriminant = LonghandId::FontFamily as usize;
- (CASCADE_PROPERTY[discriminant])(declaration,
- inherited_style,
- default_style,
- &mut context,
- &mut cacheable,
- &mut cascade_info,
- error_reporter);
- % if product == "gecko":
- context.style.mutate_font().fixup_none_generic(context.device);
- % endif
+ if !_skip_font_family {
+ if let Some(declaration) = font_family {
+
+ let discriminant = LonghandId::FontFamily as usize;
+ (CASCADE_PROPERTY[discriminant])(declaration,
+ inherited_style,
+ default_style,
+ &mut context,
+ &mut cacheable,
+ &mut cascade_info,
+ error_reporter);
+ % if product == "gecko":
+ context.style.mutate_font().fixup_none_generic(context.device);
+ % endif
+ }
}
if let Some(declaration) = font_size {
let discriminant = LonghandId::FontSize as usize;
(CASCADE_PROPERTY[discriminant])(declaration,
inherited_style,
default_style,
&mut context,