You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
7.3 KiB
153 lines
7.3 KiB
/* |
|
** fontface -- Font Preparation for Web usage via CSS @font-face |
|
** Copyright (c) 2010-2015 Ralf S. Engelschall <rse@engelschall.com> |
|
** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt> |
|
** fontface.js: browser workarounds (language: JavaScript/1.5) |
|
** |
|
** Background: |
|
** Opera (even until 11.60, appVersion 9.80) is known |
|
** to be buggy when it comes to the @font-face rules. |
|
** The bug is that is does only use the font-family |
|
** as the unique name and not the combination of |
|
** font-family+font-style+font-weight+font-stretch+font-variant. |
|
** Additionally, the CSS3 font-stretch property is also not |
|
** understood at all. |
|
** |
|
** Problem: |
|
** The last @font-face rule for a particular font-family overrides |
|
** all previous ones and as a result the wrong fonts are used. |
|
** |
|
** Workaround: |
|
** We walk through all @font-face rules and make copies of |
|
** them with a font-family property value including the |
|
** font-weight+font-style+font-stretch+font-variant information. |
|
** Additionally, we activate these generated @font-face rules |
|
** and change the style on all DOM elements to those generated |
|
** @font-face rules. |
|
** |
|
** See Also: |
|
** http://dev.opera.com/articles/view/seven-web-fonts-showcases/ |
|
*/ |
|
|
|
(function () { |
|
var fixme = function () { |
|
/* 1. determine all @font-face CSS rules, remember |
|
their font-family attributes (for later substitution) |
|
and assemble the substitution CSS rules */ |
|
|
|
/* iterate over all stylesheets */ |
|
var css_rules = ""; |
|
var font_families = {}; |
|
for (var i = 0; i < document.styleSheets.length; i++) { |
|
/* iterate over all stylesheet rules */ |
|
var len = document.styleSheets[i].cssRules.length; |
|
for (var j = 0; j < len; j++) { |
|
/* act on @font-face rules only */ |
|
var m; |
|
var cssText = document.styleSheets[i].cssRules[j].cssText; |
|
if (m = cssText.match(/^@font-face\s+\{(.+)\}/)) { |
|
var rules = m[1]; |
|
|
|
/* extract font related rules */ |
|
var font_family = "sans-serif"; |
|
var font_style = "normal"; |
|
var font_weight = "normal"; |
|
var font_stretch = "normal"; |
|
var font_variant = "normal"; |
|
if (m = rules.match(/font-family:\s*("([^""]+)"|'([^'']+)'|([^\s;}]+))/)) |
|
font_family = m[2] || m[3] || m[4]; |
|
if (m = rules.match(/font-style:\s*("([^""]+)"|'([^'']+)'|([^\s;}]+))/)) |
|
font_style = m[2] || m[3] || m[4]; |
|
if (m = rules.match(/font-weight:\s*("([^""]+)"|'([^'']+)'|([^\s;}]+))/)) |
|
font_weight = m[2] || m[3] || m[4]; |
|
if (m = rules.match(/font-stretch:\s*("([^""]+)"|'([^'']+)'|([^\s;}]+))/)) |
|
font_stretch = m[2] || m[3] || m[4]; |
|
if (m = rules.match(/font-variant:\s*("([^""]+)"|'([^'']+)'|([^\s;}]+))/)) |
|
font_variant = m[2] || m[3] || m[4]; |
|
|
|
/* special treatment for oblique style */ |
|
if (font_style == "oblique") { |
|
font_style = "italic"; |
|
cssText = cssText.replace(/(font-style:\s*)[^\s;}]+/, "$1" + font_style); |
|
} |
|
|
|
/* extend the font-family with the style-weight-stretch tag |
|
and remember the original font-family */ |
|
var tag = font_style + "-" + font_weight + "-" + font_stretch + "-" + font_variant; |
|
cssText = cssText.replace(/src:\s+url\('.+?\.eot'\);/, ""); |
|
cssText = cssText.replace(/src:\s+url\(.+?\.eot\);/, ""); |
|
cssText = cssText.replace(/url\('\S+?\.(eot|woff)'\) format\(.+?\),/g, ""); |
|
cssText = cssText.replace(/url\(\S+?\.(eot|woff)\) format\(.+?\),/g, ""); |
|
cssText = cssText.replace(/url\('\S+?\.svg#.+?'\) format\(.+?\);/, ""); |
|
cssText = cssText.replace(/url\(\S+?\.svg#.+?\) format\(.+?\);/, ""); |
|
cssText = cssText.replace(/,(\s+font-style:)/, ";$1"); |
|
cssText = cssText.replace(/local\('.+?'\),/g, ""); |
|
cssText = cssText.replace(/local\(.+?\),/g, ""); |
|
cssText = cssText.replace(/(font-family:\s*"[^""]+)(")/, "$1 "+tag+"$2"); |
|
cssText = cssText.replace(/(font-family:\s*'[^'']+)(')/, "$1 "+tag+"$2"); |
|
css_rules += cssText + "\n"; |
|
font_families[font_family] = true; |
|
} |
|
} |
|
} |
|
|
|
/* 2. activate all generated @font-face CSS rules */ |
|
var sheet = document.createElement('style') |
|
sheet.innerHTML = css_rules; |
|
document.body.appendChild(sheet); |
|
|
|
/* 3. walk over all elements in the whole DOM tree |
|
and substitute font-family rules */ |
|
var walker = document.createTreeWalker( |
|
document, |
|
NodeFilter.SHOW_ELEMENT, |
|
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } }, |
|
false |
|
); |
|
while (walker.nextNode()) { |
|
var node = walker.currentNode; |
|
|
|
/* determine the computed style of an element */ |
|
var style = window.getComputedStyle(node, null); |
|
var font_family = style.getPropertyValue("font-family") || "sans-serif"; |
|
var font_style = style.getPropertyValue("font-style") || "normal"; |
|
var font_weight = style.getPropertyValue("font-weight") || "normal"; |
|
var font_stretch = style.getPropertyValue("font-stretch") || "normal"; |
|
var font_variant = style.getPropertyValue("font-variant") || "normal"; |
|
|
|
/* font-weight alias canonicalization */ |
|
if (font_weight == "normal") { font_weight = "400"; } |
|
else if (font_weight == "bold") { font_weight = "700"; } |
|
|
|
/* act on font-family styled elements for which a @font-face was seen */ |
|
font_family = font_family.replace(/^"(.+)"$/, "$1").replace(/^'(.+)'$/, "$1"); |
|
if (typeof font_families[font_family] !== "undefined" && font_families[font_family]) { |
|
/* extend the font-family with the style-weight-stretch tag */ |
|
font_family += " " + font_style + "-" + font_weight + "-" + font_stretch + "-" + font_variant; |
|
|
|
/* apply the font-family (but delay it a little bit to ensure |
|
that Opera does not stumple over its feet because we are |
|
currently walking through the elements) */ |
|
(function (el, font_family) { |
|
setTimeout(function () { |
|
el.style.fontFamily = font_family; |
|
}, 20); |
|
})(node, font_family); |
|
} |
|
} |
|
}; |
|
|
|
/* act for Opera only */ |
|
if (window.opera && navigator.userAgent.match(/Opera/)) { |
|
var m = navigator.userAgent.match(/Version\/(\d+\.\d+)/) |
|
var version = (m && m[1] ? parseFloat("" + m[1]) : 0.0); |
|
if (version < 12.00) { |
|
window.onload = function () { |
|
setTimeout(function () { |
|
fixme(); |
|
}, 1*1000); |
|
} |
|
} |
|
} |
|
})(); |
|
|
|
|