Обнаружение поддержки отдельных символов Unicode с помощью JavaScript - PullRequest
24 голосов
/ 16 декабря 2009

Можно ли определить, поддерживает ли клиент определенный символ Unicode или он будет отображен как отсутствующий глиф?

Важно: поддержка в максимально возможном количестве браузеров

Не важно: эффективность, скорость или элегантность

Единственный метод, который я могу придумать, - это использовать холст, поэтому я решил спросить, прежде чем начать этот путь.

Спасибо!

Редактировать: это не предназначено для использования на общедоступном веб-сайте; Я просто пытаюсь составить список символов, поддерживаемых каждым браузером.

Ответы [ 4 ]

9 голосов
/ 16 декабря 2009

Это скорее дикая идея, чем реальный ответ:

Если бы вы могли найти символ, который, как вы знали, всегда отображали бы как отсутствующее поле глифа, вы могли бы использовать ту же технику, что и этот детектор шрифтов javascript - визуализировать символ и отсутствующее поле символа и сравните их ширину. Если они разные, то вы знаете, что персонаж не отображается как отсутствующий глиф. Конечно, это не будет работать вообще для шрифтов с фиксированной шириной, и может иметь много фиксированных негативов для других шрифтов, где много символов имеют одинаковую ширину.

2 голосов
/ 03 ноября 2012

Не уверен, что на него можно положиться при продвижении вперед (браузеры могут изменить то, что показано для неподдерживаемых символов), и я не уверен, что это оптимизировано (поскольку у меня нет хорошего понимания идеальных границ для измерения здесь) ), но следующий подход (рисование текста на холсте и проверка результата в виде изображения) может, в случае проверки, обеспечить более надежную и точную проверку, чем проверка ширины. Весь код в начале - это просто обнаружение браузером, которое мы должны использовать, так как обнаружение функций невозможно.

(function () {

// http://www.quirksmode.org/js/detect.html
var BrowserDetect = {
    init: function () {
        this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
        this.version = this.searchVersion(navigator.userAgent)
            || this.searchVersion(navigator.appVersion)
            || "an unknown version";
        this.OS = this.searchString(this.dataOS) || "an unknown OS";
    },
    searchString: function (data) {
        for (var i=0;i<data.length;i++) {
            var dataString = data[i].string;
            var dataProp = data[i].prop;
            this.versionSearchString = data[i].versionSearch || data[i].identity;
            if (dataString) {
                if (dataString.indexOf(data[i].subString) != -1)
                    return data[i].identity;
            }
            else if (dataProp)
                return data[i].identity;
        }
    },
    searchVersion: function (dataString) {
        var index = dataString.indexOf(this.versionSearchString);
        if (index == -1) return;
        return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
    },
    dataBrowser: [
        {
            string: navigator.userAgent,
            subString: "Chrome",
            identity: "Chrome"
        },
        {   string: navigator.userAgent,
            subString: "OmniWeb",
            versionSearch: "OmniWeb/",
            identity: "OmniWeb"
        },
        {
            string: navigator.vendor,
            subString: "Apple",
            identity: "Safari",
            versionSearch: "Version"
        },
        {
            prop: window.opera,
            identity: "Opera",
            versionSearch: "Version"
        },
        {
            string: navigator.vendor,
            subString: "iCab",
            identity: "iCab"
        },
        {
            string: navigator.vendor,
            subString: "KDE",
            identity: "Konqueror"
        },
        {
            string: navigator.userAgent,
            subString: "Firefox",
            identity: "Firefox"
        },
        {
            string: navigator.vendor,
            subString: "Camino",
            identity: "Camino"
        },
        {       // for newer Netscapes (6+)
            string: navigator.userAgent,
            subString: "Netscape",
            identity: "Netscape"
        },
        {
            string: navigator.userAgent,
            subString: "MSIE",
            identity: "Explorer",
            versionSearch: "MSIE"
        },
        {
            string: navigator.userAgent,
            subString: "Gecko",
            identity: "Mozilla",
            versionSearch: "rv"
        },
        {       // for older Netscapes (4-)
            string: navigator.userAgent,
            subString: "Mozilla",
            identity: "Netscape",
            versionSearch: "Mozilla"
        }
    ],
    dataOS : [
        {
            string: navigator.platform,
            subString: "Win",
            identity: "Windows"
        },
        {
            string: navigator.platform,
            subString: "Mac",
            identity: "Mac"
        },
        {
               string: navigator.userAgent,
               subString: "iPhone",
               identity: "iPhone/iPod"
        },
        {
            string: navigator.platform,
            subString: "Linux",
            identity: "Linux"
        }
    ]

};
BrowserDetect.init();


/**
* Checks whether a given character is supported in the specified font. If the
*   font argument is not provided, it will default to sans-serif, the default
*   of the canvas element
* @param {String} chr Character to check for support
* @param {String} [font] Font Defaults to sans-serif
* @returns {Boolean} Whether or not the character is visually distinct from characters that are not supported
*/
function characterInFont (chr, font) {
    var data,
        size = 10, // We use 10 to confine results (could do further?) and minimum required for 10px
        x = 0, 
        y = size,
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');
    // Necessary?
    canvas.width = size;
    canvas.height = size;

    if (font) { // Default of canvas is 10px sans-serif
        font = size + 'px ' + font; // Fix size so we can test consistently
        /**
        // Is there use to confining by this height?
        var d = document.createElement("span");
        d.font = font;
        d.textContent = chr;
        document.body.appendChild(d);
        var emHeight = d.offsetHeight;
        document.body.removeChild(d);
        alert(emHeight); // 19 after page load on Firefox and Chrome regardless of canvas height
        //*/
    }

    ctx.fillText(chr, x, y);
    data = ctx.getImageData(0, 0, ctx.measureText(chr).width, canvas.height).data; // canvas.width
    data = Array.prototype.slice.apply(data);

    function compareDataToBox (data, box, filter) {
        if (filter) { // We can stop making this conditional if we confirm the exact arrays will continue to work, or otherwise remove and rely on safer full arrays
            data = data.filter(function (item) {
                return item != 0;
            });
        }
        return data.toString() !== box;
    }

    var missingCharBox;
    switch (BrowserDetect.browser) {
        case 'Firefox': // Draws nothing
            missingCharBox = '';
            break;
        case 'Opera':
            //missingCharBox = '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0';
            missingCharBox = '197,255,255,255,255,73,36,36,36,36,36,36,36,36,197,255,255,255,255,73';
            break;
        case 'Chrome':
            missingCharBox = '2,151,255,255,255,255,67,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,151,255,255,255,255,67';
            break;
        case 'Safari':
            missingCharBox = '17,23,23,23,23,5,52,21,21,21,21,41,39,39,39,39,39,39,39,39,63,40,40,40,40,43';
            break;
        default:
            throw 'characterInFont() not tested successfully for this browser';
    }
    return compareDataToBox(data, missingCharBox, true);
}

// EXPORTS
((typeof exports !== 'undefined') ? exports : this).characterInFont = characterInFont;

}());

