From 567d2d741b87bcad8c25aa932fef2d8ac9ec0b18 Mon Sep 17 00:00:00 2001 From: Semion Chichelnitsky Date: Tue, 12 May 2015 10:47:06 +0300 Subject: [PATCH 1/2] Add bidi levels attribute, update decor dependency to 0.6.x --- README.md | 2 +- TextLayoutEngine.js | 93 ++++++--------- bower.json | 4 +- docs/TextLayoutEngine.md | 6 +- package.json | 2 +- tests/TextLayoutEngineMapsTest.js | 10 +- tests/testBidiEngine.html | 182 ++++++++++++++++++++++++++++++ 7 files changed, 235 insertions(+), 64 deletions(-) create mode 100644 tests/testBidiEngine.html diff --git a/README.md b/README.md index 320d81a..ad91bcd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project provides bidi utilities for JavaScript/AMD/Dojo Applications ## Status -The most recent pre-release is 0.2.0. +The most recent pre-release is 0.3.0. ## Migration diff --git a/TextLayoutEngine.js b/TextLayoutEngine.js index 428b151..84a44e7 100644 --- a/TextLayoutEngine.js +++ b/TextLayoutEngine.js @@ -51,6 +51,9 @@ define([ // Array, containing positions of each character from the resulting text in the source text. targetToSource: [], + + // Array, containing bidi level of each character from the source text + levels: [], bidiTransform: function (/*String*/text, /*String*/formatIn, /*String*/formatOut) { // summary: @@ -152,7 +155,10 @@ define([ if (!this.checkParameters(formatIn, formatOut)) { return text; } - + + formatIn = this.inputFormat; + formatOut = this.outputFormat; + var result = text; var bdx = BDX; var orientIn = getOrientation(formatIn.charAt(1)), orientOut = getOrientation(formatOut.charAt(1)), @@ -180,14 +186,16 @@ define([ tsMap = this.targetToSource; if (formatIn.charAt(3) === formatOut.charAt(3)) { - return stage1Text; + result = stage1Text; } else if (formatOut.charAt(3) === "S") { - return shape(isRtl, stage1Text, true); + result = shape(isRtl, stage1Text, true); } else { //formatOut.charAt(3) === "N" - return deshape(stage1Text, isRtl, true); + result = deshape(stage1Text, isRtl, true); } this.sourceToTarget = stMap; this.targetToSource = tsMap; + this.levels = lvMap; + return result; }, _setInputFormatAttr: function (format) { @@ -272,30 +280,16 @@ define([ // text: // The source string. // description: - // Iterates over the text string, letter by letter starting from its beginning, - // searching for RTL directed character. - // Return true if found else false. Needed for vml transformation. + // Searches for RTL directed character. + // Returns true if found, else returns false. // returns: /*Boolean*/ // true - if text has a RTL directed character. // false - otherwise. // tags: // public - var type = null, uc = null, hi = null; - for (var i = 0; i < text.length; i++) { - uc = text.charAt(i).charCodeAt(0); - hi = MasterTable[uc >> 8]; - type = hi < TBBASE ? hi : UnicodeTable[hi - TBBASE][uc & 0xFF]; - if (type === UBAT_R || type === UBAT_AL) { - return true; - } - if (type === UBAT_B) { - break; - } - } - return false; + return bidiChars.test(text); } - }); function doBidiReorder(/*String*/text, /*String*/inFormat, @@ -359,7 +353,8 @@ define([ if ((inOrdering === "V") && (outOrdering === "V")) { //inOrientation != outOrientation //cases: VRTL->VLTR, VLTR->VRTL - return invertStr(text); + bdx.dir = inOrientation === "RTL"? RTL : LTR; + return invertStr(text, bdx); } if ((inOrdering === "L") && (outFormat === "VRTL")) { //cases: LLTR->VRTL, LRTL->VRTL @@ -590,8 +585,7 @@ define([ // text: // The source string. // description: - // Iterates over the text string, letter by letter starting from its beginning, - // searching for first "strong" character. + // Searches for first "strong" character. // Returns if strong character was found with the direction defined by this // character, if no strong character was found returns an empty string. // returns: String @@ -601,22 +595,9 @@ define([ // tags: // private - var type = null, uc = null, hi = null; - for (var i = 0; i < text.length; i++) { - uc = text.charAt(i).charCodeAt(0); - hi = MasterTable[uc >> 8]; - type = hi < TBBASE ? hi : UnicodeTable[hi - TBBASE][uc & 0xFF]; - if (type === UBAT_R || type === UBAT_AL) { - return "rtl"; - } - if (type === UBAT_L) { - return "ltr"; - } - if (type === UBAT_B) { - break; - } - } - return ""; + var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text); + // if found return the direction that defined by the character + return fdc ? (fdc[0] <= "z" ? "ltr" : "rtl") : ""; } function lastStrongDir(text) { @@ -625,26 +606,14 @@ define([ // text: // The source string. // description: - // Iterates over the text string, letter by letter starting from its end, - // searching for first (from the end) "strong" character. + // Searches for first (from the end) "strong" character. // Returns if strong character was found with the direction defined by this // character, if no strong character was found returns an empty string. // tags: // private - var type = null; - for (var i = text.length - 1; i >= 0; i--) { - type = getCharacterType(text.charAt(i)); - if (type === UBAT_R || type === UBAT_AL) { - return "rtl"; - } - if (type === UBAT_L) { - return "ltr"; - } - if (type === UBAT_B) { - break; - } - } - return ""; + var chars = text.split(""); + chars.reverse(); + return firstStrongDir(chars.join("")); } function deshape(/*String*/text, /*boolean*/rtl, /*boolean*/consumeNextSpace) { //jshint maxcomplexity: 15 @@ -730,6 +699,7 @@ define([ swapChars(chars, levels, bdx); invertLevel(2, chars, levels, bdx); invertLevel(1, chars, levels, bdx); + lvMap = levels; return chars.join(""); } @@ -843,7 +813,7 @@ define([ return (hi < TBBASE) ? hi : UnicodeTable[hi - TBBASE][uc & 0xFF]; } - function invertStr(str) { + function invertStr(str, bdx) { // summary: // Return the reversed string. // str: @@ -853,6 +823,11 @@ define([ // tags: // private var chars = str.split(""); + if (bdx) { + var levels = []; + computeLevels(chars, levels, bdx); + lvMap = levels; + } chars.reverse(); stMap.reverse(); return chars.join(""); @@ -1117,6 +1092,7 @@ define([ function initMaps(map1, map2, length) { stMap = []; + lvMap = []; for (var i = 0; i < length; i++) { map1[i] = i; map2[i] = i; @@ -1142,6 +1118,7 @@ define([ var stMap = []; var tsMap = []; + var lvMap = []; var BDX = { dir: 0, @@ -1168,6 +1145,8 @@ define([ var validFormat = /^[(I|V)][(L|R|C|D)][(Y|N)][(S|N)][N]$/; + var bidiChars = /[\u0591-\u06ff\ufb1d-\ufefc]/; + /****************************************************************************/ /* Array in which directional characters are replaced by their symmetric. */ /****************************************************************************/ diff --git a/bower.json b/bower.json index a79fd88..f512610 100644 --- a/bower.json +++ b/bower.json @@ -1,9 +1,9 @@ { "name": "dbidi", - "version": "0.2.0", + "version": "0.3.0", "dependencies": { "dcl": "1.1.x", - "decor": "0.3.x" + "decor": "0.6.x" }, "devDependencies": { "requirejs": "2.1.x" diff --git a/docs/TextLayoutEngine.md b/docs/TextLayoutEngine.md index 43beb09..a2797cf 100644 --- a/docs/TextLayoutEngine.md +++ b/docs/TextLayoutEngine.md @@ -9,8 +9,10 @@ The `dbidi/TextLayoutEngine` module provides a bidi transformation engine used f Engine implements Unicode Bidi Algorithm as specified at [Unicode Standard Annex #9](http://www.unicode.org/reports/tr9/). Type of the transformation is controlled by parameters, which describe actual format of input and required format of output. Object holds these parameters as a properties, which allow to reuse them in multiply calls of engine. -Additionally object holds info about relative positions of each character in the source and resulting strings. -This info is placed into sourceToTarget and targetToSource attributes. +Additionally object holds +* info about relative positions of each character in the source and resulting strings; +* info about bidi levels of each character in the source string. +This info is placed into `sourceToTarget`, `targetToSource` and `levels` attributes. ##### Table of Contents [Instantiation](#instantiation) diff --git a/package.json b/package.json index 9719225..47e0300 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dbidi", - "version": "0.2.0", + "version": "0.3.0", "repository": { "type": "git", "url": "http://github.com/ibm-js/dbidi.git" diff --git a/tests/TextLayoutEngineMapsTest.js b/tests/TextLayoutEngineMapsTest.js index c4d1b7c..3aec5e3 100644 --- a/tests/TextLayoutEngineMapsTest.js +++ b/tests/TextLayoutEngineMapsTest.js @@ -5,7 +5,7 @@ define([ ], function (registerSuite, assert, TextLayoutEngine) { var engine = new TextLayoutEngine(); registerSuite({ - name: "Test Text Layout Engine source-to-target and target-to-source maps", + name: "Test Text Layout Engine source-to-target, target-to-source and level maps", "(1) implicit ltr -> visual ltr" : function () { var result = engine.bidiTransform(txt1, "ILYNN", "VLNNN"); assert.equal(engine.sourceToTarget.length, result.length, lengthErr); @@ -50,6 +50,14 @@ define([ assert.equal(txt1.charAt(ind), result.charAt(val), contErr); }); }, + "(5) Levels: ltr" : function () { + var result = engine.bidiTransform(txt1, "ILYNN", "VRNNN"); + assert.equal(engine.levels.join(""), "1111222000000000", contErr); + }, + "(6) Levels: rtl" : function () { + var result = engine.bidiTransform(txt1, "IRYNN", "VLNNN"); + assert.equal(engine.levels.join(""), "1111222122222221", contErr); + } }); var txt1 = "\u05d0\u05d1\u05d2 123 ABC 456."; diff --git a/tests/testBidiEngine.html b/tests/testBidiEngine.html new file mode 100644 index 0000000..b1ca6ce --- /dev/null +++ b/tests/testBidiEngine.html @@ -0,0 +1,182 @@ + + + + +Test Bidi Engine + + + + + +

