PageSourceSearch

https://globalvillagebelfast.com/wp-content/themes/wisebusiness/js/cufon-yui.js

js globalvillagebelfast.com collected 2026-10-07 03:56:18 UTC 32,513 bytes, 1,241 lines download raw bytes

1/*!
2* Copyright (c) 2009 Simo Kinnunen.
3* Licensed under the MIT license.
4*
5* @version ${Version}
6*/
7 
8var Cufon = (function() {
9 
10var api = function() {
11return api.replace.apply(null, arguments);
12};
13 
14var DOM = api.DOM = {
15 
16ready: (function() {
17 
18var complete = false, readyStatus = { loaded: 1, complete: 1 };
19 
20var queue = [], perform = function() {
21if (complete) return;
22complete = true;
23for (var fn; fn = queue.shift(); fn());
24};
25 
26// Gecko, Opera, WebKit r26101+
27 
28if (document.addEventListener) {
29document.addEventListener('DOMContentLoaded', perform, false);
30window.addEventListener('pageshow', perform, false); // For cached Gecko pages
31}
32 
33// Old WebKit, Internet Explorer
34 
35if (!window.opera && document.readyState) (function() {
36readyStatus[document.readyState] ? perform() : setTimeout(arguments.callee, 10);
37})();
38 
39// Internet Explorer
40 
41if (document.readyState && document.createStyleSheet) (function() {
42try {
43document.body.doScroll('left');
44perform();
45}
46catch (e) {
47setTimeout(arguments.callee, 1);
48}
49})();
50 
51addEvent(window, 'load', perform); // Fallback
52 
53return function(listener) {
54if (!arguments.length) perform();
55else complete ? listener() : queue.push(listener);
56};
57 
58})(),
59 
60root: function() {
61return document.documentElement || document.body;
62}
63 
64};
65 
66var CSS = api.CSS = {
67 
68Size: function(value, base) {
69 
70this.value = parseFloat(value);
71this.unit = String(value).match(/[a-z%]*$/)[0] || 'px';
72 
73this.convert = function(value) {
74return value / base * this.value;
75};
76 
77this.convertFrom = function(value) {
78return value / this.value * base;
79};
80 
81this.toString = function() {
82return this.value + this.unit;
83};
84 
85},
86 
87addClass: function(el, className) {
88var current = el.className;
89el.className = current + (current && ' ') + className;
90return el;
91},
92 
93color: cached(function(value) {
94var parsed = {};
95parsed.color = value.replace(/^rgba\((.*?),\s*([\d.]+)\)/, function($0, $1, $2) {
96parsed.opacity = parseFloat($2);
97return 'rgb(' + $1 + ')';
98});
99return parsed;
100}),
101 
102// has no direct CSS equivalent.
103// @see http://msdn.microsoft.com/en-us/library/system.windows.fontstretches.aspx
104fontStretch: cached(function(value) {
105if (typeof value == 'number') return value;
106if (/%$/.test(value)) return parseFloat(value) / 100;
107return {
108'ultra-condensed': 0.5,
109'extra-condensed': 0.625,
110condensed: 0.75,
111'semi-condensed': 0.875,
112'semi-expanded': 1.125,
113expanded: 1.25,
114'extra-expanded': 1.5,
115'ultra-expanded': 2
116}[value] || 1;
117}),
118 
119getStyle: function(el) {
120var view = document.defaultView;
121if (view && view.getComputedStyle) return new Style(view.getComputedStyle(el, null));
122if (el.currentStyle) return new Style(el.currentStyle);
123return new Style(el.style);
124},
125 
126gradient: cached(function(value) {
127var gradient = {
128id: value,
129type: value.match(/^-([a-z]+)-gradient\(/)[1],
130stops: []
131}, colors = value.substr(value.indexOf('(')).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);
132for (var i = 0, l = colors.length, stop; i < l; ++i) {
133stop = colors[i].split('=', 2).reverse();
134gradient.stops.push([ stop[1] || i / (l - 1), stop[0] ]);
135}
136return gradient;
137}),
138 
139hasClass: function(el, className) {
140return RegExp('(?:^|\\s)' + className + '(?=\\s|$)').test(el.className);
141},
142 
143quotedList: cached(function(value) {
144// doesn't work properly with empty quoted strings (""), but
145// it's not worth the extra code.
146var list = [], re = /\s*((["'])([\s\S]*?[^\\])\2|[^,]+)\s*/g, match;
147while (match = re.exec(value)) list.push(match[3] || match[1]);
148return list;
149}),
150 
151recognizesMedia: cached(function(media) {
152var el = document.createElement('style'), sheet, container, supported;
153el.type = 'text/css';
154el.media = media;
155try { // this is cached anyway
156el.appendChild(document.createTextNode('/**/'));
157} catch (e) {}
158container = elementsByTagName('head')[0];
159container.insertBefore(el, container.firstChild);
160sheet = (el.sheet || el.styleSheet);
161supported = sheet && !sheet.disabled;
162container.removeChild(el);
163return supported;
164}),
165 
166removeClass: function(el, className) {
167var re = RegExp('(?:^|\\s+)' + className + '(?=\\s|$)', 'g');
168el.className = el.className.replace(re, '');
169return el;
170},
171 
172supports: function(property, value) {
173var checker = document.createElement('span').style;
174if (checker[property] === undefined) return false;
175checker[property] = value;
176return checker[property] === value;
177},
178 
179textAlign: function(word, style, position, wordCount) {
180if (style.get('textAlign') == 'right') {
181if (position > 0) word = ' ' + word;
182}
183else if (position < wordCount - 1) word += ' ';
184return word;
185},
186 
187textDecoration: function(el, style) {
188if (!style) style = this.getStyle(el);
189var types = {
190underline: null,
191overline: null,
192'line-through': null
193};
194for (var search = el; search.parentNode && search.parentNode.nodeType == 1; ) {
195var foundAll = true;
196for (var type in types) {
197if (!hasOwnProperty(types, type) || types[type]) continue;
198if (style.get('textDecoration').indexOf(type) != -1) types[type] = style.get('color');
199foundAll = false;
200}
201if (foundAll) break; // this is rather unlikely to happen
202style = this.getStyle(search = search.parentNode);
203}
204return types;
205},
206 
207textShadow: cached(function(value) {
208if (value == 'none') return null;
209var shadows = [], currentShadow = {}, result, offCount = 0;
210var re = /(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)|(-?[\d.]+[a-z%]*)|,/ig;
211while (result = re.exec(value)) {
212if (result[0] == ',') {
213shadows.push(currentShadow);
214currentShadow = {};
215offCount = 0;
216}
217else if (result[1]) {
218currentShadow.color = result[1];
219}
220else {
221currentShadow[[ 'offX', 'offY', 'blur' ][offCount++]] = result[2];
222}
223}
224shadows.push(currentShadow);
225return shadows;
226}),
227 
228textTransform: (function() {
229var map = {
230uppercase: function(s) {
231return s.toUpperCase();
232},
233lowercase: function(s) {
234return s.toLowerCase();
235},
236capitalize: function(s) {
237return s.replace(/\b./g, function($0) {
238return $0.toUpperCase();
239});
240}
241};
242return function(text, style) {
243var transform = map[style.get('textTransform')];
244return transform ? transform(text) : text;
245};
246})(),
247 
248whiteSpace: (function() {
249var ignore = {
250inline: 1,
251'inline-block': 1,
252'run-in': 1
253};
254return function(text, style, node) {
255if (ignore[style.get('display')]) return text;
256if (!node.previousSibling) text = text.replace(/^\s+/, '');
257if (!node.nextSibling) text = text.replace(/\s+$/, '');
258return text;
259};
260})()
261 
262};
263 
264CSS.ready = (function() {
265 
266// don't do anything in Safari 2 (it doesn't recognize any media type)
267var complete = !CSS.recognizesMedia('all'), hasLayout = false;
268 
269var queue = [], perform = function() {
270complete = true;
271for (var fn; fn = queue.shift(); fn());
272};
273 
274var links = elementsByTagName('link'), styles = elementsByTagName('style');
275 
276function isContainerReady(el) {
277return el.disabled || isSheetReady(el.sheet, el.media || 'screen');
278}
279 
280function isSheetReady(sheet, media) {
281// in Opera sheet.disabled is true when it's still loading,
282// even though link.disabled is false. they stay in sync if
283// set manually.
284if (!CSS.recognizesMedia(media || 'all')) return true;
285if (!sheet || sheet.disabled) return false;
286try {
287var rules = sheet.cssRules, rule;
288if (rules) {
289// needed for Safari 3 and Chrome 1.0.
290// in standards-conforming browsers cssRules contains @-rules.
291// Chrome 1.0 weirdness: rules[<number larger than .length - 1>]
292// returns the last rule, so a for loop is the only option.
293search: for (var i = 0, l = rules.length; rule = rules[i], i < l; ++i) {
294switch (rule.type) {
295case 2: // @charset
296break;
297case 3: // @import
298if (!isSheetReady(rule.styleSheet, rule.media.mediaText)) return false;
299break;
300default:
301// only @charset can precede @import
302break search;
303}
304}
305}
306}
307catch (e) {} // probably a style sheet from another domain
308return true;
309}
310 
311function allStylesLoaded() {
312// Internet Explorer's style sheet model, there's no need to do anything
313if (document.createStyleSheet) return true;
314// standards-compliant browsers
315var el, i;
316for (i = 0; el = links[i]; ++i) {
317if (el.rel.toLowerCase() == 'stylesheet' && !isContainerReady(el)) return false;
318}
319for (i = 0; el = styles[i]; ++i) {
320if (!isContainerReady(el)) return false;
321}
322return true;
323}
324 
325DOM.ready(function() {
326// getComputedStyle returns null in Gecko if used in an iframe with display: none
327if (!hasLayout) hasLayout = CSS.getStyle(document.body).isUsable();
328if (complete || (hasLayout && allStylesLoaded())) perform();
329else setTimeout(arguments.callee, 10);
330});
331 
332return function(listener) {
333if (complete) listener();
334else queue.push(listener);
335};
336 
337})();
338 
339function Font(data) {
340 
341var face = this.face = data.face;
342this.glyphs = data.glyphs;
343this.w = data.w;
344this.baseSize = parseInt(face['units-per-em'], 10);
345 
346this.family = face['font-family'].toLowerCase();
347this.weight = face['font-weight'];
348this.style = face['font-style'] || 'normal';
349 
350this.viewBox = (function () {
351var parts = face.bbox.split(/\s+/);
352var box = {
353minX: parseInt(parts[0], 10),
354minY: parseInt(parts[1], 10),
355maxX: parseInt(parts[2], 10),
356maxY: parseInt(parts[3], 10)
357};
358box.width = box.maxX - box.minX;
359box.height = box.maxY - box.minY;
360box.toString = function() {
361return [ this.minX, this.minY, this.width, this.height ].join(' ');
362};
363return box;
364})();
365 
366this.ascent = -parseInt(face.ascent, 10);
367this.descent = -parseInt(face.descent, 10);
368 
369this.height = -this.ascent + this.descent;
370 
371}
372 
373function FontFamily() {
374 
375var styles = {}, mapping = {
376oblique: 'italic',
377italic: 'oblique'
378};
379 
380this.add = function(font) {
381(styles[font.style] || (styles[font.style] = {}))[font.weight] = font;
382};
383 
384this.get = function(style, weight) {
385var weights = styles[style] || styles[mapping[style]]
386|| styles.normal || styles.italic || styles.oblique;
387if (!weights) return null;
388// we don't have to worry about "bolder" and "lighter"
389// because IE's currentStyle returns a numeric value for it,
390// and other browsers use the computed value anyway
391weight = {
392normal: 400,
393bold: 700
394}[weight] || parseInt(weight, 10);
395if (weights[weight]) return weights[weight];
396// http://www.w3.org/TR/CSS21/fonts.html#propdef-font-weight
397// Gecko uses x99/x01 for lighter/bolder
398var up = {
3991: 1,
40099: 0
401}[weight % 100], alts = [], min, max;
402if (up === undefined) up = weight > 400;
403if (weight == 500) weight = 400;
404for (var alt in weights) {
405if (!hasOwnProperty(weights, alt)) continue;
406alt = parseInt(alt, 10);
407if (!min || alt < min) min = alt;
408if (!max || alt > max) max = alt;
409alts.push(alt);
410}
411if (weight < min) weight = min;
412if (weight > max) weight = max;
413alts.sort(function(a, b) {
414return (up
415? (a > weight && b > weight) ? a < b : a > b
416: (a < weight && b < weight) ? a > b : a < b) ? -1 : 1;
417});
418return weights[alts[0]];
419};
420 
421}
422 
423function HoverHandler() {
424 
425function contains(node, anotherNode) {
426if (node.contains) return node.contains(anotherNode);
427return node.compareDocumentPosition(anotherNode) & 16;
428}
429 
430function onOverOut(e) {
431var related = e.relatedTarget;
432if (!related || contains(this, related)) return;
433trigger(this);
434}
435 
436function onEnterLeave(e) {
437trigger(this);
438}
439 
440function trigger(el) {
441// A timeout is needed so that the event can actually "happen"
442// before replace is triggered. This ensures that styles are up
443// to date.
444setTimeout(function() {
445api.replace(el, sharedStorage.get(el).options, true);
446}, 10);
447}
448 
449this.attach = function(el) {
450if (el.onmouseenter === undefined) {
451addEvent(el, 'mouseover', onOverOut);
452addEvent(el, 'mouseout', onOverOut);
453}
454else {
455addEvent(el, 'mouseenter', onEnterLeave);
456addEvent(el, 'mouseleave', onEnterLeave);
457}
458};
459 
460}
461 
462function ReplaceHistory() {
463 
464var list = [], map = {};
465 
466function filter(keys) {
467var values = [], key;
468for (var i = 0; key = keys[i]; ++i) values[i] = list[map[key]];
469return values;
470}
471 
472this.add = function(key, args) {
473map[key] = list.push(args) - 1;
474};
475 
476this.repeat = function() {
477var snapshot = arguments.length ? filter(arguments) : list, args;
478for (var i = 0; args = snapshot[i++];) api.replace(args[0], args[1], true);
479};
480 
481}
482 
483function Storage() {
484 
485var map = {}, at = 0;
486 
487function identify(el) {
488return el.cufid || (el.cufid = ++at);
489}
490 
491this.get = function(el) {
492var id = identify(el);
493return map[id] || (map[id] = {});
494};
495 
496}
497 
498function Style(style) {
499 
500var custom = {}, sizes = {};
501 
502this.extend = function(styles) {
503for (var property in styles) {
504if (hasOwnProperty(styles, property)) custom[property] = styles[property];
505}
506return this;
507};
508 
509this.get = function(property) {
510return custom[property] != undefined ? custom[property] : style[property];
511};
512 
513this.getSize = function(property, base) {
514return sizes[property] || (sizes[property] = new CSS.Size(this.get(property), base));
515};
516 
517this.isUsable = function() {
518return !!style;
519};
520 
521}
522 
523function addEvent(el, type, listener) {
524if (el.addEventListener) {
525el.addEventListener(type, listener, false);
526}
527else if (el.attachEvent) {
528el.attachEvent('on' + type, function() {
529return listener.call(el, window.event);
530});
531}
532}
533 
534function attach(el, options) {
535var storage = sharedStorage.get(el);
536if (storage.options) return el;
537if (options.hover && options.hoverables[el.nodeName.toLowerCase()]) {
538hoverHandler.attach(el);
539}
540storage.options = options;
541return el;
542}
543 
544function cached(fun) {
545var cache = {};
546return function(key) {
547if (!hasOwnProperty(cache, key)) cache[key] = fun.apply(null, arguments);
548return cache[key];
549};
550}
551 
552function getFont(el, style) {
553var families = CSS.quotedList(style.get('fontFamily').toLowerCase()), family;
554for (var i = 0; family = families[i]; ++i) {
555if (fonts[family]) return fonts[family].get(style.get('fontStyle'), style.get('fontWeight'));
556}
557return null;
558}
559 
560function elementsByTagName(query) {
561return document.getElementsByTagName(query);
562}
563 
564function hasOwnProperty(obj, property) {
565return obj.hasOwnProperty(property);
566}
567 
568function merge() {
569var merged = {}, args, key;
570for (var i = 0, l = arguments.length; args = arguments[i], i < l; ++i) {
571for (key in args) {
572if (hasOwnProperty(args, key)) merged[key] = args[key];
573}
574}
575return merged;
576}
577 
578function process(font, text, style, options, node, el) {
579var fragment = document.createDocumentFragment(), processed;
580if (text === '') return fragment;
581var separate = options.separate;
582var parts = text.split(separators[separate]), needsAligning = (separate == 'words');
583if (needsAligning && HAS_BROKEN_REGEXP) {
584// @todo figure out a better way to do this
585if (/^\s/.test(text)) parts.unshift('');
586if (/\s$/.test(text)) parts.push('');
587}
588for (var i = 0, l = parts.length; i < l; ++i) {
589processed = engines[options.engine](font,
590needsAligning ? CSS.textAlign(parts[i], style, i, l) : parts[i],
591style, options, node, el, i < l - 1);
592if (processed) fragment.appendChild(processed);
593}
594return fragment;
595}
596 
597function replaceElement(el, options) {
598var style = CSS.getStyle(attach(el, options)).extend(options);
599var font = getFont(el, style), node, type, next, anchor, text;
600for (node = el.firstChild; node; node = next) {
601type = node.nodeType;
602next = node.nextSibling;
603if (type == 3) {
604// Node.normalize() is broken in IE 6, 7, 8
605if (anchor) {
606anchor.appendData(node.data);
607el.removeChild(node);
608}
609else anchor = node;
610if (next) continue;
611}
612if (anchor) {
613el.replaceChild(process(font,
614CSS.whiteSpace(anchor.data, style, anchor),
615style, options, node, el), anchor);
616anchor = null;
617}
618if (type == 1 && node.firstChild) {
619if (CSS.hasClass(node, 'cufon')) {
620engines[options.engine](font, null, style, options, node, el);
621}
622else arguments.callee(node, options);
623}
624}
625}
626 
627var HAS_BROKEN_REGEXP = ' '.split(/\s+/).length == 0;
628 
629var sharedStorage = new Storage();
630var hoverHandler = new HoverHandler();
631var replaceHistory = new ReplaceHistory();
632var initialized = false;
633 
634var engines = {}, fonts = {}, defaultOptions = {
635autoDetect: false,
636enableTextDecoration: false,
637engine: null,
638//fontScale: 1,
639//fontScaling: false,
640forceHitArea: false,
641hover: false,
642hoverables: {
643a: true
644},
645printable: true,
646//rotation: 0,
647//selectable: false,
648selector: (
649window.Sizzle
650|| (window.jQuery && function(query) { return jQuery(query); }) // avoid noConflict issues
651|| (window.dojo && dojo.query)
652|| (window.Ext && Ext.query)
653|| (window.$$ && function(query) { return $$(query); })
654|| (window.$ && function(query) { return $(query); })
655|| (document.querySelectorAll && function(query) { return document.querySelectorAll(query); })
656|| elementsByTagName
657),
658separate: 'words', // 'none' and 'characters' are also accepted
659textShadow: 'none'
660};
661 
662var separators = {
663words: /[^\S\u00a0]+/,
664characters: '',
665none: /^/
666};
667 
668api.now = function() {
669DOM.ready();
670return api;
671};
672 
673api.refresh = function() {
674replaceHistory.repeat.apply(replaceHistory, arguments);
675return api;
676};
677 
678api.registerEngine = function(id, engine) {
679if (!engine) return api;
680engines[id] = engine;
681return api.set('engine', id);
682};
683 
684api.registerFont = function(data) {
685var font = new Font(data), family = font.family;
686if (!fonts[family]) fonts[family] = new FontFamily();
687fonts[family].add(font);
688return api.set('fontFamily', '"' + family + '"');
689};
690 
691api.replace = function(elements, options, ignoreHistory) {
692options = merge(defaultOptions, options);
693if (!options.engine) return api; // there's no browser support so we'll just stop here
694if (!initialized) {
695CSS.addClass(DOM.root(), 'cufon-active cufon-loading');
696CSS.ready(function() {
697// fires before any replace() calls, but it doesn't really matter
698CSS.addClass(CSS.removeClass(DOM.root(), 'cufon-loading'), 'cufon-ready');
699});
700initialized = true;
701}
702if (options.hover) options.forceHitArea = true;
703if (options.autoDetect) delete options.fontFamily;
704if (typeof options.textShadow == 'string')
705options.textShadow = CSS.textShadow(options.textShadow);
706if (typeof options.color == 'string' && /^-/.test(options.color))
707options.textGradient = CSS.gradient(options.color);
708if (!ignoreHistory) replaceHistory.add(elements, arguments);
709if (elements.nodeType || typeof elements == 'string') elements = [ elements ];
710CSS.ready(function() {
711for (var i = 0, l = elements.length; i < l; ++i) {
712var el = elements[i];
713if (typeof el == 'string') api.replace(options.selector(el), options, true);
714else replaceElement(el, options);
715}
716});
717return api;
718};
719 
720api.set = function(option, value) {
721defaultOptions[option] = value;
722return api;
723};
724 
725return api;
726 
727})();
728 
729Cufon.registerEngine('canvas', (function() {
730 
731// Safari 2 doesn't support .apply() on native methods
732 
733var check = document.createElement('canvas');
734if (!check || !check.getContext || !check.getContext.apply) return;
735check = null;
736 
737var HAS_INLINE_BLOCK = Cufon.CSS.supports('display', 'inline-block');
738 
739// Firefox 2 w/ non-strict doctype (almost standards mode)
740var HAS_BROKEN_LINEHEIGHT = !HAS_INLINE_BLOCK && (document.compatMode == 'BackCompat' || /frameset|transitional/i.test(document.doctype.publicId));
741 
742var styleSheet = document.createElement('style');
743styleSheet.type = 'text/css';
744styleSheet.appendChild(document.createTextNode((
745'.cufon-canvas{text-indent:0;}' +
746'@media screen,projection{' +
747'.cufon-canvas{display:inline;display:inline-block;position:relative;vertical-align:middle;' +
748(HAS_BROKEN_LINEHEIGHT
749? ''
750: 'font-size:1px;line-height:1px;') +
751'}.cufon-canvas .cufon-alt{display:-moz-inline-box;display:inline-block;width:0;height:0;overflow:hidden;text-indent:-10000in;}' +
752(HAS_INLINE_BLOCK
753? '.cufon-canvas canvas{position:relative;}'
754: '.cufon-canvas canvas{position:absolute;}') +
755'}' +
756'@media print{' +
757'.cufon-canvas{padding:0;}' +
758'.cufon-canvas canvas{display:none;}' +
759'.cufon-canvas .cufon-alt{display:inline;}' +
760'}'
761).replace(/;/g, '!important;')));
762document.getElementsByTagName('head')[0].appendChild(styleSheet);
763 
764function generateFromVML(path, context) {
765var atX = 0, atY = 0;
766var code = [], re = /([mrvxe])([^a-z]*)/g, match;
767generate: for (var i = 0; match = re.exec(path); ++i) {
768var c = match[2].split(',');
769switch (match[1]) {
770case 'v':
771code[i] = { m: 'bezierCurveTo', a: [ atX + ~~c[0], atY + ~~c[1], atX + ~~c[2], atY + ~~c[3], atX += ~~c[4], atY += ~~c[5] ] };
772break;
773case 'r':
774code[i] = { m: 'lineTo', a: [ atX += ~~c[0], atY += ~~c[1] ] };
775break;
776case 'm':
777code[i] = { m: 'moveTo', a: [ atX = ~~c[0], atY = ~~c[1] ] };
778break;
779case 'x':
780code[i] = { m: 'closePath' };
781break;
782case 'e':
783break generate;
784}
785context[code[i].m].apply(context, code[i].a);
786}
787return code;
788}
789 
790function interpret(code, context) {
791for (var i = 0, l = code.length; i < l; ++i) {
792var line = code[i];
793context[line.m].apply(context, line.a);
794}
795}
796 
797return function(font, text, style, options, node, el) {
798 
799var redraw = (text === null);
800 
801if (redraw) text = node.alt;
802 
803var viewBox = font.viewBox;
804 
805var size = style.getSize('fontSize', font.baseSize);
806 
807var letterSpacing = style.get('letterSpacing');
808letterSpacing = (letterSpacing == 'normal') ? 0 : size.convertFrom(parseInt(letterSpacing, 10));
809 
810var expandTop = 0, expandRight = 0, expandBottom = 0, expandLeft = 0;
811var shadows = options.textShadow, shadowOffsets = [];
812if (shadows) {
813for (var i = shadows.length; i--;) {
814var shadow = shadows[i];
815var x = size.convertFrom(parseFloat(shadow.offX));
816var y = size.convertFrom(parseFloat(shadow.offY));
817shadowOffsets[i] = [ x, y ];
818if (y < expandTop) expandTop = y;
819if (x > expandRight) expandRight = x;
820if (y > expandBottom) expandBottom = y;
821if (x < expandLeft) expandLeft = x;
822}
823}
824 
825var chars = Cufon.CSS.textTransform(text, style).split(''), chr;
826 
827var glyphs = font.glyphs, glyph, kerning, k;
828var width = 0, advance, jumps = [];
829 
830for (var i = 0, j = 0, l = chars.length; i < l; ++i) {
831glyph = glyphs[chr = chars[i]] || font.missingGlyph;
832if (!glyph) continue;
833if (kerning) {
834width -= k = kerning[chr] || 0;
835jumps[j - 1] -= k;
836}
837width += advance = jumps[j++] = ~~(glyph.w || font.w) + letterSpacing;
838kerning = glyph.k;
839}
840 
841if (advance === undefined) return null; // there's nothing to render
842 
843expandRight += viewBox.width - advance;
844expandLeft += viewBox.minX;
845 
846var wrapper, canvas;
847 
848if (redraw) {
849wrapper = node;
850canvas = node.firstChild;
851}
852else {
853wrapper = document.createElement('span');
854wrapper.className = 'cufon cufon-canvas';
855wrapper.alt = text;
856 
857canvas = document.createElement('canvas');
858wrapper.appendChild(canvas);
859 
860if (options.printable) {
861var print = document.createElement('span');
862print.className = 'cufon-alt';
863print.appendChild(document.createTextNode(text));
864wrapper.appendChild(print);
865}
866}
867 
868var wStyle = wrapper.style;
869var cStyle = canvas.style;
870 
871var height = size.convert(viewBox.height);
872var roundedHeight = Math.ceil(height);
873var roundingFactor = roundedHeight / height;
874var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));
875var stretchedWidth = width * stretchFactor;
876 
877var canvasWidth = Math.ceil(size.convert(stretchedWidth + expandRight - expandLeft));
878var canvasHeight = Math.ceil(size.convert(viewBox.height - expandTop + expandBottom));
879 
880canvas.width = canvasWidth;
881canvas.height = canvasHeight;
882 
883// needed for WebKit and full page zoom
884cStyle.width = canvasWidth + 'px';
885cStyle.height = canvasHeight + 'px';
886 
887// minY has no part in canvas.height
888expandTop += viewBox.minY;
889 
890cStyle.top = Math.round(size.convert(expandTop - font.ascent)) + 'px';
891cStyle.left = Math.round(size.convert(expandLeft)) + 'px';
892 
893var wrapperWidth = Math.ceil(size.convert(stretchedWidth)) + 'px';
894 
895if (HAS_INLINE_BLOCK) {
896wStyle.width = wrapperWidth;
897wStyle.height = size.convert(font.height) + 'px';
898}
899else {
900wStyle.paddingLeft = wrapperWidth;
901wStyle.paddingBottom = (size.convert(font.height) - 1) + 'px';
902}
903 
904var g = canvas.getContext('2d'), scale = height / viewBox.height;
905 
906// proper horizontal scaling is performed later
907g.scale(scale, scale * roundingFactor);
908g.translate(-expandLeft, -expandTop);
909 
910g.lineWidth = font.face['underline-thickness'];
911 
912g.save();
913 
914function line(y, color) {
915g.strokeStyle = color;
916 
917g.beginPath();
918 
919g.moveTo(0, y);
920g.lineTo(width, y);
921 
922g.stroke();
923}
924 
925var textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {};
926 
927if (textDecoration.underline) line(-font.face['underline-position'], textDecoration.underline);
928if (textDecoration.overline) line(font.ascent, textDecoration.overline);
929 
930function renderText() {
931g.scale(stretchFactor, 1);
932for (var i = 0, j = 0, l = chars.length; i < l; ++i) {
933var glyph = glyphs[chars[i]] || font.missingGlyph;
934if (!glyph) continue;
935if (glyph.d) {
936g.beginPath();
937if (glyph.code) interpret(glyph.code, g);
938else glyph.code = generateFromVML('m' + glyph.d, g);
939g.fill();
940}
941g.translate(jumps[j++], 0);
942}
943g.restore();
944}
945 
946if (shadows) {
947for (var i = shadows.length; i--;) {
948var shadow = shadows[i];
949g.save();
950g.fillStyle = shadow.color;
951g.translate.apply(g, shadowOffsets[i]);
952renderText();
953}
954}
955 
956var gradient = options.textGradient;
957if (gradient) {
958var stops = gradient.stops, fill = g.createLinearGradient(0, viewBox.minY, 0, viewBox.maxY);
959for (var i = 0, l = stops.length; i < l; ++i) {
960fill.addColorStop.apply(fill, stops[i]);
961}
962g.fillStyle = fill;
963}
964else g.fillStyle = style.get('color');
965 
966renderText();
967 
968if (textDecoration['line-through']) line(-font.descent, textDecoration['line-through']);
969 
970return wrapper;
971 
972};
973 
974})());
975 
976Cufon.registerEngine('vml', (function() {
977 
978var ns = document.namespaces;
979if (!ns) return;
980ns.add('cvml', 'urn:schemas-microsoft-com:vml');
981ns = null;
982 
983var check = document.createElement('cvml:shape');
984check.style.behavior = 'url(#default#VML)';
985if (!check.coordsize) return; // VML isn't supported
986check = null;
987 
988var HAS_BROKEN_LINEHEIGHT = (document.documentMode || 0) < 8;
989 
990document.write(('<style type="text/css">' +
991'.cufon-vml-canvas{text-indent:0;}' +
992'@media screen{' +
993'cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}' +
994'.cufon-vml-canvas{position:absolute;text-align:left;}' +
995'.cufon-vml{display:inline-block;position:relative;vertical-align:' +
996(HAS_BROKEN_LINEHEIGHT
997? 'middle'
998: 'text-bottom') +
999';}' +
1000'.cufon-vml .cufon-alt{position:absolute;left:-10000in;font-size:1px;}' +
1001'a .cufon-vml{cursor:pointer}' + // ignore !important here
1002'}' +
1003'@media print{' +
1004'.cufon-vml *{display:none;}' +
1005'.cufon-vml .cufon-alt{display:inline;}' +
1006'}' +
1007'</style>').replace(/;/g, '!important;'));
1008 
1009function getFontSizeInPixels(el, value) {
1010return getSizeInPixels(el, /(?:em|ex|%)$|^[a-z-]+$/i.test(value) ? '1em' : value);
1011}
1012 
1013// Original by Dead Edwards.
1014// Combined with getFontSizeInPixels it also works with relative units.
1015function getSizeInPixels(el, value) {
1016if (/px$/i.test(value)) return parseFloat(value);
1017var style = el.style.left, runtimeStyle = el.runtimeStyle.left;
1018el.runtimeStyle.left = el.currentStyle.left;
1019el.style.left = value.replace('%', 'em');
1020var result = el.style.pixelLeft;
1021el.style.left = style;
1022el.runtimeStyle.left = runtimeStyle;
1023return result;
1024}
1025 
1026var fills = {};
1027 
1028function gradientFill(gradient) {
1029var id = gradient.id;
1030if (!fills[id]) {
1031var stops = gradient.stops, fill = document.createElement('cvml:fill'), colors = [];
1032fill.type = 'gradient';
1033fill.angle = 180;
1034fill.focus = '0';
1035fill.method = 'sigma';
1036fill.color = stops[0][1];
1037for (var j = 1, k = stops.length - 1; j < k; ++j) {
1038colors.push(stops[j][0] * 100 + '% ' + stops[j][1]);
1039}
1040fill.colors = colors.join(',');
1041fill.color2 = stops[k][1];
1042fills[id] = fill;
1043}
1044return fills[id];
1045}
1046 
1047return function(font, text, style, options, node, el, hasNext) {
1048 
1049var redraw = (text === null);
1050 
1051if (redraw) text = node.alt;
1052 
1053// @todo word-spacing, text-decoration
1054 
1055var viewBox = font.viewBox;
1056 
1057var size = style.computedFontSize || (style.computedFontSize = new Cufon.CSS.Size(getFontSizeInPixels(el, style.get('fontSize')) + 'px', font.baseSize));
1058 
1059var letterSpacing = style.computedLSpacing;
1060 
1061if (letterSpacing == undefined) {
1062letterSpacing = style.get('letterSpacing');
1063style.computedLSpacing = letterSpacing = (letterSpacing == 'normal') ? 0 : ~~size.convertFrom(getSizeInPixels(el, letterSpacing));
1064}
1065 
1066var wrapper, canvas;
1067 
1068if (redraw) {
1069wrapper = node;
1070canvas = node.firstChild;
1071}
1072else {
1073wrapper = document.createElement('span');
1074wrapper.className = 'cufon cufon-vml';
1075wrapper.alt = text;
1076 
1077canvas = document.createElement('span');
1078canvas.className = 'cufon-vml-canvas';
1079wrapper.appendChild(canvas);
1080 
1081if (options.printable) {
1082var print = document.createElement('span');
1083print.className = 'cufon-alt';
1084print.appendChild(document.createTextNode(text));
1085wrapper.appendChild(print);
1086}
1087 
1088// ie6, for some reason, has trouble rendering the last VML element in the document.
1089// we can work around this by injecting a dummy element where needed.
1090// @todo find a better solution
1091if (!hasNext) wrapper.appendChild(document.createElement('cvml:shape'));
1092}
1093 
1094var wStyle = wrapper.style;
1095var cStyle = canvas.style;
1096 
1097var height = size.convert(viewBox.height), roundedHeight = Math.
1097ceil(height);
1098var roundingFactor = roundedHeight / height;
1099var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));
1100var minX = viewBox.minX, minY = viewBox.minY;
1101 
1102cStyle.height = roundedHeight;
1103cStyle.top = Math.round(size.convert(minY - font.ascent));
1104cStyle.left = Math.round(size.convert(minX));
1105 
1106wStyle.height = size.convert(font.height) + 'px';
1107 
1108var textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {};
1109 
1110var color = style.get('color');
1111var chars = Cufon.CSS.textTransform(text, style).split(''), chr;
1112 
1113var glyphs = font.glyphs, glyph, kerning, k;
1114var width = 0, jumps = [], offsetX = 0, advance;
1115 
1116var shape, shadows = options.textShadow;
1117 
1118// pre-calculate width
1119for (var i = 0, j = 0, l = chars.length; i < l; ++i) {
1120glyph = glyphs[chr = chars[i]] || font.missingGlyph;
1121if (!glyph) continue;
1122if (kerning) {
1123width -= k = kerning[chr] || 0;
1124jumps[j - 1] -= k;
1125}
1126width += advance = jumps[j++] = ~~(glyph.w || font.w) + letterSpacing;
1127kerning = glyph.k;
1128}
1129 
1130if (advance === undefined) return null;
1131 
1132var fullWidth = -minX + width + (viewBox.width - advance);
1133 
1134var shapeWidth = size.convert(fullWidth * stretchFactor), roundedShapeWidth = Math.round(shapeWidth);
1135 
1136var coordSize = fullWidth + ',' + viewBox.height, coordOrigin;
1137var stretch = 'r' + coordSize + 'ns';
1138 
1139var fill = options.textGradient && gradientFill(options.textGradient);
1140 
1141for (i = 0, j = 0; i < l; ++i) {
1142 
1143glyph = glyphs[chars[i]] || font.missingGlyph;
1144if (!glyph) continue;
1145 
1146if (redraw) {
1147// some glyphs may be missing so we can't use i
1148shape = canvas.childNodes[j];
1149while (shape.firstChild) shape.removeChild(shape.firstChild); // shadow, fill
1150}
1151else {
1152shape = document.createElement('cvml:shape');
1153canvas.appendChild(shape);
1154}
1155 
1156shape.stroked = 'f';
1157shape.coordsize = coordSize;
1158shape.coordorigin = coordOrigin = (minX - offsetX) + ',' + minY;
1159shape.path = (glyph.d ? 'm' + glyph.d + 'xe' : '') + 'm' + coordOrigin + stretch;
1160shape.fillcolor = color;
1161 
1162if (fill) shape.appendChild(fill.cloneNode(false));
1163 
1164// it's important to not set top/left or IE8 will grind to a halt
1165var sStyle = shape.style;
1166sStyle.width = roundedShapeWidth;
1167sStyle.height = roundedHeight;
1168 
1169if (shadows) {
1170// due to the limitations of the VML shadow element there
1171// can only be two visible shadows. opacity is shared
1172// for all shadows.
1173var shadow1 = shadows[0], shadow2 = shadows[1];
1174var color1 = Cufon.CSS.color(shadow1.color), color2;
1175var shadow = document.createElement('cvml:shadow');
1176shadow.on = 't';
1177shadow.color = color1.color;
1178shadow.offset = shadow1.offX + ',' + shadow1.offY;
1179if (shadow2) {
1180color2 = Cufon.CSS.color(shadow2.color);
1181shadow.type = 'double';
1182shadow.color2 = color2.color;
1183shadow.offset2 = shadow2.offX + ',' + shadow2.offY;
1184}
1185shadow.opacity = color1.opacity || (color2 && color2.opacity) || 1;
1186shape.appendChild(shadow);
1187}
1188 
1189offsetX += jumps[j++];
1190}
1191 
1192// addresses flickering issues on :hover
1193 
1194var cover = shape.nextSibling, coverFill, vStyle;
1195 
1196if (options.forceHitArea) {
1197 
1198if (!cover) {
1199cover = document.createElement('cvml:rect');
1200cover.stroked = 'f';
1201cover.className = 'cufon-vml-cover';
1202coverFill = document.createElement('cvml:fill');
1203coverFill.opacity = 0;
1204cover.appendChild(coverFill);
1205canvas.appendChild(cover);
1206}
1207 
1208vStyle = cover.style;
1209 
1210vStyle.width = roundedShapeWidth;
1211vStyle.height = roundedHeight;
1212 
1213}
1214else if (cover) canvas.removeChild(cover);
1215 
1216wStyle.width = Math.max(Math.ceil(size.convert(width * stretchFactor)), 0);
1217 
1218if (HAS_BROKEN_LINEHEIGHT) {
1219 
1220var yAdjust = style.computedYAdjust;
1221 
1222if (yAdjust === undefined) {
1223var lineHeight = style.get('lineHeight');
1224if (lineHeight == 'normal') lineHeight = '1em';
1225else if (!isNaN(lineHeight)) lineHeight += 'em'; // no unit
1226style.computedYAdjust = yAdjust = 0.5 * (getSizeInPixels(el, lineHeight) - parseFloat(wStyle.height));
1227}
1228 
1229if (yAdjust) {
1230wStyle.marginTop = Math.ceil(yAdjust) + 'px';
1231wStyle.marginBottom = yAdjust + 'px';
1232}
1233 
1234}
1235 
1236return wrapper;
1237 
1238};
1239 
1240})());
1241 

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.