var r1 = characterInFont('a', 'Arial'); // true
var r2 = characterInFont('\uFAAA', 'Arial'); // false
alert(r1);
alert(r2);

ОБНОВЛЕНИЕ 1

Я попытался обновить для современного Firefox (чтобы проверить ожидаемые шестнадцатеричные цифры на холсте) и проверил, чтобы, в отличие от моего кода выше, холст (и шаблон, соответствующий ему) был достаточно большим, чтобы приспосабливать самый широкий символ на context.measureText() (U + 0BCC из моего тестирования, хотя предположительно зависит от шрифта, в моем случае "Arial Unicode MS"). На https://bugzilla.mozilla.org/show_bug.cgi?id=442133#c9, однако measureText в настоящее время по ошибке реагирует на увеличение только для неизвестных символов. Теперь, если бы только один мог имитировать масштабирование в холсте JavaScript, чтобы влиять на эти измерения (и только эти измерения) ...

Код доступен для справки на https://gist.github.com/brettz9/1f061bb2ce06368db3e5

0 голосов
/ 17 февраля 2011

Вы всегда можете оценить каждый символ, используя метод charCodeAt (). Это вернет значение символа Unicode. В зависимости от того, что вы делаете, вы можете ограничить диапазон, который вы хотите принять как «Действительные» символы ... Если вы скопируете символ, который находится в «поле», вы можете использовать переводчик символов в Интернете, чтобы увидеть, что соответствующее значение Unicode.

Вот тот, который я нашел и нашел: введите описание ссылки здесь

0 голосов
/ 16 декабря 2009

Если вы хотите максимально увеличить поддержку браузера, вы, вероятно, не хотите полагаться на javascript для чего-либо. Многие мобильные браузеры даже не поддерживают его.

Если браузер не поддерживает набор символов, каков запасной вариант? Отображение контента на другом языке? Возможно, ссылки на сайт, которые переключают языки по требованию, были бы более надежными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...