From d059cd483456787788b7f5d38b0ae7683b75cb80 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 7 Nov 2012 12:43:15 +0100 Subject: [PATCH 01/66] Removed the test for the webkit font fallback bug in favour of a better approximation of the actual behaviour. --- src-test/core/fontwatchrunnertest.js | 37 ++-------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 1e100812..807d773f 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -49,14 +49,13 @@ FontWatchRunnerTest.prototype.setUp = function() { }; this.timesToCheckWidthsBeforeChange_ = 0; - this.timesToReportChangedWidth_ = 2; this.fakeFontSizer_ = { getWidth: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) != -1) { // This is a font stack with fontFamily included (not just fallbacks) - if (self.timesToCheckWidthsBeforeChange_ <= 0 && self.timesToReportChangedWidth_ > 0) { + if (self.timesToCheckWidthsBeforeChange_ <= 0) { // Decrement by 0.5 because we're checking two separate font stacks each iteration - self.timesToReportChangedWidth_ -= 0.5; + self.timesToCheckWidthsBeforeChange_ -= 0.5; return 2; } else { // Decrement by 0.5 because we're checking two separate font stacks each iteration @@ -89,7 +88,6 @@ FontWatchRunnerTest.prototype.setUp = function() { FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() { this.timesToCheckWidthsBeforeChange_ = 0; - this.timesToReportChangedWidth_ = 2; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -108,7 +106,6 @@ FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() { FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { this.timesToCheckWidthsBeforeChange_ = 3; - this.timesToReportChangedWidth_ = 2; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -127,7 +124,6 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { this.timesToCheckWidthsBeforeChange_ = 10; - this.timesToReportChangedWidth_ = 2; this.timesToGetTimeBeforeTimeout_ = 5; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -144,36 +140,8 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { assertEquals(true, this.fontInactive_['fontFamily1 n4']); }; -/** - * This test ensures that even if the fonts change width for one cycle and - * then change back, active won't be fired. This works around an issue in Webkit - * browsers, where an inactive webfont will briefly change widths for one cycle - * and then change back to fallback widths on the next cycle. This is apparently - * due to some quirk in the way that web fonts are rendered. - */ -FontWatchRunnerTest.prototype.testWatchFontWithInconsistentWidthIsStillInactive = function() { - this.timesToCheckWidthsBeforeChange_ = 3; - // Only report a new width for one cycle, then switch back to original fallback width - this.timesToReportChangedWidth_ = 1; - this.timesToGetTimeBeforeTimeout_ = 10; - - var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, - this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, - this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); - - fontWatchRunner.start(); - - assertEquals(9, this.asyncCount_); - - assertEquals(0, this.fontActiveCalled_); - assertEquals(1, this.fontInactiveCalled_); - assertEquals(true, this.fontInactive_['fontFamily1 n4']); -}; - FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckWidthsBeforeChange_ = 3; - this.timesToReportChangedWidth_ = 2; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -206,7 +174,6 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { this.timesToCheckWidthsBeforeChange_ = 3; - this.timesToReportChangedWidth_ = 2; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, From c282155ef51503e3aa2d8160c69bf4bffa5ef4dc Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 7 Nov 2012 12:48:39 +0100 Subject: [PATCH 02/66] Added an accurate model of the broken way webkit used to handle fallback fonts while loading webfonts. Also added two new tests that test for the case where a font is parsed and applied quickly and slowly (where the slow one currently fails.) --- src-test/core/fontwatchrunnertest.js | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 807d773f..46c66c27 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -68,6 +68,35 @@ FontWatchRunnerTest.prototype.setUp = function() { } }; + /** + * This accurately models the way webkit used to handle + * fallback fonts while loading web fonts. Even though + * this Webkit bug is now patched, we still have a large + * portion of our users using old webkit builds. + * + * See: https://bugs.webkit.org/show_bug.cgi?id=76684 + */ + this.timesToDelayChangedWidthWebkit_ = 1; + this.fakeWebkitFontSizer_ = { + getWidth: function(el) { + if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { + if (self.timesToDelayChangedWidthWebkit_ > 0) { + self.timesToDelayChangedWidthWebkit_ -= 0.5; + // Return the incorrect width for a certain number of cycles. + // The actual number depends on how fast or how slow the font + // is parsed and applied. + return 2; + } else { + // Return the correct width + return 1; + } + } else { + // Return the default width + return 1; + } + } + }; + this.timesToGetTimeBeforeTimeout_ = 10; this.fakeGetTime_ = function() { if (self.timesToGetTimeBeforeTimeout_ <= 0) { @@ -140,6 +169,38 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { assertEquals(true, this.fontInactive_['fontFamily1 n4']); }; +FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedWidthWebkit_ = 1; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_); + + fontWatchRunner.start(); + + assertEquals(9, this.asyncCount_); + assertEquals(1, this.fontInactiveCalled_); + assertEquals(true, this.fontInactive_['fontFamily1 n4']); +}; + +FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedWidthWebkit_ = 2; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_); + + fontWatchRunner.start(); + + assertEquals(9, this.asyncCount_); + assertEquals(1, this.fontInactiveCalled_); + assertEquals(true, this.fontInactive_['fontFamily1 n4']); +}; + FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckWidthsBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; From 6e8bbc33370cdb7f125ce76a74d56a0f50d1ab5a Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 7 Nov 2012 14:57:09 +0100 Subject: [PATCH 03/66] Changed FontWatchRunner to take an extra argument indicating the presence of the Webkit fallback bug. Changed the check_ method to do the correct thing if the bug is present. Updated the tests accordingly. --- src-test/core/fontwatchrunnertest.js | 30 +++++++++++++------------- src/core/fontwatcher.js | 2 +- src/core/fontwatchrunner.js | 32 ++++++++++++++-------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 46c66c27..6abe7390 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -122,11 +122,11 @@ FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(1, this.asyncCount_); + assertEquals(0, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); @@ -140,11 +140,11 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(4, this.asyncCount_); + assertEquals(3, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); @@ -158,7 +158,7 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); @@ -176,13 +176,13 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, true); fontWatchRunner.start(); - assertEquals(9, this.asyncCount_); - assertEquals(1, this.fontInactiveCalled_); - assertEquals(true, this.fontInactive_['fontFamily1 n4']); + assertEquals(1, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); }; FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { @@ -192,13 +192,13 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, true); fontWatchRunner.start(); - assertEquals(9, this.asyncCount_); - assertEquals(1, this.fontInactiveCalled_); - assertEquals(true, this.fontInactive_['fontFamily1 n4']); + assertEquals(2, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); }; FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { @@ -208,7 +208,7 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); @@ -240,7 +240,7 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_, 'testString'); + this.fontDescription_, false, 'testString'); fontWatchRunner.start(); diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index d8c28bba..367295ad 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -68,7 +68,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, fontTestString); + this.getTime_, fontFamily, fontDescription, false, fontTestString); fontWatchRunner.start(); } diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 016de10a..bafcda07 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -8,10 +8,11 @@ * @param {function(): number} getTime * @param {string} fontFamily * @param {string} fontDescription + * @param {boolean} hasWebkitFallbackBug * @param {string=} opt_fontTestString */ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString) { this.activeCallback_ = activeCallback; this.inactiveCallback_ = inactiveCallback; this.domHelper_ = domHelper; @@ -23,12 +24,12 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontFamily_ = fontFamily; this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; - this.originalSizeA_ = this.getDefaultFontSize_( + this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; + this.lastObservedSizeA_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_A); - this.originalSizeB_ = this.getDefaultFontSize_( + this.lastObservedSizeB_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_B); - this.lastObservedSizeA_ = this.originalSizeA_; - this.lastObservedSizeB_ = this.originalSizeB_; + this.widthChangeCount_ = 0; this.requestedFontA_ = this.createHiddenElementWithFont_( webfont.FontWatchRunner.DEFAULT_FONTS_A); this.requestedFontB_ = this.createHiddenElementWithFont_( @@ -80,26 +81,25 @@ webfont.FontWatchRunner.prototype.start = function() { * callback. If we wait more than 5 seconds and nothing has changed, we finish * with the inactive callback. * - * Because of an odd Webkit quirk, we wait to observe the new width twice - * in a row before finishing with the active callback. Sometimes, Webkit will - * render the spans with a changed width for one iteration even though the font - * is broken. This only happens for one async loop, so waiting for 2 consistent - * measurements allows us to work around the quirk. - * * @private */ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.fontSizer_.getWidth(this.requestedFontA_); var sizeB = this.fontSizer_.getWidth(this.requestedFontB_); - if ((this.originalSizeA_ != sizeA || this.originalSizeB_ != sizeB) && - this.lastObservedSizeA_ == sizeA && this.lastObservedSizeB_ == sizeB) { - this.finish_(this.activeCallback_); + if (this.lastObservedSizeA_ != sizeA || this.lastObservedSizeB_ != sizeB) { + if ((this.hasWebkitFallbackBug_ && this.widthChangeCount_ === 1) || + (!this.hasWebkitFallbackBug_ && this.widthChangeCount_ === 0)) { + this.finish_(this.activeCallback_); + } else { + this.lastObservedSizeA_ = sizeA; + this.lastObservedSizeB_ = sizeB; + this.widthChangeCount_ += 1; + this.asyncCheck_(); + } } else if (this.getTime_() - this.started_ >= 5000) { this.finish_(this.inactiveCallback_); } else { - this.lastObservedSizeA_ = sizeA; - this.lastObservedSizeB_ = sizeB; this.asyncCheck_(); } }; From 9fca6e7576422152e46308356bc0e83915233cba Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 7 Nov 2012 16:16:11 +0100 Subject: [PATCH 04/66] Fixed formatting. --- src-test/core/fontwatchrunnertest.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 6abe7390..24efb156 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -81,14 +81,14 @@ FontWatchRunnerTest.prototype.setUp = function() { getWidth: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { if (self.timesToDelayChangedWidthWebkit_ > 0) { - self.timesToDelayChangedWidthWebkit_ -= 0.5; - // Return the incorrect width for a certain number of cycles. - // The actual number depends on how fast or how slow the font - // is parsed and applied. - return 2; + self.timesToDelayChangedWidthWebkit_ -= 0.5; + // Return the incorrect width for a certain number of cycles. + // The actual number depends on how fast or how slow the font + // is parsed and applied. + return 2; } else { - // Return the correct width - return 1; + // Return the correct width + return 1; } } else { // Return the default width From b33738676811d41ba7624c936b44de6b33a83d88 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 7 Nov 2012 16:18:03 +0100 Subject: [PATCH 05/66] Added test for when the fallback font and the loaded font have the same metrics. --- src-test/core/fontwatchrunnertest.js | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 24efb156..762a1df6 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -97,6 +97,24 @@ FontWatchRunnerTest.prototype.setUp = function() { } }; + this.fakeWebkitFontSizerWithEqualMetrics_ = { + getWidth: function(el) { + if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { + if (self.timesToDelayChangedWidthWebkit_ > 0) { + return 2; + } else { + // This time the fallback font picked by Webkit has the + // same metrics as the font being loaded. This is a rare + // case but we should be able to handle it. + return 2; + } + } else { + // Return the default width + return 1; + } + } + }; + this.timesToGetTimeBeforeTimeout_ = 10; this.fakeGetTime_ = function() { if (self.timesToGetTimeBeforeTimeout_ <= 0) { @@ -201,6 +219,21 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { assertEquals(true, this.fontActive_['fontFamily1 n4']); }; +FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedWidthWebkit_ = 2; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerWithEqualMetrics_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true); + + fontWatchRunner.start(); + assertEquals(2, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); +}; + FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckWidthsBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; From 9b294c36304fa696ad63056d7144125f9f837dd6 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 11:52:07 +0100 Subject: [PATCH 06/66] Fixed type annotations on core/fontwatcher. --- src/core/fontwatcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 367295ad..38108c41 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -35,7 +35,7 @@ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; * function(string, string), webfont.DomHelper, * Object., * function(function(), number=), function(): number, string, string, - * string=)} fontWatchRunnerCtor The font watch runner constructor. + * boolean, string=)} fontWatchRunnerCtor The font watch runner constructor. * @param {boolean} last True if this is the last set of families to watch. */ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, From bb209f91ced899a11449826bdf40a3686202db35 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 11:55:01 +0100 Subject: [PATCH 07/66] Changed the fontwatchrunner to test both width and height of the test elements. --- src-test/core/fontwatchertest.js | 6 +- src-test/core/fontwatchrunnertest.js | 83 ++++++++++++++++++---------- src/core/font.js | 7 ++- src/core/fontwatchrunner.js | 20 ++++--- 4 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index dd035722..503d5de6 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -36,8 +36,8 @@ FontWatcherTest.prototype.setUp = function() { }; this.fakeFontSizer_ = { - getWidth: function() { - fail('Fake getWidth should not be called.'); + getSize: function() { + fail('Fake getSize should not be called.'); } }; @@ -55,7 +55,7 @@ FontWatcherTest.prototype.setUp = function() { this.testStringCount_ = 0; this.testStrings_ = {}; webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString) { if (opt_fontTestString) { self.testStringCount_++; self.testStrings_[fontFamily] = opt_fontTestString; diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 762a1df6..e84cb442 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -48,22 +48,31 @@ FontWatchRunnerTest.prototype.setUp = function() { } }; - this.timesToCheckWidthsBeforeChange_ = 0; + this.timesToCheckSizesBeforeChange_ = 0; this.fakeFontSizer_ = { - getWidth: function(el) { + getSize: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) != -1) { // This is a font stack with fontFamily included (not just fallbacks) - if (self.timesToCheckWidthsBeforeChange_ <= 0) { + if (self.timesToCheckSizesBeforeChange_ <= 0) { // Decrement by 0.5 because we're checking two separate font stacks each iteration - self.timesToCheckWidthsBeforeChange_ -= 0.5; - return 2; + self.timesToCheckSizesBeforeChange_ -= 0.5; + return { + width: 2, + height: 2 + }; } else { // Decrement by 0.5 because we're checking two separate font stacks each iteration - self.timesToCheckWidthsBeforeChange_ -= 0.5; - return 1; + self.timesToCheckSizesBeforeChange_ -= 0.5; + return { + width: 1, + height: 1 + }; } } else { - return 1; + return { + width: 1, + height: 1 + }; } } }; @@ -76,41 +85,59 @@ FontWatchRunnerTest.prototype.setUp = function() { * * See: https://bugs.webkit.org/show_bug.cgi?id=76684 */ - this.timesToDelayChangedWidthWebkit_ = 1; + this.timesToDelayChangedSizeWebkit_ = 1; this.fakeWebkitFontSizer_ = { - getWidth: function(el) { + getSize: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { - if (self.timesToDelayChangedWidthWebkit_ > 0) { - self.timesToDelayChangedWidthWebkit_ -= 0.5; + if (self.timesToDelayChangedSizeWebkit_ > 0) { + self.timesToDelayChangedSizeWebkit_ -= 0.5; // Return the incorrect width for a certain number of cycles. // The actual number depends on how fast or how slow the font // is parsed and applied. - return 2; + return { + width: 2, + height: 2 + }; } else { // Return the correct width - return 1; + return { + width: 1, + height: 1 + }; } } else { // Return the default width - return 1; + return { + width: 1, + height: 1 + }; } } }; this.fakeWebkitFontSizerWithEqualMetrics_ = { - getWidth: function(el) { + getSize: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { - if (self.timesToDelayChangedWidthWebkit_ > 0) { - return 2; + if (self.timesToDelayChangedSizeWebkit_ > 0) { + return { + width: 2, + height: 2 + }; } else { // This time the fallback font picked by Webkit has the // same metrics as the font being loaded. This is a rare // case but we should be able to handle it. - return 2; + return { + width: 2, + height: 2 + }; } } else { // Return the default width - return 1; + return { + width: 1, + height: 1 + }; } } }; @@ -134,7 +161,7 @@ FontWatchRunnerTest.prototype.setUp = function() { }; FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() { - this.timesToCheckWidthsBeforeChange_ = 0; + this.timesToCheckSizesBeforeChange_ = 0; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -152,7 +179,7 @@ FontWatchRunnerTest.prototype.testWatchFontAlreadyLoaded = function() { }; FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { - this.timesToCheckWidthsBeforeChange_ = 3; + this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -170,7 +197,7 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { }; FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { - this.timesToCheckWidthsBeforeChange_ = 10; + this.timesToCheckSizesBeforeChange_ = 10; this.timesToGetTimeBeforeTimeout_ = 5; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -189,7 +216,7 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { this.timesToGetTimeBeforeTimeout_ = 10; - this.timesToDelayChangedWidthWebkit_ = 1; + this.timesToDelayChangedSizeWebkit_ = 1; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, @@ -205,7 +232,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { this.timesToGetTimeBeforeTimeout_ = 10; - this.timesToDelayChangedWidthWebkit_ = 2; + this.timesToDelayChangedSizeWebkit_ = 2; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, @@ -221,7 +248,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { this.timesToGetTimeBeforeTimeout_ = 10; - this.timesToDelayChangedWidthWebkit_ = 2; + this.timesToDelayChangedSizeWebkit_ = 2; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerWithEqualMetrics_, @@ -235,7 +262,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { }; FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { - this.timesToCheckWidthsBeforeChange_ = 3; + this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, @@ -267,7 +294,7 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { }; FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { - this.timesToCheckWidthsBeforeChange_ = 3; + this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, diff --git a/src/core/font.js b/src/core/font.js index fc01c6ee..e35c920e 100644 --- a/src/core/font.js +++ b/src/core/font.js @@ -73,8 +73,11 @@ webfont.WebFont.prototype.load_ = function(eventDispatcher, configuration) { var fontWatcher = new webfont.FontWatcher(this.domHelper_, eventDispatcher, { - getWidth: function(elem) { - return elem.offsetWidth; + getSize: function(elem) { + return { + width: elem.offsetWidth, + height: elem.offsetHeight + }; }}, self.asyncCall_, function() { return new Date().getTime(); }); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index bafcda07..eeea63da 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -3,7 +3,7 @@ * @param {function(string, string)} activeCallback * @param {function(string, string)} inactiveCallback * @param {webfont.DomHelper} domHelper - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime * @param {string} fontFamily @@ -29,7 +29,7 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, webfont.FontWatchRunner.DEFAULT_FONTS_A); this.lastObservedSizeB_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_B); - this.widthChangeCount_ = 0; + this.sizeChangeCount_ = 0; this.requestedFontA_ = this.createHiddenElementWithFont_( webfont.FontWatchRunner.DEFAULT_FONTS_A); this.requestedFontB_ = this.createHiddenElementWithFont_( @@ -84,17 +84,18 @@ webfont.FontWatchRunner.prototype.start = function() { * @private */ webfont.FontWatchRunner.prototype.check_ = function() { - var sizeA = this.fontSizer_.getWidth(this.requestedFontA_); - var sizeB = this.fontSizer_.getWidth(this.requestedFontB_); + var sizeA = this.fontSizer_.getSize(this.requestedFontA_); + var sizeB = this.fontSizer_.getSize(this.requestedFontB_); - if (this.lastObservedSizeA_ != sizeA || this.lastObservedSizeB_ != sizeB) { - if ((this.hasWebkitFallbackBug_ && this.widthChangeCount_ === 1) || - (!this.hasWebkitFallbackBug_ && this.widthChangeCount_ === 0)) { + if (this.lastObservedSizeA_.width != sizeA.width || this.lastObservedSizeB_.width != sizeB.width || + this.lastObservedSizeA_.height != sizeB.height || this.lastObservedSizeB_.height != sizeB.height) { + if ((this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 1) || + (!this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 0)) { this.finish_(this.activeCallback_); } else { this.lastObservedSizeA_ = sizeA; this.lastObservedSizeB_ = sizeB; - this.widthChangeCount_ += 1; + this.sizeChangeCount_ += 1; this.asyncCheck_(); } } else if (this.getTime_() - this.started_ >= 5000) { @@ -128,10 +129,11 @@ webfont.FontWatchRunner.prototype.finish_ = function(callback) { /** * @private * @param {string} defaultFonts + * @return {{width: number, height: number}} */ webfont.FontWatchRunner.prototype.getDefaultFontSize_ = function(defaultFonts) { var defaultFont = this.createHiddenElementWithFont_(defaultFonts, true); - var size = this.fontSizer_.getWidth(defaultFont); + var size = this.fontSizer_.getSize(defaultFont); this.domHelper_.removeElement(defaultFont); return size; From 2e27db4373ec0f76c4daf2c723e566ad8908451e Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 11:56:34 +0100 Subject: [PATCH 08/66] Patched up the Google lastresortwebkitfontwatchrunner to match the changes to core. This patch does not change its functionality. --- .../lastresortwebkitfontwatchrunnertest.js | 87 ++++++++++++++----- src/google/lastresortwebkitfontwatchrunner.js | 33 +++---- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src-test/google/lastresortwebkitfontwatchrunnertest.js b/src-test/google/lastresortwebkitfontwatchrunnertest.js index fd4547e4..d0e5a7c4 100644 --- a/src-test/google/lastresortwebkitfontwatchrunnertest.js +++ b/src-test/google/lastresortwebkitfontwatchrunnertest.js @@ -81,29 +81,44 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontIgnored = var fontWatchRunner = new webfont.LastResortWebKitFontWatchRunner( this.activeCallback_, this.inactiveCallback_, - this.fakeDomHelper_, {getWidth: function() { + this.fakeDomHelper_, {getSize: function() { if (originalSizeCount > 0) { originalSizeCount--; - return 1; + return { + width: 1, + height: 1 + }; } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return 2; + return { + width: 2, + height: 2 + }; } if (firstSize > 0) { firstSize--; - return 1; + return { + width: 1, + height: 1 + }; } if (secondSize > 0) { secondSize--; - return 2; + return { + width: 2, + height: 2 + }; } if (thirdSize > 0) { thirdSize--; - return 3; + return { + width: 3, + height: 3 + }; } }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); @@ -127,22 +142,34 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontActiveWhenSizeMa var fontWatchRunner = new webfont.LastResortWebKitFontWatchRunner( this.activeCallback_, this.inactiveCallback_, - this.fakeDomHelper_, {getWidth: function() { + this.fakeDomHelper_, {getSize: function() { if (originalSizeCount > 0) { originalSizeCount--; - return 1; + return { + width: 1, + height: 1 + }; } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return 2; + return { + width: 2, + height: 2 + }; } if (firstSize > 0) { firstSize--; - return 1; + return { + width: 1, + height: 1 + }; } - return 2; + return { + width: 2, + height: 2 + }; }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); @@ -165,33 +192,51 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontInactiveWhenSize var fontWatchRunner = new webfont.LastResortWebKitFontWatchRunner( this.activeCallback_, this.inactiveCallback_, - this.fakeDomHelper_, {getWidth: function(elem) { + this.fakeDomHelper_, {getSize: function(elem) { if (originalSizeCount > 0) { originalSizeCount--; - return 1; + return { + width: 1, + height: 1 + }; } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return 2; + return { + width: 2, + height: 2 + }; } if (firstSize > 0) { firstSize--; - return 1; + return { + width: 1, + height: 1 + }; } if (secondSize > 0) { secondSize--; - return 2; + return { + width: 2, + height: 2 + }; } if (thirdSize == 2) { thirdSize--; - return 2; + return { + width: 2, + height: 2 + }; } if (thirdSize == 1) { thirdSize--; - return 4; + return { + width: 4, + height: 4 + }; } }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_); + this.fontDescription_, false); fontWatchRunner.start(); diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index a0c6d2b6..8a257792 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -3,20 +3,21 @@ * @param {function(string, string)} activeCallback * @param {function(string, string)} inactiveCallback * @param {webfont.DomHelper} domHelper - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime * @param {string} fontFamily * @param {string} fontDescription + * @param {boolean} hasWebkitFallbackBug * @param {string=} opt_fontTestString * @extends webfont.FontWatchRunner */ webfont.LastResortWebKitFontWatchRunner = function(activeCallback, inactiveCallback, domHelper, fontSizer, asyncCall, getTime, fontFamily, - fontDescription, opt_fontTestString) { + fontDescription, hasWebkitFallbackBug, opt_fontTestString) { webfont.LastResortWebKitFontWatchRunner.superCtor_.call(this, activeCallback, inactiveCallback, domHelper, fontSizer, asyncCall, - getTime, fontFamily, fontDescription, opt_fontTestString); + getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString); this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_(); this.webKitLastResortSizeChange_ = false; }; @@ -43,19 +44,19 @@ webfont.LastResortWebKitFontWatchRunner.prototype var webKitLastResortFontSizes = {}; var element = this.createHiddenElementWithFont_(lastResortFonts[0], true); - webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true; + webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; for (var i = 1; i < lastResortFontSizes; i++) { var font = lastResortFonts[i]; this.domHelper_.setStyle(element, this.computeStyleString_(font, this.fontDescription_, true)); - webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true; + webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; // Another WebKit quirk if the normal weight/style is loaded first, // the size of the normal weight is returned when loading another weight. if (this.fontDescription_[1] != '4') { this.domHelper_.setStyle(element, this.computeStyleString_(font, this.fontDescription_[0] + '4', true)); - webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true; + webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; } } this.domHelper_.removeElement(element); @@ -63,18 +64,18 @@ webfont.LastResortWebKitFontWatchRunner.prototype }; webfont.LastResortWebKitFontWatchRunner.prototype.check_ = function() { - var sizeA = this.fontSizer_.getWidth(this.requestedFontA_); - var sizeB = this.fontSizer_.getWidth(this.requestedFontB_); + var sizeA = this.fontSizer_.getSize(this.requestedFontA_); + var sizeB = this.fontSizer_.getSize(this.requestedFontB_); - if (!this.webKitLastResortSizeChange_ && sizeA == sizeB && - this.webKitLastResortFontSizes_[sizeA]) { + if (!this.webKitLastResortSizeChange_ && sizeA.width == sizeB.width && + this.webKitLastResortFontSizes_[sizeA.width]) { this.webKitLastResortFontSizes_ = {}; - this.webKitLastResortFontSizes_[sizeA] = true; + this.webKitLastResortFontSizes_[sizeA.width] = true; this.webKitLastResortSizeChange_ = true; } - if ((this.originalSizeA_ != sizeA || this.originalSizeB_ != sizeB) && - (!this.webKitLastResortFontSizes_[sizeA] && - !this.webKitLastResortFontSizes_[sizeB])) { + if ((this.lastObservedSizeA_.width != sizeA.width || this.lastObservedSizeB_.width != sizeB.width) && + (!this.webKitLastResortFontSizes_[sizeA.width] && + !this.webKitLastResortFontSizes_[sizeB.width])) { this.finish_(this.activeCallback_); } else if (this.getTime_() - this.started_ >= 5000) { @@ -82,8 +83,8 @@ webfont.LastResortWebKitFontWatchRunner.prototype.check_ = function() { // default browser font on a webkit browser, mark the font as active // after 5 seconds if the latest 2 sizes are in webKitLastResortFontSizes_ // and the font name is known to be metrics compatible. - if (this.webKitLastResortFontSizes_[sizeA] - && this.webKitLastResortFontSizes_[sizeB] && + if (this.webKitLastResortFontSizes_[sizeA.width] + && this.webKitLastResortFontSizes_[sizeB.width] && webfont.LastResortWebKitFontWatchRunner.METRICS_COMPATIBLE_FONTS[ this.fontFamily_]) { this.finish_(this.activeCallback_); From 58e03c9ffb4f3349fb169390733189926a2c08b7 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 14:05:09 +0100 Subject: [PATCH 09/66] Added two tests for checking both the width and height when monitoring metric changes. --- src-test/core/fontwatchrunnertest.js | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index e84cb442..3d2d5e23 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -77,6 +77,31 @@ FontWatchRunnerTest.prototype.setUp = function() { } }; + this.fakeFontSizerWithDifferentHeight_ = { + getSize: function(el) { + if (el.style.fontFamily.indexOf(self.fontFamily_) != -1) { + if (self.timesToCheckSizesBeforeChange_ <= 0) { + self.timesToCheckSizesBeforeChange_ -= 0.5; + return { + width: 1, + height: 2 + }; + } else { + self.timesToCheckSizesBeforeChange_ -= 0.5; + return { + width: 1, + height: 1 + }; + } + } else { + return { + width: 1, + height: 1 + }; + } + } + }; + /** * This accurately models the way webkit used to handle * fallback fonts while loading web fonts. Even though @@ -119,6 +144,7 @@ FontWatchRunnerTest.prototype.setUp = function() { getSize: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { if (self.timesToDelayChangedSizeWebkit_ > 0) { + self.timesToDelayChangedSizeWebkit_ -= 0.5; return { width: 2, height: 2 @@ -142,6 +168,32 @@ FontWatchRunnerTest.prototype.setUp = function() { } }; + this.fakeWebkitFontSizeWithDifferentMetrics_ = { + getSize: function(el) { + if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { + if (self.timesToDelayChangedSizeWebkit_ > 0) { + self.timesToDelayChangedSizeWebkit_ -= 0.5; + return { + width: 2, + height: 2 + }; + } else { + // Even though the width is the same, the height + // is different, so this should trigger the active event. + return { + width: 2, + height: 3 + }; + } + } else { + return { + width: 1, + height: 1 + }; + } + } + }; + this.timesToGetTimeBeforeTimeout_ = 10; this.fakeGetTime_ = function() { if (self.timesToGetTimeBeforeTimeout_ <= 0) { @@ -196,6 +248,24 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActive = function() { assertEquals(0, this.fontInactiveCalled_); }; +FontWatchRunnerTest.prototype.testWatchFontWaitForLoadActiveWithDifferentHeight = function() { + this.timesToCheckSizesBeforeChange_ = 3; + this.timesToGetTimeBeforeTimeout_ = 10; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizerWithDifferentHeight_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, false); + + fontWatchRunner.start(); + + assertEquals(3, this.asyncCount_); + + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); + assertEquals(0, this.fontInactiveCalled_); +}; + FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { this.timesToCheckSizesBeforeChange_ = 10; this.timesToGetTimeBeforeTimeout_ = 5; @@ -261,6 +331,22 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { assertEquals(true, this.fontActive_['fontFamily1 n4']); }; +FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedSizeWebkit_ = 2; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizeWithDifferentMetrics_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true); + + fontWatchRunner.start(); + + assertEquals(2, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); +}; + FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; From 2dcd25701d158e4875d77036983c41d40534fabc Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 14:13:18 +0100 Subject: [PATCH 10/66] Changed the behaviour of the timeout when the Webkit bug is present. If the timeout happens, and we are running in a webkit browser with the bug and we observed at least one size change, we assume the font has loaded and has identical metrics to the last resort font. In this case we fire the active event instead of the inactive event. --- src-test/core/fontwatchrunnertest.js | 2 +- src/core/fontwatchrunner.js | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 3d2d5e23..3f23de0e 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -326,7 +326,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { this.fontDescription_, true); fontWatchRunner.start(); - assertEquals(2, this.asyncCount_); + assertEquals(10, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index eeea63da..06079806 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -99,7 +99,15 @@ webfont.FontWatchRunner.prototype.check_ = function() { this.asyncCheck_(); } } else if (this.getTime_() - this.started_ >= 5000) { - this.finish_(this.inactiveCallback_); + if (this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 1) { + // If we reach the timeout and we are in a Webkit browser with the + // fallback and we observed at least one size change, hope for the + // best and assume that the font has loaded and has identical font + // metrics compared to the browser's last resort font. + this.finish_(this.activeCallback_); + } else { + this.finish_(this.inactiveCallback_); + } } else { this.asyncCheck_(); } From 3351efcc3b8b6cc843d08ae5892251c648c2ab37 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 15:38:30 +0100 Subject: [PATCH 11/66] Added a test for detecting the Webkit fallback bug where it does not respect the font stack while loading webfonts. --- src-test/core/fonttest.js | 3 ++- src-test/core/fontwatchertest.js | 10 ++++++++ src/core/fontwatcher.js | 44 +++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src-test/core/fonttest.js b/src-test/core/fonttest.js index bf6a5712..4b54f06f 100644 --- a/src-test/core/fonttest.js +++ b/src-test/core/fonttest.js @@ -10,7 +10,8 @@ FontTest.prototype.setUp = function() { return document.createElement(name); }, insertInto: function() {}, - removeElement: function() {} + removeElement: function() {}, + setStyle: function() {} }; this.fontModuleLoader_ = new webfont.FontModuleLoader(); }; diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 503d5de6..5a368a97 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -35,6 +35,16 @@ FontWatcherTest.prototype.setUp = function() { } }; + this.fakeDomHelper_ = { + createElement: function(name, attrs, innerHtml) { + var element = document.createElement(name); + return element; + }, + insertInto: function() {}, + removeElement: function() {}, + setStyle: function() {} + }; + this.fakeFontSizer_ = { getSize: function() { fail('Fake getSize should not be called.'); diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 38108c41..da3335c5 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -14,6 +14,7 @@ webfont.FontWatcher = function(domHelper, eventDispatcher, fontSizer, this.asyncCall_ = asyncCall; this.getTime_ = getTime; this.currentlyWatched_ = 0; + this.hasBug_ = this.hasFallbackBug_(); this.last_ = false; this.success_ = false; }; @@ -24,6 +25,47 @@ webfont.FontWatcher = function(domHelper, eventDispatcher, fontSizer, */ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; +/** + * @param {string} fontFamily + * @return {string} + * @private + */ +webfont.FontWatcher.prototype.createTestStyle_ = function(fontFamily) { + return "position:absolute;top:-999px;left:-999px;" + + "font-size:300px;width:auto;height:auto;" + + "line-height:normal;margin:0;padding:0;" + + "font-variant:normal;font-family:" + fontFamily + ";"; +}; + +/** + * Returns true if this browser has a bug that causes the font stack + * to not be respected while loading webfonts. + * + * @return {boolean} + * @private + */ +webfont.FontWatcher.prototype.hasFallbackBug_ = function() { + var font = this.domHelper_.createElement('style', null, + "@font-face{" + + "font-family:'__test__';" + + "src:url(data:application/x-font-woff;base64,) format('woff')," + + "url(data:font/truetype;base64,) format('truetype');" + + "}"), + el = this.domHelper_.createElement('div', { + style: this.createTestStyle_('monospace') + }, 'iii'); + + this.domHelper_.insertInto('body', el); + this.domHelper_.insertInto('head', font); + var beforeWidth = el.offsetWidth; + this.domHelper_.setStyle(el, this.createTestStyle_("'__test__', monospace, sans-serif")); + var hasBug = beforeWidth !== el.offsetWidth; + this.domHelper_.removeElement(el); + this.domHelper_.removeElement(font); + + return hasBug; +}; + /** * Watches a set of font families. * @param {Array.} fontFamilies The font family names to watch. @@ -68,7 +110,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, false, fontTestString); + this.getTime_, fontFamily, fontDescription, this.hasBug_, fontTestString); fontWatchRunner.start(); } From 56ebd353f8f06da67aab7fa23a3129ce4a166aa7 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 20:40:43 +0100 Subject: [PATCH 12/66] Renamed the null-font from __test__ to __webfontloader_test__ so it is a bit more obvious what it does. --- src/core/fontwatcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index da3335c5..c362ae91 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -47,7 +47,7 @@ webfont.FontWatcher.prototype.createTestStyle_ = function(fontFamily) { webfont.FontWatcher.prototype.hasFallbackBug_ = function() { var font = this.domHelper_.createElement('style', null, "@font-face{" + - "font-family:'__test__';" + + "font-family:'__webfontloader_test__';" + "src:url(data:application/x-font-woff;base64,) format('woff')," + "url(data:font/truetype;base64,) format('truetype');" + "}"), @@ -58,7 +58,7 @@ webfont.FontWatcher.prototype.hasFallbackBug_ = function() { this.domHelper_.insertInto('body', el); this.domHelper_.insertInto('head', font); var beforeWidth = el.offsetWidth; - this.domHelper_.setStyle(el, this.createTestStyle_("'__test__', monospace, sans-serif")); + this.domHelper_.setStyle(el, this.createTestStyle_("'__webfontloader_test__', monospace, sans-serif")); var hasBug = beforeWidth !== el.offsetWidth; this.domHelper_.removeElement(el); this.domHelper_.removeElement(font); From b5a10554d0996ff9d78598c29edbbebc7b334405 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 13 Nov 2012 21:21:26 +0100 Subject: [PATCH 13/66] Only test for the Webkit fallback bug when the user is using Webkit. --- src-test/core/fontwatchertest.js | 18 ++++++++++-------- src/core/font.js | 2 +- src/core/fontwatcher.js | 5 +++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 5a368a97..3a77dc2f 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -45,6 +45,8 @@ FontWatcherTest.prototype.setUp = function() { setStyle: function() {} }; + this.fakeUserAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); + this.fakeFontSizer_ = { getSize: function() { fail('Fake getSize should not be called.'); @@ -94,7 +96,7 @@ FontWatcherTest.prototype.testWatchOneFontNotLast = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, false); @@ -108,7 +110,7 @@ FontWatcherTest.prototype.testWatchOneFontActive = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -126,7 +128,7 @@ FontWatcherTest.prototype.testWatchOneFontInactive = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = []; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -144,7 +146,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsActive = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -166,7 +168,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsInactive = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = []; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -188,7 +190,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsMixed = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily3' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -216,7 +218,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithDescriptions = function() { 'fontFamily3': ['n4', 'i4', 'n7'] }; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, fontDescriptions, {}, webfont.FontWatchRunner, true); @@ -249,7 +251,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { 'fontFamily4': null }; - var fontWatcher = new webfont.FontWatcher(this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, fontTestStrings, webfont.FontWatchRunner, diff --git a/src/core/font.js b/src/core/font.js index e35c920e..6a0c2a40 100644 --- a/src/core/font.js +++ b/src/core/font.js @@ -71,7 +71,7 @@ webfont.WebFont.prototype.load_ = function(eventDispatcher, configuration) { this.moduleFailedLoading_ = this.moduleLoading_ = modules.length; - var fontWatcher = new webfont.FontWatcher(this.domHelper_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.domHelper_, eventDispatcher, { getSize: function(elem) { return { diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index c362ae91..593fee4b 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -1,12 +1,13 @@ /** * @constructor + * @param {webfont.UserAgent} userAgent * @param {webfont.DomHelper} domHelper * @param {webfont.EventDispatcher} eventDispatcher * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime */ -webfont.FontWatcher = function(domHelper, eventDispatcher, fontSizer, +webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, asyncCall, getTime) { this.domHelper_ = domHelper; this.eventDispatcher_ = eventDispatcher; @@ -14,7 +15,7 @@ webfont.FontWatcher = function(domHelper, eventDispatcher, fontSizer, this.asyncCall_ = asyncCall; this.getTime_ = getTime; this.currentlyWatched_ = 0; - this.hasBug_ = this.hasFallbackBug_(); + this.hasBug_ = userAgent.getEngine() === 'AppleWebKit' ? this.hasFallbackBug_() : false; this.last_ = false; this.success_ = false; }; From 3db8e8ac0842a026d440e81108363fa3637cbf06 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 14 Nov 2012 13:40:03 +0100 Subject: [PATCH 14/66] Refactored the font measurements so that we do not have duplicated CSS strings. --- src-test/core/fontwatchrunnertest.js | 18 ++++- src/core/fontruler.js | 69 +++++++++++++++++++ src/core/fontwatcher.js | 31 +++------ src/core/fontwatchrunner.js | 55 ++++----------- src/google/lastresortwebkitfontwatchrunner.js | 21 +++--- src/modules.yml | 1 + 6 files changed, 115 insertions(+), 80 deletions(-) create mode 100644 src/core/fontruler.js diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 3f23de0e..b0ebbcf0 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -26,14 +26,14 @@ FontWatchRunnerTest.prototype.setUp = function() { this.fakeDomHelper_ = { createElement: function(name, attrs, innerHtml) { self.createElementCalled_++; + var element = document.createElement(name); self.createdElements_.push({ 'name': name, 'attrs': attrs, - 'innerHtml': innerHtml + 'innerHtml': innerHtml, + 'element': element }); - var element = document.createElement(name); - for (var attr in attrs) { element.setAttribute(attr, attrs[attr]); } @@ -45,6 +45,18 @@ FontWatchRunnerTest.prototype.setUp = function() { }, removeElement: function(el) { self.removeElementCalled_++; + }, + setStyle: function(el, style) { + el.setAttribute('style', style); + for (var i = 0; i < self.createdElements_.length; i += 1) { + if (self.createdElements_[i].element === el) { + if (!self.createdElements_[i].attrs) { + self.createdElements_[i].attrs = {}; + } + self.createdElements_[i].attrs.style = style; + break; + } + } } }; diff --git a/src/core/fontruler.js b/src/core/fontruler.js new file mode 100644 index 00000000..14915422 --- /dev/null +++ b/src/core/fontruler.js @@ -0,0 +1,69 @@ +/** + * An element that can be used to measure the metrics + * of a given font and string. + * @constructor + * @param {webfont.DomHelper} domHelper + * @param {Object.} fontSizer + * @param {string} fontFamily + * @param {string} fontDescription + * @param {string} fontTestString + */ +webfont.FontRuler = function(domHelper, fontSizer, fontFamily, fontDescription, fontTestString) { + this.domHelper_ = domHelper; + this.fontSizer_ = fontSizer; + this.fontFamily_ = fontFamily; + this.fontDescription_ = fontDescription; + this.fontTestString_ = fontTestString; + this.nameHelper_ = new webfont.CssFontFamilyName(); + this.fvd_ = new webfont.FontVariationDescription(); + this.el_ = this.create_(); + this.setFont(fontFamily, fontDescription); +}; + +/** + * @param {string} fontFamily + * @param {string} fontDescription + */ +webfont.FontRuler.prototype.setFont = function(fontFamily, fontDescription) { + var styleString = this.computeStyleString_(fontFamily, fontDescription); + this.domHelper_.setStyle(this.el_, styleString); +}; + +/** + * @private + * @return {Element} + */ +webfont.FontRuler.prototype.create_ = function() { + var span = this.domHelper_.createElement('span', {}, this.fontTestString_); + this.domHelper_.insertInto('body', span); + return span; +}; + +/** + * @private + * @param {string} fontFamily + * @param {string} fontDescription + * @return {string} + */ +webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, fontDescription) { + var variationCss = this.fvd_.expand(fontDescription); + var styleString = "position:absolute;top:-999px;left:-999px;" + + "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" + + "padding:0;font-variant:normal;font-family:" + + this.nameHelper_.quote(fontFamily) + ";" + variationCss; + return styleString; +}; + +/** + * @return {{width: number, height: number}} + */ +webfont.FontRuler.prototype.getSize = function() { + return this.fontSizer_.getSize(this.el_); +}; + +/** + * Removes the ruler element from the DOM. + */ +webfont.FontRuler.prototype.remove = function() { + this.domHelper_.removeElement(this.el_); +}; diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 593fee4b..ff55fbcb 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -26,18 +26,6 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, */ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; -/** - * @param {string} fontFamily - * @return {string} - * @private - */ -webfont.FontWatcher.prototype.createTestStyle_ = function(fontFamily) { - return "position:absolute;top:-999px;left:-999px;" + - "font-size:300px;width:auto;height:auto;" + - "line-height:normal;margin:0;padding:0;" + - "font-variant:normal;font-family:" + fontFamily + ";"; -}; - /** * Returns true if this browser has a bug that causes the font stack * to not be respected while loading webfonts. @@ -52,19 +40,16 @@ webfont.FontWatcher.prototype.hasFallbackBug_ = function() { "src:url(data:application/x-font-woff;base64,) format('woff')," + "url(data:font/truetype;base64,) format('truetype');" + "}"), - el = this.domHelper_.createElement('div', { - style: this.createTestStyle_('monospace') - }, 'iii'); + ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'monospace', '', 'iii'); - this.domHelper_.insertInto('body', el); - this.domHelper_.insertInto('head', font); - var beforeWidth = el.offsetWidth; - this.domHelper_.setStyle(el, this.createTestStyle_("'__webfontloader_test__', monospace, sans-serif")); - var hasBug = beforeWidth !== el.offsetWidth; - this.domHelper_.removeElement(el); - this.domHelper_.removeElement(font); + this.domHelper_.insertInto('head', font); + var beforeWidth = ruler.getSize().width; + ruler.setFont("'__webfontloader_test__', monospace, sans-serif", ''); + var hasBug = beforeWidth !== ruler.getSize().width; + this.domHelper_.removeElement(font); + ruler.remove(); - return hasBug; + return hasBug; }; /** diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 06079806..5bb014e8 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -19,8 +19,6 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontSizer_ = fontSizer; this.asyncCall_ = asyncCall; this.getTime_ = getTime; - this.nameHelper_ = new webfont.CssFontFamilyName(); - this.fvd_ = new webfont.FontVariationDescription(); this.fontFamily_ = fontFamily; this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; @@ -30,10 +28,12 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.lastObservedSizeB_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_B); this.sizeChangeCount_ = 0; - this.requestedFontA_ = this.createHiddenElementWithFont_( - webfont.FontWatchRunner.DEFAULT_FONTS_A); - this.requestedFontB_ = this.createHiddenElementWithFont_( - webfont.FontWatchRunner.DEFAULT_FONTS_B); + this.requestedFontA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, + this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, + this.fontDescription_, this.fontTestString_); + this.requestedFontB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, + this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, + this.fontDescription_, this.fontTestString_); }; /** @@ -84,8 +84,8 @@ webfont.FontWatchRunner.prototype.start = function() { * @private */ webfont.FontWatchRunner.prototype.check_ = function() { - var sizeA = this.fontSizer_.getSize(this.requestedFontA_); - var sizeB = this.fontSizer_.getSize(this.requestedFontB_); + var sizeA = this.requestedFontA_.getSize(); + var sizeB = this.requestedFontB_.getSize(); if (this.lastObservedSizeA_.width != sizeA.width || this.lastObservedSizeB_.width != sizeB.width || this.lastObservedSizeA_.height != sizeB.height || this.lastObservedSizeB_.height != sizeB.height) { @@ -129,8 +129,8 @@ webfont.FontWatchRunner.prototype.asyncCheck_ = function() { * @param {function(string, string)} callback */ webfont.FontWatchRunner.prototype.finish_ = function(callback) { - this.domHelper_.removeElement(this.requestedFontA_); - this.domHelper_.removeElement(this.requestedFontB_); + this.requestedFontA_.remove(); + this.requestedFontB_.remove(); callback(this.fontFamily_, this.fontDescription_); }; @@ -140,37 +140,8 @@ webfont.FontWatchRunner.prototype.finish_ = function(callback) { * @return {{width: number, height: number}} */ webfont.FontWatchRunner.prototype.getDefaultFontSize_ = function(defaultFonts) { - var defaultFont = this.createHiddenElementWithFont_(defaultFonts, true); - var size = this.fontSizer_.getSize(defaultFont); - - this.domHelper_.removeElement(defaultFont); + var defaultFont = new webfont.FontRuler(this.domHelper_, this.fontSizer_, defaultFonts, this.fontDescription_, this.fontTestString_); + var size = defaultFont.getSize(); + defaultFont.remove(); return size; }; - -/** - * @private - * @param {string} defaultFonts - * @param {boolean=} opt_withoutFontFamily - */ -webfont.FontWatchRunner.prototype.createHiddenElementWithFont_ = function( - defaultFonts, opt_withoutFontFamily) { - var styleString = this.computeStyleString_(defaultFonts, - this.fontDescription_, opt_withoutFontFamily); - var span = this.domHelper_.createElement('span', { 'style': styleString }, - this.fontTestString_); - - this.domHelper_.insertInto('body', span); - return span; -}; - -webfont.FontWatchRunner.prototype.computeStyleString_ = function(defaultFonts, - fontDescription, opt_withoutFontFamily) { - var variationCss = this.fvd_.expand(fontDescription); - var styleString = "position:absolute;top:-999px;left:-999px;" + - "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" + - "padding:0;font-variant:normal;font-family:" - + (opt_withoutFontFamily ? "" : - this.nameHelper_.quote(this.fontFamily_) + ",") - + defaultFonts + ";" + variationCss; - return styleString; -}; diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index 8a257792..078249c3 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -42,30 +42,27 @@ webfont.LastResortWebKitFontWatchRunner.prototype var lastResortFonts = ['Times New Roman', 'Arial', 'Times', 'Sans', 'Serif']; var lastResortFontSizes = lastResortFonts.length; var webKitLastResortFontSizes = {}; - var element = this.createHiddenElementWithFont_(lastResortFonts[0], true); - - webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; + var fontRuler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, lastResortFonts[0], this.fontDescription_, this.fontTestString_); + webKitLastResortFontSizes[fontRuler.getSize().width] = true; for (var i = 1; i < lastResortFontSizes; i++) { var font = lastResortFonts[i]; - this.domHelper_.setStyle(element, this.computeStyleString_(font, - this.fontDescription_, true)); - webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; + fontRuler.setFont(font, this.fontDescription_); + webKitLastResortFontSizes[fontRuler.getSize().width] = true; // Another WebKit quirk if the normal weight/style is loaded first, // the size of the normal weight is returned when loading another weight. if (this.fontDescription_[1] != '4') { - this.domHelper_.setStyle(element, this.computeStyleString_(font, - this.fontDescription_[0] + '4', true)); - webKitLastResortFontSizes[this.fontSizer_.getSize(element).width] = true; + fontRuler.setFont(font, this.fontDescription_[0] + '4'); + webKitLastResortFontSizes[fontRuler.getSize().width] = true; } } - this.domHelper_.removeElement(element); + fontRuler.remove(); return webKitLastResortFontSizes; }; webfont.LastResortWebKitFontWatchRunner.prototype.check_ = function() { - var sizeA = this.fontSizer_.getSize(this.requestedFontA_); - var sizeB = this.fontSizer_.getSize(this.requestedFontB_); + var sizeA = this.requestedFontA_.getSize(); + var sizeB = this.requestedFontB_.getSize(); if (!this.webKitLastResortSizeChange_ && sizeA.width == sizeB.width && this.webKitLastResortFontSizes_[sizeA.width]) { diff --git a/src/modules.yml b/src/modules.yml index f6283437..478ae183 100644 --- a/src/modules.yml +++ b/src/modules.yml @@ -7,6 +7,7 @@ core: - core/fontmoduleloader.js - core/fontwatcher.js - core/fontwatchrunner.js + - core/fontruler.js - core/font.js - core/cssclassname.js - core/cssfontfamilyname.js From 3d1978968f110d8c608900f2d1f4564fbf287642 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 14 Nov 2012 14:24:17 +0100 Subject: [PATCH 15/66] Added test for the case where the font fails to load and the Webkit bug is present. --- src-test/core/fontwatchrunnertest.js | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index b0ebbcf0..1f53b5cf 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -137,13 +137,39 @@ FontWatchRunnerTest.prototype.setUp = function() { }; } else { // Return the correct width + return { + width: 3, + height: 3 + }; + } + } else { + // Return the default width + return { + width: 1, + height: 1 + }; + } + } + }; + + this.fakeWebkitFontSizerFailedLoad_ = { + getSize: function(el) { + if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { + if (self.timesToDelayChangedSizeWebkit_ > 0) { + self.timesToDelayChangedSizeWebkit_ -= 0.5; + return { + width: 2, + height: 2 + }; + } else { + // Return the original width, indicating the font + // failed to load. This should trigger `inactive`. return { width: 1, height: 1 }; } } else { - // Return the default width return { width: 1, height: 1 @@ -359,6 +385,22 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function assertEquals(true, this.fontActive_['fontFamily1 n4']); }; +FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedSizeWebkit_ = 2; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerFailedLoad_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true); + + fontWatchRunner.start(); + + assertEquals(2, this.asyncCount_); + assertEquals(1, this.fontInactiveCalled_); + assertEquals(true, this.fontInactive_['fontFamily1 n4']); +}; + FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; From 100f8489edfc359eea01ea767dca08a48eeed7c4 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 14 Nov 2012 14:44:02 +0100 Subject: [PATCH 16/66] Extracted size comparison method. --- src/core/fontwatchrunner.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 5bb014e8..872ff849 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -74,6 +74,16 @@ webfont.FontWatchRunner.prototype.start = function() { this.check_(); }; +/** + * Returns true if two metrics are the same. + * @param {{width: number, height: number}} a + * @param {{width: number, height: number}} b + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.sizeEquals = function(a, b) { + return a.width === b.width && a.height === b.height; +}; + /** * Checks the size of the two spans against their original sizes during each * async loop. If the size of one of the spans is different than the original @@ -87,8 +97,7 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.requestedFontA_.getSize(); var sizeB = this.requestedFontB_.getSize(); - if (this.lastObservedSizeA_.width != sizeA.width || this.lastObservedSizeB_.width != sizeB.width || - this.lastObservedSizeA_.height != sizeB.height || this.lastObservedSizeB_.height != sizeB.height) { + if (!this.sizeEquals(this.lastObservedSizeA_, sizeA) || !this.sizeEquals(this.lastObservedSizeB_, sizeB)) { if ((this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 1) || (!this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 0)) { this.finish_(this.activeCallback_); From 318223f796775f7265bda8b705be2b4b86917c45 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 14 Nov 2012 15:28:59 +0100 Subject: [PATCH 17/66] Rewrote the FontWatchRunner check_ method to correctly handle all cases when the Webkit fallback bug is present. --- src-test/core/fontwatchrunnertest.js | 2 +- src/core/fontwatchrunner.js | 78 +++++++++++++++++++--------- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 1f53b5cf..8f295cf1 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -364,7 +364,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { this.fontDescription_, true); fontWatchRunner.start(); - assertEquals(10, this.asyncCount_); + assertEquals(9, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 872ff849..60bfb40a 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -23,11 +23,12 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; - this.lastObservedSizeA_ = this.getDefaultFontSize_( + this.originalSizeA_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_A); - this.lastObservedSizeB_ = this.getDefaultFontSize_( + this.originalSizeB_ = this.getDefaultFontSize_( webfont.FontWatchRunner.DEFAULT_FONTS_B); - this.sizeChangeCount_ = 0; + this.lastObservedSizeA_ = null; + this.lastObservedSizeB_ = null; this.requestedFontA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_, this.fontTestString_); @@ -75,13 +76,23 @@ webfont.FontWatchRunner.prototype.start = function() { }; /** + * @private * Returns true if two metrics are the same. - * @param {{width: number, height: number}} a - * @param {{width: number, height: number}} b + * @param {?{width: number, height: number}} a + * @param {?{width: number, height: number}} b + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.sizeEquals_ = function(a, b) { + return !!a && !!b && a.width === b.width && a.height === b.height; +}; + +/** + * @private + * Returns true if the loading has timed out. * @return {boolean} */ -webfont.FontWatchRunner.prototype.sizeEquals = function(a, b) { - return a.width === b.width && a.height === b.height; +webfont.FontWatchRunner.prototype.hasTimedOut_ = function() { + return this.getTime_() - this.started_ >= 5000; }; /** @@ -97,28 +108,45 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.requestedFontA_.getSize(); var sizeB = this.requestedFontB_.getSize(); - if (!this.sizeEquals(this.lastObservedSizeA_, sizeA) || !this.sizeEquals(this.lastObservedSizeB_, sizeB)) { - if ((this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 1) || - (!this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 0)) { - this.finish_(this.activeCallback_); + if (this.hasWebkitFallbackBug_) { + // Check if we have seen the first change in size + if (!this.lastObservedSizeA_ && !this.lastObservedSizeB_) { + if (this.hasTimedOut_()) { + // We didn't observe any size changes and the timeout occurred, so fire `inactive` + this.finish_(this.inactiveCallback_); + } else if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { + this.asyncCheck_(); // Nothing, so let's wait. + } else { + // First size change. Record the size and wait for the next one. + this.lastObservedSizeA_ = sizeA; + this.lastObservedSizeB_ = sizeB; + this.asyncCheck_(); + } } else { - this.lastObservedSizeA_ = sizeA; - this.lastObservedSizeB_ = sizeB; - this.sizeChangeCount_ += 1; - this.asyncCheck_(); + if (this.hasTimedOut_()) { + if (this.sizeEquals_(sizeA, this.lastObservedSizeA_) && this.sizeEquals_(sizeB, this.lastObservedSizeB_)) { + this.finish_(this.activeCallback_); + } else { + this.finish_(this.inactiveCallback_); + } + } else if (this.sizeEquals_(sizeA, this.lastObservedSizeA_) && this.sizeEquals_(sizeB, this.lastObservedSizeB_)) { + this.asyncCheck_(); + } else { + if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { + this.finish_(this.inactiveCallback_); + } else { + this.finish_(this.activeCallback_); + } + } } - } else if (this.getTime_() - this.started_ >= 5000) { - if (this.hasWebkitFallbackBug_ && this.sizeChangeCount_ === 1) { - // If we reach the timeout and we are in a Webkit browser with the - // fallback and we observed at least one size change, hope for the - // best and assume that the font has loaded and has identical font - // metrics compared to the browser's last resort font. - this.finish_(this.activeCallback_); - } else { + } else { + if (this.hasTimedOut_()) { this.finish_(this.inactiveCallback_); + } else if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { + this.asyncCheck_(); + } else { + this.finish_(this.activeCallback_); } - } else { - this.asyncCheck_(); } }; From 6fd8ca604693c8e78b066de496bea2a94244428d Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:31:06 +0100 Subject: [PATCH 18/66] FontRuler no longer automatically inserts itself into the DOM. This operation now has to be done explicitly. --- src/core/fontruler.js | 19 +++++---------- src/core/fontwatcher.js | 6 +++-- src/core/fontwatchrunner.js | 24 +++++++++++++------ src/google/lastresortwebkitfontwatchrunner.js | 6 ++++- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/core/fontruler.js b/src/core/fontruler.js index 14915422..953e5dfc 100644 --- a/src/core/fontruler.js +++ b/src/core/fontruler.js @@ -4,20 +4,15 @@ * @constructor * @param {webfont.DomHelper} domHelper * @param {Object.} fontSizer - * @param {string} fontFamily - * @param {string} fontDescription * @param {string} fontTestString */ -webfont.FontRuler = function(domHelper, fontSizer, fontFamily, fontDescription, fontTestString) { +webfont.FontRuler = function(domHelper, fontSizer, fontTestString) { this.domHelper_ = domHelper; this.fontSizer_ = fontSizer; - this.fontFamily_ = fontFamily; - this.fontDescription_ = fontDescription; this.fontTestString_ = fontTestString; this.nameHelper_ = new webfont.CssFontFamilyName(); this.fvd_ = new webfont.FontVariationDescription(); - this.el_ = this.create_(); - this.setFont(fontFamily, fontDescription); + this.el_ = null; }; /** @@ -30,13 +25,11 @@ webfont.FontRuler.prototype.setFont = function(fontFamily, fontDescription) { }; /** - * @private * @return {Element} */ -webfont.FontRuler.prototype.create_ = function() { - var span = this.domHelper_.createElement('span', {}, this.fontTestString_); - this.domHelper_.insertInto('body', span); - return span; +webfont.FontRuler.prototype.insert = function() { + this.el_ = this.domHelper_.createElement('span', {}, this.fontTestString_); + this.domHelper_.insertInto('body', this.el_); }; /** @@ -46,7 +39,7 @@ webfont.FontRuler.prototype.create_ = function() { * @return {string} */ webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, fontDescription) { - var variationCss = this.fvd_.expand(fontDescription); + var variationCss = this.fvd_.expand(fontDescription || ''); var styleString = "position:absolute;top:-999px;left:-999px;" + "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" + "padding:0;font-variant:normal;font-family:" + diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index ff55fbcb..22856588 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -40,11 +40,13 @@ webfont.FontWatcher.prototype.hasFallbackBug_ = function() { "src:url(data:application/x-font-woff;base64,) format('woff')," + "url(data:font/truetype;base64,) format('truetype');" + "}"), - ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'monospace', '', 'iii'); + ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); + ruler.insert(); + ruler.setFont('monospace'); this.domHelper_.insertInto('head', font); var beforeWidth = ruler.getSize().width; - ruler.setFont("'__webfontloader_test__', monospace, sans-serif", ''); + ruler.setFont("'__webfontloader_test__', monospace, sans-serif"); var hasBug = beforeWidth !== ruler.getSize().width; this.domHelper_.removeElement(font); ruler.remove(); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 60bfb40a..550f7f58 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -29,12 +29,20 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, webfont.FontWatchRunner.DEFAULT_FONTS_B); this.lastObservedSizeA_ = null; this.lastObservedSizeB_ = null; - this.requestedFontA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, - this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, - this.fontDescription_, this.fontTestString_); - this.requestedFontB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, - this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, - this.fontDescription_, this.fontTestString_); + + this.requestedFontA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + this.requestedFontA_.insert(); + this.requestedFontA_.setFont( + this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, + this.fontDescription_ + ); + + this.requestedFontB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + this.requestedFontB_.insert(); + this.requestedFontB_.setFont( + this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, + this.fontDescription_ + ) }; /** @@ -177,7 +185,9 @@ webfont.FontWatchRunner.prototype.finish_ = function(callback) { * @return {{width: number, height: number}} */ webfont.FontWatchRunner.prototype.getDefaultFontSize_ = function(defaultFonts) { - var defaultFont = new webfont.FontRuler(this.domHelper_, this.fontSizer_, defaultFonts, this.fontDescription_, this.fontTestString_); + var defaultFont = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + defaultFont.insert(); + defaultFont.setFont(defaultFonts, this.fontDescription_); var size = defaultFont.getSize(); defaultFont.remove(); return size; diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index 078249c3..0e36d5db 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -42,7 +42,11 @@ webfont.LastResortWebKitFontWatchRunner.prototype var lastResortFonts = ['Times New Roman', 'Arial', 'Times', 'Sans', 'Serif']; var lastResortFontSizes = lastResortFonts.length; var webKitLastResortFontSizes = {}; - var fontRuler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, lastResortFonts[0], this.fontDescription_, this.fontTestString_); + var fontRuler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + + fontRuler.insert(); + fontRuler.setFont(lastResortFonts[0], this.fontDescription_); + webKitLastResortFontSizes[fontRuler.getSize().width] = true; for (var i = 1; i < lastResortFontSizes; i++) { var font = lastResortFonts[i]; From 247f0f08b8790dc51c8d605e1b9fb6751dd3cdb5 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:34:12 +0100 Subject: [PATCH 19/66] Renamed requestFontA/B to fontRulerA/B. --- src/core/fontwatchrunner.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 550f7f58..957d89f9 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -30,16 +30,16 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.lastObservedSizeA_ = null; this.lastObservedSizeB_ = null; - this.requestedFontA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); - this.requestedFontA_.insert(); - this.requestedFontA_.setFont( + this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + this.fontRulerA_.insert(); + this.fontRulerA_.setFont( this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_ ); - this.requestedFontB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); - this.requestedFontB_.insert(); - this.requestedFontB_.setFont( + this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + this.fontRulerB_.insert(); + this.fontRulerB_.setFont( this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_ ) @@ -113,8 +113,8 @@ webfont.FontWatchRunner.prototype.hasTimedOut_ = function() { * @private */ webfont.FontWatchRunner.prototype.check_ = function() { - var sizeA = this.requestedFontA_.getSize(); - var sizeB = this.requestedFontB_.getSize(); + var sizeA = this.fontRulerA_.getSize(); + var sizeB = this.fontRulerB_.getSize(); if (this.hasWebkitFallbackBug_) { // Check if we have seen the first change in size @@ -174,8 +174,8 @@ webfont.FontWatchRunner.prototype.asyncCheck_ = function() { * @param {function(string, string)} callback */ webfont.FontWatchRunner.prototype.finish_ = function(callback) { - this.requestedFontA_.remove(); - this.requestedFontB_.remove(); + this.fontRulerA_.remove(); + this.fontRulerB_.remove(); callback(this.fontFamily_, this.fontDescription_); }; From f4ef7ef4ed6a81d8a263be6f6037dbc68797cd63 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:46:46 +0100 Subject: [PATCH 20/66] Re-use the same two FontRuler instances for both the initial measurement and the monitoring. --- src-test/core/fontwatchrunnertest.js | 40 ++++++++++------------------ src/core/fontwatchrunner.js | 33 +++++------------------ 2 files changed, 21 insertions(+), 52 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 8f295cf1..62aa3b4a 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -412,25 +412,19 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { fontWatchRunner.start(); - assertEquals(4, this.createElementCalled_); + assertEquals(2, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); - assertEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); assertEquals('BESbswy', this.createdElements_[0]['innerHtml']); + assertEquals('span', this.createdElements_[1]['name']); - assertEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); assertEquals('BESbswy', this.createdElements_[1]['innerHtml']); - assertEquals('span', this.createdElements_[2]['name']); - assertNotEquals(-1, this.createdElements_[2]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[2]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); - assertEquals('BESbswy', this.createdElements_[2]['innerHtml']); - assertEquals('span', this.createdElements_[3]['name']); - assertNotEquals(-1, this.createdElements_[3]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[3]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); - assertEquals('BESbswy', this.createdElements_[3]['innerHtml']); - assertEquals(4, this.insertIntoCalled_); - assertEquals(4, this.removeElementCalled_); + + assertEquals(2, this.insertIntoCalled_); + assertEquals(2, this.removeElementCalled_); }; FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { @@ -444,24 +438,18 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { fontWatchRunner.start(); - assertEquals(4, this.createElementCalled_); + assertEquals(2, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); - assertEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); assertEquals('testString', this.createdElements_[0]['innerHtml']); + assertEquals('span', this.createdElements_[1]['name']); - assertEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); assertEquals('testString', this.createdElements_[1]['innerHtml']); - assertEquals('span', this.createdElements_[2]['name']); - assertNotEquals(-1, this.createdElements_[2]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[2]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); - assertEquals('testString', this.createdElements_[2]['innerHtml']); - assertEquals('span', this.createdElements_[3]['name']); - assertNotEquals(-1, this.createdElements_[3]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[3]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); - assertEquals('testString', this.createdElements_[3]['innerHtml']); - assertEquals(4, this.insertIntoCalled_); - assertEquals(4, this.removeElementCalled_); + + assertEquals(2, this.insertIntoCalled_); + assertEquals(2, this.removeElementCalled_); }; diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 957d89f9..8d33f92f 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -23,26 +23,21 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; - this.originalSizeA_ = this.getDefaultFontSize_( - webfont.FontWatchRunner.DEFAULT_FONTS_A); - this.originalSizeB_ = this.getDefaultFontSize_( - webfont.FontWatchRunner.DEFAULT_FONTS_B); + this.lastObservedSizeA_ = null; this.lastObservedSizeB_ = null; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); - this.fontRulerA_.setFont( - this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, - this.fontDescription_ - ); + this.fontRulerA_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); + this.originalSizeA_ = this.fontRulerA_.getSize(); + this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - this.fontRulerB_.setFont( - this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, - this.fontDescription_ - ) + this.fontRulerB_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); + this.originalSizeB_ = this.fontRulerB_.getSize(); + this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); }; /** @@ -178,17 +173,3 @@ webfont.FontWatchRunner.prototype.finish_ = function(callback) { this.fontRulerB_.remove(); callback(this.fontFamily_, this.fontDescription_); }; - -/** - * @private - * @param {string} defaultFonts - * @return {{width: number, height: number}} - */ -webfont.FontWatchRunner.prototype.getDefaultFontSize_ = function(defaultFonts) { - var defaultFont = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); - defaultFont.insert(); - defaultFont.setFont(defaultFonts, this.fontDescription_); - var size = defaultFont.getSize(); - defaultFont.remove(); - return size; -}; From 63e3160e715c25a9ae99dddbf3333ee3563bb7fd Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:50:30 +0100 Subject: [PATCH 21/66] Renamed lastObservedSizeA/B to webkitFallbackSizeA/B. --- src/core/fontwatchrunner.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 8d33f92f..88ae16a5 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -24,8 +24,8 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; - this.lastObservedSizeA_ = null; - this.lastObservedSizeB_ = null; + this.webkitFallbackSizeA_ = null; + this.webkitFallbackSizeB_ = null; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); @@ -113,7 +113,7 @@ webfont.FontWatchRunner.prototype.check_ = function() { if (this.hasWebkitFallbackBug_) { // Check if we have seen the first change in size - if (!this.lastObservedSizeA_ && !this.lastObservedSizeB_) { + if (!this.webkitFallbackSizeA_ && !this.webkitFallbackSizeB_) { if (this.hasTimedOut_()) { // We didn't observe any size changes and the timeout occurred, so fire `inactive` this.finish_(this.inactiveCallback_); @@ -121,18 +121,18 @@ webfont.FontWatchRunner.prototype.check_ = function() { this.asyncCheck_(); // Nothing, so let's wait. } else { // First size change. Record the size and wait for the next one. - this.lastObservedSizeA_ = sizeA; - this.lastObservedSizeB_ = sizeB; + this.webkitFallbackSizeA_ = sizeA; + this.webkitFallbackSizeB_ = sizeB; this.asyncCheck_(); } } else { if (this.hasTimedOut_()) { - if (this.sizeEquals_(sizeA, this.lastObservedSizeA_) && this.sizeEquals_(sizeB, this.lastObservedSizeB_)) { + if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); } - } else if (this.sizeEquals_(sizeA, this.lastObservedSizeA_) && this.sizeEquals_(sizeB, this.lastObservedSizeB_)) { + } else if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { this.asyncCheck_(); } else { if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { From 584b78b2bd7ce47f5871a9db05defcd688b0e872 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:53:32 +0100 Subject: [PATCH 22/66] Renamed hasBug => hasWebkitFallbackBug and hasFallbackBug => checkWebkitFallbackBug. --- src/core/fontwatcher.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 22856588..5544b74a 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -15,7 +15,7 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, this.asyncCall_ = asyncCall; this.getTime_ = getTime; this.currentlyWatched_ = 0; - this.hasBug_ = userAgent.getEngine() === 'AppleWebKit' ? this.hasFallbackBug_() : false; + this.hasWebkitFallbackBug_ = userAgent.getEngine() === 'AppleWebKit' ? this.checkWebkitFallbackBug_() : false; this.last_ = false; this.success_ = false; }; @@ -33,7 +33,7 @@ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; * @return {boolean} * @private */ -webfont.FontWatcher.prototype.hasFallbackBug_ = function() { +webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { var font = this.domHelper_.createElement('style', null, "@font-face{" + "font-family:'__webfontloader_test__';" + @@ -98,7 +98,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, this.hasBug_, fontTestString); + this.getTime_, fontFamily, fontDescription, this.hasWebkitFallbackBug_, fontTestString); fontWatchRunner.start(); } From 2049d042976edb1f8074b946692d1d46bcae626b Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 11:57:23 +0100 Subject: [PATCH 23/66] Renamed fakeUserAgent_ to userAgent_. --- src-test/core/fontwatchertest.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 3a77dc2f..ea3590c5 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -45,7 +45,7 @@ FontWatcherTest.prototype.setUp = function() { setStyle: function() {} }; - this.fakeUserAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); + this.userAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); this.fakeFontSizer_ = { getSize: function() { @@ -96,7 +96,7 @@ FontWatcherTest.prototype.testWatchOneFontNotLast = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, false); @@ -110,7 +110,7 @@ FontWatcherTest.prototype.testWatchOneFontActive = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -128,7 +128,7 @@ FontWatcherTest.prototype.testWatchOneFontInactive = function() { var fontFamilies = [ 'fontFamily1' ]; this.fontWatchRunnerActiveFamilies_ = []; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -146,7 +146,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsActive = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -168,7 +168,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsInactive = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = []; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -190,7 +190,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsMixed = function() { var fontFamilies = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ]; this.fontWatchRunnerActiveFamilies_ = [ 'fontFamily1', 'fontFamily3' ]; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, {}, webfont.FontWatchRunner, true); @@ -218,7 +218,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithDescriptions = function() { 'fontFamily3': ['n4', 'i4', 'n7'] }; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, fontDescriptions, {}, webfont.FontWatchRunner, true); @@ -251,7 +251,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { 'fontFamily4': null }; - var fontWatcher = new webfont.FontWatcher(this.fakeUserAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, + var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); fontWatcher.watch(fontFamilies, {}, fontTestStrings, webfont.FontWatchRunner, From c652d82f8e401aa68a7c4950c5b5a28dac20da83 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 12:15:24 +0100 Subject: [PATCH 24/66] Added documentation to the Webkit fallback bug detection code. --- src/core/fontwatcher.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 5544b74a..28839dbf 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -30,10 +30,15 @@ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; * Returns true if this browser has a bug that causes the font stack * to not be respected while loading webfonts. * + * @see https://bugs.webkit.org/show_bug.cgi?id=76684 + * * @return {boolean} * @private */ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { + // We build an empty webfont and try to set it as the font for our + // ruler. Even though this will fail (since our webfont is invalid) + // it will actually trigger the Webkit fallback bug. var font = this.domHelper_.createElement('style', null, "@font-face{" + "font-family:'__webfontloader_test__';" + @@ -43,10 +48,34 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); ruler.insert(); + + // First we set the font to monospace and the test string to `iii`. Based + // on our research, all platforms have at least a monospace, sans-serif, + // and serif font installed. By using a test string that has a very + // narrow width in non-monospace fonts it becomes easy to detect changes + // in width. ruler.setFont('monospace'); this.domHelper_.insertInto('head', font); + + // Measure the original size (of our monospace font) var beforeWidth = ruler.getSize().width; + + // Set the font to include our fake webfont, and then fallback to + // `monospace` and `sans-serif`. Browsers without the bug will fall + // back on the `monospace` font while loading the webfont, while + // Webkit with the bug will fall back to its last resort font (which + // according to our data is never `monospace`.) The `sans-serif` is + // included here to deal with another bug in Chrome Android where + // instead of using the last resort font it picks the last font in + // the stack. + // + // See http://code.google.com/p/chromium/issues/detail?id=138257 + // for more information on the Chrome Android bug. ruler.setFont("'__webfontloader_test__', monospace, sans-serif"); + + // Finally we compare the initial width and the current width. If + // they do not match (i.e. it is either the sans-serif font, or + // the last resort font) we assume the bug is present. var hasBug = beforeWidth !== ruler.getSize().width; this.domHelper_.removeElement(font); ruler.remove(); From 10080df4349cb1c7b89e266b6817472282e36e0c Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 12:19:41 +0100 Subject: [PATCH 25/66] Fixed type annotations and made fontDescription explicitly optional. --- src/core/fontruler.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/fontruler.js b/src/core/fontruler.js index 953e5dfc..bb3cd3b5 100644 --- a/src/core/fontruler.js +++ b/src/core/fontruler.js @@ -17,15 +17,15 @@ webfont.FontRuler = function(domHelper, fontSizer, fontTestString) { /** * @param {string} fontFamily - * @param {string} fontDescription + * @param {string=} opt_fontDescription */ -webfont.FontRuler.prototype.setFont = function(fontFamily, fontDescription) { - var styleString = this.computeStyleString_(fontFamily, fontDescription); +webfont.FontRuler.prototype.setFont = function(fontFamily, opt_fontDescription) { + var styleString = this.computeStyleString_(fontFamily, opt_fontDescription); this.domHelper_.setStyle(this.el_, styleString); }; /** - * @return {Element} + * Inserts the ruler into the DOM. */ webfont.FontRuler.prototype.insert = function() { this.el_ = this.domHelper_.createElement('span', {}, this.fontTestString_); @@ -35,11 +35,11 @@ webfont.FontRuler.prototype.insert = function() { /** * @private * @param {string} fontFamily - * @param {string} fontDescription + * @param {string=} opt_fontDescription * @return {string} */ -webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, fontDescription) { - var variationCss = this.fvd_.expand(fontDescription || ''); +webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, opt_fontDescription) { + var variationCss = this.fvd_.expand(opt_fontDescription || ''); var styleString = "position:absolute;top:-999px;left:-999px;" + "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" + "padding:0;font-variant:normal;font-family:" + From 1bfcb1bcd141050b6c808d655cee7f87e7611a2e Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 12:21:55 +0100 Subject: [PATCH 26/66] Fixed google/lastresortwebkitfontwatchrunner.js so it works with the latest changes in core. --- src/google/lastresortwebkitfontwatchrunner.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index 0e36d5db..3afd2fe6 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -20,6 +20,8 @@ webfont.LastResortWebKitFontWatchRunner = function(activeCallback, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString); this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_(); this.webKitLastResortSizeChange_ = false; + this.lastObservedSizeA_ = this.originalSizeA_; + this.lastObservedSizeB_ = this.originalSizeB_; }; webfont.extendsClass(webfont.FontWatchRunner, webfont.LastResortWebKitFontWatchRunner); @@ -65,8 +67,8 @@ webfont.LastResortWebKitFontWatchRunner.prototype }; webfont.LastResortWebKitFontWatchRunner.prototype.check_ = function() { - var sizeA = this.requestedFontA_.getSize(); - var sizeB = this.requestedFontB_.getSize(); + var sizeA = this.fontRulerA_.getSize(); + var sizeB = this.fontRulerB_.getSize(); if (!this.webKitLastResortSizeChange_ && sizeA.width == sizeB.width && this.webKitLastResortFontSizes_[sizeA.width]) { From 07173c8f03615d6484ea8b429a9842c3f632b9cc Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 12:53:46 +0100 Subject: [PATCH 27/66] Added tests to exercise the webkit fallback bug detection code. --- src-test/core/fontwatchertest.js | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index ea3590c5..e04e17e1 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -261,3 +261,64 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { assertEquals('testString1', this.testStrings_['fontFamily1']); assertEquals('testString3', this.testStrings_['fontFamily3']); }; + +FontWatcherTest.prototype.testWebkitBugDetectionOnlyOnWebkit = function() { + var createElementCalled = false; + var fakeDomHelper = { + createElement: function() { + createElementCalled = true; + } + }; + var fontWatcher = new webfont.FontWatcher(this.userAgent_, fakeDomHelper, this.fakeEventDispatcher_, + this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); + + assertEquals(false, fontWatcher.hasWebkitFallbackBug_); + assertEquals(false, createElementCalled); +}; + +FontWatcherTest.prototype.testWebkitFallbackBugDetectionWithBug = function() { + var userAgent = new webfont.UserAgent('Chrome', '18.0.1271.64', 'AppleWebKit', '537.11', 'Macintosh', '10.6', undefined, true); + var isInitial = true; + var fakeFontSizer = { + getSize: function(el) { + if (isInitial) { + isInitial = false; + // Monospace + return { + width: 1, + height: 1 + }; + } else { + // Something not monospace + return { + width: 2, + height: 2 + }; + } + } + }; + + var fontWatcher = new webfont.FontWatcher(userAgent, this.fakeDomHelper_, this.fakeEventDispatcher_, + fakeFontSizer, this.fakeAsyncCall_, this.fakeGetTime_); + + assertEquals(true, fontWatcher.hasWebkitFallbackBug_); +}; + +FontWatcherTest.prototype.testWebkitFallbackBugDetectionWithoutBug = function() { + var userAgent = new webfont.UserAgent('Chrome', '23.0.1271.64', 'AppleWebKit', '537.11', 'Macintosh', '10.6', undefined, true); + var isInitial = true; + var fakeFontSizer = { + getSize: function(el) { + // Monospace + return { + width: 1, + height: 1 + }; + } + }; + + var fontWatcher = new webfont.FontWatcher(userAgent, this.fakeDomHelper_, this.fakeEventDispatcher_, + fakeFontSizer, this.fakeAsyncCall_, this.fakeGetTime_); + + assertEquals(false, fontWatcher.hasWebkitFallbackBug_); +}; From 2db3b2b520a8e2b567aed23f887e2e9deda20375 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 15 Nov 2012 13:57:28 +0100 Subject: [PATCH 28/66] Updated gemspec. --- webfontloader.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/webfontloader.gemspec b/webfontloader.gemspec index dc862cae..26cd9e79 100644 --- a/webfontloader.gemspec +++ b/webfontloader.gemspec @@ -129,6 +129,7 @@ DESC src/core/eventdispatcher.js src/core/font.js src/core/fontmoduleloader.js + src/core/fontruler.js src/core/fontvariationdescription.js src/core/fontwatcher.js src/core/fontwatchrunner.js From c4924b9c5b5fd6dfaa122e28a8b78eef7f6ae5fa Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Fri, 16 Nov 2012 10:06:16 +0100 Subject: [PATCH 29/66] Moved inserting the ruler adjacent to the measurement call. --- src/core/fontwatcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 28839dbf..1fafd355 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -47,8 +47,6 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { "}"), ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); - ruler.insert(); - // First we set the font to monospace and the test string to `iii`. Based // on our research, all platforms have at least a monospace, sans-serif, // and serif font installed. By using a test string that has a very @@ -57,6 +55,8 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { ruler.setFont('monospace'); this.domHelper_.insertInto('head', font); + ruler.insert(); + // Measure the original size (of our monospace font) var beforeWidth = ruler.getSize().width; From 2da24c4549df4b2717d6ed27e7bd85ca4e6948eb Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 19 Nov 2012 16:01:02 +0100 Subject: [PATCH 30/66] Changed FontRuler so that the element is created on instantiation but only inserted into the DOM when insert() is called. --- src/core/fontruler.js | 3 +-- src/core/fontwatcher.js | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/fontruler.js b/src/core/fontruler.js index bb3cd3b5..3b332f72 100644 --- a/src/core/fontruler.js +++ b/src/core/fontruler.js @@ -12,7 +12,7 @@ webfont.FontRuler = function(domHelper, fontSizer, fontTestString) { this.fontTestString_ = fontTestString; this.nameHelper_ = new webfont.CssFontFamilyName(); this.fvd_ = new webfont.FontVariationDescription(); - this.el_ = null; + this.el_ = this.domHelper_.createElement('span', {}, this.fontTestString_); }; /** @@ -28,7 +28,6 @@ webfont.FontRuler.prototype.setFont = function(fontFamily, opt_fontDescription) * Inserts the ruler into the DOM. */ webfont.FontRuler.prototype.insert = function() { - this.el_ = this.domHelper_.createElement('span', {}, this.fontTestString_); this.domHelper_.insertInto('body', this.el_); }; diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 1fafd355..0c37fb9f 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -47,13 +47,14 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { "}"), ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); + this.domHelper_.insertInto('head', font); + // First we set the font to monospace and the test string to `iii`. Based // on our research, all platforms have at least a monospace, sans-serif, // and serif font installed. By using a test string that has a very // narrow width in non-monospace fonts it becomes easy to detect changes // in width. ruler.setFont('monospace'); - this.domHelper_.insertInto('head', font); ruler.insert(); From 1fe77f435279bf63229b6f5a29241c83dc305157 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 21 Nov 2012 15:36:27 +0100 Subject: [PATCH 31/66] Prevent a race condition where a WebKit version with the bug loads a cached font. This change ensures that we do not miss the double size change while we are waiting. --- src-test/core/fontwatchrunnertest.js | 27 +++++++++--------- src/core/fontwatchrunner.js | 41 +++++++++++++++++----------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 62aa3b4a..6548da44 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -323,19 +323,18 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { }; FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { - this.timesToGetTimeBeforeTimeout_ = 10; - this.timesToDelayChangedSizeWebkit_ = 1; - - var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, - this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, - this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_, true); + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedSizeWebkit_ = 1; - fontWatchRunner.start(); + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true); - assertEquals(1, this.asyncCount_); - assertEquals(1, this.fontActiveCalled_); - assertEquals(true, this.fontActive_['fontFamily1 n4']); + fontWatchRunner.start(); + assertEquals(0, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); }; FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { @@ -349,7 +348,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { fontWatchRunner.start(); - assertEquals(2, this.asyncCount_); + assertEquals(1, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; @@ -380,7 +379,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function fontWatchRunner.start(); - assertEquals(2, this.asyncCount_); + assertEquals(1, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; @@ -396,7 +395,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { fontWatchRunner.start(); - assertEquals(2, this.asyncCount_); + assertEquals(1, this.asyncCount_); assertEquals(1, this.fontInactiveCalled_); assertEquals(true, this.fontInactive_['fontFamily1 n4']); }; diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 88ae16a5..51a2e043 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -31,13 +31,11 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontRulerA_.insert(); this.fontRulerA_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); this.originalSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); this.fontRulerB_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); this.originalSizeB_ = this.fontRulerB_.getSize(); - this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); }; /** @@ -75,6 +73,22 @@ webfont.FontWatchRunner.DEFAULT_TEST_STRING = 'BESbswy'; webfont.FontWatchRunner.prototype.start = function() { this.started_ = this.getTime_(); + + // Right after trigger the font we measure the fallback size + // if the webkit fallback bug is present. This is safe because + // we rely on the same trick to detect the bug in the first + // place. This also prevents a cached font completing its + // size cycle before we start checking. + this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); + if (this.hasWebkitFallbackBug_) { + this.webkitFallbackSizeA_ = this.fontRulerA_.getSize(); + } + + this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); + if (this.hasWebkitFallbackBug_) { + this.webkitFallbackSizeB_ = this.fontRulerB_.getSize(); + } + this.check_(); }; @@ -112,35 +126,30 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeB = this.fontRulerB_.getSize(); if (this.hasWebkitFallbackBug_) { - // Check if we have seen the first change in size - if (!this.webkitFallbackSizeA_ && !this.webkitFallbackSizeB_) { - if (this.hasTimedOut_()) { - // We didn't observe any size changes and the timeout occurred, so fire `inactive` - this.finish_(this.inactiveCallback_); - } else if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { - this.asyncCheck_(); // Nothing, so let's wait. - } else { - // First size change. Record the size and wait for the next one. - this.webkitFallbackSizeA_ = sizeA; - this.webkitFallbackSizeB_ = sizeB; - this.asyncCheck_(); - } - } else { + if (this.webkitFallbackSizeA_ && this.webkitFallbackSizeB_) { if (this.hasTimedOut_()) { + // A timeout has occured. If the size is the same as the fallback size we assume we have + // a font metrics compatible font and fire the `active` event. Otherwise fire `inactive`. if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); } } else if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { + // Nothing has changed, so let's wait. this.asyncCheck_(); } else { + // The size has changed. If the size is the same as the original size we assume the font + // failed to load and we fire `inactive`. Otherwise we fire `active`. if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { this.finish_(this.inactiveCallback_); } else { this.finish_(this.activeCallback_); } } + } else { + // The check_ method is called before the fallback sizes are known. Wait. + this.asyncCheck_(); } } else { if (this.hasTimedOut_()) { From 79205af5b3e58d2df209cbd91dfe1b3e167917a1 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 21 Nov 2012 21:48:12 +0100 Subject: [PATCH 32/66] Fixed a small bug that causes null to be inserted when there is no font description. --- src/core/fontruler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/fontruler.js b/src/core/fontruler.js index 3b332f72..17b725b8 100644 --- a/src/core/fontruler.js +++ b/src/core/fontruler.js @@ -38,7 +38,7 @@ webfont.FontRuler.prototype.insert = function() { * @return {string} */ webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, opt_fontDescription) { - var variationCss = this.fvd_.expand(opt_fontDescription || ''); + var variationCss = opt_fontDescription ? this.fvd_.expand(opt_fontDescription) : ''; var styleString = "position:absolute;top:-999px;left:-999px;" + "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" + "padding:0;font-variant:normal;font-family:" + From d86aa64fb86ebc8d7e5b44352f87de9eea68f181 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Fri, 30 Nov 2012 20:39:03 +0100 Subject: [PATCH 33/66] Merged in new font watching strategy. Google lastresortwebkitfontwatchrunner.js tests are still broken. --- src-test/core/fontwatchrunnertest.js | 50 +++++++---- src/core/fontwatchrunner.js | 90 ++++++------------- src/google/lastresortwebkitfontwatchrunner.js | 4 +- 3 files changed, 62 insertions(+), 82 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 6548da44..e31a8f8e 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -142,12 +142,17 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else { + } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { // Return the default width return { width: 1, height: 1 }; + } else { + return { + width: 2, + height: 2 + }; } } }; @@ -169,11 +174,16 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 1 }; } - } else { + } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { return { width: 1, height: 1 }; + } else { + return { + width: 2, + height: 2 + }; } } }; @@ -196,12 +206,17 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 2 }; } - } else { + } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { // Return the default width return { width: 1, height: 1 }; + } else { + return { + width: 2, + height: 2 + }; } } }; @@ -223,11 +238,16 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else { + } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { return { width: 1, height: 1 }; + } else { + return { + width: 2, + height: 2 + }; } } }; @@ -332,7 +352,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { this.fontDescription_, true); fontWatchRunner.start(); - assertEquals(0, this.asyncCount_); + assertEquals(1, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; @@ -347,8 +367,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { this.fontDescription_, true); fontWatchRunner.start(); - - assertEquals(1, this.asyncCount_); + assertEquals(2, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; @@ -378,15 +397,14 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function this.fontDescription_, true); fontWatchRunner.start(); - - assertEquals(1, this.asyncCount_); + assertEquals(2, this.asyncCount_); assertEquals(1, this.fontActiveCalled_); assertEquals(true, this.fontActive_['fontFamily1 n4']); }; FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { this.timesToGetTimeBeforeTimeout_ = 10; - this.timesToDelayChangedSizeWebkit_ = 2; + this.timesToDelayChangedSizeWebkit_ = 5; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerFailedLoad_, @@ -394,8 +412,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { this.fontDescription_, true); fontWatchRunner.start(); - - assertEquals(1, this.asyncCount_); + assertEquals(9, this.asyncCount_); assertEquals(1, this.fontInactiveCalled_); assertEquals(true, this.fontInactive_['fontFamily1 n4']); }; @@ -410,16 +427,15 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(2, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_A)); assertEquals('BESbswy', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_B)); assertEquals('BESbswy', this.createdElements_[1]['innerHtml']); assertEquals(2, this.insertIntoCalled_); @@ -440,12 +456,12 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { assertEquals(2, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_A)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_A)); assertEquals('testString', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.DEFAULT_FONTS_B)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_B)); assertEquals('testString', this.createdElements_[1]['innerHtml']); assertEquals(2, this.insertIntoCalled_); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 51a2e043..da590b4c 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -24,43 +24,38 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; - this.webkitFallbackSizeA_ = null; - this.webkitFallbackSizeB_ = null; - this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); - this.fontRulerA_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); - this.originalSizeA_ = this.fontRulerA_.getSize(); + this.fontRulerA_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); + this.lastResortSizeA_ = this.fontRulerA_.getSize(); + this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + this.fallbackSizeA_ = this.fontRulerA_.getSize(); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - this.fontRulerB_.setFont(webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); - this.originalSizeB_ = this.fontRulerB_.getSize(); + this.fontRulerB_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); + this.lastResortSizeB_ = this.fontRulerB_.getSize(); + this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); + this.fallbackSizeB_ = this.fontRulerB_.getSize(); }; /** - * A set of sans-serif fonts and a generic family that cover most platforms: - * Windows - arial - 99.71% - * Mac - arial - 97.67% - * Linux - 97.67% - * (Based on http://www.codestyle.org/css/font-family/sampler-CombinedResults.shtml) * @type {string} * @const */ -webfont.FontWatchRunner.DEFAULT_FONTS_A = "arial,'URW Gothic L',sans-serif"; +webfont.FontWatchRunner.FALLBACK_FONTS_A = "serif,sans-serif"; /** - * A set of serif fonts and a generic family that cover most platforms. We - * want each of these fonts to have a different width when rendering the test - * string than each of the fonts in DEFAULT_FONTS_A: - * Windows - Georgia - 98.98% - * Mac - Georgia - 95.60% - * Linux - Century Schoolbook L - 97.97% - * (Based on http://www.codestyle.org/css/font-family/sampler-CombinedResults.shtml) * @type {string} * @const */ -webfont.FontWatchRunner.DEFAULT_FONTS_B = "Georgia,'Century Schoolbook L',serif"; +webfont.FontWatchRunner.FALLBACK_FONTS_B = "sans-serif,serif"; + +/** + * @type {string} + * @const + */ +webfont.FontWatchRunner.LAST_RESORT_FONT = "''"; /** * Default test string. Characters are chosen so that their widths vary a lot @@ -74,20 +69,8 @@ webfont.FontWatchRunner.DEFAULT_TEST_STRING = 'BESbswy'; webfont.FontWatchRunner.prototype.start = function() { this.started_ = this.getTime_(); - // Right after trigger the font we measure the fallback size - // if the webkit fallback bug is present. This is safe because - // we rely on the same trick to detect the bug in the first - // place. This also prevents a cached font completing its - // size cycle before we start checking. - this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_A, this.fontDescription_); - if (this.hasWebkitFallbackBug_) { - this.webkitFallbackSizeA_ = this.fontRulerA_.getSize(); - } - - this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.DEFAULT_FONTS_B, this.fontDescription_); - if (this.hasWebkitFallbackBug_) { - this.webkitFallbackSizeB_ = this.fontRulerB_.getSize(); - } + this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); this.check_(); }; @@ -125,40 +108,21 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.fontRulerA_.getSize(); var sizeB = this.fontRulerB_.getSize(); - if (this.hasWebkitFallbackBug_) { - if (this.webkitFallbackSizeA_ && this.webkitFallbackSizeB_) { - if (this.hasTimedOut_()) { - // A timeout has occured. If the size is the same as the fallback size we assume we have - // a font metrics compatible font and fire the `active` event. Otherwise fire `inactive`. - if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { - this.finish_(this.activeCallback_); - } else { - this.finish_(this.inactiveCallback_); - } - } else if (this.sizeEquals_(sizeA, this.webkitFallbackSizeA_) && this.sizeEquals_(sizeB, this.webkitFallbackSizeB_)) { - // Nothing has changed, so let's wait. - this.asyncCheck_(); + if ((this.sizeEquals_(sizeA, this.fallbackSizeA_) && this.sizeEquals_(sizeB, this.fallbackSizeB_)) || + (this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { + if (this.hasTimedOut_()) { + if (this.hasWebkitFallbackBug_ && + this.sizeEquals_(sizeA, this.lastResortSizeA_) && + this.sizeEquals_(sizeB, this.lastResortSizeB_)) { + this.finish_(this.activeCallback_); } else { - // The size has changed. If the size is the same as the original size we assume the font - // failed to load and we fire `inactive`. Otherwise we fire `active`. - if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { - this.finish_(this.inactiveCallback_); - } else { - this.finish_(this.activeCallback_); - } + this.finish_(this.inactiveCallback_); } } else { - // The check_ method is called before the fallback sizes are known. Wait. this.asyncCheck_(); } } else { - if (this.hasTimedOut_()) { - this.finish_(this.inactiveCallback_); - } else if (this.sizeEquals_(sizeA, this.originalSizeA_) && this.sizeEquals_(sizeB, this.originalSizeB_)) { - this.asyncCheck_(); - } else { - this.finish_(this.activeCallback_); - } + this.finish_(this.activeCallback_); } }; diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index 3afd2fe6..d3264331 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -20,8 +20,8 @@ webfont.LastResortWebKitFontWatchRunner = function(activeCallback, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString); this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_(); this.webKitLastResortSizeChange_ = false; - this.lastObservedSizeA_ = this.originalSizeA_; - this.lastObservedSizeB_ = this.originalSizeB_; + this.lastObservedSizeA_ = this.fallbackSizeA_; + this.lastObservedSizeB_ = this.fallbackSizeB_; }; webfont.extendsClass(webfont.FontWatchRunner, webfont.LastResortWebKitFontWatchRunner); From a8854dee717facb378f7f5eba55362d43c453859 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 4 Dec 2012 15:33:22 +0100 Subject: [PATCH 34/66] Fixed lastresortwebkitfontwatchrunnertest. --- src-test/google/lastresortwebkitfontwatchrunnertest.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src-test/google/lastresortwebkitfontwatchrunnertest.js b/src-test/google/lastresortwebkitfontwatchrunnertest.js index d0e5a7c4..0c28d506 100644 --- a/src-test/google/lastresortwebkitfontwatchrunnertest.js +++ b/src-test/google/lastresortwebkitfontwatchrunnertest.js @@ -121,8 +121,7 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontIgnored = this.fontDescription_, false); fontWatchRunner.start(); - - assertEquals(2, this.asyncCount_); + assertEquals(1, this.asyncCount_); // When on webkit time out ends up activating the font. assertEquals(1, this.fontActiveCalled_); @@ -235,6 +234,10 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontInactiveWhenSize height: 4 }; } + return { + width: 2, + height: 2 + }; }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, this.fontDescription_, false); From 8b4c6c6f1ea1e4165232b0f5fd64b3c855932706 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 4 Dec 2012 16:48:17 -0800 Subject: [PATCH 35/66] Insert the null web font just before the measurement is taken This helps to ensure that we're measuring the font when the browser still thinks it's a web font, instead of waiting until the browser knows that the font isn't a valid font. --- src/core/fontwatcher.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 0c37fb9f..dc8e5089 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -47,8 +47,6 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { "}"), ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); - this.domHelper_.insertInto('head', font); - // First we set the font to monospace and the test string to `iii`. Based // on our research, all platforms have at least a monospace, sans-serif, // and serif font installed. By using a test string that has a very @@ -72,6 +70,7 @@ webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { // // See http://code.google.com/p/chromium/issues/detail?id=138257 // for more information on the Chrome Android bug. + this.domHelper_.insertInto('head', font); ruler.setFont("'__webfontloader_test__', monospace, sans-serif"); // Finally we compare the initial width and the current width. If From 4e829cc8aa370543fa58f936ae6b2ea865ef3db9 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 4 Dec 2012 16:51:04 -0800 Subject: [PATCH 36/66] Don't detect or pay attention to last resort sizes unless webkit bug exists We don't want to ignore any sizes other than the fallback size unless the webkit bug is present. --- .../lastresortwebkitfontwatchrunnertest.js | 2 +- src/core/fontwatchrunner.js | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src-test/google/lastresortwebkitfontwatchrunnertest.js b/src-test/google/lastresortwebkitfontwatchrunnertest.js index 0c28d506..13126851 100644 --- a/src-test/google/lastresortwebkitfontwatchrunnertest.js +++ b/src-test/google/lastresortwebkitfontwatchrunnertest.js @@ -121,7 +121,7 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontIgnored = this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(1, this.asyncCount_); + assertEquals(2, this.asyncCount_); // When on webkit time out ends up activating the font. assertEquals(1, this.fontActiveCalled_); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index da590b4c..0d734387 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -26,15 +26,20 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); - this.fontRulerA_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); - this.lastResortSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); - this.fallbackSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - this.fontRulerB_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); - this.lastResortSizeB_ = this.fontRulerB_.getSize(); + + // If the webkit bug is present, get the last resort sizes that we need to + // ignore as well. + if (this.hasWebkitFallbackBug_) { + this.fontRulerA_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); + this.lastResortSizeA_ = this.fontRulerA_.getSize(); + this.fontRulerB_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); + this.lastResortSizeB_ = this.fontRulerB_.getSize(); + } + + this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + this.fallbackSizeA_ = this.fontRulerA_.getSize(); this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); this.fallbackSizeB_ = this.fontRulerB_.getSize(); }; @@ -109,7 +114,7 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeB = this.fontRulerB_.getSize(); if ((this.sizeEquals_(sizeA, this.fallbackSizeA_) && this.sizeEquals_(sizeB, this.fallbackSizeB_)) || - (this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { + (this.hasWebkitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { if (this.hasTimedOut_()) { if (this.hasWebkitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && From ff13db64ab2c62b19fffb7119d14274c4d112e00 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 4 Dec 2012 19:11:41 -0800 Subject: [PATCH 37/66] Fix whitespace (tab to spaces) in DomHelper --- src/core/domhelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/domhelper.js b/src/core/domhelper.js index e98877f8..833df029 100644 --- a/src/core/domhelper.js +++ b/src/core/domhelper.js @@ -28,7 +28,7 @@ webfont.DomHelper.prototype.createElement = function(elem, opt_attr, if (opt_attr.hasOwnProperty(attr)) { if (attr == "style") { this.setStyle(domElement, opt_attr[attr]); - } else { + } else { domElement.setAttribute(attr, opt_attr[attr]); } } From 74c05dcea642b39f12ea749e24c5b313be55dd8b Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 4 Dec 2012 19:21:23 -0800 Subject: [PATCH 38/66] Initial code to combine bug and last resort size detection (needs test fixes) Because we need to know the last resort sizes to ignore, and the last resort sizes can depend on the font stack and text content, we need to actually detect them in the same context to be 100% sure that they'll be the same. This change creates more null fonts on the page (one for each variation that we're detecting), but it seems like these don't stay behind in the console, and they hopefully shouldn't provide too much of a drain performance wise. If they do, we can do additional work to use a single global null font rule for every round of watchers (but since they're time-limited before the browser detects that they don't contain a valid font, we'll need to make a new one for each round of detection). --- src/core/domhelper.js | 59 +++++++++++++++++++++++++++++++++++ src/core/fontwatcher.js | 61 ++----------------------------------- src/core/fontwatchrunner.js | 56 +++++++++++++++++++++++----------- 3 files changed, 99 insertions(+), 77 deletions(-) diff --git a/src/core/domhelper.js b/src/core/domhelper.js index 833df029..57678579 100644 --- a/src/core/domhelper.js +++ b/src/core/domhelper.js @@ -194,3 +194,62 @@ webfont.DomHelper.prototype.hasSupportForStyle_ = function() { } return this.supportForStyle_ }; + +/** + * A counter to ensure that null fonts have unique family names. + * @private + * @type {number} + */ +webfont.DomHelper.nullFontCounter_ = 0; + +/** + * A global place to save created null font style elements until they are + * removed. + * @private + * @type {Object.} + */ +webfont.DomHelper.nullFontStyles_ = {}; + +/** + * Creates a null font style element and inserts it into the head of the page. + * The element can be used to detect the WebKit last resort fallback bug for + * font detection. + * @return {string} Returns the un-quoted font-family name of the new null font + * style rule just inserted into the document (e.g. __webfontloader_test_0__). + */ +webfont.DomHelper.prototype.insertNullFontStyle = function(fontDescription) { + var fontFamily = "__webfontloader_test_" + webfont.DomHelper.nullFontCounter_ + "__"; + webfont.DomHelper.nullFontCounter_++; + + var fvd = new webfont.FontVariationDescription(); + var weightAndStyle = fvd.expand(fontDescription); + + var style = this.createElement('style', null, + "@font-face{" + + "font-family:'" + fontFamily + "';" + + "src:url(data:application/x-font-woff;base64,) format('woff')," + + "url(data:font/truetype;base64,) format('truetype');" + + weightAndStyle + + "}"); + + this.insertInto('head', style); + webfont.DomHelper.nullFontStyles_[fontFamily] = style; + + return fontFamily +}; + +/** + * Removes a previously created null font style from the page, using the + * associated font-family name to locate it. + * @param {string} fontFamily The name of the null font family to remove. + * @return {boolean} Returns true if the null font style element was found and + * removed successfully, and false otherwise. + */ +webfont.DomHelper.prototype.removeNullFontStyle = function(fontFamily) { + var style = webfont.DomHelper.nullFontStyles_[fontFamily]; + if (style) { + return this.removeElement(style); + } else { + return false; + } +}; diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index dc8e5089..74b7cc1a 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -15,7 +15,7 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, this.asyncCall_ = asyncCall; this.getTime_ = getTime; this.currentlyWatched_ = 0; - this.hasWebkitFallbackBug_ = userAgent.getEngine() === 'AppleWebKit' ? this.checkWebkitFallbackBug_() : false; + this.checkWebkitFallbackBug_ = userAgent.getEngine() === 'AppleWebKit'; this.last_ = false; this.success_ = false; }; @@ -26,63 +26,6 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, */ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; -/** - * Returns true if this browser has a bug that causes the font stack - * to not be respected while loading webfonts. - * - * @see https://bugs.webkit.org/show_bug.cgi?id=76684 - * - * @return {boolean} - * @private - */ -webfont.FontWatcher.prototype.checkWebkitFallbackBug_ = function() { - // We build an empty webfont and try to set it as the font for our - // ruler. Even though this will fail (since our webfont is invalid) - // it will actually trigger the Webkit fallback bug. - var font = this.domHelper_.createElement('style', null, - "@font-face{" + - "font-family:'__webfontloader_test__';" + - "src:url(data:application/x-font-woff;base64,) format('woff')," + - "url(data:font/truetype;base64,) format('truetype');" + - "}"), - ruler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, 'iii'); - - // First we set the font to monospace and the test string to `iii`. Based - // on our research, all platforms have at least a monospace, sans-serif, - // and serif font installed. By using a test string that has a very - // narrow width in non-monospace fonts it becomes easy to detect changes - // in width. - ruler.setFont('monospace'); - - ruler.insert(); - - // Measure the original size (of our monospace font) - var beforeWidth = ruler.getSize().width; - - // Set the font to include our fake webfont, and then fallback to - // `monospace` and `sans-serif`. Browsers without the bug will fall - // back on the `monospace` font while loading the webfont, while - // Webkit with the bug will fall back to its last resort font (which - // according to our data is never `monospace`.) The `sans-serif` is - // included here to deal with another bug in Chrome Android where - // instead of using the last resort font it picks the last font in - // the stack. - // - // See http://code.google.com/p/chromium/issues/detail?id=138257 - // for more information on the Chrome Android bug. - this.domHelper_.insertInto('head', font); - ruler.setFont("'__webfontloader_test__', monospace, sans-serif"); - - // Finally we compare the initial width and the current width. If - // they do not match (i.e. it is either the sans-serif font, or - // the last resort font) we assume the bug is present. - var hasBug = beforeWidth !== ruler.getSize().width; - this.domHelper_.removeElement(font); - ruler.remove(); - - return hasBug; -}; - /** * Watches a set of font families. * @param {Array.} fontFamilies The font family names to watch. @@ -127,7 +70,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, this.hasWebkitFallbackBug_, fontTestString); + this.getTime_, fontFamily, fontDescription, this.checkWebkitFallbackBug_, fontTestString); fontWatchRunner.start(); } diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 0d734387..c9f4b4b8 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -8,11 +8,11 @@ * @param {function(): number} getTime * @param {string} fontFamily * @param {string} fontDescription - * @param {boolean} hasWebkitFallbackBug + * @param {boolean} checkWebkitFallbackBug * @param {string=} opt_fontTestString */ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, checkWebkitFallbackBug, opt_fontTestString) { this.activeCallback_ = activeCallback; this.inactiveCallback_ = inactiveCallback; this.domHelper_ = domHelper; @@ -22,26 +22,52 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontFamily_ = fontFamily; this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; - this.hasWebkitFallbackBug_ = hasWebkitFallbackBug; + this.hasWebkitFallbackBug_ = false; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - // If the webkit bug is present, get the last resort sizes that we need to - // ignore as well. - if (this.hasWebkitFallbackBug_) { - this.fontRulerA_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); - this.lastResortSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerB_.setFont(webfont.FontWatchRunner.LAST_RESORT_FONT, this.fontDescription_); - this.lastResortSizeB_ = this.fontRulerB_.getSize(); - } - this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); this.fallbackSizeA_ = this.fontRulerA_.getSize(); this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); this.fallbackSizeB_ = this.fontRulerB_.getSize(); + + // Detect webkit fallback bug and last resort sizes, if present. + if (checkWebkitFallbackBug) { + // We build an empty webfont and try to set it as the font for our ruler. + // Even though this will fail (since our webfont is invalid) it will + // actually trigger the Webkit fallback bug. + var nullFontFamily = this.domHelper_.insertNullFontStyle(this.fontDescription_); + + // Set the font stack to include our fake webfont first, and then the + // respective fallback stacks. Browsers without the bug will fall back to + // the first font in the stack, yielding the same width. Browsers with the + // bug will fall back to the last resort font instead, which should be + // different for at least one of the font stacks. The second generic font + // family name in each font stack is there for Android Webkit, where the + // last resort font is determined by the last font in the stack instead of + // a hard-coded constant. + // + // See http://code.google.com/p/chromium/issues/detail?id=138257 for more + // information on the Chrome Android bug. + this.fontRulerA_.setFont(nullFontFamily + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + this.lastResortSizeA_ = this.fontRulerA_.getSize(); + this.fontRulerB_.setFont(nullFontFamily + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); + this.lastResortSizeB_ = this.fontRulerB_.getSize(); + + // Finally we compare the expected fallback size and the actual fallback + // size. If either do not match, it must mean the last resort font was being + // used instead so we assume the bug is present. + this.hasWebkitFallbackBug_ = !this.sizeEquals_(this.fallbackSizeA_, this.lastResortSizeA_) || !this.sizeEquals_(this.fallbackSizeB_, this.lastResortSizeB_); + + // Clean up the empty webfont that we created and reset the rulers to the + // standard fallback stack. + this.domHelper_.removeNullFontStyle(nullFontFamily); + this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); + } }; /** @@ -56,12 +82,6 @@ webfont.FontWatchRunner.FALLBACK_FONTS_A = "serif,sans-serif"; */ webfont.FontWatchRunner.FALLBACK_FONTS_B = "sans-serif,serif"; -/** - * @type {string} - * @const - */ -webfont.FontWatchRunner.LAST_RESORT_FONT = "''"; - /** * Default test string. Characters are chosen so that their widths vary a lot * between the fonts in the default stacks. We want each fallback stack From 7bfb60d3d913f5915f735c09bc7e5006ab0deb92 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 4 Dec 2012 19:24:45 -0800 Subject: [PATCH 39/66] Chrome console complains about font/truetype MIME type Use font/opentype instead, which doesn't cause complaints. --- src/core/domhelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/domhelper.js b/src/core/domhelper.js index 57678579..64956cd3 100644 --- a/src/core/domhelper.js +++ b/src/core/domhelper.js @@ -228,7 +228,7 @@ webfont.DomHelper.prototype.insertNullFontStyle = function(fontDescription) { "@font-face{" + "font-family:'" + fontFamily + "';" + "src:url(data:application/x-font-woff;base64,) format('woff')," + - "url(data:font/truetype;base64,) format('truetype');" + + "url(data:font/opentype;base64,) format('truetype');" + weightAndStyle + "}"); From baf288200c174cf2eb7d767d64e5fb93f64f95dd Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 5 Dec 2012 13:40:22 +0100 Subject: [PATCH 40/66] Added missing semicolon. --- src/core/domhelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/domhelper.js b/src/core/domhelper.js index 64956cd3..56c205b3 100644 --- a/src/core/domhelper.js +++ b/src/core/domhelper.js @@ -235,7 +235,7 @@ webfont.DomHelper.prototype.insertNullFontStyle = function(fontDescription) { this.insertInto('head', style); webfont.DomHelper.nullFontStyles_[fontFamily] = style; - return fontFamily + return fontFamily; }; /** From 3b47f357f9bea6ddbb567b161a6f83ec9f7736e3 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 5 Dec 2012 13:41:10 +0100 Subject: [PATCH 41/66] Fixed tests. --- src-test/core/fontwatchertest.js | 49 +--------------------------- src-test/core/fontwatchrunnertest.js | 47 +++++++++++++------------- 2 files changed, 26 insertions(+), 70 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index e04e17e1..7b27021d 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -272,53 +272,6 @@ FontWatcherTest.prototype.testWebkitBugDetectionOnlyOnWebkit = function() { var fontWatcher = new webfont.FontWatcher(this.userAgent_, fakeDomHelper, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); - assertEquals(false, fontWatcher.hasWebkitFallbackBug_); + assertEquals(false, fontWatcher.checkWebkitFallbackBug_); assertEquals(false, createElementCalled); }; - -FontWatcherTest.prototype.testWebkitFallbackBugDetectionWithBug = function() { - var userAgent = new webfont.UserAgent('Chrome', '18.0.1271.64', 'AppleWebKit', '537.11', 'Macintosh', '10.6', undefined, true); - var isInitial = true; - var fakeFontSizer = { - getSize: function(el) { - if (isInitial) { - isInitial = false; - // Monospace - return { - width: 1, - height: 1 - }; - } else { - // Something not monospace - return { - width: 2, - height: 2 - }; - } - } - }; - - var fontWatcher = new webfont.FontWatcher(userAgent, this.fakeDomHelper_, this.fakeEventDispatcher_, - fakeFontSizer, this.fakeAsyncCall_, this.fakeGetTime_); - - assertEquals(true, fontWatcher.hasWebkitFallbackBug_); -}; - -FontWatcherTest.prototype.testWebkitFallbackBugDetectionWithoutBug = function() { - var userAgent = new webfont.UserAgent('Chrome', '23.0.1271.64', 'AppleWebKit', '537.11', 'Macintosh', '10.6', undefined, true); - var isInitial = true; - var fakeFontSizer = { - getSize: function(el) { - // Monospace - return { - width: 1, - height: 1 - }; - } - }; - - var fontWatcher = new webfont.FontWatcher(userAgent, this.fakeDomHelper_, this.fakeEventDispatcher_, - fakeFontSizer, this.fakeAsyncCall_, this.fakeGetTime_); - - assertEquals(false, fontWatcher.hasWebkitFallbackBug_); -}; diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index e31a8f8e..1c5ea526 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -57,7 +57,9 @@ FontWatchRunnerTest.prototype.setUp = function() { break; } } - } + }, + insertNullFontStyle: function () { return '__webfontloader_test_0'; }, + removeNullFontStyle: function () { return true; } }; this.timesToCheckSizesBeforeChange_ = 0; @@ -142,16 +144,17 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { - // Return the default width + } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { + // Return the last resort width return { - width: 1, - height: 1 + width: 2, + height: 2 }; } else { + // Return the default width return { - width: 2, - height: 2 + width: 1, + height: 1 }; } } @@ -174,15 +177,15 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 1 }; } - } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { + } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { return { - width: 1, - height: 1 + width: 2, + height: 2 }; } else { return { - width: 2, - height: 2 + width: 1, + height: 1 }; } } @@ -206,16 +209,16 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 2 }; } - } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { + } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { // Return the default width return { - width: 1, - height: 1 + width: 2, + height: 2 }; } else { return { - width: 2, - height: 2 + width: 1, + height: 1 }; } } @@ -238,15 +241,15 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily.indexOf('sans-serif') !== -1) { + } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { return { - width: 1, - height: 1 + width: 2, + height: 2 }; } else { return { - width: 2, - height: 2 + width: 1, + height: 1 }; } } From 7d7edc35b106bf533dca88f8538df6253424b5b7 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 5 Dec 2012 14:08:04 +0100 Subject: [PATCH 42/66] Added test for insertNullFontStyle. --- src-test/core/domhelpertest.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src-test/core/domhelpertest.js b/src-test/core/domhelpertest.js index 34d5095b..5ea147ac 100644 --- a/src-test/core/domhelpertest.js +++ b/src-test/core/domhelpertest.js @@ -106,3 +106,13 @@ DomHelperTest.prototype.testHasSupportForStyle = function() { this.domHelper_.supportForStyle_ = true; assertTrue(this.domHelper_.hasSupportForStyle_()); }; + +DomHelperTest.prototype.testInsertNullFontStyle = function() { + var counter = webfont.DomHelper.nullFontCounter_, + name = this.domHelper_.insertNullFontStyle(''); + + assertNotNull(name); + assertEquals(name, '__webfontloader_test_' + counter + '__'); + assertNotEquals(counter, webfont.DomHelper.nullFontCounter_); + assertNotNull(webfont.DomHelper.nullFontStyles_[name]); +}; From e2dde82508515b61cc1cdbc64ca688d381727e78 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 6 Dec 2012 14:47:46 -0800 Subject: [PATCH 43/66] Only detect webkit fallback bug for older versions that may have it --- src-test/core/fontwatchertest.js | 30 ++++++++++++++++++++---------- src/core/fontwatcher.js | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 7b27021d..245e60f8 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -67,7 +67,7 @@ FontWatcherTest.prototype.setUp = function() { this.testStringCount_ = 0; this.testStrings_ = {}; webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, checkWebkitFallbackBug, opt_fontTestString) { if (opt_fontTestString) { self.testStringCount_++; self.testStrings_[fontFamily] = opt_fontTestString; @@ -262,16 +262,26 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { assertEquals('testString3', this.testStrings_['fontFamily3']); }; -FontWatcherTest.prototype.testWebkitBugDetectionOnlyOnWebkit = function() { - var createElementCalled = false; - var fakeDomHelper = { - createElement: function() { - createElementCalled = true; - } - }; - var fontWatcher = new webfont.FontWatcher(this.userAgent_, fakeDomHelper, this.fakeEventDispatcher_, +FontWatcherTest.prototype.testNoWebkitBugDetectionOnNonWebkit = function() { + var ua = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); + var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); assertEquals(false, fontWatcher.checkWebkitFallbackBug_); - assertEquals(false, createElementCalled); +}; + +FontWatcherTest.prototype.testNoWebkitBugDetectionOnNewWebkit = function() { + var ua = new webfont.UserAgent('Safari', '6.0.2', 'AppleWebKit', '537.6.17', 'Macintosh', '10_7_5', undefined, true); + var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, + this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); + + assertEquals(false, fontWatcher.checkWebkitFallbackBug_); +}; + +FontWatcherTest.prototype.testYesWebkitBugDetectionOnOlderWebkit = function() { + var ua = new webfont.UserAgent('Chrome', '16.0.912.75', 'AppleWebKit', '535.7', 'Android', '4.0.3', undefined, true); + var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, + this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); + + assertEquals(true, fontWatcher.checkWebkitFallbackBug_); }; diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 74b7cc1a..565c28a1 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -15,9 +15,22 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, this.asyncCall_ = asyncCall; this.getTime_ = getTime; this.currentlyWatched_ = 0; - this.checkWebkitFallbackBug_ = userAgent.getEngine() === 'AppleWebKit'; this.last_ = false; this.success_ = false; + + // There's a bug in WebKit that affects font watching in versions before + // 536.11. We only attempt to detect the bug in browsers that might have it, + // so that detection is simpler and does less work in more recent browsers. + // For more detail on the bug and our detection/workaround, see the code and + // comments in fontwatchrunner.js. + this.checkWebkitFallbackBug_ = false; + if (userAgent.getEngine() === 'AppleWebKit') { + var version = userAgent.getEngineVersion(); + var parts = version.split("."); + var major = parseInt(parts[0], 10) || 0; + var minor = parseInt(parts[1], 10) || 0; + this.checkWebkitFallbackBug_ = major < 536 || (major == 536 && minor < 11); + } }; /** From f822fd70eb47a8a3f69ccbe312194972f92a747c Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 13 Dec 2012 00:06:42 +0100 Subject: [PATCH 44/66] First pass at moving browser information into a separate object. --- src-test/core/fonttest.js | 11 ++++++++-- src/core/useragent.js | 24 ++++++++++++++++++---- src/core/useragentparser.js | 41 ++++++++++++++++++++----------------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src-test/core/fonttest.js b/src-test/core/fonttest.js index d304660c..0b28decd 100644 --- a/src-test/core/fonttest.js +++ b/src-test/core/fonttest.js @@ -5,8 +5,12 @@ FontTest.prototype.setUp = function() { }; FontTest.prototype.testFontLoad = function() { + var browserInfo = {}; + + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = true; + var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', - 'Macintosh', '10.6', undefined, true); + 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(window, this.fontModuleLoader_, function(func, timeout) { func(); }, userAgent); var testModule = null; @@ -59,9 +63,12 @@ FontTest.prototype.testFontLoad = function() { FontTest.prototype.testFontLoadWithContext = function() { var fakeMainWindow = {}; + var browserInfo = {}; + + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = true; var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', - 'Macintosh', '10.6', undefined, true); + 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(fakeMainWindow, this.fontModuleLoader_, function(func, timeout) { func(); }, userAgent); var testModule = null; diff --git a/src/core/useragent.js b/src/core/useragent.js index 291f6051..467f0dc2 100644 --- a/src/core/useragent.js +++ b/src/core/useragent.js @@ -6,11 +6,11 @@ * @param {string} platform * @param {string} platformVersion * @param {number|undefined} documentMode - * @param {boolean} webFontSupport + * @param {Object.} browserInfo * @constructor */ webfont.UserAgent = function(name, version, engine, engineVersion, platform, - platformVersion, documentMode, webFontSupport) { + platformVersion, documentMode, browserInfo) { this.name_ = name; this.version_ = version; this.engine_ = engine; @@ -18,7 +18,15 @@ webfont.UserAgent = function(name, version, engine, engineVersion, platform, this.platform_ = platform; this.platformVersion_ = platformVersion; this.documentMode_ = documentMode; - this.webFontSupport_ = webFontSupport; + this.browserInfo_ = browserInfo || {}; +}; + +/** + * @enum {number} + */ +webfont.UserAgent.BrowserInfo = { + HAS_WEBFONT_SUPPORT: 1, + WEBKIT_FALLBACK_BUG: 2 }; /** @@ -28,6 +36,14 @@ webfont.UserAgent.prototype.getName = function() { return this.name_; }; +/** + * @param {webfont.UserAgent.BrowserInfo} property + * @return {boolean} + */ +webfont.UserAgent.prototype.getInfo = function(property) { + return !!this.browserInfo_[property]; +}; + /** * @return {string} */ @@ -74,5 +90,5 @@ webfont.UserAgent.prototype.getDocumentMode = function() { * @return {boolean} */ webfont.UserAgent.prototype.isSupportingWebFont = function() { - return this.webFontSupport_; + return this.getInfo(webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT); }; diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index f5ebe945..255cdedd 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -25,7 +25,7 @@ webfont.UserAgentParser.UNKNOWN_USER_AGENT = new webfont.UserAgent( webfont.UserAgentParser.UNKNOWN, webfont.UserAgentParser.UNKNOWN, undefined, - false); + {}); /** * Parses the user agent string and returns an object. @@ -113,6 +113,7 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { var platformVersion = this.getPlatformVersion_(); var browser = this.getMatchingGroup_(this.userAgent_, /(MSIE [\d\w\.]+)/, 1); + var browserInfo = {}; if (browser != "") { var pair = browser.split(' '); @@ -121,17 +122,16 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { var majorVersion = this.getMajorVersion_(version); var majorPlatformVersion = this.getMajorVersion_(platformVersion); - var supportWebFont = (platform == "Windows" && majorVersion >= 6) || + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = (platform == "Windows" && majorVersion >= 6) || (platform == "Windows Phone" && majorPlatformVersion >= 8); return new webfont.UserAgent(name, version, name, version, - platform, platformVersion, this.getDocumentMode_(this.doc_), - supportWebFont); + platform, platformVersion, this.getDocumentMode_(this.doc_), browserInfo); } return new webfont.UserAgent("MSIE", webfont.UserAgentParser.UNKNOWN, "MSIE", webfont.UserAgentParser.UNKNOWN, - platform, platformVersion, this.getDocumentMode_(this.doc_), false); + platform, platformVersion, this.getDocumentMode_(this.doc_), {}); }; /** @@ -149,6 +149,7 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var engineVersion = webfont.UserAgentParser.UNKNOWN; var enginePair = this.getMatchingGroup_(this.userAgent_, /(Presto\/[\d\w\.]+)/, 1); + var browserInfo = {}; if (enginePair != "") { var splittedEnginePair = enginePair.split('/'); @@ -176,7 +177,7 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { return new webfont.UserAgent("OperaMini", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), false); + this.getDocumentMode_(this.doc_), browserInfo); } // Otherwise, find version information for normal Opera or Opera Mobile @@ -184,21 +185,23 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var version = this.getMatchingGroup_(this.userAgent_, /Version\/([\d\.]+)/, 1); if (version != "") { + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) >= 10; return new webfont.UserAgent("Opera", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), this.getMajorVersion_(version) >= 10); + this.getDocumentMode_(this.doc_), browserInfo); } } var version = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1); if (version != "") { + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) >= 10; return new webfont.UserAgent("Opera", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), this.getMajorVersion_(version) >= 10); + this.getDocumentMode_(this.doc_), browserInfo); } return new webfont.UserAgent("Opera", webfont.UserAgentParser.UNKNOWN, engineName, engineVersion, this.getPlatform_(), - this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), false); + this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), browserInfo); }; /** @@ -216,6 +219,7 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { var platformVersion = this.getPlatformVersion_(); var webKitVersion = this.getMatchingGroup_(this.userAgent_, /AppleWebKit\/([\d\.\+]+)/, 1); + var browserInfo = {}; if (webKitVersion == "") { webKitVersion = webfont.UserAgentParser.UNKNOWN; @@ -241,19 +245,18 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { version = this.getMatchingGroup_(this.userAgent_, /AdobeAIR\/([\d\.]+)/, 1); } - var supportWebFont = false; if (name == "AdobeAIR") { var minor = this.getMatchingGroup_(version, /\d+\.(\d+)/, 1); - supportWebFont = this.getMajorVersion_(version) > 2 || + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) > 2 || this.getMajorVersion_(version) == 2 && parseInt(minor, 10) >= 5; } else { var minor = this.getMatchingGroup_(webKitVersion, /\d+\.(\d+)/, 1); - supportWebFont = this.getMajorVersion_(webKitVersion) >= 526 || + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(webKitVersion) >= 526 || this.getMajorVersion_(webKitVersion) >= 525 && parseInt(minor, 10) >= 13; } return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersion, - platform, platformVersion, this.getDocumentMode_(this.doc_), supportWebFont); + platform, platformVersion, this.getDocumentMode_(this.doc_), browserInfo); }; /** @@ -269,7 +272,7 @@ webfont.UserAgentParser.prototype.isGecko_ = function() { webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { var name = webfont.UserAgentParser.UNKNOWN; var version = webfont.UserAgentParser.UNKNOWN; - var supportWebFont = false; + var browserInfo = {}; if (this.userAgent_.indexOf("Firefox") != -1) { name = "Firefox"; @@ -280,7 +283,8 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { var minor = this.getMatchingGroup_(versionNum, /\d+\.(\d+)/, 1); version = versionNum; - supportWebFont = versionNum != "" && this.getMajorVersion_(versionNum) >= 3 && + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = versionNum != "" && + this.getMajorVersion_(versionNum) >= 3 && parseInt(minor, 10) >= 5; } } else if (this.userAgent_.indexOf("Mozilla") != -1) { @@ -291,12 +295,12 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { if (geckoVersion == "") { geckoVersion = webfont.UserAgentParser.UNKNOWN; } else { - if (!supportWebFont) { + if (!browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT]) { var majorVersion = this.getMajorVersion_(geckoVersion); var intMinorVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.(\d+)/, 1), 10); var subVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.\d+\.(\d+)/, 1), 10); - supportWebFont = majorVersion > 1 || + browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = majorVersion > 1 || majorVersion == 1 && intMinorVersion > 9 || majorVersion == 1 && intMinorVersion == 9 && subVersion >= 2 || geckoVersion.match(/1\.9\.1b[123]/) != null || @@ -304,8 +308,7 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { } } return new webfont.UserAgent(name, version, "Gecko", geckoVersion, - this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), - supportWebFont); + this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), browserInfo); }; /** From cd93994541b39ec8bf38d56c65119052d4e0725a Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 17 Dec 2012 11:39:31 +0100 Subject: [PATCH 45/66] Changed BrowserInfo enum to a real class. --- src-test/core/fonttest.js | 10 ++----- src/core/browserinfo.js | 32 ++++++++++++++++++++++ src/core/useragent.js | 29 +++++++------------- src/core/useragentparser.js | 53 ++++++++++++++++--------------------- src/modules.yml | 1 + webfontloader.gemspec | 1 + 6 files changed, 69 insertions(+), 57 deletions(-) create mode 100644 src/core/browserinfo.js diff --git a/src-test/core/fonttest.js b/src-test/core/fonttest.js index 0b28decd..e30b0e85 100644 --- a/src-test/core/fonttest.js +++ b/src-test/core/fonttest.js @@ -5,10 +5,7 @@ FontTest.prototype.setUp = function() { }; FontTest.prototype.testFontLoad = function() { - var browserInfo = {}; - - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = true; - + var browserInfo = new webfont.BrowserInfo(true, false, false); var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(window, this.fontModuleLoader_, @@ -63,10 +60,7 @@ FontTest.prototype.testFontLoad = function() { FontTest.prototype.testFontLoadWithContext = function() { var fakeMainWindow = {}; - var browserInfo = {}; - - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = true; - + var browserInfo = new webfont.BrowserInfo(true, false, false); var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(fakeMainWindow, this.fontModuleLoader_, diff --git a/src/core/browserinfo.js b/src/core/browserinfo.js new file mode 100644 index 00000000..0810dd11 --- /dev/null +++ b/src/core/browserinfo.js @@ -0,0 +1,32 @@ +/** + * @constructor + * @param {boolean} webfontSupport + * @param {boolean} webkitFallbackBug + * @param {boolean} androidFallbackBug + */ +webfont.BrowserInfo = function (webfontSupport, webkitFallbackBug, androidFallbackBug) { + this.webfontSupport_ = webfontSupport; + this.webkitFallbackBug_ = webkitFallbackBug; + this.androidFallbackBug_ = androidFallbackBug; +}; + +/** + * @return {boolean} + */ +webfont.BrowserInfo.prototype.hasWebfontSupport = function () { + return this.webfontSupport_; +}; + +/** + * @return {boolean} + */ +webfont.BrowserInfo.prototype.hasWebkitFallbackBug = function () { + return this.webkitFallbackBug_; +}; + +/** + * @return {boolean} + */ +webfont.BrowserInfo.prototype.hasAndroidFallbackBug = function () { + return this.androidFallbackBug_; +}; diff --git a/src/core/useragent.js b/src/core/useragent.js index 467f0dc2..adc6d9f5 100644 --- a/src/core/useragent.js +++ b/src/core/useragent.js @@ -6,7 +6,7 @@ * @param {string} platform * @param {string} platformVersion * @param {number|undefined} documentMode - * @param {Object.} browserInfo + * @param {!webfont.BrowserInfo} browserInfo * @constructor */ webfont.UserAgent = function(name, version, engine, engineVersion, platform, @@ -18,15 +18,7 @@ webfont.UserAgent = function(name, version, engine, engineVersion, platform, this.platform_ = platform; this.platformVersion_ = platformVersion; this.documentMode_ = documentMode; - this.browserInfo_ = browserInfo || {}; -}; - -/** - * @enum {number} - */ -webfont.UserAgent.BrowserInfo = { - HAS_WEBFONT_SUPPORT: 1, - WEBKIT_FALLBACK_BUG: 2 + this.browserInfo_ = browserInfo; }; /** @@ -36,14 +28,6 @@ webfont.UserAgent.prototype.getName = function() { return this.name_; }; -/** - * @param {webfont.UserAgent.BrowserInfo} property - * @return {boolean} - */ -webfont.UserAgent.prototype.getInfo = function(property) { - return !!this.browserInfo_[property]; -}; - /** * @return {string} */ @@ -86,9 +70,16 @@ webfont.UserAgent.prototype.getDocumentMode = function() { return this.documentMode_; }; +/** + * @return {webfont.BrowserInfo} + */ +webfont.UserAgent.prototype.getBrowserInfo = function() { + return this.browserInfo_; +}; + /** * @return {boolean} */ webfont.UserAgent.prototype.isSupportingWebFont = function() { - return this.getInfo(webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT); + return this.browserInfo_.hasWebfontSupport(); }; diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index b055226e..3f3846b1 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -35,7 +35,7 @@ webfont.UserAgentParser.UNKNOWN_USER_AGENT = new webfont.UserAgent( webfont.UserAgentParser.UNKNOWN, webfont.UserAgentParser.UNKNOWN, undefined, - {}); + new webfont.BrowserInfo(false, false, false)); /** * Parses the user agent string and returns an object. @@ -131,7 +131,6 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { var platformVersion = this.getPlatformVersion_(); var browser = this.getMatchingGroup_(this.userAgent_, /(MSIE [\d\w\.]+)/, 1); - var browserInfo = {}; if (browser != "") { var pair = browser.split(' '); @@ -139,17 +138,16 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { var version = pair[1]; var majorVersion = this.getMajorVersion_(version); var majorPlatformVersion = this.getMajorVersion_(platformVersion); - - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = (platform == "Windows" && majorVersion >= 6) || + var supportWebFont = (platform == "Windows" && majorVersion >= 6) || (platform == "Windows Phone" && majorPlatformVersion >= 8); return new webfont.UserAgent(name, version, name, version, - platform, platformVersion, this.getDocumentMode_(this.doc_), browserInfo); + platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); } return new webfont.UserAgent("MSIE", webfont.UserAgentParser.UNKNOWN, "MSIE", webfont.UserAgentParser.UNKNOWN, - platform, platformVersion, this.getDocumentMode_(this.doc_), {}); + platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); }; /** @@ -167,7 +165,6 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var engineVersion = webfont.UserAgentParser.UNKNOWN; var enginePair = this.getMatchingGroup_(this.userAgent_, /(Presto\/[\d\w\.]+)/, 1); - var browserInfo = {}; if (enginePair != "") { var splittedEnginePair = enginePair.split('/'); @@ -195,7 +192,7 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { return new webfont.UserAgent("OperaMini", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), browserInfo); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); } // Otherwise, find version information for normal Opera or Opera Mobile @@ -203,23 +200,21 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var version = this.getMatchingGroup_(this.userAgent_, /Version\/([\d\.]+)/, 1); if (version != "") { - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) >= 10; return new webfont.UserAgent("Opera", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), browserInfo); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(this.getMajorVersion_(version) >= 10, false, false)); } } var version = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1); if (version != "") { - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) >= 10; return new webfont.UserAgent("Opera", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), browserInfo); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(this.getMajorVersion_(version) >= 10, false, false)); } return new webfont.UserAgent("Opera", webfont.UserAgentParser.UNKNOWN, engineName, engineVersion, this.getPlatform_(), - this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), browserInfo); + this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); }; /** @@ -237,7 +232,7 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { var platformVersion = this.getPlatformVersion_(); var webKitVersion = this.getMatchingGroup_(this.userAgent_, /AppleWebKit\/([\d\.\+]+)/, 1); - var browserInfo = {}; + var supportWebFont = false; if (webKitVersion == "") { webKitVersion = webfont.UserAgentParser.UNKNOWN; @@ -269,20 +264,18 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { } if (name == "AdobeAIR") { var minor = this.getMatchingGroup_(version, /\d+\.(\d+)/, 1); - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(version) > 2 || - this.getMajorVersion_(version) == 2 && parseInt(minor, 10) >= 5; + supportWebFont = this.getMajorVersion_(version) > 2 || this.getMajorVersion_(version) == 2 && parseInt(minor, 10) >= 5; } else if (platform == "BlackBerry") { supportWebFont = parseInt(platformVersion, 10) >= 10; } else if (platform == "Android") { supportWebFont = parseFloat(platformVersion) > 2.1; } else { var minor = this.getMatchingGroup_(webKitVersion, /\d+\.(\d+)/, 1); - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = this.getMajorVersion_(webKitVersion) >= 526 || - this.getMajorVersion_(webKitVersion) >= 525 && parseInt(minor, 10) >= 13; + supportWebFont = this.getMajorVersion_(webKitVersion) >= 526 || this.getMajorVersion_(webKitVersion) >= 525 && parseInt(minor, 10) >= 13; } return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersion, - platform, platformVersion, this.getDocumentMode_(this.doc_), browserInfo); + platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); }; /** @@ -298,7 +291,7 @@ webfont.UserAgentParser.prototype.isGecko_ = function() { webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { var name = webfont.UserAgentParser.UNKNOWN; var version = webfont.UserAgentParser.UNKNOWN; - var browserInfo = {}; + var supportWebFont = false;; if (this.userAgent_.indexOf("Firefox") != -1) { name = "Firefox"; @@ -309,9 +302,9 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { var minor = this.getMatchingGroup_(versionNum, /\d+\.(\d+)/, 1); version = versionNum; - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = versionNum != "" && - this.getMajorVersion_(versionNum) >= 3 && - parseInt(minor, 10) >= 5; + supportWebFont = versionNum != "" && + this.getMajorVersion_(versionNum) >= 3 && + parseInt(minor, 10) >= 5; } } else if (this.userAgent_.indexOf("Mozilla") != -1) { name = "Mozilla"; @@ -321,20 +314,20 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { if (geckoVersion == "") { geckoVersion = webfont.UserAgentParser.UNKNOWN; } else { - if (!browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT]) { + if (!supportWebFont) { var majorVersion = this.getMajorVersion_(geckoVersion); var intMinorVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.(\d+)/, 1), 10); var subVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.\d+\.(\d+)/, 1), 10); - browserInfo[webfont.UserAgent.BrowserInfo.HAS_WEBFONT_SUPPORT] = majorVersion > 1 || - majorVersion == 1 && intMinorVersion > 9 || - majorVersion == 1 && intMinorVersion == 9 && subVersion >= 2 || - geckoVersion.match(/1\.9\.1b[123]/) != null || - geckoVersion.match(/1\.9\.1\.[\d\.]+/) != null; + supportWebFont = majorVersion > 1 || + majorVersion == 1 && intMinorVersion > 9 || + majorVersion == 1 && intMinorVersion == 9 && subVersion >= 2 || + geckoVersion.match(/1\.9\.1b[123]/) != null || + geckoVersion.match(/1\.9\.1\.[\d\.]+/) != null; } } return new webfont.UserAgent(name, version, "Gecko", geckoVersion, - this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), browserInfo); + this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); }; /** diff --git a/src/modules.yml b/src/modules.yml index f6283437..93412031 100644 --- a/src/modules.yml +++ b/src/modules.yml @@ -1,6 +1,7 @@ core: - core/namespace.js - core/domhelper.js + - core/browserinfo.js - core/useragent.js - core/useragentparser.js - core/eventdispatcher.js diff --git a/webfontloader.gemspec b/webfontloader.gemspec index dab0e62e..fa2fb118 100644 --- a/webfontloader.gemspec +++ b/webfontloader.gemspec @@ -142,6 +142,7 @@ DESC src/core/namespace.js src/core/useragent.js src/core/useragentparser.js + src/core/browserinfo.js src/custom/customcss.js src/fontdeck/fontdeck_script.js src/google/fontapiparser.js From a0063b52838b660c1b6917bba4ccaac21ecfad33 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 17 Dec 2012 11:48:49 +0100 Subject: [PATCH 46/66] UserAgent parameters are not optional. --- src-test/core/fonttest.js | 3 ++- src-test/monotype/monotype_script_test.js | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src-test/core/fonttest.js b/src-test/core/fonttest.js index e30b0e85..095b7bf8 100644 --- a/src-test/core/fonttest.js +++ b/src-test/core/fonttest.js @@ -92,7 +92,8 @@ FontTest.prototype.testFontLoadWithContext = function() { }; FontTest.prototype.testFontInactive = function() { - var userAgent = new webfont.UserAgent('Firefox', '3.0', false); + var userAgent = new webfont.UserAgent('Firefox', '3.0', 'Gecko', '1.9.2', + 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false, false)); var font = new webfont.WebFont(window, this.fontModuleLoader_, function(func, timeout) { func(); }, userAgent); var testModule; diff --git a/src-test/monotype/monotype_script_test.js b/src-test/monotype/monotype_script_test.js index fff8932a..dec332d8 100644 --- a/src-test/monotype/monotype_script_test.js +++ b/src-test/monotype/monotype_script_test.js @@ -45,7 +45,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () { return null; } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", true); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); monotypeScript.load(function (fontFamilies) { @@ -107,7 +107,7 @@ MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () { return null; } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", true); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); monotypeScript.load(function (fontFamilies) { @@ -181,7 +181,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurl = function () { } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", true); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); @@ -243,7 +243,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurlAndTheScriptUrlH } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", true); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); @@ -291,7 +291,7 @@ MonotypeScriptTest.prototype.testWithoutProjectId = function () { }; var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", true); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); From 8770cb90030fa8009466b9c839eecace1ed2b20a Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 17 Dec 2012 12:08:43 +0100 Subject: [PATCH 47/66] Removed UserAgent.isSupportingWebFont method. --- src-test/core/useragenttest.js | 88 ++++++++++++++++----------------- src/ascender/ascender_script.js | 2 +- src/core/browserinfo.js | 2 +- src/core/font.js | 2 +- src/core/initialize.js | 3 +- src/core/useragent.js | 7 --- src/custom/customcss.js | 2 +- src/google/googlefontapi.js | 2 +- src/monotype/monotype_script.js | 2 +- 9 files changed, 52 insertions(+), 58 deletions(-) diff --git a/src-test/core/useragenttest.js b/src-test/core/useragenttest.js index 566af72f..75692091 100644 --- a/src-test/core/useragenttest.js +++ b/src-test/core/useragenttest.js @@ -17,7 +17,7 @@ UserAgentTest.prototype.testBrowserIsAir = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.9", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsUnsupportedAir = function() { @@ -33,7 +33,7 @@ UserAgentTest.prototype.testBrowserIsUnsupportedAir = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.9", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsFirefox = function() { @@ -49,7 +49,7 @@ UserAgentTest.prototype.testBrowserIsFirefox = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.9.2.3", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsFirefox4beta = function() { @@ -65,7 +65,7 @@ UserAgentTest.prototype.testBrowserIsFirefox4beta = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("2.0b1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsChrome = function() { @@ -81,7 +81,7 @@ UserAgentTest.prototype.testBrowserIsChrome = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("533.2", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsChromeOS = function() { @@ -97,7 +97,7 @@ UserAgentTest.prototype.testBrowserIsChromeOS = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("535.19", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsSafari = function() { @@ -113,7 +113,7 @@ UserAgentTest.prototype.testBrowserIsSafari = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.21.8", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIE = function() { @@ -129,7 +129,7 @@ UserAgentTest.prototype.testBrowserIsIE = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("7.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIEMinimal = function() { @@ -145,7 +145,7 @@ UserAgentTest.prototype.testBrowserIsIEMinimal = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("7.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIEOnWindowsPhone = function() { @@ -161,7 +161,7 @@ UserAgentTest.prototype.testBrowserIsIEOnWindowsPhone = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("10.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIEOnOldWindowsPhone = function() { @@ -177,7 +177,7 @@ UserAgentTest.prototype.testBrowserIsIEOnOldWindowsPhone = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("9.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPhone = function() { @@ -193,7 +193,7 @@ UserAgentTest.prototype.testBrowserIsIPhone = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("528.18", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsAndroid = function() { @@ -209,7 +209,7 @@ UserAgentTest.prototype.testBrowserIsAndroid = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("533.1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOldUnsupportedAndroid = function() { @@ -225,7 +225,7 @@ UserAgentTest.prototype.testBrowserIsOldUnsupportedAndroid = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("530.17", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsAndroidChromeMobile = function() { @@ -241,7 +241,7 @@ UserAgentTest.prototype.testBrowserIsAndroidChromeMobile = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("535.7", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsAndroidFirefox = function() { @@ -259,7 +259,7 @@ UserAgentTest.prototype.testBrowserIsAndroidFirefox = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("13.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); } UserAgentTest.prototype.testBrowserIsFirefoxLettersVersion = function() { @@ -275,7 +275,7 @@ UserAgentTest.prototype.testBrowserIsFirefoxLettersVersion = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.9.2a1pre", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsFirefoxNoVersion = function() { @@ -291,7 +291,7 @@ UserAgentTest.prototype.testBrowserIsFirefoxNoVersion = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.8.1.19", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIELetterVersion = function() { @@ -307,7 +307,7 @@ UserAgentTest.prototype.testBrowserIsIELetterVersion = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("7.0b", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOpera = function() { @@ -323,7 +323,7 @@ UserAgentTest.prototype.testBrowserIsOpera = function() { assertEquals("Presto", userAgent.getEngine()); assertEquals("2.5.22", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOperaFirefoxInUAString = function() { @@ -339,7 +339,7 @@ UserAgentTest.prototype.testBrowserIsOperaFirefoxInUAString = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.8.1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOperaBeforeVersion10 = function() { @@ -355,7 +355,7 @@ UserAgentTest.prototype.testBrowserIsOperaBeforeVersion10 = function() { assertEquals("Presto", userAgent.getEngine()); assertEquals("2.1.1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOperaMobileAndroid = function() { @@ -374,7 +374,7 @@ UserAgentTest.prototype.testBrowserIsOperaMobileAndroid = function() { assertEquals("Presto", userAgent.getEngine()); assertEquals("2.10.254", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsOperaMiniAndroid = function() { @@ -394,7 +394,7 @@ UserAgentTest.prototype.testBrowserIsOperaMiniAndroid = function() { assertEquals("Presto", userAgent.getEngine()); assertEquals("2.8.119", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); } UserAgentTest.prototype.testBrowserIsIEOnMac = function() { @@ -410,7 +410,7 @@ UserAgentTest.prototype.testBrowserIsIEOnMac = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("5.23", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPad = function() { @@ -426,7 +426,7 @@ UserAgentTest.prototype.testBrowserIsIPad = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.21.10", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPadAlt = function() { @@ -442,7 +442,7 @@ UserAgentTest.prototype.testBrowserIsIPadAlt = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.21.10", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPadWithoutIPhone = function() { @@ -458,7 +458,7 @@ UserAgentTest.prototype.testBrowserIsIPadWithoutIPhone = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("531.21.10", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPadChrome = function() { @@ -474,7 +474,7 @@ UserAgentTest.prototype.testBrowserIsIPadChrome = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("534.46.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); } UserAgentTest.prototype.testBrowserIsIPod = function() { @@ -490,7 +490,7 @@ UserAgentTest.prototype.testBrowserIsIPod = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("525.18.1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPodSafari = function() { @@ -506,7 +506,7 @@ UserAgentTest.prototype.testBrowserIsIPodSafari = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("528.18", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIPodChrome = function() { @@ -522,7 +522,7 @@ UserAgentTest.prototype.testBrowserIsIPodChrome = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("534.46.0", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); } UserAgentTest.prototype.testBrowserIsSafariWithPlusVersion = function() { @@ -538,7 +538,7 @@ UserAgentTest.prototype.testBrowserIsSafariWithPlusVersion = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("528.4+", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserIsIEWithTridentVersion = function() { @@ -554,7 +554,7 @@ UserAgentTest.prototype.testBrowserIsIEWithTridentVersion = function() { assertEquals("MSIE", userAgent.getEngine()); assertEquals("8.0", userAgent.getEngineVersion()); assertEquals(8, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; // Invented user agent strings @@ -571,7 +571,7 @@ UserAgentTest.prototype.testBrowserGeckoShouldSupportWebFont = function() { assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.9.1.4", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoNotExistingVersionShouldSupportWebFont = function() { @@ -587,7 +587,7 @@ UserAgentTest.prototype.testBrowserGeckoNotExistingVersionShouldSupportWebFont = assertEquals("Gecko", userAgent.getEngine()); assertEquals("2.5.8", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoVer110ShouldSupportWebFont = function() { @@ -603,7 +603,7 @@ UserAgentTest.prototype.testBrowserGeckoVer110ShouldSupportWebFont = function() assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.10.1b", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoWeirdVerShouldNotSupportWebFont = function() { @@ -619,7 +619,7 @@ UserAgentTest.prototype.testBrowserGeckoWeirdVerShouldNotSupportWebFont = functi assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.b", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoYetAnotherWeirdVerShouldNotSupportWebFont = function() { @@ -635,7 +635,7 @@ UserAgentTest.prototype.testBrowserGeckoYetAnotherWeirdVerShouldNotSupportWebFon assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.b", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoNoSubVerShouldNotSupportWebFont = function() { @@ -651,7 +651,7 @@ UserAgentTest.prototype.testBrowserGeckoNoSubVerShouldNotSupportWebFont = functi assertEquals("Gecko", userAgent.getEngine()); assertEquals("1.9", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoHighMinorVerShouldNotSupportWebFont = function() { @@ -667,7 +667,7 @@ UserAgentTest.prototype.testBrowserGeckoHighMinorVerShouldNotSupportWebFont = fu assertEquals("Gecko", userAgent.getEngine()); assertEquals("0.10.1", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserGeckoHighSubVerShouldNotSupportWebFont = function() { @@ -683,7 +683,7 @@ UserAgentTest.prototype.testBrowserGeckoHighSubVerShouldNotSupportWebFont = func assertEquals("Gecko", userAgent.getEngine()); assertEquals("0.3.42", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserBBSupportWebfont = function() { @@ -699,7 +699,7 @@ UserAgentTest.prototype.testBrowserBBSupportWebfont = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("537.3+", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); }; UserAgentTest.prototype.testBrowserBBNotSupportWebfont = function() { @@ -715,5 +715,5 @@ UserAgentTest.prototype.testBrowserBBNotSupportWebfont = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("534.11+", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertFalse(userAgent.isSupportingWebFont()); + assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; diff --git a/src/ascender/ascender_script.js b/src/ascender/ascender_script.js index 121214e6..6ccecc30 100644 --- a/src/ascender/ascender_script.js +++ b/src/ascender/ascender_script.js @@ -28,7 +28,7 @@ webfont.AscenderScript.VARIATIONS = { }; webfont.AscenderScript.prototype.supportUserAgent = function(userAgent, support) { - return support(userAgent.isSupportingWebFont()); + return support(userAgent.getBrowserInfo().hasWebFontSupport()); }; webfont.AscenderScript.prototype.load = function(onReady) { diff --git a/src/core/browserinfo.js b/src/core/browserinfo.js index 0810dd11..1b3c4a89 100644 --- a/src/core/browserinfo.js +++ b/src/core/browserinfo.js @@ -13,7 +13,7 @@ webfont.BrowserInfo = function (webfontSupport, webkitFallbackBug, androidFallba /** * @return {boolean} */ -webfont.BrowserInfo.prototype.hasWebfontSupport = function () { +webfont.BrowserInfo.prototype.hasWebFontSupport = function () { return this.webfontSupport_; }; diff --git a/src/core/font.js b/src/core/font.js index 526a7a52..2518caec 100644 --- a/src/core/font.js +++ b/src/core/font.js @@ -26,7 +26,7 @@ webfont.WebFont.prototype.load = function(configuration) { var eventDispatcher = new webfont.EventDispatcher( this.domHelper_, context.document.documentElement, configuration); - if (this.userAgent_.isSupportingWebFont()) { + if (this.userAgent_.getBrowserInfo().hasWebFontSupport()) { this.load_(eventDispatcher, configuration); } else { eventDispatcher.dispatchInactive(); diff --git a/src/core/initialize.js b/src/core/initialize.js index b362cfee..21ef0222 100644 --- a/src/core/initialize.js +++ b/src/core/initialize.js @@ -23,4 +23,5 @@ webfont.UserAgent.prototype['getEngineVersion'] = webfont.UserAgent.prototype.ge webfont.UserAgent.prototype['getPlatform'] = webfont.UserAgent.prototype.getPlatform; webfont.UserAgent.prototype['getPlatformVersion'] = webfont.UserAgent.prototype.getPlatformVersion; webfont.UserAgent.prototype['getDocumentMode'] = webfont.UserAgent.prototype.getDocumentMode; -webfont.UserAgent.prototype['isSupportingWebFont'] = webfont.UserAgent.prototype.isSupportingWebFont; +webfont.UserAgent.prototype['getBrowserInfo'] = webfont.UserAgent.prototype.getBrowserInfo; +webfont.BrowserInfo.prototype['hasWebFontSupport'] = webfont.BrowserInfo.prototype.hasWebFontSupport; diff --git a/src/core/useragent.js b/src/core/useragent.js index adc6d9f5..c613e104 100644 --- a/src/core/useragent.js +++ b/src/core/useragent.js @@ -76,10 +76,3 @@ webfont.UserAgent.prototype.getDocumentMode = function() { webfont.UserAgent.prototype.getBrowserInfo = function() { return this.browserInfo_; }; - -/** - * @return {boolean} - */ -webfont.UserAgent.prototype.isSupportingWebFont = function() { - return this.browserInfo_.hasWebfontSupport(); -}; diff --git a/src/custom/customcss.js b/src/custom/customcss.js index 0b9b1d63..1b491ce3 100644 --- a/src/custom/customcss.js +++ b/src/custom/customcss.js @@ -28,7 +28,7 @@ webfont.CustomCss.prototype.load = function(onReady) { }; webfont.CustomCss.prototype.supportUserAgent = function(userAgent, support) { - return support(userAgent.isSupportingWebFont()); + return support(userAgent.getBrowserInfo().hasWebFontSupport()); }; globalNamespaceObject.addModule(webfont.CustomCss.NAME, function(configuration, domHelper) { diff --git a/src/google/googlefontapi.js b/src/google/googlefontapi.js index 4ddae87a..9dc551aa 100644 --- a/src/google/googlefontapi.js +++ b/src/google/googlefontapi.js @@ -10,7 +10,7 @@ webfont.GoogleFontApi = function(userAgent, domHelper, configuration) { webfont.GoogleFontApi.NAME = 'google'; webfont.GoogleFontApi.prototype.supportUserAgent = function(userAgent, support) { - support(userAgent.isSupportingWebFont()); + support(userAgent.getBrowserInfo().hasWebFontSupport()); }; webfont.GoogleFontApi.prototype.getFontWatchRunnerCtor = function() { diff --git a/src/monotype/monotype_script.js b/src/monotype/monotype_script.js index c76fa31e..37d4e4c0 100644 --- a/src/monotype/monotype_script.js +++ b/src/monotype/monotype_script.js @@ -55,7 +55,7 @@ webfont.MonotypeScript.prototype.supportUserAgent = function (userAgent, support } } } - support(userAgent.isSupportingWebFont()); + support(userAgent.getBrowserInfo().hasWebFontSupport()); } var done = false; From d86e4f84cf37bf1bbe50771103cd82bf0bab912d Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 19 Dec 2012 21:38:27 +0100 Subject: [PATCH 48/66] Cleaned up version number parsing. --- src/core/useragentparser.js | 99 +++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index 3f3846b1..8d1542d0 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -128,7 +128,7 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { // instead of the specific Trident engine name and version var platform = this.getPlatform_(); - var platformVersion = this.getPlatformVersion_(); + var platformVersionString = this.getPlatformVersion_(); var browser = this.getMatchingGroup_(this.userAgent_, /(MSIE [\d\w\.]+)/, 1); @@ -136,18 +136,18 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { var pair = browser.split(' '); var name = pair[0]; var version = pair[1]; - var majorVersion = this.getMajorVersion_(version); - var majorPlatformVersion = this.getMajorVersion_(platformVersion); - var supportWebFont = (platform == "Windows" && majorVersion >= 6) || - (platform == "Windows Phone" && majorPlatformVersion >= 8); + var browserVersion = this.parseVersion_(version); + var platformVersion = this.parseVersion_(platformVersionString); + var supportWebFont = (platform == "Windows" && browserVersion.major >= 6) || + (platform == "Windows Phone" && platformVersion.major >= 8); return new webfont.UserAgent(name, version, name, version, - platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); } return new webfont.UserAgent("MSIE", webfont.UserAgentParser.UNKNOWN, "MSIE", webfont.UserAgentParser.UNKNOWN, - platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); }; /** @@ -197,20 +197,22 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { // Otherwise, find version information for normal Opera or Opera Mobile if (this.userAgent_.indexOf("Version/") != -1) { - var version = this.getMatchingGroup_(this.userAgent_, /Version\/([\d\.]+)/, 1); + var versionString = this.getMatchingGroup_(this.userAgent_, /Version\/([\d\.]+)/, 1); - if (version != "") { - return new webfont.UserAgent("Opera", version, engineName, engineVersion, + if (versionString != "") { + var version = this.parseVersion_(versionString); + return new webfont.UserAgent("Opera", versionString, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(this.getMajorVersion_(version) >= 10, false, false)); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false, false)); } } - var version = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1); + var versionString = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1); - if (version != "") { - return new webfont.UserAgent("Opera", version, engineName, engineVersion, + if (versionString != "") { + var version = this.parseVersion_(versionString); + return new webfont.UserAgent("Opera", versionString, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(this.getMajorVersion_(version) >= 10, false, false)); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false, false)); } return new webfont.UserAgent("Opera", webfont.UserAgentParser.UNKNOWN, engineName, engineVersion, this.getPlatform_(), @@ -230,13 +232,16 @@ webfont.UserAgentParser.prototype.isWebKit_ = function() { webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { var platform = this.getPlatform_(); var platformVersion = this.getPlatformVersion_(); - var webKitVersion = this.getMatchingGroup_(this.userAgent_, + var webKitVersionString = this.getMatchingGroup_(this.userAgent_, /AppleWebKit\/([\d\.\+]+)/, 1); var supportWebFont = false; - if (webKitVersion == "") { - webKitVersion = webfont.UserAgentParser.UNKNOWN; + if (webKitVersionString == "") { + webKitVersionString = webfont.UserAgentParser.UNKNOWN; } + + var webKitVersion = this.parseVersion_(webKitVersionString); + var name = webfont.UserAgentParser.UNKNOWN; if (this.userAgent_.indexOf("Chrome") != -1 || this.userAgent_.indexOf("CrMo") != -1 || this.userAgent_.indexOf("CriOS") != -1) { @@ -263,18 +268,16 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { /AdobeAIR\/([\d\.]+)/, 1); } if (name == "AdobeAIR") { - var minor = this.getMatchingGroup_(version, /\d+\.(\d+)/, 1); - supportWebFont = this.getMajorVersion_(version) > 2 || this.getMajorVersion_(version) == 2 && parseInt(minor, 10) >= 5; + var browserVersion = this.parseVersion_(version); + supportWebFont = browserVersion.major > 2 || browserVersion.major == 2 && browserVersion.minor >= 5; } else if (platform == "BlackBerry") { supportWebFont = parseInt(platformVersion, 10) >= 10; } else if (platform == "Android") { supportWebFont = parseFloat(platformVersion) > 2.1; } else { - var minor = this.getMatchingGroup_(webKitVersion, /\d+\.(\d+)/, 1); - supportWebFont = this.getMajorVersion_(webKitVersion) >= 526 || this.getMajorVersion_(webKitVersion) >= 525 && parseInt(minor, 10) >= 13; + supportWebFont = webKitVersion.major >= 526 || webKitVersion.major >= 525 && webKitVersion.minor >= 13; } - - return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersion, + return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersionString, platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); }; @@ -291,7 +294,7 @@ webfont.UserAgentParser.prototype.isGecko_ = function() { webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { var name = webfont.UserAgentParser.UNKNOWN; var version = webfont.UserAgentParser.UNKNOWN; - var supportWebFont = false;; + var supportWebFont = false; if (this.userAgent_.indexOf("Firefox") != -1) { name = "Firefox"; @@ -299,47 +302,47 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { /Firefox\/([\d\w\.]+)/, 1); if (versionNum != "") { - var minor = this.getMatchingGroup_(versionNum, /\d+\.(\d+)/, 1); + var firefoxVersion = this.parseVersion_(versionNum); version = versionNum; - supportWebFont = versionNum != "" && - this.getMajorVersion_(versionNum) >= 3 && - parseInt(minor, 10) >= 5; + supportWebFont = firefoxVersion.major >= 3 && + firefoxVersion.minor >= 5; } } else if (this.userAgent_.indexOf("Mozilla") != -1) { name = "Mozilla"; } - var geckoVersion = this.getMatchingGroup_(this.userAgent_, /rv:([^\)]+)/, 1); + var geckoVersionString = this.getMatchingGroup_(this.userAgent_, /rv:([^\)]+)/, 1); - if (geckoVersion == "") { - geckoVersion = webfont.UserAgentParser.UNKNOWN; + if (geckoVersionString == "") { + geckoVersionString = webfont.UserAgentParser.UNKNOWN; } else { if (!supportWebFont) { - var majorVersion = this.getMajorVersion_(geckoVersion); - var intMinorVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.(\d+)/, 1), 10); - var subVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.\d+\.(\d+)/, 1), 10); - - supportWebFont = majorVersion > 1 || - majorVersion == 1 && intMinorVersion > 9 || - majorVersion == 1 && intMinorVersion == 9 && subVersion >= 2 || - geckoVersion.match(/1\.9\.1b[123]/) != null || - geckoVersion.match(/1\.9\.1\.[\d\.]+/) != null; + var geckoVersion = this.parseVersion_(geckoVersionString); + + supportWebFont = geckoVersion.major > 1 || + geckoVersion.major == 1 && geckoVersion.minor > 9 || + geckoVersion.major == 1 && geckoVersion.minor == 9 && geckoVersion.patch >= 2 || + geckoVersionString.match(/1\.9\.1b[123]/) != null || + geckoVersionString.match(/1\.9\.1\.[\d\.]+/) != null; } } - return new webfont.UserAgent(name, version, "Gecko", geckoVersion, + return new webfont.UserAgent(name, version, "Gecko", geckoVersionString, this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); }; /** * @private */ -webfont.UserAgentParser.prototype.getMajorVersion_ = function(version) { - var majorVersion = this.getMatchingGroup_(version, /(\d+)/, 1); - - if (majorVersion != "") { - return parseInt(majorVersion, 10); +webfont.UserAgentParser.prototype.parseVersion_ = function(version) { + var m = /([0-9]+)(?:\.([0-9]+)(?:\.([0-9]+)?)?)?/.exec(version), + result = {}; + + if (m) { + result.major = parseInt(m[1] || -1, 10); + result.minor = parseInt(m[2] || -1, 10); + result.patch = parseInt(m[3] || -1, 10); } - return -1; + return result; }; /** From ecd7c414929d2d8a0bd584758a66f3fa839aaa8e Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 3 Jan 2013 13:17:13 +0100 Subject: [PATCH 49/66] Hardcoded detection of the webkit fallback bug and the android font stack bug. --- src/core/useragentparser.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index 8d1542d0..af109b39 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -231,7 +231,7 @@ webfont.UserAgentParser.prototype.isWebKit_ = function() { */ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { var platform = this.getPlatform_(); - var platformVersion = this.getPlatformVersion_(); + var platformVersionString = this.getPlatformVersion_(); var webKitVersionString = this.getMatchingGroup_(this.userAgent_, /AppleWebKit\/([\d\.\+]+)/, 1); var supportWebFont = false; @@ -241,6 +241,7 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { } var webKitVersion = this.parseVersion_(webKitVersionString); + var platformVersion = this.parseVersion_(platformVersionString); var name = webfont.UserAgentParser.UNKNOWN; @@ -271,14 +272,18 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { var browserVersion = this.parseVersion_(version); supportWebFont = browserVersion.major > 2 || browserVersion.major == 2 && browserVersion.minor >= 5; } else if (platform == "BlackBerry") { - supportWebFont = parseInt(platformVersion, 10) >= 10; + supportWebFont = platformVersion.major >= 10; } else if (platform == "Android") { - supportWebFont = parseFloat(platformVersion) > 2.1; + supportWebFont = platformVersion.major > 2 || (platformVersion.major == 2 && platformVersion.minor > 1); } else { supportWebFont = webKitVersion.major >= 526 || webKitVersion.major >= 525 && webKitVersion.minor >= 13; } + + var hasWebKitFallbackBug = webKitVersion.major < 536 && webKitVersion.minor < 11; + var hasAndroidFontStackBug = hasWebKitFallbackBug && platform == "Android"; + return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersionString, - platform, platformVersion, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, hasWebKitFallbackBug, hasAndroidFontStackBug)); }; /** From 2bd7b2a332f06b911bb7e30b3b40ccbc548dc8e0 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 3 Jan 2013 13:56:30 +0100 Subject: [PATCH 50/66] Added tests for browserinfo bugs and did some minor renaming. --- src-test/core/useragenttest.js | 31 +++++++++++++++++++++++++++++++ src/core/browserinfo.js | 18 +++++++++--------- src/core/useragentparser.js | 2 +- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src-test/core/useragenttest.js b/src-test/core/useragenttest.js index 75692091..2ff9316c 100644 --- a/src-test/core/useragenttest.js +++ b/src-test/core/useragenttest.js @@ -717,3 +717,34 @@ UserAgentTest.prototype.testBrowserBBNotSupportWebfont = function() { assertEquals(undefined, userAgent.getDocumentMode()); assertFalse(userAgent.getBrowserInfo().hasWebFontSupport()); }; + +UserAgentTest.prototype.testBrowserWebKitFallbackBug = function() { + var userAgentParser = new webfont.UserAgentParser( + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", + this.defaultDocument_); + + var userAgent = userAgentParser.parse(); + + assertTrue(userAgent.getBrowserInfo().hasWebKitFallbackBug()); +}; + +UserAgentTest.prototype.testBrowserWebKitNoFallbackBug = function() { + var userAgentParser = new webfont.UserAgentParser( + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.814.2 Safari/536.11", + this.defaultDocument_); + + var userAgent = userAgentParser.parse(); + + assertFalse(userAgent.getBrowserInfo().hasWebKitFallbackBug()); +}; + +UserAgentTest.prototype.testBrowserFontStackBug = function() { + var userAgentParser = new webfont.UserAgentParser( + "Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", + this.defaultDocument_); + + var userAgent = userAgentParser.parse(); + + assertTrue(userAgent.getBrowserInfo().hasWebKitFallbackBug()); + assertTrue(userAgent.getBrowserInfo().hasAndroidFontStackBug()); +}; diff --git a/src/core/browserinfo.js b/src/core/browserinfo.js index 1b3c4a89..90be359d 100644 --- a/src/core/browserinfo.js +++ b/src/core/browserinfo.js @@ -1,13 +1,13 @@ /** * @constructor * @param {boolean} webfontSupport - * @param {boolean} webkitFallbackBug - * @param {boolean} androidFallbackBug + * @param {boolean} webKitFallbackBug + * @param {boolean} androidFontStackBug */ -webfont.BrowserInfo = function (webfontSupport, webkitFallbackBug, androidFallbackBug) { +webfont.BrowserInfo = function (webfontSupport, webKitFallbackBug, androidFontStackBug) { this.webfontSupport_ = webfontSupport; - this.webkitFallbackBug_ = webkitFallbackBug; - this.androidFallbackBug_ = androidFallbackBug; + this.webKitFallbackBug_ = webKitFallbackBug; + this.androidFontStackBug_ = androidFontStackBug; }; /** @@ -20,13 +20,13 @@ webfont.BrowserInfo.prototype.hasWebFontSupport = function () { /** * @return {boolean} */ -webfont.BrowserInfo.prototype.hasWebkitFallbackBug = function () { - return this.webkitFallbackBug_; +webfont.BrowserInfo.prototype.hasWebKitFallbackBug = function () { + return this.webKitFallbackBug_; }; /** * @return {boolean} */ -webfont.BrowserInfo.prototype.hasAndroidFallbackBug = function () { - return this.androidFallbackBug_; +webfont.BrowserInfo.prototype.hasAndroidFontStackBug = function () { + return this.androidFontStackBug_; }; diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index af109b39..c719cc0e 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -279,7 +279,7 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { supportWebFont = webKitVersion.major >= 526 || webKitVersion.major >= 525 && webKitVersion.minor >= 13; } - var hasWebKitFallbackBug = webKitVersion.major < 536 && webKitVersion.minor < 11; + var hasWebKitFallbackBug = webKitVersion.major < 536 || (webKitVersion.major == 536 && webKitVersion.minor < 11); var hasAndroidFontStackBug = hasWebKitFallbackBug && platform == "Android"; return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersionString, From 311945b0531c54960e42b1edf5f5112c271cc1be Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 3 Jan 2013 14:38:35 +0100 Subject: [PATCH 51/66] Rewrote font watching strategy and updated tests. --- src-test/core/fontwatchertest.js | 14 ++++----- src-test/core/fontwatchrunnertest.js | 8 ++--- src/core/fontwatcher.js | 16 ++-------- src/core/fontwatchrunner.js | 45 ++++++---------------------- 4 files changed, 22 insertions(+), 61 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 245e60f8..d16734cf 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -45,7 +45,7 @@ FontWatcherTest.prototype.setUp = function() { setStyle: function() {} }; - this.userAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); + this.userAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false, false)); this.fakeFontSizer_ = { getSize: function() { @@ -263,25 +263,25 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { }; FontWatcherTest.prototype.testNoWebkitBugDetectionOnNonWebkit = function() { - var ua = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, true); + var ua = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(true, false, false)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); - assertEquals(false, fontWatcher.checkWebkitFallbackBug_); + assertEquals(false, fontWatcher.hasWebKitFallbackBug_); }; FontWatcherTest.prototype.testNoWebkitBugDetectionOnNewWebkit = function() { - var ua = new webfont.UserAgent('Safari', '6.0.2', 'AppleWebKit', '537.6.17', 'Macintosh', '10_7_5', undefined, true); + var ua = new webfont.UserAgent('Safari', '6.0.2', 'AppleWebKit', '537.6.17', 'Macintosh', '10_7_5', undefined, new webfont.BrowserInfo(true, false, false)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); - assertEquals(false, fontWatcher.checkWebkitFallbackBug_); + assertEquals(false, fontWatcher.hasWebKitFallbackBug_); }; FontWatcherTest.prototype.testYesWebkitBugDetectionOnOlderWebkit = function() { - var ua = new webfont.UserAgent('Chrome', '16.0.912.75', 'AppleWebKit', '535.7', 'Android', '4.0.3', undefined, true); + var ua = new webfont.UserAgent('Chrome', '16.0.912.75', 'AppleWebKit', '535.7', 'Android', '4.0.3', undefined, new webfont.BrowserInfo(true, true, false)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); - assertEquals(true, fontWatcher.checkWebkitFallbackBug_); + assertEquals(true, fontWatcher.hasWebKitFallbackBug_); }; diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 1c5ea526..b6de64ba 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -144,7 +144,7 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { + } else if (el.style.fontFamily == "") { // Return the last resort width return { width: 2, @@ -177,7 +177,7 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 1 }; } - } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { + } else if (el.style.fontFamily == "") { return { width: 2, height: 2 @@ -209,7 +209,7 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 2 }; } - } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { + } else if (el.style.fontFamily == "") { // Return the default width return { width: 2, @@ -241,7 +241,7 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily.indexOf('__webfontloader_test_') !== -1) { + } else if (el.style.fontFamily == "") { return { width: 2, height: 2 diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 565c28a1..5ed0ea22 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -18,19 +18,7 @@ webfont.FontWatcher = function(userAgent, domHelper, eventDispatcher, fontSizer, this.last_ = false; this.success_ = false; - // There's a bug in WebKit that affects font watching in versions before - // 536.11. We only attempt to detect the bug in browsers that might have it, - // so that detection is simpler and does less work in more recent browsers. - // For more detail on the bug and our detection/workaround, see the code and - // comments in fontwatchrunner.js. - this.checkWebkitFallbackBug_ = false; - if (userAgent.getEngine() === 'AppleWebKit') { - var version = userAgent.getEngineVersion(); - var parts = version.split("."); - var major = parseInt(parts[0], 10) || 0; - var minor = parseInt(parts[1], 10) || 0; - this.checkWebkitFallbackBug_ = major < 536 || (major == 536 && minor < 11); - } + this.hasWebKitFallbackBug_ = userAgent.getBrowserInfo().hasWebKitFallbackBug(); }; /** @@ -83,7 +71,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, this.checkWebkitFallbackBug_, fontTestString); + this.getTime_, fontFamily, fontDescription, this.hasWebKitFallbackBug_, fontTestString); fontWatchRunner.start(); } diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index c9f4b4b8..337491a6 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -8,11 +8,11 @@ * @param {function(): number} getTime * @param {string} fontFamily * @param {string} fontDescription - * @param {boolean} checkWebkitFallbackBug + * @param {boolean} hasWebKitFallbackBug * @param {string=} opt_fontTestString */ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, checkWebkitFallbackBug, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebKitFallbackBug, opt_fontTestString) { this.activeCallback_ = activeCallback; this.inactiveCallback_ = inactiveCallback; this.domHelper_ = domHelper; @@ -22,7 +22,7 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontFamily_ = fontFamily; this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; - this.hasWebkitFallbackBug_ = false; + this.hasWebKitFallbackBug_ = hasWebKitFallbackBug; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); @@ -34,39 +34,12 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); this.fallbackSizeB_ = this.fontRulerB_.getSize(); - // Detect webkit fallback bug and last resort sizes, if present. - if (checkWebkitFallbackBug) { - // We build an empty webfont and try to set it as the font for our ruler. - // Even though this will fail (since our webfont is invalid) it will - // actually trigger the Webkit fallback bug. - var nullFontFamily = this.domHelper_.insertNullFontStyle(this.fontDescription_); - - // Set the font stack to include our fake webfont first, and then the - // respective fallback stacks. Browsers without the bug will fall back to - // the first font in the stack, yielding the same width. Browsers with the - // bug will fall back to the last resort font instead, which should be - // different for at least one of the font stacks. The second generic font - // family name in each font stack is there for Android Webkit, where the - // last resort font is determined by the last font in the stack instead of - // a hard-coded constant. - // - // See http://code.google.com/p/chromium/issues/detail?id=138257 for more - // information on the Chrome Android bug. - this.fontRulerA_.setFont(nullFontFamily + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); + if (this.hasWebKitFallbackBug_) { + this.fontRulerA_.setFont("''", this.fontDescription_); this.lastResortSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerB_.setFont(nullFontFamily + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); - this.lastResortSizeB_ = this.fontRulerB_.getSize(); - - // Finally we compare the expected fallback size and the actual fallback - // size. If either do not match, it must mean the last resort font was being - // used instead so we assume the bug is present. - this.hasWebkitFallbackBug_ = !this.sizeEquals_(this.fallbackSizeA_, this.lastResortSizeA_) || !this.sizeEquals_(this.fallbackSizeB_, this.lastResortSizeB_); - // Clean up the empty webfont that we created and reset the rulers to the - // standard fallback stack. - this.domHelper_.removeNullFontStyle(nullFontFamily); - this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); - this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); + this.fontRulerB_.setFont("''", this.fontDescription_); + this.lastResortSizeB_ = this.fontRulerB_.getSize(); } }; @@ -134,9 +107,9 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeB = this.fontRulerB_.getSize(); if ((this.sizeEquals_(sizeA, this.fallbackSizeA_) && this.sizeEquals_(sizeB, this.fallbackSizeB_)) || - (this.hasWebkitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { + (this.hasWebKitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { if (this.hasTimedOut_()) { - if (this.hasWebkitFallbackBug_ && + if (this.hasWebKitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_)) { this.finish_(this.activeCallback_); From cc988ec90a45654f3bd9340dcb8eac06c0fd45bb Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 3 Jan 2013 14:41:03 +0100 Subject: [PATCH 52/66] Removed NullFont methods. --- src-test/core/domhelpertest.js | 10 ------ src/core/domhelper.js | 59 ---------------------------------- 2 files changed, 69 deletions(-) diff --git a/src-test/core/domhelpertest.js b/src-test/core/domhelpertest.js index 94f22541..356b86b2 100644 --- a/src-test/core/domhelpertest.js +++ b/src-test/core/domhelpertest.js @@ -107,16 +107,6 @@ DomHelperTest.prototype.testHasSupportForStyle = function() { assertTrue(this.domHelper_.hasSupportForStyle_()); }; -DomHelperTest.prototype.testInsertNullFontStyle = function() { - var counter = webfont.DomHelper.nullFontCounter_, - name = this.domHelper_.insertNullFontStyle(''); - - assertNotNull(name); - assertEquals(name, '__webfontloader_test_' + counter + '__'); - assertNotEquals(counter, webfont.DomHelper.nullFontCounter_); - assertNotNull(webfont.DomHelper.nullFontStyles_[name]); -}; - DomHelperTest.prototype.testGetWindows = function() { var fakeMainWindow = 'main window'; var fakeLoadWindow = 'load window'; diff --git a/src/core/domhelper.js b/src/core/domhelper.js index 44e45f68..da0eaec0 100644 --- a/src/core/domhelper.js +++ b/src/core/domhelper.js @@ -226,62 +226,3 @@ webfont.DomHelper.prototype.getProtocol = function() { } return protocol == 'https:' ? 'https:' : 'http:'; }; - -/** - * A counter to ensure that null fonts have unique family names. - * @private - * @type {number} - */ -webfont.DomHelper.nullFontCounter_ = 0; - -/** - * A global place to save created null font style elements until they are - * removed. - * @private - * @type {Object.} - */ -webfont.DomHelper.nullFontStyles_ = {}; - -/** - * Creates a null font style element and inserts it into the head of the page. - * The element can be used to detect the WebKit last resort fallback bug for - * font detection. - * @return {string} Returns the un-quoted font-family name of the new null font - * style rule just inserted into the document (e.g. __webfontloader_test_0__). - */ -webfont.DomHelper.prototype.insertNullFontStyle = function(fontDescription) { - var fontFamily = "__webfontloader_test_" + webfont.DomHelper.nullFontCounter_ + "__"; - webfont.DomHelper.nullFontCounter_++; - - var fvd = new webfont.FontVariationDescription(); - var weightAndStyle = fvd.expand(fontDescription); - - var style = this.createElement('style', null, - "@font-face{" + - "font-family:'" + fontFamily + "';" + - "src:url(data:application/x-font-woff;base64,) format('woff')," + - "url(data:font/opentype;base64,) format('truetype');" + - weightAndStyle + - "}"); - - this.insertInto('head', style); - webfont.DomHelper.nullFontStyles_[fontFamily] = style; - - return fontFamily; -}; - -/** - * Removes a previously created null font style from the page, using the - * associated font-family name to locate it. - * @param {string} fontFamily The name of the null font family to remove. - * @return {boolean} Returns true if the null font style element was found and - * removed successfully, and false otherwise. - */ -webfont.DomHelper.prototype.removeNullFontStyle = function(fontFamily) { - var style = webfont.DomHelper.nullFontStyles_[fontFamily]; - if (style) { - return this.removeElement(style); - } else { - return false; - } -}; From edc12d105a73b8dac541fbc62f27aad64cc83155 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Thu, 3 Jan 2013 14:54:17 +0100 Subject: [PATCH 53/66] Removed Android web font loading bug detection code. --- src-test/core/fonttest.js | 6 +++--- src-test/core/fontwatchertest.js | 8 ++++---- src-test/core/useragenttest.js | 11 ----------- src-test/monotype/monotype_script_test.js | 10 +++++----- src/core/browserinfo.js | 11 +---------- src/core/useragentparser.js | 19 +++++++++---------- 6 files changed, 22 insertions(+), 43 deletions(-) diff --git a/src-test/core/fonttest.js b/src-test/core/fonttest.js index 095b7bf8..28d088ac 100644 --- a/src-test/core/fonttest.js +++ b/src-test/core/fonttest.js @@ -5,7 +5,7 @@ FontTest.prototype.setUp = function() { }; FontTest.prototype.testFontLoad = function() { - var browserInfo = new webfont.BrowserInfo(true, false, false); + var browserInfo = new webfont.BrowserInfo(true, false); var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(window, this.fontModuleLoader_, @@ -60,7 +60,7 @@ FontTest.prototype.testFontLoad = function() { FontTest.prototype.testFontLoadWithContext = function() { var fakeMainWindow = {}; - var browserInfo = new webfont.BrowserInfo(true, false, false); + var browserInfo = new webfont.BrowserInfo(true, false); var userAgent = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, browserInfo); var font = new webfont.WebFont(fakeMainWindow, this.fontModuleLoader_, @@ -93,7 +93,7 @@ FontTest.prototype.testFontLoadWithContext = function() { FontTest.prototype.testFontInactive = function() { var userAgent = new webfont.UserAgent('Firefox', '3.0', 'Gecko', '1.9.2', - 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false, false)); + 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false)); var font = new webfont.WebFont(window, this.fontModuleLoader_, function(func, timeout) { func(); }, userAgent); var testModule; diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index d16734cf..0b795f20 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -45,7 +45,7 @@ FontWatcherTest.prototype.setUp = function() { setStyle: function() {} }; - this.userAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false, false)); + this.userAgent_ = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(false, false)); this.fakeFontSizer_ = { getSize: function() { @@ -263,7 +263,7 @@ FontWatcherTest.prototype.testWatchMultipleFontsWithTestStrings = function() { }; FontWatcherTest.prototype.testNoWebkitBugDetectionOnNonWebkit = function() { - var ua = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(true, false, false)); + var ua = new webfont.UserAgent('Firefox', '3.6', 'Gecko', '1.9.2', 'Macintosh', '10.6', undefined, new webfont.BrowserInfo(true, false)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); @@ -271,7 +271,7 @@ FontWatcherTest.prototype.testNoWebkitBugDetectionOnNonWebkit = function() { }; FontWatcherTest.prototype.testNoWebkitBugDetectionOnNewWebkit = function() { - var ua = new webfont.UserAgent('Safari', '6.0.2', 'AppleWebKit', '537.6.17', 'Macintosh', '10_7_5', undefined, new webfont.BrowserInfo(true, false, false)); + var ua = new webfont.UserAgent('Safari', '6.0.2', 'AppleWebKit', '537.6.17', 'Macintosh', '10_7_5', undefined, new webfont.BrowserInfo(true, false)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); @@ -279,7 +279,7 @@ FontWatcherTest.prototype.testNoWebkitBugDetectionOnNewWebkit = function() { }; FontWatcherTest.prototype.testYesWebkitBugDetectionOnOlderWebkit = function() { - var ua = new webfont.UserAgent('Chrome', '16.0.912.75', 'AppleWebKit', '535.7', 'Android', '4.0.3', undefined, new webfont.BrowserInfo(true, true, false)); + var ua = new webfont.UserAgent('Chrome', '16.0.912.75', 'AppleWebKit', '535.7', 'Android', '4.0.3', undefined, new webfont.BrowserInfo(true, true)); var fontWatcher = new webfont.FontWatcher(ua, this.fakeDomHelper_, this.fakeEventDispatcher_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_); diff --git a/src-test/core/useragenttest.js b/src-test/core/useragenttest.js index 2ff9316c..1e7fcedb 100644 --- a/src-test/core/useragenttest.js +++ b/src-test/core/useragenttest.js @@ -737,14 +737,3 @@ UserAgentTest.prototype.testBrowserWebKitNoFallbackBug = function() { assertFalse(userAgent.getBrowserInfo().hasWebKitFallbackBug()); }; - -UserAgentTest.prototype.testBrowserFontStackBug = function() { - var userAgentParser = new webfont.UserAgentParser( - "Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - this.defaultDocument_); - - var userAgent = userAgentParser.parse(); - - assertTrue(userAgent.getBrowserInfo().hasWebKitFallbackBug()); - assertTrue(userAgent.getBrowserInfo().hasAndroidFontStackBug()); -}; diff --git a/src-test/monotype/monotype_script_test.js b/src-test/monotype/monotype_script_test.js index dec332d8..72c49f64 100644 --- a/src-test/monotype/monotype_script_test.js +++ b/src-test/monotype/monotype_script_test.js @@ -45,7 +45,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () { return null; } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); monotypeScript.load(function (fontFamilies) { @@ -107,7 +107,7 @@ MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () { return null; } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); monotypeScript.load(function (fontFamilies) { @@ -181,7 +181,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurl = function () { } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); @@ -243,7 +243,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurlAndTheScriptUrlH } var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); @@ -291,7 +291,7 @@ MonotypeScriptTest.prototype.testWithoutProjectId = function () { }; var isSupport = null; - var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false, false)); + var userAgent = new webfont.UserAgent("Test", "1.0", "TestEngine", "2.0", "TestPlatform", "3.0", undefined, new webfont.BrowserInfo(false, false)); var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config); monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; }); diff --git a/src/core/browserinfo.js b/src/core/browserinfo.js index 90be359d..bf43cc71 100644 --- a/src/core/browserinfo.js +++ b/src/core/browserinfo.js @@ -2,12 +2,10 @@ * @constructor * @param {boolean} webfontSupport * @param {boolean} webKitFallbackBug - * @param {boolean} androidFontStackBug */ -webfont.BrowserInfo = function (webfontSupport, webKitFallbackBug, androidFontStackBug) { +webfont.BrowserInfo = function (webfontSupport, webKitFallbackBug) { this.webfontSupport_ = webfontSupport; this.webKitFallbackBug_ = webKitFallbackBug; - this.androidFontStackBug_ = androidFontStackBug; }; /** @@ -23,10 +21,3 @@ webfont.BrowserInfo.prototype.hasWebFontSupport = function () { webfont.BrowserInfo.prototype.hasWebKitFallbackBug = function () { return this.webKitFallbackBug_; }; - -/** - * @return {boolean} - */ -webfont.BrowserInfo.prototype.hasAndroidFontStackBug = function () { - return this.androidFontStackBug_; -}; diff --git a/src/core/useragentparser.js b/src/core/useragentparser.js index c719cc0e..b490a14a 100644 --- a/src/core/useragentparser.js +++ b/src/core/useragentparser.js @@ -35,7 +35,7 @@ webfont.UserAgentParser.UNKNOWN_USER_AGENT = new webfont.UserAgent( webfont.UserAgentParser.UNKNOWN, webfont.UserAgentParser.UNKNOWN, undefined, - new webfont.BrowserInfo(false, false, false)); + new webfont.BrowserInfo(false, false)); /** * Parses the user agent string and returns an object. @@ -142,12 +142,12 @@ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() { (platform == "Windows Phone" && platformVersion.major >= 8); return new webfont.UserAgent(name, version, name, version, - platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false)); } return new webfont.UserAgent("MSIE", webfont.UserAgentParser.UNKNOWN, "MSIE", webfont.UserAgentParser.UNKNOWN, - platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false)); }; /** @@ -192,7 +192,7 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { return new webfont.UserAgent("OperaMini", version, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false)); } // Otherwise, find version information for normal Opera or Opera Mobile @@ -203,7 +203,7 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var version = this.parseVersion_(versionString); return new webfont.UserAgent("Opera", versionString, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false, false)); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false)); } } var versionString = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1); @@ -212,11 +212,11 @@ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() { var version = this.parseVersion_(versionString); return new webfont.UserAgent("Opera", versionString, engineName, engineVersion, this.getPlatform_(), this.getPlatformVersion_(), - this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false, false)); + this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(version.major >= 10, false)); } return new webfont.UserAgent("Opera", webfont.UserAgentParser.UNKNOWN, engineName, engineVersion, this.getPlatform_(), - this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false, false)); + this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(false, false)); }; /** @@ -280,10 +280,9 @@ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() { } var hasWebKitFallbackBug = webKitVersion.major < 536 || (webKitVersion.major == 536 && webKitVersion.minor < 11); - var hasAndroidFontStackBug = hasWebKitFallbackBug && platform == "Android"; return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersionString, - platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, hasWebKitFallbackBug, hasAndroidFontStackBug)); + platform, platformVersionString, this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, hasWebKitFallbackBug)); }; /** @@ -332,7 +331,7 @@ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() { } } return new webfont.UserAgent(name, version, "Gecko", geckoVersionString, - this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false, false)); + this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), new webfont.BrowserInfo(supportWebFont, false)); }; /** From 98a84b0592b48415b55c51caaa274ff38ad79423 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 7 Jan 2013 14:30:34 +0100 Subject: [PATCH 54/66] Rewrote detection code to use generic font family sizes to detect the last resort font. --- src-test/core/fontwatchrunnertest.js | 22 ----- src/core/fontwatchrunner.js | 91 +++++++++++++------ src/google/lastresortwebkitfontwatchrunner.js | 4 +- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index b6de64ba..bda2dcbc 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -144,12 +144,6 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily == "") { - // Return the last resort width - return { - width: 2, - height: 2 - }; } else { // Return the default width return { @@ -177,11 +171,6 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 1 }; } - } else if (el.style.fontFamily == "") { - return { - width: 2, - height: 2 - }; } else { return { width: 1, @@ -209,12 +198,6 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 2 }; } - } else if (el.style.fontFamily == "") { - // Return the default width - return { - width: 2, - height: 2 - }; } else { return { width: 1, @@ -241,11 +224,6 @@ FontWatchRunnerTest.prototype.setUp = function() { height: 3 }; } - } else if (el.style.fontFamily == "") { - return { - width: 2, - height: 2 - }; } else { return { width: 1, diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 337491a6..d10d3cbf 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -23,37 +23,27 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebKitFallbackBug_ = hasWebKitFallbackBug; + this.genericFontFamilySizes_ = {}; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - this.fontRulerA_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); - this.fallbackSizeA_ = this.fontRulerA_.getSize(); - this.fontRulerB_.setFont(webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); - this.fallbackSizeB_ = this.fontRulerB_.getSize(); - - if (this.hasWebKitFallbackBug_) { - this.fontRulerA_.setFont("''", this.fontDescription_); - this.lastResortSizeA_ = this.fontRulerA_.getSize(); - - this.fontRulerB_.setFont("''", this.fontDescription_); - this.lastResortSizeB_ = this.fontRulerB_.getSize(); - } + this.setupGenericFontFamilySizes_(); }; /** - * @type {string} - * @const - */ -webfont.FontWatchRunner.FALLBACK_FONTS_A = "serif,sans-serif"; - -/** - * @type {string} + * @enum {string} * @const */ -webfont.FontWatchRunner.FALLBACK_FONTS_B = "sans-serif,serif"; +webfont.FontWatchRunner.GenericFontFamily = { + SERIF: 'serif', + SANS_SERIF: 'sans-serif', + MONOSPACE: 'monospace', + CURSIVE: 'cursive', + FANTASY: 'fantasy' +}; /** * Default test string. Characters are chosen so that their widths vary a lot @@ -64,11 +54,28 @@ webfont.FontWatchRunner.FALLBACK_FONTS_B = "sans-serif,serif"; */ webfont.FontWatchRunner.DEFAULT_TEST_STRING = 'BESbswy'; +/** + * @private + */ +webfont.FontWatchRunner.prototype.setupGenericFontFamilySizes_ = function() { + var fontRuler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); + + fontRuler.insert(); + + for (var genericFontFamily in webfont.FontWatchRunner.GenericFontFamily) { + if (webfont.FontWatchRunner.GenericFontFamily.hasOwnProperty(genericFontFamily)) { + fontRuler.setFont(webfont.FontWatchRunner.GenericFontFamily[genericFontFamily], this.fontDescription_); + this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily[genericFontFamily]] = fontRuler.getSize(); + } + } + fontRuler.remove(); +}; + webfont.FontWatchRunner.prototype.start = function() { this.started_ = this.getTime_(); - this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_A, this.fontDescription_); - this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.FALLBACK_FONTS_B, this.fontDescription_); + this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.GenericFontFamily.SERIF, this.fontDescription_); + this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF, this.fontDescription_); this.check_(); }; @@ -84,6 +91,38 @@ webfont.FontWatchRunner.prototype.sizeEquals_ = function(a, b) { return !!a && !!b && a.width === b.width && a.height === b.height; }; +/** + * Returns true if the given size matches the generic font family size. + * + * @private + * @param {?{width: number, height: number}} size + * @param {string} genericFontFamily + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, genericFontFamily) { + return this.sizeEquals_(size, this.genericFontFamilySizes_[genericFontFamily]); +}; + +/** + * Return true if the given sizes match any of the generic font family + * sizes. + * + * @private + * @param {?{width: number, height: number}} a + * @param {?{width: number, height: number}} b + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.sizesMatchGenericFontSizes_ = function(a, b) { + for (var genericFontFamily in webfont.FontWatchRunner.GenericFontFamily) { + if (webfont.FontWatchRunner.GenericFontFamily.hasOwnProperty(genericFontFamily)) { + if (this.sizeMatches_(a, genericFontFamily) && this.sizeMatches_(b, genericFontFamily)) { + return true; + } + } + } + return false; +}; + /** * @private * Returns true if the loading has timed out. @@ -106,12 +145,10 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.fontRulerA_.getSize(); var sizeB = this.fontRulerB_.getSize(); - if ((this.sizeEquals_(sizeA, this.fallbackSizeA_) && this.sizeEquals_(sizeB, this.fallbackSizeB_)) || - (this.hasWebKitFallbackBug_ && this.sizeEquals_(sizeA, this.lastResortSizeA_) && this.sizeEquals_(sizeB, this.lastResortSizeB_))) { + if ((this.sizeMatches_(sizeA, webfont.FontWatchRunner.GenericFontFamily.SERIF) && this.sizeMatches_(sizeB, webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)) || + (this.hasWebKitFallbackBug_ && this.sizesMatchGenericFontSizes_(sizeA, sizeB))) { if (this.hasTimedOut_()) { - if (this.hasWebKitFallbackBug_ && - this.sizeEquals_(sizeA, this.lastResortSizeA_) && - this.sizeEquals_(sizeB, this.lastResortSizeB_)) { + if (this.hasWebKitFallbackBug_ && this.sizesMatchGenericFontSizes_(sizeA, sizeB)) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index d3264331..cffbba3f 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -20,8 +20,8 @@ webfont.LastResortWebKitFontWatchRunner = function(activeCallback, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString); this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_(); this.webKitLastResortSizeChange_ = false; - this.lastObservedSizeA_ = this.fallbackSizeA_; - this.lastObservedSizeB_ = this.fallbackSizeB_; + this.lastObservedSizeA_ = this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily.SERIF]; + this.lastObservedSizeB_ = this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF];; }; webfont.extendsClass(webfont.FontWatchRunner, webfont.LastResortWebKitFontWatchRunner); From 624cef85e0e5039b742af7abdd92d00d83e88a1d Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 7 Jan 2013 16:14:17 +0100 Subject: [PATCH 55/66] Fixed incorrect indexing of the generic font family lookup. --- src/core/fontwatchrunner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index d10d3cbf..b3e06cfd 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -115,7 +115,7 @@ webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, genericFontFamil webfont.FontWatchRunner.prototype.sizesMatchGenericFontSizes_ = function(a, b) { for (var genericFontFamily in webfont.FontWatchRunner.GenericFontFamily) { if (webfont.FontWatchRunner.GenericFontFamily.hasOwnProperty(genericFontFamily)) { - if (this.sizeMatches_(a, genericFontFamily) && this.sizeMatches_(b, genericFontFamily)) { + if (this.sizeMatches_(a, webfont.FontWatchRunner.GenericFontFamily[genericFontFamily]) && this.sizeMatches_(b, webfont.FontWatchRunner.GenericFontFamily[genericFontFamily])) { return true; } } From 40c7eade64ffd2e8b600b427646e154967334d12 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 8 Jan 2013 14:43:43 +0100 Subject: [PATCH 56/66] Added Apple Color Emoji to the generic (last resort) font families. According to http://www.opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/mac/FontCacheMac.mm?txt, Apple Color Emoji is used as a fall back font when it is available. Since it is available on all iOS versions we'll always get it before any other fallback font. Since it doesn't match any of the other generic fonts either we'll have to add it to our list. --- src/core/fontwatchrunner.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index b3e06cfd..3cc5feaa 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -41,8 +41,7 @@ webfont.FontWatchRunner.GenericFontFamily = { SERIF: 'serif', SANS_SERIF: 'sans-serif', MONOSPACE: 'monospace', - CURSIVE: 'cursive', - FANTASY: 'fantasy' + EMOJI: 'Apple Color Emoji' }; /** From 05a4eb65113ea47c7fdc3bd317a7c8b4769c0cb3 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 8 Jan 2013 16:28:48 +0100 Subject: [PATCH 57/66] Fixed FontWatchRunner tests. --- src-test/core/fontwatchrunnertest.js | 98 +++++++++++++++++++--------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index bda2dcbc..242ea4b8 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -125,6 +125,7 @@ FontWatchRunnerTest.prototype.setUp = function() { * See: https://bugs.webkit.org/show_bug.cgi?id=76684 */ this.timesToDelayChangedSizeWebkit_ = 1; + this.firstCallToRetrieveSizeWebkit_ = true; this.fakeWebkitFontSizer_ = { getSize: function(el) { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { @@ -145,11 +146,19 @@ FontWatchRunnerTest.prototype.setUp = function() { }; } } else { - // Return the default width - return { - width: 1, - height: 1 - }; + if (self.firstCallToRetrieveSizeWebkit_) { + self.firstCallToRetrieveSizeWebkit_ = false; + return { + width: 2, + height: 2 + }; + } else { + // Return the default width + return { + width: 1, + height: 1 + }; + } } } }; @@ -165,17 +174,25 @@ FontWatchRunnerTest.prototype.setUp = function() { }; } else { // Return the original width, indicating the font - // failed to load. This should trigger `inactive`. + // failed to load. This should incorrectly trigger `inactive`. return { width: 1, height: 1 }; } } else { - return { - width: 1, - height: 1 - }; + if (self.firstCallToRetrieveSizeWebkit_) { + self.firstCallToRetrieveSizeWebkit_ = false; + return { + width: 2, + height: 2 + }; + } else { + return { + width: 1, + height: 1 + }; + } } } }; @@ -199,10 +216,18 @@ FontWatchRunnerTest.prototype.setUp = function() { }; } } else { - return { - width: 1, - height: 1 - }; + if (self.firstCallToRetrieveSizeWebkit_) { + self.firstCallToRetrieveSizeWebkit_ = false; + return { + width: 2, + height: 2 + }; + } else { + return { + width: 1, + height: 1 + }; + } } } }; @@ -225,10 +250,18 @@ FontWatchRunnerTest.prototype.setUp = function() { }; } } else { - return { - width: 1, - height: 1 - }; + if (self.firstCallToRetrieveSizeWebkit_) { + self.firstCallToRetrieveSizeWebkit_ = false; + return { + width: 2, + height: 2 + }; + } else { + return { + width: 1, + height: 1 + }; + } } } }; @@ -326,6 +359,7 @@ FontWatchRunnerTest.prototype.testWatchFontWaitForLoadInactive = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { this.timesToGetTimeBeforeTimeout_ = 10; this.timesToDelayChangedSizeWebkit_ = 1; + this.firstCallToRetrieveSizeWebkit_ = true; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, @@ -341,6 +375,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithFastFont = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { this.timesToGetTimeBeforeTimeout_ = 10; this.timesToDelayChangedSizeWebkit_ = 2; + this.firstCallToRetrieveSizeWebkit_ = true; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizer_, @@ -356,6 +391,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithSlowFont = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { this.timesToGetTimeBeforeTimeout_ = 10; this.timesToDelayChangedSizeWebkit_ = 2; + this.firstCallToRetrieveSizeWebkit_ = true; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerWithEqualMetrics_, @@ -371,6 +407,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetrics = function() { FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function() { this.timesToGetTimeBeforeTimeout_ = 10; this.timesToDelayChangedSizeWebkit_ = 2; + this.firstCallToRetrieveSizeWebkit_ = true; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizeWithDifferentMetrics_, @@ -386,6 +423,7 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitWithDifferentMetrics = function FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { this.timesToGetTimeBeforeTimeout_ = 10; this.timesToDelayChangedSizeWebkit_ = 5; + this.firstCallToRetrieveSizeWebkit_ = true; var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerFailedLoad_, @@ -394,8 +432,8 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { fontWatchRunner.start(); assertEquals(9, this.asyncCount_); - assertEquals(1, this.fontInactiveCalled_); - assertEquals(true, this.fontInactive_['fontFamily1 n4']); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); }; FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { @@ -408,19 +446,19 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(2, this.createElementCalled_); + assertEquals(3, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_A)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SERIF)); assertEquals('BESbswy', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_B)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)); assertEquals('BESbswy', this.createdElements_[1]['innerHtml']); - assertEquals(2, this.insertIntoCalled_); - assertEquals(2, this.removeElementCalled_); + assertEquals(3, this.insertIntoCalled_); + assertEquals(3, this.removeElementCalled_); }; FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { @@ -434,18 +472,18 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { fontWatchRunner.start(); - assertEquals(2, this.createElementCalled_); + assertEquals(3, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_A)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SERIF)); assertEquals('testString', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.FALLBACK_FONTS_B)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)); assertEquals('testString', this.createdElements_[1]['innerHtml']); - assertEquals(2, this.insertIntoCalled_); - assertEquals(2, this.removeElementCalled_); + assertEquals(3, this.insertIntoCalled_); + assertEquals(3, this.removeElementCalled_); }; From 2acec0bf951cbde1ff875a3568efef5a84575056 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Tue, 8 Jan 2013 19:02:09 +0100 Subject: [PATCH 58/66] Fixed lastresortwebkitfontwatchrunnertest.js. --- src-test/google/lastresortwebkitfontwatchrunnertest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-test/google/lastresortwebkitfontwatchrunnertest.js b/src-test/google/lastresortwebkitfontwatchrunnertest.js index 13126851..0c28d506 100644 --- a/src-test/google/lastresortwebkitfontwatchrunnertest.js +++ b/src-test/google/lastresortwebkitfontwatchrunnertest.js @@ -121,7 +121,7 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontIgnored = this.fontDescription_, false); fontWatchRunner.start(); - assertEquals(2, this.asyncCount_); + assertEquals(1, this.asyncCount_); // When on webkit time out ends up activating the font. assertEquals(1, this.fontActiveCalled_); From 8a52b5a3f25e2f2d56af53763fec1514682ad0a8 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 9 Jan 2013 10:18:26 +0100 Subject: [PATCH 59/66] Renamed genericFontFamilySizes to lastResortSizes. --- src-test/core/fontwatchrunnertest.js | 8 ++-- src/core/fontwatchrunner.js | 41 ++++++++++--------- src/google/lastresortwebkitfontwatchrunner.js | 4 +- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 242ea4b8..8e733668 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -449,12 +449,12 @@ FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { assertEquals(3, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SERIF)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.LastResortFonts.SERIF)); assertEquals('BESbswy', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.LastResortFonts.SANS_SERIF)); assertEquals('BESbswy', this.createdElements_[1]['innerHtml']); assertEquals(3, this.insertIntoCalled_); @@ -475,12 +475,12 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { assertEquals(3, this.createElementCalled_); assertEquals('span', this.createdElements_[0]['name']); assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SERIF)); + assertNotEquals(-1, this.createdElements_[0]['attrs']['style'].indexOf(webfont.FontWatchRunner.LastResortFonts.SERIF)); assertEquals('testString', this.createdElements_[0]['innerHtml']); assertEquals('span', this.createdElements_[1]['name']); assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf('fontFamily1')); - assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)); + assertNotEquals(-1, this.createdElements_[1]['attrs']['style'].indexOf(webfont.FontWatchRunner.LastResortFonts.SANS_SERIF)); assertEquals('testString', this.createdElements_[1]['innerHtml']); assertEquals(3, this.insertIntoCalled_); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 3cc5feaa..d384e0eb 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -23,21 +23,21 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.fontDescription_ = fontDescription; this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING; this.hasWebKitFallbackBug_ = hasWebKitFallbackBug; - this.genericFontFamilySizes_ = {}; + this.lastResortSizes_ = {}; this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerB_.insert(); - this.setupGenericFontFamilySizes_(); + this.setupLastResortSizes_(); }; /** * @enum {string} * @const */ -webfont.FontWatchRunner.GenericFontFamily = { +webfont.FontWatchRunner.LastResortFonts = { SERIF: 'serif', SANS_SERIF: 'sans-serif', MONOSPACE: 'monospace', @@ -56,15 +56,15 @@ webfont.FontWatchRunner.DEFAULT_TEST_STRING = 'BESbswy'; /** * @private */ -webfont.FontWatchRunner.prototype.setupGenericFontFamilySizes_ = function() { +webfont.FontWatchRunner.prototype.setupLastResortSizes_ = function() { var fontRuler = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); fontRuler.insert(); - for (var genericFontFamily in webfont.FontWatchRunner.GenericFontFamily) { - if (webfont.FontWatchRunner.GenericFontFamily.hasOwnProperty(genericFontFamily)) { - fontRuler.setFont(webfont.FontWatchRunner.GenericFontFamily[genericFontFamily], this.fontDescription_); - this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily[genericFontFamily]] = fontRuler.getSize(); + for (var font in webfont.FontWatchRunner.LastResortFonts) { + if (webfont.FontWatchRunner.LastResortFonts.hasOwnProperty(font)) { + fontRuler.setFont(webfont.FontWatchRunner.LastResortFonts[font], this.fontDescription_); + this.lastResortSizes_[webfont.FontWatchRunner.LastResortFonts[font]] = fontRuler.getSize(); } } fontRuler.remove(); @@ -73,8 +73,8 @@ webfont.FontWatchRunner.prototype.setupGenericFontFamilySizes_ = function() { webfont.FontWatchRunner.prototype.start = function() { this.started_ = this.getTime_(); - this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.GenericFontFamily.SERIF, this.fontDescription_); - this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF, this.fontDescription_); + this.fontRulerA_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.LastResortFonts.SERIF, this.fontDescription_); + this.fontRulerB_.setFont(this.fontFamily_ + ',' + webfont.FontWatchRunner.LastResortFonts.SANS_SERIF, this.fontDescription_); this.check_(); }; @@ -95,11 +95,11 @@ webfont.FontWatchRunner.prototype.sizeEquals_ = function(a, b) { * * @private * @param {?{width: number, height: number}} size - * @param {string} genericFontFamily + * @param {string} lastResortFont * @return {boolean} */ -webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, genericFontFamily) { - return this.sizeEquals_(size, this.genericFontFamilySizes_[genericFontFamily]); +webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, lastResortFont) { + return this.sizeEquals_(size, this.lastResortSizes_[lastResortFont]); }; /** @@ -111,10 +111,11 @@ webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, genericFontFamil * @param {?{width: number, height: number}} b * @return {boolean} */ -webfont.FontWatchRunner.prototype.sizesMatchGenericFontSizes_ = function(a, b) { - for (var genericFontFamily in webfont.FontWatchRunner.GenericFontFamily) { - if (webfont.FontWatchRunner.GenericFontFamily.hasOwnProperty(genericFontFamily)) { - if (this.sizeMatches_(a, webfont.FontWatchRunner.GenericFontFamily[genericFontFamily]) && this.sizeMatches_(b, webfont.FontWatchRunner.GenericFontFamily[genericFontFamily])) { +webfont.FontWatchRunner.prototype.sizesMatchLastResortSizes_ = function(a, b) { + for (var font in webfont.FontWatchRunner.LastResortFonts) { + if (webfont.FontWatchRunner.LastResortFonts.hasOwnProperty(font)) { + if (this.sizeMatches_(a, webfont.FontWatchRunner.LastResortFonts[font]) && + this.sizeMatches_(b, webfont.FontWatchRunner.LastResortFonts[font])) { return true; } } @@ -144,10 +145,10 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.fontRulerA_.getSize(); var sizeB = this.fontRulerB_.getSize(); - if ((this.sizeMatches_(sizeA, webfont.FontWatchRunner.GenericFontFamily.SERIF) && this.sizeMatches_(sizeB, webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF)) || - (this.hasWebKitFallbackBug_ && this.sizesMatchGenericFontSizes_(sizeA, sizeB))) { + if ((this.sizeMatches_(sizeA, webfont.FontWatchRunner.LastResortFonts.SERIF) && this.sizeMatches_(sizeB, webfont.FontWatchRunner.LastResortFonts.SANS_SERIF)) || + (this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB))) { if (this.hasTimedOut_()) { - if (this.hasWebKitFallbackBug_ && this.sizesMatchGenericFontSizes_(sizeA, sizeB)) { + if (this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB)) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index cffbba3f..6a997be0 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -20,8 +20,8 @@ webfont.LastResortWebKitFontWatchRunner = function(activeCallback, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_fontTestString); this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_(); this.webKitLastResortSizeChange_ = false; - this.lastObservedSizeA_ = this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily.SERIF]; - this.lastObservedSizeB_ = this.genericFontFamilySizes_[webfont.FontWatchRunner.GenericFontFamily.SANS_SERIF];; + this.lastObservedSizeA_ = this.lastResortSizes_[webfont.FontWatchRunner.LastResortFonts.SERIF]; + this.lastObservedSizeB_ = this.lastResortSizes_[webfont.FontWatchRunner.LastResortFonts.SANS_SERIF];; }; webfont.extendsClass(webfont.FontWatchRunner, webfont.LastResortWebKitFontWatchRunner); From 42dc22412bfd582eaea3027408d5f6ef0847829a Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 9 Jan 2013 14:48:24 +0100 Subject: [PATCH 60/66] Removed old nullFontStyle shim. --- src-test/core/fontwatchrunnertest.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index 8e733668..cf1ec106 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -57,9 +57,7 @@ FontWatchRunnerTest.prototype.setUp = function() { break; } } - }, - insertNullFontStyle: function () { return '__webfontloader_test_0'; }, - removeNullFontStyle: function () { return true; } + } }; this.timesToCheckSizesBeforeChange_ = 0; From ddcef488eab67f1ba8187a09a2f53e981931cd2e Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 9 Jan 2013 15:00:55 +0100 Subject: [PATCH 61/66] Added clarifying comment about Apple Color Emoji. --- src/core/fontwatchrunner.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index d384e0eb..08ad2074 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -41,6 +41,14 @@ webfont.FontWatchRunner.LastResortFonts = { SERIF: 'serif', SANS_SERIF: 'sans-serif', MONOSPACE: 'monospace', + // Apple Color Emoji is the last character fallback on iOS. Since + // all iOS installations that support web fonts have this font it + // effectively means that Apple Color Emoji is the last resort + // font on iOS. The caveat is that it only has characters in the + // Emoji code range, and falls back to the real last resort font, + // which is the default sans-serif font. It however affects the + // height of the span we are monitoring, so we'll have to include + // it in our list of last resort fonts. EMOJI: 'Apple Color Emoji' }; From fef9a9ae9d5cc9e5eddd7d908cc67178a36414ec Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 14 Jan 2013 08:48:51 +0100 Subject: [PATCH 62/66] Export BrowserInfo.prototype.hasWebKitFallbackBug. --- src/core/initialize.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/initialize.js b/src/core/initialize.js index 21ef0222..6c64ca8a 100644 --- a/src/core/initialize.js +++ b/src/core/initialize.js @@ -25,3 +25,4 @@ webfont.UserAgent.prototype['getPlatformVersion'] = webfont.UserAgent.prototype. webfont.UserAgent.prototype['getDocumentMode'] = webfont.UserAgent.prototype.getDocumentMode; webfont.UserAgent.prototype['getBrowserInfo'] = webfont.UserAgent.prototype.getBrowserInfo; webfont.BrowserInfo.prototype['hasWebFontSupport'] = webfont.BrowserInfo.prototype.hasWebFontSupport; +webfont.BrowserInfo.prototype['hasWebKitFallbackBug'] = webfont.BrowserInfo.prototype.hasWebKitFallbackBug; From 06cf21d48eefea3c5a685380f55715519cedc1b3 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 21 Jan 2013 09:55:17 +0100 Subject: [PATCH 63/66] Introduced webfont.Size object. --- src-test/core/fontwatchrunnertest.js | 110 ++++-------------- .../lastresortwebkitfontwatchrunnertest.js | 80 +++---------- src/core/font.js | 5 +- src/core/fontruler.js | 4 +- src/core/fontwatcher.js | 2 +- src/core/fontwatchrunner.js | 21 +--- src/core/size.js | 19 +++ src/google/lastresortwebkitfontwatchrunner.js | 2 +- src/modules.yml | 1 + webfontloader.gemspec | 1 + 10 files changed, 69 insertions(+), 176 deletions(-) create mode 100644 src/core/size.js diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index cf1ec106..cd77bd99 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -68,23 +68,14 @@ FontWatchRunnerTest.prototype.setUp = function() { if (self.timesToCheckSizesBeforeChange_ <= 0) { // Decrement by 0.5 because we're checking two separate font stacks each iteration self.timesToCheckSizesBeforeChange_ -= 0.5; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // Decrement by 0.5 because we're checking two separate font stacks each iteration self.timesToCheckSizesBeforeChange_ -= 0.5; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } else { - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } }; @@ -94,22 +85,13 @@ FontWatchRunnerTest.prototype.setUp = function() { if (el.style.fontFamily.indexOf(self.fontFamily_) != -1) { if (self.timesToCheckSizesBeforeChange_ <= 0) { self.timesToCheckSizesBeforeChange_ -= 0.5; - return { - width: 1, - height: 2 - }; + return new webfont.Size(1, 2); } else { self.timesToCheckSizesBeforeChange_ -= 0.5; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } else { - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } }; @@ -132,30 +114,18 @@ FontWatchRunnerTest.prototype.setUp = function() { // Return the incorrect width for a certain number of cycles. // The actual number depends on how fast or how slow the font // is parsed and applied. - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // Return the correct width - return { - width: 3, - height: 3 - }; + return new webfont.Size(3, 3); } } else { if (self.firstCallToRetrieveSizeWebkit_) { self.firstCallToRetrieveSizeWebkit_ = false; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // Return the default width - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } } @@ -166,30 +136,18 @@ FontWatchRunnerTest.prototype.setUp = function() { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { if (self.timesToDelayChangedSizeWebkit_ > 0) { self.timesToDelayChangedSizeWebkit_ -= 0.5; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // Return the original width, indicating the font // failed to load. This should incorrectly trigger `inactive`. - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } else { if (self.firstCallToRetrieveSizeWebkit_) { self.firstCallToRetrieveSizeWebkit_ = false; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } } @@ -200,31 +158,19 @@ FontWatchRunnerTest.prototype.setUp = function() { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { if (self.timesToDelayChangedSizeWebkit_ > 0) { self.timesToDelayChangedSizeWebkit_ -= 0.5; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // This time the fallback font picked by Webkit has the // same metrics as the font being loaded. This is a rare // case but we should be able to handle it. - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } } else { if (self.firstCallToRetrieveSizeWebkit_) { self.firstCallToRetrieveSizeWebkit_ = false; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } } @@ -235,30 +181,18 @@ FontWatchRunnerTest.prototype.setUp = function() { if (el.style.fontFamily.indexOf(self.fontFamily_) !== -1) { if (self.timesToDelayChangedSizeWebkit_ > 0) { self.timesToDelayChangedSizeWebkit_ -= 0.5; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { // Even though the width is the same, the height // is different, so this should trigger the active event. - return { - width: 2, - height: 3 - }; + return new webfont.Size(2, 3); } } else { if (self.firstCallToRetrieveSizeWebkit_) { self.firstCallToRetrieveSizeWebkit_ = false; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } else { - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } } } diff --git a/src-test/google/lastresortwebkitfontwatchrunnertest.js b/src-test/google/lastresortwebkitfontwatchrunnertest.js index 0c28d506..f7156058 100644 --- a/src-test/google/lastresortwebkitfontwatchrunnertest.js +++ b/src-test/google/lastresortwebkitfontwatchrunnertest.js @@ -84,38 +84,23 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontIgnored = this.fakeDomHelper_, {getSize: function() { if (originalSizeCount > 0) { originalSizeCount--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } if (firstSize > 0) { firstSize--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } if (secondSize > 0) { secondSize--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } if (thirdSize > 0) { thirdSize--; - return { - width: 3, - height: 3 - }; + return new webfont.Size(3, 3); } }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, this.fontDescription_, false); @@ -144,29 +129,17 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontActiveWhenSizeMa this.fakeDomHelper_, {getSize: function() { if (originalSizeCount > 0) { originalSizeCount--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } if (firstSize > 0) { firstSize--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, this.fontDescription_, false); @@ -194,50 +167,29 @@ LastResortWebKitFontWatchRunnerTest.prototype.testLastResortFontInactiveWhenSize this.fakeDomHelper_, {getSize: function(elem) { if (originalSizeCount > 0) { originalSizeCount--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1); } if (lastResortFontsCount > 0) { lastResortFontsCount--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } if (firstSize > 0) { firstSize--; - return { - width: 1, - height: 1 - }; + return new webfont.Size(1, 1) } if (secondSize > 0) { secondSize--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2) } if (thirdSize == 2) { thirdSize--; - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); } if (thirdSize == 1) { thirdSize--; - return { - width: 4, - height: 4 - }; + return new webfont.Size(4, 4); } - return { - width: 2, - height: 2 - }; + return new webfont.Size(2, 2); }}, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, this.fontDescription_, false); diff --git a/src/core/font.js b/src/core/font.js index 7fc14b46..97ef230a 100644 --- a/src/core/font.js +++ b/src/core/font.js @@ -80,10 +80,7 @@ webfont.WebFont.prototype.load_ = function(eventDispatcher, configuration) { var fontWatcher = new webfont.FontWatcher(this.userAgent_, this.domHelper_, eventDispatcher, { getSize: function(elem) { - return { - width: elem.offsetWidth, - height: elem.offsetHeight - }; + return new webfont.Size(elem.offsetWidth, elem.offsetHeight); }}, self.asyncCall_, function() { return new Date().getTime(); }); diff --git a/src/core/fontruler.js b/src/core/fontruler.js index 17b725b8..43d76658 100644 --- a/src/core/fontruler.js +++ b/src/core/fontruler.js @@ -3,7 +3,7 @@ * of a given font and string. * @constructor * @param {webfont.DomHelper} domHelper - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {string} fontTestString */ webfont.FontRuler = function(domHelper, fontSizer, fontTestString) { @@ -47,7 +47,7 @@ webfont.FontRuler.prototype.computeStyleString_ = function(fontFamily, opt_fontD }; /** - * @return {{width: number, height: number}} + * @return {webfont.Size} */ webfont.FontRuler.prototype.getSize = function() { return this.fontSizer_.getSize(this.el_); diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 5ed0ea22..001bf1f6 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -3,7 +3,7 @@ * @param {webfont.UserAgent} userAgent * @param {webfont.DomHelper} domHelper * @param {webfont.EventDispatcher} eventDispatcher - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime */ diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 08ad2074..714aef14 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -3,7 +3,7 @@ * @param {function(string, string)} activeCallback * @param {function(string, string)} inactiveCallback * @param {webfont.DomHelper} domHelper - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime * @param {string} fontFamily @@ -87,27 +87,16 @@ webfont.FontWatchRunner.prototype.start = function() { this.check_(); }; -/** - * @private - * Returns true if two metrics are the same. - * @param {?{width: number, height: number}} a - * @param {?{width: number, height: number}} b - * @return {boolean} - */ -webfont.FontWatchRunner.prototype.sizeEquals_ = function(a, b) { - return !!a && !!b && a.width === b.width && a.height === b.height; -}; - /** * Returns true if the given size matches the generic font family size. * * @private - * @param {?{width: number, height: number}} size + * @param {?webfont.Size} size * @param {string} lastResortFont * @return {boolean} */ webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, lastResortFont) { - return this.sizeEquals_(size, this.lastResortSizes_[lastResortFont]); + return size.equals(this.lastResortSizes_[lastResortFont]); }; /** @@ -115,8 +104,8 @@ webfont.FontWatchRunner.prototype.sizeMatches_ = function(size, lastResortFont) * sizes. * * @private - * @param {?{width: number, height: number}} a - * @param {?{width: number, height: number}} b + * @param {?webfont.Size} a + * @param {?webfont.Size} b * @return {boolean} */ webfont.FontWatchRunner.prototype.sizesMatchLastResortSizes_ = function(a, b) { diff --git a/src/core/size.js b/src/core/size.js new file mode 100644 index 00000000..0b43231a --- /dev/null +++ b/src/core/size.js @@ -0,0 +1,19 @@ +/** + * @constructor + * @param {number} width + * @param {number} height + */ +webfont.Size = function (width, height) { + this.width = width; + this.height = height; +}; + +/** + * Returns true if this size equals other. + * + * @param {webfont.Size} other + * @return {boolean} + */ +webfont.Size.prototype.equals = function (other) { + return !!other && this.width == other.width && this.height == other.height; +}; diff --git a/src/google/lastresortwebkitfontwatchrunner.js b/src/google/lastresortwebkitfontwatchrunner.js index 6a997be0..abc3d9ab 100644 --- a/src/google/lastresortwebkitfontwatchrunner.js +++ b/src/google/lastresortwebkitfontwatchrunner.js @@ -3,7 +3,7 @@ * @param {function(string, string)} activeCallback * @param {function(string, string)} inactiveCallback * @param {webfont.DomHelper} domHelper - * @param {Object.} fontSizer + * @param {Object.} fontSizer * @param {function(function(), number=)} asyncCall * @param {function(): number} getTime * @param {string} fontFamily diff --git a/src/modules.yml b/src/modules.yml index 61b0b8ca..051e82e0 100644 --- a/src/modules.yml +++ b/src/modules.yml @@ -6,6 +6,7 @@ core: - core/useragentparser.js - core/eventdispatcher.js - core/fontmoduleloader.js + - core/size.js - core/fontwatcher.js - core/fontwatchrunner.js - core/fontruler.js diff --git a/webfontloader.gemspec b/webfontloader.gemspec index 1c0463fe..629636e9 100644 --- a/webfontloader.gemspec +++ b/webfontloader.gemspec @@ -133,6 +133,7 @@ DESC src/core/cssfontfamilyname.js src/core/domhelper.js src/core/eventdispatcher.js + src/core/size.js src/core/font.js src/core/fontmoduleloader.js src/core/fontruler.js From 75c67f79b6e54918ae381539410b93b40f7ab4d2 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 21 Jan 2013 10:29:21 +0100 Subject: [PATCH 64/66] Added option to configure metric compatible fonts that are checked for matches when the timeout has occured and we suspect a metric compatible font. --- src-test/core/fontwatchertest.js | 2 +- src-test/core/fontwatchrunnertest.js | 35 +++++++++++++++++++++++++++- src/core/fontwatcher.js | 4 ++-- src/core/fontwatchrunner.js | 9 +++++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src-test/core/fontwatchertest.js b/src-test/core/fontwatchertest.js index 0b795f20..dd6e69f5 100644 --- a/src-test/core/fontwatchertest.js +++ b/src-test/core/fontwatchertest.js @@ -67,7 +67,7 @@ FontWatcherTest.prototype.setUp = function() { this.testStringCount_ = 0; this.testStrings_ = {}; webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, checkWebkitFallbackBug, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebkitFallbackBug, opt_metricCompatibleFonts, opt_fontTestString) { if (opt_fontTestString) { self.testStringCount_++; self.testStrings_[fontFamily] = opt_fontTestString; diff --git a/src-test/core/fontwatchrunnertest.js b/src-test/core/fontwatchrunnertest.js index cd77bd99..35b286d8 100644 --- a/src-test/core/fontwatchrunnertest.js +++ b/src-test/core/fontwatchrunnertest.js @@ -368,6 +368,39 @@ FontWatchRunnerTest.prototype.testWatchFontWebkitFailedLoad = function() { assertEquals(true, this.fontActive_['fontFamily1 n4']); }; +FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetricsIncompatibleFont = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedSizeWebkit_ = 2; + this.firstCallToRetrieveSizeWebkit_ = true; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerWithEqualMetrics_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true, { 'fontFamily2': true }); + + fontWatchRunner.start(); + assertEquals(9, this.asyncCount_); + assertEquals(1, this.fontInactiveCalled_); + assertEquals(true, this.fontInactive_['fontFamily1 n4']); +}; + +FontWatchRunnerTest.prototype.testWatchFontWebkitWithEqualMetricsCompatibleFont = function() { + this.timesToGetTimeBeforeTimeout_ = 10; + this.timesToDelayChangedSizeWebkit_ = 2; + this.firstCallToRetrieveSizeWebkit_ = true; + + var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, + this.inactiveCallback_, this.fakeDomHelper_, this.fakeWebkitFontSizerWithEqualMetrics_, + this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, + this.fontDescription_, true, { 'fontFamily1': true }); + + fontWatchRunner.start(); + assertEquals(9, this.asyncCount_); + assertEquals(1, this.fontActiveCalled_); + assertEquals(true, this.fontActive_['fontFamily1 n4']); +}; + + FontWatchRunnerTest.prototype.testDomWithDefaultTestString = function() { this.timesToCheckSizesBeforeChange_ = 3; this.timesToGetTimeBeforeTimeout_ = 10; @@ -400,7 +433,7 @@ FontWatchRunnerTest.prototype.testDomWithNotDefaultTestString = function() { var fontWatchRunner = new webfont.FontWatchRunner(this.activeCallback_, this.inactiveCallback_, this.fakeDomHelper_, this.fakeFontSizer_, this.fakeAsyncCall_, this.fakeGetTime_, this.fontFamily_, - this.fontDescription_, false, 'testString'); + this.fontDescription_, false, null, 'testString'); fontWatchRunner.start(); diff --git a/src/core/fontwatcher.js b/src/core/fontwatcher.js index 001bf1f6..01994ae4 100644 --- a/src/core/fontwatcher.js +++ b/src/core/fontwatcher.js @@ -38,7 +38,7 @@ webfont.FontWatcher.DEFAULT_VARIATION = 'n4'; * function(string, string), webfont.DomHelper, * Object., * function(function(), number=), function(): number, string, string, - * boolean, string=)} fontWatchRunnerCtor The font watch runner constructor. + * boolean, Object.=, string=)} fontWatchRunnerCtor The font watch runner constructor. * @param {boolean} last True if this is the last set of families to watch. */ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, @@ -71,7 +71,7 @@ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions, var inactiveCallback = webfont.bind(this, this.fontInactive_) var fontWatchRunner = new fontWatchRunnerCtor(activeCallback, inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_, - this.getTime_, fontFamily, fontDescription, this.hasWebKitFallbackBug_, fontTestString); + this.getTime_, fontFamily, fontDescription, this.hasWebKitFallbackBug_, null, fontTestString); fontWatchRunner.start(); } diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 714aef14..2152f23e 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -9,10 +9,11 @@ * @param {string} fontFamily * @param {string} fontDescription * @param {boolean} hasWebKitFallbackBug + * @param {Object.=} opt_metricCompatibleFonts * @param {string=} opt_fontTestString */ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, - fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebKitFallbackBug, opt_fontTestString) { + fontSizer, asyncCall, getTime, fontFamily, fontDescription, hasWebKitFallbackBug, opt_metricCompatibleFonts, opt_fontTestString) { this.activeCallback_ = activeCallback; this.inactiveCallback_ = inactiveCallback; this.domHelper_ = domHelper; @@ -25,6 +26,8 @@ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper, this.hasWebKitFallbackBug_ = hasWebKitFallbackBug; this.lastResortSizes_ = {}; + this.metricCompatibleFonts_ = opt_metricCompatibleFonts || null; + this.fontRulerA_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); this.fontRulerA_.insert(); this.fontRulerB_ = new webfont.FontRuler(this.domHelper_, this.fontSizer_, this.fontTestString_); @@ -145,7 +148,9 @@ webfont.FontWatchRunner.prototype.check_ = function() { if ((this.sizeMatches_(sizeA, webfont.FontWatchRunner.LastResortFonts.SERIF) && this.sizeMatches_(sizeB, webfont.FontWatchRunner.LastResortFonts.SANS_SERIF)) || (this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB))) { if (this.hasTimedOut_()) { - if (this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB)) { + if (this.hasWebKitFallbackBug_ && + this.sizesMatchLastResortSizes_(sizeA, sizeB) && + (this.metricCompatibleFonts_ === null || this.metricCompatibleFonts_.hasOwnProperty(this.fontFamily_))) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); From df9172338767558100d6d33c9b7d44092c86a33d Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Mon, 21 Jan 2013 10:47:16 +0100 Subject: [PATCH 65/66] Attempt at clearing up FontWatchRunner.prototype.check_ logic. --- src/core/fontwatchrunner.js | 43 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 2152f23e..4581421b 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -132,6 +132,42 @@ webfont.FontWatchRunner.prototype.hasTimedOut_ = function() { return this.getTime_() - this.started_ >= 5000; }; +/** + * Returns true if both fonts match the normal fallback fonts. + * + * @private + * @param {webfont.Size} sizeA + * @param {webfont.Size} sizeB + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.isFallbackFont_ = function (sizeA, sizeB) { + return this.sizeMatches_(sizeA, webfont.FontWatchRunner.LastResortFonts.SERIF) && + this.sizeMatches_(sizeB, webfont.FontWatchRunner.LastResortFonts.SANS_SERIF); +}; + +/** + * Returns true if the WebKit bug is present and both sizes match a last resort font. + * + * @private + * @param {webfont.Size} sizeA + * @param {webfont.Size} sizeB + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.isLastResortFont_ = function (sizeA, sizeB) { + return this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB); +}; + +/** + * Returns true if the current font is metric compatible. Also returns true + * if we do not have a list of metric compatible fonts. + * + * @private + * @return {boolean} + */ +webfont.FontWatchRunner.prototype.isMetricCompatibleFont_ = function () { + return this.metricCompatibleFonts_ === null || this.metricCompatibleFonts_.hasOwnProperty(this.fontFamily_); +}; + /** * Checks the size of the two spans against their original sizes during each * async loop. If the size of one of the spans is different than the original @@ -145,12 +181,9 @@ webfont.FontWatchRunner.prototype.check_ = function() { var sizeA = this.fontRulerA_.getSize(); var sizeB = this.fontRulerB_.getSize(); - if ((this.sizeMatches_(sizeA, webfont.FontWatchRunner.LastResortFonts.SERIF) && this.sizeMatches_(sizeB, webfont.FontWatchRunner.LastResortFonts.SANS_SERIF)) || - (this.hasWebKitFallbackBug_ && this.sizesMatchLastResortSizes_(sizeA, sizeB))) { + if (this.isFallbackFont_(sizeA, sizeB) || this.isLastResortFont_(sizeA, sizeB)) { if (this.hasTimedOut_()) { - if (this.hasWebKitFallbackBug_ && - this.sizesMatchLastResortSizes_(sizeA, sizeB) && - (this.metricCompatibleFonts_ === null || this.metricCompatibleFonts_.hasOwnProperty(this.fontFamily_))) { + if (this.isLastResortFont_(sizeA, sizeB) && this.isMetricCompatibleFont_()) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); From 77c5e3be854591352670015fa00a962c5a333868 Mon Sep 17 00:00:00 2001 From: Bram Stein Date: Wed, 30 Jan 2013 13:01:21 +0100 Subject: [PATCH 66/66] Fixed broken test after merging in master. --- src-test/core/useragenttest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-test/core/useragenttest.js b/src-test/core/useragenttest.js index 9e70df91..01bd80df 100644 --- a/src-test/core/useragenttest.js +++ b/src-test/core/useragenttest.js @@ -751,5 +751,5 @@ UserAgentTest.prototype.testBrowserWebKitVSWebkit = function() { assertEquals("AppleWebKit", userAgent.getEngine()); assertEquals("534.30", userAgent.getEngineVersion()); assertEquals(undefined, userAgent.getDocumentMode()); - assertTrue(userAgent.isSupportingWebFont()); + assertTrue(userAgent.getBrowserInfo().hasWebFontSupport()); };