1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/StaticPresData.h"
8 
9 #include "mozilla/Preferences.h"
10 #include "mozilla/ServoBindings.h"
11 #include "nsPresContext.h"
12 namespace mozilla {
13 
14 static StaticPresData* sSingleton = nullptr;
15 
Init()16 void StaticPresData::Init() {
17   MOZ_ASSERT(!sSingleton);
18   sSingleton = new StaticPresData();
19 }
20 
Shutdown()21 void StaticPresData::Shutdown() {
22   MOZ_ASSERT(sSingleton);
23   delete sSingleton;
24   sSingleton = nullptr;
25 }
26 
Get()27 StaticPresData* StaticPresData::Get() {
28   MOZ_ASSERT(sSingleton);
29   return sSingleton;
30 }
31 
StaticPresData()32 StaticPresData::StaticPresData() {
33   mLangService = nsLanguageAtomService::GetService();
34 
35   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] =
36       nsPresContext::CSSPixelsToAppUnits(1);
37   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] =
38       nsPresContext::CSSPixelsToAppUnits(3);
39   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] =
40       nsPresContext::CSSPixelsToAppUnits(5);
41 }
42 
43 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
44   _pref.Assign(_s0);                        \
45   _pref.Append(_s1);
46 
47 static const char* const kGenericFont[] = {
48     ".variable.",  ".fixed.",   ".serif.",  ".sans-serif.",
49     ".monospace.", ".cursive.", ".fantasy."};
50 
51 // These are private, use the list in nsFont.h if you want a public list.
52 enum {
53   eDefaultFont_Variable,
54   eDefaultFont_Fixed,
55   eDefaultFont_Serif,
56   eDefaultFont_SansSerif,
57   eDefaultFont_Monospace,
58   eDefaultFont_Cursive,
59   eDefaultFont_Fantasy,
60   eDefaultFont_COUNT
61 };
62 
Initialize(nsAtom * aLangGroupAtom)63 void LangGroupFontPrefs::Initialize(nsAtom* aLangGroupAtom) {
64   mLangGroup = aLangGroupAtom;
65 
66   /* Fetch the font prefs to be used -- see bug 61883 for details.
67      Not all prefs are needed upfront. Some are fallback prefs intended
68      for the GFX font sub-system...
69 
70   -- attributes for generic fonts --------------------------------------
71   font.default.[langGroup] = serif | sans-serif - fallback generic font
72   font.name.[generic].[langGroup] = current user' selected font on the pref
73   dialog font.name-list.[generic].[langGroup] = fontname1, fontname2, ...
74   [factory pre-built list] font.size.[generic].[langGroup] = integer - settable
75   by the user font.size-adjust.[generic].[langGroup] = "float" - settable by the
76   user font.minimum-size.[langGroup] = integer - settable by the user
77   */
78 
79   nsAutoCString langGroup;
80   aLangGroupAtom->ToUTF8String(langGroup);
81 
82   mDefaultVariableFont.size = nsPresContext::CSSPixelsToAppUnits(16);
83   mDefaultFixedFont.size = nsPresContext::CSSPixelsToAppUnits(13);
84 
85   nsAutoCString pref;
86 
87   // get font.minimum-size.[langGroup]
88 
89   MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
90 
91   int32_t size = Preferences::GetInt(pref.get());
92   mMinimumFontSize = nsPresContext::CSSPixelsToAppUnits(size);
93 
94   nsFont* fontTypes[] = {&mDefaultVariableFont,  &mDefaultFixedFont,
95                          &mDefaultSerifFont,     &mDefaultSansSerifFont,
96                          &mDefaultMonospaceFont, &mDefaultCursiveFont,
97                          &mDefaultFantasyFont};
98   static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
99                 "FontTypes array count is not correct");
100 
101   // Get attributes specific to each generic font. We do not get the user's
102   // generic-font-name-to-specific-family-name preferences because its the
103   // generic name that should be fed into the cascade. It is up to the GFX
104   // code to look up the font prefs to convert generic names to specific
105   // family names as necessary.
106   nsAutoCString generic_dot_langGroup;
107   for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
108     generic_dot_langGroup.Assign(kGenericFont[eType]);
109     generic_dot_langGroup.Append(langGroup);
110 
111     nsFont* font = fontTypes[eType];
112 
113     // set the default variable font (the other fonts are seen as 'generic'
114     // fonts in GFX and will be queried there when hunting for alternative
115     // fonts)
116     if (eType == eDefaultFont_Variable) {
117       // XXX "font.name.variable."?  There is no such pref...
118       MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
119 
120       nsAutoString value;
121       Preferences::GetString(pref.get(), value);
122       if (!value.IsEmpty()) {
123         FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
124         FontFamilyType defaultType = defaultVariableName.mType;
125         NS_ASSERTION(
126             defaultType == eFamily_serif || defaultType == eFamily_sans_serif,
127             "default type must be serif or sans-serif");
128         mDefaultVariableFont.fontlist = FontFamilyList();
129         mDefaultVariableFont.fontlist.SetDefaultFontType(defaultType);
130         // We create mDefaultVariableFont.fontlist with defaultType as the
131         // fallback font, and not as part of the font list proper. This way,
132         // it can be overwritten should there be a language change.
133       } else {
134         MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
135         Preferences::GetString(pref.get(), value);
136         if (!value.IsEmpty()) {
137           FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
138           FontFamilyType defaultType = defaultVariableName.mType;
139           NS_ASSERTION(
140               defaultType == eFamily_serif || defaultType == eFamily_sans_serif,
141               "default type must be serif or sans-serif");
142           mDefaultVariableFont.fontlist = FontFamilyList();
143           mDefaultVariableFont.fontlist.SetDefaultFontType(defaultType);
144           // We create mDefaultVariableFont.fontlist with defaultType as the
145           // (fallback) font, and not as part of the font list proper. This way,
146           // it can be overwritten should there be a language change.
147         }
148       }
149     } else {
150       if (eType == eDefaultFont_Monospace) {
151         // This takes care of the confusion whereby people often expect
152         // "monospace" to have the same default font-size as "-moz-fixed" (this
153         // tentative size may be overwritten with the specific value for
154         // "monospace" when "font.size.monospace.[langGroup]" is read -- see
155         // below)
156         mDefaultMonospaceFont.size = mDefaultFixedFont.size;
157       } else if (eType != eDefaultFont_Fixed) {
158         // all the other generic fonts are initialized with the size of the
159         // variable font, but their specific size can supersede later -- see
160         // below
161         font->size = mDefaultVariableFont.size;
162       }
163     }
164 
165     // Bug 84398: for spec purists, a different font-size only applies to the
166     // .variable. and .fixed. fonts and the other fonts should get
167     // |font-size-adjust|. The problem is that only GfxWin has the support for
168     // |font-size-adjust|. So for parity, we enable the ability to set a
169     // different font-size on all platforms.
170 
171     // get font.size.[generic].[langGroup]
172     // size=0 means 'Auto', i.e., generic fonts retain the size of the variable
173     // font
174     MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
175     size = Preferences::GetInt(pref.get());
176     if (size > 0) {
177       font->size = nsPresContext::CSSPixelsToAppUnits(size);
178     }
179 
180     // get font.size-adjust.[generic].[langGroup]
181     // XXX only applicable on GFX ports that handle |font-size-adjust|
182     MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
183     nsAutoCString cvalue;
184     Preferences::GetCString(pref.get(), cvalue);
185     if (!cvalue.IsEmpty()) {
186       font->sizeAdjust = (float)atof(cvalue.get());
187     }
188 
189 #ifdef DEBUG_rbs
190     printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
191            generic_dot_langGroup.get(), NS_ConvertUTF16toUTF8(font->name).get(),
192            font->size, font->sizeAdjust);
193 #endif
194   }
195 }
196 
GetLangGroup(nsAtom * aLanguage,bool * aNeedsToCache) const197 nsAtom* StaticPresData::GetLangGroup(nsAtom* aLanguage,
198                                      bool* aNeedsToCache) const {
199   nsAtom* langGroupAtom = nullptr;
200   langGroupAtom = mLangService->GetLanguageGroup(aLanguage, aNeedsToCache);
201   if (!langGroupAtom) {
202     langGroupAtom = nsGkAtoms::x_western;  // Assume x-western is safe...
203   }
204   return langGroupAtom;
205 }
206 
GetUncachedLangGroup(nsAtom * aLanguage) const207 already_AddRefed<nsAtom> StaticPresData::GetUncachedLangGroup(
208     nsAtom* aLanguage) const {
209   RefPtr<nsAtom> langGroupAtom =
210       mLangService->GetUncachedLanguageGroup(aLanguage);
211   if (!langGroupAtom) {
212     langGroupAtom = nsGkAtoms::x_western;  // Assume x-western is safe...
213   }
214   return langGroupAtom.forget();
215 }
216 
GetFontPrefsForLangHelper(nsAtom * aLanguage,const LangGroupFontPrefs * aPrefs,bool * aNeedsToCache) const217 const LangGroupFontPrefs* StaticPresData::GetFontPrefsForLangHelper(
218     nsAtom* aLanguage, const LangGroupFontPrefs* aPrefs,
219     bool* aNeedsToCache) const {
220   // Get language group for aLanguage:
221   MOZ_ASSERT(aLanguage);
222   MOZ_ASSERT(mLangService);
223   MOZ_ASSERT(aPrefs);
224 
225   nsAtom* langGroupAtom = GetLangGroup(aLanguage, aNeedsToCache);
226 
227   if (aNeedsToCache && *aNeedsToCache) {
228     return nullptr;
229   }
230 
231   LangGroupFontPrefs* prefs = const_cast<LangGroupFontPrefs*>(aPrefs);
232   if (prefs->mLangGroup) {  // if initialized
233     DebugOnly<uint32_t> count = 0;
234     for (;;) {
235       NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
236       if (prefs->mLangGroup == langGroupAtom) {
237         return prefs;
238       }
239       if (!prefs->mNext) {
240         break;
241       }
242       prefs = prefs->mNext;
243     }
244     if (aNeedsToCache) {
245       *aNeedsToCache = true;
246       return nullptr;
247     }
248     AssertIsMainThreadOrServoLangFontPrefsCacheLocked();
249     // nothing cached, so go on and fetch the prefs for this lang group:
250     prefs = prefs->mNext = new LangGroupFontPrefs;
251   }
252 
253   if (aNeedsToCache) {
254     *aNeedsToCache = true;
255     return nullptr;
256   }
257 
258   AssertIsMainThreadOrServoLangFontPrefsCacheLocked();
259   prefs->Initialize(langGroupAtom);
260 
261   return prefs;
262 }
263 
GetDefaultFontHelper(uint8_t aFontID,nsAtom * aLanguage,const LangGroupFontPrefs * aPrefs) const264 const nsFont* StaticPresData::GetDefaultFontHelper(
265     uint8_t aFontID, nsAtom* aLanguage,
266     const LangGroupFontPrefs* aPrefs) const {
267   MOZ_ASSERT(aLanguage);
268   MOZ_ASSERT(aPrefs);
269 
270   const nsFont* font;
271   switch (aFontID) {
272     // Special (our default variable width font and fixed width font)
273     case kPresContext_DefaultVariableFont_ID:
274       font = &aPrefs->mDefaultVariableFont;
275       break;
276     case kPresContext_DefaultFixedFont_ID:
277       font = &aPrefs->mDefaultFixedFont;
278       break;
279     // CSS
280     case kGenericFont_serif:
281       font = &aPrefs->mDefaultSerifFont;
282       break;
283     case kGenericFont_sans_serif:
284       font = &aPrefs->mDefaultSansSerifFont;
285       break;
286     case kGenericFont_monospace:
287       font = &aPrefs->mDefaultMonospaceFont;
288       break;
289     case kGenericFont_cursive:
290       font = &aPrefs->mDefaultCursiveFont;
291       break;
292     case kGenericFont_fantasy:
293       font = &aPrefs->mDefaultFantasyFont;
294       break;
295     default:
296       font = nullptr;
297       NS_ERROR("invalid arg");
298       break;
299   }
300   return font;
301 }
302 
303 }  // namespace mozilla
304