From ccf0eec889ec68b03ba78139c3e81a985b71823c Mon Sep 17 00:00:00 2001 From: mkwiser Date: Thu, 9 Oct 2014 22:44:44 +0800 Subject: [PATCH] add setting adjust glyf --- css/common/common.less | 63 ++-- css/ttf.less | 3 +- src/fonteditor/dialog/setting-adjust.js | 95 ----- src/fonteditor/dialog/setting.js | 45 +++ src/fonteditor/ttf/main.js | 29 +- src/fonteditor/widget/controller/default.js | 6 +- src/fonteditor/widget/glyfviewer.js | 157 ++++---- src/fonteditor/widget/loading.js | 26 +- src/fonteditor/widget/ttfmanager.js | 252 ++++--------- src/ttf/ttf.js | 373 +++++++++++++++++++- ttf.html | 5 +- 11 files changed, 649 insertions(+), 405 deletions(-) delete mode 100644 src/fonteditor/dialog/setting-adjust.js diff --git a/css/common/common.less b/css/common/common.less index 777287e..ee78395 100644 --- a/css/common/common.less +++ b/css/common/common.less @@ -2,36 +2,36 @@ @import './bootstrap.less'; body, html { - margin: 0; - padding: 0; - font-size: 13px; - height: 100%; + margin: 0; + padding: 0; + font-size: 13px; + height: 100%; } // scroll bar ::-webkit-scrollbar { - width: 14px; - height: 14px; + width: 14px; + height: 14px; } ::-webkit-scrollbar-track, ::-webkit-scrollbar-thumb { - border-radius: 999px; - border: 5px solid transparent; + border-radius: 999px; + border: 5px solid transparent; } ::-webkit-scrollbar-track { - box-shadow: 1px 1px 5px rgba(0,0,0,.2) inset; + box-shadow: 1px 1px 5px rgba(0,0,0,.2) inset; } ::-webkit-scrollbar-thumb { - min-height: 20px; - background-clip: content-box; - box-shadow: 0 0 0 5px rgba(0,0,0,.2) inset; + min-height: 20px; + background-clip: content-box; + box-shadow: 0 0 0 5px rgba(0,0,0,.2) inset; } ::-webkit-scrollbar-corner { - background: transparent; + background: transparent; } .navbar { @@ -85,22 +85,31 @@ body, html { // loading 动画 .loading { - position: fixed; - left: 50%; - top: 30%; - width: 200px; - margin-left: -100px; - line-height: 24px; - text-align: center; - display: none; + position: fixed; + left: 50%; + top: 30%; + width: 200px; + margin-left: -100px; + line-height: 24px; + text-align: center; + display: none; + + span { + display: inline-block; + padding: 0 6px; + background: rgba(84, 114, 93, 0.8); + color: #FFF; + border: 1px solid #DDD; + } + } .selection-range { - position: absolute; - z-index: 6; - display: none; - border: 1px solid #CCC; - background: rgba(222, 222, 222, 0.5); - pointer-events: none; + position: absolute; + z-index: 6; + display: none; + border: 1px solid #CCC; + background: rgba(222, 222, 222, 0.5); + pointer-events: none; } \ No newline at end of file diff --git a/css/ttf.less b/css/ttf.less index 9adce57..da9c5d7 100644 --- a/css/ttf.less +++ b/css/ttf.less @@ -103,7 +103,8 @@ } } - >.new { + >.new, + >.edit { .path { fill: blue!important; } diff --git a/src/fonteditor/dialog/setting-adjust.js b/src/fonteditor/dialog/setting-adjust.js deleted file mode 100644 index dfe226a..0000000 --- a/src/fonteditor/dialog/setting-adjust.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file setting-adjust.js - * @author mengke01 - * @date - * @description - * 设置自动调整字形 - */ - -define( - function(require) { - - var lang = require('common/lang'); - - var tpl = '' - + '
' - + '左边轴' - + '' - + '
' - + '
' - + '右边轴' - + '' - + '
' - + '
' - + '
' - + '
' - + '缩放字形到em框' - + '' - + '' - + '' - + '
' - + '
' - + ' ' - + '
' - + '
' - + '顶部和底部留白' - + '' - + '
' - + '
' - + '
' - + '
' - + '基线偏移' - + '' - + '
'; - - - return require('./setting').derive({ - - title: '调整字形', - - getTpl: function() { - return tpl; - }, - - set: function(setting) { - setting = setting || {}; - this.getDialog().find('[data-field]').each(function(i, item) { - item = $(item); - item.val(setting[item.attr('data-field')] || ''); - }); - }, - - validate: function() { - var setting = {}; - this.getDialog().find('[data-field]').each(function(i, item) { - - if (item.type == 'checkbox') { - if (item.checked) { - setting[$(item).attr('data-field')] = true; - } - } - else { - item = $(item); - var val = item.val().trim(); - if (val) { - setting[item.attr('data-field')] = Math.floor(+val); - } - } - }); - - if(setting.leftSideBearing == undefined - && setting.rightSideBearing == undefined - && setting.ajdustToEmBox == undefined - && setting.verticalAlign == undefined - ) { - alert('没有设置项目!'); - return false; - } - else { - return setting; - } - } - - }); - } -); diff --git a/src/fonteditor/dialog/setting.js b/src/fonteditor/dialog/setting.js index 5847fbc..07e3b19 100644 --- a/src/fonteditor/dialog/setting.js +++ b/src/fonteditor/dialog/setting.js @@ -79,6 +79,51 @@ define( return true; }; + + /** + * 设置field字段值 + * + * @return {boolean} + */ + Setting.prototype.setFields = function(setting) { + this.getDialog().find('[data-field]').each(function(i, item) { + + if (item.type == 'checkbox') { + item.checked = setting[item.getAttribute('data-field')] ? 'checked' : ''; + } + else { + item = $(item); + item.val(setting[item.attr('data-field')]); + } + }); + return this; + }; + + /** + * 获取field字段值 + * + * @return {Object} + */ + Setting.prototype.getFields = function() { + var setting = {}; + this.getDialog().find('[data-field]').each(function(i, item) { + + if (item.type == 'checkbox') { + if (item.checked) { + setting[item.getAttribute('data-field')] = true; + } + } + else { + item = $(item); + var val = item.val().trim(); + if (val) { + setting[item.attr('data-field')] = item.attr('data-ceil') ? Math.floor(val) : +val ; + } + } + }); + return setting; + }; + /** * 显示 * @param {Object} setting 设置选项 diff --git a/src/fonteditor/ttf/main.js b/src/fonteditor/ttf/main.js index 9a1922a..0773af9 100644 --- a/src/fonteditor/ttf/main.js +++ b/src/fonteditor/ttf/main.js @@ -25,7 +25,8 @@ define( var setting = { 'unicode': require('../dialog/setting-unicode'), 'name': require('../dialog/setting-name'), - 'adjust': require('../dialog/setting-adjust'), + 'adjust-pos': require('../dialog/setting-adjust-pos'), + 'adjust-glyf': require('../dialog/setting-adjust-glyf'), 'online': require('../dialog/font-online') } @@ -96,12 +97,14 @@ define( onChange: function(url) { // 此处延迟处理 setTimeout(function(){ + program.loading.show('正在加载..', 1000); ajaxBinaryFile({ url: url, onSuccess: function(buffer) { loader.load(buffer, { type: 'ttf', success: function(imported) { + program.loading.hide(); if (program.ttfmanager.get()) { program.ttfmanager.merge(imported, { scale: true @@ -156,14 +159,14 @@ define( } }, - // 调整字形 - 'setting-adjust': function() { + // 调整字形位置 + 'setting-adjust-pos': function() { var ttf = program.ttfmanager.get(); if (ttf) { - var dlg = new setting.adjust({ + var dlg = new setting['adjust-pos']({ onChange: function(setting) { setTimeout(function() { - program.ttfmanager.adjustGlyf(setting, selected); + program.ttfmanager.adjustGlyfPos(setting, selected); }, 20); } }); @@ -181,6 +184,22 @@ define( dlg.show(); } } + }, + + // 调整字形 + 'setting-adjust-glyf': function() { + var ttf = program.ttfmanager.get(); + if (ttf) { + var dlg = new setting['adjust-glyf']({ + onChange: function(setting) { + setTimeout(function() { + program.ttfmanager.adjustGlyf(setting, program.viewer.getSelected()); + }, 20); + } + }); + + dlg.show(); + } } }; diff --git a/src/fonteditor/widget/controller/default.js b/src/fonteditor/widget/controller/default.js index 43e4fd9..c9d7bdc 100644 --- a/src/fonteditor/widget/controller/default.js +++ b/src/fonteditor/widget/controller/default.js @@ -36,7 +36,7 @@ define( }).on('paste', function(e) { var glyfList = clipboard.get('glyf'); if (glyfList && glyfList.length) { - program.ttfmanager.appendGlyf(glyfList); + program.ttfmanager.appendGlyf(glyfList, program.viewer.getSelected()); } }).on('undo', function(e) { program.ttfmanager.undo(); @@ -48,6 +48,7 @@ define( if (program.data.projectName) { program.project.add(program.data.projectName, program.ttfmanager.get()); program.ttfmanager.setState('new'); + program.loading.show('保存成功..', 400); } else { var name = ''; @@ -57,9 +58,12 @@ define( program.projectViewer.show(list); program.data.projectName = name; program.ttfmanager.setState('new'); + program.loading.show('保存成功..', 400); } } } + + }); program.projectViewer.on('open', function(e) { diff --git a/src/fonteditor/widget/glyfviewer.js b/src/fonteditor/widget/glyfviewer.js index b98b345..8a16663 100644 --- a/src/fonteditor/widget/glyfviewer.js +++ b/src/fonteditor/widget/glyfviewer.js @@ -79,6 +79,83 @@ define( }); } + + // 选择范围内元素 + function selectRangeItem(bound, toggle, append) { + + if (!toggle && !append) { + this.main.children().removeClass('selected'); + } + + this.main.children().each(function(i, element) { + var item = $(element); + var pos = item.offset(); + var p = { + x: pos.left + item.width() / 2, + y: pos.top + item.height() / 2 + } + + if (p.x >= bound.x && p.x <= bound.x + bound.width + && p.y >= bound.y && p.y <= bound.y + bound.height + ) { + if (toggle) { + item.toggleClass('selected'); + } + else { + item.addClass('selected') + } + } + }); + } + + // 按下事件 + function downlistener(e) { + var me = this; + + // 保存 + if (83 === e.keyCode && e.ctrlKey) { + e.preventDefault(); + e.stopPropagation(); + me.fire('save'); + } + // 处理其他事件,需要focus + else { + if (me.listening) { + // 阻止ctrl+A默认事件 + if (65 === e.keyCode && e.ctrlKey) { + e.preventDefault(); + e.stopPropagation(); + me.main.children().addClass('selected'); + } + // 撤销 + else if(e.keyCode == 90 && e.ctrlKey) { + e.stopPropagation(); + me.fire('undo'); + } + // 重做 + else if(e.keyCode == 89 && e.ctrlKey) { + e.stopPropagation(); + me.fire('redo'); + } + // 取消选中 + else if (27 === e.keyCode) { + e.stopPropagation(); + me.main.children().removeClass('selected'); + } + // 其他操作 + else if (keyMap[e.keyCode] && (e.keyCode == 46 || e.ctrlKey)) { + e.stopPropagation(); + var selected = me.getSelected(); + if (e.keyCode == 86 || selected.length) { + me.fire(keyMap[e.keyCode], { + list: selected + }); + } + } + } + } + } + /** * glyf查看器 * @@ -95,81 +172,15 @@ define( var me = this; - me.downlistener = function(e) { - // 阻止ctrl+A默认事件 - if (65 === e.keyCode && e.ctrlKey) { - e.preventDefault(); - e.stopPropagation(); - me.main.children().addClass('selected'); - } - // 撤销 - else if(e.keyCode == 90 && e.ctrlKey) { - e.stopPropagation(); - me.fire('undo'); - } - // 重做 - else if(e.keyCode == 89 && e.ctrlKey) { - e.stopPropagation(); - me.fire('redo'); - } - // 保存 - else if (83 === e.keyCode && e.ctrlKey) { - e.preventDefault(); - e.stopPropagation(); - me.fire('save'); - } - // 取消选中 - else if (27 === e.keyCode) { - e.stopPropagation(); - me.main.children().removeClass('selected'); - } - // 其他操作 - else if (keyMap[e.keyCode] && (e.keyCode == 46 || e.ctrlKey)) { - e.stopPropagation(); - var selected = me.getSelected(); - if (e.keyCode == 86 || selected.length) { - me.fire(keyMap[e.keyCode], { - list: selected - }); - } - } - }; + me.downlistener = lang.bind(downlistener, this); + + document.body.addEventListener('keydown', this.downlistener); - $(document.body).on('click', function(e) { var focused = me.main.get(0) === e.target || me.main.get(0).contains(e.target); - focused ? me.focus() : me.blur(); + me.listening = focused; }); - // 选择范围内元素 - function selectRangeItem(bound, toggle, append) { - - if (!toggle && !append) { - me.main.children().removeClass('selected'); - } - - me.main.children().each(function(i, element) { - var item = $(element); - var pos = item.offset(); - var p = { - x: pos.left + item.width() / 2, - y: pos.top + item.height() / 2 - } - - if (p.x >= bound.x && p.x <= bound.x + bound.width - && p.y >= bound.y && p.y <= bound.y + bound.height - ) { - if (toggle) { - item.toggleClass('selected'); - } - else { - item.addClass('selected') - } - } - }); - } - - me.capture = new MouseCapture(me.main.get(0), { events: { dblclick: false, @@ -217,14 +228,10 @@ define( } GlyfViewer.prototype.focus = function() { - if (!this.listening) { - document.body.addEventListener('keydown', this.downlistener); - this.listening = true; - } + this.listening = true; }; GlyfViewer.prototype.blur = function() { - document.body.removeEventListener('keydown', this.downlistener); this.listening = false; }; diff --git a/src/fonteditor/widget/loading.js b/src/fonteditor/widget/loading.js index 9d2c7f3..9d69023 100644 --- a/src/fonteditor/widget/loading.js +++ b/src/fonteditor/widget/loading.js @@ -17,10 +17,30 @@ define( */ var loading = { - show: function(text) { - $('#loading').html(text || '正在加载...').show(); + /** + * 显示提示框 + * + * @param {string} text 显示文字 + * @param {number} duration 显示时间 + * @return {this} + */ + show: function(text, duration) { + + clearTimeout(this.showtimer); + + $('#loading span').html(text || '正在加载...') + $('#loading').show(); + + if (duration) { + this.showtimer = setTimeout(this.hide, duration); + } + + return this; }, - + + /** + * 隐藏 + */ hide: function() { $('#loading').hide(); } diff --git a/src/fonteditor/widget/ttfmanager.js b/src/fonteditor/widget/ttfmanager.js index a5bcecb..6e9bc84 100644 --- a/src/fonteditor/widget/ttfmanager.js +++ b/src/fonteditor/widget/ttfmanager.js @@ -10,11 +10,8 @@ define( function(require) { var lang = require('common/lang'); - var postName = require('ttf/enum/postName'); - var pathAdjust = require('graphics/pathAdjust'); - var pathCeil = require('graphics/pathCeil'); var History = require('editor/util/History'); - var computeBoundingBox = require('graphics/computeBoundingBox'); + var TTF = require('ttf/ttf'); /** * 清除glyf编辑状态 @@ -29,46 +26,6 @@ define( return glyfList; } - /** - * 合并两个ttfObject,此处仅合并简单字形 - * - * @param {Object} ttf ttfObject - * @param {Object} imported ttfObject - * @param {Object} options 参数选项 - * @param {boolean} options.scale 是否自动缩放 - * - * @return {Object} 合并后的ttfObject - */ - function merge(ttf, imported, options) { - options = options || {}; - - // 调整glyf以适应打开的文件 - var scale = 1; - // 对导入的轮廓进行缩放处理 - if (options.scale && imported.head.unitsPerEm && imported.head.unitsPerEm != ttf.head.unitsPerEm) { - scale = ttf.head.unitsPerEm / imported.head.unitsPerEm; - } - - var list = imported.glyf.filter(function(g, index) { - return g.contours && g.contours.length //简单轮廓 - && g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; // 非预定义字形 - - }); - - list.forEach(function(g) { - if (scale !== 1) { - g.contours.forEach(function(contour) { - pathAdjust(contour, scale, scale); - pathCeil(contour); - }); - } - g.modify = 'new'; - ttf.glyf.push(g); - }); - - return list.length; - } - /** * 构造函数 * @@ -76,7 +33,7 @@ define( * @param {ttfObject} ttf ttf对象 */ function Manager(ttf) { - this.ttf = ttf; + this.ttf = new TTF(ttf); this.changed = false; // ttf是否被改过 this.history = new History(); } @@ -88,10 +45,10 @@ define( * @return {this} */ Manager.prototype.fireChange = function(pushHistory) { - pushHistory && this.history.add(lang.clone(this.ttf.glyf)); + pushHistory && this.history.add(lang.clone(this.ttf.getGlyf())); this.changed = true; this.fire('change', { - ttf: this.ttf + ttf: this.ttf.get() }); return this; }; @@ -104,16 +61,19 @@ define( */ Manager.prototype.set = function(ttf) { - if (this.ttf !== ttf) { - this.ttf = ttf; + if (this.ttf.get() !== ttf) { + this.ttf.set(ttf); + clearGlyfTag(this.ttf.getGlyf()); + this.history.reset(); - this.history.add(lang.clone(this.ttf.glyf)); + this.history.add(lang.clone(this.ttf.getGlyf())); + this.changed = false; this.fire('change', { - ttf: this.ttf + ttf: this.ttf.get() }); } - + return this; }; @@ -123,7 +83,7 @@ define( * @return {ttfObject} ttf ttf对象 */ Manager.prototype.get = function() { - return this.ttf; + return this.ttf.get(); }; /** @@ -134,9 +94,11 @@ define( * @return {this} */ Manager.prototype.addGlyf = function(glyf) { + glyf.modify = 'new'; - this.ttf.glyf.push(glyf); + this.ttf.addGlyf(glyf); this.fireChange(true); + return this; }; @@ -150,10 +112,15 @@ define( * @return {this} */ Manager.prototype.merge = function(imported, options) { - var count = merge(this.ttf, imported, options); - if (count) { + + var list = this.ttf.mergeGlyf(imported, options); + if (list.length) { + list.forEach(function(g) { + g.modify = 'new'; + }); this.fireChange(true); } + return this; }; @@ -165,15 +132,9 @@ define( * @return {this} */ Manager.prototype.removeGlyf = function(indexList) { - var glyf = this.ttf.glyf, count = 0; - for(var i = glyf.length - 1; i > 0; i--) { - if (indexList.indexOf(i) >= 0) { - glyf.splice(i, 1); - count++; - } - } - if (count) { + var list = this.ttf.removeGlyf(indexList); + if (list.length) { this.fireChange(true); } @@ -189,30 +150,12 @@ define( * @return {this} */ Manager.prototype.setUnicode = function(unicode, indexList) { - var glyf = this.ttf.glyf, list; - if (indexList && indexList.length) { - list = indexList.map(function(item) { - return glyf[item]; - }); - } - else { - list = glyf; - } - - list = list.filter(function(g) { - return g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; - }); + var list = this.ttf.setUnicode(unicode, indexList); if (list.length) { - - unicode = Number('0x' + unicode.slice(1)); - list.forEach(function(g) { - g.unicode = [unicode]; - g.name = unicode - 29 < 258 ? postName[unicode - 29] : 'uni' + unicode.toString(16).toUpperCase(); - unicode++; + g.modify = 'edit'; }); - this.fireChange(true); } @@ -227,24 +170,39 @@ define( * @return {Array} glyflist */ Manager.prototype.appendGlyf = function(glyfList, indexList) { - var glyf = this.ttf.glyf; - if (indexList && indexList.length) { - var l = Math.min(glyfList.length, indexList.length); - for (var i = 0; i < l; i++) { - glyf[indexList[i]] = glyfList[i]; - } - glyfList = glyfList.slice(l); - } - if (glyfList.length) { - glyfList.forEach(function(g) { + + var list = this.ttf.appendGlyf(glyfList, indexList); + if (list.length) { + list.forEach(function(g) { g.modify = 'new'; }); - Array.prototype.splice.apply(glyf, [glyf.length, 0].concat(glyfList)); + this.fireChange(true); } - this.fireChange(true); + return this; }; + /** + * 调整glyf位置 + * + * @param {Object} setting 选项 + * @param {Array} indexList 索引列表 + * @return {boolean} + */ + Manager.prototype.adjustGlyfPos = function(setting, indexList) { + + var list = this.ttf.adjustGlyfPos(setting, indexList); + if (list.length) { + list.forEach(function(g) { + g.modify = 'edit'; + }); + this.fireChange(true); + } + + return this; + }; + + /** * 调整glyf * @@ -253,87 +211,12 @@ define( * @return {boolean} */ Manager.prototype.adjustGlyf = function(setting, indexList) { - - var glyfList = indexList && indexList.length ? this.getGlyf(indexList) : this.ttf.glyf; - var changed = false; - - // 缩放到embox - if (setting.ajdustToEmBox) { - - changed = true; - - var dencent = this.ttf.hhea.descent; - var unitsPerEm = this.ttf.head.unitsPerEm; - var ajdustToEmPadding = 2 * (setting.ajdustToEmPadding || 0); - - glyfList.forEach(function(g) { - if (g.contours && g.contours.length) { - var bound = computeBoundingBox.computePath.apply(this, g.contours); - var scale = (unitsPerEm - ajdustToEmPadding) / bound.height; - if (scale != 1) { - var yOffset = (unitsPerEm / 2 + dencent) - (bound.y + bound.height / 2) * scale; - g.contours.forEach(function(contour) { - pathAdjust(contour, scale, scale); - pathAdjust(contour, 1, 1, 0, yOffset); - pathCeil(contour); - }); - } - } + + var list = this.ttf.adjustGlyf(setting, indexList); + if (list.length) { + list.forEach(function(g) { + g.modify = 'edit'; }); - } - - // 左右边轴 - if (undefined !== setting.leftSideBearing || undefined !== setting.rightSideBearing) { - - changed = true; - - glyfList.forEach(function(g) { - - // 设置左边轴 - if (undefined !== setting.leftSideBearing && g.leftSideBearing != setting.leftSideBearing) { - var offset = setting.leftSideBearing - g.leftSideBearing; - g.xMax += offset; - g.advanceWidth += offset; - g.leftSideBearing = g.xMin = setting.leftSideBearing; - if (g.contours && g.contours.length) { - g.contours.forEach(function(contour) { - pathAdjust(contour, 1, 1, offset); - }); - } - } - - if (undefined !== setting.rightSideBearing) { - g.advanceWidth = g.xMax + setting.rightSideBearing; - } - }); - } - - // 基线高度 - if (undefined !== setting.verticalAlign) { - - changed = true; - - verticalAlign = setting.verticalAlign || 0; - glyfList.forEach(function(g) { - if (g.contours && g.contours.length) { - var bound = computeBoundingBox.computePath.apply(this, g.contours); - var offset = verticalAlign - bound.y; - - g.yMin += offset; - g.yMax += offset; - - if (g.contours && g.contours.length) { - g.contours.forEach(function(contour) { - pathAdjust(contour, 1, 1, 0, offset); - }); - } - } - }); - - } - - - if (changed) { this.fireChange(true); } @@ -347,10 +230,7 @@ define( * @return {Array} glyflist */ Manager.prototype.getGlyf = function(indexList) { - var glyf = this.ttf.glyf; - return indexList.map(function(item) { - return glyf[item]; - }); + return this.ttf.getGlyf(indexList); }; /** @@ -358,12 +238,8 @@ define( * @return {this} */ Manager.prototype.setName = function(name) { - if (name) { - name.fontFamily = name.fontFamily || 'fonteditor'; - name.fontSubFamily = name.fontSubFamily || 'Medium'; - name.fullName = name.fontFamily; - this.ttf.name = name; - } + this.ttf.setName(name); + return this; }; /** @@ -372,7 +248,7 @@ define( */ Manager.prototype.undo = function() { if (!this.history.atFirst()) { - this.ttf.glyf = this.history.back(); + this.ttf.setGlyf(this.history.back()); this.fireChange(false); } }; @@ -384,7 +260,7 @@ define( */ Manager.prototype.redo = function() { if (!this.history.atLast()) { - this.ttf.glyf = this.history.forward(); + this.ttf.setGlyf(this.history.forward()); this.fireChange(false); } }; diff --git a/src/ttf/ttf.js b/src/ttf/ttf.js index 3e8e857..7d61be5 100644 --- a/src/ttf/ttf.js +++ b/src/ttf/ttf.js @@ -10,7 +10,54 @@ define( function(require) { - + + var lang = require('common/lang'); + var postName = require('./enum/postName'); + var pathAdjust = require('graphics/pathAdjust'); + var pathCeil = require('graphics/pathCeil'); + var computeBoundingBox = require('graphics/computeBoundingBox'); + + + /** + * 合并两个ttfObject,此处仅合并简单字形 + * + * @param {Object} ttf ttfObject + * @param {Object} imported ttfObject + * @param {Object} options 参数选项 + * @param {boolean} options.scale 是否自动缩放 + * + * @return {Object} 合并后的ttfObject + */ + function merge(ttf, imported, options) { + options = options || {}; + + // 调整glyf以适应打开的文件 + var scale = 1; + // 对导入的轮廓进行缩放处理 + if (options.scale && imported.head.unitsPerEm && imported.head.unitsPerEm != ttf.head.unitsPerEm) { + scale = ttf.head.unitsPerEm / imported.head.unitsPerEm; + } + + var list = imported.glyf.filter(function(g, index) { + return g.contours && g.contours.length //简单轮廓 + && g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; // 非预定义字形 + + }); + + list.forEach(function(g) { + if (scale !== 1) { + g.contours.forEach(function(contour) { + pathAdjust(contour, scale, scale); + pathCeil(contour); + }); + } + ttf.glyf.push(g); + }); + + return list; + } + + /** * ttf读取函数 * @@ -62,16 +109,326 @@ define( TTF.prototype.getIndexGlyf = function(glyfIndex) { var glyfList = this.ttf.glyf; var glyf = glyfList[glyfIndex]; - // 如果是复合图元, 则把相关的glyf代入 - if(glyf.compound) { - glyf.glyfs.forEach(function(g) { - g.glyf = glyfList[g.glyphIndex]; - }); - } - return glyf; }; + /** + * 设置ttf对象 + * + * @return {this} + */ + TTF.prototype.set = function(ttf) { + delete this.ttf; + this.ttf = ttf; + return this; + }; + + /** + * 获取ttf对象 + * + * @return {ttfObject} ttf ttf对象 + */ + TTF.prototype.get = function() { + return this.ttf; + }; + + /** + * 添加glyf + * + * @param {Object} glyf glyf对象 + * + * @return {Number} 添加的glyf + */ + TTF.prototype.addGlyf = function(glyf) { + this.ttf.glyf.push(glyf); + return [glyf]; + }; + + /** + * 合并两个ttfObject,此处仅合并简单字形 + * + * @param {Object} imported ttfObject + * @param {Object} options 参数选项 + * @param {boolean} options.scale 是否自动缩放 + * + * @return {Array} 添加的glyf + */ + TTF.prototype.mergeGlyf = function(imported, options) { + var list = merge(this.ttf, imported, options); + return list; + }; + + + /** + * 删除指定字形 + * + * @param {Array} indexList 索引列表 + * @return {Array} 删除的glyf + */ + TTF.prototype.removeGlyf = function(indexList) { + var glyf = this.ttf.glyf; + var removed = []; + for(var i = glyf.length - 1; i > 0; i--) { + if (indexList.indexOf(i) >= 0) { + removed.push(glyf[i]); + glyf.splice(i, 1); + } + } + return removed; + }; + + + /** + * 设置unicode代码 + * + * @param {string} unicode unicode代码 + * @param {Array} indexList 索引列表 + * @return {Array} 改变的glyf + */ + TTF.prototype.setUnicode = function(unicode, indexList) { + var glyf = this.ttf.glyf, list; + if (indexList && indexList.length) { + list = indexList.map(function(item) { + return glyf[item]; + }); + } + else { + list = glyf; + } + + list = list.filter(function(g) { + return g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; + }); + + if (list.length) { + unicode = Number('0x' + unicode.slice(1)); + list.forEach(function(g) { + g.unicode = [unicode]; + g.name = unicode - 29 < 258 ? postName[unicode - 29] : 'uni' + unicode.toString(16).toUpperCase(); + unicode++; + }); + } + + return list; + }; + + /** + * 添加并体替换指定的glyf + * + * @param {Array} glyfList 添加的列表 + * @param {Array} indexList 需要替换的索引列表 + * @return {Array} 改变的glyf + */ + TTF.prototype.appendGlyf = function(glyfList, indexList) { + var glyf = this.ttf.glyf, result = glyfList.slice(0); + + if (indexList && indexList.length) { + var l = Math.min(glyfList.length, indexList.length); + for (var i = 0; i < l; i++) { + glyf[indexList[i]] = glyfList[i]; + } + glyfList = glyfList.slice(l); + } + + if (glyfList.length) { + Array.prototype.splice.apply(glyf, [glyf.length, 0].concat(glyfList)); + } + + return result; + }; + + /** + * 调整glyf位置 + * + * @param {Object} setting 选项 + * @param {Array} indexList 索引列表 + * @return {Array} 改变的glyf + */ + TTF.prototype.adjustGlyfPos = function(setting, indexList) { + + var glyfList = this.getGlyf(indexList); + var changed = false; + + // 左右边轴 + if (undefined !== setting.leftSideBearing || undefined !== setting.rightSideBearing) { + + changed = true; + + glyfList.forEach(function(g) { + + // 设置左边轴 + if (undefined !== setting.leftSideBearing && g.leftSideBearing != setting.leftSideBearing) { + var offset = setting.leftSideBearing - g.leftSideBearing; + g.xMax += offset; + g.advanceWidth += offset; + g.leftSideBearing = g.xMin = setting.leftSideBearing; + if (g.contours && g.contours.length) { + g.contours.forEach(function(contour) { + pathAdjust(contour, 1, 1, offset); + }); + } + } + + if (undefined !== setting.rightSideBearing) { + g.advanceWidth = g.xMax + setting.rightSideBearing; + } + }); + } + + // 基线高度 + if (undefined !== setting.verticalAlign) { + + changed = true; + + verticalAlign = setting.verticalAlign || 0; + glyfList.forEach(function(g) { + if (g.contours && g.contours.length) { + var bound = computeBoundingBox.computePath.apply(this, g.contours); + var offset = verticalAlign - bound.y; + + g.yMin += offset; + g.yMax += offset; + + if (g.contours && g.contours.length) { + g.contours.forEach(function(contour) { + pathAdjust(contour, 1, 1, 0, offset); + }); + } + } + }); + + } + + return changed ? glyfList : []; + }; + + + /** + * 调整glyf + * + * @param {Object} setting 选项 + * @param {Array} indexList 索引列表 + * @return {boolean} + */ + TTF.prototype.adjustGlyf = function(setting, indexList) { + + var glyfList = this.getGlyf(indexList); + var changed = false; + + if (setting.reverse || setting.mirror) { + + changed = true; + + glyfList.forEach(function(g) { + if (g.contours && g.contours.length) { + var xMax = g.xMax; + var yMax = g.yMax; + g.contours.forEach(function(contour) { + pathAdjust(contour, setting.reverse ? -1 : 1, setting.mirror ? -1 : 1); + pathAdjust(contour, 1, 1, setting.reverse ? xMax : 0, setting.mirror ? yMax : 0); + }); + } + }); + } + + + if (setting.scale && setting.scale != 1) { + + changed = true; + + var scale = setting.scale; + glyfList.forEach(function(g) { + if (g.contours && g.contours.length) { + g.contours.forEach(function(contour) { + pathAdjust(contour, scale, scale); + pathCeil(contour); + }); + + g.xMin = Math.round(g.xMin * scale); + g.xMax = Math.round(g.xMax * scale); + g.yMin = Math.round(g.yMin * scale); + g.yMax = Math.round(g.yMax * scale); + } + }); + } + // 缩放到embox + else if (setting.ajdustToEmBox) { + + changed = true; + + var dencent = this.ttf.hhea.descent; + var unitsPerEm = this.ttf.head.unitsPerEm; + var ajdustToEmPadding = 2 * (setting.ajdustToEmPadding || 0); + + glyfList.forEach(function(g) { + if (g.contours && g.contours.length) { + var bound = computeBoundingBox.computePath.apply(null, g.contours); + var scale = (unitsPerEm - ajdustToEmPadding) / bound.height; + if (scale != 1) { + var yOffset = (unitsPerEm / 2 + dencent) - (bound.y + bound.height / 2) * scale; + g.contours.forEach(function(contour) { + pathAdjust(contour, scale, scale); + pathAdjust(contour, 1, 1, 0, yOffset); + pathCeil(contour); + }); + var box = computeBoundingBox.computePathBox.apply(null, g.contours); + g.xMin = box.x; + g.xMax = box.x + box.width; + g.yMin = box.y; + g.yMax = box.y + box.height; + } + } + }); + } + + return changed ? glyfList : []; + }; + + /** + * 获取glyf列表 + * + * @param {Array} indexList 索引列表 + * @return {Array} glyflist + */ + TTF.prototype.getGlyf = function(indexList) { + var glyf = this.ttf.glyf; + if (indexList && indexList.length) { + return indexList.map(function(item) { + return glyf[item]; + }); + } + else { + return glyf; + } + }; + + /** + * 设置glyf + * + * @param {Array} glyfList glyf列表 + * @return {Array} 设置的glyf列表 + */ + TTF.prototype.setGlyf = function(glyfList) { + delete this.glyf; + this.ttf.glyf = glyfList || []; + return this.ttf.glyf; + }; + + + /** + * 设置名字 + * + * @return {Object} 名字对象 + */ + TTF.prototype.setName = function(name) { + if (name) { + name.fontFamily = name.fontFamily || 'fonteditor'; + name.fontSubFamily = name.fontSubFamily || 'Medium'; + name.fullName = name.fontFamily; + this.ttf.name = name; + } + return this.ttf.name; + }; return TTF; } diff --git a/ttf.html b/ttf.html index b672c4b..c6f9dc2 100644 --- a/ttf.html +++ b/ttf.html @@ -41,7 +41,8 @@ @@ -60,7 +61,7 @@
-
正在加载...
+
正在加载...