@qooxdoo/framework 7.5.0 → 7.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/Manifest.json +169 -44
  2. package/bin/deploy/qx +7 -5
  3. package/lib/compiler/compile-info.json +70 -62
  4. package/lib/compiler/index.js +3809 -2695
  5. package/lib/resource/qx/tool/cli/templates/skeleton/desktop/source/class/custom/Application.tmpl.js +7 -7
  6. package/lib/resource/qx/tool/cli/templates/skeleton/desktop/source/class/custom/test/DemoTest.tmpl.js +10 -10
  7. package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/Application.tmpl.js +6 -6
  8. package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/page/Login.tmpl.js +9 -9
  9. package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/page/Overview.tmpl.js +5 -5
  10. package/lib/resource/qx/tool/cli/templates/skeleton/package/source/class/custom/demo/Application.tmpl.js +7 -7
  11. package/lib/resource/qx/tool/cli/templates/skeleton/package/source/class/custom/test/DemoTest.tmpl.js +10 -10
  12. package/lib/resource/qx/tool/cli/templates/skeleton/server/source/class/custom/Application.tmpl.js +6 -6
  13. package/lib/resource/qx/tool/cli/templates/skeleton/server/source/class/custom/test/DemoTest.tmpl.js +12 -12
  14. package/lib/resource/qx/tool/schema/Manifest-1-0-0.json +79 -26
  15. package/lib/resource/qx/tool/schema/Manifest-2-0-0.json +17 -26
  16. package/lib/resource/qx/tool/schema/compile-1-0-0.json +40 -53
  17. package/lib/resource/qx/tool/website/src/about.md +1 -1
  18. package/package.json +3 -3
  19. package/source/class/qx/bom/Font.js +36 -0
  20. package/source/class/qx/bom/webfonts/Validator.js +31 -6
  21. package/source/class/qx/bom/webfonts/WebFont.js +60 -64
  22. package/source/class/qx/bom/webfonts/WebFontLoader.js +461 -0
  23. package/source/class/qx/core/Object.js +1 -1
  24. package/source/class/qx/data/Array.js +27 -0
  25. package/source/class/qx/dev/FakeServer.js +1 -1
  26. package/source/class/qx/event/handler/Focus.js +2 -1
  27. package/source/class/qx/event/handler/GestureCore.js +1 -1
  28. package/source/class/qx/test/bom/webfonts/Validator.js +0 -6
  29. package/source/class/qx/test/core/Environment.js +8 -8
  30. package/source/class/qx/test/core/Validation.js +2 -2
  31. package/source/class/qx/test/dev/unit/Requirements.js +6 -6
  32. package/source/class/qx/test/io/transport/Websocket.js +1 -1
  33. package/source/class/qx/test/ui/basic/Image.js +3 -3
  34. package/source/class/qx/test/ui/basic/Label.js +0 -65
  35. package/source/class/qx/test/ui/form/Field.js +56 -52
  36. package/source/class/qx/theme/IndigoDark.js +1 -1
  37. package/source/class/qx/theme/classic/Font.js +7 -23
  38. package/source/class/qx/theme/iconfont/LoadMaterialIcons.js +2 -4
  39. package/source/class/qx/theme/iconfont/LoadMaterialIconsOutlined.js +2 -4
  40. package/source/class/qx/theme/iconfont/LoadMaterialIconsRound.js +2 -4
  41. package/source/class/qx/theme/iconfont/LoadMaterialIconsSharp.js +2 -4
  42. package/source/class/qx/theme/iconfont/LoadMaterialIconsTwoTone.js +2 -4
  43. package/source/class/qx/theme/indigo/DecorationDark.js +30 -0
  44. package/source/class/qx/theme/indigo/Font.js +8 -15
  45. package/source/class/qx/theme/manager/Font.js +151 -38
  46. package/source/class/qx/theme/modern/Font.js +1 -0
  47. package/source/class/qx/theme/simple/Font.js +3 -1
  48. package/source/class/qx/theme/tangible/Appearance.js +1 -0
  49. package/source/class/qx/theme/tangible/Font.js +9 -62
  50. package/source/class/qx/theme/tangible/Image.js +1 -4
  51. package/source/class/qx/tool/cli/Application.js +4 -1
  52. package/source/class/qx/tool/cli/Cli.js +34 -23
  53. package/source/class/qx/tool/cli/Watch.js +8 -6
  54. package/source/class/qx/tool/cli/api/CompilerApi.js +8 -0
  55. package/source/class/qx/tool/cli/commands/Add.js +1 -1
  56. package/source/class/qx/tool/cli/commands/Compile.js +24 -1
  57. package/source/class/qx/tool/cli/commands/Config.js +16 -141
  58. package/source/class/qx/tool/cli/commands/ExportGlyphs.js +134 -0
  59. package/source/class/qx/tool/cli/commands/Lint.js +1 -1
  60. package/source/class/qx/tool/cli/commands/Package.js +3 -0
  61. package/source/class/qx/tool/cli/commands/Pkg.js +1 -1
  62. package/source/class/qx/tool/cli/commands/Run.js +6 -7
  63. package/source/class/qx/tool/cli/commands/Serve.js +29 -36
  64. package/source/class/qx/tool/cli/commands/Test.js +3 -2
  65. package/source/class/qx/tool/cli/commands/add/Script.js +3 -1
  66. package/source/class/qx/tool/cli/commands/config/Delete.js +47 -0
  67. package/source/class/qx/tool/cli/commands/config/Get.js +52 -0
  68. package/source/class/qx/tool/cli/commands/config/List.js +81 -0
  69. package/source/class/qx/tool/cli/commands/config/Set.js +61 -0
  70. package/source/class/qx/tool/cli/commands/package/Install.js +3 -0
  71. package/source/class/qx/tool/cli/commands/package/Update.js +3 -3
  72. package/source/class/qx/tool/compiler/Analyser.js +45 -0
  73. package/source/class/qx/tool/compiler/ClassFile.js +43 -1
  74. package/source/class/qx/tool/compiler/Console.js +6 -1
  75. package/source/class/qx/tool/compiler/app/Application.js +19 -0
  76. package/source/class/qx/tool/compiler/app/Cldr.js +63 -26
  77. package/source/class/qx/tool/compiler/app/Library.js +51 -2
  78. package/source/class/qx/tool/compiler/app/ManifestFont.js +181 -0
  79. package/source/class/qx/tool/compiler/app/WebFont.js +144 -234
  80. package/source/class/qx/tool/compiler/makers/AppMaker.js +13 -0
  81. package/source/class/qx/tool/compiler/resources/ImageLoader.js +22 -12
  82. package/source/class/qx/tool/compiler/resources/Manager.js +2 -2
  83. package/source/class/qx/tool/compiler/resources/MetaLoader.js +7 -2
  84. package/source/class/qx/tool/compiler/resources/ResourceLoader.js +21 -0
  85. package/source/class/qx/tool/compiler/targets/Target.js +186 -67
  86. package/source/class/qx/tool/migration/M7_5_6.js +75 -0
  87. package/source/class/qx/tool/utils/Http.js +69 -0
  88. package/source/class/qx/ui/basic/Image.js +6 -2
  89. package/source/class/qx/ui/basic/Label.js +20 -38
  90. package/source/class/qx/ui/core/Widget.js +13 -42
  91. package/source/class/qx/ui/form/AbstractField.js +8 -2
  92. package/source/class/qx/ui/form/FileSelectorButton.js +5 -0
  93. package/source/class/qx/ui/table/pane/FocusIndicator.js +5 -4
  94. package/source/class/qx/ui/table/pane/Pane.js +14 -0
  95. package/source/class/qx/ui/table/pane/Scroller.js +3 -3
  96. package/source/class/qx/ui/virtual/core/Scroller.js +8 -2
  97. package/source/class/qx/ui/window/Window.js +9 -8
  98. package/source/resource/qx/iconfont/MaterialIcons/materialicons.json +10912 -0
  99. package/source/resource/qx/iconfont/MaterialIcons/materialiconsoutlined.json +10967 -0
  100. package/source/resource/qx/iconfont/MaterialIcons/materialiconsround.json +10992 -0
  101. package/source/resource/qx/iconfont/MaterialIcons/materialiconssharp.json +10992 -0
  102. package/source/resource/qx/iconfont/MaterialIcons/materialiconstwotone.json +9947 -0
  103. package/source/resource/qx/iconfont/MaterialIcons/x.json +10967 -0
  104. package/source/resource/qx/iconfont/export-glyphs.sh +22 -0
  105. package/source/resource/qx/mobile/scss/common/_gradients.scss +1 -1
  106. package/source/resource/qx/tool/cli/templates/skeleton/desktop/source/class/custom/Application.tmpl.js +7 -7
  107. package/source/resource/qx/tool/cli/templates/skeleton/desktop/source/class/custom/test/DemoTest.tmpl.js +10 -10
  108. package/source/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/Application.tmpl.js +6 -6
  109. package/source/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/page/Login.tmpl.js +9 -9
  110. package/source/resource/qx/tool/cli/templates/skeleton/mobile/source/class/custom/page/Overview.tmpl.js +5 -5
  111. package/source/resource/qx/tool/cli/templates/skeleton/package/source/class/custom/demo/Application.tmpl.js +7 -7
  112. package/source/resource/qx/tool/cli/templates/skeleton/package/source/class/custom/test/DemoTest.tmpl.js +10 -10
  113. package/source/resource/qx/tool/cli/templates/skeleton/server/source/class/custom/Application.tmpl.js +6 -6
  114. package/source/resource/qx/tool/cli/templates/skeleton/server/source/class/custom/test/DemoTest.tmpl.js +12 -12
  115. package/source/resource/qx/tool/schema/Manifest-1-0-0.json +79 -26
  116. package/source/resource/qx/tool/schema/Manifest-2-0-0.json +17 -26
  117. package/source/resource/qx/tool/schema/compile-1-0-0.json +40 -53
  118. package/source/resource/qx/tool/website/src/about.md +1 -1
  119. package/source/class/qx/bom/webfonts/Manager.js +0 -652
  120. package/source/class/qx/test/bom/webfonts/Manager.js +0 -238