Test Bidi Engine

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type text:
Source looks:
Buffer:
Params:


Result looks:
Buffer:
Maps
Source to Target:
Target to Source:
Levels:
+

+ + +
+ + + + + + + + + + + + +
Source format:
Target format:
+ + +
+ + + \ No newline at end of file From 0de7e4c53dc1d09910d1edb66a59b2c922da2c8d Mon Sep 17 00:00:00 2001 From: Semion Chichelnitsky Date: Tue, 12 May 2015 11:09:17 +0300 Subject: [PATCH 2/2] 0.3.0 --- TextLayoutEngine.js | 2 +- tests/TextLayoutEngineMapsTest.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TextLayoutEngine.js b/TextLayoutEngine.js index 84a44e7..4e5b38d 100644 --- a/TextLayoutEngine.js +++ b/TextLayoutEngine.js @@ -353,7 +353,7 @@ define([ if ((inOrdering === "V") && (outOrdering === "V")) { //inOrientation != outOrientation //cases: VRTL->VLTR, VLTR->VRTL - bdx.dir = inOrientation === "RTL"? RTL : LTR; + bdx.dir = inOrientation === "RTL" ? RTL : LTR; return invertStr(text, bdx); } if ((inOrdering === "L") && (outFormat === "VRTL")) { diff --git a/tests/TextLayoutEngineMapsTest.js b/tests/TextLayoutEngineMapsTest.js index 3aec5e3..5dc9716 100644 --- a/tests/TextLayoutEngineMapsTest.js +++ b/tests/TextLayoutEngineMapsTest.js @@ -51,13 +51,13 @@ define([ }); }, "(5) Levels: ltr" : function () { - var result = engine.bidiTransform(txt1, "ILYNN", "VRNNN"); + engine.bidiTransform(txt1, "ILYNN", "VRNNN"); assert.equal(engine.levels.join(""), "1111222000000000", contErr); }, "(6) Levels: rtl" : function () { - var result = engine.bidiTransform(txt1, "IRYNN", "VLNNN"); + engine.bidiTransform(txt1, "IRYNN", "VLNNN"); assert.equal(engine.levels.join(""), "1111222122222221", contErr); - } + } }); var txt1 = "\u05d0\u05d1\u05d2 123 ABC 456.";