/*!* Copyright (c) 2010 Simo Kinnunen.* Licensed under the MIT license.** @version ${Version}*/ var Cufon = (function() { 	var api = function() {		return api.replace.apply(null, arguments);	}; 	var DOM = api.DOM = {	 		ready: (function() {		 			var complete = false, readyStatus = { loaded: 1, complete: 1 };		 			var queue = [], perform = function() {				if (complete) return;				complete = true;				for (var fn; fn = queue.shift(); fn());			};		 			// Gecko, Opera, WebKit r26101+		 			if (document.addEventListener) {				document.addEventListener('DOMContentLoaded', perform, false);				window.addEventListener('pageshow', perform, false); // For cached Gecko pages			}		 		// Old WebKit, Internet Explorer		 		if (!window.opera && document.readyState) (function() {			readyStatus[document.readyState] ? perform() : setTimeout(arguments.callee, 10);		})();		 		// Internet Explorer		 		if (document.readyState && document.createStyleSheet) (function() {		try {			document.body.doScroll('left');			perform();		}		catch (e) {			setTimeout(arguments.callee, 1);		}		})();		 		addEvent(window, 'load', perform); // Fallback		 		return function(listener) {		if (!arguments.length) perform();		else complete ? listener() : queue.push(listener);		};		 		})(),		 	root: function() {	return document.documentElement || document.body;	}	 	};	 var CSS = api.CSS = { Size: function(value, base) { this.value = parseFloat(value);this.unit = String(value).match(/[a-z%]*$/)[0] || 'px'; this.convert = function(value) {return value / base * this.value;}; this.convertFrom = function(value) {return value / this.value * base;}; this.toString = function() {return this.value + this.unit;}; }, addClass: function(el, className) {var current = el.className;el.className = current + (current && ' ') + className;return el;}, color: cached(function(value) {var parsed = {};parsed.color = value.replace(/^rgba\((.*?),\s*([\d.]+)\)/, function($0, $1, $2) {parsed.opacity = parseFloat($2);return 'rgb(' + $1 + ')';});return parsed;}), // has no direct CSS equivalent.// @see http://msdn.microsoft.com/en-us/library/system.windows.fontstretches.aspxfontStretch: cached(function(value) {if (typeof value == 'number') return value;if (/%$/.test(value)) return parseFloat(value) / 100;return {'ultra-condensed': 0.5,'extra-condensed': 0.625,condensed: 0.75,'semi-condensed': 0.875,'semi-expanded': 1.125,expanded: 1.25,'extra-expanded': 1.5,'ultra-expanded': 2}[value] || 1;}), getStyle: function(el) {var view = document.defaultView;if (view && view.getComputedStyle) return new Style(view.getComputedStyle(el, null));if (el.currentStyle) return new Style(el.currentStyle);return new Style(el.style);}, gradient: cached(function(value) {var gradient = {id: value,type: value.match(/^-([a-z]+)-gradient\(/)[1],stops: []}, colors = value.substr(value.indexOf('(')).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);for (var i = 0, l = colors.length, stop; i < l; ++i) {stop = colors[i].split('=', 2).reverse();gradient.stops.push([ stop[1] || i / (l - 1), stop[0] ]);}return gradient;}), quotedList: cached(function(value) {// doesn't work properly with empty quoted strings (""), but// it's not worth the extra code.var list = [], re = /\s*((["'])([\s\S]*?[^\\])\2|[^,]+)\s*/g, match;while (match = re.exec(value)) list.push(match[3] || match[1]);return list;}), recognizesMedia: cached(function(media) {var el = document.createElement('style'), sheet, container, supported;el.type = 'text/css';el.media = media;try { // this is cached anywayel.appendChild(document.createTextNode('/**/'));} catch (e) {}container = elementsByTagName('head')[0];container.insertBefore(el, container.firstChild);sheet = (el.sheet || el.styleSheet);supported = sheet && !sheet.disabled;container.removeChild(el);return supported;}), removeClass: function(el, className) {var re = RegExp('(?:^|\\s+)' + className + '(?=\\s|$)', 'g');el.className = el.className.replace(re, '');return el;}, supports: function(property, value) {var checker = document.createElement('span').style;if (checker[property] === undefined) return false;checker[property] = value;return checker[property] === value;}, textAlign: function(word, style, position, wordCount) {if (style.get('textAlign') == 'right') {if (position > 0) word = ' ' + word;}else if (position < wordCount - 1) word += ' ';return word;}, textShadow: cached(function(value) {if (value == 'none') return null;var shadows = [], currentShadow = {}, result, offCount = 0;var re = /(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)|(-?[\d.]+[a-z%]*)|,/ig;while (result = re.exec(value)) {if (result[0] == ',') {shadows.push(currentShadow);currentShadow = {};offCount = 0;}else if (result[1]) {currentShadow.color = result[1];}else {currentShadow[[ 'offX', 'offY', 'blur' ][offCount++]] = result[2];}}shadows.push(currentShadow);return shadows;}), textTransform: (function() {var map = {uppercase: function(s) {return s.toUpperCase();},lowercase: function(s) {return s.toLowerCase();},capitalize: function(s) {return s.replace(/\b./g, function($0) {return $0.toUpperCase();});}};return function(text, style) {var transform = map[style.get('textTransform')];return transform ? transform(text) : text;};})(), whiteSpace: (function() {var ignore = {inline: 1,'inline-block': 1,'run-in': 1};var wsStart = /^\s+/, wsEnd = /\s+$/;return function(text, style, node, previousElement) {if (previousElement) {if (previousElement.nodeName.toLowerCase() == 'br') {text = text.replace(wsStart, '');}}if (ignore[style.get('display')]) return text;if (!node.previousSibling) text = text.replace(wsStart, '');if (!node.nextSibling) text = text.replace(wsEnd, '');return text;};})() }; CSS.ready = (function() { // don't do anything in Safari 2 (it doesn't recognize any media type)var complete = !CSS.recognizesMedia('all'), hasLayout = false; var queue = [], perform = function() {complete = true;for (var fn; fn = queue.shift(); fn());}; var links = elementsByTagName('link'), styles = elementsByTagName('style'); function isContainerReady(el) {return el.disabled || isSheetReady(el.sheet, el.media || 'screen');} function isSheetReady(sheet, media) {// in Opera sheet.disabled is true when it's still loading,// even though link.disabled is false. they stay in sync if// set manually.if (!CSS.recognizesMedia(media || 'all')) return true;if (!sheet || sheet.disabled) return false;try {var rules = sheet.cssRules, rule;if (rules) {// needed for Safari 3 and Chrome 1.0.// in standards-conforming browsers cssRules contains @-rules.// Chrome 1.0 weirdness: rules[<number larger than .length - 1>]// returns the last rule, so a for loop is the only option.search: for (var i = 0, l = rules.length; rule = rules[i], i < l; ++i) {switch (rule.type) {case 2: // @charsetbreak;case 3: // @importif (!isSheetReady(rule.styleSheet, rule.media.mediaText)) return false;break;default:// only @charset can precede @importbreak search;}}}}catch (e) {} // probably a style sheet from another domainreturn true;} function allStylesLoaded() {// Internet Explorer's style sheet model, there's no need to do anythingif (document.createStyleSheet) return true;// standards-compliant browsersvar el, i;for (i = 0; el = links[i]; ++i) {if (el.rel.toLowerCase() == 'stylesheet' && !isContainerReady(el)) return false;}for (i = 0; el = styles[i]; ++i) {if (!isContainerReady(el)) return false;}return true;} DOM.ready(function() {// getComputedStyle returns null in Gecko if used in an iframe with display: noneif (!hasLayout) hasLayout = CSS.getStyle(document.body).isUsable();if (complete || (hasLayout && allStylesLoaded())) perform();else setTimeout(arguments.callee, 10);}); return function(listener) {if (complete) listener();else queue.push(listener);}; })(); function Font(data) { var face = this.face = data.face, wordSeparators = {'\u0020': 1,'\u00a0': 1,'\u3000': 1}; this.glyphs = data.glyphs;this.w = data.w;this.baseSize = parseInt(face['units-per-em'], 10); this.family = face['font-family'].toLowerCase();this.weight = face['font-weight'];this.style = face['font-style'] || 'normal'; this.viewBox = (function () {var parts = face.bbox.split(/\s+/);var box = {minX: parseInt(parts[0], 10),minY: parseInt(parts[1], 10),maxX: parseInt(parts[2], 10),maxY: parseInt(parts[3], 10)};box.width = box.maxX - box.minX;box.height = box.maxY - box.minY;box.toString = function() {return [ this.minX, this.minY, this.width, this.height ].join(' ');};return box;})(); this.ascent = -parseInt(face.ascent, 10);this.descent = -parseInt(face.descent, 10); this.height = -this.ascent + this.descent; this.spacing = function(chars, letterSpacing, wordSpacing) {var glyphs = this.glyphs, glyph,kerning, k,jumps = [],width = 0, w,i = -1, j = -1, chr;while (chr = chars[++i]) {glyph = glyphs[chr] || this.missingGlyph;if (!glyph) continue;if (kerning) {width -= k = kerning[chr] || 0;jumps[j] -= k;}w = glyph.w;if (isNaN(w)) w = +this.w; // may have been a String in old fontsif (w > 0) {w += letterSpacing;if (wordSeparators[chr]) w += wordSpacing;}width += jumps[++j] = ~~w; // get rid of decimalskerning = glyph.k;}jumps.total = width;return jumps;}; } function FontFamily() { var styles = {}, mapping = {oblique: 'italic',italic: 'oblique'}; this.add = function(font) {(styles[font.style] || (styles[font.style] = {}))[font.weight] = font;}; this.get = function(style, weight) {var weights = styles[style] || styles[mapping[style]]|| styles.normal || styles.italic || styles.oblique;if (!weights) return null;// we don't have to worry about "bolder" and "lighter"// because IE's currentStyle returns a numeric value for it,// and other browsers use the computed value anywayweight = {normal: 400,bold: 700}[weight] || parseInt(weight, 10);if (weights[weight]) return weights[weight];// http://www.w3.org/TR/CSS21/fonts.html#propdef-font-weight// Gecko uses x99/x01 for lighter/boldervar up = {1: 1,99: 0}[weight % 100], alts = [], min, max;if (up === undefined) up = weight > 400;if (weight == 500) weight = 400;for (var alt in weights) {if (!hasOwnProperty(weights, alt)) continue;alt = parseInt(alt, 10);if (!min || alt < min) min = alt;if (!max || alt > max) max = alt;alts.push(alt);}if (weight < min) weight = min;if (weight > max) weight = max;alts.sort(function(a, b) {return (up? (a >= weight && b >= weight) ? a < b : a > b: (a <= weight && b <= weight) ? a > b : a < b) ? -1 : 1;});return weights[alts[0]];}; } function HoverHandler() { function contains(node, anotherNode) {try {if (node.contains) return node.contains(anotherNode);return node.compareDocumentPosition(anotherNode) & 16;}catch(e) {} // probably a XUL element such as a scrollbarreturn false;} function onOverOut(e) {var related = e.relatedTarget;// there might be no relatedTarget if the element is right next// to the window frameif (related && contains(this, related)) return;trigger(this, e.type == 'mouseover');} function onEnterLeave(e) {trigger(this, e.type == 'mouseenter');} function trigger(el, hoverState) {// A timeout is needed so that the event can actually "happen"// before replace is triggered. This ensures that styles are up// to date.setTimeout(function() {var options = sharedStorage.get(el).options;api.replace(el, hoverState ? merge(options, options.hover) : options, true);}, 10);} this.attach = function(el) {if (el.onmouseenter === undefined) {addEvent(el, 'mouseover', onOverOut);addEvent(el, 'mouseout', onOverOut);}else {addEvent(el, 'mouseenter', onEnterLeave);addEvent(el, 'mouseleave', onEnterLeave);}}; } function ReplaceHistory() { var list = [], map = {}; function filter(keys) {var values = [], key;for (var i = 0; key = keys[i]; ++i) values[i] = list[map[key]];return values;} this.add = function(key, args) {map[key] = list.push(args) - 1;}; this.repeat = function() {var snapshot = arguments.length ? filter(arguments) : list, args;for (var i = 0; args = snapshot[i++];) api.replace(args[0], args[1], true);}; } function Storage() { var map = {}, at = 0; function identify(el) {return el.cufid || (el.cufid = ++at);} this.get = function(el) {var id = identify(el);return map[id] || (map[id] = {});}; } function Style(style) { var custom = {}, sizes = {}; this.extend = function(styles) {for (var property in styles) {if (hasOwnProperty(styles, property)) custom[property] = styles[property];}return this;}; this.get = function(property) {return custom[property] != undefined ? custom[property] : style[property];}; this.getSize = function(property, base) {return sizes[property] || (sizes[property] = new CSS.Size(this.get(property), base));}; this.isUsable = function() {return !!style;}; } function addEvent(el, type, listener) {if (el.addEventListener) {el.addEventListener(type, listener, false);}else if (el.attachEvent) {el.attachEvent('on' + type, function() {return listener.call(el, window.event);});}} function attach(el, options) {var storage = sharedStorage.get(el);if (storage.options) return el;if (options.hover && options.hoverables[el.nodeName.toLowerCase()]) {hoverHandler.attach(el);}storage.options = options;return el;} function cached(fun) {var cache = {};return function(key) {if (!hasOwnProperty(cache, key)) cache[key] = fun.apply(null, arguments);return cache[key];};} function getFont(el, style) {var families = CSS.quotedList(style.get('fontFamily').toLowerCase()), family;for (var i = 0; family = families[i]; ++i) {if (fonts[family]) return fonts[family].get(style.get('fontStyle'), style.get('fontWeight'));}return null;} function elementsByTagName(query) {return document.getElementsByTagName(query);} function hasOwnProperty(obj, property) {return obj.hasOwnProperty(property);} function merge() {var merged = {}, arg, key;for (var i = 0, l = arguments.length; arg = arguments[i], i < l; ++i) {for (key in arg) {if (hasOwnProperty(arg, key)) merged[key] = arg[key];}}return merged;} function process(font, text, style, options, node, el) {var fragment = document.createDocumentFragment(), processed;if (text === '') return fragment;var separate = options.separate;var parts = text.split(separators[separate]), needsAligning = (separate == 'words');if (needsAligning && HAS_BROKEN_REGEXP) {// @todo figure out a better way to do thisif (/^\s/.test(text)) parts.unshift('');if (/\s$/.test(text)) parts.push('');}for (var i = 0, l = parts.length; i < l; ++i) {processed = engines[options.engine](font,needsAligning ? CSS.textAlign(parts[i], style, i, l) : parts[i],style, options, node, el, i < l - 1);if (processed) fragment.appendChild(processed);}return fragment;} function replaceElement(el, options) {var name = el.nodeName.toLowerCase();if (options.ignore[name]) return;var replace = !options.textless[name];var style = CSS.getStyle(attach(el, options)).extend(options);// may cause issues if the element contains other elements// with larger fontSize, however such cases are rare and can// be fixed by using a more specific selectorif (parseFloat(style.get('fontSize')) === 0) return;var font = getFont(el, style), node, type, next, anchor, text, lastElement;if (!font) return;for (node = el.firstChild; node; node = next) {type = node.nodeType;next = node.nextSibling;if (replace && type == 3) {// Node.normalize() is broken in IE 6, 7, 8if (anchor) {anchor.appendData(node.data);el.removeChild(node);}else anchor = node;if (next) continue;}if (anchor) {el.replaceChild(process(font,CSS.whiteSpace(anchor.data, style, anchor, lastElement),style, options, node, el), anchor);anchor = null;}if (type == 1) {if (node.firstChild) {if (node.nodeName.toLowerCase() == 'cufon') {engines[options.engine](font, null, style, options, node, el);}else arguments.callee(node, options);}lastElement = node;}}} var HAS_BROKEN_REGEXP = ' '.split(/\s+/).length == 0; var sharedStorage = new Storage();var hoverHandler = new HoverHandler();var replaceHistory = new ReplaceHistory();var initialized = false; var engines = {}, fonts = {}, defaultOptions = {autoDetect: false,engine: null,//fontScale: 1,//fontScaling: false,forceHitArea: false,hover: false,hoverables: {a: true},ignore: {applet: 1,canvas: 1,col: 1,colgroup: 1,head: 1,iframe: 1,map: 1,noscript: 1,optgroup: 1,option: 1,script: 1,select: 1,style: 1,textarea: 1,title: 1,pre: 1},printable: true,//rotation: 0,//selectable: false,selector: (window.Sizzle|| (window.jQuery && function(query) { return jQuery(query); }) // avoid noConflict issues|| (window.dojo && dojo.query)|| (window.glow && glow.dom && glow.dom.get)|| (window.Ext && Ext.query)|| (window.YAHOO && YAHOO.util && YAHOO.util.Selector && YAHOO.util.Selector.query)|| (window.$$ && function(query) { return $$(query); })|| (window.$ && function(query) { return $(query); })|| (document.querySelectorAll && function(query) { return document.querySelectorAll(query); })|| elementsByTagName),separate: 'words', // 'none' and 'characters' are also acceptedtextless: {dl: 1,html: 1,ol: 1,table: 1,tbody: 1,thead: 1,tfoot: 1,tr: 1,ul: 1},textShadow: 'none'}; var separators = {// The first pattern may cause unicode characters above// code point 255 to be removed in Safari 3.0. Luckily enough// Safari 3.0 does not include non-breaking spaces in \s, so// we can just use a simple alternative pattern.words: /\s/.test('\u00a0') ? /[^\S\u00a0]+/ : /\s+/,characters: '',none: /^/}; api.now = function() {DOM.ready();return api;}; api.refresh = function() {replaceHistory.repeat.apply(replaceHistory, arguments);return api;}; api.registerEngine = function(id, engine) {if (!engine) return api;engines[id] = engine;return api.set('engine', id);}; api.registerFont = function(data) {if (!data) return api;var font = new Font(data), family = font.family;if (!fonts[family]) fonts[family] = new FontFamily();fonts[family].add(font);return api.set('fontFamily', '"' + family + '"');}; api.replace = function(elements, options, ignoreHistory) {options = merge(defaultOptions, options);if (!options.engine) return api; // there's no browser support so we'll just stop hereif (!initialized) {CSS.addClass(DOM.root(), 'cufon-active cufon-loading');CSS.ready(function() {// fires before any replace() calls, but it doesn't really matterCSS.addClass(CSS.removeClass(DOM.root(), 'cufon-loading'), 'cufon-ready');});initialized = true;}if (options.hover) options.forceHitArea = true;if (options.autoDetect) delete options.fontFamily;if (typeof options.textShadow == 'string') {options.textShadow = CSS.textShadow(options.textShadow);}if (typeof options.color == 'string' && /^-/.test(options.color)) {options.textGradient = CSS.gradient(options.color);}else delete options.textGradient;if (!ignoreHistory) replaceHistory.add(elements, arguments);if (elements.nodeType || typeof elements == 'string') elements = [ elements ];CSS.ready(function() {for (var i = 0, l = elements.length; i < l; ++i) {var el = elements[i];if (typeof el == 'string') api.replace(options.selector(el), options, true);else replaceElement(el, options);}});return api;}; api.set = function(option, value) {defaultOptions[option] = value;return api;}; return api; })(); Cufon.registerEngine('canvas', (function() { // Safari 2 doesn't support .apply() on native methods var check = document.createElement('canvas');if (!check || !check.getContext || !check.getContext.apply) return;check = null; var HAS_INLINE_BLOCK = Cufon.CSS.supports('display', 'inline-block'); // Firefox 2 w/ non-strict doctype (almost standards mode)var HAS_BROKEN_LINEHEIGHT = !HAS_INLINE_BLOCK && (document.compatMode == 'BackCompat' || /frameset|transitional/i.test(document.doctype.publicId)); var styleSheet = document.createElement('style');styleSheet.type = 'text/css';styleSheet.appendChild(document.createTextNode(('cufon{text-indent:0;}' +'@media screen,projection{' +'cufon{display:inline;display:inline-block;position:relative;vertical-align:middle;' +(HAS_BROKEN_LINEHEIGHT? '': 'font-size:1px;line-height:1px;') +'}cufon cufontext{display:-moz-inline-box;display:inline-block;width:0;height:0;text-indent:-10000in;}' +(HAS_INLINE_BLOCK? 'cufon canvas{position:relative;}': 'cufon canvas{position:absolute;}') +'}' +'@media print{' +'cufon{padding:0;}' + // Firefox 2'cufon canvas{display:none;}' +'}').replace(/;/g, '!important;')));document.getElementsByTagName('head')[0].appendChild(styleSheet); function generateFromVML(path, context) {var atX = 0, atY = 0;var code = [], re = /([mrvxe])([^a-z]*)/g, match;generate: for (var i = 0; match = re.exec(path); ++i) {var c = match[2].split(',');switch (match[1]) {case 'v':code[i] = { m: 'bezierCurveTo', a: [ atX + ~~c[0], atY + ~~c[1], atX + ~~c[2], atY + ~~c[3], atX += ~~c[4], atY += ~~c[5] ] };break;case 'r':code[i] = { m: 'lineTo', a: [ atX += ~~c[0], atY += ~~c[1] ] };break;case 'm':code[i] = { m: 'moveTo', a: [ atX = ~~c[0], atY = ~~c[1] ] };break;case 'x':code[i] = { m: 'closePath' };break;case 'e':break generate;}context[code[i].m].apply(context, code[i].a);}return code;} function interpret(code, context) {for (var i = 0, l = code.length; i < l; ++i) {var line = code[i];context[line.m].apply(context, line.a);}} return function(font, text, style, options, node, el) { var redraw = (text === null); if (redraw) text = node.getAttribute('alt'); var viewBox = font.viewBox; var size = style.getSize('fontSize', font.baseSize); var expandTop = 0, expandRight = 0, expandBottom = 0, expandLeft = 0;var shadows = options.textShadow, shadowOffsets = [];if (shadows) {for (var i = shadows.length; i--;) {var shadow = shadows[i];var x = size.convertFrom(parseFloat(shadow.offX));var y = size.convertFrom(parseFloat(shadow.offY));shadowOffsets[i] = [ x, y ];if (y < expandTop) expandTop = y;if (x > expandRight) expandRight = x;if (y > expandBottom) expandBottom = y;if (x < expandLeft) expandLeft = x;}} var chars = Cufon.CSS.textTransform(text, style).split(''); var jumps = font.spacing(chars,~~size.convertFrom(parseFloat(style.get('letterSpacing')) || 0),~~size.convertFrom(parseFloat(style.get('wordSpacing')) || 0)); if (!jumps.length) return null; // there's nothing to render var width = jumps.total; expandRight += viewBox.width - jumps[jumps.length - 1];expandLeft += viewBox.minX; var wrapper, canvas; if (redraw) {wrapper = node;canvas = node.firstChild;}else {wrapper = document.createElement('cufon');wrapper.className = 'cufon cufon-canvas';wrapper.setAttribute('alt', text); canvas = document.createElement('canvas');wrapper.appendChild(canvas); if (options.printable) {var print = document.createElement('cufontext');print.appendChild(document.createTextNode(text));wrapper.appendChild(print);}} var wStyle = wrapper.style;var cStyle = canvas.style; var height = size.convert(viewBox.height);var roundedHeight = Math.ceil(height);var roundingFactor = roundedHeight / height;var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));var stretchedWidth = width * stretchFactor; var canvasWidth = Math.ceil(size.convert(stretchedWidth + expandRight - expandLeft));var canvasHeight = Math.ceil(size.convert(viewBox.height - expandTop + expandBottom)); canvas.width = canvasWidth;canvas.height = canvasHeight; // needed for WebKit and full page zoomcStyle.width = canvasWidth + 'px';cStyle.height = canvasHeight + 'px'; // minY has no part in canvas.heightexpandTop += viewBox.minY; cStyle.top = Math.round(size.convert(expandTop - font.ascent)) + 'px';cStyle.left = Math.round(size.convert(expandLeft)) + 'px'; var wrapperWidth = Math.max(Math.ceil(size.convert(stretchedWidth)), 0) + 'px'; if (HAS_INLINE_BLOCK) {wStyle.width = wrapperWidth;wStyle.height = size.convert(font.height) + 'px';}else {wStyle.paddingLeft = wrapperWidth;wStyle.paddingBottom = (size.convert(font.height) - 1) + 'px';} var g = canvas.getContext('2d'), scale = height / viewBox.height; // proper horizontal scaling is performed laterg.scale(scale, scale * roundingFactor);g.translate(-expandLeft, -expandTop);g.save(); function renderText() {var glyphs = font.glyphs, glyph, i = -1, j = -1, chr;g.scale(stretchFactor, 1);while (chr = chars[++i]) {var glyph = glyphs[chars[i]] || font.missingGlyph;if (!glyph) continue;if (glyph.d) {g.beginPath();if (glyph.code) interpret(glyph.code, g);else glyph.code = generateFromVML('m' + glyph.d, g);g.fill();}g.translate(jumps[++j], 0);}g.restore();} if (shadows) {for (var i = shadows.length; i--;) {var shadow = shadows[i];g.save();g.fillStyle = shadow.color;g.translate.apply(g, shadowOffsets[i]);renderText();}} var gradient = options.textGradient;if (gradient) {var stops = gradient.stops, fill = g.createLinearGradient(0, viewBox.minY, 0, viewBox.maxY);for (var i = 0, l = stops.length; i < l; ++i) {fill.addColorStop.apply(fill, stops[i]);}g.fillStyle = fill;}else g.fillStyle = style.get('color'); renderText(); return wrapper; }; })()); Cufon.registerEngine('vml', (function() { var ns = document.namespaces;if (!ns) return;ns.add('cvml', 'urn:schemas-microsoft-com:vml');ns = null; var check = document.createElement('cvml:shape');check.style.behavior = 'url(#default#VML)';if (!check.coordsize) return; // VML isn't supportedcheck = null; var HAS_BROKEN_LINEHEIGHT = (document.documentMode || 0) < 8; document.write(('<style type="text/css">' +'cufoncanvas{text-indent:0;}' +'@media screen{' +'cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}' +'cufoncanvas{position:absolute;text-align:left;}' +'cufon{display:inline-block;position:relative;vertical-align:' +(HAS_BROKEN_LINEHEIGHT? 'middle': 'text-bottom') +';}' +'cufon cufontext{position:absolute;left:-10000in;font-size:1px;}' +'a cufon{cursor:pointer}' + // ignore !important here'}' +'@media print{' +'cufon cufoncanvas{display:none;}' +'}' +'</style>').replace(/;/g, '!important;')); function getFontSizeInPixels(el, value) {return getSizeInPixels(el, /(?:em|ex|%)$|^[a-z-]+$/i.test(value) ? '1em' : value);} // Original by Dead Edwards.// Combined with getFontSizeInPixels it also works with relative units.function getSizeInPixels(el, value) {if (!isNaN(value) || /px$/i.test(value)) return parseFloat(value);var style = el.style.left, runtimeStyle = el.runtimeStyle.left;el.runtimeStyle.left = el.currentStyle.left;el.style.left = value.replace('%', 'em');var result = el.style.pixelLeft;el.style.left = style;el.runtimeStyle.left = runtimeStyle;return result;} function getSpacingValue(el, style, size, property) {var key = 'computed' + property, value = style[key];if (isNaN(value)) {value = style.get(property);style[key] = value = (value == 'normal') ? 0 : ~~size.convertFrom(getSizeInPixels(el, value));}return value;} var fills = {}; function gradientFill(gradient) {var id = gradient.id;if (!fills[id]) {var stops = gradient.stops, fill = document.createElement('cvml:fill'), colors = [];fill.type = 'gradient';fill.angle = 180;fill.focus = '0';fill.method = 'none';fill.color = stops[0][1];for (var j = 1, k = stops.length - 1; j < k; ++j) {colors.push(stops[j][0] * 100 + '% ' + stops[j][1]);}fill.colors = colors.join(',');fill.color2 = stops[k][1];fills[id] = fill;}return fills[id];} return function(font, text, style, options, node, el, hasNext) { var redraw = (text === null); if (redraw) text = node.alt; var viewBox = font.viewBox; var size = style.computedFontSize || (style.computedFontSize = new Cufon.CSS.Size(getFontSizeInPixels(el, style.get('fontSize')) + 'px', font.baseSize)); var wrapper, canvas; if (redraw) {wrapper = node;canvas = node.firstChild;}else {wrapper = document.createElement('cufon');wrapper.className = 'cufon cufon-vml';wrapper.alt = text; canvas = document.createElement('cufoncanvas');wrapper.appendChild(canvas); if (options.printable) {var print = document.createElement('cufontext');print.appendChild(document.createTextNode(text));wrapper.appendChild(print);} // ie6, for some reason, has trouble rendering the last VML element in the document.// we can work around this by injecting a dummy element where needed.// @todo find a better solutionif (!hasNext) wrapper.appendChild(document.createElement('cvml:shape'));} var wStyle = wrapper.style;var cStyle = canvas.style; var height = size.convert(viewBox.height), roundedHeight = Math.ceil(height);var roundingFactor = roundedHeight / height;var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));var minX = viewBox.minX, minY = viewBox.minY; cStyle.height = roundedHeight;cStyle.top = Math.round(size.convert(minY - font.ascent));cStyle.left = Math.round(size.convert(minX)); wStyle.height = size.convert(font.height) + 'px'; var color = style.get('color');var chars = Cufon.CSS.textTransform(text, style).split(''); var jumps = font.spacing(chars,getSpacingValue(el, style, size, 'letterSpacing'),getSpacingValue(el, style, size, 'wordSpacing')); if (!jumps.length) return null; var width = jumps.total;var fullWidth = -minX + width + (viewBox.width - jumps[jumps.length - 1]); var shapeWidth = size.convert(fullWidth * stretchFactor), roundedShapeWidth = Math.round(shapeWidth); var coordSize = fullWidth + ',' + viewBox.height, coordOrigin;var stretch = 'r' + coordSize + 'ns'; var fill = options.textGradient && gradientFill(options.textGradient); var glyphs = font.glyphs, offsetX = 0;var shadows = options.textShadow;var i = -1, j = 0, chr; while (chr = chars[++i]) { var glyph = glyphs[chars[i]] || font.missingGlyph, shape;if (!glyph) continue; if (redraw) {// some glyphs may be missing so we can't use ishape = canvas.childNodes[j];while (shape.firstChild) shape.removeChild(shape.firstChild); // shadow, fill}else {shape = document.createElement('cvml:shape');canvas.appendChild(shape);} shape.stroked = 'f';shape.coordsize = coordSize;shape.coordorigin = coordOrigin = (minX - offsetX) + ',' + minY;shape.path = (glyph.d ? 'm' + glyph.d + 'xe' : '') + 'm' + coordOrigin + stretch;shape.fillcolor = color; if (fill) shape.appendChild(fill.cloneNode(false)); // it's important to not set top/left or IE8 will grind to a haltvar sStyle = shape.style;sStyle.width = roundedShapeWidth;sStyle.height = roundedHeight; if (shadows) {// due to the limitations of the VML shadow element there// can only be two visible shadows. opacity is shared// for all shadows.var shadow1 = shadows[0], shadow2 = shadows[1];var color1 = Cufon.CSS.color(shadow1.color), color2;var shadow = document.createElement('cvml:shadow');shadow.on = 't';shadow.color = color1.color;shadow.offset = shadow1.offX + ',' + shadow1.offY;if (shadow2) {color2 = Cufon.CSS.color(shadow2.color);shadow.type = 'double';shadow.color2 = color2.color;shadow.offset2 = shadow2.offX + ',' + shadow2.offY;}shadow.opacity = color1.opacity || (color2 && color2.opacity) || 1;shape.appendChild(shadow);} offsetX += jumps[j++];} // addresses flickering issues on :hover var cover = shape.nextSibling, coverFill, vStyle; if (options.forceHitArea) { if (!cover) {cover = document.createElement('cvml:rect');cover.stroked = 'f';cover.className = 'cufon-vml-cover';coverFill = document.createElement('cvml:fill');coverFill.opacity = 0;cover.appendChild(coverFill);canvas.appendChild(cover);} vStyle = cover.style; vStyle.width = roundedShapeWidth;vStyle.height = roundedHeight; }else if (cover) canvas.removeChild(cover); wStyle.width = Math.max(Math.ceil(size.convert(width * stretchFactor)), 0); if (HAS_BROKEN_LINEHEIGHT) { var yAdjust = style.computedYAdjust; if (yAdjust === undefined) {var lineHeight = style.get('lineHeight');if (lineHeight == 'normal') lineHeight = '1em';else if (!isNaN(lineHeight)) lineHeight += 'em'; // no unitstyle.computedYAdjust = yAdjust = 0.5 * (getSizeInPixels(el, lineHeight) - parseFloat(wStyle.height));} if (yAdjust) {wStyle.marginTop = Math.ceil(yAdjust) + 'px';wStyle.marginBottom = yAdjust + 'px';} } return wrapper; }; })()); 