quickwin 1.0.2 → 1.1.1
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.
- package/README.en.md +204 -204
- package/README.md +203 -203
- package/examples/PdfCanvas.tsx +83 -83
- package/examples/exec_server.ts +35 -35
- package/examples/pdf_preview2.ts +375 -375
- package/examples/pdf_viewer.tsx +279 -279
- package/examples/test_gallery.tsx +285 -285
- package/examples/test_react_lazy.tsx +63 -63
- package/examples/test_react_listbox.tsx +71 -71
- package/examples/test_root_window.tsx +41 -41
- package/examples/test_tab.tsx +75 -75
- package/examples/tray_demo.tsx +81 -81
- package/lib/assert.ts +6 -6
- package/lib/cache-utils.ts +40 -40
- package/lib/dumpRects.ts +25 -25
- package/lib/fetch.ts +502 -502
- package/lib/http-common.ts +399 -399
- package/lib/http-server.ts +424 -424
- package/lib/polyfill.ts +171 -171
- package/lib/react-qw/components/index.ts +17 -17
- package/lib/react-qw/index.ts +90 -90
- package/lib/react-qw/jsx.d.ts +34 -34
- package/lib/react-qw/layout.ts +111 -111
- package/lib/react-qw/props.ts +36 -36
- package/lib/react-qw/reconciler.ts +373 -373
- package/lib/stream.ts +21 -21
- package/lib/text-codec.ts +171 -171
- package/lib/text-measure.ts +54 -54
- package/lib/url.ts +201 -201
- package/lib/vendor/web-streams/ponyfill.d.mts +829 -829
- package/lib/vendor/web-streams/ponyfill.mjs +8 -8
- package/lib/websocket.js +8 -0
- package/lib/websocket.ts +563 -555
- package/package.json +50 -44
- package/qwin-nowasm-x86.exe +0 -0
- package/qwin-nowasm.exe +0 -0
- package/qwin-x86.exe +0 -0
- package/qwin.exe +0 -0
- package/test/run.ts +96 -96
- package/test/test_basic.ts +9 -9
- package/test/test_basic_fetch.ts +33 -33
- package/test/test_brotli.ts +52 -52
- package/test/test_fetch_cache.ts +187 -187
- package/test/test_ffi.ts +174 -174
- package/test/test_frame_encoding.ts +132 -132
- package/test/test_helper.ts +80 -80
- package/test/test_http_import.ts +74 -74
- package/test/test_http_server.ts +136 -136
- package/test/test_import_dir.ts +5 -5
- package/test/test_ipv6.ts +129 -129
- package/test/test_meta_url.ts +4 -4
- package/test/test_mupdf_render.ts +74 -74
- package/test/test_mupdf_twice.ts +81 -81
- package/test/test_mupdf_wasm.ts +30 -30
- package/test/test_net_event.ts +55 -55
- package/test/test_net_fetch.ts +238 -238
- package/test/test_net_websocket.ts +164 -164
- package/test/test_polyfill.ts +159 -159
- package/test/test_url.ts +183 -183
- package/test/test_wasm_basic.ts +73 -73
- package/test/test_wasm_import_global.ts +45 -45
- package/test/test_wasm_sjlj.ts +125 -125
- package/test/test_wasm_types.ts +124 -124
- package/test/test_worker.ts +24 -24
- package/test/test_worker_fetch.ts +27 -27
- package/test/test_worker_net.ts +54 -54
- package/test/test_worker_wasm_concurrent.ts +45 -45
- package/test/worker_fetch.ts +13 -13
- package/test/worker_helper.ts +1 -1
- package/test/worker_http.ts +20 -20
- package/test/worker_import_lib.ts +13 -13
- package/test/worker_module.ts +17 -17
- package/test/worker_wasm_concurrent.ts +22 -22
- package/tsconfig.json +27 -27
- package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -571
- package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -2749
- package/vendor/mupdf-wasm/mupdf.d.ts +939 -939
- package/vendor/mupdf-wasm/mupdf.js +3317 -3317
package/lib/stream.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
export {}
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
ReadableStream as ReadableStreamImpl,
|
|
5
|
-
ReadableStreamDefaultController as ReadableStreamDefaultControllerImpl,
|
|
6
|
-
ReadableStreamDefaultReader as ReadableStreamDefaultReaderImpl,
|
|
7
|
-
} from './vendor/web-streams/ponyfill.mjs'
|
|
8
|
-
|
|
9
|
-
declare global {
|
|
10
|
-
type ReadableStreamReadResult<R = any> =
|
|
11
|
-
| { done: false; value: R }
|
|
12
|
-
| { done: true; value?: undefined }
|
|
13
|
-
|
|
14
|
-
interface ReadableStreamReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {}
|
|
15
|
-
interface ReadableStreamDefaultReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {}
|
|
16
|
-
interface ReadableStream<R = any> extends ReadableStreamImpl<R> {}
|
|
17
|
-
interface ReadableStreamDefaultController<R = any> extends ReadableStreamDefaultControllerImpl<R> {}
|
|
18
|
-
|
|
19
|
-
var ReadableStream: typeof ReadableStreamImpl
|
|
20
|
-
}
|
|
21
|
-
|
|
1
|
+
export {}
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ReadableStream as ReadableStreamImpl,
|
|
5
|
+
ReadableStreamDefaultController as ReadableStreamDefaultControllerImpl,
|
|
6
|
+
ReadableStreamDefaultReader as ReadableStreamDefaultReaderImpl,
|
|
7
|
+
} from './vendor/web-streams/ponyfill.mjs'
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
type ReadableStreamReadResult<R = any> =
|
|
11
|
+
| { done: false; value: R }
|
|
12
|
+
| { done: true; value?: undefined }
|
|
13
|
+
|
|
14
|
+
interface ReadableStreamReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {}
|
|
15
|
+
interface ReadableStreamDefaultReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {}
|
|
16
|
+
interface ReadableStream<R = any> extends ReadableStreamImpl<R> {}
|
|
17
|
+
interface ReadableStreamDefaultController<R = any> extends ReadableStreamDefaultControllerImpl<R> {}
|
|
18
|
+
|
|
19
|
+
var ReadableStream: typeof ReadableStreamImpl
|
|
20
|
+
}
|
|
21
|
+
|
|
22
22
|
globalThis.ReadableStream = ReadableStreamImpl
|
package/lib/text-codec.ts
CHANGED
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
export {} // make this a module so declare global works
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
interface TextDecoder<T extends _Label | undefined = _Label | undefined> extends TextDecoderImpl<T> {}
|
|
5
|
-
var TextDecoder: typeof TextDecoderImpl
|
|
6
|
-
|
|
7
|
-
interface TextEncoder<T extends _Label | undefined = _Label | undefined> extends TextEncoderImpl<T> {}
|
|
8
|
-
var TextEncoder: typeof TextEncoderImpl
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const _labelMap = {
|
|
12
|
-
'utf-8': 'utf-8',
|
|
13
|
-
'utf8': 'utf-8',
|
|
14
|
-
'unicode-1-1-utf-8': 'utf-8',
|
|
15
|
-
'utf-16': 'utf-16le',
|
|
16
|
-
'utf-16le': 'utf-16le',
|
|
17
|
-
'utf-16be': 'utf-16be',
|
|
18
|
-
} as const
|
|
19
|
-
|
|
20
|
-
type _Label = keyof typeof _labelMap
|
|
21
|
-
type _Encoding = typeof _labelMap[_Label]
|
|
22
|
-
type _Result<T> = T extends _Label ? typeof _labelMap[T] : 'utf-8'
|
|
23
|
-
|
|
24
|
-
function _normalizeLabel<T extends _Label | undefined>(label: T): _Result<T> {
|
|
25
|
-
if (!label) return 'utf-8' as _Result<T>
|
|
26
|
-
const result = _labelMap[label.trim().toLowerCase() as _Label]
|
|
27
|
-
if (result) return result as _Result<T>
|
|
28
|
-
throw new RangeError(`The encoding label "${label}" is not supported`)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function _decodeUTF8(buf: Uint8Array, fatal: boolean): string {
|
|
32
|
-
let out = ''
|
|
33
|
-
for (let i = 0; i < buf.length; ) {
|
|
34
|
-
const b = buf[i++]!
|
|
35
|
-
if (b < 0x80) { out += String.fromCharCode(b); continue }
|
|
36
|
-
if (b < 0xC0) { out += fatal ? (() => { throw new TypeError('unexpected continuation byte') })() : '\uFFFD'; continue }
|
|
37
|
-
let c: number, min: number
|
|
38
|
-
if (b < 0xE0) {
|
|
39
|
-
if (i >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
40
|
-
const b2 = buf[i++]!
|
|
41
|
-
if ((b2 & 0xC0) !== 0x80) { out += '\uFFFD'; continue }
|
|
42
|
-
c = ((b & 0x1F) << 6) | (b2 & 0x3F)
|
|
43
|
-
min = 0x80
|
|
44
|
-
} else if (b < 0xF0) {
|
|
45
|
-
if (i + 1 >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
46
|
-
const b2 = buf[i++]!; const b3 = buf[i++]!
|
|
47
|
-
if (((b2 & 0xC0) !== 0x80) || ((b3 & 0xC0) !== 0x80)) { out += '\uFFFD'; continue }
|
|
48
|
-
c = ((b & 0x0F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)
|
|
49
|
-
min = 0x800
|
|
50
|
-
} else if (b < 0xF8) {
|
|
51
|
-
if (i + 2 >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
52
|
-
const b2 = buf[i++]!; const b3 = buf[i++]!; const b4 = buf[i++]!
|
|
53
|
-
if (((b2 & 0xC0) !== 0x80) || ((b3 & 0xC0) !== 0x80) || ((b4 & 0xC0) !== 0x80)) { out += '\uFFFD'; continue }
|
|
54
|
-
c = ((b & 0x07) << 18) | ((b2 & 0x3F) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F)
|
|
55
|
-
min = 0x10000
|
|
56
|
-
} else { out += fatal ? (() => { throw new TypeError('invalid utf-8 start') })() : '\uFFFD'; continue }
|
|
57
|
-
if (c < min || (c >= 0xD800 && c <= 0xDFFF) || c > 0x10FFFF) {
|
|
58
|
-
out += fatal ? (() => { throw new TypeError('invalid utf-8 codepoint') })() : '\uFFFD'; continue
|
|
59
|
-
}
|
|
60
|
-
if (c <= 0xFFFF) out += String.fromCharCode(c)
|
|
61
|
-
else { c -= 0x10000; out += String.fromCharCode(0xD800 | (c >> 10), 0xDC00 | (c & 0x3FF)) }
|
|
62
|
-
}
|
|
63
|
-
return out
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function _decodeUTF16(buf: Uint8Array, le: boolean, fatal: boolean): string {
|
|
67
|
-
const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
|
|
68
|
-
let out = ''
|
|
69
|
-
for (let i = 0; i + 1 < buf.length; i += 2) {
|
|
70
|
-
let c = dv.getUint16(i, le)
|
|
71
|
-
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
72
|
-
i += 2
|
|
73
|
-
if (i + 1 >= buf.length) {
|
|
74
|
-
out += fatal ? (() => { throw new TypeError('truncated surrogate pair') })() : '\uFFFD'; break
|
|
75
|
-
}
|
|
76
|
-
const c2 = dv.getUint16(i, le)
|
|
77
|
-
if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
|
|
78
|
-
out += String.fromCharCode(c, c2)
|
|
79
|
-
} else {
|
|
80
|
-
out += fatal ? (() => { throw new TypeError('invalid surrogate pair') })() : '\uFFFD'
|
|
81
|
-
i -= 2
|
|
82
|
-
}
|
|
83
|
-
} else if (c >= 0xDC00 && c <= 0xDFFF) {
|
|
84
|
-
out += fatal ? (() => { throw new TypeError('unexpected trailing surrogate') })() : '\uFFFD'
|
|
85
|
-
} else {
|
|
86
|
-
out += String.fromCharCode(c)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return out
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
class TextDecoderImpl<T extends _Label | undefined = _Label | undefined> {
|
|
93
|
-
_encoding: _Encoding
|
|
94
|
-
_fatal: boolean
|
|
95
|
-
_ignoreBOM: boolean
|
|
96
|
-
|
|
97
|
-
constructor(label?: T, options?: { fatal?: boolean, ignoreBOM?: boolean }) {
|
|
98
|
-
this._encoding = _normalizeLabel(label)
|
|
99
|
-
this._fatal = options?.fatal ?? false
|
|
100
|
-
this._ignoreBOM = options?.ignoreBOM ?? false
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
get encoding(): _Result<T> { return this._encoding as _Result<T> }
|
|
104
|
-
get fatal(): boolean { return this._fatal }
|
|
105
|
-
get ignoreBOM(): boolean { return this._ignoreBOM }
|
|
106
|
-
|
|
107
|
-
decode(buffer?: ArrayBufferView | ArrayBuffer | null): string {
|
|
108
|
-
if (!buffer) return ''
|
|
109
|
-
const arr = buffer instanceof Uint8Array ? buffer
|
|
110
|
-
: buffer instanceof ArrayBuffer ? new Uint8Array(buffer)
|
|
111
|
-
: new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
112
|
-
|
|
113
|
-
if (this._encoding === 'utf-8') {
|
|
114
|
-
return _decodeUTF8(arr, this._fatal)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const le = this._encoding === 'utf-16le'
|
|
118
|
-
let offset = 0
|
|
119
|
-
|
|
120
|
-
if (arr.length >= 2 && !this._ignoreBOM) {
|
|
121
|
-
const bomLo = le ? arr[0]! : arr[1]!
|
|
122
|
-
const bomHi = le ? arr[1]! : arr[0]!
|
|
123
|
-
const bom = (bomHi << 8) | bomLo
|
|
124
|
-
if (bom === 0xFEFF || bom === 0xFFFE) {
|
|
125
|
-
offset = 2
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return _decodeUTF16(arr.slice(offset), le, this._fatal)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
class TextEncoderImpl<T extends _Label | undefined = _Label | undefined> {
|
|
134
|
-
_encoding: _Encoding
|
|
135
|
-
|
|
136
|
-
constructor(label?: T) {
|
|
137
|
-
this._encoding = _normalizeLabel(label)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
get encoding(): _Result<T> { return this._encoding as _Result<T> }
|
|
141
|
-
|
|
142
|
-
encode(input?: string): Uint8Array<ArrayBuffer> {
|
|
143
|
-
if (!input) return new Uint8Array(0)
|
|
144
|
-
|
|
145
|
-
if (this._encoding === 'utf-8') {
|
|
146
|
-
const bytes: number[] = []
|
|
147
|
-
for (let i = 0; i < input.length; i++) {
|
|
148
|
-
let c = input.charCodeAt(i)
|
|
149
|
-
if (c < 0x80) { bytes.push(c) }
|
|
150
|
-
else if (c < 0x800) { bytes.push(0xC0 | (c >> 6), 0x80 | (c & 0x3F)) }
|
|
151
|
-
else if (c < 0xD800 || c >= 0xE000) { bytes.push(0xE0 | (c >> 12), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
|
|
152
|
-
else { i++; const c2 = input.charCodeAt(i); c = 0x10000 + ((c & 0x3FF) << 10) | (c2 & 0x3FF); bytes.push(0xF0 | (c >> 18), 0x80 | ((c >> 12) & 0x3F), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
|
|
153
|
-
}
|
|
154
|
-
return new Uint8Array(bytes)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const le = this._encoding === 'utf-16le'
|
|
158
|
-
const buf = new ArrayBuffer(input.length * 2)
|
|
159
|
-
const dv = new DataView(buf)
|
|
160
|
-
for (let i = 0; i < input.length; i++) dv.setUint16(i * 2, input.charCodeAt(i), le)
|
|
161
|
-
return new Uint8Array(buf)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (typeof globalThis.TextDecoder === 'undefined') {
|
|
166
|
-
globalThis.TextDecoder = TextDecoderImpl
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (typeof globalThis.TextEncoder === 'undefined') {
|
|
170
|
-
globalThis.TextEncoder = TextEncoderImpl
|
|
171
|
-
}
|
|
1
|
+
export {} // make this a module so declare global works
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
interface TextDecoder<T extends _Label | undefined = _Label | undefined> extends TextDecoderImpl<T> {}
|
|
5
|
+
var TextDecoder: typeof TextDecoderImpl
|
|
6
|
+
|
|
7
|
+
interface TextEncoder<T extends _Label | undefined = _Label | undefined> extends TextEncoderImpl<T> {}
|
|
8
|
+
var TextEncoder: typeof TextEncoderImpl
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const _labelMap = {
|
|
12
|
+
'utf-8': 'utf-8',
|
|
13
|
+
'utf8': 'utf-8',
|
|
14
|
+
'unicode-1-1-utf-8': 'utf-8',
|
|
15
|
+
'utf-16': 'utf-16le',
|
|
16
|
+
'utf-16le': 'utf-16le',
|
|
17
|
+
'utf-16be': 'utf-16be',
|
|
18
|
+
} as const
|
|
19
|
+
|
|
20
|
+
type _Label = keyof typeof _labelMap
|
|
21
|
+
type _Encoding = typeof _labelMap[_Label]
|
|
22
|
+
type _Result<T> = T extends _Label ? typeof _labelMap[T] : 'utf-8'
|
|
23
|
+
|
|
24
|
+
function _normalizeLabel<T extends _Label | undefined>(label: T): _Result<T> {
|
|
25
|
+
if (!label) return 'utf-8' as _Result<T>
|
|
26
|
+
const result = _labelMap[label.trim().toLowerCase() as _Label]
|
|
27
|
+
if (result) return result as _Result<T>
|
|
28
|
+
throw new RangeError(`The encoding label "${label}" is not supported`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function _decodeUTF8(buf: Uint8Array, fatal: boolean): string {
|
|
32
|
+
let out = ''
|
|
33
|
+
for (let i = 0; i < buf.length; ) {
|
|
34
|
+
const b = buf[i++]!
|
|
35
|
+
if (b < 0x80) { out += String.fromCharCode(b); continue }
|
|
36
|
+
if (b < 0xC0) { out += fatal ? (() => { throw new TypeError('unexpected continuation byte') })() : '\uFFFD'; continue }
|
|
37
|
+
let c: number, min: number
|
|
38
|
+
if (b < 0xE0) {
|
|
39
|
+
if (i >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
40
|
+
const b2 = buf[i++]!
|
|
41
|
+
if ((b2 & 0xC0) !== 0x80) { out += '\uFFFD'; continue }
|
|
42
|
+
c = ((b & 0x1F) << 6) | (b2 & 0x3F)
|
|
43
|
+
min = 0x80
|
|
44
|
+
} else if (b < 0xF0) {
|
|
45
|
+
if (i + 1 >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
46
|
+
const b2 = buf[i++]!; const b3 = buf[i++]!
|
|
47
|
+
if (((b2 & 0xC0) !== 0x80) || ((b3 & 0xC0) !== 0x80)) { out += '\uFFFD'; continue }
|
|
48
|
+
c = ((b & 0x0F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)
|
|
49
|
+
min = 0x800
|
|
50
|
+
} else if (b < 0xF8) {
|
|
51
|
+
if (i + 2 >= buf.length) { out += fatal ? (() => { throw new TypeError('incomplete utf-8') })() : '\uFFFD'; break }
|
|
52
|
+
const b2 = buf[i++]!; const b3 = buf[i++]!; const b4 = buf[i++]!
|
|
53
|
+
if (((b2 & 0xC0) !== 0x80) || ((b3 & 0xC0) !== 0x80) || ((b4 & 0xC0) !== 0x80)) { out += '\uFFFD'; continue }
|
|
54
|
+
c = ((b & 0x07) << 18) | ((b2 & 0x3F) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F)
|
|
55
|
+
min = 0x10000
|
|
56
|
+
} else { out += fatal ? (() => { throw new TypeError('invalid utf-8 start') })() : '\uFFFD'; continue }
|
|
57
|
+
if (c < min || (c >= 0xD800 && c <= 0xDFFF) || c > 0x10FFFF) {
|
|
58
|
+
out += fatal ? (() => { throw new TypeError('invalid utf-8 codepoint') })() : '\uFFFD'; continue
|
|
59
|
+
}
|
|
60
|
+
if (c <= 0xFFFF) out += String.fromCharCode(c)
|
|
61
|
+
else { c -= 0x10000; out += String.fromCharCode(0xD800 | (c >> 10), 0xDC00 | (c & 0x3FF)) }
|
|
62
|
+
}
|
|
63
|
+
return out
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function _decodeUTF16(buf: Uint8Array, le: boolean, fatal: boolean): string {
|
|
67
|
+
const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
|
|
68
|
+
let out = ''
|
|
69
|
+
for (let i = 0; i + 1 < buf.length; i += 2) {
|
|
70
|
+
let c = dv.getUint16(i, le)
|
|
71
|
+
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
72
|
+
i += 2
|
|
73
|
+
if (i + 1 >= buf.length) {
|
|
74
|
+
out += fatal ? (() => { throw new TypeError('truncated surrogate pair') })() : '\uFFFD'; break
|
|
75
|
+
}
|
|
76
|
+
const c2 = dv.getUint16(i, le)
|
|
77
|
+
if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
|
|
78
|
+
out += String.fromCharCode(c, c2)
|
|
79
|
+
} else {
|
|
80
|
+
out += fatal ? (() => { throw new TypeError('invalid surrogate pair') })() : '\uFFFD'
|
|
81
|
+
i -= 2
|
|
82
|
+
}
|
|
83
|
+
} else if (c >= 0xDC00 && c <= 0xDFFF) {
|
|
84
|
+
out += fatal ? (() => { throw new TypeError('unexpected trailing surrogate') })() : '\uFFFD'
|
|
85
|
+
} else {
|
|
86
|
+
out += String.fromCharCode(c)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return out
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
class TextDecoderImpl<T extends _Label | undefined = _Label | undefined> {
|
|
93
|
+
_encoding: _Encoding
|
|
94
|
+
_fatal: boolean
|
|
95
|
+
_ignoreBOM: boolean
|
|
96
|
+
|
|
97
|
+
constructor(label?: T, options?: { fatal?: boolean, ignoreBOM?: boolean }) {
|
|
98
|
+
this._encoding = _normalizeLabel(label)
|
|
99
|
+
this._fatal = options?.fatal ?? false
|
|
100
|
+
this._ignoreBOM = options?.ignoreBOM ?? false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get encoding(): _Result<T> { return this._encoding as _Result<T> }
|
|
104
|
+
get fatal(): boolean { return this._fatal }
|
|
105
|
+
get ignoreBOM(): boolean { return this._ignoreBOM }
|
|
106
|
+
|
|
107
|
+
decode(buffer?: ArrayBufferView | ArrayBuffer | null): string {
|
|
108
|
+
if (!buffer) return ''
|
|
109
|
+
const arr = buffer instanceof Uint8Array ? buffer
|
|
110
|
+
: buffer instanceof ArrayBuffer ? new Uint8Array(buffer)
|
|
111
|
+
: new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
112
|
+
|
|
113
|
+
if (this._encoding === 'utf-8') {
|
|
114
|
+
return _decodeUTF8(arr, this._fatal)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const le = this._encoding === 'utf-16le'
|
|
118
|
+
let offset = 0
|
|
119
|
+
|
|
120
|
+
if (arr.length >= 2 && !this._ignoreBOM) {
|
|
121
|
+
const bomLo = le ? arr[0]! : arr[1]!
|
|
122
|
+
const bomHi = le ? arr[1]! : arr[0]!
|
|
123
|
+
const bom = (bomHi << 8) | bomLo
|
|
124
|
+
if (bom === 0xFEFF || bom === 0xFFFE) {
|
|
125
|
+
offset = 2
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return _decodeUTF16(arr.slice(offset), le, this._fatal)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class TextEncoderImpl<T extends _Label | undefined = _Label | undefined> {
|
|
134
|
+
_encoding: _Encoding
|
|
135
|
+
|
|
136
|
+
constructor(label?: T) {
|
|
137
|
+
this._encoding = _normalizeLabel(label)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
get encoding(): _Result<T> { return this._encoding as _Result<T> }
|
|
141
|
+
|
|
142
|
+
encode(input?: string): Uint8Array<ArrayBuffer> {
|
|
143
|
+
if (!input) return new Uint8Array(0)
|
|
144
|
+
|
|
145
|
+
if (this._encoding === 'utf-8') {
|
|
146
|
+
const bytes: number[] = []
|
|
147
|
+
for (let i = 0; i < input.length; i++) {
|
|
148
|
+
let c = input.charCodeAt(i)
|
|
149
|
+
if (c < 0x80) { bytes.push(c) }
|
|
150
|
+
else if (c < 0x800) { bytes.push(0xC0 | (c >> 6), 0x80 | (c & 0x3F)) }
|
|
151
|
+
else if (c < 0xD800 || c >= 0xE000) { bytes.push(0xE0 | (c >> 12), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
|
|
152
|
+
else { i++; const c2 = input.charCodeAt(i); c = 0x10000 + ((c & 0x3FF) << 10) | (c2 & 0x3FF); bytes.push(0xF0 | (c >> 18), 0x80 | ((c >> 12) & 0x3F), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
|
|
153
|
+
}
|
|
154
|
+
return new Uint8Array(bytes)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const le = this._encoding === 'utf-16le'
|
|
158
|
+
const buf = new ArrayBuffer(input.length * 2)
|
|
159
|
+
const dv = new DataView(buf)
|
|
160
|
+
for (let i = 0; i < input.length; i++) dv.setUint16(i * 2, input.charCodeAt(i), le)
|
|
161
|
+
return new Uint8Array(buf)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof globalThis.TextDecoder === 'undefined') {
|
|
166
|
+
globalThis.TextDecoder = TextDecoderImpl
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (typeof globalThis.TextEncoder === 'undefined') {
|
|
170
|
+
globalThis.TextEncoder = TextEncoderImpl
|
|
171
|
+
}
|
package/lib/text-measure.ts
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import * as ffi from 'ffi'
|
|
2
|
-
import * as win from 'win'
|
|
3
|
-
import * as gui from 'gui'
|
|
4
|
-
|
|
5
|
-
function loadProc(lib: win.HMODULE, name: string): number {
|
|
6
|
-
const ptr = win.GetProcAddress(lib, name)
|
|
7
|
-
if (!ptr) throw new Error(`Cannot load ${name}`)
|
|
8
|
-
return ptr
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const user32 = win.LoadLibrary('user32.dll')
|
|
12
|
-
const gdi32 = win.LoadLibrary('gdi32.dll')
|
|
13
|
-
if (!user32 || !gdi32) throw new Error('Failed to load system DLLs')
|
|
14
|
-
const DrawTextW = loadProc(user32, 'DrawTextW')
|
|
15
|
-
const GetDC = loadProc(user32, 'GetDC')
|
|
16
|
-
const ReleaseDC = loadProc(user32, 'ReleaseDC')
|
|
17
|
-
const SelectObject = loadProc(gdi32, 'SelectObject')
|
|
18
|
-
|
|
19
|
-
const FFI_TYPE_UINT64 = ffi.FFI_TYPE_UINT64
|
|
20
|
-
const FFI_S32 = ffi.FFI_TYPE_SINT32
|
|
21
|
-
const FFI_PTR = ffi.FFI_TYPE_POINTER
|
|
22
|
-
|
|
23
|
-
export function measureText(hdc: number, text: string, maxWidth: number): { width: number; height: number } {
|
|
24
|
-
const textBuf = new TextEncoder('utf-16le').encode(text + '\0').buffer
|
|
25
|
-
const rect = new ArrayBuffer(16)
|
|
26
|
-
const dv = new DataView(rect)
|
|
27
|
-
dv.setInt32(8, maxWidth, true)
|
|
28
|
-
ffi.ffiCall(DrawTextW, [FFI_TYPE_UINT64, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [hdc, textBuf, -1, rect, gui.DrawTextFlag.CALCRECT], FFI_TYPE_UINT64)
|
|
29
|
-
return { width: dv.getInt32(8, true), height: dv.getInt32(12, true) }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function getButtonIdealSize(hwnd: gui.HWND): { width: number; height: number } {
|
|
33
|
-
const size = new ArrayBuffer(8)
|
|
34
|
-
gui.SendMessage(hwnd, gui.ButtonExtMsg.GETIDEALSIZE, 0, ffi.bufferPtr(size))
|
|
35
|
-
const dv = new DataView(size)
|
|
36
|
-
return { width: dv.getInt32(0, true), height: dv.getInt32(4, true) }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function measureTextForHwnd(hwnd: gui.HWND, text: string): { width: number; height: number } {
|
|
40
|
-
const hdc = ffi.ffiCall(GetDC, [FFI_TYPE_UINT64], [hwnd], FFI_TYPE_UINT64)
|
|
41
|
-
if (!hdc) return { width: 0, height: 0 }
|
|
42
|
-
const hFont = gui.SendMessage(hwnd, gui.WmMsg.GETFONT, 0, 0)
|
|
43
|
-
const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hdc, hFont], FFI_TYPE_UINT64) : 0
|
|
44
|
-
const result = measureText(hdc, text, 0)
|
|
45
|
-
if (hFont) ffi.ffiCall(SelectObject, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hdc, oldFont], FFI_TYPE_UINT64)
|
|
46
|
-
ffi.ffiCall(ReleaseDC, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32)
|
|
47
|
-
const wr = gui.GetWindowRect(hwnd)
|
|
48
|
-
const cr = gui.GetClientRect(hwnd)
|
|
49
|
-
if (wr && cr) {
|
|
50
|
-
result.width += (wr.right - wr.left) - (cr.right - cr.left)
|
|
51
|
-
result.height += (wr.bottom - wr.top) - (cr.bottom - cr.top)
|
|
52
|
-
}
|
|
53
|
-
return result
|
|
54
|
-
}
|
|
1
|
+
import * as ffi from 'ffi'
|
|
2
|
+
import * as win from 'win'
|
|
3
|
+
import * as gui from 'gui'
|
|
4
|
+
|
|
5
|
+
function loadProc(lib: win.HMODULE, name: string): number {
|
|
6
|
+
const ptr = win.GetProcAddress(lib, name)
|
|
7
|
+
if (!ptr) throw new Error(`Cannot load ${name}`)
|
|
8
|
+
return ptr
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const user32 = win.LoadLibrary('user32.dll')
|
|
12
|
+
const gdi32 = win.LoadLibrary('gdi32.dll')
|
|
13
|
+
if (!user32 || !gdi32) throw new Error('Failed to load system DLLs')
|
|
14
|
+
const DrawTextW = loadProc(user32, 'DrawTextW')
|
|
15
|
+
const GetDC = loadProc(user32, 'GetDC')
|
|
16
|
+
const ReleaseDC = loadProc(user32, 'ReleaseDC')
|
|
17
|
+
const SelectObject = loadProc(gdi32, 'SelectObject')
|
|
18
|
+
|
|
19
|
+
const FFI_TYPE_UINT64 = ffi.FFI_TYPE_UINT64
|
|
20
|
+
const FFI_S32 = ffi.FFI_TYPE_SINT32
|
|
21
|
+
const FFI_PTR = ffi.FFI_TYPE_POINTER
|
|
22
|
+
|
|
23
|
+
export function measureText(hdc: number, text: string, maxWidth: number): { width: number; height: number } {
|
|
24
|
+
const textBuf = new TextEncoder('utf-16le').encode(text + '\0').buffer
|
|
25
|
+
const rect = new ArrayBuffer(16)
|
|
26
|
+
const dv = new DataView(rect)
|
|
27
|
+
dv.setInt32(8, maxWidth, true)
|
|
28
|
+
ffi.ffiCall(DrawTextW, [FFI_TYPE_UINT64, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [hdc, textBuf, -1, rect, gui.DrawTextFlag.CALCRECT], FFI_TYPE_UINT64)
|
|
29
|
+
return { width: dv.getInt32(8, true), height: dv.getInt32(12, true) }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getButtonIdealSize(hwnd: gui.HWND): { width: number; height: number } {
|
|
33
|
+
const size = new ArrayBuffer(8)
|
|
34
|
+
gui.SendMessage(hwnd, gui.ButtonExtMsg.GETIDEALSIZE, 0, ffi.bufferPtr(size))
|
|
35
|
+
const dv = new DataView(size)
|
|
36
|
+
return { width: dv.getInt32(0, true), height: dv.getInt32(4, true) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function measureTextForHwnd(hwnd: gui.HWND, text: string): { width: number; height: number } {
|
|
40
|
+
const hdc = ffi.ffiCall(GetDC, [FFI_TYPE_UINT64], [hwnd], FFI_TYPE_UINT64)
|
|
41
|
+
if (!hdc) return { width: 0, height: 0 }
|
|
42
|
+
const hFont = gui.SendMessage(hwnd, gui.WmMsg.GETFONT, 0, 0)
|
|
43
|
+
const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hdc, hFont], FFI_TYPE_UINT64) : 0
|
|
44
|
+
const result = measureText(hdc, text, 0)
|
|
45
|
+
if (hFont) ffi.ffiCall(SelectObject, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hdc, oldFont], FFI_TYPE_UINT64)
|
|
46
|
+
ffi.ffiCall(ReleaseDC, [FFI_TYPE_UINT64, FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32)
|
|
47
|
+
const wr = gui.GetWindowRect(hwnd)
|
|
48
|
+
const cr = gui.GetClientRect(hwnd)
|
|
49
|
+
if (wr && cr) {
|
|
50
|
+
result.width += (wr.right - wr.left) - (cr.right - cr.left)
|
|
51
|
+
result.height += (wr.bottom - wr.top) - (cr.bottom - cr.top)
|
|
52
|
+
}
|
|
53
|
+
return result
|
|
54
|
+
}
|