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

/*
** 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);
}
}
}
})();