xbintsc 0.5.37 → 0.5.41
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/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.js +23 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/deferred.d.ts +63 -0
- package/dist/src/driver/bundler/deferred.js +279 -0
- package/dist/src/driver/bundler/deferred.js.map +1 -0
- package/dist/src/driver/bundler/merge.js +214 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/html.js +98 -15
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +1 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +4 -3
- package/dist/src/extensions/gui/three.js +4 -3
- package/dist/src/extensions/gui/three.js.map +1 -1
- package/dist/tests/codegen/closures.test.js +7 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
- package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
- package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
- package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
- package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
- package/dist/tests/e2e/gui-perf.test.js +283 -0
- package/dist/tests/e2e/gui-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +169 -0
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl.test.js +4 -4
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
- package/dist/tests/e2e/url.test.d.ts +6 -0
- package/dist/tests/e2e/url.test.js +114 -0
- package/dist/tests/e2e/url.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +45 -10
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/api.md +28 -2
- package/doc/gui/canvas.md +110 -27
- package/doc/gui/known-issues.md +32 -10
- package/doc/gui/rendering.md +77 -0
- package/doc/gui/runtime.md +18 -3
- package/doc/gui/webgl.md +58 -29
- package/doc/gui-scripts.md +19 -19
- package/doc/gui.md +43 -9
- package/doc/implemented/fetch.md +5 -0
- package/doc/implemented/modules.md +13 -0
- package/doc/implemented/stdlib.md +17 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/api.md +25 -2
- package/doc/zh-CN/gui/canvas.md +95 -26
- package/doc/zh-CN/gui/known-issues.md +21 -4
- package/doc/zh-CN/gui/rendering.md +59 -0
- package/doc/zh-CN/gui/runtime.md +13 -3
- package/doc/zh-CN/gui/webgl.md +30 -8
- package/doc/zh-CN/gui-scripts.md +14 -13
- package/doc/zh-CN/gui.md +32 -8
- package/doc/zh-CN/implemented/fetch.md +4 -0
- package/doc/zh-CN/implemented/modules.md +10 -0
- package/doc/zh-CN/implemented/stdlib.md +15 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +3 -1
- package/runtime/ext_gui/canvas.cpp +135 -89
- package/runtime/ext_gui/canvas.h +116 -0
- package/runtime/ext_gui/canvas_clip.cpp +143 -0
- package/runtime/ext_gui/canvas_composite.cpp +241 -0
- package/runtime/ext_gui/canvas_coverage.cpp +241 -0
- package/runtime/ext_gui/canvas_gradient.cpp +41 -4
- package/runtime/ext_gui/canvas_image_data.cpp +4 -0
- package/runtime/ext_gui/canvas_internal.h +34 -9
- package/runtime/ext_gui/canvas_raster.cpp +207 -178
- package/runtime/ext_gui/canvas_shadow.cpp +161 -0
- package/runtime/ext_gui/canvas_stroke.cpp +37 -9
- package/runtime/ext_gui/canvas_style.cpp +59 -0
- package/runtime/ext_gui/canvas_text.cpp +140 -0
- package/runtime/ext_gui/css.h +7 -0
- package/runtime/ext_gui/css_sheet.cpp +22 -0
- package/runtime/ext_gui/document.cpp +25 -1
- package/runtime/ext_gui/document.h +8 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +16 -1
- package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
- package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
- package/runtime/ext_gui/dom_api_internal.h +36 -37
- package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
- package/runtime/ext_gui/dom_api_proto.cpp +18 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +29 -9
- package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
- package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
- package/runtime/ext_gui/gradient_values.cpp +12 -1
- package/runtime/ext_gui/gui.cpp +5 -0
- package/runtime/ext_gui/gui_canvas.cpp +4 -0
- package/runtime/ext_gui/gui_engine.h +32 -0
- package/runtime/ext_gui/gui_events.cpp +182 -58
- package/runtime/ext_gui/gui_media.cpp +3 -0
- package/runtime/ext_gui/image.cpp +69 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
- package/runtime/ext_gui/layout.cpp +4 -0
- package/runtime/ext_gui/paint.cpp +19 -0
- package/runtime/ext_gui/paint_background.cpp +18 -1
- package/runtime/ext_gui/perf.cpp +171 -0
- package/runtime/ext_gui/perf.h +127 -0
- package/runtime/ext_gui/renderer.cpp +109 -41
- package/runtime/ext_gui/renderer.h +33 -9
- package/runtime/ext_gui/renderer_image.cpp +135 -65
- package/runtime/ext_gui/renderer_internal.h +15 -3
- package/runtime/ext_gui/renderer_text.cpp +24 -12
- package/runtime/ext_gui/script.cpp +31 -0
- package/runtime/ext_gui/style.cpp +101 -30
- package/runtime/ext_gui/style.h +6 -3
- package/runtime/ext_gui/style_print.cpp +7 -1
- package/runtime/ext_gui/text.cpp +23 -4
- package/runtime/ext_gui/text.h +29 -0
- package/runtime/ext_gui/text_cache.cpp +118 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
- package/runtime/ext_gui/webgl.h +48 -146
- package/runtime/ext_gui/webgl_blit.cpp +12 -1
- package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
- package/runtime/ext_gui/webgl_buffer.cpp +59 -1
- package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
- package/runtime/ext_gui/webgl_clear.cpp +3 -0
- package/runtime/ext_gui/webgl_context.cpp +29 -3
- package/runtime/ext_gui/webgl_draw.cpp +75 -270
- package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
- package/runtime/ext_gui/webgl_draw_state.h +130 -0
- package/runtime/ext_gui/webgl_glsl.h +3 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
- package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
- package/runtime/ext_gui/webgl_msl.cpp +4 -0
- package/runtime/ext_gui/webgl_objects.h +148 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
- package/runtime/ext_gui/webgl_program_internal.h +35 -0
- package/runtime/ext_gui/webgl_shader.cpp +34 -36
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/runtime/rt.h +3 -0
- package/runtime/xt_fetch/async.inc +60 -0
- package/runtime/xt_url_object.c +463 -0
- package/src/codegen/generator/module.ts +22 -7
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/bundler/deferred.ts +351 -0
- package/src/driver/bundler/merge.ts +219 -2
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +100 -17
- package/src/extensions/gui/index.ts +1 -0
- package/src/extensions/gui/three.ts +4 -3
|
@@ -78,6 +78,7 @@ void WebGLContext::save_vertex_array() {
|
|
|
78
78
|
void WebGLContext::load_vertex_array(const WebGLVertexArray *array) {
|
|
79
79
|
for (int i = 0; i < kWebGLMaxAttribs; i++) attribs_[i] = array->attribs[i];
|
|
80
80
|
bound_element_ = array->element_buffer;
|
|
81
|
+
attribs_version_ += 1;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
void WebGLContext::bind_vertex_array(uint32_t id) {
|
|
@@ -238,6 +239,11 @@ bool WebGLContext::sampler_parameter(uint32_t id, int pname, int value) {
|
|
|
238
239
|
else if (pname == GL_TEXTURE_MAG_FILTER) record->mag_filter = value;
|
|
239
240
|
else if (pname == GL_TEXTURE_WRAP_S) record->wrap_s = value;
|
|
240
241
|
else if (pname == GL_TEXTURE_WRAP_T) record->wrap_t = value;
|
|
242
|
+
else if (pname == GL_TEXTURE_COMPARE_MODE) {
|
|
243
|
+
record->compare_mode = value == GL_COMPARE_REF_TO_TEXTURE;
|
|
244
|
+
} else if (pname == GL_TEXTURE_COMPARE_FUNC) {
|
|
245
|
+
record->compare_func = value;
|
|
246
|
+
}
|
|
241
247
|
if (record->gpu != nullptr && guidev::g_device != nullptr) {
|
|
242
248
|
SDL_ReleaseGPUSampler(guidev::g_device, record->gpu);
|
|
243
249
|
record->gpu = nullptr;
|
|
@@ -252,6 +258,10 @@ int WebGLContext::sampler_parameter_value(uint32_t id, int pname) {
|
|
|
252
258
|
if (pname == GL_TEXTURE_MAG_FILTER) return record->mag_filter;
|
|
253
259
|
if (pname == GL_TEXTURE_WRAP_S) return record->wrap_s;
|
|
254
260
|
if (pname == GL_TEXTURE_WRAP_T) return record->wrap_t;
|
|
261
|
+
if (pname == GL_TEXTURE_COMPARE_MODE) {
|
|
262
|
+
return record->compare_mode ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
|
|
263
|
+
}
|
|
264
|
+
if (pname == GL_TEXTURE_COMPARE_FUNC) return record->compare_func;
|
|
255
265
|
return 0;
|
|
256
266
|
}
|
|
257
267
|
|
|
@@ -270,6 +280,32 @@ SDL_GPUSampler *WebGLContext::sampler_gpu(WebGLSampler *record) {
|
|
|
270
280
|
/* A sampler object has no texture, so it cannot know how many levels exist;
|
|
271
281
|
* textures created by this engine always carry a full mip chain. */
|
|
272
282
|
info.max_lod = 1000.0f;
|
|
283
|
+
if (record->compare_mode) {
|
|
284
|
+
info.enable_compare = true;
|
|
285
|
+
switch (record->compare_func) {
|
|
286
|
+
case GL_NEVER:
|
|
287
|
+
info.compare_op = SDL_GPU_COMPAREOP_NEVER;
|
|
288
|
+
break;
|
|
289
|
+
case GL_LESS:
|
|
290
|
+
info.compare_op = SDL_GPU_COMPAREOP_LESS;
|
|
291
|
+
break;
|
|
292
|
+
case GL_EQUAL:
|
|
293
|
+
info.compare_op = SDL_GPU_COMPAREOP_EQUAL;
|
|
294
|
+
break;
|
|
295
|
+
case GL_GREATER:
|
|
296
|
+
info.compare_op = SDL_GPU_COMPAREOP_GREATER;
|
|
297
|
+
break;
|
|
298
|
+
case GL_NOTEQUAL:
|
|
299
|
+
info.compare_op = SDL_GPU_COMPAREOP_NOT_EQUAL;
|
|
300
|
+
break;
|
|
301
|
+
case GL_GEQUAL:
|
|
302
|
+
info.compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL;
|
|
303
|
+
break;
|
|
304
|
+
default:
|
|
305
|
+
info.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
273
309
|
record->gpu = SDL_CreateGPUSampler(guidev::g_device, &info);
|
|
274
310
|
return record->gpu;
|
|
275
311
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
#include "inline_svg.h"
|
|
17
17
|
#include "paint.h"
|
|
18
|
+
#include "perf.h"
|
|
18
19
|
#include "text.h"
|
|
19
20
|
|
|
20
21
|
static xt_value g_window_proto = XT_UNDEFINED;
|
|
@@ -72,10 +73,15 @@ static xt_value win_load_html(xt_value self, xt_value env, int32_t argc, xt_valu
|
|
|
72
73
|
xt_gui_window_viewport(win, &width, &height);
|
|
73
74
|
win->document->load(html, width, height);
|
|
74
75
|
win->geometry.dirty = 1;
|
|
76
|
+
win->present_dirty = 1;
|
|
75
77
|
/* Run the AOT-compiled `<script>` bodies now that the tree is parsed, so
|
|
76
78
|
* `document.getElementById(...)` resolves, then settle the first layout. */
|
|
77
79
|
xt_gui_run_scripts(win);
|
|
78
80
|
xt_gui_flush_dom(win);
|
|
81
|
+
/* The document was replaced, so the frame loop must reconcile the media
|
|
82
|
+
* and canvas tables with it on the next frame. `loadHTML` already flushed
|
|
83
|
+
* the style/layout, so this is a sync request, not a restyle. */
|
|
84
|
+
win->sync_dirty = 1;
|
|
79
85
|
}
|
|
80
86
|
xt_object_set(self, xt_string_from_cstr("__xt_gui_html"), xt_string_from_cstr(html.c_str()));
|
|
81
87
|
/* Painting the document is milestone M3b+; the parsed tree and computed
|
|
@@ -199,6 +205,7 @@ static xt_value win_set_background(xt_value self, xt_value env, int32_t argc, xt
|
|
|
199
205
|
win->background[1] = color.g;
|
|
200
206
|
win->background[2] = color.b;
|
|
201
207
|
win->background[3] = color.a;
|
|
208
|
+
win->present_dirty = 1;
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
xt_object_set(self, xt_string_from_cstr("__xt_gui_background"), text);
|
|
@@ -265,7 +272,10 @@ static xt_value win_advance(xt_value self, xt_value env, int32_t argc, xt_value
|
|
|
265
272
|
XtGuiWindow *win = xt_gui_window_from_this(self);
|
|
266
273
|
if (win == nullptr || win->document == nullptr) return XT_UNDEFINED;
|
|
267
274
|
double ms = argc > 0 ? xt_to_number(xt_arg(argc, argv, 0)) : 0.0;
|
|
268
|
-
if (win->document->advance(ms))
|
|
275
|
+
if (win->document->advance(ms)) {
|
|
276
|
+
win->geometry.dirty = 1;
|
|
277
|
+
win->present_dirty = 1;
|
|
278
|
+
}
|
|
269
279
|
return XT_UNDEFINED;
|
|
270
280
|
}
|
|
271
281
|
|
|
@@ -481,6 +491,51 @@ static xt_value win_stats(xt_value self, xt_value env, int32_t argc, xt_value *a
|
|
|
481
491
|
xt_number(win != nullptr ? (double)win->node_order.size() : 0));
|
|
482
492
|
xt_object_set(object, xt_string_from_cstr("listeners"),
|
|
483
493
|
xt_number(win != nullptr ? (double)win->node_listeners.size() : 0));
|
|
494
|
+
/* -- renderer counters (see `perf.h`) ---------------------------------- */
|
|
495
|
+
/* The `*Ms` values describe the last completed frame; every other counter is
|
|
496
|
+
* cumulative (diff two calls to get the work one frame did). */
|
|
497
|
+
const xtgui::PerfTimings &ms = xtgui::g_perf_last;
|
|
498
|
+
xt_object_set(object, xt_string_from_cstr("frameMs"), xt_number(ms.frame));
|
|
499
|
+
xt_object_set(object, xt_string_from_cstr("restyleMs"), xt_number(ms.restyle));
|
|
500
|
+
xt_object_set(object, xt_string_from_cstr("layoutMs"), xt_number(ms.layout));
|
|
501
|
+
xt_object_set(object, xt_string_from_cstr("paintMs"), xt_number(ms.paint));
|
|
502
|
+
xt_object_set(object, xt_string_from_cstr("uploadMs"), xt_number(ms.upload));
|
|
503
|
+
xt_object_set(object, xt_string_from_cstr("drawMs"), xt_number(ms.draw));
|
|
504
|
+
const xtgui::PerfCounters &counters = xtgui::g_perf_total;
|
|
505
|
+
auto setCounter = [&object](const char *name, uint64_t value) {
|
|
506
|
+
xt_object_set(object, xt_string_from_cstr(name), xt_number((double)value));
|
|
507
|
+
};
|
|
508
|
+
setCounter("frames", counters.frames);
|
|
509
|
+
setCounter("presents", counters.presents);
|
|
510
|
+
setCounter("exposes", counters.exposes);
|
|
511
|
+
setCounter("deferred", counters.deferred);
|
|
512
|
+
setCounter("starvedFrames", counters.starvedFrames);
|
|
513
|
+
setCounter("skippedFrames", counters.skippedFrames);
|
|
514
|
+
setCounter("restyles", counters.restyles);
|
|
515
|
+
setCounter("restyleNodes", counters.restyleNodes);
|
|
516
|
+
setCounter("rulesEvaluated", counters.rulesEvaluated);
|
|
517
|
+
setCounter("mediaEvaluated", counters.mediaEvaluated);
|
|
518
|
+
setCounter("layouts", counters.layouts);
|
|
519
|
+
setCounter("layoutBoxes", counters.layoutBoxes);
|
|
520
|
+
setCounter("textShapeCalls", counters.textShapeCalls);
|
|
521
|
+
setCounter("textShapeHits", counters.textShapeHits);
|
|
522
|
+
setCounter("textCacheBytes", xtgui::xt_text_cache_bytes());
|
|
523
|
+
setCounter("textCacheEntries", xtgui::xt_text_cache_entries());
|
|
524
|
+
setCounter("paints", counters.paints);
|
|
525
|
+
setCounter("paintOps", counters.paintOps);
|
|
526
|
+
setCounter("drawRuns", counters.drawRuns);
|
|
527
|
+
setCounter("drawCalls", counters.drawCalls);
|
|
528
|
+
setCounter("uploadSubmits", counters.uploadSubmits);
|
|
529
|
+
setCounter("vertices", counters.vertices);
|
|
530
|
+
setCounter("syncNodes", counters.syncNodes);
|
|
531
|
+
setCounter("transitionFrames", counters.transitionFrames);
|
|
532
|
+
setCounter("canvasDraws", counters.canvasDraws);
|
|
533
|
+
setCounter("canvasUploads", counters.canvasUploads);
|
|
534
|
+
setCounter("canvasUploadBytes", counters.canvasUploadBytes);
|
|
535
|
+
setCounter("webglDraws", counters.webglDraws);
|
|
536
|
+
setCounter("webglPasses", counters.webglPasses);
|
|
537
|
+
setCounter("webglPipelineMisses", counters.webglPipelineMisses);
|
|
538
|
+
setCounter("webglBufferUploadBytes", counters.webglBufferUploadBytes);
|
|
484
539
|
return object;
|
|
485
540
|
}
|
|
486
541
|
|
package/runtime/rt.h
CHANGED
|
@@ -305,6 +305,9 @@ xt_value xt_date_static(xt_value name, int32_t argc, xt_value *argv);
|
|
|
305
305
|
xt_value xt_regexp_ctor(int32_t argc, xt_value *argv);
|
|
306
306
|
|
|
307
307
|
/* -- node:url ------------------------------------------------------------- */
|
|
308
|
+
xt_value xt_url_ctor(int32_t argc, xt_value *argv);
|
|
309
|
+
/** Resolve a `fetch` reference to a filesystem path (file: URLs and relative paths). */
|
|
310
|
+
int xt_url_file_path(const char *url, char *out, size_t size);
|
|
308
311
|
xt_value xt_url_path_to_file_url(int32_t argc, xt_value *argv);
|
|
309
312
|
xt_value xt_url_file_url_to_path(int32_t argc, xt_value *argv);
|
|
310
313
|
|
|
@@ -201,6 +201,66 @@ static void xt_fetch_hop_complete(xt_async_job *job) {
|
|
|
201
201
|
|
|
202
202
|
/* Main thread: validate the current URL and queue one exchange. */
|
|
203
203
|
static void xt_fetch_start(xt_fetch_state *state) {
|
|
204
|
+
/* `file:` URLs and references with no scheme (a relative path) read a local
|
|
205
|
+
* file. This is what lets a compiled page load an asset from disk without an
|
|
206
|
+
* HTTP server; the response is built on this thread because a local read is
|
|
207
|
+
* already complete. */
|
|
208
|
+
char path[4096];
|
|
209
|
+
if (xt_url_file_path(state->url, path, sizeof(path))) {
|
|
210
|
+
if (strcmp(state->method, "GET") != 0 && strcmp(state->method, "HEAD") != 0) {
|
|
211
|
+
xt_fetch_state_reject(state, "fetch failed: file URLs only support GET or HEAD");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
FILE *file = fopen(path, "rb");
|
|
215
|
+
if (!file) {
|
|
216
|
+
xt_fetch_state_reject(state, "fetch failed: cannot read file");
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
size_t capacity = 0;
|
|
220
|
+
size_t length = 0;
|
|
221
|
+
char *body = NULL;
|
|
222
|
+
char chunk[16384];
|
|
223
|
+
for (;;) {
|
|
224
|
+
size_t count = fread(chunk, 1, sizeof(chunk), file);
|
|
225
|
+
if (count > 0) {
|
|
226
|
+
if (length + count + 1 > capacity) {
|
|
227
|
+
capacity = (length + count + 1) * 2;
|
|
228
|
+
char *grown = (char *)realloc(body, capacity);
|
|
229
|
+
if (!grown) {
|
|
230
|
+
free(body);
|
|
231
|
+
fclose(file);
|
|
232
|
+
xt_fetch_state_reject(state, "fetch failed");
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
body = grown;
|
|
236
|
+
}
|
|
237
|
+
memcpy(body + length, chunk, count);
|
|
238
|
+
length += count;
|
|
239
|
+
}
|
|
240
|
+
if (count < sizeof(chunk)) break;
|
|
241
|
+
}
|
|
242
|
+
fclose(file);
|
|
243
|
+
|
|
244
|
+
char href[4300];
|
|
245
|
+
if (path[0] == '/') {
|
|
246
|
+
snprintf(href, sizeof(href), "file://%s", path);
|
|
247
|
+
} else {
|
|
248
|
+
snprintf(href, sizeof(href), "file:///%s", path);
|
|
249
|
+
}
|
|
250
|
+
xt_value headers = xt_headers_new();
|
|
251
|
+
char lengthText[32];
|
|
252
|
+
snprintf(lengthText, sizeof(lengthText), "%zu", length);
|
|
253
|
+
xt_headers_set_raw(headers, "content-length", lengthText);
|
|
254
|
+
xt_headers_set_raw(headers, "content-type", "application/octet-stream");
|
|
255
|
+
size_t bodyLength = strcmp(state->method, "HEAD") == 0 ? 0 : length;
|
|
256
|
+
xt_value response = xt_response_new(headers, 200, "OK", href, body, bodyLength);
|
|
257
|
+
free(body);
|
|
258
|
+
xt_value promise = state->promise;
|
|
259
|
+
xt_fetch_state_free(state);
|
|
260
|
+
xt_promise_fulfill(promise, response);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
204
264
|
xt_fetch_url parsed;
|
|
205
265
|
if (xt_fetch_parse_url(state->url, &parsed) != 0) {
|
|
206
266
|
xt_fetch_state_reject(state, "Failed to parse URL");
|