fix the algorithms, and try to add a bigframe initially.
This commit is contained in:
parent
a4f79a3761
commit
f12842e5a4
80 changed files with 2233 additions and 437 deletions
|
@ -35,6 +35,7 @@
|
|||
- 20231029-30: hyphenating for english.
|
||||
- 20231105-06: 利用fontkit算文字的對應px寬度 initially pushed.
|
||||
- 20231109-10: Keng-kái oa̍h-chōa ián-sǹg-hoat.
|
||||
- 20231113: the algorithm is basically fixed, and make a `bigFrame` to prepare for convert to boxes and positions.
|
||||
|
||||
## 之後的做法
|
||||
- 先做一個前處理註冊器,註冊下列的前處理
|
||||
|
|
2
b.clo
2
b.clo
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
The book of the generation of Jesus Christ, the son of David,
|
||||
In the beginning was the Word, and the Word was with God, and the Word was God. The same was in the beginning with God.
|
|
@ -1 +1 @@
|
|||
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA42XW0/bMBSA/0ue0TYYsI230gZWoGnUZAMJocqkbuPVsaPEKa2m/fe5iZM6t+M8leZ8/hpfzvHh9a8l8F5YN1aA2A5ZZ1aMRCi/RnyVUZx+zh9/CkVEZWxL2Mq6uTizgpDQVYKZdfNaCXz54YkDxScJZllUKqpwXfb931nN8IzJJhT9iiLe7xhTfhpMmMDJGgXVPGS0MZer6/rgMY8iJCOgQ0GQ6o6z5mq0TBUDidYScqXA9RwUYReRBDC2YUjtTu4mPMgizLQFF4e40mlAw/Plx7fzq4vG3nkiwSj6xUiPrs6YjOtydXx+/POkXGcsEIQzfdIaWPdeX2rKOBPHd+hXKaCleNMk8hnetxMlfzwoUUJM4wlOg5NjhxKC3jWLIuq6r/rqxAmX256Oks2uazqFR4PAKVHyHuh5U86peD5oUhOS4Py3m6mrHFV8YOoGFKXp6RVaiXt+oQ+95fvOrFCjZRjM1UQmi0FRMpBndLmcOkv3pWtjlaZEgJ0N/mx3t5QH23TKFnijn7WWrsUavDkjC4ScHTNodRSwrvAaZVTky9Oody1tizV7Oy6VPm3PBVOzhoc4xOyOJ7Wzdkqb8sBrGFBOCszf+gnGRluBQcVJ+NzdA54CAAxpTIkYPzz+BiQVA3jEB19gkSUs9bmDPyhh0PQ6aLDYxChJcdIuNsXzYa0G32L2SPRruig2ylHF+4uNaOxacU+p8aJjr9oX1Hju+Lbjd51M5VEEcCCnM3e+gBQFYDTYttFh20aLZ5R4gMOZ+8sRNJcCMBqWvv1i1uQU4HIX83tAcgwDoz37fgbvrSJAx2w6nj/NHdCiGMBD8V7Pl5YjjwPjeSZkX2Pr2dJyVIzR8xMjs+gIGU0zslp1F/aaq8AAG4pjeji25Li7S1Q2HQOKn8JkAzDElmMm2zSKeWKUFdQwVzpMlppsDhej3pZY91WgyeiiAW+XQ4NMz0SE8hgMW8H2CNNveHgz5NQozGyLyJhTvQfu8ynQaIxlD+o8GX0FZrIN2WjDHhOm/kXyeV/Xo2wNEmo3ZNjnDx4gK5GOxuLtPxjWUt7DEAAA"
|
||||
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA52YXXObOBRA/4ufM9s223Z38+Y4JHEbYyZm28xkOh4Fy0a1kBghUrs7/e8rQIBAcMX0KQn36OgD6V6R5/9mEp/k7GoWIfaKZhezFMlY/ZnwXU5x9qZ8/EcsE6piR8J2s6vLi1kUE7oTmM2unhvBLWdyI88UtxLM8qRWNOGu7O9fF40hVD++YnKI5bCijY87FpS3jQmTWOxR1MxDRXtz+fCx23jBkwSpCOjQEKQqxtpbDcvUMJBor9YtUIJg46MEB4gIwGjDkDq4ub3hUZ5gZiy4PKeNzgB6nrf//PXuw6U1X4FR8i8jI7ou4zLu6w0T8uLXVrnPWSQJZ+akDbDr/fjeUKa5LMYwrtKApfhmSGIk9i/5z5/2Wakjk45LDYc4GxxQKzNAcGDqGT7ZoyofTxsSpukNzqLW8YoEQS+GRRNd3Z/ma0sFV/sxm4vD69C0Ko8BgVOi5CUyD3Q9p+r5pEndEIHLvvs5RTua+MScElGUZe0QrIzy7tJses1Pg8dVt1Zh6IBeq7NyDDgxd/+ApKHA3Kb2kWM0GoEst0LlFYemZiDP/R3Nh1OjlpQAuDb8hLOlxEk/17RLW8VdeWb+frv0t8HT0K7XrhoBtn30/fh6TXl0zJbsER/Mg2jpLNbhLRmV1tUaMYfWRAHrDu9RTmX5pnpVytJarNs7UPzGtCM1sLsGiEY5RRKXFwCyk/F975bQ5pd6LUaaAMVhrMk8P/1GR6oV0NeeUPWGvCSVZ1UQCTsAPVgs4I3PaYzZLRedlGUpTcxpC4+hwNhpqzCo+MqQB9BSVgBgyNIiQ4S8THhpNy1aNhsGzZTIxafPX0ChZgCP/MEfscwFUx37+AclDFq4AXpCNXzzUszoQcHZWGHctsikGnld43N64ILI2Eiq3Xpnmu1WdiU0h58ikWFhj7l6PmmgIT9i9pmY9/OqmGtHEx8v5rK3nauiodvLgU1sV4zF2g89PxxKbtqjCSCnLVfB+hFSVIDT4HlOh+c5LRunZAM4/HW4nUNzqQCnYRt6T25NSQGu4HF9B0iKMNB6492t4HerCdCxWi7WD2sftGgG8FB8Ms+L5SjjQHueS/VB45mnxXI0jNNzj5FbVEBO04rsdsN3g46rwgAbSlN6Lr7F8XAl0DYTA3K3xtRNdIqtxFy2ZZJy4ZRV1DRXNk2WuWw+l/PRb2HT14AuY4AmjK6EJpm+qnqitsG0FbRbuPrY4MOUXaMxty0hC07Nb8wxnwadxuL24j84fRXmsk150Y53TJj+30jIx66D2tYjoduSCof80waQ1Qh4L0p3+xViJC3v4QP3CzPcq+2/vv0PRTFWxwIVAAA="
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
293
docs/classes/libclo_breakLines.BreakLineAlgorithm.html
Normal file
293
docs/classes/libclo_breakLines.BreakLineAlgorithm.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
58
docs/functions/harfbuzz.harfbuzzTest.html
Normal file
58
docs/functions/harfbuzz.harfbuzzTest.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
63
docs/functions/libclo.calculateTextWidthHeight.html
Normal file
63
docs/functions/libclo.calculateTextWidthHeight.html
Normal file
File diff suppressed because one or more lines are too long
63
docs/functions/libclo.calculateTextWidthHeightAux.html
Normal file
63
docs/functions/libclo.calculateTextWidthHeightAux.html
Normal file
File diff suppressed because one or more lines are too long
69
docs/functions/libclo.filterEmptyString.html
Normal file
69
docs/functions/libclo.filterEmptyString.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
71
docs/functions/libclo.spacesToBreakpoint.html
Normal file
71
docs/functions/libclo.spacesToBreakpoint.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
80
docs/interfaces/libclo.BreakPoint.html
Normal file
80
docs/interfaces/libclo.BreakPoint.html
Normal file
File diff suppressed because one or more lines are too long
164
docs/interfaces/libclo.CharBox.html
Normal file
164
docs/interfaces/libclo.CharBox.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
80
docs/interfaces/libclo.HGlue.html
Normal file
80
docs/interfaces/libclo.HGlue.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
54
docs/modules/harfbuzz.html
Normal file
54
docs/modules/harfbuzz.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
54
docs/modules/libclo_breakLines.html
Normal file
54
docs/modules/libclo_breakLines.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
45
docs/modules/pdfManipulate.html
Normal file
45
docs/modules/pdfManipulate.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
49
docs/types/libclo.BoxesItem.html
Normal file
49
docs/types/libclo.BoxesItem.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,95 +1,149 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.totalCost = void 0;
|
||||
exports.BreakLineAlgorithm = void 0;
|
||||
/**
|
||||
* Algorithms in LATEX language
|
||||
TotalCost(i) = min_{j}~TotalCost(j) + LineCost(j, i)~~~~j=0, 1, ..., i-1
|
||||
|
||||
LineCost(j, i)= \begin{cases}
|
||||
\infty ~~~ if~~LineWidth - \sum_{k=j+1}^{i-1} OrigWidth(item[k]) - newLineWidth(item[i]) < 0 \\
|
||||
\infty~~if~~NOT~~breakable(item[i]) \\
|
||||
(LineWidth - \sum_{k=j+1}^{i-1} OrigWidth(item[k]) - newLineWidth(item[i]))^3 ~~elsewhere
|
||||
\end{cases} */
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
function isBreakPoint(item) {
|
||||
return item.newLined !== undefined;
|
||||
}
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
function isHGlue(item) {
|
||||
return item.stretchFactor !== undefined;
|
||||
}
|
||||
/** measuring original advance width */
|
||||
function origWidth(item) {
|
||||
if (isBreakPoint(item)) {
|
||||
console.log(item);
|
||||
return origWidth(item.original);
|
||||
}
|
||||
else if (Array.isArray(item)) {
|
||||
return item.map((x) => origWidth(x))
|
||||
.reduce((acc, current) => acc + current, 0.0);
|
||||
}
|
||||
else if (isHGlue(item)) {
|
||||
return 0.0;
|
||||
}
|
||||
else {
|
||||
return item.width;
|
||||
}
|
||||
}
|
||||
/** measuring new-line triggered advance width */
|
||||
function newLineWidth(item) {
|
||||
if (isBreakPoint(item)) {
|
||||
return origWidth(item.newLined);
|
||||
}
|
||||
else {
|
||||
// impossible to make a new line
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
let lineCostStorage = new Object();
|
||||
/**
|
||||
* check the total cost item[0..j].
|
||||
* @param items
|
||||
* @param i
|
||||
* @param lineWidth
|
||||
* Algorithms in LATEX-like language
|
||||
*/
|
||||
function totalCost(items, j, lineWidth) {
|
||||
if (j in lineCostStorage) {
|
||||
return lineCostStorage[j];
|
||||
class BreakLineAlgorithm {
|
||||
constructor() {
|
||||
this.prevNodes = [];
|
||||
this.totalCostAuxStorage = [];
|
||||
this.lineCostStorage = [[]];
|
||||
}
|
||||
var returnCost = Infinity;
|
||||
for (var i = -1; i <= j; i++) {
|
||||
// lineCost
|
||||
let lCost = lineCost(items, i, j, lineWidth);
|
||||
if (returnCost > lCost) {
|
||||
returnCost = lCost;
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
isBreakPoint(item) {
|
||||
return item.newLined !== undefined;
|
||||
}
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
isHGlue(item) {
|
||||
return item.stretchFactor !== undefined;
|
||||
}
|
||||
/** measuring original advance width */
|
||||
origWidth(item) {
|
||||
if (this.isBreakPoint(item)) {
|
||||
return this.origWidth(item.original);
|
||||
}
|
||||
else if (Array.isArray(item)) {
|
||||
return item.map((x) => this.origWidth(x))
|
||||
.reduce((acc, current) => acc + current, 0.0);
|
||||
}
|
||||
else if (this.isHGlue(item)) {
|
||||
return 0.0;
|
||||
}
|
||||
else {
|
||||
return item.width;
|
||||
}
|
||||
}
|
||||
lineCostStorage[j] = returnCost;
|
||||
return returnCost;
|
||||
}
|
||||
exports.totalCost = totalCost;
|
||||
/**
|
||||
* check the line cost of a line containing items[i+1..j]
|
||||
* @param items items of box
|
||||
* @param i beginning (excluded)
|
||||
* @param j end of the line
|
||||
* @param lineWidth line width
|
||||
*/
|
||||
function lineCost(items, i, j, lineWidth) {
|
||||
if (!isBreakPoint(items[j])) {
|
||||
return Infinity;
|
||||
}
|
||||
else {
|
||||
var tmpItemWidth = 0;
|
||||
for (var k = i + 1; k < j; k++) {
|
||||
tmpItemWidth += origWidth(items[k]);
|
||||
segmentedNodes(items, lineWidth) {
|
||||
this.totalCost(items, lineWidth);
|
||||
let nodeList = this.generateBreakLineNodeList();
|
||||
console.log("~~~", nodeList);
|
||||
let res = [];
|
||||
let low = -1;
|
||||
let up = nodeList[0];
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
res.push(items.slice(low + 1, up + 1));
|
||||
low = nodeList[i];
|
||||
up = nodeList[i + 1];
|
||||
}
|
||||
tmpItemWidth += newLineWidth(items[j]);
|
||||
if (tmpItemWidth > lineWidth) {
|
||||
return res;
|
||||
}
|
||||
/**genrate the list of point of breaking line. it returns a correct list ascending*/
|
||||
generateBreakLineNodeList() {
|
||||
let res = [];
|
||||
var pointer = this.prevNodes.length - 1;
|
||||
while (this.prevNodes[pointer] !== undefined) {
|
||||
res.push(pointer);
|
||||
pointer = this.prevNodes[pointer];
|
||||
}
|
||||
return res.reverse();
|
||||
}
|
||||
/** measuring new-line triggered advance width */
|
||||
newLineWidth(item) {
|
||||
if (this.isBreakPoint(item)) {
|
||||
return this.origWidth(item.newLined);
|
||||
}
|
||||
else {
|
||||
// impossible to make a new line
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* check all the total cost of paragraphes of the segnemt
|
||||
*/
|
||||
totalCost(items, lineWidth) {
|
||||
let itemsLength = items.length;
|
||||
this.lineCostStorage = Array(itemsLength);
|
||||
this.prevNodes = Array(itemsLength).fill(null);
|
||||
for (var i = 0; i < itemsLength; i++) {
|
||||
this.lineCostStorage[i] = Array(itemsLength).fill(undefined);
|
||||
}
|
||||
this.totalCostAuxStorage = Array(itemsLength).fill(undefined);
|
||||
console.log("===", itemsLength);
|
||||
let a = this.totalCostAux(items, itemsLength - 1, lineWidth);
|
||||
console.log(this.lineCostStorage);
|
||||
return a;
|
||||
}
|
||||
/**
|
||||
* check the total cost item[0..j].
|
||||
* @param items
|
||||
* @param i
|
||||
* @param lineWidth
|
||||
*/
|
||||
totalCostAux(items, j, lineWidth) {
|
||||
if (this.totalCostAuxStorage[j] !== undefined) {
|
||||
return this.totalCostAuxStorage[j];
|
||||
}
|
||||
let rawLineCost = this.lineCost(items, 0, j, lineWidth);
|
||||
if (rawLineCost != Infinity) {
|
||||
this.totalCostAuxStorage[j] = rawLineCost;
|
||||
return rawLineCost;
|
||||
}
|
||||
else {
|
||||
var returnCost = Infinity;
|
||||
for (var k = 0; k < j; k++) {
|
||||
let tmp = this.totalCostAux(items, k, lineWidth) + this.lineCost(items, k + 1, j, lineWidth);
|
||||
if (returnCost > tmp) {
|
||||
this.prevNodes[j] = k;
|
||||
returnCost = tmp;
|
||||
}
|
||||
}
|
||||
this.totalCostAuxStorage[j] = returnCost;
|
||||
return returnCost;
|
||||
}
|
||||
return returnCost;
|
||||
}
|
||||
/**
|
||||
* check the line cost of a line containing items[i..j]
|
||||
* @param items items of box
|
||||
* @param i beginning (excluded)
|
||||
* @param j end of the line
|
||||
* @param lineWidth line width
|
||||
*/
|
||||
lineCost(items, i, j, lineWidth) {
|
||||
if (this.lineCostStorage[i] !== undefined && this.lineCostStorage[i][j] !== undefined) {
|
||||
return this.lineCostStorage[i][j];
|
||||
}
|
||||
if (!this.isBreakPoint(items[j])) {
|
||||
this.lineCostStorage[i][j] = Infinity;
|
||||
return Infinity;
|
||||
}
|
||||
else {
|
||||
return (lineWidth - tmpItemWidth) ** 3.0;
|
||||
var tmpItemWidth = 0;
|
||||
for (var k = i; k < j; k++) {
|
||||
tmpItemWidth += this.origWidth(items[k]);
|
||||
}
|
||||
tmpItemWidth += this.newLineWidth(items[j]);
|
||||
if (tmpItemWidth > lineWidth) {
|
||||
this.lineCostStorage[i][j] = Infinity;
|
||||
return Infinity;
|
||||
}
|
||||
else {
|
||||
let returnValue = (lineWidth - tmpItemWidth) ** 3.0;
|
||||
this.lineCostStorage[i][j] = returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BreakLineAlgorithm = BreakLineAlgorithm;
|
||||
|
|
|
@ -3,107 +3,182 @@
|
|||
*/
|
||||
import { join } from "path";
|
||||
import {BreakPoint, BoxesItem, HGlue} from "./index.js";
|
||||
import { listenerCount } from "process";
|
||||
import { unwatchFile } from "fs";
|
||||
/**
|
||||
* Algorithms in LATEX language
|
||||
TotalCost(i) = min_{j}~TotalCost(j) + LineCost(j, i)~~~~j=0, 1, ..., i-1
|
||||
|
||||
LineCost(j, i)= \begin{cases}
|
||||
\infty ~~~ if~~LineWidth - \sum_{k=j+1}^{i-1} OrigWidth(item[k]) - newLineWidth(item[i]) < 0 \\
|
||||
\infty~~if~~NOT~~breakable(item[i]) \\
|
||||
(LineWidth - \sum_{k=j+1}^{i-1} OrigWidth(item[k]) - newLineWidth(item[i]))^3 ~~elsewhere
|
||||
\end{cases} */
|
||||
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
function isBreakPoint (item : any) : item is BreakPoint{
|
||||
return (item as BreakPoint).newLined !== undefined;
|
||||
}
|
||||
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
function isHGlue (item : any) : item is HGlue{
|
||||
return (item as HGlue).stretchFactor !== undefined;
|
||||
}
|
||||
|
||||
|
||||
/** measuring original advance width */
|
||||
function origWidth(item : BoxesItem) : number{
|
||||
if (isBreakPoint(item)){
|
||||
console.log(item);
|
||||
return origWidth(item.original);
|
||||
}else if(Array.isArray(item)){
|
||||
return item.map((x)=>origWidth(x))
|
||||
.reduce((acc, current) => acc + current,
|
||||
0.0,)
|
||||
}else if(isHGlue(item)){
|
||||
return 0.0;
|
||||
}
|
||||
else{
|
||||
return item.width;
|
||||
}
|
||||
}
|
||||
|
||||
/** measuring new-line triggered advance width */
|
||||
function newLineWidth(item : BoxesItem) : number{
|
||||
if (isBreakPoint(item)){
|
||||
return origWidth(item.newLined);
|
||||
}else{
|
||||
// impossible to make a new line
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
|
||||
let lineCostStorage : any = new Object();
|
||||
|
||||
/**
|
||||
* check the total cost item[0..j].
|
||||
* @param items
|
||||
* @param i
|
||||
* @param lineWidth
|
||||
* Algorithms in LATEX-like language
|
||||
*/
|
||||
export function totalCost(items : BoxesItem[], j : number, lineWidth: number){
|
||||
if (j in lineCostStorage){
|
||||
return lineCostStorage[j];
|
||||
}
|
||||
var returnCost = Infinity;
|
||||
|
||||
export class BreakLineAlgorithm {
|
||||
|
||||
lineCostStorage : number[][];
|
||||
totalCostAuxStorage : number[];
|
||||
prevNodes : number[];
|
||||
|
||||
for(var i=-1; i<=j; i++){
|
||||
// lineCost
|
||||
let lCost = lineCost(items, i, j, lineWidth);
|
||||
|
||||
if (returnCost > lCost){
|
||||
returnCost = lCost;
|
||||
|
||||
constructor(){
|
||||
this.prevNodes = [];
|
||||
this.totalCostAuxStorage = [];
|
||||
this.lineCostStorage = [[]];
|
||||
}
|
||||
|
||||
/**check if a boeitem is BreakPoint Type */
|
||||
isBreakPoint (item : any) : item is BreakPoint{
|
||||
return (item as BreakPoint).newLined !== undefined;
|
||||
}
|
||||
|
||||
/**check if a boeitem is HGlue Type */
|
||||
isHGlue (item : any) : item is HGlue{
|
||||
return (item as HGlue).stretchFactor !== undefined;
|
||||
}
|
||||
|
||||
|
||||
/** measuring original advance width */
|
||||
origWidth(item : BoxesItem) : number{
|
||||
if (this.isBreakPoint(item)){
|
||||
return this.origWidth(item.original);
|
||||
}else if(Array.isArray(item)){
|
||||
return item.map((x)=>this.origWidth(x))
|
||||
.reduce((acc, current) => acc + current,
|
||||
0.0,)
|
||||
}else if(this.isHGlue(item)){
|
||||
return 0.0;
|
||||
}
|
||||
else{
|
||||
return item.width;
|
||||
}
|
||||
}
|
||||
|
||||
lineCostStorage[j] = returnCost;
|
||||
return returnCost;
|
||||
segmentedNodes(items : BoxesItem[], lineWidth : number) : BoxesItem[][]{
|
||||
this.totalCost(items ,lineWidth);
|
||||
let nodeList = this.generateBreakLineNodeList();
|
||||
console.log("~~~", nodeList);
|
||||
let res = [];
|
||||
let low = -1;
|
||||
let up = nodeList[0];
|
||||
|
||||
}
|
||||
for(var i=0; i<nodeList.length; i++){
|
||||
res.push(items.slice(low+1, up+1));
|
||||
low = nodeList[i];
|
||||
up = nodeList[i+1];
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**genrate the list of point of breaking line. it returns a correct list ascending*/
|
||||
generateBreakLineNodeList() : number[]{
|
||||
let res : number[] = [];
|
||||
var pointer = this.prevNodes.length-1;
|
||||
while (this.prevNodes[pointer] !== undefined){
|
||||
res.push(pointer);
|
||||
pointer = this.prevNodes[pointer];
|
||||
}
|
||||
return res.reverse();
|
||||
}
|
||||
|
||||
/** measuring new-line triggered advance width */
|
||||
newLineWidth(item : BoxesItem) : number{
|
||||
if (this.isBreakPoint(item)){
|
||||
return this.origWidth(item.newLined);
|
||||
}else{
|
||||
// impossible to make a new line
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* check all the total cost of paragraphes of the segnemt
|
||||
*/
|
||||
totalCost(items : BoxesItem[], lineWidth: number) : number{
|
||||
|
||||
let itemsLength = items.length;
|
||||
this.lineCostStorage = Array(itemsLength);
|
||||
this.prevNodes = Array(itemsLength).fill(null);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* check the line cost of a line containing items[i+1..j]
|
||||
* @param items items of box
|
||||
* @param i beginning (excluded)
|
||||
* @param j end of the line
|
||||
* @param lineWidth line width
|
||||
*/
|
||||
function lineCost(items : BoxesItem[], i : number, j : number, lineWidth: number){
|
||||
if (!isBreakPoint(items[j])){
|
||||
return Infinity;
|
||||
}else{
|
||||
var tmpItemWidth = 0;
|
||||
for (var k = i+1; k<j; k++){
|
||||
tmpItemWidth += origWidth(items[k]);
|
||||
for (var i=0; i<itemsLength; i++){
|
||||
this.lineCostStorage[i] = Array(itemsLength).fill(undefined);
|
||||
}
|
||||
|
||||
tmpItemWidth += newLineWidth(items[j]);
|
||||
this.totalCostAuxStorage = Array(itemsLength).fill(undefined);
|
||||
console.log("===", itemsLength);
|
||||
let a = this.totalCostAux(items, itemsLength-1, lineWidth);
|
||||
console.log(this.lineCostStorage);
|
||||
return a;
|
||||
|
||||
if (tmpItemWidth > lineWidth){
|
||||
}
|
||||
|
||||
/**
|
||||
* check the total cost item[0..j].
|
||||
* @param items
|
||||
* @param i
|
||||
* @param lineWidth
|
||||
*/
|
||||
totalCostAux(items : BoxesItem[], j : number, lineWidth: number): number{
|
||||
|
||||
if (this.totalCostAuxStorage[j] !== undefined){
|
||||
return this.totalCostAuxStorage[j];
|
||||
}
|
||||
|
||||
let rawLineCost = this.lineCost(items, 0, j, lineWidth);
|
||||
if (rawLineCost != Infinity){
|
||||
this.totalCostAuxStorage[j] = rawLineCost;
|
||||
return rawLineCost;
|
||||
}else{
|
||||
var returnCost = Infinity;
|
||||
for(var k=0; k<j; k++){
|
||||
let tmp = this.totalCostAux(items, k, lineWidth) + this.lineCost(items, k+1,j, lineWidth);
|
||||
if (returnCost > tmp){
|
||||
this.prevNodes[j] = k;
|
||||
returnCost = tmp;
|
||||
}
|
||||
}
|
||||
this.totalCostAuxStorage[j] = returnCost;
|
||||
return returnCost;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return returnCost;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* check the line cost of a line containing items[i..j]
|
||||
* @param items items of box
|
||||
* @param i beginning (excluded)
|
||||
* @param j end of the line
|
||||
* @param lineWidth line width
|
||||
*/
|
||||
lineCost(items : BoxesItem[], i : number, j : number, lineWidth: number) : number{
|
||||
if (this.lineCostStorage[i] !== undefined && this.lineCostStorage[i][j] !== undefined){
|
||||
return this.lineCostStorage[i][j];
|
||||
}
|
||||
|
||||
if (!this.isBreakPoint(items[j])){
|
||||
this.lineCostStorage[i][j] = Infinity;
|
||||
return Infinity;
|
||||
}else{
|
||||
return (lineWidth - tmpItemWidth)**3.0;
|
||||
var tmpItemWidth = 0;
|
||||
for (var k = i; k<j; k++){
|
||||
tmpItemWidth += this.origWidth(items[k]);
|
||||
}
|
||||
|
||||
tmpItemWidth += this.newLineWidth(items[j]);
|
||||
|
||||
if (tmpItemWidth > lineWidth){
|
||||
this.lineCostStorage[i][j] = Infinity;
|
||||
return Infinity;
|
||||
}else{
|
||||
let returnValue = (lineWidth - tmpItemWidth)**3.0;
|
||||
this.lineCostStorage[i][j] = returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
exports.Clo = exports.calculateTextWidthHeightAux = exports.calculateTextWidthHeight = exports.hyphenTkTree = exports.filterEmptyString = exports.spacesToBreakpoint = exports.hyphenForClo = exports.splitCJKV = exports.twoReturnsToNewline = exports.ptToPx = exports.cjkvRegexPattern = exports.cjkvBlocksInRegex = exports.defaultFrameStyle = exports.defaultTextStyle = exports.A4_IN_PX = exports.Direction = void 0;
|
||||
const canva_1 = require("../canva");
|
||||
const fontkit = __importStar(require("fontkit"));
|
||||
const util = __importStar(require("node:util"));
|
||||
const breakLines = __importStar(require("./breakLines"));
|
||||
/**
|
||||
* TYPES
|
||||
|
@ -360,11 +359,127 @@ class Clo {
|
|||
// generate the width and height of the stream
|
||||
let defaultFontStyle = this.attrs["defaultFrameStyle"].textStyle;
|
||||
let a = yield calculateTextWidthHeight(preprocessed, defaultFontStyle);
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
// TODO
|
||||
console.log(util.inspect(a, true, 100));
|
||||
console.log(breakLines.totalCost(a, 3, 100));
|
||||
//console.log(breakLineAlgorithms.totalCost(a,70));
|
||||
let segmentedNodes = breakLineAlgorithms.segmentedNodes(a, 70);
|
||||
console.log(this.segmentedNodesToFrameBox(segmentedNodes, this.attrs["defaultFrameStyle"]));
|
||||
});
|
||||
}
|
||||
segmentedNodesToFrameBox(segmentedNodes, frame) {
|
||||
let baseLineskip = frame.baseLineskip;
|
||||
let boxArrayEmpty = [];
|
||||
let bigBox = {
|
||||
x: frame.x,
|
||||
y: frame.y,
|
||||
textStyle: frame.textStyle,
|
||||
direction: frame.direction,
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
content: boxArrayEmpty,
|
||||
};
|
||||
var bigBoxContent = boxArrayEmpty;
|
||||
let segmentedNodesFixed = segmentedNodes.map((x) => this.removeBreakPoints(x).flat());
|
||||
let segmentedNodeUnglue = segmentedNodesFixed.map((x) => this.removeGlue(x, frame).flat());
|
||||
for (var i = 0; i < segmentedNodesFixed.length - 1; i++) {
|
||||
var currentLineSkip = baseLineskip;
|
||||
var glyphMaxHeight = this.getGlyphMaxHeight(segmentedNodesFixed[i]);
|
||||
if (currentLineSkip === null || glyphMaxHeight > currentLineSkip) {
|
||||
currentLineSkip = glyphMaxHeight;
|
||||
}
|
||||
var currentLineBox = {
|
||||
x: null,
|
||||
y: null,
|
||||
textStyle: exports.defaultTextStyle,
|
||||
direction: frame.directionInsideLine,
|
||||
width: frame.width,
|
||||
height: currentLineSkip,
|
||||
content: segmentedNodeUnglue[i],
|
||||
};
|
||||
bigBoxContent.push(currentLineBox);
|
||||
}
|
||||
bigBox.content = bigBoxContent;
|
||||
return bigBox;
|
||||
}
|
||||
/**
|
||||
* get the max height of the glyph`[a, b, c]`
|
||||
* @param nodeLine the node line [a, b, c, ...]
|
||||
* @returns
|
||||
*/
|
||||
getGlyphMaxHeight(nodeLine) {
|
||||
let segmentedNodeLineHeight = nodeLine.map((x) => { if ("height" in x && x.height > 0.0) {
|
||||
return x.height;
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
} });
|
||||
let maxHeight = Math.max(...segmentedNodeLineHeight);
|
||||
return maxHeight;
|
||||
}
|
||||
removeGlue(nodeLine, frame) {
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
let glueRemoved = nodeLine.filter((x) => !breakLineAlgorithms.isHGlue(x));
|
||||
let onlyGlue = nodeLine.filter((x) => breakLineAlgorithms.isHGlue(x));
|
||||
let sumStretchFactor = onlyGlue.map((x) => { if ("stretchFactor" in x) {
|
||||
return x.stretchFactor;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
} })
|
||||
.reduce((acc, cur) => acc + cur, 0);
|
||||
let glueRemovedWidth = glueRemoved.map((x) => { if ("width" in x) {
|
||||
return x.width;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
} })
|
||||
.reduce((acc, cur) => acc + cur, 0);
|
||||
let offset = frame.width - glueRemovedWidth;
|
||||
var res = [];
|
||||
for (var i = 0; i < nodeLine.length; i++) {
|
||||
var ele = nodeLine[i];
|
||||
if (breakLineAlgorithms.isHGlue(ele)) {
|
||||
let tmp = {
|
||||
x: null,
|
||||
y: null,
|
||||
textStyle: null,
|
||||
direction: frame.directionInsideLine,
|
||||
width: ele.stretchFactor / sumStretchFactor * offset,
|
||||
height: 0,
|
||||
content: "",
|
||||
};
|
||||
res.push(tmp);
|
||||
}
|
||||
else {
|
||||
res.push(ele);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* remove breakpoints
|
||||
* @param boxitemline boxitem in a line with a breakpoint
|
||||
* @returns boxitemline with break points removed
|
||||
*/
|
||||
removeBreakPoints(boxitemline) {
|
||||
var res = [];
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
for (var i = 0; i < boxitemline.length; i++) {
|
||||
let ele = boxitemline[i];
|
||||
if (breakLineAlgorithms.isBreakPoint(ele)) {
|
||||
if (i == boxitemline.length - 1) {
|
||||
res.push(ele.newLined);
|
||||
}
|
||||
else {
|
||||
res.push(ele.original);
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.push(ele);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
exports.Clo = Clo;
|
||||
/*
|
||||
|
|
|
@ -438,14 +438,133 @@ export class Clo{
|
|||
let defaultFontStyle : TextStyle = this.attrs["defaultFrameStyle"].textStyle;
|
||||
let a = await calculateTextWidthHeight(preprocessed, defaultFontStyle);
|
||||
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
// TODO
|
||||
console.log(util.inspect(a, true, 100));
|
||||
console.log(breakLines.totalCost(a,3,100));
|
||||
//console.log(breakLineAlgorithms.totalCost(a,70));
|
||||
let segmentedNodes = breakLineAlgorithms.segmentedNodes(a, 70);
|
||||
|
||||
console.log(this.segmentedNodesToFrameBox(segmentedNodes, <FrameBox>this.attrs["defaultFrameStyle"]));
|
||||
}
|
||||
|
||||
segmentedNodesToFrameBox(segmentedNodes : BoxesItem[][], frame : FrameBox) : Box{
|
||||
let baseLineskip = frame.baseLineskip;
|
||||
let boxArrayEmpty : Box[] = [];
|
||||
let bigBox : Box = {
|
||||
x : frame.x,
|
||||
y : frame.y,
|
||||
textStyle : frame.textStyle,
|
||||
direction : frame.direction,
|
||||
width : frame.width,
|
||||
height : frame.height,
|
||||
content : boxArrayEmpty,
|
||||
}
|
||||
|
||||
var bigBoxContent : Box[] = boxArrayEmpty;
|
||||
|
||||
let segmentedNodesFixed = segmentedNodes.map((x)=>this.removeBreakPoints
|
||||
(x).flat());
|
||||
let segmentedNodeUnglue = segmentedNodesFixed.map((x)=>this.removeGlue(x, frame).flat());
|
||||
|
||||
for (var i=0; i<segmentedNodesFixed.length-1; i++){
|
||||
var currentLineSkip = baseLineskip;
|
||||
var glyphMaxHeight = this.getGlyphMaxHeight(segmentedNodesFixed[i]);
|
||||
if (currentLineSkip === null || glyphMaxHeight >currentLineSkip ){
|
||||
currentLineSkip = glyphMaxHeight;
|
||||
}
|
||||
|
||||
var currentLineBox : Box = {
|
||||
x : null,
|
||||
y : null,
|
||||
textStyle : defaultTextStyle,
|
||||
direction : frame.directionInsideLine,
|
||||
width : frame.width,
|
||||
height : currentLineSkip,
|
||||
content : <Box[]>segmentedNodeUnglue[i],
|
||||
}
|
||||
|
||||
bigBoxContent.push(currentLineBox);
|
||||
|
||||
}
|
||||
|
||||
bigBox.content = bigBoxContent;
|
||||
|
||||
return bigBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the max height of the glyph`[a, b, c]`
|
||||
* @param nodeLine the node line [a, b, c, ...]
|
||||
* @returns
|
||||
*/
|
||||
getGlyphMaxHeight(nodeLine : BoxesItem[]) : number{
|
||||
let segmentedNodeLineHeight = nodeLine.map((x : BoxesItem)=>{if ("height" in x && x.height > 0.0){return x.height}else{return 0.0}});
|
||||
let maxHeight = Math.max(...segmentedNodeLineHeight);
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
removeGlue(nodeLine : BoxesItem[], frame : FrameBox) : BoxesItem[]{
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
let glueRemoved = nodeLine.filter((x)=>!breakLineAlgorithms.isHGlue(x));
|
||||
let onlyGlue = nodeLine.filter((x)=>breakLineAlgorithms.isHGlue(x));
|
||||
let sumStretchFactor = onlyGlue.map((x)=>{if("stretchFactor" in x){ return x.stretchFactor} else{return 0;}})
|
||||
.reduce((acc, cur)=>acc+cur , 0);
|
||||
|
||||
let glueRemovedWidth = glueRemoved.map((x)=>{if("width" in x){ return x.width} else{return 0;}})
|
||||
.reduce((acc, cur)=>acc+cur , 0);
|
||||
let offset = frame.width - glueRemovedWidth;
|
||||
var res = [];
|
||||
for (var i=0; i<nodeLine.length; i++){
|
||||
var ele = nodeLine[i];
|
||||
if (breakLineAlgorithms.isHGlue(ele)){
|
||||
let tmp : Box = {
|
||||
x : null,
|
||||
y : null,
|
||||
textStyle : null,
|
||||
direction : frame.directionInsideLine,
|
||||
width : ele.stretchFactor / sumStretchFactor * offset,
|
||||
height : 0,
|
||||
content : "",
|
||||
|
||||
}
|
||||
|
||||
res.push(tmp);
|
||||
}else{
|
||||
res.push(ele);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove breakpoints
|
||||
* @param boxitemline boxitem in a line with a breakpoint
|
||||
* @returns boxitemline with break points removed
|
||||
*/
|
||||
removeBreakPoints(boxitemline : BoxesItem[]) : BoxesItem[]{
|
||||
var res : BoxesItem[] = [];
|
||||
let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
|
||||
|
||||
for (var i = 0; i<boxitemline.length; i++){
|
||||
let ele = boxitemline[i];
|
||||
if (breakLineAlgorithms.isBreakPoint(ele)){
|
||||
if (i == boxitemline.length-1){
|
||||
res.push(ele.newLined);
|
||||
}else{
|
||||
res.push(ele.original);
|
||||
}
|
||||
}else{
|
||||
res.push(ele);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
export let a = new Clo();
|
||||
export default a; */
|
Loading…
Reference in a new issue