@@ -0,0 +1,181 @@
1
+ /* ************************************************************************
2
+
3
+ qooxdoo - the new era of web development
4
+
5
+ http://qooxdoo.org
6
+
7
+ Copyright:
8
+ 2023 Zenesis Limited https://www.zenesis.com
9
+
10
+ License:
11
+ MIT: https://opensource.org/licenses/MIT
12
+ See the LICENSE file in the project's top-level directory for details.
13
+
14
+ Authors:
15
+ * John Spackman (@johnspackman)
16
+
17
+ ************************************************************************ */
18
+
19
+ const fs = require("fs");
20
+ const path = require("path");
21
+
22
+ /**
23
+ * Represents a font as defined in the Manifest.json's
24
+ *
25
+ * @typedef Sources
26
+ * @param {String?} family the family name that is in the font files (defaults to the name of the font)
27
+ * @param {String[]?} paths the filenames of font files inside the resources dircetory
28
+ * @param {String[]?} urls the urls of font files in a CDN
29
+ *
30
+ */
31
+ qx.Class.define("qx.tool.compiler.app.ManifestFont", {
32
+ extend: qx.core.Object,
33
+
34
+ construct(name) {
35
+ super();
36
+ this.setName(name);
37
+ },
38
+
39
+ properties: {
40
+ /** The name of the font - this is the key in Manifest.json provides.fonts */
41
+ name: {
42
+ check: "String"
43
+ },
44
+
45
+ /** Default size of the font */
46
+ defaultSize: {
47
+ init: null,
48
+ nullable: true,
49
+ check: "Integer"
50
+ },
51
+
52
+ /** Comparison string to be used */
53
+ comparisonString: {
54
+ init: null,
55
+ nullable: true,
56
+ check: "String"
57
+ },
58
+
59
+ /** CSS filenames or URLs to be loaded (indicating that font-face will be defined outside of Qooxdoo) */
60
+ css: {
61
+ init: null,
62
+ check: "Array",
63
+ nullable: true
64
+ },
65
+
66
+ /** Font faces that have to be defined, including the resource paths or urls */
67
+ fontFaces: {
68
+ init: null,
69
+ check: "Array",
70
+ nullable: true
71
+ },
72
+
73
+ /** Glyphs filename (relative to resources of the library that defines it) */
74
+ glyphs: {
75
+ init: null,
76
+ nullable: true,
77
+ check: "String"
78
+ },
79
+
80
+ /** Family names for the browser to search for */
81
+ family: {
82
+ init: null,
83
+ nullable: true,
84
+ check: "Array"
85
+ }
86
+ },
87
+
88
+ members: {
89
+ /** @type{Map<String,Object>} font data required by the Qooxdoo app at runtime */
90
+ __fontData: null,
91
+
92
+ /**
93
+ * Updates this from the data in the Manifest.json
94
+ *
95
+ * @param {Object} data the data from Manifest
96
+ * @param {qx.tool.compiler.app.Library} library the library
97
+ */
98
+ async updateFromManifest(data, library) {
99
+ let toSet = {};
100
+ [
101
+ "defaultSize",
102
+ "comparisonString",
103
+ "css",
104
+ "fontFaces",
105
+ "glyphs",
106
+ "family"
107
+ ].forEach(name => {
108
+ if (data.hasOwnProperty(name)) {
109
+ toSet[name] = data[name];
110
+ }
111
+ });
112
+ this.set(toSet);
113
+ if (data.glyphs !== undefined) {
114
+ let glyphsFilename = library.getResourceFilename(data.glyphs);
115
+ let glyphsData = await fs.promises.readFile(glyphsFilename, "utf8");
116
+ glyphsData = JSON.parse(glyphsData);
117
+ this.__fontData = {};
118
+ let name = this.getName();
119
+ let defaultSize = this.getDefaultSize();
120
+
121
+ for (let key in glyphsData) {
122
+ let glyph = glyphsData[key];
123
+ this.__fontData["@" + name + "/" + key] = [
124
+ // width
125
+ Math.ceil((defaultSize * glyph.advanceWidth) / glyph.advanceHeight),
126
+
127
+ // height
128
+ defaultSize,
129
+ glyph.codePoint
130
+ ];
131
+ }
132
+ }
133
+ },
134
+
135
+ /**
136
+ * Generates the font data used by the application; loads the data if not already loaded
137
+ *
138
+ * @returns {Map<String,Object>}
139
+ */
140
+ getApplicationFontData() {
141
+ return this.__fontData;
142
+ },
143
+
144
+ /**
145
+ * Return bootstrap code that is executed before the Application starts.
146
+ *
147
+ * @param {qx.tool.compiler.targets.Target} target the target
148
+ * @param {qx.tool.compiler.app.Application} application the application being built
149
+ * @param {Boolean} useLocalFonts whether to use local fonts or use CSS
150
+ * @return {String} code to include in the output
151
+ */
152
+ getBootstrapCode(target, application, useLocalFonts) {
153
+ let res = "";
154
+ let font = {
155
+ family: this.getFamily() || [this.getName()]
156
+ };
157
+
158
+ if (!useLocalFonts) {
159
+ if (this.getCss()) {
160
+ font.css = this.getCss();
161
+ }
162
+ } else {
163
+ font.fontFaces = this.getFontFaces();
164
+ }
165
+
166
+ if (this.getDefaultSize() !== null) {
167
+ font.defaultSize = this.getDefaultSize();
168
+ }
169
+ if (this.getComparisonString() !== null) {
170
+ font.comparisonString = this.getComparisonString();
171
+ }
172
+
173
+ return (res +=
174
+ "qx.$$fontBootstrap['" +
175
+ this.getName() +
176
+ "']=" +
177
+ JSON.stringify(font, null, 2) +
178
+ ";");
179
+ }
180
+ }
181
+ });
@@ -88,236 +88,166 @@ qx.Class.define("qx.tool.compiler.app.WebFont", {
88
88
  * Helper which triggers a local font analyze run.
89
89
  *
90
90
  * @param filename {String} Filename for the local font
91
- * @return {Promise}
91
+ * @return {Map<String,String>} mapping of glyphs to codepoints
92
92
  */
93
- _loadLocalFont(filename) {
94
- return new Promise((resolve, reject) => {
95
- let fontpath = path.join(
96
- this.__library.getRootDir(),
97
- path.join(this.__library.getResourcePath(), filename)
98
- );
93
+ async _loadLocalFont(filename) {
94
+ let fontpath = path.join(
95
+ this.__library.getRootDir(),
96
+ path.join(this.__library.getResourcePath(), filename)
97
+ );
99
98
 
100
- this.__processFontFile(fontpath, resolve, reject);
101
- });
99
+ return await this.__processFontFile(fontpath);
102
100
  },
103
101
 
104
102
  /**
105
103
  * Helper which loads a remote font to analyze the result.
106
104
  *
107
105
  * @param url {String} URL for the font download
108
- * @return {Promise}
106
+ * @return {Map<String,String>} mapping of glyphs to codepoints
109
107
  */
110
- _loadRemoteFont(url) {
111
- return new Promise(
112
- function (resolve, reject) {
113
- http
114
- .get(
115
- url,
116
- function (res) {
117
- let error;
118
- const { statusCode } = res;
119
- const contentType = res.headers["content-type"];
120
-
121
- if (statusCode !== 200) {
122
- error = new Error(
123
- `Request Failed.\nStatus Code: ${statusCode}`
124
- );
125
- } else if (
126
- !/^font\/(ttf|svg|eot|woff|woff2)$/.test(contentType)
127
- ) {
128
- error = new Error(
129
- "Invalid content-type.\n" +
130
- `Expected font/ttf, font/svg, font/eot, font/woff or font/woff2 but received ${contentType}`
131
- );
132
- }
133
-
134
- if (error) {
135
- res.resume();
136
- reject(error);
137
- return;
138
- }
139
-
140
- tmp.tmpName(
141
- function _tempNameGenerated(err, tmpFilename) {
142
- if (err) {
143
- reject(err);
144
- return;
145
- }
146
-
147
- let outFile = fs.createWriteStream(tmpFilename);
148
- outFile.on(
149
- "close",
150
- function () {
151
- this.__processFontFile(tmpFilename, resolve, reject);
152
- fs.unlink(tmpFilename);
153
- }.bind(this)
154
- );
155
-
156
- res.on("data", chunk => {
157
- outFile.write(chunk);
158
- });
159
- res.on("end", function () {
160
- outFile.end();
161
- });
162
- }.bind(this)
163
- );
164
- }.bind(this)
165
- )
166
- .on("error", e => {
167
- reject(e);
168
- });
169
- }.bind(this)
108
+ async _loadRemoteFont(url) {
109
+ let tmpFilename = await qx.tool.utils.Http.downloadToTempFile(
110
+ url,
111
+ /^font\/(ttf|svg|eot|woff|woff2)$/
170
112
  );
113
+
114
+ let result = await this.__processFontFile(tmpFilename);
115
+ fs.unlink(tmpFilename);
116
+ return result;
171
117
  },
172
118
 
173
119
  /**
174
120
  * Common code to extract the desired font information from a font file
175
- * on disk. It resolves the promises given by the calling stub (remote or
176
- * local font retrieval).
121
+ * on disk.
177
122
  *
178
123
  * @param filename {String} Path to font file
179
- * @param resolve {Function} External promise resolve
180
- * @param reject {Function} External promise reject
124
+ * @return {Map<String,String>} mapping of glyphs to codepoints
181
125
  */
182
- __processFontFile(filename, resolve, reject) {
183
- fontkit.open(
184
- filename,
185
- null,
186
- function (err, font) {
187
- if (err) {
188
- reject(err);
189
- return;
190
- }
191
-
192
- let resources = {};
126
+ async __processFontFile(filename) {
127
+ let fn = qx.tool.utils.Promisify.promisify(cb =>
128
+ fontkit.open(filename, null, cb)
129
+ );
193
130
 
194
- // If we have a mapping file, take qx.tool.compiler.Console.information instead
195
- // of anaylzing the font.
196
- if (this.getMapping()) {
197
- let mapPath = path.join(
198
- this.__library.getRootDir(),
199
- path.join(this.__library.getResourcePath(), this.getMapping())
200
- );
131
+ let font = await fn();
132
+ let resources = {};
201
133
 
202
- fs.readFile(mapPath, { encoding: "utf-8" }, (err, data) => {
203
- if (err) {
204
- log.error(`Cannot read mapping file '${mapPath}': ${err.code}`);
205
- reject(err);
206
- return;
207
- }
208
-
209
- let map = JSON.parse(data);
210
- Object.keys(map).forEach(key => {
211
- let codePoint = parseInt(map[key], 16);
212
- let glyph = font.glyphForCodePoint(codePoint);
213
- if (!glyph.id) {
214
- qx.tool.compiler.Console.trace(
215
- `WARN: no glyph found in ${filename} ${key}: ${codePoint}`
216
- );
217
-
218
- return;
219
- }
220
- resources["@" + this.getName() + "/" + key] = [
221
- Math.ceil(
222
- (this.getDefaultSize() * glyph.advanceWidth) /
223
- glyph.advanceHeight
224
- ),
225
-
226
- // width
227
- this.getDefaultSize(), // height
228
- codePoint
229
- ];
230
- }, this);
231
-
232
- resolve(resources);
233
- return;
234
- });
134
+ // If we have a mapping file, take qx.tool.compiler.Console.information instead
135
+ // of anaylzing the font.
136
+ if (this.getMapping()) {
137
+ let mapPath = path.join(
138
+ this.__library.getRootDir(),
139
+ path.join(this.__library.getResourcePath(), this.getMapping())
140
+ );
235
141
 
236
- return;
237
- }
142
+ let data;
143
+ try {
144
+ data = await fs.promises.readFile(mapPath, { encoding: "utf-8" });
145
+ } catch (err) {
146
+ log.error(`Cannot read mapping file '${mapPath}': ${err.code}`);
147
+ throw err;
148
+ }
238
149
 
239
- if (!font.GSUB) {
240
- qx.tool.compiler.Console.error(
241
- `The webfont in ${filename} does not have any ligatures`
150
+ let map = JSON.parse(data);
151
+ Object.keys(map).forEach(key => {
152
+ let codePoint = parseInt(map[key], 16);
153
+ let glyph = font.glyphForCodePoint(codePoint);
154
+ if (!glyph.id) {
155
+ qx.tool.compiler.Console.trace(
156
+ `WARN: no glyph found in ${filename} ${key}: ${codePoint}`
242
157
  );
243
158
 
244
- resolve(resources);
245
159
  return;
246
160
  }
161
+ resources["@" + this.getName() + "/" + key] = [
162
+ Math.ceil(
163
+ (this.getDefaultSize() * glyph.advanceWidth) / glyph.advanceHeight
164
+ ),
165
+
166
+ // width
167
+ this.getDefaultSize(), // height
168
+ codePoint
169
+ ];
170
+ }, this);
171
+
172
+ return resources;
173
+ }
174
+
175
+ if (!font.GSUB) {
176
+ qx.tool.compiler.Console.error(
177
+ `The webfont in ${filename} does not have any ligatures`
178
+ );
179
+
180
+ return resources;
181
+ }
247
182
 
248
- // some IconFonts (MaterialIcons for example) use ligatures
249
- // to name their icons. This code extracts the ligatures
250
- // hat tip to Jossef Harush https://stackoverflow.com/questions/54721774/extracting-ttf-font-ligature-mappings/54728584
251
- let ligatureName = {};
252
- let lookupList = font.GSUB.lookupList.toArray();
253
- let lookupListIndexes =
254
- font.GSUB.featureList[0].feature.lookupListIndexes;
255
- lookupListIndexes.forEach(index => {
256
- let subTable = lookupList[index].subTables[0];
257
- let leadingCharacters = [];
258
- if (subTable.coverage.rangeRecords) {
259
- subTable.coverage.rangeRecords.forEach(coverage => {
260
- for (let i = coverage.start; i <= coverage.end; i++) {
261
- let character = font.stringsForGlyph(i)[0];
262
- leadingCharacters.push(character);
263
- }
264
- });
183
+ // some IconFonts (MaterialIcons for example) use ligatures
184
+ // to name their icons. This code extracts the ligatures
185
+ // hat tip to Jossef Harush https://stackoverflow.com/questions/54721774/extracting-ttf-font-ligature-mappings/54728584
186
+ let ligatureName = {};
187
+ let lookupList = font.GSUB.lookupList.toArray();
188
+ let lookupListIndexes =
189
+ font.GSUB.featureList[0].feature.lookupListIndexes;
190
+ lookupListIndexes.forEach(index => {
191
+ let subTable = lookupList[index].subTables[0];
192
+ let leadingCharacters = [];
193
+ if (subTable.coverage.rangeRecords) {
194
+ subTable.coverage.rangeRecords.forEach(coverage => {
195
+ for (let i = coverage.start; i <= coverage.end; i++) {
196
+ let character = font.stringsForGlyph(i)[0];
197
+ leadingCharacters.push(character);
265
198
  }
266
- let ligatureSets = subTable.ligatureSets.toArray();
267
- ligatureSets.forEach((ligatureSet, ligatureSetIndex) => {
268
- let leadingCharacter = leadingCharacters[ligatureSetIndex];
269
- ligatureSet.forEach(ligature => {
270
- let character = font.stringsForGlyph(ligature.glyph)[0];
271
- if (!character) {
272
- // qx.tool.compiler.Console.log(`WARN: ${this.getName()} no character ${ligature}`);
273
- return;
274
- }
275
- let ligatureText =
276
- leadingCharacter +
277
- ligature.components
278
- .map(x => font.stringsForGlyph(x)[0])
279
- .join("");
280
- var hexId = character.charCodeAt(0).toString(16);
281
- if (ligatureName[hexId] == undefined) {
282
- ligatureName[hexId] = [ligatureText];
283
- } else {
284
- ligatureName[hexId].push(ligatureText);
285
- }
286
- });
287
- });
288
199
  });
289
-
290
- let defaultSize = this.getDefaultSize();
291
- font.characterSet.forEach(codePoint => {
292
- let glyph = font.glyphForCodePoint(codePoint);
293
- if (glyph.path.commands.length < 1 && !glyph.layers) {
200
+ }
201
+ let ligatureSets = subTable.ligatureSets.toArray();
202
+ ligatureSets.forEach((ligatureSet, ligatureSetIndex) => {
203
+ let leadingCharacter = leadingCharacters[ligatureSetIndex];
204
+ ligatureSet.forEach(ligature => {
205
+ let character = font.stringsForGlyph(ligature.glyph)[0];
206
+ if (!character) {
207
+ // qx.tool.compiler.Console.log(`WARN: ${this.getName()} no character ${ligature}`);
294
208
  return;
295
209
  }
296
-
297
- const found = gName => {
298
- resources["@" + this.getName() + "/" + gName] = [
299
- Math.ceil(
300
- (this.getDefaultSize() * glyph.advanceWidth) /
301
- glyph.advanceHeight
302
- ),
303
-
304
- // width
305
- defaultSize, // height
306
- codePoint
307
- ];
308
- };
309
- if (glyph.name) {
310
- found(glyph.name);
311
- }
312
- var names = ligatureName[codePoint.toString(16)];
313
- if (names) {
314
- names.forEach(found);
210
+ let ligatureText =
211
+ leadingCharacter +
212
+ ligature.components.map(x => font.stringsForGlyph(x)[0]).join("");
213
+ var hexId = character.charCodeAt(0).toString(16);
214
+ if (ligatureName[hexId] == undefined) {
215
+ ligatureName[hexId] = [ligatureText];
216
+ } else {
217
+ ligatureName[hexId].push(ligatureText);
315
218
  }
316
- }, this);
219
+ });
220
+ });
221
+ });
317
222
 
318
- resolve(resources);
319
- }.bind(this)
320
- );
223
+ let defaultSize = this.getDefaultSize();
224
+ font.characterSet.forEach(codePoint => {
225
+ let glyph = font.glyphForCodePoint(codePoint);
226
+ if (glyph.path.commands.length < 1 && !glyph.layers) {
227
+ return;
228
+ }
229
+
230
+ const found = gName => {
231
+ resources["@" + this.getName() + "/" + gName] = [
232
+ Math.ceil(
233
+ (this.getDefaultSize() * glyph.advanceWidth) / glyph.advanceHeight
234
+ ),
235
+
236
+ // width
237
+ defaultSize, // height
238
+ codePoint
239
+ ];
240
+ };
241
+ if (glyph.name) {
242
+ found(glyph.name);
243
+ }
244
+ var names = ligatureName[codePoint.toString(16)];
245
+ if (names) {
246
+ names.forEach(found);
247
+ }
248
+ }, this);
249
+
250
+ return resources;
321
251
  },
322
252
 
323
253
  /**
@@ -325,24 +255,17 @@ qx.Class.define("qx.tool.compiler.app.WebFont", {
325
255
  *
326
256
  * @param target {qx.tool.compiler.targets.Target} the target
327
257
  * @param application {qx.tool.compiler.app.Application} the application being built
328
- * @param initial {Boolean} true if this is the first pass
329
258
  * @return {String}
330
259
  */
331
- getBootstrapCode(target, application, initial) {
260
+ getBootstrapCode(target, application) {
332
261
  let res = "";
333
-
334
- if (initial) {
335
- res = "qx.$$fontBootstrap={};\n";
336
- }
337
-
338
262
  let font = {
339
- size: this.getDefaultSize(),
263
+ defaultSize: this.getDefaultSize(),
340
264
  lineHeight: 1,
341
265
  family: [this.getName()],
342
- sources: [
266
+ fontFaces: [
343
267
  {
344
- family: this.getName(),
345
- source: this.getResources()
268
+ paths: this.getResources()
346
269
  }
347
270
  ]
348
271
  };
@@ -355,7 +278,7 @@ qx.Class.define("qx.tool.compiler.app.WebFont", {
355
278
  "qx.$$fontBootstrap['" +
356
279
  this.getName() +
357
280
  "']=" +
358
- JSON.stringify(font) +
281
+ JSON.stringify(font, null, 2) +
359
282
  ";");
360
283
  },
361
284
 
@@ -371,7 +294,7 @@ qx.Class.define("qx.tool.compiler.app.WebFont", {
371
294
  return this.__generateForTargetPromise;
372
295
  }
373
296
 
374
- this.__generateForTargetPromise = new Promise((resolve, reject) => {
297
+ const generate = async () => {
375
298
  for (let resource of this.getResources()) {
376
299
  // Search for the first supported extension
377
300
  let basename = resource.match(/^.*[/\\]([^/\\\?#]+).*$/)[1];
@@ -379,35 +302,22 @@ qx.Class.define("qx.tool.compiler.app.WebFont", {
379
302
  if (!basename.match(/\.(ttf|otf|woff|woff2)$/)) {
380
303
  continue;
381
304
  }
382
- // We support http/https and local files, check for URLs
383
- // first.
305
+
384
306
  if (resource.match(/^https?:\/\//)) {
385
- this._loadRemoteFont(resource)
386
- .then(data => {
387
- this.__fontData = data;
388
- resolve();
389
- })
390
- .catch(err => {
391
- reject(err);
392
- });
393
- return;
307
+ this.__fontData = await this._loadRemoteFont(resource);
308
+ } else {
309
+ this.__fontData = await this._loadLocalFont(resource);
394
310
  }
395
- // handle local file
396
- this._loadLocalFont(resource)
397
- .then(data => {
398
- this.__fontData = data;
399
- resolve();
400
- })
401
- .catch(err => {
402
- reject(err);
403
- });
404
- return;
311
+
312
+ return this.__fontData;
405
313
  }
406
- reject(
314
+
315
+ throw new Error(
407
316
  `Failed to load/validate FontMap for webfont (expected ttf, otf, woff or woff2) ${this.getName()}`
408
317
  );
409
- });
318
+ };
410
319
 
320
+ this.__generateForTargetPromise = generate();
411
321
  return this.__generateForTargetPromise;
412
322
  },
413
323
 
@@ -165,6 +165,18 @@ qx.Class.define("qx.tool.compiler.makers.AppMaker", {
165
165
  this.__applications.forEach(app => app.setAnalyser(analyser));
166
166
  await target.open();
167
167
 
168
+ for (let library of analyser.getLibraries()) {
169
+ let fontsData = library.getFontsData();
170
+ for (let fontName in fontsData) {
171
+ let fontData = fontsData[fontName];
172
+ let font = analyser.getFont(fontName);
173
+ if (!font) {
174
+ font = analyser.getFont(fontName, true);
175
+ await font.updateFromManifest(fontData, library);
176
+ }
177
+ }
178
+ }
179
+
168
180
  if (this.isOutputTypescript()) {
169
181
  analyser.getLibraries().forEach(library => {
170
182
  var symbols = library.getKnownSymbols();
@@ -208,6 +220,7 @@ qx.Class.define("qx.tool.compiler.makers.AppMaker", {
208
220
  let stat = await qx.tool.utils.files.Utils.safeStat(
209
221
  localModules[requireName]
210
222
  );
223
+
211
224
  res ||=
212
225
  stat.mtime.getTime() >
213
226
  (db?.modulesInfo?.localModules[requireName] || 0);