/*! * Copyright (c) 2009 Simo Kinnunen. * Licensed under the MIT license. */ 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); }; })() }; 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; }; }, getStyle: function(el) { return new Style(el.style); /* 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); */ }, 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; }), ready: (function() { var complete = false; var queue = [], perform = function() { complete = true; for (var fn; fn = queue.shift(); fn()); }; // Safari 2 does not include '); function getFontSizeInPixels(el, value) { return getSizeInPixels(el, /(?:em|ex|%)$/i.test(value) ? '1em' : value); } // Original by Dead Edwards. // Combined with getFontSizeInPixels it also works with relative units. function getSizeInPixels(el, value) { if (/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; var result = el.style.pixelLeft; el.style.left = style; el.runtimeStyle.left = runtimeStyle; return result; } return function(font, text, style, options, node, el, hasNext) { var redraw = (text === null); if (redraw) text = node.alt; // @todo word-spacing, text-decoration var viewBox = font.viewBox; var size = style.computedFontSize || (style.computedFontSize = new Cufon.CSS.Size(getFontSizeInPixels(el, style.get('fontSize')) + 'px', font.baseSize)); var letterSpacing = style.computedLSpacing; if (letterSpacing == undefined) { letterSpacing = style.get('letterSpacing'); style.computedLSpacing = letterSpacing = (letterSpacing == 'normal') ? 0 : ~~size.convertFrom(getSizeInPixels(el, letterSpacing)); } var wrapper, canvas; if (redraw) { wrapper = node; canvas = node.firstChild; } else { wrapper = document.createElement('span'); wrapper.className = 'cufon cufon-vml'; wrapper.alt = text; canvas = document.createElement('span'); canvas.className = 'cufon-vml-canvas'; wrapper.appendChild(canvas); if (options.printable) { var print = document.createElement('span'); print.className = 'cufon-alt'; 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 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 textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {}; var color = style.get('color'); var chars = Cufon.CSS.textTransform(text, style).split(''); var width = 0, offsetX = 0, advance = null; var glyph, shape, shadows = options.textShadow; // pre-calculate width for (var i = 0, k = 0, l = chars.length; i < l; ++i) { glyph = font.glyphs[chars[i]] || font.missingGlyph; if (glyph) width += advance = ~~(glyph.w || font.w) + letterSpacing; } if (advance === null) return null; var fullWidth = -minX + width + (viewBox.width - advance); var shapeWidth = size.convert(fullWidth * roundingFactor), roundedShapeWidth = Math.round(shapeWidth); var coordSize = fullWidth + ',' + viewBox.height, coordOrigin; var stretch = 'r' + coordSize + 'nsnf'; for (i = 0; i < l; ++i) { glyph = font.glyphs[chars[i]] || font.missingGlyph; if (!glyph) continue; if (redraw) { // some glyphs may be missing so we can't use i shape = canvas.childNodes[k]; if (shape.firstChild) shape.removeChild(shape.firstChild); // shadow } 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; // 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 += ~~(glyph.w || font.w) + letterSpacing; ++k; } wStyle.width = Math.max(Math.ceil(size.convert(width * roundingFactor)), 0); return wrapper; }; })()); if (typeof exports != 'undefined') { exports.Cufon = Cufon; }