From d3164163235d2712bc2f3fd6e24f3cf78bfe5984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Sat, 18 Mar 2017 11:12:33 +0100 Subject: [PATCH] Backport #891 to 1.x Parse font using parse-css-font and units-css --- lib/context2d.js | 67 ++++++++++++++++++++------------------------ package.json | 4 ++- test/public/tests.js | 12 ++++++++ 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/lib/context2d.js b/lib/context2d.js index 80d5e89e7..1857f2c34 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -16,6 +16,10 @@ var canvas = require('./bindings') , CanvasPattern = canvas.CanvasPattern , ImageData = canvas.ImageData; +var parseCssFont = require('parse-css-font'); + +var unitsCss = require('units-css'); + /** * Export `Context2d` as the module. */ @@ -34,26 +38,6 @@ var cache = {}; var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging']; -/** - * Font RegExp helpers. - */ - -var weights = 'normal|bold|bolder|lighter|[1-9]00' - , styles = 'normal|italic|oblique' - , units = 'px|pt|pc|in|cm|mm|%' - , string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+'; - -/** - * Font parser RegExp; - */ - -var fontre = new RegExp('^ *' - + '(?:(' + weights + ') *)?' - + '(?:(' + styles + ') *)?' - + '([\\d\\.]+)(' + units + ') *' - + '((?:' + string + ')( *, *(?:' + string + '))*)' - ); - /** * Parse font `str`. * @@ -62,40 +46,51 @@ var fontre = new RegExp('^ *' * @api private */ -var parseFont = exports.parseFont = function(str){ - var font = {} - , captures = fontre.exec(str); +var parseFont = exports.parseFont = function(str) { + var parsedFont; - // Invalid - if (!captures) return; + // Try to parse the font string using parse-css-font. + // It will throw an exception if it fails. + try { + parsedFont = parseCssFont(str); + } + catch (e) { + // Invalid + return; + } // Cached if (cache[str]) return cache[str]; - // Populate font object - font.weight = captures[1] || 'normal'; - font.style = captures[2] || 'normal'; - font.size = parseFloat(captures[3]); - font.unit = captures[4]; - font.family = captures[5].replace(/["']/g, '').split(',')[0].trim(); + // Parse size into value and unit using units-css + var size = unitsCss.parse(parsedFont.size); // TODO: dpi // TODO: remaining unit conversion - switch (font.unit) { + switch (size.unit) { case 'pt': - font.size /= .75; + size.value /= .75; break; case 'in': - font.size *= 96; + size.value *= 96; break; case 'mm': - font.size *= 96.0 / 25.4; + size.value *= 96.0 / 25.4; break; case 'cm': - font.size *= 96.0 / 2.54; + size.value *= 96.0 / 2.54; break; } + // Populate font object + var font = { + weight: parsedFont.weight, + style: parsedFont.style, + size: size.value, + unit: size.unit, + family: parsedFont.family[0] + }; + return cache[str] = font; }; diff --git a/package.json b/package.json index 4211c75bc..6db985df0 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "test-server": "node test/server.js" }, "dependencies": { - "nan": "^2.4.0" + "nan": "^2.4.0", + "parse-css-font": "^2.0.2", + "units-css": "^0.4.0" }, "devDependencies": { "body-parser": "^1.13.3", diff --git a/test/public/tests.js b/test/public/tests.js index f0b9f0d97..359a7f0ed 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -988,6 +988,18 @@ tests['font family invalid'] = function(ctx){ ctx.fillText("14px Invalid, Impact", 100, 100); }; +tests['font style variant weight size family'] = function (ctx) { + ctx.strokeStyle = '#666' + ctx.strokeRect(0, 0, 200, 200) + ctx.lineTo(0, 100) + ctx.lineTo(200, 100) + ctx.stroke() + + ctx.font = 'normal normal normal 16px Impact' + ctx.textAlign = 'center' + ctx.fillText('normal normal normal 16px', 100, 100) +} + tests['globalCompositeOperation source-over'] = function(ctx){ ctx.fillStyle = 'blue'; ctx.fillRect(0,0,100,100);