diff --git a/dist/all.js b/dist/all.js index 632b68d0..8d023fe1 100644 --- a/dist/all.js +++ b/dist/all.js @@ -1192,14 +1192,7 @@ Cufon.registerEngine('canvas', (function() { g.fillStyle = Cufon.textOptions.color || style.get('color'); - if (textDecoration.underline) line(-font.face['underline-position'], g.fillStyle); - if (textDecoration.overline) line(font.ascent, g.fillStyle); - function renderText() { - if (isItalic) { - g.save(); - g.transform(1, 0, -0.25, 1, 0, 0); - } var left = 0; for (var i = 0, l = chars.length; i < l; ++i) { if (chars[i] === '\n') { @@ -1208,20 +1201,50 @@ Cufon.registerEngine('canvas', (function() { continue; } var glyph = font.glyphs[chars[i]] || font.missingGlyph; + if (!glyph) continue; + + var charWidth = Number(glyph.w || font.w) + letterSpacing; + + if (textDecoration) { + g.save(); + g.strokeStyle = g.fillStyle; + g.beginPath(); + if (textDecoration.underline) { + g.moveTo(0, -font.face['underline-position']); + g.lineTo(charWidth, -font.face['underline-position']); + } + if (textDecoration.overline) { + g.moveTo(0, font.ascent); + g.lineTo(charWidth, font.ascent); + } + if (textDecoration['line-through']) { + g.moveTo(0, -font.descent); + g.lineTo(charWidth, -font.descent); + } + g.stroke(); + g.restore(); + } + + if (isItalic) { + g.save(); + g.transform(1, 0, -0.25, 1, 0, 0); + } + g.beginPath(); if (glyph.d) { if (glyph.code) interpret(glyph.code, g); else glyph.code = generateFromVML('m' + glyph.d, g); } g.fill(); - var charWidth = Number(glyph.w || font.w) + letterSpacing; + + if (isItalic) { + g.restore(); + } + g.translate(charWidth, 0); left += charWidth; } - if (isItalic) { - g.restore(); - } } if (shadows) { @@ -1238,11 +1261,6 @@ Cufon.registerEngine('canvas', (function() { g.save(); renderText(); g.restore(); - - if (textDecoration['line-through']) { - line(-font.descent, g.fillStyle); - } - g.restore(); g.restore(); @@ -9492,7 +9510,8 @@ fabric.util.animate = animate; fontFamily: this.fontfamily, enableTextDecoration: true, textDecoration: this.textDecoration, - textShadow: this.textShadow + textShadow: this.textShadow, + fontStyle: this.fontStyle }); this.width = o.width; @@ -9514,7 +9533,6 @@ fabric.util.animate = animate; el.style.fontSize = '40px'; el.style.fontWeight = '400'; - el.style.fontStyle = 'normal'; el.style.letterSpacing = 'normal'; el.style.color = '#000000'; el.style.fontWeight = '600'; diff --git a/lib/cufon.js b/lib/cufon.js index 4d335165..bfd611b2 100644 --- a/lib/cufon.js +++ b/lib/cufon.js @@ -644,16 +644,16 @@ Cufon.registerEngine('canvas', (function() { } return function(font, text, style, options, node, el) { - + var redraw = (text === null); - + var viewBox = font.viewBox; - + var size = style.getSize('fontSize', font.baseSize); - + var letterSpacing = style.get('letterSpacing'); letterSpacing = (letterSpacing == 'normal') ? 0 : size.convertFrom(parseInt(letterSpacing, 10)); - + var expandTop = 0, expandRight = 0, expandBottom = 0, expandLeft = 0; var shadows = options.textShadow, shadowOffsets = []; if (shadows) { @@ -668,11 +668,11 @@ Cufon.registerEngine('canvas', (function() { if (x < expandLeft) expandLeft = x; } } - + var chars = Cufon.CSS.textTransform(redraw ? node.alt : text, style).split(''); - + var width = 0, lastWidth = null; - + var maxWidth = 0, lines = 1; for (var i = 0, l = chars.length; i < l; ++i) { if (chars[i] === '\n') { @@ -688,14 +688,14 @@ Cufon.registerEngine('canvas', (function() { width += lastWidth = Number(glyph.w || font.w) + letterSpacing; } width = Math.max(maxWidth, width) - + if (lastWidth === null) return null; // there's nothing to render - + expandRight += (viewBox.width - lastWidth); expandLeft += viewBox.minX; - + var wrapper, canvas; - + if (redraw) { wrapper = node; canvas = node.firstChild; @@ -704,10 +704,10 @@ Cufon.registerEngine('canvas', (function() { wrapper = document.createElement('span'); wrapper.className = 'cufon cufon-canvas'; wrapper.alt = text; - + canvas = document.createElement('canvas'); wrapper.appendChild(canvas); - + if (options.printable) { var print = document.createElement('span'); print.className = 'cufon-alt'; @@ -715,33 +715,32 @@ Cufon.registerEngine('canvas', (function() { wrapper.appendChild(print); } } - + var wStyle = wrapper.style; var cStyle = canvas.style; - + var height = size.convert(viewBox.height - expandTop + expandBottom); var roundedHeight = Math.ceil(height); var roundingFactor = roundedHeight / height; - + canvas.width = Math.ceil(size.convert(width + expandRight - expandLeft) * roundingFactor); canvas.height = roundedHeight; - - - // 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 _width = Math.ceil(size.convert(width * roundingFactor)); var wrapperWidth = _width + 'px'; - + var _height = size.convert(font.height); - + Cufon.textOptions.width = _width; Cufon.textOptions.height = _height * lines; Cufon.textOptions.lines = lines; - + if (HAS_INLINE_BLOCK) { wStyle.width = wrapperWidth; wStyle.height = _height + 'px'; @@ -750,71 +749,93 @@ Cufon.registerEngine('canvas', (function() { wStyle.paddingLeft = wrapperWidth; wStyle.paddingBottom = (_height - 1) + 'px'; } - - var g = Cufon.textOptions.context || canvas.getContext('2d'), + + var g = Cufon.textOptions.context || canvas.getContext('2d'), scale = roundedHeight / viewBox.height; - + g.save(); g.scale(scale, scale); - + g.translate( - -expandLeft - ((1/scale * canvas.width) / 2) + (Cufon.fonts[font.family].offsetLeft || 0), + -expandLeft - ((1/scale * canvas.width) / 2) + (Cufon.fonts[font.family].offsetLeft || 0), -expandTop - (canvas.height / scale * Cufon.textOptions.lines) / 2 ); - + g.lineWidth = font.face['underline-thickness']; - + g.save(); - + function line(y, color) { g.strokeStyle = color; - + g.beginPath(); - + g.moveTo(0, y); g.lineTo(width, y); - + g.stroke(); } - + var textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {}, isItalic = options.fontStyle === 'italic'; - + g.fillStyle = Cufon.textOptions.color || style.get('color'); - if (textDecoration.underline) line(-font.face['underline-position'], g.fillStyle); - if (textDecoration.overline) line(font.ascent, g.fillStyle); - function renderText() { - if (isItalic) { - g.save(); - g.transform(1, 0, -0.25, 1, 0, 0); - } var left = 0; for (var i = 0, l = chars.length; i < l; ++i) { if (chars[i] === '\n') { - // move "caret" to the current left g.translate(-left, -font.ascent - font.ascent / 5 /* space between lines */); left = 0; continue; } var glyph = font.glyphs[chars[i]] || font.missingGlyph; + if (!glyph) continue; + + var charWidth = Number(glyph.w || font.w) + letterSpacing; + + if (textDecoration) { + g.save(); + g.strokeStyle = g.fillStyle; + g.beginPath(); + if (textDecoration.underline) { + g.moveTo(0, -font.face['underline-position']); + g.lineTo(charWidth, -font.face['underline-position']); + } + if (textDecoration.overline) { + g.moveTo(0, font.ascent); + g.lineTo(charWidth, font.ascent); + } + if (textDecoration['line-through']) { + g.moveTo(0, -font.descent); + g.lineTo(charWidth, -font.descent); + } + g.stroke(); + g.restore(); + } + + if (isItalic) { + g.save(); + g.transform(1, 0, -0.25, 1, 0, 0); + } + g.beginPath(); if (glyph.d) { if (glyph.code) interpret(glyph.code, g); else glyph.code = generateFromVML('m' + glyph.d, g); } g.fill(); - var charWidth = Number(glyph.w || font.w) + letterSpacing; + + if (isItalic) { + g.restore(); + } + g.translate(charWidth, 0); left += charWidth; } - if (isItalic) { - g.restore(); - } } - + if (shadows) { for (var i = 0, l = shadows.length; i < l; ++i) { var shadow = shadows[i]; @@ -825,20 +846,15 @@ Cufon.registerEngine('canvas', (function() { g.restore(); } } - + g.save(); renderText(); g.restore(); - - if (textDecoration['line-through']) { - line(-font.descent, g.fillStyle); - } - g.restore(); g.restore(); - + return wrapper; - + }; })()); diff --git a/src/text.class.js b/src/text.class.js index d75cffd4..07874e26 100644 --- a/src/text.class.js +++ b/src/text.class.js @@ -108,7 +108,8 @@ fontFamily: this.fontfamily, enableTextDecoration: true, textDecoration: this.textDecoration, - textShadow: this.textShadow + textShadow: this.textShadow, + fontStyle: this.fontStyle }); // update width, height @@ -134,7 +135,6 @@ // need to specify these manually, since Jaxer doesn't support retrieving computed style el.style.fontSize = '40px'; el.style.fontWeight = '400'; - el.style.fontStyle = 'normal'; el.style.letterSpacing = 'normal'; el.style.color = '#000000'; el.style.fontWeight = '600'; diff --git a/test/demo/demo.css b/test/demo/demo.css index 6092ff90..a71e2335 100644 --- a/test/demo/demo.css +++ b/test/demo/demo.css @@ -7,10 +7,17 @@ h2 { background: #ffc; margin-top: 0; padding: 5px; color: #333; font-size: 1em; #commands ul { list-style: none; padding-left: 0; } #canvas-console { display: block; font-size: 11px; } #rasterize { margin-top: 10px; color: green; } -#complexity { position: absolute; bottom: -20px; left: 0; } +#complexity { clear: both; padding-top: 10px; } #controls { margin-bottom: 5px; } +#text-controls { clear: both; margin-top: 20px } +#text-controls button { vertical-align: top; } #drawing-mode-options { margin-top: 5px; background: #ffc; padding: 5px; border: 1px solid #aaa; } -#text { position: relative; top: 30px; width: 250px; height: 100px; } +#text { position: relative; width: 250px; height: 100px; } +#text-cmd-linethrough { text-decoration: line-through; } +#text-cmd-underline { text-decoration: underline; } +#text-cmd-overline { text-decoration: overline; } +#text-cmd-italic { font-style: italic; } +#text-cmd-shadow { text-shadow: rgb(100,100,100) 1px 1px 3px; } .canvas-container { margin: 0 auto; float: left; border: 1px solid #aaa; } .clear { color: red; font-weight: bold; margin-top: 1em; } @@ -19,4 +26,6 @@ h2 { background: #ffc; margin-top: 0; padding: 5px; color: #333; font-size: 1em; #drawing-mode.is-drawing { color: red; } .svg-shapes { overflow: hidden; width: 320px; } -.svg-shapes li { display: inline; } \ No newline at end of file +.svg-shapes li { display: inline; } + +button.selected { font-weight: bold; vertical-align: top } \ No newline at end of file diff --git a/test/demo/demo.js b/test/demo/demo.js index 417020fa..473d490d 100644 --- a/test/demo/demo.js +++ b/test/demo/demo.js @@ -443,4 +443,64 @@ }; } + var cmdUnderlineBtn = document.getElementById('text-cmd-underline'); + if (cmdUnderlineBtn) { + cmdUnderlineBtn.onclick = function() { + var activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === 'text') { + activeObject.textDecoration = (activeObject.textDecoration == 'underline' ? '' : 'underline'); + this.className = activeObject.textDecoration ? 'selected' : ''; + canvas.renderAll(); + } + }; + } + + var cmdLinethroughBtn = document.getElementById('text-cmd-linethrough'); + if (cmdLinethroughBtn) { + cmdLinethroughBtn.onclick = function() { + var activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === 'text') { + activeObject.textDecoration = (activeObject.textDecoration == 'line-through' ? '' : 'line-through'); + this.className = activeObject.textDecoration ? 'selected' : ''; + canvas.renderAll(); + } + }; + } + + var cmdOverlineBtn = document.getElementById('text-cmd-overline'); + if (cmdOverlineBtn) { + cmdOverlineBtn.onclick = function() { + var activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === 'text') { + activeObject.textDecoration = (activeObject.textDecoration == 'overline' ? '' : 'overline'); + this.className = activeObject.textDecoration ? 'selected' : ''; + canvas.renderAll(); + } + }; + } + + var cmdItalicBtn = document.getElementById('text-cmd-italic'); + if (cmdItalicBtn) { + cmdItalicBtn.onclick = function() { + var activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === 'text') { + activeObject.fontStyle = (activeObject.fontStyle == 'italic' ? '' : 'italic'); + this.className = activeObject.fontStyle ? 'selected' : ''; + canvas.renderAll(); + } + }; + } + + var cmdShadowBtn = document.getElementById('text-cmd-shadow'); + if (cmdShadowBtn) { + cmdShadowBtn.onclick = function() { + var activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === 'text') { + activeObject.textShadow = !activeObject.textShadow ? 'rgba(0,0,0,0.2) 2px 2px 10px' : ''; + this.className = activeObject.fontStyle ? 'selected' : ''; + canvas.renderAll(); + } + }; + } + })(this); \ No newline at end of file diff --git a/test/demo/index.html b/test/demo/index.html index 3d9d3205..2110949d 100644 --- a/test/demo/index.html +++ b/test/demo/index.html @@ -24,10 +24,17 @@
-
 
+
Canvas complexity (number of paths):
- +
+ + + + + + +