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

