Skip to content

Commit 5d36bcb

Browse files
committed
Added a set of possible last resort fallback font for webkit.
We now check the size against that set to make sure that we do not report the font has loaded while the font is actually loading (since webkit changes the font to a last resort fallback font and is not respecting the CSS font stack). We're also marking the font as active when reaching the timeout (instead of marking it as inactive). This is needed in the case of a web font having the same size as any font in the last resort fallback font set.
1 parent 9cebf75 commit 5d36bcb

File tree

5 files changed

+195
-98
lines changed

5 files changed

+195
-98
lines changed

src-test/core/domhelpertest.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,13 @@ DomHelperTest.prototype.testHasClassName = function() {
9191
assertFalse(this.domHelper_.hasClassName(div, 'meuh'));
9292
assertFalse(this.domHelper_.hasClassName(div, 'missingClassName'));
9393
}
94+
95+
DomHelperTest.prototype.testSetStyleString = function() {
96+
var div = this.domHelper_.createElement('div');
97+
98+
this.domHelper_.setStyle(div, 'font-family: Arial');
99+
assertTrue(div.style.cssText.indexOf('Arial') != -1);
100+
this.domHelper_.setStyle(div, "font-family: 'Times New Roman'");
101+
assertTrue(div.style.cssText.indexOf('Arial') == -1);
102+
assertTrue(div.style.cssText.indexOf("Times New Roman") != -1);
103+
};

src-test/core/fontwatchertest.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ FontWatcherTest.prototype.setUp = function() {
4949
fail('Fake getTime should not be called.');
5050
};
5151

52+
this.fakeUserAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko',
53+
'1.9.2', 'Macintosh', '10.6', undefined, true);
54+
5255
// Mock out FontWatchRunner to return active/inactive for families we give it
5356
this.originalFontWatchRunner_ = webfont.FontWatchRunner;
5457
this.fontWatchRunnerActiveFamilies_ = [];
5558
this.testStringCount_ = 0;
5659
this.testStrings_ = {};
57-
webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper,
58-
fontSizer, asyncCall, getTime, fontFamily, fontDescription, opt_fontTestString) {
60+
webfont.FontWatchRunner = function(activeCallback, inactiveCallback, userAgent,
61+
domHelper, fontSizer, asyncCall, getTime, fontFamily, fontDescription,
62+
opt_fontTestString) {
5963
if (opt_fontTestString) {
6064
self.testStringCount_++;
6165
self.testStrings_[fontFamily] = opt_fontTestString;
@@ -80,7 +84,8 @@ FontWatcherTest.prototype.testWatchOneFontNotLast = function() {
8084
var fontFamilies = [ 'fontFamily1' ];
8185
this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ];
8286

83-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
87+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
88+
this.fakeDomHelper_, this.fakeEventDispatcher_,
8489
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
8590

8691
fontWatcher.watch(fontFamilies, {}, {}, false);
@@ -94,7 +99,8 @@ FontWatcherTest.prototype.testWatchOneFontActive = function() {
9499
var fontFamilies = [ 'fontFamily1' ];
95100
this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ];
96101

97-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
102+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
103+
this.fakeDomHelper_, this.fakeEventDispatcher_,
98104
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
99105

100106
fontWatcher.watch(fontFamilies, {}, {}, true);
@@ -112,7 +118,8 @@ FontWatcherTest.prototype.testWatchOneFontInactive = function() {
112118
var fontFamilies = [ 'fontFamily1' ];
113119
this.fontWatchRunnerActiveFamilies_ = [];
114120

115-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
121+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
122+
this.fakeDomHelper_, this.fakeEventDispatcher_,
116123
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
117124

118125
fontWatcher.watch(fontFamilies, {}, {}, true);
@@ -130,7 +137,8 @@ FontWatcherTest.prototype.testWatchMultipleFontsActive = function() {
130137
var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ];
131138
this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ];
132139

133-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
140+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
141+
this.fakeDomHelper_, this.fakeEventDispatcher_,
134142
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
135143

136144
fontWatcher.watch(fontFamilies, {}, {}, true);
@@ -152,7 +160,8 @@ FontWatcherTest.prototype.testWatchMultipleFontsInactive = function() {
152160
var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ];
153161
this.fontWatchRunnerActiveFamilies_ = [];
154162

155-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
163+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
164+
this.fakeDomHelper_, this.fakeEventDispatcher_,
156165
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
157166

158167
fontWatcher.watch(fontFamilies, {}, {}, true);
@@ -174,7 +183,8 @@ FontWatcherTest.prototype.testWatchMultipleFontsMixed = function() {
174183
var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ];
175184
this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily3' ];
176185

177-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
186+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
187+
this.fakeDomHelper_, this.fakeEventDispatcher_,
178188
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
179189

180190
fontWatcher.watch(fontFamilies, {}, {}, true);
@@ -202,7 +212,8 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithDescriptions = function() {
202212
'fontFamily3': ['n4', 'i4', 'n7']
203213
};
204214

205-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
215+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
216+
this.fakeDomHelper_, this.fakeEventDispatcher_,
206217
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
207218

208219
fontWatcher.watch(fontFamilies, fontDescriptions, {}, true);
@@ -235,7 +246,8 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() {
235246
'fontFamily4': null
236247
};
237248

238-
var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_,
249+
var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_,
250+
this.fakeDomHelper_, this.fakeEventDispatcher_,
239251
this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_);
240252

241253
fontWatcher.watch(fontFamilies, {}, fontTestStrings, true);

src-test/core/fontwatchrunnertest.js

Lines changed: 98 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ FontWatchRunnerTest.prototype.setUp = function() {
1919
self.fontInactive_[fontFamily + ' ' + fontDescription] = true;
2020
};
2121

22+
this.fakeFirefoxUserAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko',
23+
'1.9.2', 'Macintosh', '10.6', undefined, true);
24+
2225
this.createElementCalled_ = 0;
2326
this.createdElements_ = [];
2427
this.insertIntoCalled_ = 0;
@@ -45,6 +48,8 @@ FontWatchRunnerTest.prototype.setUp = function() {
4548
},
4649
removeElement: function(el) {
4750
self.removeElementCalled_++;
51+
},
52+
setStyle: function(e, styleString) {
4853
}
4954
};
5055

