Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsFont.h"
7 #include "gfxFont.h" // for gfxFontStyle
8 #include "gfxFontConstants.h" // for NS_FONT_KERNING_AUTO, etc
9 #include "gfxFontFeatures.h" // for gfxFontFeature, etc
10 #include "gfxFontUtils.h" // for TRUETYPE_TAG
11 #include "nsCRT.h" // for nsCRT
12 #include "nsDebug.h" // for NS_ASSERTION
13 #include "nsISupports.h"
14 #include "nsUnicharUtils.h"
15 #include "nscore.h" // for char16_t
16 #include "mozilla/ArrayUtils.h"
17 #include "mozilla/gfx/2D.h"
19 nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
20 uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
21 nscoord aSize)
22 {
23 NS_ASSERTION(aName && IsASCII(nsDependentCString(aName)),
24 "Must only pass ASCII names here");
25 name.AssignASCII(aName);
26 style = aStyle;
27 systemFont = false;
28 variant = aVariant;
29 weight = aWeight;
30 stretch = aStretch;
31 decorations = aDecoration;
32 smoothing = NS_FONT_SMOOTHING_AUTO;
33 size = aSize;
34 sizeAdjust = 0.0;
35 kerning = NS_FONT_KERNING_AUTO;
36 synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
38 variantAlternates = 0;
39 variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
40 variantEastAsian = 0;
41 variantLigatures = 0;
42 variantNumeric = 0;
43 variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
44 }
46 nsFont::nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
47 uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
48 nscoord aSize)
49 : name(aName)
50 {
51 style = aStyle;
52 systemFont = false;
53 variant = aVariant;
54 weight = aWeight;
55 stretch = aStretch;
56 decorations = aDecoration;
57 smoothing = NS_FONT_SMOOTHING_AUTO;
58 size = aSize;
59 sizeAdjust = 0.0;
60 kerning = NS_FONT_KERNING_AUTO;
61 synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
63 variantAlternates = 0;
64 variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
65 variantEastAsian = 0;
66 variantLigatures = 0;
67 variantNumeric = 0;
68 variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
69 }
71 nsFont::nsFont(const nsFont& aOther)
72 : name(aOther.name)
73 {
74 style = aOther.style;
75 systemFont = aOther.systemFont;
76 variant = aOther.variant;
77 weight = aOther.weight;
78 stretch = aOther.stretch;
79 decorations = aOther.decorations;
80 smoothing = aOther.smoothing;
81 size = aOther.size;
82 sizeAdjust = aOther.sizeAdjust;
83 kerning = aOther.kerning;
84 synthesis = aOther.synthesis;
85 fontFeatureSettings = aOther.fontFeatureSettings;
86 languageOverride = aOther.languageOverride;
87 variantAlternates = aOther.variantAlternates;
88 variantCaps = aOther.variantCaps;
89 variantEastAsian = aOther.variantEastAsian;
90 variantLigatures = aOther.variantLigatures;
91 variantNumeric = aOther.variantNumeric;
92 variantPosition = aOther.variantPosition;
93 alternateValues = aOther.alternateValues;
94 featureValueLookup = aOther.featureValueLookup;
95 }
97 nsFont::nsFont()
98 {
99 }
101 nsFont::~nsFont()
102 {
103 }
105 bool nsFont::BaseEquals(const nsFont& aOther) const
106 {
107 if ((style == aOther.style) &&
108 (systemFont == aOther.systemFont) &&
109 (weight == aOther.weight) &&
110 (stretch == aOther.stretch) &&
111 (size == aOther.size) &&
112 (sizeAdjust == aOther.sizeAdjust) &&
113 name.Equals(aOther.name, nsCaseInsensitiveStringComparator()) &&
114 (kerning == aOther.kerning) &&
115 (synthesis == aOther.synthesis) &&
116 (fontFeatureSettings == aOther.fontFeatureSettings) &&
117 (languageOverride == aOther.languageOverride) &&
118 (variantAlternates == aOther.variantAlternates) &&
119 (variantCaps == aOther.variantCaps) &&
120 (variantEastAsian == aOther.variantEastAsian) &&
121 (variantLigatures == aOther.variantLigatures) &&
122 (variantNumeric == aOther.variantNumeric) &&
123 (variantPosition == aOther.variantPosition) &&
124 (alternateValues == aOther.alternateValues) &&
125 (featureValueLookup == aOther.featureValueLookup) &&
126 (smoothing == aOther.smoothing)) {
127 return true;
128 }
129 return false;
130 }
132 bool nsFont::Equals(const nsFont& aOther) const
133 {
134 if (BaseEquals(aOther) &&
135 (variant == aOther.variant) &&
136 (decorations == aOther.decorations)) {
137 return true;
138 }
139 return false;
140 }
142 nsFont& nsFont::operator=(const nsFont& aOther)
143 {
144 name = aOther.name;
145 style = aOther.style;
146 systemFont = aOther.systemFont;
147 variant = aOther.variant;
148 weight = aOther.weight;
149 stretch = aOther.stretch;
150 decorations = aOther.decorations;
151 smoothing = aOther.smoothing;
152 size = aOther.size;
153 sizeAdjust = aOther.sizeAdjust;
154 kerning = aOther.kerning;
155 synthesis = aOther.synthesis;
156 fontFeatureSettings = aOther.fontFeatureSettings;
157 languageOverride = aOther.languageOverride;
158 variantAlternates = aOther.variantAlternates;
159 variantCaps = aOther.variantCaps;
160 variantEastAsian = aOther.variantEastAsian;
161 variantLigatures = aOther.variantLigatures;
162 variantNumeric = aOther.variantNumeric;
163 variantPosition = aOther.variantPosition;
164 alternateValues = aOther.alternateValues;
165 featureValueLookup = aOther.featureValueLookup;
166 return *this;
167 }
169 void
170 nsFont::CopyAlternates(const nsFont& aOther)
171 {
172 variantAlternates = aOther.variantAlternates;
173 alternateValues = aOther.alternateValues;
174 featureValueLookup = aOther.featureValueLookup;
175 }
177 static bool IsGenericFontFamily(const nsString& aFamily)
178 {
179 uint8_t generic;
180 nsFont::GetGenericID(aFamily, &generic);
181 return generic != kGenericFont_NONE;
182 }
184 const char16_t kSingleQuote = char16_t('\'');
185 const char16_t kDoubleQuote = char16_t('\"');
186 const char16_t kComma = char16_t(',');
188 bool nsFont::EnumerateFamilies(nsFontFamilyEnumFunc aFunc, void* aData) const
189 {
190 const char16_t *p, *p_end;
191 name.BeginReading(p);
192 name.EndReading(p_end);
193 nsAutoString family;
195 while (p < p_end) {
196 while (nsCRT::IsAsciiSpace(*p))
197 if (++p == p_end)
198 return true;
200 bool generic;
201 if (*p == kSingleQuote || *p == kDoubleQuote) {
202 // quoted font family
203 char16_t quoteMark = *p;
204 if (++p == p_end)
205 return true;
206 const char16_t *nameStart = p;
208 // XXX What about CSS character escapes?
209 while (*p != quoteMark)
210 if (++p == p_end)
211 return true;
213 family = Substring(nameStart, p);
214 generic = false;
216 while (++p != p_end && *p != kComma)
217 /* nothing */ ;
219 } else {
220 // unquoted font family
221 const char16_t *nameStart = p;
222 while (++p != p_end && *p != kComma)
223 /* nothing */ ;
225 family = Substring(nameStart, p);
226 family.CompressWhitespace(false, true);
227 generic = IsGenericFontFamily(family);
228 }
230 if (!family.IsEmpty() && !(*aFunc)(family, generic, aData))
231 return false;
233 ++p; // may advance past p_end
234 }
236 return true;
237 }
239 // mapping from bitflag to font feature tag/value pair
240 //
241 // these need to be kept in sync with the constants listed
242 // in gfxFontConstants.h (e.g. NS_FONT_VARIANT_EAST_ASIAN_JIS78)
244 // NS_FONT_VARIANT_EAST_ASIAN_xxx values
245 const gfxFontFeature eastAsianDefaults[] = {
246 { TRUETYPE_TAG('j','p','7','8'), 1 },
247 { TRUETYPE_TAG('j','p','8','3'), 1 },
248 { TRUETYPE_TAG('j','p','9','0'), 1 },
249 { TRUETYPE_TAG('j','p','0','4'), 1 },
250 { TRUETYPE_TAG('s','m','p','l'), 1 },
251 { TRUETYPE_TAG('t','r','a','d'), 1 },
252 { TRUETYPE_TAG('f','w','i','d'), 1 },
253 { TRUETYPE_TAG('p','w','i','d'), 1 },
254 { TRUETYPE_TAG('r','u','b','y'), 1 }
255 };
257 static_assert(MOZ_ARRAY_LENGTH(eastAsianDefaults) ==
258 eFeatureEastAsian_numFeatures,
259 "eFeatureEastAsian_numFeatures should be correct");
261 // NS_FONT_VARIANT_LIGATURES_xxx values
262 const gfxFontFeature ligDefaults[] = {
263 { TRUETYPE_TAG('l','i','g','a'), 0 }, // none value means all off
264 { TRUETYPE_TAG('l','i','g','a'), 1 },
265 { TRUETYPE_TAG('l','i','g','a'), 0 },
266 { TRUETYPE_TAG('d','l','i','g'), 1 },
267 { TRUETYPE_TAG('d','l','i','g'), 0 },
268 { TRUETYPE_TAG('h','l','i','g'), 1 },
269 { TRUETYPE_TAG('h','l','i','g'), 0 },
270 { TRUETYPE_TAG('c','a','l','t'), 1 },
271 { TRUETYPE_TAG('c','a','l','t'), 0 }
272 };
274 static_assert(MOZ_ARRAY_LENGTH(ligDefaults) ==
275 eFeatureLigatures_numFeatures,
276 "eFeatureLigatures_numFeatures should be correct");
278 // NS_FONT_VARIANT_NUMERIC_xxx values
279 const gfxFontFeature numericDefaults[] = {
280 { TRUETYPE_TAG('l','n','u','m'), 1 },
281 { TRUETYPE_TAG('o','n','u','m'), 1 },
282 { TRUETYPE_TAG('p','n','u','m'), 1 },
283 { TRUETYPE_TAG('t','n','u','m'), 1 },
284 { TRUETYPE_TAG('f','r','a','c'), 1 },
285 { TRUETYPE_TAG('a','f','r','c'), 1 },
286 { TRUETYPE_TAG('z','e','r','o'), 1 },
287 { TRUETYPE_TAG('o','r','d','n'), 1 }
288 };
290 static_assert(MOZ_ARRAY_LENGTH(numericDefaults) ==
291 eFeatureNumeric_numFeatures,
292 "eFeatureNumeric_numFeatures should be correct");
294 static void
295 AddFontFeaturesBitmask(uint32_t aValue, uint32_t aMin, uint32_t aMax,
296 const gfxFontFeature aFeatureDefaults[],
297 nsTArray<gfxFontFeature>& aFeaturesOut)
299 {
300 uint32_t i, m;
302 for (i = 0, m = aMin; m <= aMax; i++, m <<= 1) {
303 if (m & aValue) {
304 const gfxFontFeature& feature = aFeatureDefaults[i];
305 aFeaturesOut.AppendElement(feature);
306 }
307 }
308 }
310 void nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const
311 {
312 // add in font-variant features
313 gfxFontFeature setting;
315 // -- kerning
316 setting.mTag = TRUETYPE_TAG('k','e','r','n');
317 switch (kerning) {
318 case NS_FONT_KERNING_NONE:
319 setting.mValue = 0;
320 aStyle->featureSettings.AppendElement(setting);
321 break;
322 case NS_FONT_KERNING_NORMAL:
323 setting.mValue = 1;
324 aStyle->featureSettings.AppendElement(setting);
325 break;
326 default:
327 // auto case implies use user agent default
328 break;
329 }
331 // -- alternates
332 if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_HISTORICAL) {
333 setting.mValue = 1;
334 setting.mTag = TRUETYPE_TAG('h','i','s','t');
335 aStyle->featureSettings.AppendElement(setting);
336 }
339 // -- copy font-specific alternate info into style
340 // (this will be resolved after font-matching occurs)
341 aStyle->alternateValues.AppendElements(alternateValues);
342 aStyle->featureValueLookup = featureValueLookup;
344 // -- caps
345 setting.mValue = 1;
346 switch (variantCaps) {
347 case NS_FONT_VARIANT_CAPS_ALLSMALL:
348 setting.mTag = TRUETYPE_TAG('c','2','s','c');
349 aStyle->featureSettings.AppendElement(setting);
350 // fall through to the small-caps case
351 case NS_FONT_VARIANT_CAPS_SMALLCAPS:
352 setting.mTag = TRUETYPE_TAG('s','m','c','p');
353 aStyle->featureSettings.AppendElement(setting);
354 break;
356 case NS_FONT_VARIANT_CAPS_ALLPETITE:
357 setting.mTag = TRUETYPE_TAG('c','2','p','c');
358 aStyle->featureSettings.AppendElement(setting);
359 // fall through to the petite-caps case
360 case NS_FONT_VARIANT_CAPS_PETITECAPS:
361 setting.mTag = TRUETYPE_TAG('p','c','a','p');
362 aStyle->featureSettings.AppendElement(setting);
363 break;
365 case NS_FONT_VARIANT_CAPS_TITLING:
366 setting.mTag = TRUETYPE_TAG('t','i','t','l');
367 aStyle->featureSettings.AppendElement(setting);
368 break;
370 case NS_FONT_VARIANT_CAPS_UNICASE:
371 setting.mTag = TRUETYPE_TAG('u','n','i','c');
372 aStyle->featureSettings.AppendElement(setting);
373 break;
375 default:
376 break;
377 }
379 // -- east-asian
380 if (variantEastAsian) {
381 AddFontFeaturesBitmask(variantEastAsian,
382 NS_FONT_VARIANT_EAST_ASIAN_JIS78,
383 NS_FONT_VARIANT_EAST_ASIAN_RUBY,
384 eastAsianDefaults, aStyle->featureSettings);
385 }
387 // -- ligatures
388 if (variantLigatures) {
389 AddFontFeaturesBitmask(variantLigatures,
390 NS_FONT_VARIANT_LIGATURES_NONE,
391 NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
392 ligDefaults, aStyle->featureSettings);
394 if (variantLigatures & NS_FONT_VARIANT_LIGATURES_COMMON) {
395 // liga already enabled, need to enable clig also
396 setting.mTag = TRUETYPE_TAG('c','l','i','g');
397 setting.mValue = 1;
398 aStyle->featureSettings.AppendElement(setting);
399 } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NO_COMMON) {
400 // liga already disabled, need to disable clig also
401 setting.mTag = TRUETYPE_TAG('c','l','i','g');
402 setting.mValue = 0;
403 aStyle->featureSettings.AppendElement(setting);
404 } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NONE) {
405 // liga already disabled, need to disable dlig, hlig, calt, clig
406 setting.mValue = 0;
407 setting.mTag = TRUETYPE_TAG('d','l','i','g');
408 aStyle->featureSettings.AppendElement(setting);
409 setting.mTag = TRUETYPE_TAG('h','l','i','g');
410 aStyle->featureSettings.AppendElement(setting);
411 setting.mTag = TRUETYPE_TAG('c','a','l','t');
412 aStyle->featureSettings.AppendElement(setting);
413 setting.mTag = TRUETYPE_TAG('c','l','i','g');
414 aStyle->featureSettings.AppendElement(setting);
415 }
416 }
418 // -- numeric
419 if (variantNumeric) {
420 AddFontFeaturesBitmask(variantNumeric,
421 NS_FONT_VARIANT_NUMERIC_LINING,
422 NS_FONT_VARIANT_NUMERIC_ORDINAL,
423 numericDefaults, aStyle->featureSettings);
424 }
426 // -- position
427 setting.mTag = 0;
428 setting.mValue = 1;
429 switch (variantPosition) {
430 case NS_FONT_VARIANT_POSITION_SUPER:
431 setting.mTag = TRUETYPE_TAG('s','u','p','s');
432 aStyle->featureSettings.AppendElement(setting);
433 break;
435 case NS_FONT_VARIANT_POSITION_SUB:
436 setting.mTag = TRUETYPE_TAG('s','u','b','s');
437 aStyle->featureSettings.AppendElement(setting);
438 break;
440 default:
441 break;
442 }
444 // add in features from font-feature-settings
445 aStyle->featureSettings.AppendElements(fontFeatureSettings);
447 // enable grayscale antialiasing for text
448 if (smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
449 aStyle->useGrayscaleAntialiasing = true;
450 }
451 }
453 static bool FontEnumCallback(const nsString& aFamily, bool aGeneric, void *aData)
454 {
455 *((nsString*)aData) = aFamily;
456 return false;
457 }
459 void nsFont::GetFirstFamily(nsString& aFamily) const
460 {
461 EnumerateFamilies(FontEnumCallback, &aFamily);
462 }
464 /*static*/
465 void nsFont::GetGenericID(const nsString& aGeneric, uint8_t* aID)
466 {
467 *aID = kGenericFont_NONE;
468 if (aGeneric.LowerCaseEqualsLiteral("-moz-fixed")) *aID = kGenericFont_moz_fixed;
469 else if (aGeneric.LowerCaseEqualsLiteral("serif")) *aID = kGenericFont_serif;
470 else if (aGeneric.LowerCaseEqualsLiteral("sans-serif")) *aID = kGenericFont_sans_serif;
471 else if (aGeneric.LowerCaseEqualsLiteral("cursive")) *aID = kGenericFont_cursive;
472 else if (aGeneric.LowerCaseEqualsLiteral("fantasy")) *aID = kGenericFont_fantasy;
473 else if (aGeneric.LowerCaseEqualsLiteral("monospace")) *aID = kGenericFont_monospace;
474 }