diff --git a/css/main.css b/css/main.css
new file mode 100644
index 0000000..1213f80
--- /dev/null
+++ b/css/main.css
@@ -0,0 +1,948 @@
+* {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+blockquote,
+body,
+button,
+dd,
+dl,
+dt,
+fieldset,
+form,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+input,
+legend,
+li,
+ol,
+p,
+pre,
+td,
+textarea,
+th,
+ul {
+ margin: 0;
+ padding: 0;
+}
+body,
+button,
+input,
+select,
+textarea {
+ font: 12px/1.5 tahoma, arial, sans-serif;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: 100%;
+}
+address,
+cite,
+dfn,
+em,
+var {
+ font-style: normal;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: courier new, courier, monospace;
+}
+small {
+ font-size: 12px;
+}
+ol,
+ul {
+ list-style: none;
+}
+a {
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+legend {
+ color: #000000;
+}
+fieldset,
+img {
+ border: 0;
+}
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.modal-dialog {
+ margin-top: 100px;
+}
+.modal-header {
+ padding-top: 6px;
+ padding-bottom: 6px;
+ background: #327EC0;
+ color: #FFF;
+}
+.modal-header .close {
+ margin-top: 3px;
+}
+.modal-header .modal-title {
+ font-size: 14px;
+ line-height: 25px;
+}
+.modal-footer {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+.modal-body {
+ min-height: 100px;
+}
+.modal-content {
+ border-color: rgba(0, 0, 0, 0.5);
+ -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+ overflow: hidden;
+}
+.dropdown-menu {
+ margin-top: 0;
+ border-radius: 0;
+ background: #323842;
+ border: none;
+}
+.dropdown-menu > li > a {
+ cursor: pointer;
+ color: #B6CBDD;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ color: #FFF;
+ background: #232830;
+}
+.input-group {
+ margin-bottom: 10px;
+}
+.list-group-item .from {
+ float: right;
+}
+hr {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.form-inline .form-group {
+ margin-right: 10px;
+ width: 30%;
+}
+.navbar {
+ height: 50px;
+ background: #F9F9F9;
+}
+.btn-groups {
+ line-height: 50px;
+}
+.btn-groups > .split {
+ width: 1px;
+ height: 30px;
+ line-height: 30px;
+ background: #D8D8D8;
+ margin: 0 8px;
+ display: inline-block;
+ vertical-align: middle;
+}
+.btn-flat {
+ border-radius: 0;
+ color: #FFF;
+ background: #738089;
+}
+.btn-flat:hover,
+.btn-flat:focus {
+ background: #323842;
+ color: #B6CBDD;
+ outline: none;
+}
+.btn-flat > .ico-left {
+ margin-right: 8px;
+}
+.btn-flat > .ico {
+ pointer-events: none;
+}
+.btn-flat > .drop {
+ display: inline-block;
+}
+.btn-new {
+ color: #FFF;
+ background: #4A90E2;
+}
+.btn-new:hover,
+.btn-new:focus {
+ background: #2275d7;
+ color: #FFF;
+}
+.btn-preview {
+ color: #FFF;
+ background: #28B4A0;
+}
+.btn-preview:hover,
+.btn-preview:focus {
+ background: #3bd4be;
+ color: #FFF;
+}
+.btn-preview.dropdown-toggle:focus {
+ background: #323842;
+ color: #B6CBDD;
+}
+.btn-confirm {
+ color: #FFF;
+ background: #4A90E2;
+}
+.btn-confirm:hover,
+.btn-confirm:focus {
+ background: #2275d7;
+ color: #FFF;
+}
+.btn-ico {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.btn-ico > .ico {
+ font-size: 16px;
+ line-height: 18px;
+ margin-right: 0;
+}
+.command-groups {
+ height: 40px;
+ padding-left: 8px;
+ overflow: hidden;
+ background: rgba(112, 119, 128, 0.8);
+}
+.command-groups > li {
+ float: left;
+ line-height: 40px;
+ padding: 0 8px;
+ color: #FFF;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+}
+.command-groups > li > i {
+ font-style: normal;
+ text-decoration: underline;
+}
+.command-groups > li > .ico {
+ font-size: 20px;
+ text-decoration: none;
+}
+.command-groups > li:hover {
+ background: #8a919a;
+}
+.command-groups > li[data-theme="ico"] {
+ padding: 0 12px;
+}
+.command-groups > li[data-disabled] {
+ color: #B9BDC1;
+}
+.command-groups > li[data-on] {
+ background: #585e66;
+}
+.command-groups > [data-split] {
+ padding: 0!important;
+ width: 1px;
+ height: 40px;
+ background: #989ea6;
+ pointer-events: none;
+}
+.pager {
+ margin: 0;
+}
+.pager .form-control {
+ display: inline-block;
+ width: 40px;
+ height: 30px;
+ padding: 6px;
+ margin: 0 5px;
+}
+.pager [data-pager="goto"] {
+ margin-right: 5px;
+}
+.pager [data-pager="info"] {
+ margin: 0 5px;
+ color: #FFF;
+}
+.form-line {
+ line-height: 34px;
+}
+.form-title {
+ vertical-align: 3px;
+}
+.btn-right {
+ float: right;
+}
+body,
+html {
+ margin: 0;
+ padding: 0;
+ font-size: 13px;
+ height: 100%;
+}
+::-webkit-scrollbar {
+ width: 12px;
+ height: 12px;
+}
+::-webkit-scrollbar-track,
+::-webkit-scrollbar-thumb {
+ border-radius: 999px;
+ border: 1px solid transparent;
+}
+::-webkit-scrollbar-track {
+ box-shadow: 1px 1px 5px rgba(0, 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, 0.2) inset;
+}
+::-webkit-scrollbar-corner {
+ background: transparent;
+}
+.navbar {
+ border-radius: 0;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ z-index: 10;
+ width: 100%;
+ height: 51px;
+ min-width: 1024px;
+ top: 0;
+}
+.navbar > .logo {
+ loat: left;
+ width: 180px;
+ height: 50px;
+ background: url(img/logo.png) no-repeat;
+ float: left;
+ background-color: #fff;
+ background-position: center;
+ background-image: url(img/logo@1x.png);
+ background-image: -webkit-image-set(url(img/logo@1x.png) 1x, url(img/logo@2x.png) 2x);
+ background-repeat: no-repeat;
+}
+.navbar > .action-groups {
+ margin-left: 180px;
+ padding-left: 8px;
+}
+.container {
+ display: flex;
+ flex: 1;
+}
+.sidebar {
+ position: fixed;
+ width: 180px;
+ top: 50px;
+ bottom: 0;
+ background: #232830;
+}
+.main {
+ margin-left: 180px;
+ padding-top: 90px;
+ height: 100%;
+ background: #BCC5CD;
+}
+.main .glyf-list {
+ padding: 10px 0 0 10px;
+}
+.main .command-groups {
+ margin-top: -40px;
+ display: none;
+}
+.main .pager {
+ position: absolute;
+ z-index: 10;
+ padding: 5px;
+ right: 0;
+ bottom: 0;
+ background: #707780;
+ display: none;
+}
+.main.editing {
+ margin-left: 70%;
+ padding-top: 50px;
+}
+.main.editing .command-groups {
+ display: none;
+}
+.loading {
+ position: fixed;
+ left: 50%;
+ top: 30%;
+ width: 200px;
+ margin-left: -100px;
+ line-height: 24px;
+ text-align: center;
+ z-index: 10000;
+ display: none;
+}
+.loading span {
+ display: inline-block;
+ padding: 0 6px;
+ background: rgba(84, 114, 93, 0.9);
+ color: #FFF;
+ border: 1px solid #DDD;
+}
+.loading[data-status="error"] span {
+ color: red;
+ background: rgba(236, 234, 69, 0.9);
+}
+.loading[data-status="warn"] span {
+ color: #FF8722;
+ background: rgba(255, 255, 255, 0.9);
+}
+.editor {
+ position: fixed;
+ width: 70%;
+ top: 50px;
+ padding-top: 40px;
+ bottom: 0;
+ z-index: 1;
+ background: #FEFEFE;
+ border-right: 1px solid #DDD;
+ display: none;
+}
+.editor .command-groups {
+ background: #707780;
+ margin-top: -40px;
+}
+.editor .close-editor {
+ position: absolute;
+ right: 0;
+ top: 0;
+ padding-right: 5px;
+ z-index: 100;
+ font-size: 20px;
+ line-height: 38px;
+ color: #FFF;
+ display: none;
+}
+.editor .close-editor:hover {
+ cursor: pointer;
+}
+.editor:hover .close-editor {
+ display: block;
+}
+@media screen and (min-width: 1300px) and (max-width: 1600px) {
+ .editor .command-groups > li,
+ .editor .command-groups > li[data-theme="ico"] {
+ padding: 0 8px;
+ }
+}
+@media screen and (max-width: 1300px) {
+ .editor .command-groups > li,
+ .editor .command-groups > li[data-theme="ico"] {
+ padding: 0 4px;
+ }
+}
+.editor.editing {
+ display: block;
+}
+.selection-range {
+ position: absolute;
+ z-index: 6;
+ display: none;
+ border: 1px solid #CCC;
+ background: rgba(222, 222, 222, 0.5);
+ pointer-events: none;
+}
+.forkme {
+ position: absolute;
+ color: #FFF;
+ right: 2px;
+ top: 2px;
+ color: #333333;
+}
+.userguide {
+ position: absolute;
+ color: #FFF;
+ right: 2px;
+ top: 24px;
+ color: #333;
+}
+.modal {
+ background: -webkit-radial-gradient(center, circle contain, rgba(255, 255, 255, 0.6) 0%, rgba(0, 0, 0, 0.6) 100%);
+}
+.modal-content {
+ border-radius: 0;
+}
+.modal-header {
+ background: #fff;
+ color: #202430;
+}
+.modal-body {
+ background: #F8F9F9;
+}
+.modal-footer {
+ border-top: 0;
+ background: #F8F9F9;
+}
+.modal-footer .btn-default {
+ border-radius: 0;
+ color: #FFF;
+ background: #738089;
+}
+.modal-footer .btn-primary {
+ border-radius: 0;
+ background: #4A90E2;
+}
+@font-face {
+ font-family: 'fonteditor';
+ src: url('../font/fonteditor.ttf') format('truetype');
+}
+.ico {
+ display: inline-block;
+}
+.ico:before,
+.ico:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.i-leave:before {
+ content: '\e00c';
+}
+.i-edit,
+.i-del,
+.i-leave {
+ font-size: 12px;
+}
+.i-edit:hover,
+.i-del:hover,
+.i-leave:hover {
+ cursor: pointer;
+ color: #4A90E2;
+}
+.i-edit,
+.i-del {
+ color: #76abe9;
+}
+.i-edit:before {
+ content: '\e021';
+}
+.i-del:before {
+ content: '\e020';
+}
+.i-github:before {
+ content: '\e01e';
+}
+.i-help:before {
+ content: '\e016';
+}
+.i-new:before {
+ content: '\e019';
+}
+.i-open:before {
+ content: '\e01A';
+}
+.i-add:before {
+ content: '\e003';
+}
+.i-undo:before {
+ content: '\e001';
+}
+.i-redo:before {
+ content: '\e002';
+}
+.i-down:before {
+ content: '\e00e';
+}
+.i-left:before {
+ content: '\e00a';
+}
+.i-ttf:before {
+ content: '\e00f';
+}
+.i-woff:before {
+ content: '\e010';
+}
+.i-zip:before {
+ content: '\e011';
+}
+.i-save:before {
+ content: '\e022';
+}
+.i-upshape:before {
+ content: '\e014';
+}
+.i-downshape:before {
+ content: '\e00b';
+}
+.i-reversepoints:before {
+ content: '\e00d';
+}
+.i-alignleft:before {
+ content: '\e006';
+}
+.i-aligncenter:before {
+ content: '\e004';
+}
+.i-alignright:before {
+ content: '\e007';
+}
+.i-aligntop:before {
+ content: '\e008';
+}
+.i-alignmiddle:before {
+ content: '\e005';
+}
+.i-aligndescent:before {
+ content: '\e009';
+}
+.i-alignbaseline:before {
+ content: '\e009';
+}
+.i-rotateleft:before {
+ content: '\e01c';
+}
+.i-rotateright:before {
+ content: '\e01d';
+}
+.i-flip:before {
+ content: '\e013';
+}
+.i-mirror:before {
+ content: '\e012';
+}
+.i-splitshapes:before {
+ content: '\e024';
+}
+.i-joinshapes:before {
+ content: '\e025';
+}
+.i-intersectshapes:before {
+ content: '\e026';
+}
+.i-tangencyshapes:before {
+ content: '\e027';
+}
+.i-rangemode:before {
+ content: '\e029';
+}
+.i-pointmode:before {
+ content: '\e028';
+}
+.project-btns {
+ margin: 0 15px;
+ padding: 10px 0;
+ border-bottom: #353D45 1px solid;
+}
+.project-btns .btn {
+ margin-right: 8px;
+ padding-left: 12px;
+ padding-right: 12px;
+}
+.project-btns .btn:last-child {
+ margin-right: 0;
+}
+.project .project-title {
+ font-weight: bold;
+ color: #6F7D88;
+ padding-left: 15px;
+ line-height: 32px;
+}
+.project .project-list dl {
+ padding: 0 10px 0 15px;
+ cursor: pointer;
+}
+.project .project-list dl dt {
+ line-height: 28px;
+ font-weight: normal;
+ color: #9EB0C0;
+}
+.project .project-list dl dd {
+ display: none;
+ line-height: 28px;
+ color: #6F7D88;
+}
+.project .project-list dl dd span {
+ margin-right: 10px;
+}
+.project .project-list dl dd span:hover {
+ text-decoration: underline;
+}
+.project .project-list dl:hover {
+ background: #48515f;
+}
+.project .project-list dl:hover dt {
+ color: #FFF;
+}
+.project .project-list dl.selected {
+ background: #323842;
+}
+.project .project-list dl.selected dd {
+ display: block;
+}
+.glyf-list {
+ height: 100%;
+ overflow: auto;
+}
+.glyf-list > .glyf-item {
+ float: left;
+ position: relative;
+ margin: 10px;
+ width: 80px;
+ box-shadow: 1px 1px 4px #999;
+ cursor: pointer;
+ background: #ECECEC;
+}
+.glyf-list > .glyf-item .unicode,
+.glyf-list > .glyf-item .name {
+ font-size: 12px;
+ line-height: 20px;
+ height: 20px;
+ padding-left: 4px;
+ color: #45283F;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.glyf-list > .glyf-item .unicode {
+ color: #70A9D6;
+}
+.glyf-list > .glyf-item .glyf {
+ width: 80px;
+ height: 80px;
+ border: 3px solid #FFF;
+ background: #FFF;
+ box-sizing: border-box;
+ display: block;
+}
+.glyf-list > .glyf-item .glyf .path {
+ fill: #232830;
+}
+.glyf-list > .glyf-item .i-del,
+.glyf-list > .glyf-item .i-edit {
+ position: absolute;
+ right: 4px;
+ padding: 0 2px;
+ display: none;
+}
+.glyf-list > .glyf-item .i-edit {
+ right: 20px;
+}
+.glyf-list > .glyf-item:hover .glyf,
+.glyf-list > .selected .glyf {
+ border-color: #232830;
+}
+.glyf-list > .glyf-item:hover .name,
+.glyf-list > .selected .name {
+ color: #FFF;
+}
+.glyf-list > .glyf-item:hover {
+ background: #3C619B;
+}
+.glyf-list > .glyf-item:hover .name {
+ color: #FFF;
+}
+.glyf-list > .glyf-item:hover .i-del {
+ display: block;
+}
+.glyf-list > .glyf-item:hover .i-edit {
+ display: block;
+}
+.glyf-list > .selected,
+.glyf-list > .selected:hover {
+ background: #232830;
+}
+.glyf-list > .editing .glyf,
+.glyf-list > .editing:hover .glyf {
+ border-color: #066BC5;
+}
+.glyf-list > .compound .path {
+ fill: #80ff80 !important;
+}
+.glyf-list > .new .path,
+.glyf-list > .edit .path {
+ fill: blue!important;
+}
+.glyf-list.xlarge > .glyf-item {
+ width: 160px;
+}
+.glyf-list.xlarge > .glyf-item .glyf {
+ width: 160px;
+ height: 160px;
+}
+.glyf-list.large > .glyf-item {
+ width: 120px;
+}
+.glyf-list.large > .glyf-item .glyf {
+ width: 120px;
+ height: 120px;
+}
+.glyf-list.small > .glyf-item {
+ width: 60px;
+}
+.glyf-list.small > .glyf-item .glyf {
+ width: 60px;
+ height: 60px;
+}
+.glyf-list.no-hover .glyf-item {
+ pointer-events: none;
+}
+.glyf-editor {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ display: none;
+}
+.glyf-editor .marker-x,
+.glyf-editor .marker-y {
+ position: absolute;
+ width: 0;
+ height: 0;
+ z-index: 60;
+ pointer-events: none;
+}
+.glyf-editor .marker-x {
+ width: 20px;
+ border-top: 1px dashed #000;
+}
+.glyf-editor .marker-y {
+ height: 20px;
+ border-left: 1px dashed #000;
+}
+.editor-contextmenu {
+ color: #333;
+ width: 140px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+}
+.editor-contextmenu li {
+ padding-left: 10px;
+ cursor: pointer;
+ border-bottom: 1px solid #CCC;
+}
+.editor-contextmenu li > ul {
+ display: none;
+ color: #333;
+ width: 140px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+ margin-left: 120px;
+}
+.editor-contextmenu > li[data-sub] {
+ color: #4A90E2;
+}
+.editor-contextmenu > li[data-sub]:after {
+ content: '>';
+ margin-right: 10px;
+ float: right;
+ font-family: 'Simsun';
+}
+.editor-contextmenu li[data-tag="selected"] {
+ display: inline-block;
+ display: block;
+}
+.editor-contextmenu li[data-tag="selected"]:before,
+.editor-contextmenu li[data-tag="selected"]:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ content: '\e01f';
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ float: right;
+ margin-right: 10px;
+ color: #4A90E2;
+}
+.editor-contextmenu li:hover {
+ background: #EEE;
+}
+.editor-contextmenu li:hover > ul {
+ display: block;
+}
+.editor-contextmenu li:last-child {
+ border-bottom: none;
+}
+.import-pic-dialog .modal-dialog {
+ width: 960px;
+}
+.import-pic-dialog .form-group {
+ width: auto;
+}
+.import-pic-dialog .modal-body {
+ padding-bottom: 0;
+}
+.import-pic-dialog .preview-panel {
+ background: #FFF;
+ margin-bottom: 15px;
+}
+.import-pic-dialog .preview-panel .canvas-left,
+.import-pic-dialog .preview-panel .canvas-right {
+ display: inline-block;
+ width: 50%;
+ height: 420px;
+ overflow: auto;
+}
+.import-pic-dialog .preview-panel .canvas-left {
+ border-right: 1px solid #BAC1CB;
+}
+.import-pic-dialog .preview-panel.fitpanel canvas {
+ max-width: 100%;
+ max-height: 99%;
+}
+.import-pic-dialog .preview-panel.showleft .canvas-left {
+ width: 100%;
+ border-right: none;
+ display: inline-block;
+}
+.import-pic-dialog .preview-panel.showleft .canvas-right {
+ display: none;
+}
+.import-pic-dialog .preview-panel.showright .canvas-right {
+ width: 100%;
+ display: inline-block;
+}
+.import-pic-dialog .preview-panel.showright .canvas-left {
+ display: none;
+}
+.import-pic-dialog .import-pic-url {
+ position: absolute;
+ margin-top: 30px;
+ background: #4A90E2;
+ padding: 10px 10px 0;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ display: none;
+}
+.import-pic-dialog .import-pic-url.show-url {
+ display: block;
+}
diff --git a/css/preview.css b/css/preview.css
new file mode 100644
index 0000000..14cf29e
--- /dev/null
+++ b/css/preview.css
@@ -0,0 +1,137 @@
+* {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+blockquote,
+body,
+button,
+dd,
+dl,
+dt,
+fieldset,
+form,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+input,
+legend,
+li,
+ol,
+p,
+pre,
+td,
+textarea,
+th,
+ul {
+ margin: 0;
+ padding: 0;
+}
+body,
+button,
+input,
+select,
+textarea {
+ font: 12px/1.5 tahoma, arial, sans-serif;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: 100%;
+}
+address,
+cite,
+dfn,
+em,
+var {
+ font-style: normal;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: courier new, courier, monospace;
+}
+small {
+ font-size: 12px;
+}
+ol,
+ul {
+ list-style: none;
+}
+a {
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+legend {
+ color: #000000;
+}
+fieldset,
+img {
+ border: 0;
+}
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.main {
+ padding: 30px 100px;
+}
+.main h1 {
+ font-size: 36px;
+ color: #333;
+ text-align: left;
+ margin-bottom: 30px;
+ border-bottom: 1px solid #eeeeee;
+}
+.helps {
+ margin-top: 40px;
+}
+.helps pre {
+ padding: 20px;
+ margin: 10px 0;
+ border: solid 1px #e7e1cd;
+ background-color: #fffdef;
+ overflow: auto;
+}
+.icon-list {
+ overflow: hidden;
+}
+.icon-list li {
+ float: left;
+ width: 100px;
+ height: 150px;
+ text-align: center;
+}
+.icon-list .icon {
+ font-size: 42px;
+ line-height: 100px;
+ margin: 10px 0;
+ color: #333;
+ font-style: normal;
+ -webkit-transition: font-size 0.25s ease-out 0s;
+ -moz-transition: font-size 0.25s ease-out 0s;
+ transition: font-size 0.25s ease-out 0s;
+}
+.icon-list .icon:hover {
+ font-size: 100px;
+}
+.icon-list .code {
+ color: green;
+ font-weight: bold;
+}
diff --git a/demo/css/editortest.css b/demo/css/editortest.css
new file mode 100644
index 0000000..689a09b
--- /dev/null
+++ b/demo/css/editortest.css
@@ -0,0 +1,268 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+ul {
+ list-style: none;
+}
+a {
+ color: #03C;
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+.hide {
+ display: none;
+}
+@font-face {
+ font-family: 'fonteditor';
+ src: url('../font/fonteditor.ttf') format('truetype');
+}
+.ico {
+ display: inline-block;
+}
+.ico:before,
+.ico:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.i-leave:before {
+ content: '\e00c';
+}
+.i-edit,
+.i-del,
+.i-leave {
+ font-size: 12px;
+}
+.i-edit:hover,
+.i-del:hover,
+.i-leave:hover {
+ cursor: pointer;
+ color: #4A90E2;
+}
+.i-edit,
+.i-del {
+ color: #76abe9;
+}
+.i-edit:before {
+ content: '\e021';
+}
+.i-del:before {
+ content: '\e020';
+}
+.i-github:before {
+ content: '\e01e';
+}
+.i-help:before {
+ content: '\e016';
+}
+.i-new:before {
+ content: '\e019';
+}
+.i-open:before {
+ content: '\e01A';
+}
+.i-add:before {
+ content: '\e003';
+}
+.i-undo:before {
+ content: '\e001';
+}
+.i-redo:before {
+ content: '\e002';
+}
+.i-down:before {
+ content: '\e00e';
+}
+.i-left:before {
+ content: '\e00a';
+}
+.i-ttf:before {
+ content: '\e00f';
+}
+.i-woff:before {
+ content: '\e010';
+}
+.i-zip:before {
+ content: '\e011';
+}
+.i-save:before {
+ content: '\e022';
+}
+.i-upshape:before {
+ content: '\e014';
+}
+.i-downshape:before {
+ content: '\e00b';
+}
+.i-reversepoints:before {
+ content: '\e00d';
+}
+.i-alignleft:before {
+ content: '\e006';
+}
+.i-aligncenter:before {
+ content: '\e004';
+}
+.i-alignright:before {
+ content: '\e007';
+}
+.i-aligntop:before {
+ content: '\e008';
+}
+.i-alignmiddle:before {
+ content: '\e005';
+}
+.i-aligndescent:before {
+ content: '\e009';
+}
+.i-alignbaseline:before {
+ content: '\e009';
+}
+.i-rotateleft:before {
+ content: '\e01c';
+}
+.i-rotateright:before {
+ content: '\e01d';
+}
+.i-flip:before {
+ content: '\e013';
+}
+.i-mirror:before {
+ content: '\e012';
+}
+.i-splitshapes:before {
+ content: '\e024';
+}
+.i-joinshapes:before {
+ content: '\e025';
+}
+.i-intersectshapes:before {
+ content: '\e026';
+}
+.i-tangencyshapes:before {
+ content: '\e027';
+}
+.i-rangemode:before {
+ content: '\e029';
+}
+.i-pointmode:before {
+ content: '\e028';
+}
+.glyf-editor {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ display: none;
+}
+.glyf-editor .marker-x,
+.glyf-editor .marker-y {
+ position: absolute;
+ width: 0;
+ height: 0;
+ z-index: 60;
+ pointer-events: none;
+}
+.glyf-editor .marker-x {
+ width: 20px;
+ border-top: 1px dashed #000;
+}
+.glyf-editor .marker-y {
+ height: 20px;
+ border-left: 1px dashed #000;
+}
+.editor-contextmenu {
+ color: #333;
+ width: 140px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+}
+.editor-contextmenu li {
+ padding-left: 10px;
+ cursor: pointer;
+ border-bottom: 1px solid #CCC;
+}
+.editor-contextmenu li > ul {
+ display: none;
+ color: #333;
+ width: 140px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+ margin-left: 120px;
+}
+.editor-contextmenu > li[data-sub] {
+ color: #4A90E2;
+}
+.editor-contextmenu > li[data-sub]:after {
+ content: '>';
+ margin-right: 10px;
+ float: right;
+ font-family: 'Simsun';
+}
+.editor-contextmenu li[data-tag="selected"] {
+ display: inline-block;
+ display: block;
+}
+.editor-contextmenu li[data-tag="selected"]:before,
+.editor-contextmenu li[data-tag="selected"]:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ content: '\e01f';
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ float: right;
+ margin-right: 10px;
+ color: #4A90E2;
+}
+.editor-contextmenu li:hover {
+ background: #EEE;
+}
+.editor-contextmenu li:hover > ul {
+ display: block;
+}
+.editor-contextmenu li:last-child {
+ border-bottom: none;
+}
+body,
+html {
+ height: 100%;
+}
+#render-view {
+ font-size: 12px;
+ width: 100%;
+ height: 100%;
+ position: relative;
+ -webkit-text-size-adjust: none;
+ display: block;
+}
+.pan-left {
+ float: left;
+ width: 180px;
+ background: #ECECEC;
+}
+#glyf-list a {
+ display: block;
+ line-height: 24px;
+}
+#render-view {
+ margin-left: 200px;
+ width: auto;
+}
diff --git a/demo/fitImage.html b/demo/fitImage.html
deleted file mode 100644
index ce3977a..0000000
--- a/demo/fitImage.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
- canvas拟合图像
-
-
-
-
-
-
-
-
-
- 灰度阈值:
- 反转图像:
- 二值算子:
-
-
-
-
-
-
-
-
-
-
diff --git a/demo/js/fitCircle.js b/demo/js/fitCircle.js
index 849701e..d3acbd7 100644
--- a/demo/js/fitCircle.js
+++ b/demo/js/fitCircle.js
@@ -6,8 +6,8 @@
define(
function(require) {
- var fitCurve = require('graphics/image/fitCurve');
- var fitBezier = require('graphics/image/fitBezier');
+ var fitCurve = require('graphics/image/contour/fitCurve');
+ var fitBezier = require('graphics/image/contour/fitBezier');
var lang = require('common/lang');
diff --git a/demo/js/fitContours.js b/demo/js/fitContours.js
index 8a1d551..f4bc8e5 100644
--- a/demo/js/fitContours.js
+++ b/demo/js/fitContours.js
@@ -6,7 +6,7 @@
define(
function (require) {
- var fitContour = require('graphics/image/fitContour');
+ var fitContour = require('graphics/image/contour/fitContour');
var data = require('demo/../data/image-contours2');
var drawPath = require('render/util/drawPath');
var pathUtil = require('graphics/pathUtil');
diff --git a/demo/js/fitCurve.js b/demo/js/fitCurve.js
index 73280dc..3cc169a 100644
--- a/demo/js/fitCurve.js
+++ b/demo/js/fitCurve.js
@@ -6,8 +6,8 @@
define(
function(require) {
- var fitCurve = require('graphics/image/fitCurve');
- var fitBezier = require('graphics/image/fitBezier');
+ var fitCurve = require('graphics/image/contour/fitCurve');
+ var fitBezier = require('graphics/image/contour/fitBezier');
var lang = require('common/lang');
/**
diff --git a/demo/js/fitImage.js b/demo/js/fitImage.js
deleted file mode 100644
index 4d66055..0000000
--- a/demo/js/fitImage.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * @file canvas读取图片
- * @author mengke01(kekee000@gmail.com)
- */
-
-define(
- function (require) {
-
- var lang = require('common/lang');
- var image2Values = require('graphics/image/image2Values');
- var findContours = require('graphics/image/findContours');
- var findBreakPoints = require('graphics/image/findBreakPoints');
- var pathUtil = require('graphics/pathUtil');
- var pathsUtil = require('graphics/pathsUtil');
- var fitImageContours = require('graphics/image/fitImageContours');
-
- var editor = require('editor/main');
-
- var ctx = null;
- var canvas = null;
- var curImage = null;
-
- function getOptions() {
- return {
- threshold: $('#threshold-fn').val() ? $('#threshold-fn').val() : +$('#threshold-gray').val(),
- reverse: !!$('#threshold-reverse').get(0).checked
- }
- }
-
- function onUpFileChange(e) {
- var file = e.target.files[0];
- var reader = new FileReader();
- reader.onload = function(e) {
-
- var image = curImage = new Image();
- image.onload = function () {
- getContours(image);
- };
-
- image.src = e.target.result;
- }
-
- reader.onerror = function(e) {
- console.error(e);
- };
-
- reader.readAsDataURL(file);
- }
-
- function getContours(image) {
- ctx.clearRect(0,0, canvas.width, canvas.height);
- var width = image.width;
- var height = image.height;
- canvas.width = image.width;
- canvas.height = image.height;
-
- ctx.drawImage(image, 0, 0, width, height);
- var imgData = ctx.getImageData(0, 0, width, height);
- var result = image2Values(imgData, getOptions());
-
- var putData = imgData.data;
- for (var y = 0; y < height; y ++) {
- var line = width * y;
- for (var x = 0; x < width; x++) {
- var offset = line + x;
- if (result.data[offset]) {
- putData[offset * 4] = 208;
- putData[offset * 4 + 1] = 247;
- putData[offset * 4 + 2] = 113;
- putData[offset * 4 + 3] = 255;
- }
- else {
- putData[offset * 4] = 255;
- putData[offset * 4 + 1] = 255;
- putData[offset * 4 + 2] = 255;
- putData[offset * 4 + 3] = 255;
- }
- }
- }
-
- var contours = findContours(lang.clone(result));
-
- contours.forEach(function (contour) {
- contour.forEach(function (p) {
- var offset = p.y * width + p.x;
- putData[offset * 4] = 255;
- putData[offset * 4 + 1] = 0;
- putData[offset * 4 + 2] = 0;
- putData[offset * 4 + 3] = 255;
- });
- });
- ctx.putImageData(imgData, 0, 0);
-
- //getBreakPoint(contours);
-
- var contours = fitImageContours(result, getOptions());
-
- window.editor.setFont({
- contours: pathsUtil.mirror(contours, 1, -1)
- });
- }
-
-
- function getBreakPoint(contours) {
- var breakPoints = [];
- contours.forEach(function (contour) {
-
- contour = pathUtil.scale(contour, 10);
- var points = findBreakPoints(contour, 10);
-
- if (points) {
- points.forEach(function (p) {
- breakPoints.push(p);
- });
- }
-
- contour = pathUtil.scale(contour, 0.1);
- });
-
-
-
- breakPoints.forEach(function (p) {
-
- ctx.beginPath();
-
- if (p.breakPoint) {
- ctx.fillStyle = 'red';
- }
- else if (p.inflexion) {
- ctx.fillStyle = 'blue';
- }
-
- ctx.fillRect(p.x, p.y, p.right == 1 ? 6 : 3, p.right == 1 ? 6 : 3);
- });
-
- }
-
- function refresh() {
- curImage && getContours(curImage, getOptions());
- }
-
- var entry = {
-
- /**
- * 初始化
- */
- init: function () {
-
- window.editor = editor.create($('#render-view').get(0));
-
- document.getElementById('upload-file').addEventListener('change', onUpFileChange);
- canvas = document.getElementById("canvas");
- ctx = canvas.getContext("2d");
-
- $('#threshold-gray').on('change', function () {
- $('#threshold-fn').val('');
- refresh();
- });
-
- $('#threshold-fn').on('change', refresh);
- $('#threshold-reverse').on('change', refresh);
-
- var img = new Image();
- img.onload = function () {
- curImage = img;
- refresh();
- }
- img.src = '../test/meng1.gif';
- }
- };
-
- entry.init();
-
- return entry;
- }
-);
diff --git a/src/common/ajaxFile.js b/src/common/ajaxFile.js
index efb8731..38c4e8b 100644
--- a/src/common/ajaxFile.js
+++ b/src/common/ajaxFile.js
@@ -24,27 +24,30 @@ define(
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
- if (xhr.readyState === 4 && xhr.status === 200) {
- if (options.onSuccess) {
+ if (xhr.readyState === 4) {
+ var status = xhr.status;
+ if (status >= 200 && status < 300 || status === 304) {
+ if (options.onSuccess) {
+ if (options.type === 'binary') {
+ var buffer = xhr.responseBlob || xhr.response;
+ options.onSuccess(buffer);
+ }
+ else if (options.type === 'xml') {
+ options.onSuccess(xhr.responseXML);
+ }
+ else if (options.type === 'json') {
+ options.onSuccess(JSON.parse(xhr.responseText));
+ }
+ else {
+ options.onSuccess(xhr.responseText);
+ }
+ }
- if (options.type === 'binary') {
- var buffer = xhr.responseBlob || xhr.response;
- options.onSuccess(buffer);
- }
- else if (options.type === 'xml') {
- options.onSuccess(xhr.responseXML);
- }
- else if (options.type === 'json') {
- options.onSuccess(JSON.parse(xhr.responseText));
- }
- else {
- options.onSuccess(xhr.responseText);
- }
}
- }
- else if (xhr.status > 200) {
- if (options.onError) {
- options.onError(xhr, xhr.status);
+ else {
+ if (options.onError) {
+ options.onError(xhr, xhr.status);
+ }
}
}
};
diff --git a/src/common/string.js b/src/common/string.js
index 6423c3a..6a90b95 100644
--- a/src/common/string.js
+++ b/src/common/string.js
@@ -56,28 +56,6 @@ define(
return String(source).replace(/[^\x00-\xff]/g, '11').length;
},
- /**
- * 按字节截取字符串
- * @param {string} str 字符串
- * @param {number} length 截取长度
- * @param {string} tail 加的后缀
- * @return {string} 截取后的字符串
- */
- cut: function (str, length, tail) {
- tail = tail || '';
- str = String(str);
- var size = 0;
- var l = str.length;
-
- for (var i = 0; i < l; i++) {
- size += str.charCodeAt(i) > 255 ? 2 : 1;
- if (size > length) {
- return str.slice(0, i) + tail;
- }
- }
- return str + tail;
- },
-
/**
* 字符串格式化,支持如 ${xxx.xxx} 的语法
* @param {string} source 模板字符串
diff --git a/src/graphics/image/contour/findBreakPoints-1.js b/src/graphics/image/contour/findBreakPoints-1.js
deleted file mode 100644
index 5b6c08d..0000000
--- a/src/graphics/image/contour/findBreakPoints-1.js
+++ /dev/null
@@ -1,471 +0,0 @@
-/**
- * @file 查找轮廓中的关键点
- * @author mengke01(kekee000@gmail.com)
- *
- * 查找方法为此处文章的方法
- * http://wenku.baidu.com/link?url=Sz1BbYjfA7IeHAMVJ1TPlXiMhACc6sWhHliPJqAUxxtC5K9PYf4j3ile6patUEUMOE_9uJdsS1EGJBFLVbhXcn7Qe8l_FxuT3QVI8nm1aZG
- *
- * 关键点标记定义:
- *
- * p.left 左侧类型
- * p.right: 右侧类型
- * 直线为1,
- * 曲线为2
- */
-
-
-define(
- function (require) {
-
- var makeLink = require('graphics/pathUtil').makeLink;
- var getCos = require('graphics/vector').getCos;
- var getDist = require('graphics/vector').getDist;
-
- var THETA_TANGENCY = 0.1; // 相切抑制
- var THETA_CORNER = 0.5; // 拐点抑制
- var THETA_MARK_COUNT = 0.8; // 标记点个数抑制
- var THETA_INFLEXION_RANGE = 0.05; // 切线点之间的距离抑制
-
-
- function isSegmentLine(contour, start, end, isLast) {
- var contourSize = contour.length;
- var mid;
- var thetaDistance = 10; // 判断直线点距离
-
- // 判断中间点距离
- if (isLast) {
- mid = contour[Math.floor(start.index + (contourSize - start.index + end.index) / 2) % contourSize];
- }
- else {
- mid = contour[Math.floor((start.index + end.index) / 2)];
- }
-
- if (getDist(start, end, mid) > thetaDistance) {
- return false;
- }
-
- // 随机选取 几个点进行直线判断
- var startIndex = start.index;
- var endIndex = end.index;
- if (isLast) {
- startIndex = start.index;
- endIndex = contourSize + end.index;
- }
-
- // 距离比较长的话可以适当放大
- if (endIndex - startIndex > 100) {
- thetaDistance = 20;
- }
-
- var step = Math.floor(Math.max((endIndex - startIndex) / 10, 4));
- var lineFlag = true;
-
- for (var j = startIndex + step; j < endIndex; j += step) {
- var dist = getDist(start, end, contour[j % contourSize]);
- if (dist > thetaDistance) {
- lineFlag = false;
- break;
- }
- }
-
- return lineFlag;
- }
-
-
- /**
- * 计算当前点的theta值
- *
- * @param {Object} cur 当前点
- * @param {Object} leftR 左侧平均
- * @param {Object} rightR 右侧平均
- * @return {number} theta值
- */
- function computeTheta(p, leftR, rightR) {
- var leftX = 0;
- var leftY = 0;
- var t = 0;
- var cur = p;
- while (t++ < leftR) {
- cur = cur.prev;
- leftX += cur.x;
- leftY += cur.y;
- }
- leftX = leftX / leftR;
- leftY = leftY / leftR;
-
- // 右侧分量
- var rightX = 0;
- var rightY = 0;
- t = 0;
- cur = p;
- while (t++ < rightR) {
- cur = cur.next;
- rightX += cur.x;
- rightY += cur.y;
- }
- rightX = rightX / rightR;
- rightY = rightY / rightR;
-
- leftX = p.x - leftX;
- leftY = p.y - leftY;
- rightX = rightX - p.x;
- rightY = rightY - p.y;
- var theta = Math.acos(getCos(leftX, leftY, rightX, rightY));
- var m = leftX * rightY - rightX * leftY;
- if (m > 0) {
- return theta;
- }
- else if (m < 0) {
- return -theta;
- }
-
- return 0;
- }
-
- /**
- * 标记点的左右已经被访问过了
- *
- * @param {Object} p 点
- * @param {number} rl 左半径
- * @param {number} rr 右半径
- */
- function markVisited(p, rl, rr) {
- var j;
- var left = p;
- var right = p;
- p.visited = true;
-
- if (!rr || rr === rl) {
- j = 0;
- while (j++ < rl) {
- left = left.prev;
- right = right.next;
- left.visited = right.visited = true;
- }
- }
- else {
-
- j = 0;
- while (j++ < rl) {
- left = left.prev;
- left.visited = true;
- }
-
- j = 0;
- while (j++ < rr) {
- right = right.next;
- right.visited = true;
- }
- }
- }
-
- /**
- * 查找和标记直线点
- *
- * @param {Array} contour 轮廓
- * @param {Array} breakPoints 关键点
- * @param {number} r 查找范围
- * @return {Array} 关键点
- */
- function findLinePoints(contour, breakPoints, r) {
-
- // 根据角点查找竖直和水平线
- var linePoints = [];
-
- var contourSize = contour.length;
- for (var i = 0, l = breakPoints.length; i < l; i++) {
- var isLast = i === l - 1;
- var p = breakPoints[i];
- var next = isLast ? breakPoints[0] : breakPoints[i + 1];
-
- if (p.right === 1) {
- continue;
- }
-
- var range = isLast ? contourSize - p.index + next.index : next.index - p.index;
- if (range < r) {
- p.right = 1;
- next.left = 1;
- }
- else if (isSegmentLine(contour, p, next, isLast)){
- p.right = 1;
- next.left = 1;
- }
- }
-
- return breakPoints;
- }
-
-
-
-
-
- /**
- * 查找竖直和水平直线点
- *
- * @param {Array} contour 轮廓
- * @param {Array} breakPoints 关键点
- * @param {number} r 查找范围
- * @return {Array} 关键点
- */
- function findVerticalAndHorizontalPoints(contour, breakPoints, r) {
-
- var contourSize = contour.length;
- for (var i = 0, l = contourSize; i < l; i++) {
- var p = contour[i];
- var cur;
- var count;
-
- // 查找竖直直线点
- if (p.x === p.next.x && p.x === p.next.next.x) {
- cur = p.next.next;
- count = 2;
-
- while (cur.x === cur.next.x) {
- cur = cur.next;
- count++;
- }
-
- if (count > 40) {
-
- cur = cur.prev;
- //p.right = 1;
- if (-1 == breakPoints.indexOf(p)) {
- breakPoints.push(p);
- }
-
- markVisited(p, r, count + r);
- // 判断是否角点
- p.theta = computeTheta(p, r, 1);
- p.absTheta = Math.abs(p.theta);
-
- if (p.absTheta > THETA_CORNER) {
- p.breakPoint = true;
- }
- else if (p.absTheta <= THETA_TANGENCY) {
- p.tangency = true;
- }
-
- if (count > 80) {
- //cur.left = 1;
- if (-1 == breakPoints.indexOf(cur)) {
- breakPoints.push(cur);
- }
-
- cur.theta = computeTheta(cur, 1, r);
- cur.absTheta = Math.abs(cur.theta);
-
- if (cur.absTheta > THETA_CORNER) {
- cur.breakPoint = true;
- }
- else if (cur.absTheta < THETA_TANGENCY) {
- cur.tangency = true;
- }
- }
- i += count;
- }
-
- }
- else if (p.y === p.next.y && p.y === p.next.next.y) {
- cur = p.next.next;
- count = 2;
-
- while (cur.y === cur.next.y) {
- cur = cur.next;
- count++;
- }
-
- if (count > 40) {
-
- cur = cur.prev;
-
- //p.right = 1;
- if (-1 == breakPoints.indexOf(p)) {
- breakPoints.push(p);
- }
- //cur.left = 1;
- if (-1 == breakPoints.indexOf(cur)) {
- breakPoints.push(cur);
- }
-
- markVisited(p, r, count + r);
- // 判断是否角点
- p.theta = computeTheta(p, r, 1);
- p.absTheta = Math.abs(p.theta);
-
- if (p.absTheta > THETA_CORNER) {
- p.breakPoint = true;
- }
- else if (p.absTheta > THETA_TANGENCY) {
- p.tangency = true;
- }
-
- cur.theta = computeTheta(cur, 1, r);
- cur.absTheta = Math.abs(cur.theta);
-
- if (cur.absTheta > THETA_CORNER) {
- cur.breakPoint = true;
- }
- else if (cur.absTheta < THETA_TANGENCY) {
- cur.tangency = true;
- }
-
- i += count;
- }
- }
-
- }
-
- breakPoints.sort(function (a, b) {
- return a.index - b.index;
- });
-
- return breakPoints;
- }
-
-
-
- /**
- * 查找和标记拐点
- *
- * @param {Array} contour 轮廓
- * @param {Array} breakPoints 关键点
- * @param {number} r 查找范围
- * @return {Array} 关键点
- */
- function findBreakPoints(contour, breakPoints, r) {
-
- var j;
- var left;
- var right;
- var max;
- contour.forEach(function (p) {
- if (p.mark && !p.visited) {
- j = 0;
- left = p;
- right = p;
-
- max = p.absTheta;
- while (j++ < r) {
- left = left.prev;
- right = right.next;
-
- if (left.absTheta > max) {
- max = left.absTheta;
- }
-
- if (right.absTheta > max) {
- max = right.absTheta;
- }
- }
-
- if (max === p.absTheta) {
- p.breakPoint = true;
- breakPoints.push(p);
- markVisited(p, r);
- }
- }
- });
-
- return breakPoints;
- }
-
- function fixStartPoint(contour) {
-
- var i;
- var l;
-
- var minY = contour[0].y;
- var firstLine = [0];
- for (i = 1, l = contour.length; i < l; i++) {
- if (contour[i].y < minY) {
- minY = contour[i].y;
- firstLine = [i];
- }
- else if (contour[i].y === minY) {
- firstLine.push(i);
- }
- }
-
- var index = firstLine[0];
- var minX = contour[index].x;
- for (i = 1, l = firstLine.length; i < l; i++) {
- if (contour[firstLine[i]].x < minX) {
- minX = contour[firstLine[i]].x;
- index = firstLine[i];
- }
- }
-
- if (index !== 0) {
- return contour.slice(index).concat(contour.slice(0, index));
- }
-
- return contour;
- }
-
-
- /**
- * 查找轮廓中的关键点
- *
- * @param {Array} contour 轮廓点集合
- * @return {Array} 轮廓点集合
- */
- function getBreakPoints(contour) {
-
- //contour = fixStartPoint(contour);
-
- contour = makeLink(contour);
-
- var r = contour.length > 16 ? 10 : 4;
-
- var contourSize = contour.length;
- var breakPoints = [];
-
- if (contour.length > 60) {
- breakPoints = findVerticalAndHorizontalPoints(contour, breakPoints, r);
- }
-
-
- for (var i = 0, l = contourSize; i < l; i++) {
- p = contour[i];
- if (!p.visited) {
- p.theta = computeTheta(p, r, r);
- p.absTheta = Math.abs(p.theta);
-
- if (p.absTheta > THETA_CORNER) {
- p.mark = true;
- }
- else if (p.absTheta > THETA_TANGENCY) {
- p.markTangency = true;
- }
- }
- }
-
- // 非极大抑制查找角点
- breakPoints = findBreakPoints(contour, breakPoints, r);
-
- // 没有找到拐点,说明拐点不明显,或者为连续曲线,这里采用4等分
- if (breakPoints.length < 2) {
-
- if (contourSize < 100) {
- var step = Math.floor(contourSize / 2) + 1;
- }
- else {
- var step = Math.floor(contourSize / 4) + 1;
- }
- var startIndex = breakPoints[0] ? breakPoints[0].index : 0;
- for (var i = 0; i < contourSize; i += step) {
- breakPoints.push(contour[(startIndex + i) % contourSize]);
- }
- }
-
- breakPoints.sort(function (a, b) {
- return a.index - b.index;
- });
-
- return breakPoints;
- }
-
- return getBreakPoints;
- }
-);
diff --git a/src/ttf/svg2ttfobject.js b/src/ttf/svg2ttfobject.js
index fe21b25..63f9514 100644
--- a/src/ttf/svg2ttfobject.js
+++ b/src/ttf/svg2ttfobject.js
@@ -16,6 +16,7 @@ define(
var svgnode2contours = require('./svg/svgnode2contours');
var contoursTransform = require('./svg/contoursTransform');
var computeBoundingBox = require('graphics/computeBoundingBox');
+ var pathsUtil = require('graphics/pathsUtil');
var glyfAdjust = require('./util/glyfAdjust');
var error = require('./error');
var emptyttf = require('./data/empty');
@@ -282,21 +283,6 @@ define(
return ttf;
}
- function mirrorContours(contours) {
- // 这里为了使ai等工具里面的字形方便导入,对svg做了反向处理
- var bound = computeBoundingBox.computePathBox.apply(null, contours);
- contours = contoursTransform(contours, [
- {
- name: 'scale',
- params: [1, -1]
- },
- {
- name: 'translate',
- params: [1, bound.height]
- }
- ]);
- return contours;
- }
/**
* 解析字体信息相关节点
@@ -391,7 +377,8 @@ define(
// 对字形进行反转
for (i = 0, l = glyf.length; i < l; i++) {
- glyf[i].contours = mirrorContours(glyf[i].contours);
+ // 这里为了使ai等工具里面的字形方便导入,对svg做了反向处理
+ glyf[i].contours = pathsUtil.flip(glyf[i].contours);
}
}
diff --git a/unittest/lib/jasmine-2.2.0/jasmine.css b/unittest/lib/jasmine-2.2.0/jasmine.css
new file mode 100644
index 0000000..ecc5f5e
--- /dev/null
+++ b/unittest/lib/jasmine-2.2.0/jasmine.css
@@ -0,0 +1,62 @@
+body { overflow-y: scroll; }
+
+.jasmine_html-reporter { background-color: #eee; padding: 5px; margin: -8px; font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333; }
+.jasmine_html-reporter a { text-decoration: none; }
+.jasmine_html-reporter a:hover { text-decoration: underline; }
+.jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { margin: 0; line-height: 14px; }
+.jasmine_html-reporter .banner, .jasmine_html-reporter .symbol-summary, .jasmine_html-reporter .summary, .jasmine_html-reporter .result-message, .jasmine_html-reporter .spec .description, .jasmine_html-reporter .spec-detail .description, .jasmine_html-reporter .alert .bar, .jasmine_html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
+.jasmine_html-reporter .banner { position: relative; }
+.jasmine_html-reporter .banner .title { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==') no-repeat; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=') no-repeat, none; -moz-background-size: 100%; -o-background-size: 100%; -webkit-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; }
+.jasmine_html-reporter .banner .version { margin-left: 14px; position: relative; top: 6px; }
+.jasmine_html-reporter .banner .duration { position: absolute; right: 14px; top: 6px; }
+.jasmine_html-reporter #jasmine_content { position: fixed; right: 100%; }
+.jasmine_html-reporter .version { color: #aaa; }
+.jasmine_html-reporter .banner { margin-top: 14px; }
+.jasmine_html-reporter .duration { color: #aaa; float: right; }
+.jasmine_html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+.jasmine_html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; }
+.jasmine_html-reporter .symbol-summary li.passed { font-size: 14px; }
+.jasmine_html-reporter .symbol-summary li.passed:before { color: #007069; content: "\02022"; }
+.jasmine_html-reporter .symbol-summary li.failed { line-height: 9px; }
+.jasmine_html-reporter .symbol-summary li.failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; }
+.jasmine_html-reporter .symbol-summary li.disabled { font-size: 14px; }
+.jasmine_html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
+.jasmine_html-reporter .symbol-summary li.pending { line-height: 17px; }
+.jasmine_html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; }
+.jasmine_html-reporter .symbol-summary li.empty { font-size: 14px; }
+.jasmine_html-reporter .symbol-summary li.empty:before { color: #ba9d37; content: "\02022"; }
+.jasmine_html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+.jasmine_html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+.jasmine_html-reporter .bar.failed { background-color: #ca3a11; }
+.jasmine_html-reporter .bar.passed { background-color: #007069; }
+.jasmine_html-reporter .bar.skipped { background-color: #bababa; }
+.jasmine_html-reporter .bar.errored { background-color: #ca3a11; }
+.jasmine_html-reporter .bar.menu { background-color: #fff; color: #aaa; }
+.jasmine_html-reporter .bar.menu a { color: #333; }
+.jasmine_html-reporter .bar a { color: white; }
+.jasmine_html-reporter.spec-list .bar.menu.failure-list, .jasmine_html-reporter.spec-list .results .failures { display: none; }
+.jasmine_html-reporter.failure-list .bar.menu.spec-list, .jasmine_html-reporter.failure-list .summary { display: none; }
+.jasmine_html-reporter .running-alert { background-color: #666; }
+.jasmine_html-reporter .results { margin-top: 14px; }
+.jasmine_html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+.jasmine_html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+.jasmine_html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+.jasmine_html-reporter.showDetails .summary { display: none; }
+.jasmine_html-reporter.showDetails #details { display: block; }
+.jasmine_html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+.jasmine_html-reporter .summary { margin-top: 14px; }
+.jasmine_html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
+.jasmine_html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
+.jasmine_html-reporter .summary li.passed a { color: #007069; }
+.jasmine_html-reporter .summary li.failed a { color: #ca3a11; }
+.jasmine_html-reporter .summary li.empty a { color: #ba9d37; }
+.jasmine_html-reporter .summary li.pending a { color: #ba9d37; }
+.jasmine_html-reporter .description + .suite { margin-top: 0; }
+.jasmine_html-reporter .suite { margin-top: 14px; }
+.jasmine_html-reporter .suite a { color: #333; }
+.jasmine_html-reporter .failures .spec-detail { margin-bottom: 28px; }
+.jasmine_html-reporter .failures .spec-detail .description { background-color: #ca3a11; }
+.jasmine_html-reporter .failures .spec-detail .description a { color: white; }
+.jasmine_html-reporter .result-message { padding-top: 14px; color: #333; white-space: pre; }
+.jasmine_html-reporter .result-message span.result { display: block; }
+.jasmine_html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666; border: 1px solid #ddd; background: white; white-space: pre; }