@@ -84,17 +89,17 @@ FontWatchRunnerTest.prototype.setUp = function() {
8489
self.asyncCount_++;
8590
func();
8691
};
87-
8892
};
8993

9094
FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() {
91-
this.timesToCheckWidthsBeforeChange_ = 0;
95+
this.timesToCheckWidthsBeforeChange_ = 1;
9296
this.timesToReportChangedWidth_ = 2;
9397
this.timesToGetTimeBeforeTimeout_ = 10;
9498

9599
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
96-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
97-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_);
100+
this.fakeFirefoxUserAgent_, this.fakeDomHelper_, this.fakeFontSizer_,
101+
this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
102+
this.fontDescription_);
98103

99104
assertEquals(1, this.asyncCount_);
100105

@@ -104,15 +109,16 @@ FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() {
104109
};
105110

106111
FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() {
107-
this.timesToCheckWidthsBeforeChange_ = 3;
112+
this.timesToCheckWidthsBeforeChange_ = 2;
108113
this.timesToReportChangedWidth_ = 2;
109114
this.timesToGetTimeBeforeTimeout_ = 10;
110115

111116
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
112-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
113-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_);
117+
this.fakeFirefoxUserAgent_, this.fakeDomHelper_, this.fakeFontSizer_,
118+
this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
119+
this.fontDescription_);
114120

115-
assertEquals(4, this.asyncCount_);
121+
assertEquals(2, this.asyncCount_);
116122

117123
assertEquals(1, this.fontActiveCalled_);
118124
assertEquals(true, this.fontActive_['fontFamily1 n4']);
@@ -125,8 +131,9 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() {
125131
this.timesToGetTimeBeforeTimeout_ = 5;
126132

127133
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
128-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
129-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_);
134+
this.fakeFirefoxUserAgent_, this.fakeDomHelper_, this.fakeFontSizer_,
135+
this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
136+
this.fontDescription_);
130137

131138
assertEquals(4, this.asyncCount_);
132139

@@ -135,38 +142,15 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() {
135142
assertEquals(true, this.fontInactive_['fontFamily1 n4']);
136143
};
137144

138-
/**
139-
* This test ensures that even if the fonts change width for one cycle and
140-
* then change back, active won't be fired. This works around an issue in Webkit
141-
* browsers, where an inactive webfont will briefly change widths for one cycle
142-
* and then change back to fallback widths on the next cycle. This is apparently
143-
* due to some quirk in the way that web fonts are rendered.
144-
*/
145-
FontWatchRunnerTest.prototype.testWatchFontWithInconsistentWidthIsStillInactive = function() {
146-
this.timesToCheckWidthsBeforeChange_ = 3;
147-
// Only report a new width for one cycle, then switch back to original fallback width
148-
this.timesToReportChangedWidth_ = 1;
149-
this.timesToGetTimeBeforeTimeout_ = 10;
150-
151-
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
152-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
153-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_);
154-
155-
assertEquals(9, this.asyncCount_);
156-
157-
assertEquals(0, this.fontActiveCalled_);
158-
assertEquals(1, this.fontInactiveCalled_);
159-
assertEquals(true, this.fontInactive_['fontFamily1 n4']);
160-
};
161-
162145
FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() {
163146
this.timesToCheckWidthsBeforeChange_ = 3;
164147
this.timesToReportChangedWidth_ = 2;
165148
this.timesToGetTimeBeforeTimeout_ = 10;
166149

167150
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
168-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
169-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_);
151+
this.fakeFirefoxUserAgent_, this.fakeDomHelper_, this.fakeFontSizer_,
152+
this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
153+
this.fontDescription_);
170154

171155
assertEquals(4, this.createElementCalled_);
172156
assertEquals('span', this.createdElements_[0]['name']);
@@ -196,8 +180,9 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() {
196180
this.timesToGetTimeBeforeTimeout_ = 10;
197181

198182
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
199-
this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_,
200-
this.fakeGetTime_, this.fontFamily_, this.fontDescription_, 'testString');
183+
this.fakeFirefoxUserAgent_, this.fakeDomHelper_, this.fakeFontSizer_,
184+
this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
185+
this.fontDescription_, 'testString');
201186

202187
assertEquals(4, this.createElementCalled_);
203188
assertEquals('span', this.createdElements_[0]['name']);
@@ -218,5 +203,80 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() {
218203
assertEquals('testString', this.createdElements_[3]['innerHtml']);
219204
assertEquals(4, this.insertIntoCalled_);
220205
assertEquals(4, this.removeElementCalled_);
206+
};
207+
208+
FontWatchRunnerTest.prototype.testWatchFontWebKitBrowserIgnoreLastResort = function() {
209+
var userAgent = new webfont.UserAgent('Chrome', '16.0.912.36', 'AppleWebKit',
210+
'531.9', 'Macintosh', '10.6', undefined, true);
211+
var lastResortFontsCount = 12;
212+
var originalSizeCount = 2;
213+
var firstSize = 2;
214+
var secondSize = 2;
215+
var thirdSize = 3;
216+
217+
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
218+
userAgent, this.fakeDomHelper_, {getWidth: function() {
219+
if (lastResortFontsCount-- > 0) {
220+
return 2;
221+
}
222+
if (originalSizeCount-- > 0) {
223+
return 1;
224+
}
225+
if (firstSize-- > 0) {
226+
return 1;
227+
}
228+
if (secondSize-- > 0) {
229+
230+
return 2;
231+
}
232+
if (thirdSize-- > 0) {
233+
return 3;
234+
}
235+
}}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
236+
this.fontDescription_);
237+
238+
assertEquals(2, this.asyncCount_);
221239

240+
assertEquals(1, this.fontActiveCalled_);
241+
assertEquals(0, this.fontInactiveCalled_);
242+
assertEquals(true, this.fontActive_['fontFamily1 n4']);
243+
};
244+
245+
FontWatchRunnerTest.prototype.testWatchFontWebKitBrowserIgnoreLastResort = function() {
246+
this.timesToGetTimeBeforeTimeout_ = 3;
247+
var userAgent = new webfont.UserAgent('Chrome', '16.0.912.36', 'AppleWebKit',
248+
'531.9', 'Macintosh', '10.6', undefined, true);
249+
var lastResortFontsCount = 12;
250+
var originalSizeCount = 2;
251+
var firstSize = 2;
252+
var secondSize = 2;
253+
var thirdSize = 3;
254+
255+
new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_,
256+
userAgent, this.fakeDomHelper_, {getWidth: function() {
257+
if (lastResortFontsCount-- > 0) {
258+
return 2;
259+
}
260+
if (originalSizeCount-- > 0) {
261+
return 1;
262+
}
263+
if (firstSize-- > 0) {
264+
return 1;
265+
}
266+
if (secondSize-- > 0) {
267+
268+
return 2;
269+
}
270+
if (thirdSize-- > 0) {
271+
return 3;
272+
}
273+
}}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_,
274+
this.fontDescription_);
275+
276+
assertEquals(2, this.asyncCount_);
277+
278+
// When on webkit time out ends up activating the font.
279+
assertEquals(1, this.fontActiveCalled_);
280+
assertEquals(0, this.fontInactiveCalled_);
281+
assertEquals(true, this.fontActive_['fontFamily1 n4']);
222282
};

src/core/domhelper.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ webfont.DomHelper.prototype.createElement = function(elem, opt_attr,
2525
for (var attr in opt_attr) {
2626
// protect against native prototype augmentations
2727
if (opt_attr.hasOwnProperty(attr)) {
28-
if (attr == "style" && this.userAgent_.getName() == "MSIE") {
29-
domElement.style.cssText = opt_attr[attr];
30-
} else {
31-
domElement.setAttribute(attr, opt_attr[attr]);
32-
}
28+
if (attr == "style") {
29+
this.setStyle(domElement, opt_attr[attr]);
30+
} else {
31+
domElement.setAttribute(attr, opt_attr[attr]);
32+
}
3333
}
3434
}
3535
}
@@ -164,3 +164,16 @@ webfont.DomHelper.prototype.hasClassName = function(e, name) {
164164
}
165165
return false;
166166
};
167+
168+
/**
169+
* Sets the style attribute on an element.
170+
* @param {Element} e The element.
171+
* @param {string} styleString The style string.
172+
*/
173+
webfont.DomHelper.prototype.setStyle = function(e, styleString) {
174+
if (this.userAgent_.getName() == "MSIE") {
175+
e.style.cssText = styleString;
176+
} else {
177+
e.setAttribute("style", styleString);
178+
}
179+
};

0 commit comments

Comments
 (0)