From 2bea5634b618968593446f3ebf30f8f9a3cfc1b3 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 04:15:02 +0900 Subject: [PATCH 01/90] fix bug --- examples/basic/filechooser.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c index 2637f86f8..6a86f98ef 100644 --- a/examples/basic/filechooser.c +++ b/examples/basic/filechooser.c @@ -5,13 +5,17 @@ MwWidget window; MwWidget button; MwWidget mb; +#ifdef BUG MwBool fpicker_wait = MwFALSE; MwBool msgbox_wait = MwFALSE; +#endif void MWAPI ok(MwWidget handle, void* user, void* call) { (void)handle; (void)call; +#ifdef BUG msgbox_wait = MwFALSE; +#endif } void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { @@ -22,6 +26,7 @@ void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); MwAddUserHandler(mb, MwNcloseHandler, ok, mb); +#ifdef BUG msgbox_wait = MwTRUE; while(msgbox_wait) { @@ -29,6 +34,7 @@ void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { } fpicker_wait = MwFALSE; +#endif } void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { @@ -42,6 +48,7 @@ void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwSetText(fpicker, MwNbackground, MwGetInteger(fpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); +#ifdef BUG fpicker_wait = MwTRUE; while(fpicker_wait) { @@ -50,6 +57,7 @@ void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwDestroyWidget(fpicker); MwDestroyWidget(mb); +#endif } int main() { From 231df890c1e1f55e49747b76ceef56e68d066591 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 12:52:20 -0700 Subject: [PATCH 02/90] accidentally rounded MwU16 to MwU8 in color picker --- src/dialog/colorpicker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 95fc2838a..378b79603 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -127,8 +127,8 @@ static void color_picker_image_update(color_picker_t* picker) { if(hue < 0.0) { hue += 360; } - hsv_v.h = (MwU8)((hue) * (HSV_HUE_STEPS / 360.)); - hsv_v.s = (MwU8)((dist) * (HSV_SAT_MAX / 180.)); + hsv_v.h = (MwU16)((hue) * (HSV_HUE_STEPS / 360.)); + hsv_v.s = (MwU16)((dist) * (HSV_SAT_MAX / 180.)); picker->hue_table[n] = hsv_v; picker->hue_table[n].generated = 1; } From 73833b9e0632fdc990f921214a25dc9cde2dc33a Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 04:53:02 +0900 Subject: [PATCH 03/90] fix some colors --- examples/basic/colorpicker.c | 6 ++++-- examples/basic/filechooser.c | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index dbce7fe2b..d02e3576f 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -35,12 +35,14 @@ int main() { window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); - MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + MwSetText(window, MwNforeground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkForeground : MwDefaultForeground); button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); - MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + MwSetText(button, MwNforeground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkForeground : MwDefaultForeground); MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c index 6a86f98ef..6ad56369b 100644 --- a/examples/basic/filechooser.c +++ b/examples/basic/filechooser.c @@ -64,13 +64,11 @@ int main() { MwLibraryInit(); window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, - MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); - MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwDEFAULT, 640, 480, MwNtitle, "file chooser", NULL); button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "select file", NULL); - MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); From 2e9aca5d46de22027cdfb49f0f71d1027869db5e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:09:11 -0700 Subject: [PATCH 04/90] fix menu positioning under weston --- src/backend/wayland/wayland.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 839e9ac6f..087f48bb7 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -180,6 +180,9 @@ static void xdg_toplevel_configure(void* data, if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(width < 50) width = 50; if(height < 50) height = 50; + } else { + if(width < 1) width = 1; + if(height < 1) height = 1; } MwLLWaylandRegionInvalidate(self); @@ -281,7 +284,7 @@ static void setup_toplevel(MwLL r, int x, int y) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; @@ -524,7 +527,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; @@ -537,10 +540,10 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); xdg_positioner_set_anchor_rect( r->wayland.popup->xdg_positioner, - topmost_parent->wayland.x, topmost_parent->wayland.y, r->wayland.ww, r->wayland.wh); - xdg_positioner_set_offset( - r->wayland.popup->xdg_positioner, - r->wayland.x, r->wayland.y); + r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + // xdg_positioner_set_offset( + // r->wayland.popup->xdg_positioner, + // r->wayland.x, r->wayland.y); xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_GRAVITY_NONE); @@ -1120,6 +1123,9 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(w < 50) w = 50; if(h < 50) h = 50; + } else { + if(w < 1) w = 1; + if(h < 1) h = 1; } handle->wayland.ww = w; From 175827fd9b0bd588fed94d0f38fa627fe9e2f286 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:10:40 -0700 Subject: [PATCH 05/90] wayland: destroy popup surfaces at correct time --- src/backend/wayland/wayland.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 087f48bb7..34d2e1300 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -584,14 +584,13 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { /* Popup destroy function */ static void destroy_popup(MwLL r) { - MwLLWaylandBackbufferDestroy(&r->wayland); MwLLWaylandFramebufferDestroy(&r->wayland); - xdg_surface_destroy(r->wayland.popup->xdg_surface); - xdg_popup_destroy(r->wayland.popup->xdg_popup); + xdg_surface_destroy(r->wayland.popup->xdg_surface); + xdg_positioner_destroy(r->wayland.popup->xdg_positioner); wl_surface_destroy(r->wayland.framebuffer.surface); From 117fa9cf925f11dcb27e14252827bc0f3a594002 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 04:15:02 +0900 Subject: [PATCH 06/90] fix bug --- examples/basic/filechooser.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c index 2637f86f8..6a86f98ef 100644 --- a/examples/basic/filechooser.c +++ b/examples/basic/filechooser.c @@ -5,13 +5,17 @@ MwWidget window; MwWidget button; MwWidget mb; +#ifdef BUG MwBool fpicker_wait = MwFALSE; MwBool msgbox_wait = MwFALSE; +#endif void MWAPI ok(MwWidget handle, void* user, void* call) { (void)handle; (void)call; +#ifdef BUG msgbox_wait = MwFALSE; +#endif } void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { @@ -22,6 +26,7 @@ void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); MwAddUserHandler(mb, MwNcloseHandler, ok, mb); +#ifdef BUG msgbox_wait = MwTRUE; while(msgbox_wait) { @@ -29,6 +34,7 @@ void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { } fpicker_wait = MwFALSE; +#endif } void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { @@ -42,6 +48,7 @@ void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwSetText(fpicker, MwNbackground, MwGetInteger(fpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); +#ifdef BUG fpicker_wait = MwTRUE; while(fpicker_wait) { @@ -50,6 +57,7 @@ void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwDestroyWidget(fpicker); MwDestroyWidget(mb); +#endif } int main() { From b4545ed4e7b27bee997744c672a859910ab96928 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 12:52:20 -0700 Subject: [PATCH 07/90] accidentally rounded MwU16 to MwU8 in color picker --- src/dialog/colorpicker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 95fc2838a..378b79603 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -127,8 +127,8 @@ static void color_picker_image_update(color_picker_t* picker) { if(hue < 0.0) { hue += 360; } - hsv_v.h = (MwU8)((hue) * (HSV_HUE_STEPS / 360.)); - hsv_v.s = (MwU8)((dist) * (HSV_SAT_MAX / 180.)); + hsv_v.h = (MwU16)((hue) * (HSV_HUE_STEPS / 360.)); + hsv_v.s = (MwU16)((dist) * (HSV_SAT_MAX / 180.)); picker->hue_table[n] = hsv_v; picker->hue_table[n].generated = 1; } From 846bf551be6bcb649dc1b75c424d63b98bb9099b Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 04:53:02 +0900 Subject: [PATCH 08/90] fix some colors --- examples/basic/colorpicker.c | 6 ++++-- examples/basic/filechooser.c | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index dbce7fe2b..d02e3576f 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -35,12 +35,14 @@ int main() { window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); - MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + MwSetText(window, MwNforeground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkForeground : MwDefaultForeground); button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); - MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + MwSetText(button, MwNforeground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultDarkForeground : MwDefaultForeground); MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c index 6a86f98ef..6ad56369b 100644 --- a/examples/basic/filechooser.c +++ b/examples/basic/filechooser.c @@ -64,13 +64,11 @@ int main() { MwLibraryInit(); window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, - MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); - MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + MwDEFAULT, 640, 480, MwNtitle, "file chooser", NULL); button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "select file", NULL); - MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); From b02698b940c50b2275123642b8b25ba28d690181 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:09:11 -0700 Subject: [PATCH 09/90] fix menu positioning under weston --- src/backend/wayland/wayland.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 839e9ac6f..087f48bb7 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -180,6 +180,9 @@ static void xdg_toplevel_configure(void* data, if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(width < 50) width = 50; if(height < 50) height = 50; + } else { + if(width < 1) width = 1; + if(height < 1) height = 1; } MwLLWaylandRegionInvalidate(self); @@ -281,7 +284,7 @@ static void setup_toplevel(MwLL r, int x, int y) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; @@ -524,7 +527,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; @@ -537,10 +540,10 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); xdg_positioner_set_anchor_rect( r->wayland.popup->xdg_positioner, - topmost_parent->wayland.x, topmost_parent->wayland.y, r->wayland.ww, r->wayland.wh); - xdg_positioner_set_offset( - r->wayland.popup->xdg_positioner, - r->wayland.x, r->wayland.y); + r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + // xdg_positioner_set_offset( + // r->wayland.popup->xdg_positioner, + // r->wayland.x, r->wayland.y); xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_GRAVITY_NONE); @@ -1120,6 +1123,9 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(w < 50) w = 50; if(h < 50) h = 50; + } else { + if(w < 1) w = 1; + if(h < 1) h = 1; } handle->wayland.ww = w; From 892f9198abe362fdac0ab0e878035a24c92f64af Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:10:40 -0700 Subject: [PATCH 10/90] wayland: destroy popup surfaces at correct time --- src/backend/wayland/wayland.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 087f48bb7..34d2e1300 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -584,14 +584,13 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { /* Popup destroy function */ static void destroy_popup(MwLL r) { - MwLLWaylandBackbufferDestroy(&r->wayland); MwLLWaylandFramebufferDestroy(&r->wayland); - xdg_surface_destroy(r->wayland.popup->xdg_surface); - xdg_popup_destroy(r->wayland.popup->xdg_popup); + xdg_surface_destroy(r->wayland.popup->xdg_surface); + xdg_positioner_destroy(r->wayland.popup->xdg_positioner); wl_surface_destroy(r->wayland.framebuffer.surface); From 9246051de047dd10ffade7cd240c69714c535b85 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:31:37 -0700 Subject: [PATCH 11/90] new envs --- doc/ENV.md | 5 +++++ include/Mw/LowLevel.h | 11 ++++++++--- src/backend/wayland/wayland.c | 35 ++++++++++++++++++++++++----------- src/backend/x11.c | 30 ++++++++++++++++++++++-------- src/lowlevel.c | 18 +++++++++++++++--- 5 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 doc/ENV.md diff --git a/doc/ENV.md b/doc/ENV.md new file mode 100644 index 000000000..001c30113 --- /dev/null +++ b/doc/ENV.md @@ -0,0 +1,5 @@ +Platforms that support both X11 and Wayland (Linux, namely) support launching Milsko programs with following environment variables: + +- `MW_BACKEND`: set to either `wayland` or `x11` to force which display protocol Wayland uses +- `MW_FORCE_CSD`: set to force the wayland backend to use CSD instead of SSD +- `MW_LIGHT_THEME`/`MW_DARK_THEME`: set to have either wayland or x11 ignore the system's appearence settings and either just use light theme/dark theme. diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 6647672d9..8822f68ae 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -41,6 +41,11 @@ struct _MwLLCommon { MwBool supports_transparency; MwLLHandler handler; + +#if defined(USE_WAYLAND) || defined(USE_X11) + /* 0 = default, 1 = light, 2 = dark */ + int theme_override; +#endif }; struct _MwLLCommonColor { @@ -364,9 +369,9 @@ MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px); MWDECL void (*MwFLFontFree)(void* handle); #ifdef _WIN32 -MWDECL void *MwLL_winmmLib; -MWDECL long (__stdcall* MwLL_PFN_timeGetTime)(void); -MWDECL unsigned int (__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); +MWDECL void* MwLL_winmmLib; +MWDECL long(__stdcall* MwLL_PFN_timeGetTime)(void); +MWDECL unsigned int(__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); #endif #ifdef __cplusplus diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 34d2e1300..6d34e4913 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -942,11 +942,13 @@ static void dark_theme_listener(MwLL handle, MwU32 new_value) { static void detect_dark_theme(MwLL handle) { MwU32 value = 0; - MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - handle->wayland.dark_theme = (value == 1) ? 1 : 0; - - MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - + if(handle->common.theme_override != 0) { + handle->wayland.dark_theme = (handle->common.theme_override == 2) ? 1 : 0; + } else { + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + handle->wayland.dark_theme = (value == 1) ? 1 : 0; + MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); + } MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); } #endif @@ -1381,9 +1383,8 @@ static int MwLLPendingImpl(MwLL handle) { } #ifdef USE_DBUS - if(wl_call_tbl.has_dbus) { + if(wl_call_tbl.has_dbus || handle->common.theme_override == 0) { if(handle->wayland.dark_theme_detection) { - handle->wayland.dark_theme_detection = MwFALSE; detect_dark_theme(handle); MwLLDispatch(handle, draw, NULL); @@ -1907,10 +1908,22 @@ static void MwLLClipImpl(MwLL handle, MwRect* rect) { static int MwLLWaylandCallInitImpl(void) { #ifdef __linux__ - MwBool loadWayland = MwFALSE; - if(getenv("MILSKO_BACKEND")) { - loadWayland |= - (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); + MwBool loadWayland = MwFALSE; + char* milsko_backend_env = getenv("MILSKO_BACKEND"); + char* mw_backend_env = getenv("MW_BACKEND"); + + if(milsko_backend_env || mw_backend_env) { + if(milsko_backend_env) { + /* + * (deprecated since 1.5+ but we have no reason to ever remove the old variable. + * MW_BACKEND is just the one that's documented) + */ + printf("[WARNING] MILSKO_BACKEND env is deprecated, use MW_BACKEND instead.\n"); + loadWayland |= (strcmp(milsko_backend_env, "wayland") == 0); + } else { + loadWayland |= (strcmp(mw_backend_env, "wayland") == 0); + } + } else if(getenv("WAYLAND_DISPLAY")) { loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); } diff --git a/src/backend/x11.c b/src/backend/x11.c index cc4d22bcf..8b908e474 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -327,9 +327,12 @@ static XVisualInfo* get_visual_info(Display* display) { static void detect_dark_theme(MwLL handle) { MwU32 value = 0; MwU32 dark_theme = 0; - MwLLDBusPortalGet(&xsymtbl.dbus, &handle->x11.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - - dark_theme = (value == 1) ? 1 : 0; + if(handle->common.theme_override != 0) { + dark_theme = (handle->common.theme_override == 2) ? 1 : 0; + } else { + MwLLDBusPortalGet(&xsymtbl.dbus, &handle->x11.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + dark_theme = (value == 1) ? 1 : 0; + } MwLLDispatch(handle, dark_theme, &dark_theme); } @@ -652,7 +655,7 @@ static int MwLLPendingImpl(MwLL handle) { if(handle->x11.dark_theme_detection) { handle->x11.dark_theme_detection = MwFALSE; #ifdef USE_DBUS - if(xsymtbl.has_dbus) { + if(xsymtbl.has_dbus || handle->common.theme_override == 0) { detect_dark_theme(handle); MwLLDispatch(handle, draw, NULL); } @@ -1403,10 +1406,21 @@ static void MwLLClipImpl(MwLL handle, MwRect* rect) { } static int MwLLX11CallInitImpl(void) { - MwBool loadX11 = MwFALSE; - if(getenv("MILSKO_BACKEND")) { - loadX11 |= - (strcmp(getenv("MILSKO_BACKEND"), "x11") == 0); + MwBool loadX11 = MwFALSE; + char* milsko_backend_env = getenv("MILSKO_BACKEND"); + char* mw_backend_env = getenv("MW_BACKEND"); + + if(milsko_backend_env || mw_backend_env) { + if(milsko_backend_env) { + /* + * (deprecated since 1.5+ but we have no reason to ever remove the old variable. + * MW_BACKEND is just the one that's documented) + */ + printf("[WARNING] MILSKO_BACKEND env is deprecated, use MW_BACKEND instead.\n"); + loadX11 |= (strcmp(milsko_backend_env, "x11") == 0); + } else { + loadX11 |= (strcmp(mw_backend_env, "x11") == 0); + } } else if(getenv("DISPLAY")) { loadX11 |= (getenv("DISPLAY") != NULL); } diff --git a/src/lowlevel.c b/src/lowlevel.c index 2fe153563..32070d9e0 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -1,9 +1,9 @@ #include #ifdef _WIN32 -void *MwLL_winmmLib; -long (__stdcall* MwLL_PFN_timeGetTime)(void); -unsigned int (__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); +void* MwLL_winmmLib; +long(__stdcall* MwLL_PFN_timeGetTime)(void); +unsigned int(__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); #endif MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height) = NULL; @@ -66,10 +66,22 @@ void (*MwLLRaise)(MwLL handle) = NULL; void (*MwLLClip)(MwLL handle, MwRect* rect) = NULL; void MwLLCreateCommon(MwLL handle) { +#if defined(USE_WAYLAND) || defined(USE_X11) + char* light_theme = getenv("MW_LIGHT_THEME"); + char* dark_theme = getenv("MW_DARK_THEME"); +#endif + handle->common.handler = malloc(sizeof(*handle->common.handler)); memset(handle->common.handler, 0, sizeof(*handle->common.handler)); handle->common.supports_transparency = 0; + +#if defined(USE_WAYLAND) || defined(USE_X11) + if(light_theme || dark_theme) { + handle->common.theme_override = (light_theme != NULL) ? 1 : ((dark_theme != NULL) ? 2 : 0); + } + +#endif } void MwLLDestroyCommon(MwLL handle) { From 292ffe1120a65a57f13b7576aa1132dbbbc0c7f9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 13:38:58 -0700 Subject: [PATCH 12/90] more robust mw_force_csd --- src/backend/wayland/wayland.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 6d34e4913..82c053eaf 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -171,10 +171,6 @@ static void xdg_toplevel_configure(void* data, if(width == 0 || height == 0) { width = self->wayland.ww; height = self->wayland.wh; - /* if it's still 0 then bail */ - if(width == 0 || height == 0) { - return; - } } if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { @@ -257,6 +253,7 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { /* Toplevel setup function */ static void setup_toplevel(MwLL r, int x, int y) { + char* mw_force_csd = getenv("MW_FORCE_CSD"); r->wayland.type = MwLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); r->wayland.x = x; @@ -284,7 +281,10 @@ static void setup_toplevel(MwLL r, int x, int y) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { + if(mw_force_csd != NULL) { + r->wayland.has_decorations = strcmp(mw_force_csd, "0") == 0; + r->wayland.do_csd = strcmp(mw_force_csd, "1") == 0; + } else if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; @@ -492,11 +492,12 @@ struct xdg_popup_listener popup_listener = { /* Popup setup function */ static void setup_popup(MwLL r, int x, int y, MwLL parent) { - MwLL topmost_parent = r->wayland.parent; - r->wayland.type = MwLL_WAYLAND_POPUP; - r->wayland.x = x; - r->wayland.y = y; - r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); + char* mw_force_csd = getenv("MW_FORCE_CSD"); + MwLL topmost_parent = r->wayland.parent; + r->wayland.type = MwLL_WAYLAND_POPUP; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); if(parent) { MwWidget p = parent->common.user; @@ -527,7 +528,10 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { } /* check now if we have decorations so that everything else can act accordingly */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL && getenv("MW_FORCE_CSD") == NULL) { + if(mw_force_csd != NULL) { + r->wayland.has_decorations = strcmp(mw_force_csd, "0") == 0; + r->wayland.do_csd = strcmp(mw_force_csd, "1") == 0; + } else if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { r->wayland.has_decorations = MwTRUE; } else { r->wayland.do_csd = MwTRUE; From 77e652cddccb5571e59bd18d6930d833485ef98b Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 06:34:35 +0900 Subject: [PATCH 13/90] improve checkbox --- src/abstract/directory.c | 12 ++++++------ src/core.c | 8 ++++---- src/draw.c | 6 +++--- src/string.c | 6 ++---- src/widget/checkbox.c | 40 ++++++++++++++++++++++++++++++++++++---- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/abstract/directory.c b/src/abstract/directory.c index ddf10e15f..3fbc2354f 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -19,8 +19,8 @@ typedef struct dir { void* MwDirectoryOpen(const char* path) { dir_t* dir = malloc(sizeof(*dir)); - char * p; - if(!dir) { + char* p; + if(!dir) { printf("Out Of Memory\n"); return NULL; } @@ -70,15 +70,15 @@ MwDirectoryEntry* MwDirectoryRead(void* handle) { dir_t* dir = handle; MwDirectoryEntry* entry = malloc(sizeof(*entry)); #ifdef _WIN32 - ULARGE_INTEGER* l; + ULARGE_INTEGER* l; #elif defined(CLASSIC_MAC_OS) #else - struct dirent* d; + struct dirent* d; struct stat s; char* p; #endif - - if(!entry) { + + if(!entry) { printf("Out Of Memory\n"); return NULL; } diff --git a/src/core.c b/src/core.c index c27b1a60f..318092249 100644 --- a/src/core.c +++ b/src/core.c @@ -1090,14 +1090,14 @@ int MwLibraryInit(void) { int i; #ifdef _WIN32 - /* + /* There's no Windows configuration that Milsko supports that doesn't have winmm. However, uhh, Visual Studio 2022. For some fucking reason. Thanks for coming to my TED Talk. */ - MwLL_winmmLib = LoadLibrary("winmm.dll"); - MwLL_PFN_timeGetTime = (void *)GetProcAddress(MwLL_winmmLib, "timeGetTime"); - MwLL_PFN_timeBeginPeriod = (void *)GetProcAddress(MwLL_winmmLib, "timeBeginPeriod"); + MwLL_winmmLib = LoadLibrary("winmm.dll"); + MwLL_PFN_timeGetTime = (void*)GetProcAddress(MwLL_winmmLib, "timeGetTime"); + MwLL_PFN_timeBeginPeriod = (void*)GetProcAddress(MwLL_winmmLib, "timeBeginPeriod"); MwLL_PFN_timeBeginPeriod(10); #endif diff --git a/src/draw.c b/src/draw.c index 2314c0281..c6de78f3f 100644 --- a/src/draw.c +++ b/src/draw.c @@ -124,7 +124,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; - unsigned char* data = malloc(sz*2); + unsigned char* data = malloc(sz * 2); MwRect r = *rect; if(!data) { return; @@ -952,8 +952,8 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { } } - rgb = malloc(row * col * 4); - comp = malloc(cpp + 1); + rgb = malloc(row * col * 4); + comp = malloc(cpp + 1); if(!rgb || !comp) { printf("Null malloc! Out of memory?"); return NULL; diff --git a/src/string.c b/src/string.c index c894b9a5e..579c57ec5 100644 --- a/src/string.c +++ b/src/string.c @@ -2,7 +2,7 @@ char* MwStringDuplicate(const char* str) { int sz = strlen(str) + 1; - char* r = malloc(sz); + char* r = malloc(sz); if(!r) { printf("Out Of Memory\n"); return NULL; @@ -19,7 +19,7 @@ char* MwStringDuplicate(const char* str) { char* MwStringConcat(const char* str1, const char* str2) { int sz = strlen(str1) + strlen(str2) + 1; - char* r = malloc(sz); + char* r = malloc(sz); if(!r) { printf("Out Of Memory\n"); return NULL; @@ -64,8 +64,6 @@ void MwStringTime(char* out, time_t t) { struct tm* tm = localtime(&t); const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - - if(tm == NULL) { #if defined(_MSC_VER) && (_MSC_VER >= 1400) sprintf_s(out, 255, "localtime error"); diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index f196954d3..8e65dc076 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -10,8 +10,10 @@ static int wcreate(MwWidget handle) { static void draw(MwWidget handle) { MwRect r; - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor base2 = MwParseColor(handle, MwGetText(handle, MwNsubBackground)); + MwLLColor text2 = MwParseColor(handle, MwGetText(handle, MwNsubForeground)); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); r.x = 0; r.y = 0; @@ -27,12 +29,42 @@ static void draw(MwWidget handle) { r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; - MwDrawWidgetBack(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0, MwDEFAULT); + MwDrawFrame(handle, &r, base, 1); + MwDrawRect(handle, &r, base2); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); if(handle->pressed || MwGetInteger(handle, MwNchecked)) { - /* TODO: write check mark */ + MwPoint p[6]; + int gap_w = r.width / 4 / 3; + int gap_h = r.height / 4 / 3; + + r.x += gap_w; + r.y += gap_h; + r.width -= gap_w * 2; + r.height -= gap_h * 2; + + p[0].x = r.x; + p[0].y = r.y + r.height * 2 / 3; + + p[1].x = r.x + r.width / 3; + p[1].y = r.y + r.height; + + p[2].x = r.x + r.width; + p[2].y = r.y + r.height / 3; + + p[3] = p[2]; + p[3].y -= r.height / 3; + + p[4] = p[1]; + p[4].y -= r.height / 3; + + p[5] = p[0]; + p[5].y -= r.height / 3; + + MwLLPolygon(handle->lowlevel, p, 6, text2); } + MwLLFreeColor(text2); + MwLLFreeColor(base2); MwLLFreeColor(base); } From eb1db3a5e97aa1c115a2a3e22bde341c261774c5 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 06:45:45 +0900 Subject: [PATCH 14/90] fix MwDirectoryOpen --- src/abstract/directory.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/abstract/directory.c b/src/abstract/directory.c index 3fbc2354f..977f2f510 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -25,13 +25,15 @@ void* MwDirectoryOpen(const char* path) { return NULL; } #ifdef _WIN32 - p = MwStringDuplicate(path); + p = malloc(strlen(path) + 2 + 1); + + strcpy(p, path); if(strchr(path, '/') != NULL) { - MwStringConcat(p, "/"); + strcat(p, "/"); } else { - MwStringConcat(p, "\\"); + strcat(p, "\\"); } - MwStringConcat(p, "*"); + strcat(p, "*"); if((dir->hFind = FindFirstFile(p, &dir->ffd)) == INVALID_HANDLE_VALUE) { free(p); free(dir); From 806ce3b8643007510608bee2c15ee20e975f0157 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 16:22:43 -0700 Subject: [PATCH 15/90] radioboxes --- examples/basic/periodic.c | 3 +- include/Mw/Draw.h | 11 ++++ include/Mw/TypeDefs.h | 1 + src/draw.c | 103 ++++++++++++++++++++++++++++++++++++-- src/widget/radiobox.c | 75 ++++++++++++++++++++------- 5 files changed, 170 insertions(+), 23 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index 92dab70a3..b449f0950 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -237,8 +237,7 @@ int main() { sprintf(buf, "%sBox %d", i == 0 ? "Check" : "Radio", j + 1); MwVaCreateWidget(MwLabelClass, "label", b, 0, 0, 0, 0, MwNtext, buf, - MwNalignment, MwALIGNMENT_BEGINNING, - NULL); + MwNalignment, MwALIGNMENT_BEGINNING, MwNdisabled, (j == 5) ? 1 : 0, NULL); } } diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index deefe0fce..443835c77 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -187,6 +187,17 @@ MWDECL MwLLPixmap MWAPI MwLoadIcon(MwWidget handle, MwU32* data); */ MWDECL void MWAPI MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert); +/*! + * @brief Draws a circle + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param color Background to fade to; widget background used if NULL + * @param filled Fill the circle or not + * @param outward + */ +MWDECL void MWAPI MwDrawCircle(MwWidget handle, MwRect* rect, MwLLColor color, MwLLColor background, int filled); + /* text.c */ /*! diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index ad072a343..a9bc3cf90 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -92,6 +92,7 @@ struct _MwWidget { MwPoint mouse_point; int close; int prop_event; + int held; void* internal; void* opaque; diff --git a/src/draw.c b/src/draw.c index 2314c0281..c7869e0fe 100644 --- a/src/draw.c +++ b/src/draw.c @@ -124,7 +124,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; - unsigned char* data = malloc(sz*2); + unsigned char* data = malloc(sz * 2); MwRect r = *rect; if(!data) { return; @@ -303,6 +303,103 @@ void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwLLFreeColor(darker); } +void MwDrawCircle(MwWidget handle, MwRect* rect, MwLLColor color, MwLLColor background, int filled) { + MwLLPixmap pixmap; + int width = rect->width; + int height = rect->height; + unsigned long sz = (unsigned long)width * height * 4; + unsigned char* data; + double cx, cy, rx, ry; + int border; + int x, y; + int ColorDiff = (get_color_diff(handle)); + MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor base = MwLightenColor(handle, color, 0, 0, 0); + + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + color_set_disabled_if_disabled(handle, base); + + if(width <= 0 || height <= 0) return; + + data = malloc(sz); + if(!data) return; + memset(data, 0, sz); + + cx = width / 2.0; + cy = height / 2.0; + rx = width / 2.0; + ry = height / 2.0; + border = filled ? 0 : MwDefaultBorderWidth(handle); + + for(y = 0; y < height; y++) { + for(x = 0; x < width; x++) { + double nx = (x + 0.5 - cx) / rx; + double ny = (y + 0.5 - cy) / ry; + double dist = nx * nx + ny * ny; + int inside; + double inx = (x + 0.5 - cx) / (rx - border); + double iny = (y + 0.5 - cy) / (ry - border); + double innerDist = inx * inx + iny * iny; + if(filled) { + inside = dist <= 1.0; + } else if(rx > border && ry > border) { + inside = dist <= 1.0 && innerDist > 1.0; + } else { + inside = dist <= 1.0; + } + + if(inside) { + MwLLColor mixColor; + MwLLColor c = background ? background : (handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground))); + double mod; + unsigned char* pout = &data[(y * width + x) * 4]; + + if(MwGetInteger(handle, MwNdarkTheme)) { + mixColor = MwLightenColor(handle, base, -ColorDiff, -ColorDiff, -ColorDiff); + } else { + mixColor = MwLightenColor(handle, base, ColorDiff, ColorDiff, ColorDiff); + } + + if(MwGetInteger(handle, MwNdisabled)) { + mod = (innerDist * 2.) - 1; + } else { + mod = (innerDist / 2.) + 0.5; + } + color_set_disabled_if_disabled(handle, mixColor); + + if(c != NULL) { + mixColor->common.red = (MwU8)(mixColor->common.red + (c->common.red - mixColor->common.red) * mod); + mixColor->common.green = (MwU8)(mixColor->common.green + (c->common.green - mixColor->common.green) * mod); + mixColor->common.blue = (MwU8)(mixColor->common.blue + (c->common.blue - mixColor->common.blue) * mod); + MwLLColorUpdate(handle->lowlevel, mixColor, mixColor->common.red, mixColor->common.green, mixColor->common.blue); + + if(c != background) { + MwLLFreeColor(c); + } + } + + pout[0] = (MwU8)mixColor->common.red; + pout[1] = (MwU8)mixColor->common.green; + pout[2] = (MwU8)mixColor->common.blue; + + pout[3] = 255; + } + } + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, width, height); + MwLLDrawPixmap(handle->lowlevel, rect, pixmap); + MwLLDestroyPixmap(pixmap); + + MwLLFreeColor(lighter); + MwLLFreeColor(darker); + MwLLFreeColor(base); + + free(data); +}; + static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { MwPoint p[7]; int ColorDiff = get_color_diff(handle); @@ -952,8 +1049,8 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { } } - rgb = malloc(row * col * 4); - comp = malloc(cpp + 1); + rgb = malloc(row * col * 4); + comp = malloc(cpp + 1); if(!rgb || !comp) { printf("Null malloc! Out of memory?"); return NULL; diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index c93e054b4..193025936 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -30,7 +30,37 @@ static void draw(MwWidget handle) { r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; - MwDrawDiamond(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0); + if(MwGetInteger(handle, MwNmodernLook) == 1) { + int is_checked = (handle->pressed || MwGetInteger(handle, MwNchecked)); + MwLLColor darker; + MwLLColor inner; + MwLLColor innerunsel = base; + + if(MwGetInteger(handle, MwNdarkTheme) == 1) { + darker = MwLLAllocColor(handle->lowlevel, 255, 255, 255); + innerunsel = MwLightenColor(handle, base, 80, 80, 80); + inner = darker; + } else { + darker = MwLLAllocColor(handle->lowlevel, 0, 0, 0); + inner = MwLightenColor(handle, is_checked ? darker : base, -80, -80, -80); + } + MwDrawCircle(handle, &r, darker, NULL, 1); + + if(!MwGetInteger(handle, MwNdisabled)) { + r.x += 2; + r.y += 2; + r.width -= 4; + r.height -= 4; + if(!is_checked) { + MwDrawCircle(handle, &r, innerunsel, innerunsel, 1); + } else { + MwDrawCircle(handle, &r, inner, innerunsel, 1); + } + } + MwLLFreeColor(darker); + } else { + MwDrawDiamond(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0); + } MwLLFreeColor(base); } @@ -49,29 +79,38 @@ static void click(MwWidget handle) { MwDispatchUserHandler(handle, MwNchangedHandler, NULL); } +static void mouse_down(MwWidget handle, void* ptr) { + handle->held = 1; + MwForceRender2(handle, ptr); +} + +static void mouse_up(MwWidget handle, void* ptr) { + handle->held = 0; + MwForceRender2(handle, ptr); +} static void prop_change(MwWidget handle, const char* key) { if(strcmp(key, MwNchecked) == 0) MwForceRender(handle); } MwClassRec MwRadioBoxClassRec = { - wcreate, /* create */ - NULL, /* destroy */ - draw, /* draw */ - click, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - MwForceRender2, /* mouse_up */ - MwForceRender2, /* mouse_down */ - NULL, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, /* props_change */ + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + mouse_up, /* mouse_up */ + mouse_down, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ NULL, NULL, NULL}; From 5479cb3e307333bb82594fc44159f5e763f29e88 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 18:05:42 -0700 Subject: [PATCH 16/90] fix for hyprland that should go away very quickly --- CMakeLists.txt | 5 +- include/Mw/LowLevel/Wayland.h | 7 + pl/rules.pl | 4 +- src/backend/wayland/hyprland.c | 60 ++++++ src/backend/wayland/interfaces.c | 8 +- src/draw.c | 353 ++++++++++++++++++++++++------- 6 files changed, 358 insertions(+), 79 deletions(-) create mode 100644 src/backend/wayland/hyprland.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5441692f9..d072daf3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,6 +269,7 @@ if(MW_USE_WAYLAND) src/backend/cairo.c src/backend/wayland/wayland.c src/backend/wayland/buffer.c + src/backend/wayland/hyprland.c src/backend/wayland/interfaces.c src/backend/wayland/region.c ) @@ -331,7 +332,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") ) list(APPEND LIBRARIES gdi32 ole32 uuid) if(NOT MSVC) - target_link_options( + target_link_options( Mw PRIVATE -static-libgcc @@ -468,7 +469,7 @@ if(MW_BUILD_VULKAN) check_include_files(vulkan/VULKAN.h HAS_VK_HEADER) if(HAS_VK_HEADER) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE MW_VULKAN diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index ccd1f2f0f..0f570e327 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -454,6 +454,8 @@ struct _MwLLWayland { MwU64 next_elapsed; long start_time; long end_time; + + MwBool on_hyprland; }; struct _MwLLWaylandColor { @@ -479,6 +481,11 @@ void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); void MwLLWaylandRegionSetup(MwLL handle); void MwLLWaylandRegionInvalidate(MwLL handle); +int MwLLWaylandDoRoundness(MwLL handle); + +/* Reads the "roundness" value out of ~/.config/hypr/hyprland.lua, or returns `fallback` if unavailable. */ +int MwLLWaylandHyprlandGetRoundness(void); + void MwLLWaylandHangUntilConfigured(MwLL handle); MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); diff --git a/pl/rules.pl b/pl/rules.pl index 89f13e93a..80f930d9f 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,6 +49,7 @@ if (grep(/^wayland$/, @backends)) { new_object("src/backend/cairo.c"); new_object("src/backend/wayland/wayland.c"); new_object("src/backend/wayland/buffer.c"); + new_object("src/backend/wayland/hyprland.c"); new_object("src/backend/wayland/interfaces.c"); new_object("src/backend/wayland/region.c"); @@ -66,8 +67,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - scan_wayland_protocol_from_file("wlr-layer-shell", - "wlr-layer-shell-unstable-v1.xml"); + scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; } diff --git a/src/backend/wayland/hyprland.c b/src/backend/wayland/hyprland.c new file mode 100644 index 000000000..e6c86790d --- /dev/null +++ b/src/backend/wayland/hyprland.c @@ -0,0 +1,60 @@ +#include + +int MwLLWaylandDoRoundness(MwLL handle) { + if(handle->common.type == MwLLBackendWayland) { + return handle->wayland.on_hyprland; + } else { + return 0; + }; +}; + +int MwLLWaylandHyprlandGetRoundness(void) { + char* home = getenv("HOME"); + int fallback = 20; + char path[PATH_MAX]; + int roundness = fallback; + char line[512]; + FILE* f = NULL; + + if(home == NULL) { + return fallback; + } + + snprintf(path, sizeof(path), "%s/.config/hypr/hyprland.lua", home); + + f = fopen(path, "r"); + if(f == NULL) { + return fallback; + } + + while(fgets(line, sizeof(line), f) != NULL) { + char* key = strstr(line, "roundness"); + char* eq; + char* end; + long value; + + if(key == NULL) { + continue; + } + + eq = strchr(key, '='); + if(eq == NULL) { + continue; + } + eq++; + + while(*eq != '\0' && isspace((unsigned char)*eq)) { + eq++; + } + + value = strtol(eq, &end, 10); + if(end == eq) { + continue; + } + + roundness = (int)value; + } + + fclose(f); + return roundness; +} diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 84ed4923d..a72459122 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -40,15 +40,19 @@ static void new_protocol(void* data, struct wl_registry* registry, MwLL self = data; (void)version; (void)registry; + wayland_protocol_callback_table_t* cb; WAYLAND_EVENT_OP_START(self); - wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); + cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data, version)); - /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { + /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ self->common.supports_transparency = MwTRUE; + } else if(strstr(interface, "hyprland") != NULL) { + /* we have nothing to make use of with hyprland, we just want to check if we're running under it. */ + self->wayland.on_hyprland = MwTRUE; } else { // printf("unknown interface %s\n", interface); } diff --git a/src/draw.c b/src/draw.c index c7869e0fe..19b4081ab 100644 --- a/src/draw.c +++ b/src/draw.c @@ -53,6 +53,105 @@ static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { } }; +/* Whether (x, y) within a w*h rect falls inside a rounded-rect mask of the + * given corner radius. Shared by every raster-based rounded fill below so + * they all cut the same corner shape. */ +static int rounded_rect_contains(int x, int y, int w, int h, int rad) { + int cx = -1; + int cy = -1; + + if(x < rad && y < rad) { + cx = rad; + cy = rad; + } else if(x >= w - rad && y < rad) { + cx = w - rad - 1; + cy = rad; + } else if(x < rad && y >= h - rad) { + cx = rad; + cy = h - rad - 1; + } else if(x >= w - rad && y >= h - rad) { + cx = w - rad - 1; + cy = h - rad - 1; + } + + if(cx < 0) { + return 1; + } + + { + int dx = x - cx; + int dy = y - cy; + return (dx * dx + dy * dy) <= rad * rad; + } +} + +static void fill_rect(MwWidget handle, MwRect* rect, MwLLColor color) { + MwPoint p[4]; + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width; + p[2].y = rect->y + rect->height; + + p[3].x = rect->x; + p[3].y = rect->y + rect->height; + + MwLLPolygon(handle->lowlevel, p, 4, color); +} + +/* Flat-colored rounded-rect fill, for backdrops that need to match a rounded + * border/fill's shape instead of a plain MwDrawRect square. */ +static void fill_rect_rounded(MwWidget handle, MwRect* rect, MwLLColor color, int roundness) { + MwLLPixmap pixmap; + int x, y; + int w = rect->width; + int h = rect->height; + int rad = roundness; + unsigned char* data; + + if(w <= 0 || h <= 0) { + return; + } + + if(rad > w / 2) rad = w / 2; + if(rad > h / 2) rad = h / 2; + + if(rad <= 0) { + fill_rect(handle, rect, color); + return; + } + + data = malloc((unsigned long)w * h * 4); + if(!data) { + return; + } + + memset(data, 0, (unsigned long)w * h * 4); + + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + if(rounded_rect_contains(x, y, w, h, rad)) { + unsigned char* pout = &data[(y * w + x) * 4]; + + pout[0] = (unsigned char)color->common.red; + pout[1] = (unsigned char)color->common.green; + pout[2] = (unsigned char)color->common.blue; + pout[3] = 255; + } + } + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); + MwLLDrawPixmap(handle->lowlevel, rect, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); +} + void MwParseColorNoAllocate(const char* text, MwRGB* rgb) { if(text[0] == '#' && strlen(text) == 4) { rgb->red = hex(text + 1, 1); @@ -100,63 +199,104 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) } void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { - MwPoint p[4]; - - p[0].x = rect->x; - p[0].y = rect->y; - - p[1].x = rect->x + rect->width; - p[1].y = rect->y; - - p[2].x = rect->x + rect->width; - p[2].y = rect->y + rect->height; - - p[3].x = rect->x; - p[3].y = rect->y + rect->height; - - MwLLPolygon(handle->lowlevel, p, 4, color); + if(MwLLWaylandDoRoundness(handle->lowlevel)) { + fill_rect_rounded(handle, rect, color, MwLLWaylandHyprlandGetRoundness()); + } else { + fill_rect(handle, rect, color); + } } void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { - MwLLPixmap pixmap; - int y; - double darken = 0.; - int ColorDiff = get_color_diff(handle); - double darkenStep = (ColorDiff / 2.) / rect->height; - unsigned long sz = 1 * rect->height * 4; - unsigned char* data = malloc(sz * 2); - MwRect r = *rect; - if(!data) { - return; - } + MwLLPixmap pixmap; + int y; + double darken = 0.; + int ColorDiff = get_color_diff(handle); + MwRect r = *rect; + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; + if(rect->width <= 0 || rect->height <= 0) { - free(data); return; } - memset(data, 0, sz); r.x += 1; r.y += 1; r.width -= 2; r.height -= 2; - for(y = 0; y < rect->height; y++) { - MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); - int idx = y * 4; - color_set_disabled_if_disabled(handle, col); - data[idx] = col->common.red; - data[idx + 1] = col->common.green; - data[idx + 2] = col->common.blue; - data[idx + 3] = 255; - MwLLFreeColor(col); - darken += darkenStep; + if(r.width <= 0 || r.height <= 0) { + return; } - pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - MwLLDestroyPixmap(pixmap); + if(roundness <= 0) { + double darkenStep = (ColorDiff / 2.) / rect->height; + unsigned long sz = 1 * rect->height * 4; + unsigned char* data = malloc(sz * 2); + if(!data) { + return; + } + memset(data, 0, sz); - free(data); + for(y = 0; y < rect->height; y++) { + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); + int idx = y * 4; + color_set_disabled_if_disabled(handle, col); + data[idx] = col->common.red; + data[idx + 1] = col->common.green; + data[idx + 2] = col->common.blue; + data[idx + 3] = 255; + MwLLFreeColor(col); + darken += darkenStep; + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); + return; + } else { + int w = r.width; + int h = r.height; + int rad = roundness; + int x; + double darkenStep; + unsigned char* data; + + if(rad > w / 2) rad = w / 2; + if(rad > h / 2) rad = h / 2; + + darkenStep = (ColorDiff / 2.) / h; + data = malloc((unsigned long)w * h * 4); + if(!data) { + return; + } + memset(data, 0, (unsigned long)w * h * 4); + + for(y = 0; y < h; y++) { + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); + color_set_disabled_if_disabled(handle, col); + + for(x = 0; x < w; x++) { + if(rounded_rect_contains(x, y, w, h, rad)) { + unsigned char* pout = &data[(y * w + x) * 4]; + + pout[0] = (unsigned char)col->common.red; + pout[1] = (unsigned char)col->common.green; + pout[2] = (unsigned char)col->common.blue; + pout[3] = 255; + } + } + + MwLLFreeColor(col); + darken += darkenStep; + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); + } } void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -203,7 +343,8 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); if(c != NULL) { - MwDrawRect(handle, rect, c); + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; + fill_rect_rounded(handle, rect, c, MwGetInteger(handle, MwNmodernLook) ? roundness : 0); MwLLFreeColor(c); } } @@ -454,48 +595,113 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, rect->height -= border * 2; } -static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { - MwPoint p[7]; +#define FRAME_ARC_STEPS 6 + +/* Appends the points of an (up to) quarter-circle arc, sweeping from + * start_deg to end_deg (in degrees, either direction), to `points`. */ +static void frame_border_append_arc(MwPoint* points, int* count, int cx, int cy, int radius, double start_deg, double end_deg, int steps) { + int i; + for(i = 0; i <= steps; i++) { + double deg = start_deg + (end_deg - start_deg) * ((double)i / steps); + double rad = deg * M_PI / 180.0; + points[*count].x = cx + (int)(cos(rad) * radius); + points[*count].y = cy + (int)(sin(rad) * radius); + (*count)++; + } +} + +static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same, int roundness) { + MwPoint p[36]; + int n; + int x = rect->x; + int y = rect->y; + int w = rect->width; + int h = rect->height; + int r = roundness; + int ib, ir; (void)diff; (void)same; - p[0].x = rect->x; - p[0].y = rect->y; + if(r < 0) r = 0; + if(r > w / 2) r = w / 2; + if(r > h / 2) r = h / 2; - p[1].x = rect->x + rect->width; - p[1].y = rect->y; + if(r <= 0) { + p[0].x = x; + p[0].y = y; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + border; - p[3].x = rect->x + border; - p[3].y = rect->y + border; + p[1].x = x + w; + p[1].y = y; - p[4].x = rect->x + border; - p[4].y = rect->y + rect->height - border; + p[2].x = x + w - border; + p[2].y = y + border; + p[3].x = x + border; + p[3].y = y + border; - p[5].x = rect->x; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[4].x = x + border; + p[4].y = y + h - border; - p[0].x = rect->x + rect->width; - p[0].y = rect->y; + p[5].x = x; + p[5].y = y + h; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border; + p[0].x = x + w; + p[0].y = y; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border; + p[1].x = x + w - border; + p[1].y = y + border; - p[3].x = rect->x + border; - p[3].y = rect->y + rect->height - border; + p[2].x = x + w - border; + p[2].y = y + h - border; - p[4].x = rect->x; - p[4].y = rect->y + rect->height; + p[3].x = x + border; + p[3].y = y + h - border; - p[5].x = rect->x + rect->width; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[4].x = x; + p[4].y = y + h; + + p[5].x = x + w; + p[5].y = y + h; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + return; + } + + /* With rounded outer corners, each half still meets the other along + * the same two diagonals as the sharp-cornered version above, except + * the TR and BL corners (shared between both halves) are cut by an + * arc whose midpoint lies on that diagonal, and each half draws + * exactly one side of it. The TL/BR corners belong entirely to one + * half, so they get the full quarter-circle arc. + * + * The inner (border-offset) corners get the same treatment, using the + * same corner centers as the outer arcs but shrunk by the border + * width, so the border ring keeps a uniform thickness all the way + * around the curve instead of jumping to a sharp point. If the border + * is thicker than the roundness, this collapses back to the ordinary + * sharp inner corner (ib == border, ir == 0). */ + ib = (r > border) ? r : border; + ir = (r > border) ? (r - border) : 0; + + /* Top-left half: TL (full), TR (near side), BL (near side). */ + n = 0; + frame_border_append_arc(p, &n, x + r, y + r, r, 180, 270, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + w - r, y + r, r, 270, 315, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 270, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + ib, y + ib, ir, 270, 180, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 180, 135, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 180, FRAME_ARC_STEPS / 2); + MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); + + /* Bottom-right half: TR (far side), BL (far side), BR (full). */ + n = 0; + frame_border_append_arc(p, &n, x + w - r, y + r, r, 360, 315, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 360, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + h - ib, ir, 0, 90, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 90, 135, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 90, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - r, y + h - r, r, 90, 0, FRAME_ARC_STEPS); + MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); } static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { @@ -503,18 +709,19 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); MwRect r = *rect; + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; color_set_disabled_if_disabled(handle, darker); color_set_disabled_if_disabled(handle, lighter); - frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same); + frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same, roundness); if(border > 1) { r.x += border / 2; r.y += border / 2; r.width -= border; r.height -= border; - frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same); + frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same, roundness); } MwLLFreeColor(lighter); From fe17eefb215a8d2fb26b6b0599b25619a638a349 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 18:07:34 -0700 Subject: [PATCH 17/90] revert hyprland code --- src/backend/wayland/interfaces.c | 8 +- src/draw.c | 355 +++++++------------------------ 2 files changed, 76 insertions(+), 287 deletions(-) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index a72459122..84ed4923d 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -40,19 +40,15 @@ static void new_protocol(void* data, struct wl_registry* registry, MwLL self = data; (void)version; (void)registry; - wayland_protocol_callback_table_t* cb; WAYLAND_EVENT_OP_START(self); - cb = shget(self->wayland.wl_protocol_setup_map, interface); + wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data, version)); - } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ + } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { self->common.supports_transparency = MwTRUE; - } else if(strstr(interface, "hyprland") != NULL) { - /* we have nothing to make use of with hyprland, we just want to check if we're running under it. */ - self->wayland.on_hyprland = MwTRUE; } else { // printf("unknown interface %s\n", interface); } diff --git a/src/draw.c b/src/draw.c index 19b4081ab..c7869e0fe 100644 --- a/src/draw.c +++ b/src/draw.c @@ -53,105 +53,6 @@ static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { } }; -/* Whether (x, y) within a w*h rect falls inside a rounded-rect mask of the - * given corner radius. Shared by every raster-based rounded fill below so - * they all cut the same corner shape. */ -static int rounded_rect_contains(int x, int y, int w, int h, int rad) { - int cx = -1; - int cy = -1; - - if(x < rad && y < rad) { - cx = rad; - cy = rad; - } else if(x >= w - rad && y < rad) { - cx = w - rad - 1; - cy = rad; - } else if(x < rad && y >= h - rad) { - cx = rad; - cy = h - rad - 1; - } else if(x >= w - rad && y >= h - rad) { - cx = w - rad - 1; - cy = h - rad - 1; - } - - if(cx < 0) { - return 1; - } - - { - int dx = x - cx; - int dy = y - cy; - return (dx * dx + dy * dy) <= rad * rad; - } -} - -static void fill_rect(MwWidget handle, MwRect* rect, MwLLColor color) { - MwPoint p[4]; - - p[0].x = rect->x; - p[0].y = rect->y; - - p[1].x = rect->x + rect->width; - p[1].y = rect->y; - - p[2].x = rect->x + rect->width; - p[2].y = rect->y + rect->height; - - p[3].x = rect->x; - p[3].y = rect->y + rect->height; - - MwLLPolygon(handle->lowlevel, p, 4, color); -} - -/* Flat-colored rounded-rect fill, for backdrops that need to match a rounded - * border/fill's shape instead of a plain MwDrawRect square. */ -static void fill_rect_rounded(MwWidget handle, MwRect* rect, MwLLColor color, int roundness) { - MwLLPixmap pixmap; - int x, y; - int w = rect->width; - int h = rect->height; - int rad = roundness; - unsigned char* data; - - if(w <= 0 || h <= 0) { - return; - } - - if(rad > w / 2) rad = w / 2; - if(rad > h / 2) rad = h / 2; - - if(rad <= 0) { - fill_rect(handle, rect, color); - return; - } - - data = malloc((unsigned long)w * h * 4); - if(!data) { - return; - } - - memset(data, 0, (unsigned long)w * h * 4); - - for(y = 0; y < h; y++) { - for(x = 0; x < w; x++) { - if(rounded_rect_contains(x, y, w, h, rad)) { - unsigned char* pout = &data[(y * w + x) * 4]; - - pout[0] = (unsigned char)color->common.red; - pout[1] = (unsigned char)color->common.green; - pout[2] = (unsigned char)color->common.blue; - pout[3] = 255; - } - } - } - - pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); - MwLLDrawPixmap(handle->lowlevel, rect, pixmap); - MwLLDestroyPixmap(pixmap); - - free(data); -} - void MwParseColorNoAllocate(const char* text, MwRGB* rgb) { if(text[0] == '#' && strlen(text) == 4) { rgb->red = hex(text + 1, 1); @@ -199,104 +100,63 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) } void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { - if(MwLLWaylandDoRoundness(handle->lowlevel)) { - fill_rect_rounded(handle, rect, color, MwLLWaylandHyprlandGetRoundness()); - } else { - fill_rect(handle, rect, color); - } + MwPoint p[4]; + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width; + p[2].y = rect->y + rect->height; + + p[3].x = rect->x; + p[3].y = rect->y + rect->height; + + MwLLPolygon(handle->lowlevel, p, 4, color); } void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { - MwLLPixmap pixmap; - int y; - double darken = 0.; - int ColorDiff = get_color_diff(handle); - MwRect r = *rect; - int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; - - if(rect->width <= 0 || rect->height <= 0) { + MwLLPixmap pixmap; + int y; + double darken = 0.; + int ColorDiff = get_color_diff(handle); + double darkenStep = (ColorDiff / 2.) / rect->height; + unsigned long sz = 1 * rect->height * 4; + unsigned char* data = malloc(sz * 2); + MwRect r = *rect; + if(!data) { return; } + if(rect->width <= 0 || rect->height <= 0) { + free(data); + return; + } + memset(data, 0, sz); r.x += 1; r.y += 1; r.width -= 2; r.height -= 2; - if(r.width <= 0 || r.height <= 0) { - return; + for(y = 0; y < rect->height; y++) { + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); + int idx = y * 4; + color_set_disabled_if_disabled(handle, col); + data[idx] = col->common.red; + data[idx + 1] = col->common.green; + data[idx + 2] = col->common.blue; + data[idx + 3] = 255; + MwLLFreeColor(col); + darken += darkenStep; } - if(roundness <= 0) { - double darkenStep = (ColorDiff / 2.) / rect->height; - unsigned long sz = 1 * rect->height * 4; - unsigned char* data = malloc(sz * 2); - if(!data) { - return; - } - memset(data, 0, sz); + pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); - for(y = 0; y < rect->height; y++) { - MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); - int idx = y * 4; - color_set_disabled_if_disabled(handle, col); - data[idx] = col->common.red; - data[idx + 1] = col->common.green; - data[idx + 2] = col->common.blue; - data[idx + 3] = 255; - MwLLFreeColor(col); - darken += darkenStep; - } - - pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - MwLLDestroyPixmap(pixmap); - - free(data); - return; - } else { - int w = r.width; - int h = r.height; - int rad = roundness; - int x; - double darkenStep; - unsigned char* data; - - if(rad > w / 2) rad = w / 2; - if(rad > h / 2) rad = h / 2; - - darkenStep = (ColorDiff / 2.) / h; - data = malloc((unsigned long)w * h * 4); - if(!data) { - return; - } - memset(data, 0, (unsigned long)w * h * 4); - - for(y = 0; y < h; y++) { - MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); - color_set_disabled_if_disabled(handle, col); - - for(x = 0; x < w; x++) { - if(rounded_rect_contains(x, y, w, h, rad)) { - unsigned char* pout = &data[(y * w + x) * 4]; - - pout[0] = (unsigned char)col->common.red; - pout[1] = (unsigned char)col->common.green; - pout[2] = (unsigned char)col->common.blue; - pout[3] = 255; - } - } - - MwLLFreeColor(col); - darken += darkenStep; - } - - pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - MwLLDestroyPixmap(pixmap); - - free(data); - } + free(data); } void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -343,8 +203,7 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); if(c != NULL) { - int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; - fill_rect_rounded(handle, rect, c, MwGetInteger(handle, MwNmodernLook) ? roundness : 0); + MwDrawRect(handle, rect, c); MwLLFreeColor(c); } } @@ -595,113 +454,48 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, rect->height -= border * 2; } -#define FRAME_ARC_STEPS 6 - -/* Appends the points of an (up to) quarter-circle arc, sweeping from - * start_deg to end_deg (in degrees, either direction), to `points`. */ -static void frame_border_append_arc(MwPoint* points, int* count, int cx, int cy, int radius, double start_deg, double end_deg, int steps) { - int i; - for(i = 0; i <= steps; i++) { - double deg = start_deg + (end_deg - start_deg) * ((double)i / steps); - double rad = deg * M_PI / 180.0; - points[*count].x = cx + (int)(cos(rad) * radius); - points[*count].y = cy + (int)(sin(rad) * radius); - (*count)++; - } -} - -static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same, int roundness) { - MwPoint p[36]; - int n; - int x = rect->x; - int y = rect->y; - int w = rect->width; - int h = rect->height; - int r = roundness; - int ib, ir; +static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { + MwPoint p[7]; (void)diff; (void)same; - if(r < 0) r = 0; - if(r > w / 2) r = w / 2; - if(r > h / 2) r = h / 2; + p[0].x = rect->x; + p[0].y = rect->y; - if(r <= 0) { - p[0].x = x; - p[0].y = y; + p[1].x = rect->x + rect->width; + p[1].y = rect->y; - p[1].x = x + w; - p[1].y = y; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; - p[2].x = x + w - border; - p[2].y = y + border; - p[3].x = x + border; - p[3].y = y + border; + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; - p[4].x = x + border; - p[4].y = y + h - border; + p[5].x = rect->x; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - p[5].x = x; - p[5].y = y + h; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[0].x = rect->x + rect->width; + p[0].y = rect->y; - p[0].x = x + w; - p[0].y = y; + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; - p[1].x = x + w - border; - p[1].y = y + border; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; - p[2].x = x + w - border; - p[2].y = y + h - border; + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; - p[3].x = x + border; - p[3].y = y + h - border; + p[4].x = rect->x; + p[4].y = rect->y + rect->height; - p[4].x = x; - p[4].y = y + h; - - p[5].x = x + w; - p[5].y = y + h; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - return; - } - - /* With rounded outer corners, each half still meets the other along - * the same two diagonals as the sharp-cornered version above, except - * the TR and BL corners (shared between both halves) are cut by an - * arc whose midpoint lies on that diagonal, and each half draws - * exactly one side of it. The TL/BR corners belong entirely to one - * half, so they get the full quarter-circle arc. - * - * The inner (border-offset) corners get the same treatment, using the - * same corner centers as the outer arcs but shrunk by the border - * width, so the border ring keeps a uniform thickness all the way - * around the curve instead of jumping to a sharp point. If the border - * is thicker than the roundness, this collapses back to the ordinary - * sharp inner corner (ib == border, ir == 0). */ - ib = (r > border) ? r : border; - ir = (r > border) ? (r - border) : 0; - - /* Top-left half: TL (full), TR (near side), BL (near side). */ - n = 0; - frame_border_append_arc(p, &n, x + r, y + r, r, 180, 270, FRAME_ARC_STEPS); - frame_border_append_arc(p, &n, x + w - r, y + r, r, 270, 315, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 270, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + ib, y + ib, ir, 270, 180, FRAME_ARC_STEPS); - frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 180, 135, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 180, FRAME_ARC_STEPS / 2); - MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); - - /* Bottom-right half: TR (far side), BL (far side), BR (full). */ - n = 0; - frame_border_append_arc(p, &n, x + w - r, y + r, r, 360, 315, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 360, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + w - ib, y + h - ib, ir, 0, 90, FRAME_ARC_STEPS); - frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 90, 135, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 90, FRAME_ARC_STEPS / 2); - frame_border_append_arc(p, &n, x + w - r, y + h - r, r, 90, 0, FRAME_ARC_STEPS); - MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); } static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { @@ -709,19 +503,18 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); MwRect r = *rect; - int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; color_set_disabled_if_disabled(handle, darker); color_set_disabled_if_disabled(handle, lighter); - frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same, roundness); + frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same); if(border > 1) { r.x += border / 2; r.y += border / 2; r.width -= border; r.height -= border; - frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same, roundness); + frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same); } MwLLFreeColor(lighter); From 18d397b4f82121383bd1dd5c9d7c9f7fbc25020a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 19:22:32 -0700 Subject: [PATCH 18/90] wh --- CMakeLists.txt | 1 - include/Mw/LowLevel/Wayland.h | 12 +-- pl/rules.pl | 1 - src/backend/cairo.c | 12 +-- src/backend/wayland/hyprland.c | 60 ----------- src/backend/wayland/interfaces.c | 153 +++++++++++++++++---------- src/backend/wayland/wayland.c | 176 ++++++++++++++++--------------- 7 files changed, 200 insertions(+), 215 deletions(-) delete mode 100644 src/backend/wayland/hyprland.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d072daf3b..534614f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,7 +269,6 @@ if(MW_USE_WAYLAND) src/backend/cairo.c src/backend/wayland/wayland.c src/backend/wayland/buffer.c - src/backend/wayland/hyprland.c src/backend/wayland/interfaces.c src/backend/wayland/region.c ) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0f570e327..c42231cad 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -238,8 +238,6 @@ struct _MwLLWaylandTopLevel { }; struct _MwLLWaylandSublevel { - struct wl_subsurface* subsurface; - struct wl_subcompositor* subcompositor; MwLL parent; @@ -488,8 +486,9 @@ int MwLLWaylandHyprlandGetRoundness(void); void MwLLWaylandHangUntilConfigured(MwLL handle); -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); -void MwLLWaylandWidgetUndestroy(MwLL self); +// MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); +// void MwLLWaylandWidgetUndestroy(MwLL self); +void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)); /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); @@ -500,10 +499,7 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ void MwLLWaylandFlush(MwLL handle); /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) \ - if(MwLLWaylandWidgetIsDestroyed(self)) { \ - return; \ - } +#define WAYLAND_EVENT_OP_START(self) /* Footer for WAYLAND_EVENT_OP_START */ #define WAYLAND_EVENT_OP_END(self) diff --git a/pl/rules.pl b/pl/rules.pl index 80f930d9f..986ee98ca 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,7 +49,6 @@ if (grep(/^wayland$/, @backends)) { new_object("src/backend/cairo.c"); new_object("src/backend/wayland/wayland.c"); new_object("src/backend/wayland/buffer.c"); - new_object("src/backend/wayland/hyprland.c"); new_object("src/backend/wayland/interfaces.c"); new_object("src/backend/wayland/region.c"); diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 65380fbaf..d70de1b94 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -212,8 +212,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -257,10 +257,10 @@ static void MwLLRaiseImpl(MwLL handle) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {} static int MwLLCairoCallInitImpl(void) { - if(cairo_load_funcs() != 0) { - return 1; - } - return 0; + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; } #include "call.c" CALL(Cairo); diff --git a/src/backend/wayland/hyprland.c b/src/backend/wayland/hyprland.c deleted file mode 100644 index e6c86790d..000000000 --- a/src/backend/wayland/hyprland.c +++ /dev/null @@ -1,60 +0,0 @@ -#include - -int MwLLWaylandDoRoundness(MwLL handle) { - if(handle->common.type == MwLLBackendWayland) { - return handle->wayland.on_hyprland; - } else { - return 0; - }; -}; - -int MwLLWaylandHyprlandGetRoundness(void) { - char* home = getenv("HOME"); - int fallback = 20; - char path[PATH_MAX]; - int roundness = fallback; - char line[512]; - FILE* f = NULL; - - if(home == NULL) { - return fallback; - } - - snprintf(path, sizeof(path), "%s/.config/hypr/hyprland.lua", home); - - f = fopen(path, "r"); - if(f == NULL) { - return fallback; - } - - while(fgets(line, sizeof(line), f) != NULL) { - char* key = strstr(line, "roundness"); - char* eq; - char* end; - long value; - - if(key == NULL) { - continue; - } - - eq = strchr(key, '='); - if(eq == NULL) { - continue; - } - eq++; - - while(*eq != '\0' && isspace((unsigned char)*eq)) { - eq++; - } - - value = strtol(eq, &end, 10); - if(end == eq) { - continue; - } - - roundness = (int)value; - } - - fclose(f); - return roundness; -} diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 84ed4923d..caf62ac06 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -531,8 +531,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL self = data; MwLL topmost_parent = self; MwMouse p; - MwBool inArea = MwFALSE; - MwLL currentlyHeldWidget = NULL; + MwBool inArea = MwFALSE; (void)time; (void)wl_pointer; @@ -540,8 +539,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time WAYLAND_EVENT_OP_START(self); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - currentlyHeldWidget = topmost_parent->wayland.currentlyHeldWidget; - if(self->wayland.framebuffer.surface) { inArea |= self->wayland.framebuffer.surface == curSurface; } @@ -552,30 +549,92 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); - if(currentlyHeldWidget != NULL) { - currentlyHeldWidget->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); - currentlyHeldWidget->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); - } if(inArea) { p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); - } else if(currentlyHeldWidget == self) { - p.point = currentlyHeldWidget->wayland.cur_mouse_pos; - MwLLDispatch(currentlyHeldWidget, move, &p); } WAYLAND_EVENT_OP_END(self); }; +// static void recursive_dispatch_mouse_down(MwLL handle, MwMouse* p) { +// MwWidget h = (MwWidget)handle->common.user; +// MwLLDispatch(handle, down, p); +// if(h) { +// int i; +// for(i = 0; i < arrlen(h->children); i++) { +// MwLLDispatch(h->children[i]->lowlevel, down, p); +// if(arrlen(h->children[i]->children) > 0) { +// recursive_dispatch_mouse_down(h->children[i]->lowlevel, p); +// } +// } +// } +// }; +// static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) { +// MwWidget h = (MwWidget)handle->common.user; +// MwLLDispatch(handle, up, p); +// if(h) { +// int i; +// for(i = 0; i < arrlen(h->children); i++) { +// MwLLDispatch(h->children[i]->lowlevel, up, p); +// if(arrlen(h->children[i]->children) > 0) { +// recursive_dispatch_mouse_up(h->children[i]->lowlevel, p); +// } +// } +// } +// }; + +static void pointer_iterate_master(MwLL handle, MwLL child, MwBool down) { + MwLL topmost_parent = handle; + MwPoint point; + MwPoint relative_pos; + MwPoint absolute_pos; + + absolute_pos.x = child->wayland.x; + absolute_pos.y = child->wayland.y; + + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + if(topmost_parent) { + absolute_pos.x += topmost_parent->wayland.x; + absolute_pos.y += topmost_parent->wayland.y; + } + } + + point = topmost_parent->wayland.cur_mouse_pos; + relative_pos.x = point.x - absolute_pos.x; + relative_pos.y = point.y - absolute_pos.y; + + if( + point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && + point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { + MwMouse p; + p.point = relative_pos; + + if(down) { + MwLLDispatch(child, down, &p); + } else { + MwLLDispatch(child, up, &p); + } + + printf("%p %s (%d %d %d %d)\n", child, down ? "DOWN" : "UP", p.point.x, p.point.y, child->wayland.ww, child->wayland.wh); + } +} +static void pointer_iterate_down(MwLL handle, MwLL child) { + pointer_iterate_master(handle, child, MwTRUE); + MwLLWaylandChildrenIterate(child, pointer_iterate_down); +} +static void pointer_iterate_up(MwLL handle, MwLL child) { + pointer_iterate_master(handle, child, MwFALSE); + MwLLWaylandChildrenIterate(child, pointer_iterate_up); +} + /* `wl_pointer.button` callback */ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { MwLL self = data; MwMouse p; - MwBool inArea = MwFALSE; - MwLL topmost_parent = self; (void)wl_pointer; (void)serial; @@ -584,46 +643,29 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri WAYLAND_EVENT_OP_START(self); p.point = self->wayland.cur_mouse_pos; - while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - if(self->wayland.framebuffer.surface) { - inArea |= self->wayland.framebuffer.surface == curSurface; + switch(button) { + case BTN_LEFT: + p.button = MwMOUSE_LEFT; + break; + case BTN_MIDDLE: + p.button = MwMOUSE_MIDDLE; + break; + case BTN_RIGHT: + p.button = MwMOUSE_RIGHT; + break; } - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } - if(inArea) { - switch(button) { - case BTN_LEFT: - p.button = MwMOUSE_LEFT; - break; - case BTN_MIDDLE: - p.button = MwMOUSE_MIDDLE; - break; - case BTN_RIGHT: - p.button = MwMOUSE_RIGHT; - break; - } - self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - if(button == BTN_LEFT) { - topmost_parent->wayland.focusedWidget = self; - } - MwLLDispatch(self, down, &p); - topmost_parent->wayland.currentlyHeldWidget = self; - - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - if(topmost_parent->wayland.currentlyHeldWidget != NULL) { - MwLLDispatch(topmost_parent->wayland.currentlyHeldWidget, up, &p); - topmost_parent->wayland.currentlyHeldWidget = NULL; - } else { - MwLLDispatch(self, up, &p); - } - break; - } + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + MwLLDispatch(self, down, &p); + MwLLWaylandChildrenIterate(self, pointer_iterate_down); + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + MwLLDispatch(self, up, &p); + MwLLWaylandChildrenIterate(self, pointer_iterate_up); + break; } if(!self->wayland.has_decorations && self->wayland.do_csd) { @@ -1056,7 +1098,7 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } else { - wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + // wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } return NULL; @@ -1067,7 +1109,7 @@ static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, way if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wl_subcompositor_destroy(wayland->toplevel->scompositor); } else { - wl_subcompositor_destroy(wayland->sublevel->subcompositor); + // wl_subcompositor_destroy(wayland->sublevel->subcompositor); } } @@ -1201,7 +1243,6 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_shm); WL_INTERFACE(wl_compositor); - WL_INTERFACE(wl_seat); WL_INTERFACE(wl_output); WL_INTERFACE(wl_data_device_manager); WL_INTERFACE(zwp_primary_selection_device_manager_v1); @@ -1214,10 +1255,14 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(xdg_toplevel_icon_manager_v1); WL_INTERFACE(wl_subcompositor); + WL_INTERFACE(wl_seat); } else if(wayland->type == MwLL_WAYLAND_POPUP) { + WL_INTERFACE(wl_seat); } else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) { WL_INTERFACE(wp_viewporter); WL_INTERFACE(wl_subcompositor); + WL_INTERFACE(wl_seat); + WL_INTERFACE(wl_seat); } else { WL_INTERFACE(wl_subcompositor); } diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 82c053eaf..22c513710 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -12,37 +12,51 @@ MwBool MwWaylandVulkan = MwFALSE; MwBool MwWaylandCairoOnly = MwFALSE; -static pthread_mutex_t destroyedWidgetsTableMutex; -/* - * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. - * - * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. - */ -static MwLL* destroyedWidgetsTable; +// static pthread_mutex_t destroyedWidgetsTableMutex; +// /* +// * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. +// * +// * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. +// */ +// static MwLL* destroyedWidgetsTable; -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwTRUE; +// MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { +// int i; +// pthread_mutex_lock(&destroyedWidgetsTableMutex); +// for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { +// if(self == destroyedWidgetsTable[i]) { +// pthread_mutex_unlock(&destroyedWidgetsTableMutex); +// return MwTRUE; +// } +// } +// pthread_mutex_unlock(&destroyedWidgetsTableMutex); +// return MwFALSE; +// } +// void MwLLWaylandWidgetUndestroy(MwLL self) { +// int i; +// pthread_mutex_lock(&destroyedWidgetsTableMutex); +// for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { +// if(self == destroyedWidgetsTable[i]) { +// arrdel(destroyedWidgetsTable, i); +// break; +// } +// } +// pthread_mutex_unlock(&destroyedWidgetsTableMutex); +// return; +// } +// + +void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) { + if(handle->common.user) { + MwWidget w = handle->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + func(handle, child); + } } } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwFALSE; -} -void MwLLWaylandWidgetUndestroy(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - arrdel(destroyedWidgetsTable, i); - break; - } - } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return; } static int event_loop(MwLL handle); @@ -370,18 +384,6 @@ static void destroy_toplevel(MwLL r) { wl_pointer_destroy(r->wayland.pointer); wl_keyboard_destroy(r->wayland.keyboard); - if(r->common.user) { - MwWidget w = r->common.user; - int i; - for(i = 0; i < arrlen(w->children); i++) { - if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { - MwLL child = w->children[i]->lowlevel; - wl_subsurface_destroy(child->wayland.sublevel->subsurface); - child->wayland.sublevel->subsurface = NULL; - } - } - } - wl_surface_destroy(r->wayland.framebuffer.surface); free(r->wayland.toplevel); @@ -421,22 +423,12 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); - r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); - - wl_subsurface_set_desync(r->wayland.sublevel->subsurface); - wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); - - if(parent) { - wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); - } - r->wayland.xkb_keymap = parent->wayland.xkb_keymap; r->wayland.xkb_state = parent->wayland.xkb_state; r->wayland.configured = MwTRUE; MwLLWaylandFramebufferSetup(&r->wayland); - MwLLWaylandBackbufferSetup(&r->wayland); } /* Sublevel setup function */ @@ -444,8 +436,6 @@ static void destroy_sublevel(MwLL r) { MwLLWaylandBackbufferDestroy(&r->wayland); MwLLWaylandFramebufferDestroy(&r->wayland); - wl_subsurface_destroy(r->wayland.sublevel->subsurface); - free(r->wayland.sublevel); r->wayland.configured = MwFALSE; @@ -873,12 +863,7 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh r->wayland.x = x; r->wayland.y = y; r->wayland.parent = parent; - if(MwLLWaylandWidgetIsDestroyed(parent)) { - r->wayland.valid = MwFALSE; - return; - } else { - r->wayland.valid = MwTRUE; - } + r->wayland.valid = MwTRUE; if(ty == MwLL_WAYLAND_UNKNOWN) { if(parent == NULL) { @@ -963,10 +948,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); - if(MwLLWaylandWidgetIsDestroyed(r)) { - MwLLWaylandWidgetUndestroy(r); - } - r->wayland.is_toplevel = parent == NULL; r->wayland.is_clipping = 0; @@ -1030,15 +1011,11 @@ static void MwLLDestroyImpl(MwLL handle) { printf("widget invalid\n"); } - pthread_mutex_lock(&destroyedWidgetsTableMutex); - arrput(destroyedWidgetsTable, handle); - pthread_mutex_unlock(&destroyedWidgetsTableMutex); + // pthread_mutex_lock(&destroyedWidgetsTableMutex); + // arrput(destroyedWidgetsTable, handle); + // pthread_mutex_unlock(&destroyedWidgetsTableMutex); free(handle); - - // if(topmost_parent->wayland.currentlyHeldWidget == handle) { - // topmost_parent->wayland.currentlyHeldWidget = NULL; - // } } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { @@ -1066,7 +1043,7 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { /* toplevels cannot be moved */ break; case MwLL_WAYLAND_SUBLEVEL: - wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); + /* sublevels are drawn according to their own x/y */ break; case MwLL_WAYLAND_POPUP: xdg_positioner_set_anchor_rect(handle->wayland.popup->xdg_positioner, handle->wayland.parent->wayland.x, handle->wayland.parent->wayland.y, handle->wayland.ww, handle->wayland.wh); @@ -1142,6 +1119,41 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.events_pending = 1; } +static void draw_child(MwLL handle, MwLL child); +static void draw_children(MwLL handle); + +static void draw_child(MwLL handle, MwLL child) { + cairo_t* c; + cairo_surface_t* cs; + cairo_t* selected_cairo = handle->wayland.cairo.front_cairo; + + wl_surface_commit(child->wayland.framebuffer.surface); + + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, child->wayland.ww, child->wayland.wh); + c = cairo_create(cs); + + cairo_set_source_surface(c, child->wayland.cairo.front_cs, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + + cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_OVER); + + cairo_paint(c); + + cairo_set_source_surface(selected_cairo, cs, child->wayland.x, child->wayland.y); + cairo_paint(selected_cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); + + draw_children(child); +} + +static void draw_children(MwLL handle) { + MwLLWaylandChildrenIterate(handle, draw_child); + + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + handle->wayland.force_render = MwTRUE; +} typedef struct { double r, g, b; @@ -1304,6 +1316,8 @@ static void MwLLEndDrawImpl(MwLL handle) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + + draw_children(handle); } } @@ -1361,10 +1375,6 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { - return 0; - } - handle->wayland.resizing = 0; if(handle->wayland.setting_wh) { @@ -1670,7 +1680,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { dec->decoration, toggle ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { handle->wayland.do_csd = !toggle; - wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + // wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); } } } @@ -1845,20 +1855,16 @@ static void MwLLEndStateChangeImpl(MwLL handle) { if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { MwLL child = w->children[i]->lowlevel; child->wayland.sublevel->xdg_surface = handle->wayland.popup->xdg_surface; - if(child->wayland.sublevel->subsurface) - wl_subsurface_destroy(child->wayland.sublevel->subsurface); + // if(child->wayland.sublevel->subsurface) + // wl_subsurface_destroy(child->wayland.sublevel->subsurface); MwLLWaylandFlush(handle); - child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); - wl_subsurface_set_desync(child->wayland.sublevel->subsurface); - wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); + // child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); + // wl_subsurface_set_desync(child->wayland.sublevel->subsurface); + // wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); - wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); + // wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); MwLLEndStateChangeImpl(w->children[i]->lowlevel); - - if(topmost_parent) { - topmost_parent->wayland.currentlyHeldWidget = NULL; - } } } } From f25b67652343b83dadf0b7c2a34e70d3caa20126 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 21:00:38 -0700 Subject: [PATCH 19/90] and now to merge --- include/Mw/LowLevel/Wayland.h | 4 +- src/backend/wayland/interfaces.c | 141 ++++++++++++++++--------------- src/backend/wayland/wayland.c | 105 ++++++++++++++--------- 3 files changed, 141 insertions(+), 109 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c42231cad..0bfe20105 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -424,6 +424,8 @@ struct _MwLLWayland { MwBool force_render; MwBool did_event_loop_early; + MwBool do_cascading_draw; + int cascading_child_num; MwBool dispatching_resize; @@ -452,8 +454,6 @@ struct _MwLLWayland { MwU64 next_elapsed; long start_time; long end_time; - - MwBool on_hyprland; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index caf62ac06..43703a9ba 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -559,76 +559,79 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time WAYLAND_EVENT_OP_END(self); }; -// static void recursive_dispatch_mouse_down(MwLL handle, MwMouse* p) { -// MwWidget h = (MwWidget)handle->common.user; -// MwLLDispatch(handle, down, p); -// if(h) { -// int i; -// for(i = 0; i < arrlen(h->children); i++) { -// MwLLDispatch(h->children[i]->lowlevel, down, p); -// if(arrlen(h->children[i]->children) > 0) { -// recursive_dispatch_mouse_down(h->children[i]->lowlevel, p); -// } -// } -// } -// }; -// static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) { -// MwWidget h = (MwWidget)handle->common.user; -// MwLLDispatch(handle, up, p); -// if(h) { -// int i; -// for(i = 0; i < arrlen(h->children); i++) { -// MwLLDispatch(h->children[i]->lowlevel, up, p); -// if(arrlen(h->children[i]->children) > 0) { -// recursive_dispatch_mouse_up(h->children[i]->lowlevel, p); -// } -// } -// } -// }; - -static void pointer_iterate_master(MwLL handle, MwLL child, MwBool down) { - MwLL topmost_parent = handle; - MwPoint point; - MwPoint relative_pos; - MwPoint absolute_pos; - - absolute_pos.x = child->wayland.x; - absolute_pos.y = child->wayland.y; - - while(topmost_parent->wayland.parent) { - topmost_parent = topmost_parent->wayland.parent; - if(topmost_parent) { - absolute_pos.x += topmost_parent->wayland.x; - absolute_pos.y += topmost_parent->wayland.y; +static void recursive_dispatch_mouse_down(MwLL handle, MwMouse* p) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, down, p); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, down, p); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_mouse_down(h->children[i]->lowlevel, p); + } } } - - point = topmost_parent->wayland.cur_mouse_pos; - relative_pos.x = point.x - absolute_pos.x; - relative_pos.y = point.y - absolute_pos.y; - - if( - point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && - point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { - MwMouse p; - p.point = relative_pos; - - if(down) { - MwLLDispatch(child, down, &p); - } else { - MwLLDispatch(child, up, &p); +}; +static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, up, p); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, up, p); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_mouse_up(h->children[i]->lowlevel, p); + } + } + } +}; + +static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + MwLLDispatch(self, down, &p); + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + MwLLDispatch(self, up, &p); + break; + } + + if(self->common.user) { + MwWidget w = self->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + MwLL topmost_parent = child; + MwPoint point; + MwPoint relative_mouse_pos; + MwPoint absolute_pos; + + absolute_pos.x = child->wayland.x; + absolute_pos.y = child->wayland.y; + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + if(topmost_parent) { + absolute_pos.x += topmost_parent->wayland.x; + absolute_pos.y += topmost_parent->wayland.y; + } + } + + point = topmost_parent->wayland.cur_mouse_pos; + relative_mouse_pos.x = point.x - absolute_pos.x; + relative_mouse_pos.y = point.y - absolute_pos.y; + + if( + point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && + point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { + + p.point = relative_mouse_pos; + + mouse_dispatch(child, p, state); + } + } } - - printf("%p %s (%d %d %d %d)\n", child, down ? "DOWN" : "UP", p.point.x, p.point.y, child->wayland.ww, child->wayland.wh); } -} -static void pointer_iterate_down(MwLL handle, MwLL child) { - pointer_iterate_master(handle, child, MwTRUE); - MwLLWaylandChildrenIterate(child, pointer_iterate_down); -} -static void pointer_iterate_up(MwLL handle, MwLL child) { - pointer_iterate_master(handle, child, MwFALSE); - MwLLWaylandChildrenIterate(child, pointer_iterate_up); } /* `wl_pointer.button` callback */ @@ -656,17 +659,15 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; } self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - switch(state) { case WL_POINTER_BUTTON_STATE_PRESSED: MwLLDispatch(self, down, &p); - MwLLWaylandChildrenIterate(self, pointer_iterate_down); break; case WL_POINTER_BUTTON_STATE_RELEASED: MwLLDispatch(self, up, &p); - MwLLWaylandChildrenIterate(self, pointer_iterate_up); break; } + mouse_dispatch(self, p, state); if(!self->wayland.has_decorations && self->wayland.do_csd) { if(state != WL_POINTER_BUTTON_STATE_RELEASED) @@ -675,6 +676,8 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri xdg_borderless_step_mup(self, p, serial); } + MwLLForceRender(self); + WAYLAND_EVENT_OP_END(self); }; diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 22c513710..c8c4b017d 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -942,6 +942,60 @@ static void detect_dark_theme(MwLL handle) { } #endif +static void draw_child(MwLL handle, MwLL child); +static void draw_children(MwLL handle); + +static void draw_child(MwLL handle, MwLL child) { + cairo_t* c; + cairo_surface_t* cs; + cairo_t* selected_cairo = handle->wayland.cairo.front_cairo; + + wl_surface_commit(child->wayland.framebuffer.surface); + + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, child->wayland.ww, child->wayland.wh); + c = cairo_create(cs); + + cairo_set_source_surface(c, child->wayland.cairo.front_cs, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + + cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_OVER); + + cairo_paint(c); + + cairo_set_source_surface(selected_cairo, cs, child->wayland.x, child->wayland.y); + cairo_paint(selected_cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); + + draw_children(child); +} + +static void draw_children(MwLL handle) { + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + + MwLLWaylandChildrenIterate(handle, draw_child); + + if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + handle->wayland.events_pending = MwFALSE; +} + +static void cascade_child(MwLL handle, MwLL child) { + child->wayland.do_cascading_draw = 10; +} + +static void count_child(MwLL handle, MwLL child) { + handle->wayland.cascading_child_num++; +} + +static void cascade_children(MwLL handle) { + handle->wayland.cascading_child_num = 0; + MwLLWaylandChildrenIterate(handle, count_child); + + handle->wayland.do_cascading_draw = 10; + MwLLWaylandChildrenIterate(handle, cascade_child); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -1035,8 +1089,11 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign static void MwLLSetXYImpl(MwLL handle, int x, int y) { WIDGET_CHECK(handle); MwLLWaylandRegionInvalidate(handle); - handle->wayland.x = x; - handle->wayland.y = y; + + if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + handle->wayland.x = x; + handle->wayland.y = y; + } switch(handle->wayland.type) { case MwLL_WAYLAND_TOPLEVEL: @@ -1119,41 +1176,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.events_pending = 1; } -static void draw_child(MwLL handle, MwLL child); -static void draw_children(MwLL handle); - -static void draw_child(MwLL handle, MwLL child) { - cairo_t* c; - cairo_surface_t* cs; - cairo_t* selected_cairo = handle->wayland.cairo.front_cairo; - - wl_surface_commit(child->wayland.framebuffer.surface); - - cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, child->wayland.ww, child->wayland.wh); - c = cairo_create(cs); - - cairo_set_source_surface(c, child->wayland.cairo.front_cs, 0, 0); - cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - - cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_OVER); - - cairo_paint(c); - - cairo_set_source_surface(selected_cairo, cs, child->wayland.x, child->wayland.y); - cairo_paint(selected_cairo); - - cairo_destroy(c); - cairo_surface_destroy(cs); - - draw_children(child); -} - -static void draw_children(MwLL handle) { - MwLLWaylandChildrenIterate(handle, draw_child); - - wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); - handle->wayland.force_render = MwTRUE; -} typedef struct { double r, g, b; @@ -1317,7 +1339,7 @@ static void MwLLEndDrawImpl(MwLL handle) { } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - draw_children(handle); + cascade_children(handle); } } @@ -1382,6 +1404,12 @@ static int MwLLPendingImpl(MwLL handle) { handle->wayland.setting_wh = 0; } + if(handle->wayland.do_cascading_draw) { + draw_children(handle); + if(handle->wayland.do_cascading_draw > 0) + handle->wayland.do_cascading_draw--; + } + handle->wayland.end_time = MwTimeGetTick(); if(handle->wayland.holding_key) { @@ -1440,6 +1468,7 @@ static int MwLLPendingImpl(MwLL handle) { static void MwLLNextEventImpl(MwLL handle) { WIDGET_CHECK(handle); + if(!MwWaylandVulkan) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; From 5d5170e6cac8ece784b3ac366c86fe9697730620 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 21:23:20 -0700 Subject: [PATCH 20/90] currentlyHeldWidget brought back --- include/Mw/LowLevel/Wayland.h | 15 ++++++--- src/backend/wayland/interfaces.c | 48 +++++++++++++++++++++++++-- src/backend/wayland/wayland.c | 57 ++++++++++++++++---------------- 3 files changed, 83 insertions(+), 37 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0bfe20105..f7102ce1d 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -412,7 +412,7 @@ struct _MwLLWayland { MwI32 ox, oy; MwU32 ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ - MwLL currentlyHeldWidget; + MwLL* currentlyHeldWidgets; MwLL focusedWidget; int resizing; @@ -486,9 +486,9 @@ int MwLLWaylandHyprlandGetRoundness(void); void MwLLWaylandHangUntilConfigured(MwLL handle); -// MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); -// void MwLLWaylandWidgetUndestroy(MwLL self); -void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)); +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); +void MwLLWaylandWidgetUndestroy(MwLL self); +void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)); /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); @@ -498,8 +498,13 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ /* Flush Wayland events */ void MwLLWaylandFlush(MwLL handle); +void MwLLWaylandCascadeChildren(MwLL handle); + /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) +#define WAYLAND_EVENT_OP_START(self) \ + if(MwLLWaylandWidgetIsDestroyed(self)) { \ + return; \ + } /* Footer for WAYLAND_EVENT_OP_START */ #define WAYLAND_EVENT_OP_END(self) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 43703a9ba..706318a04 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -531,7 +531,9 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL self = data; MwLL topmost_parent = self; MwMouse p; - MwBool inArea = MwFALSE; + MwBool inArea = MwFALSE; + MwLL* currentlyHeldWidgets = NULL; + int i; (void)time; (void)wl_pointer; @@ -539,6 +541,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time WAYLAND_EVENT_OP_START(self); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + currentlyHeldWidgets = topmost_parent->wayland.currentlyHeldWidgets; + if(self->wayland.framebuffer.surface) { inArea |= self->wayland.framebuffer.surface == curSurface; } @@ -555,6 +559,19 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLLDispatch(self, move, &p); wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); } + for(i = 0; i < arrlen(currentlyHeldWidgets); i++) { + MwLL new_topmost = currentlyHeldWidgets[i]; + p.point = topmost_parent->wayland.cur_mouse_pos; + while(new_topmost->wayland.parent) { + p.point.x -= new_topmost->wayland.x; + p.point.y -= new_topmost->wayland.y; + new_topmost = new_topmost->wayland.parent; + } + + MwLLDispatch(currentlyHeldWidgets[i], move, &p); + } + + MwLLWaylandCascadeChildren(self); WAYLAND_EVENT_OP_END(self); }; @@ -598,7 +615,7 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { if(self->common.user) { MwWidget w = self->common.user; - int i; + int i, n; for(i = 0; i < arrlen(w->children); i++) { if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { MwLL child = w->children[i]->lowlevel; @@ -624,9 +641,27 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { if( point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { - + int idx = -1; + for(n = 0; n < arrlen(topmost_parent->wayland.currentlyHeldWidgets); n++) { + if(topmost_parent->wayland.currentlyHeldWidgets[n] == child) { + idx = n; + } + } p.point = relative_mouse_pos; + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + if(idx == -1) { + arrpush(topmost_parent->wayland.currentlyHeldWidgets, child); + } + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + if(idx != -1) { + arrdel(topmost_parent->wayland.currentlyHeldWidgets, idx); + } + break; + } + mouse_dispatch(child, p, state); } } @@ -638,12 +673,15 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { MwLL self = data; MwMouse p; + MwLL topmost_parent = self; + int i; (void)wl_pointer; (void)serial; (void)time; WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; p.point = self->wayland.cur_mouse_pos; @@ -667,6 +705,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self, up, &p); break; } + + for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { + arrdel(self->wayland.currentlyHeldWidgets, i); + } mouse_dispatch(self, p, state); if(!self->wayland.has_decorations && self->wayland.do_csd) { diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index c8c4b017d..d032e7d63 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -12,39 +12,38 @@ MwBool MwWaylandVulkan = MwFALSE; MwBool MwWaylandCairoOnly = MwFALSE; -// static pthread_mutex_t destroyedWidgetsTableMutex; +static pthread_mutex_t destroyedWidgetsTableMutex; // /* // * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. // * // * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. // */ -// static MwLL* destroyedWidgetsTable; +static MwLL* destroyedWidgetsTable; -// MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { -// int i; -// pthread_mutex_lock(&destroyedWidgetsTableMutex); -// for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { -// if(self == destroyedWidgetsTable[i]) { -// pthread_mutex_unlock(&destroyedWidgetsTableMutex); -// return MwTRUE; -// } -// } -// pthread_mutex_unlock(&destroyedWidgetsTableMutex); -// return MwFALSE; -// } -// void MwLLWaylandWidgetUndestroy(MwLL self) { -// int i; -// pthread_mutex_lock(&destroyedWidgetsTableMutex); -// for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { -// if(self == destroyedWidgetsTable[i]) { -// arrdel(destroyedWidgetsTable, i); -// break; -// } -// } -// pthread_mutex_unlock(&destroyedWidgetsTableMutex); -// return; -// } -// +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwTRUE; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwFALSE; +} +void MwLLWaylandWidgetUndestroy(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + arrdel(destroyedWidgetsTable, i); + break; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return; +} void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) { if(handle->common.user) { @@ -988,7 +987,7 @@ static void count_child(MwLL handle, MwLL child) { handle->wayland.cascading_child_num++; } -static void cascade_children(MwLL handle) { +void MwLLWaylandCascadeChildren(MwLL handle) { handle->wayland.cascading_child_num = 0; MwLLWaylandChildrenIterate(handle, count_child); @@ -1339,7 +1338,7 @@ static void MwLLEndDrawImpl(MwLL handle) { } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - cascade_children(handle); + MwLLWaylandCascadeChildren(handle); } } From 6f4164da0cf33aafcfdb4606acbe4d84d783f994 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 21:25:13 -0700 Subject: [PATCH 21/90] erm --- src/backend/wayland/wayland.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index d032e7d63..d3fb20166 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -13,11 +13,11 @@ MwBool MwWaylandVulkan = MwFALSE; MwBool MwWaylandCairoOnly = MwFALSE; static pthread_mutex_t destroyedWidgetsTableMutex; -// /* -// * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. -// * -// * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. -// */ +/* + * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. + * + * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. + */ static MwLL* destroyedWidgetsTable; MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { @@ -862,7 +862,12 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh r->wayland.x = x; r->wayland.y = y; r->wayland.parent = parent; - r->wayland.valid = MwTRUE; + if(MwLLWaylandWidgetIsDestroyed(parent)) { + r->wayland.valid = MwFALSE; + return; + } else { + r->wayland.valid = MwTRUE; + } if(ty == MwLL_WAYLAND_UNKNOWN) { if(parent == NULL) { @@ -1064,9 +1069,9 @@ static void MwLLDestroyImpl(MwLL handle) { printf("widget invalid\n"); } - // pthread_mutex_lock(&destroyedWidgetsTableMutex); - // arrput(destroyedWidgetsTable, handle); - // pthread_mutex_unlock(&destroyedWidgetsTableMutex); + pthread_mutex_lock(&destroyedWidgetsTableMutex); + arrput(destroyedWidgetsTable, handle); + pthread_mutex_unlock(&destroyedWidgetsTableMutex); free(handle); } From f835e41fb0bfda7ecdd622f2c2290275f594f88b Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 21:34:58 -0700 Subject: [PATCH 22/90] back --- src/backend/wayland/interfaces.c | 1 + src/backend/wayland/wayland.c | 46 +++++++++++++------------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 706318a04..0d960c2e8 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -681,6 +681,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri (void)time; WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; p.point = self->wayland.cur_mouse_pos; diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index d3fb20166..4f832dcc3 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -242,7 +242,8 @@ static void xdg_surface_configure( xdg_surface_ack_configure(xdg_surface, serial); - MwLLDispatch(self, draw, NULL); + MwLLWaylandCascadeChildren(self); + // MwLLDispatch(self, draw, NULL); if(self->wayland.configured) { MwLLWaylandBufferUpdate(self, &self->wayland.framebuffer); @@ -996,7 +997,7 @@ void MwLLWaylandCascadeChildren(MwLL handle) { handle->wayland.cascading_child_num = 0; MwLLWaylandChildrenIterate(handle, count_child); - handle->wayland.do_cascading_draw = 10; + handle->wayland.do_cascading_draw = handle->wayland.cascading_child_num * 10; MwLLWaylandChildrenIterate(handle, cascade_child); } @@ -1006,6 +1007,10 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + if(MwLLWaylandWidgetIsDestroyed(r)) { + MwLLWaylandWidgetUndestroy(r); + } + r->wayland.is_toplevel = parent == NULL; r->wayland.is_clipping = 0; @@ -1123,7 +1128,8 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) recursive_render(handle); - MwLLDispatch(handle, draw, NULL); + MwLLWaylandCascadeChildren(handle); + // MwLLDispatch(handle, draw, NULL); } static void actually_set_wh(MwLL handle) { @@ -1152,7 +1158,8 @@ static void actually_set_wh(MwLL handle) { MwLLWaylandFramebufferSetup(&handle->wayland); MwLLWaylandBackbufferDestroy(&handle->wayland); MwLLWaylandBackbufferSetup(&handle->wayland); - MwLLDispatch(handle, draw, NULL); + MwLLWaylandCascadeChildren(handle); + // MwLLDispatch(handle, draw, NULL); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -1401,6 +1408,10 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; + if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { + return 0; + } + handle->wayland.resizing = 0; if(handle->wayland.setting_wh) { @@ -1433,7 +1444,8 @@ static int MwLLPendingImpl(MwLL handle) { if(handle->wayland.dark_theme_detection) { handle->wayland.dark_theme_detection = MwFALSE; detect_dark_theme(handle); - MwLLDispatch(handle, draw, NULL); + MwLLWaylandCascadeChildren(handle); + // MwLLDispatch(handle, draw, NULL); } else { MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); } @@ -1881,27 +1893,6 @@ static void MwLLEndStateChangeImpl(MwLL handle) { if(!handle->wayland.parent) handle->wayland.dark_theme_detection = MwTRUE; - if(handle->common.user) { - MwWidget w = handle->common.user; - int i; - for(i = 0; i < arrlen(w->children); i++) { - if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { - MwLL child = w->children[i]->lowlevel; - child->wayland.sublevel->xdg_surface = handle->wayland.popup->xdg_surface; - // if(child->wayland.sublevel->subsurface) - // wl_subsurface_destroy(child->wayland.sublevel->subsurface); - MwLLWaylandFlush(handle); - - // child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); - // wl_subsurface_set_desync(child->wayland.sublevel->subsurface); - // wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); - - // wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); - MwLLEndStateChangeImpl(w->children[i]->lowlevel); - } - } - } - recursive_render(handle); handle->wayland.events_pending = 1; @@ -1913,7 +1904,8 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; /* Not Really what's supposed to happen with this function, but take this opprutunity to do the handlers that will force everything to redraw. */ - MwLLDispatch(handle, resize, NULL); + MwLLWaylandCascadeChildren(handle); + // MwLLDispatch(handle, resize, NULL); MwLLDispatch(handle, draw, NULL); } From 4d768455bc6e26929b36bdad64417650f66afcf1 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 11 Sep 2026 22:29:05 -0700 Subject: [PATCH 23/90] finnish --- CMakeLists.txt | 1 + examples/vkdemos/vulkan.c | 4 +-- include/Mw/LowLevel/Wayland.h | 15 +++++++++ pl/rules.pl | 1 + src/backend/wayland/buffer.c | 34 +++++++++++++++++++ src/backend/wayland/interfaces.c | 56 ++++++++++++++++++++++++++++---- src/backend/wayland/wayland.c | 43 +++++++++++++++++------- src/widget/opengl.c | 6 ++++ src/widget/vulkan.c | 2 ++ 9 files changed, 142 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 534614f04..1ec1ed85e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,6 +261,7 @@ if(MW_USE_WAYLAND) scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") + scan_wayland_protocol("staging" "fifo" "-v1") scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") target_sources( diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 9060a970f..601541529 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -257,8 +257,8 @@ void vulkan_setup(MwWidget handle) { swapchainCreateInfo.imageExtent = (VkExtent2D){.width = ow, .height = oh}, swapchainCreateInfo.imageArrayLayers = 1, swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT; + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; // th is how we specify no transformation. swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index f7102ce1d..5e43c34d6 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -207,6 +207,7 @@ MwInline int wayland_load_funcs() { #include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #include "Wayland/wlr-layer-shell-client-protocol.h" +#include "Wayland/fifo-client-protocol.h" #endif typedef struct wayland_protocol { @@ -266,6 +267,7 @@ struct _MwLLWaylandShmBuffer { struct wl_buffer* shm_buffer_back; struct wl_surface* surface; struct wl_output* output; + struct wp_fifo_v1* fifo; MwU8* buf; MwU8* buf_back; @@ -435,6 +437,8 @@ struct _MwLLWayland { struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; + MwBool fifo_wait; + MwBool disable_fifo; MwLLPixmap icon_pixmap; @@ -472,6 +476,17 @@ void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland); /* Destroy the backbuffer */ void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* handle); +/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ +void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer); +/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ +void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer); +/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ +void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer); + +#ifdef MW_VULKAN +#warning Wayland backend currently disabled by default when Vulkan enabled. Use with caution (MW_BACKEND=wayland to override). +#endif + void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height); void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer); void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); diff --git a/pl/rules.pl b/pl/rules.pl index 986ee98ca..6c4df63f4 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -66,6 +66,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); + scan_wayland_protocol("staging", "fifo", "-v1"); scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c index df1de797c..3ee5e3ca0 100644 --- a/src/backend/wayland/buffer.c +++ b/src/backend/wayland/buffer.c @@ -1,5 +1,39 @@ #include #include +#include "../../../external/stb_ds.h" + +/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ +void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer) { + wayland_protocol_t* fifo_manager; + + if(buffer->fifo || !buffer->surface) { + return; + } + + fifo_manager = shget(wayland->wl_protocol_map, wp_fifo_manager_v1_interface.name); + if(!fifo_manager) { + return; + } + + buffer->fifo = wp_fifo_manager_v1_get_fifo(fifo_manager->context, buffer->surface); +} + +/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ +void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer) { + if(buffer->fifo) { + wp_fifo_v1_destroy(buffer->fifo); + buffer->fifo = NULL; + } +} + +/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ +void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer) { + if(buffer->fifo) { + wp_fifo_v1_set_barrier(buffer->fifo); + wp_fifo_v1_wait_barrier(buffer->fifo); + } + wl_surface_commit(buffer->surface); +} void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { MwLLWaylandBufferSetup(&wayland->framebuffer, wayland->ww, wayland->wh); diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 0d960c2e8..9ce42611f 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -19,6 +19,35 @@ static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); +/* Recursively dispatch a key event to a widget and its children */ +static void recursive_dispatch_key(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key(h->children[i]->lowlevel, k); + } + } + } +}; +/* Recursively dispatch a key released event to a widget and its children */ +static void recursive_dispatch_key_released(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key_released, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key_released, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key_released(h->children[i]->lowlevel, k); + } + } + } +}; + /* Recursively dispatch a move event to a widget and its children */ static void recursive_dispatch_move(MwLL handle, MwMouse* p) { MwWidget h = (MwWidget)handle->common.user; @@ -923,15 +952,11 @@ static void keyboard_key(void* data, if(key != -1) { if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { - MwLL topmost_parent = self; - while(topmost_parent->wayland.parent) { - MwLLDispatch(topmost_parent, key, &key); - topmost_parent = topmost_parent->wayland.parent; - } + recursive_dispatch_key(self, &key); self->wayland.holding_key = MwTRUE; self->wayland.last_pressed_key = key; } else { - MwLLDispatch(self, key_released, &key); + recursive_dispatch_key_released(self, &key); self->wayland.holding_key = MwFALSE; } self->wayland.start_time = MwTimeGetTick(); @@ -1193,6 +1218,24 @@ static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, waylan (void)data; } +/* wp_fifo_manager_v1 setup function */ +static wayland_protocol_t* wp_fifo_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + (void)version; + proto->listener = NULL; + proto->context = wl_registry_bind(wayland->registry, name, &wp_fifo_manager_v1_interface, 1); + + return proto; +} + +static void wp_fifo_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + if(data->context) { + wp_fifo_manager_v1_destroy(data->context); + } + free(data); +} + /* zxdg_decoration_manager_v1 setup function */ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -1295,6 +1338,7 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(zwp_pointer_constraints_v1); WL_INTERFACE(zwp_relative_pointer_manager_v1); WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(wp_fifo_manager_v1); WL_INTERFACE(zwlr_layer_shell_v1); /* Only used for layer surface, but we use it always if it's turned into a tool window */ if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(wp_viewporter); diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 4f832dcc3..433001b58 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -242,8 +242,7 @@ static void xdg_surface_configure( xdg_surface_ack_configure(xdg_surface, serial); - MwLLWaylandCascadeChildren(self); - // MwLLDispatch(self, draw, NULL); + MwLLDispatch(self, draw, NULL); if(self->wayland.configured) { MwLLWaylandBufferUpdate(self, &self->wayland.framebuffer); @@ -260,7 +259,11 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { // Yes this is needed every time, it's how we fix weston. if(self->wayland.configured) wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - wl_surface_commit(buffer->surface); + if(self->wayland.fifo_wait) { + MwLLWaylandFifoCommit(buffer); + } else { + wl_surface_commit(buffer->surface); + } } } } @@ -309,7 +312,9 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); + MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.backbuffer); + r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); wl_subsurface_set_desync(r->wayland.toplevel->ssurface); r->wayland.toplevel->xdg_surface = @@ -384,6 +389,8 @@ static void destroy_toplevel(MwLL r) { wl_pointer_destroy(r->wayland.pointer); wl_keyboard_destroy(r->wayland.keyboard); + MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); + MwLLWaylandFifoSurfaceDestroy(&r->wayland.backbuffer); wl_surface_destroy(r->wayland.framebuffer.surface); free(r->wayland.toplevel); @@ -422,6 +429,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { } r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); + MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.xkb_keymap = parent->wayland.xkb_keymap; r->wayland.xkb_state = parent->wayland.xkb_state; @@ -546,6 +554,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { r->wayland.xkb_state = topmost_parent->wayland.xkb_state; r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.popup->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); @@ -587,6 +596,8 @@ static void destroy_popup(MwLL r) { xdg_positioner_destroy(r->wayland.popup->xdg_positioner); + MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); + wl_surface_destroy(r->wayland.framebuffer.surface); wl_registry_destroy(r->wayland.registry); @@ -670,6 +681,7 @@ static void setup_layer_surface(MwLL r, int x, int y, int width, int height) { r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.layer_surface->surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, r->wayland.framebuffer.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "milsko-surfaces"); @@ -700,6 +712,8 @@ static void destroy_layer_surface(MwLL r) { zxdg_decoration_manager_v1_destroy(dec->manager); } + MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); + wl_surface_destroy(r->wayland.framebuffer.surface); wl_compositor_destroy(r->wayland.compositor); @@ -1128,8 +1142,7 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) recursive_render(handle); - MwLLWaylandCascadeChildren(handle); - // MwLLDispatch(handle, draw, NULL); + MwLLDispatch(handle, draw, NULL); } static void actually_set_wh(MwLL handle) { @@ -1158,8 +1171,7 @@ static void actually_set_wh(MwLL handle) { MwLLWaylandFramebufferSetup(&handle->wayland); MwLLWaylandBackbufferDestroy(&handle->wayland); MwLLWaylandBackbufferSetup(&handle->wayland); - MwLLWaylandCascadeChildren(handle); - // MwLLDispatch(handle, draw, NULL); + MwLLDispatch(handle, draw, NULL); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -1444,8 +1456,7 @@ static int MwLLPendingImpl(MwLL handle) { if(handle->wayland.dark_theme_detection) { handle->wayland.dark_theme_detection = MwFALSE; detect_dark_theme(handle); - MwLLWaylandCascadeChildren(handle); - // MwLLDispatch(handle, draw, NULL); + MwLLDispatch(handle, draw, NULL); } else { MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); } @@ -1474,10 +1485,12 @@ static int MwLLPendingImpl(MwLL handle) { return pending; } + if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwTRUE; MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } + if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwFALSE; return handle->wayland.force_render || handle->wayland.events_pending || pending; } @@ -1494,9 +1507,11 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.force_render) { + handle->wayland.fifo_wait = MwTRUE; MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); handle->wayland.force_render = 0; + handle->wayland.fifo_wait = MwFALSE; } if(handle->wayland.events_pending) { handle->wayland.events_pending = 0; @@ -1904,7 +1919,7 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; /* Not Really what's supposed to happen with this function, but take this opprutunity to do the handlers that will force everything to redraw. */ - MwLLWaylandCascadeChildren(handle); + MwLLDispatch(handle, draw, NULL); // MwLLDispatch(handle, resize, NULL); MwLLDispatch(handle, draw, NULL); } @@ -1958,10 +1973,14 @@ static int MwLLWaylandCallInitImpl(void) { } else { loadWayland |= (strcmp(mw_backend_env, "wayland") == 0); } + } - } else if(getenv("WAYLAND_DISPLAY")) { + /* NOTE: when vulkan is enabled, refuse to default to wayland. Remove this if I ever get Vulkan widget working with the new surfaces system. */ +#ifndef MW_VULKAN + else if(getenv("WAYLAND_DISPLAY")) { loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); } +#endif #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 30a1cee89..9e1b91e84 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -240,6 +240,12 @@ static int wcreate(MwWidget handle) { waylandopengl_t* o = r = malloc(sizeof(*o)); int gbm_format = 0; EGLConfig egl_configs[1024]; + MwWidget topmost_parent = handle; + + /* Disable fifo waiting when we have an OpenGL widget */ + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + topmost_parent->lowlevel->wayland.disable_fifo = MwTRUE; + memset(o, 0, sizeof(waylandopengl_t)); o->gllib = MwDynamicOpen("libEGL.so"); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index f4c534029..acffda3ad 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -240,6 +240,8 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { + MwWidget topmost_parent = handle; + arrput(o->enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ MwWaylandVulkan = MwTRUE; From 8fc51bd1e4d58dc7f84086b761ff5e9934b18ab0 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 12:21:05 +0900 Subject: [PATCH 24/90] unicode fix --- examples/basic/filechooser.c | 4 +- examples/vkdemos/vulkan.c | 4 +- include/Mw/Abstract/CharSet.h | 4 +- include/Mw/Unicode.h | 40 +++++++++++- pl/rules.pl | 3 +- src/abstract/charset.c | 42 ++---------- src/abstract/directory.c | 6 +- src/backend/cairo.c | 12 ++-- src/dialog/filechooser.c | 4 +- src/text/gdi.c | 46 +++++++++---- src/unicode.c | 118 ++++++++++++++++++++++++++++++++++ 11 files changed, 218 insertions(+), 65 deletions(-) diff --git a/examples/basic/filechooser.c b/examples/basic/filechooser.c index 6ad56369b..a9a5ec0b5 100644 --- a/examples/basic/filechooser.c +++ b/examples/basic/filechooser.c @@ -16,10 +16,12 @@ void MWAPI ok(MwWidget handle, void* user, void* call) { #ifdef BUG msgbox_wait = MwFALSE; #endif + + MwDestroyWidget(mb); } void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { - mb = MwMessageBox(handle, call_data, "File chosen", MwMB_ICONERROR | MwMB_BUTTONOK); + mb = MwMessageBox(window, call_data, "File chosen", MwMB_ICONERROR | MwMB_BUTTONOK); (void)user_data; diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 601541529..9060a970f 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -257,8 +257,8 @@ void vulkan_setup(MwWidget handle) { swapchainCreateInfo.imageExtent = (VkExtent2D){.width = ow, .height = oh}, swapchainCreateInfo.imageArrayLayers = 1, swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT; + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; // th is how we specify no transformation. swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; diff --git a/include/Mw/Abstract/CharSet.h b/include/Mw/Abstract/CharSet.h index f0a42f7d0..0d92ec46e 100644 --- a/include/Mw/Abstract/CharSet.h +++ b/include/Mw/Abstract/CharSet.h @@ -11,9 +11,9 @@ extern "C" { #endif -MWDECL char* MWAPI MwACPToUTF8(const char* input); +MWDECL char* MWAPI MwACPTextToUTF8Text(const char* input); -MWDECL char* MWAPI MwUTF8ToACP(const char* input); +MWDECL char* MWAPI MwUTF8TextToACPText(const char* input); #ifdef __cplusplus } diff --git a/include/Mw/Unicode.h b/include/Mw/Unicode.h index 32edeaabc..781fad269 100644 --- a/include/Mw/Unicode.h +++ b/include/Mw/Unicode.h @@ -20,6 +20,22 @@ extern "C" { */ MWDECL int MWAPI MwUTF8ToUTF32(const char* input, int* output); +/*! + * @brief Converts UTF-8 to UTF-16 + * @brief input Input + * @brief output Output + * @return Bytes this multibyte takes + * @note Output gets NUL terminated + */ +MWDECL int MWAPI MwUTF8ToUTF16(const char* input, wchar_t* output); + +/*! + * @brief Converts UTF-8 text to UTF-16 text + * @brief input Input + * @return Output + */ +MWDECL wchar_t* MWAPI MwUTF8TextToUTF16Text(const char* input); + /*! * @brief Calculates UTF-8 string length * @brief input Input @@ -38,11 +54,33 @@ MWDECL int MWAPI MwUTF8Length(const char* input); */ MWDECL int MWAPI MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len); +/*! + * @brief Returns the count current word takes + * @brief input Input + * @return Count + */ +MWDECL int MWAPI MwUTF16Count(const wchar_t* input); + +/*! + * @brief Converts UTF-16 to UTF-8 + * @brief input Input + * @brief output Output + * @return Bytes this multibyte takes + */ +MWDECL int MWAPI MwUTF16ToUTF8(const wchar_t* input, char* output); + +/*! + * @brief Converts UTF-16 text to UTF-8 text + * @brief input Input + * @return Output + */ +MWDECL char* MWAPI MwUTF16TextToUTF8Text(const wchar_t* input); + /*! * @brief Converts UTF-32 to UTF-8 * @brief input Input * @brief output Output - * @return Bytes this wide byte takes + * @return Bytes this multibyte takes */ MWDECL int MWAPI MwUTF32ToUTF8(int input, char* output); diff --git a/pl/rules.pl b/pl/rules.pl index 6c4df63f4..0fe264cbf 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -67,7 +67,8 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); scan_wayland_protocol("staging", "fifo", "-v1"); - scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); + scan_wayland_protocol_from_file("wlr-layer-shell", + "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; } diff --git a/src/abstract/charset.c b/src/abstract/charset.c index 3bd76252f..2c339d594 100644 --- a/src/abstract/charset.c +++ b/src/abstract/charset.c @@ -1,21 +1,16 @@ #include -#ifndef CP_UTF8 -#define CP_UTF8 65001 -#endif - -char* MwACPToUTF8(const char* input) { +char* MwACPTextToUTF8Text(const char* input) { #if defined(_WIN32) && defined(MW_HAS_WCHAR) int mbbytes = (strlen(input) + 1) * 4; int wbytes = 0; int len; wchar_t* wout; - char* mbout = malloc(mbbytes); + char* mbout; wbytes = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); if(wbytes == 0) { - free(mbout); return MwStringDuplicate(input); } @@ -23,23 +18,15 @@ char* MwACPToUTF8(const char* input) { len = wbytes / sizeof(wchar_t); memset(wout, 0, wbytes); - memset(mbout, 0, mbbytes); len = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), wout, len); if(len == 0) { - free(mbout); free(wout); return MwStringDuplicate(input); } wout[len] = 0; - len = WideCharToMultiByte(CP_UTF8, 0, wout, len, mbout, mbbytes, 0, 0); - if(len == 0) { - free(mbout); - free(wout); - return MwStringDuplicate(input); - } - mbout[len] = 0; + mbout = MwUTF16TextToUTF8Text(wout); free(wout); @@ -49,7 +36,7 @@ char* MwACPToUTF8(const char* input) { #endif } -char* MwUTF8ToACP(const char* input) { +char* MwUTF8TextToACPText(const char* input) { #if defined(_WIN32) && defined(MW_HAS_WCHAR) int mbbytes = (strlen(input) + 1) * 4; int wbytes = 0; @@ -58,25 +45,8 @@ char* MwUTF8ToACP(const char* input) { wchar_t* wout; char* mbout = malloc(mbbytes); - wbytes = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); - if(wbytes == 0) { - free(mbout); - return MwStringDuplicate(input); - } - - wout = malloc(wbytes + sizeof(wchar_t)); - len = wbytes / sizeof(wchar_t); - - memset(wout, 0, wbytes); - memset(mbout, 0, mbbytes); - - len = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), wout, len); - if(len == 0) { - free(mbout); - free(wout); - return MwStringDuplicate(input); - } - wout[len] = 0; + wout = MwUTF8TextToUTF16Text(input); + len = wcslen(wout); len = WideCharToMultiByte(CP_ACP, 0, wout, len, mbout, mbbytes, 0, 0); if(len == 0) { diff --git a/src/abstract/directory.c b/src/abstract/directory.c index 977f2f510..d7b364ff0 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -184,8 +184,8 @@ static void MwDirectoryJoinSingle(char* target, char* p) { b[0] = DIRSEP; b[1] = 0; - MwStringConcat(target, b); - MwStringConcat(target, p); + strcat(target, b); + strcat(target, p); } for(i = strlen(target) - 1; i >= 0; i--) { @@ -201,7 +201,7 @@ static void MwDirectoryJoinSingle(char* target, char* p) { b[0] = DIRSEP; b[1] = 0; - MwStringConcat(target, b); + strcat(target, b); } } diff --git a/src/backend/cairo.c b/src/backend/cairo.c index d70de1b94..65380fbaf 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -212,8 +212,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -257,10 +257,10 @@ static void MwLLRaiseImpl(MwLL handle) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {} static int MwLLCairoCallInitImpl(void) { - if(cairo_load_funcs() != 0) { - return 1; - } - return 0; + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; } #include "call.c" CALL(Cairo); diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index 138fc6cf0..b1fcc9b26 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -469,7 +469,7 @@ static void scan(MwWidget handle, const char* path, int record) { if(strcmp(fc->entries[i]->name, ".") == 0 || strcmp(fc->entries[i]->name, "..") == 0) continue; if(fc->entries[i]->type == MwDIRECTORY_DIRECTORY) { char date[128]; - char* n = MwACPToUTF8(fc->entries[i]->name); + char* n = MwACPTextToUTF8Text(fc->entries[i]->name); MwStringTime(date, fc->entries[i]->mtime); @@ -487,7 +487,7 @@ static void scan(MwWidget handle, const char* path, int record) { if(fc->entries[i]->type == MwDIRECTORY_FILE && !fc->dir_only) { char date[128]; char size[128]; - char* n = MwACPToUTF8(fc->entries[i]->name); + char* n = MwACPTextToUTF8Text(fc->entries[i]->name); MwStringTime(date, fc->entries[i]->mtime); MwStringSize(size, fc->entries[i]->size); diff --git a/src/text/gdi.c b/src/text/gdi.c index 97e687099..91ccac940 100644 --- a/src/text/gdi.c +++ b/src/text/gdi.c @@ -5,6 +5,8 @@ static HANDLE(WINAPI* _AddFontMemResourceEx)(PVOID pFileView, DWORD cjSize, PVOI static BOOL(WINAPI* _RemoveFontMemResourceEx)(HANDLE h) = NULL; static HANDLE WINAPI _AddFontMemResourceExPolyFill(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts); static BOOL WINAPI _RemoveFontMemResourceExPolyFill(HANDLE h); +static BOOL(WINAPI* _TextOutW)(HDC hdc, int x, int y, LPCWSTR lpString, int c); +static BOOL(WINAPI* _GetTextExtentPoint32W)(HDC hdc, LPCWSTR lpString, int c, LPSIZE psizl); struct _MwFLFont { HANDLE handle; @@ -19,8 +21,9 @@ static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c HBITMAP hbm; RGBQUAD* bits = NULL; HDC hmdc; - char* t = MwUTF8ToACP(text); unsigned char* px; + char* t; + wchar_t* t16; int y, x; MwRect r; MwLLPixmap p; @@ -33,14 +36,20 @@ static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c int old_bkmode = SetBkMode(handle->lowlevel->gdi.hDC, TRANSPARENT); COLORREF old_color = SetTextColor(handle->lowlevel->gdi.hDC, RGB(color->common.red, color->common.green, color->common.blue)); - TextOut(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t, strlen(t)); + if(_TextOutW == NULL) { + t = MwUTF8TextToACPText(text); + TextOutA(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t, strlen(t)); + free(t); + } else { + t16 = MwUTF8TextToUTF16Text(text); + TextOutW(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t16, wcslen(t16)); + free(t16); + } SetTextColor(handle->lowlevel->gdi.hDC, old_color); SetBkMode(handle->lowlevel->gdi.hDC, old_bkmode); SelectObject(handle->lowlevel->gdi.hDC, old_font); - free(t); - return 0; } @@ -64,7 +73,15 @@ static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c SelectObject(hmdc, hbm); SelectObject(hmdc, ttf->font); - TextOut(hmdc, 0, 0, t, strlen(t)); + if(_TextOutW == NULL) { + t = MwUTF8TextToACPText(text); + TextOutA(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t, strlen(t)); + free(t); + } else { + t16 = MwUTF8TextToUTF16Text(text); + TextOutW(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t16, wcslen(t16)); + free(t16); + } DeleteDC(hmdc); @@ -90,18 +107,22 @@ static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c free(px); DeleteObject(hbm); - free(t); return 0; } static int GDI_MwTextWidth(MwFLFont ttf, const char* text) { - char* t = MwUTF8ToACP(text); - SIZE sz; + SIZE sz; - GetTextExtentPoint32(ttf->dc, t, strlen(t), &sz); - - free(t); + if(_GetTextExtentPoint32W == NULL) { + char* t = MwUTF8TextToACPText(text); + GetTextExtentPoint32A(ttf->dc, t, strlen(t), &sz); + free(t); + } else { + wchar_t* t16 = MwUTF8TextToUTF16Text(text); + _GetTextExtentPoint32W(ttf->dc, t16, wcslen(t16), &sz); + free(t16); + } return sz.cx; } @@ -255,6 +276,9 @@ int MwFL_GDISetup(void) { if(!_RemoveFontMemResourceEx) { _RemoveFontMemResourceEx = _RemoveFontMemResourceExPolyFill; } + + _TextOutW = (void*)GetProcAddress(gdilib, "TextOutW"); + _GetTextExtentPoint32W = (void*)GetProcAddress(gdilib, "GetTextExtentPoint32W"); } MwFLDrawText = GDI_MwDrawText; diff --git a/src/unicode.c b/src/unicode.c index f6c768548..979fd3146 100644 --- a/src/unicode.c +++ b/src/unicode.c @@ -58,6 +58,50 @@ int MwUTF8ToUTF32(const char* input, int* output) { return b; } +int MwUTF8ToUTF16(const char* input, wchar_t* output) { + int o; + int n = MwUTF8ToUTF32(input, &o); + + if(n == 0 || n >= 0x10ffff) return 0; + + if(o < 0x10000) { + output[0] = o; + output[1] = 0; + } else { + output[0] = (o - 0x10000) / 0x400 + 0xd800; + output[1] = (o - 0x10000) % 0x400 + 0xdc00; + output[2] = 0; + } + + return n; +} + +wchar_t* MwUTF8TextToUTF16Text(const char* input) { + wchar_t* o = malloc((MwUTF8Length(input) * 2 + 1) * sizeof(*o)); + int n = 0; + wchar_t buffer[3]; + + o[0] = 0; + + while(input[0] != 0) { + int new = MwUTF8ToUTF16(input, buffer); + + if(new == 0) { + free(o); + return NULL; + } + + memcpy(o + n, buffer, wcslen(buffer) * sizeof(*o)); + + input += new; + n += wcslen(buffer); + } + + o[n] = 0; + + return o; +} + int MwUTF8Length(const char* input) { int out; int len = 0; @@ -97,6 +141,80 @@ int MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len) { return total; } +static int is_u16_high(wchar_t ch) { + return 0xd800 <= ch && ch < 0xdc00; +} + +static int is_u16_low(wchar_t ch) { + return 0xdc00 <= ch && ch < 0xe000; +} + +int MwUTF16Count(const wchar_t* input) { + if(is_u16_high(input[0])) { + if(is_u16_low(input[1])) { + return 2; + } else if(input[1] == 0) { + return 2; + } else { + return 0; + } + } else if(is_u16_low(input[0])) { + if(input[1] == 0) { + return 2; + } else { + return 0; + } + } else { + return 1; + } +} + +int MwUTF16ToUTF8(const wchar_t* input, char* output) { + if(is_u16_high(input[0])) { + if(is_u16_low(input[1])) { + return MwUTF32ToUTF8(0x10000 + (CAST_I32(input[0]) - 0xd800) * 0x400 + (CAST_I32(input[1]) - 0xdc00), output); + } else if(input[1] == 0) { + return MwUTF32ToUTF8(input[0], output); + } else { + return 0; + } + } else if(is_u16_low(input[0])) { + if(input[1] == 0) { + return MwUTF32ToUTF8(input[0], output); + } else { + return 0; + } + } else { + return MwUTF32ToUTF8(input[0], output); + } +} + +char* MwUTF16TextToUTF8Text(const wchar_t* input) { + char* o = malloc(4 * wcslen(input) + 1); + int n = 0; + char buffer[4]; + + o[0] = 0; + + while(input[0]) { + int new = MwUTF16ToUTF8(input, buffer); + + if(new == 0) { + free(o); + return NULL; + } + + memcpy(o + n, buffer, new); + + input += MwUTF16Count(input); + n += new; + } + + o[n] = 0; + + return o; +} + int MwUTF32ToUTF8(int input, char* output) { if(input < 128) { output[0] = input; From d98d2e15cef86ee8848975d81e6f4ea7941d0b4d Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 00:17:18 -0700 Subject: [PATCH 25/90] fix submenus --- include/Mw/LowLevel/Wayland.h | 5 +- pl/rules.pl | 2 +- src/backend/wayland/interfaces.c | 122 ++++++++++++++----------------- src/backend/wayland/wayland.c | 14 ++-- 4 files changed, 67 insertions(+), 76 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 5e43c34d6..234e3e802 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -239,8 +239,9 @@ struct _MwLLWaylandTopLevel { }; struct _MwLLWaylandSublevel { - - MwLL parent; + MwLL parent; + struct wl_subcompositor* subcompositor; + struct wl_subsurface* subsurface; struct xdg_surface* xdg_surface; }; diff --git a/pl/rules.pl b/pl/rules.pl index 0fe264cbf..afc9ef99d 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -66,7 +66,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - scan_wayland_protocol("staging", "fifo", "-v1"); + scan_wayland_protocol("staging", "fifo", "-v1"); scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 9ce42611f..a69ad1ba9 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -587,21 +587,21 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); - } - for(i = 0; i < arrlen(currentlyHeldWidgets); i++) { - MwLL new_topmost = currentlyHeldWidgets[i]; - p.point = topmost_parent->wayland.cur_mouse_pos; - while(new_topmost->wayland.parent) { - p.point.x -= new_topmost->wayland.x; - p.point.y -= new_topmost->wayland.y; - new_topmost = new_topmost->wayland.parent; + + for(i = 0; i < arrlen(currentlyHeldWidgets); i++) { + MwLL new_topmost = currentlyHeldWidgets[i]; + p.point = topmost_parent->wayland.cur_mouse_pos; + while(new_topmost->wayland.parent) { + p.point.x -= new_topmost->wayland.x; + p.point.y -= new_topmost->wayland.y; + new_topmost = new_topmost->wayland.parent; + } + + MwLLDispatch(currentlyHeldWidgets[i], move, &p); } - - MwLLDispatch(currentlyHeldWidgets[i], move, &p); + MwLLWaylandCascadeChildren(self); } - MwLLWaylandCascadeChildren(self); - WAYLAND_EVENT_OP_END(self); }; @@ -704,6 +704,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwMouse p; MwLL topmost_parent = self; int i; + MwBool inArea = MwFALSE; (void)wl_pointer; (void)serial; @@ -711,45 +712,54 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri WAYLAND_EVENT_OP_START(self); - while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + if(self->wayland.type != MwLL_WAYLAND_POPUP) { + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + } p.point = self->wayland.cur_mouse_pos; - switch(button) { - case BTN_LEFT: - p.button = MwMOUSE_LEFT; - break; - case BTN_MIDDLE: - p.button = MwMOUSE_MIDDLE; - break; - case BTN_RIGHT: - p.button = MwMOUSE_RIGHT; - break; + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; } - self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - MwLLDispatch(self, down, &p); - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - MwLLDispatch(self, up, &p); - break; + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; } + if(inArea) { + switch(button) { + case BTN_LEFT: + p.button = MwMOUSE_LEFT; + break; + case BTN_MIDDLE: + p.button = MwMOUSE_MIDDLE; + break; + case BTN_RIGHT: + p.button = MwMOUSE_RIGHT; + break; + } + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; + // switch(state) { + // case WL_POINTER_BUTTON_STATE_PRESSED: + // MwLLDispatch(self, down, &p); + // break; + // case WL_POINTER_BUTTON_STATE_RELEASED: + // MwLLDispatch(self, up, &p); + // break; + // } - for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { - arrdel(self->wayland.currentlyHeldWidgets, i); + for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { + arrdel(self->wayland.currentlyHeldWidgets, i); + } + mouse_dispatch(self, p, state); + + if(!self->wayland.has_decorations && self->wayland.do_csd) { + if(state != WL_POINTER_BUTTON_STATE_RELEASED) + xdg_borderless_step_mdown(self, p, serial); + else + xdg_borderless_step_mup(self, p, serial); + } + + MwLLForceRender(self); } - mouse_dispatch(self, p, state); - - if(!self->wayland.has_decorations && self->wayland.do_csd) { - if(state != WL_POINTER_BUTTON_STATE_RELEASED) - xdg_borderless_step_mdown(self, p, serial); - else - xdg_borderless_step_mup(self, p, serial); - } - - MwLLForceRender(self); - WAYLAND_EVENT_OP_END(self); }; @@ -1169,7 +1179,7 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } else { - // wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } return NULL; @@ -1180,7 +1190,7 @@ static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, way if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wl_subcompositor_destroy(wayland->toplevel->scompositor); } else { - // wl_subcompositor_destroy(wayland->sublevel->subcompositor); + wl_subcompositor_destroy(wayland->sublevel->subcompositor); } } @@ -1218,24 +1228,6 @@ static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, waylan (void)data; } -/* wp_fifo_manager_v1 setup function */ -static wayland_protocol_t* wp_fifo_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - (void)version; - proto->listener = NULL; - proto->context = wl_registry_bind(wayland->registry, name, &wp_fifo_manager_v1_interface, 1); - - return proto; -} - -static void wp_fifo_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - if(data->context) { - wp_fifo_manager_v1_destroy(data->context); - } - free(data); -} - /* zxdg_decoration_manager_v1 setup function */ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -1338,7 +1330,6 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(zwp_pointer_constraints_v1); WL_INTERFACE(zwp_relative_pointer_manager_v1); WL_INTERFACE(xdg_wm_base); - WL_INTERFACE(wp_fifo_manager_v1); WL_INTERFACE(zwlr_layer_shell_v1); /* Only used for layer surface, but we use it always if it's turned into a tool window */ if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(wp_viewporter); @@ -1352,7 +1343,6 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wp_viewporter); WL_INTERFACE(wl_subcompositor); WL_INTERFACE(wl_seat); - WL_INTERFACE(wl_seat); } else { WL_INTERFACE(wl_subcompositor); } diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 433001b58..3c2d9bd61 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -417,8 +417,10 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { if(parent->wayland.type == MwLL_WAYLAND_TOPLEVEL) { r->wayland.sublevel->xdg_surface = parent->wayland.toplevel->xdg_surface; - } else { + } else if(parent->wayland.type == MwLL_WAYLAND_SUBLEVEL) { r->wayland.sublevel->xdg_surface = parent->wayland.sublevel->xdg_surface; + } else if(parent->wayland.type == MwLL_WAYLAND_POPUP) { + r->wayland.sublevel->xdg_surface = parent->wayland.popup->xdg_surface; } wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); @@ -427,9 +429,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { raise(SIGTRAP); return; } - r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.xkb_keymap = parent->wayland.xkb_keymap; r->wayland.xkb_state = parent->wayland.xkb_state; @@ -542,10 +542,10 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); xdg_positioner_set_anchor_rect( r->wayland.popup->xdg_positioner, - r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); - // xdg_positioner_set_offset( - // r->wayland.popup->xdg_positioner, - // r->wayland.x, r->wayland.y); + topmost_parent->wayland.x, topmost_parent->wayland.y, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_offset( + r->wayland.popup->xdg_positioner, + r->wayland.x, r->wayland.y); xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_GRAVITY_NONE); From d5e6847334196cc2b8f623a276361283e8ccc274 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 00:20:08 -0700 Subject: [PATCH 26/90] fix accidental subsurface reinclusion --- include/Mw/LowLevel/Wayland.h | 4 +--- src/backend/wayland/interfaces.c | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 234e3e802..3e9d671e9 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -239,9 +239,7 @@ struct _MwLLWaylandTopLevel { }; struct _MwLLWaylandSublevel { - MwLL parent; - struct wl_subcompositor* subcompositor; - struct wl_subsurface* subsurface; + MwLL parent; struct xdg_surface* xdg_surface; }; diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index a69ad1ba9..73ac8b1f6 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -1178,8 +1178,6 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan (void)version; if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); - } else { - wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } return NULL; @@ -1189,8 +1187,6 @@ static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, way (void)data; if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wl_subcompositor_destroy(wayland->toplevel->scompositor); - } else { - wl_subcompositor_destroy(wayland->sublevel->subcompositor); } } From 95dd0932f706cca1696942ebfeabfb80881a7aed Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 01:40:40 -0700 Subject: [PATCH 27/90] fix? --- src/backend/wayland/interfaces.c | 33 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 73ac8b1f6..e0b962c72 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -576,9 +576,9 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time inArea |= self->wayland.framebuffer.surface == curSurface; } - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } + // if(self->wayland.backbuffer.surface) { + // inArea |= self->wayland.backbuffer.surface == curSurface; + // } self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); @@ -601,7 +601,9 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time } MwLLWaylandCascadeChildren(self); } - + if(self->wayland.backbuffer.surface) { + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); + } WAYLAND_EVENT_OP_END(self); }; @@ -663,7 +665,8 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { } } - point = topmost_parent->wayland.cur_mouse_pos; + point = topmost_parent->wayland.cur_mouse_pos; + relative_mouse_pos.x = point.x - absolute_pos.x; relative_mouse_pos.y = point.y - absolute_pos.y; @@ -721,9 +724,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri if(self->wayland.framebuffer.surface) { inArea |= self->wayland.framebuffer.surface == curSurface; } - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } + if(inArea) { switch(button) { case BTN_LEFT: @@ -737,29 +738,23 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; } self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - // switch(state) { - // case WL_POINTER_BUTTON_STATE_PRESSED: - // MwLLDispatch(self, down, &p); - // break; - // case WL_POINTER_BUTTON_STATE_RELEASED: - // MwLLDispatch(self, up, &p); - // break; - // } for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { arrdel(self->wayland.currentlyHeldWidgets, i); } mouse_dispatch(self, p, state); - + } + if(self->wayland.backbuffer.surface) { if(!self->wayland.has_decorations && self->wayland.do_csd) { if(state != WL_POINTER_BUTTON_STATE_RELEASED) xdg_borderless_step_mdown(self, p, serial); else xdg_borderless_step_mup(self, p, serial); } - - MwLLForceRender(self); } + + MwLLForceRender(self); + WAYLAND_EVENT_OP_END(self); }; From e11b8f19399787cc1d3d8be023c5b2a1d296d968 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 02:11:40 -0700 Subject: [PATCH 28/90] keyboard fix --- src/backend/wayland/interfaces.c | 83 +++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index e0b962c72..b200dd258 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -634,6 +634,36 @@ static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) { } }; +static bool hit_detect(MwLL child, MwLL* _topmost_parent, MwPoint* _point, MwPoint* _relative_mouse_pos, MwPoint* _absolute_pos) { + MwLL topmost_parent = child; + MwPoint point; + MwPoint relative_mouse_pos; + MwPoint absolute_pos; + + absolute_pos.x = child->wayland.x; + absolute_pos.y = child->wayland.y; + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + if(topmost_parent) { + absolute_pos.x += topmost_parent->wayland.x; + absolute_pos.y += topmost_parent->wayland.y; + } + } + + point = topmost_parent->wayland.cur_mouse_pos; + + relative_mouse_pos.x = point.x - absolute_pos.x; + relative_mouse_pos.y = point.y - absolute_pos.y; + + *_topmost_parent = topmost_parent; + *_point = point; + *_relative_mouse_pos = relative_mouse_pos; + *_absolute_pos = absolute_pos; + + return point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && + point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh; +} + static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { switch(state) { case WL_POINTER_BUTTON_STATE_PRESSED: @@ -655,24 +685,7 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { MwPoint relative_mouse_pos; MwPoint absolute_pos; - absolute_pos.x = child->wayland.x; - absolute_pos.y = child->wayland.y; - while(topmost_parent->wayland.parent) { - topmost_parent = topmost_parent->wayland.parent; - if(topmost_parent) { - absolute_pos.x += topmost_parent->wayland.x; - absolute_pos.y += topmost_parent->wayland.y; - } - } - - point = topmost_parent->wayland.cur_mouse_pos; - - relative_mouse_pos.x = point.x - absolute_pos.x; - relative_mouse_pos.y = point.y - absolute_pos.y; - - if( - point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && - point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { + if(hit_detect(child, &topmost_parent, &point, &relative_mouse_pos, &absolute_pos)) { int idx = -1; for(n = 0; n < arrlen(topmost_parent->wayland.currentlyHeldWidgets); n++) { if(topmost_parent->wayland.currentlyHeldWidgets[n] == child) { @@ -844,6 +857,32 @@ static void keyboard_leave(void* data, WAYLAND_EVENT_OP_END(self); }; +static void key_dispatch(MwLL self, int* k, MwBool down) { + if(self->common.user) { + MwWidget w = self->common.user; + int i, n; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + MwLL topmost_parent = child; + MwPoint point; + MwPoint relative_mouse_pos; + MwPoint absolute_pos; + + if(hit_detect(child, &topmost_parent, &point, &relative_mouse_pos, &absolute_pos)) { + if(down) { + MwLLDispatch(child, key, k); + } else { + MwLLDispatch(child, key_released, k); + } + + key_dispatch(child, k, down); + } + } + } + } +} + /* `wl_keyboard.key` callback */ static void keyboard_key(void* data, struct wl_keyboard* wl_keyboard, @@ -867,13 +906,10 @@ static void keyboard_key(void* data, inArea |= self->wayland.framebuffer.surface == curSurface; } - if(self->wayland.backbuffer.surface) { - inArea |= self->wayland.backbuffer.surface == curSurface; - } - inArea |= (self == topmost_parent->wayland.focusedWidget); if(inArea) { + xkb_layout_index_t layout; MwU32 levels; xkb_level_index_t level = 0; @@ -957,13 +993,12 @@ static void keyboard_key(void* data, if(key != -1) { if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { - recursive_dispatch_key(self, &key); self->wayland.holding_key = MwTRUE; self->wayland.last_pressed_key = key; } else { - recursive_dispatch_key_released(self, &key); self->wayland.holding_key = MwFALSE; } + key_dispatch(self, &key, state == WL_KEYBOARD_KEY_STATE_PRESSED); self->wayland.start_time = MwTimeGetTick(); self->wayland.next_elapsed = self->wayland.keyboard_delay; } From 8fb77771bb52511ccf53a1eb6ae5f094bd2e3c7c Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 18:13:31 +0900 Subject: [PATCH 29/90] bool --- src/backend/wayland/interfaces.c | 1 + src/backend/wayland/wayland.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index b200dd258..0ab3f43ac 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -11,6 +11,7 @@ #include #endif +#include #include static void setup_clipboard(MwLL self, struct wl_seat* wl_seat); diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 3c2d9bd61..2b5fce98f 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1984,7 +1984,7 @@ static int MwLLWaylandCallInitImpl(void) { #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { - loadWayland = 0; + loadWayland = 1; } #endif From c6aaf54656847a37ed2e996469bb5661636857b9 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 20:11:01 +0900 Subject: [PATCH 30/90] add clock widget (closes #35) --- examples/basic/periodic.c | 9 +++ examples/basic/rotate.c | 2 +- examples/gldemos/gears.c | 2 +- include/Mw/Draw.h | 7 ++ include/Mw/MachDep.h | 2 +- include/Mw/Milsko.h | 1 + include/Mw/StringDefs.h | 3 + include/Mw/Widget/Clock.h | 24 +++++++ milsko.xml | 10 +++ pl/rules.pl | 4 +- src/abstract/charset.c | 4 +- src/core.c | 2 +- src/draw.c | 18 ++--- src/widget/chart.c | 0 src/widget/clock.c | 138 ++++++++++++++++++++++++++++++++++++++ 15 files changed, 210 insertions(+), 16 deletions(-) create mode 100644 include/Mw/Widget/Clock.h create mode 100644 src/widget/chart.c create mode 100644 src/widget/clock.c diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index b449f0950..06a115b68 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -245,6 +245,15 @@ int main() { MwNscale, 1, NULL); + f = frame("Clock", -PaddingContent, -PaddingContent, MwClockClass, + MwNhour, 15, + MwNminute, 0, + MwNsecond, 10, + NULL); + + f = frame("Chart", -PaddingContent, -PaddingContent, MwCalendarClass, + NULL); + f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); MwComboBoxAdd(w, -1, "Hello!"); diff --git a/examples/basic/rotate.c b/examples/basic/rotate.c index dbf9c5e15..112d5fc7b 100644 --- a/examples/basic/rotate.c +++ b/examples/basic/rotate.c @@ -4,7 +4,7 @@ #include #ifndef M_PI -#define M_PI 3.14159265 +#define M_PI 3.14159265359 #endif #define SIZE 100 diff --git a/examples/gldemos/gears.c b/examples/gldemos/gears.c index 5d06b067b..a1aad909c 100644 --- a/examples/gldemos/gears.c +++ b/examples/gldemos/gears.c @@ -13,7 +13,7 @@ #include #ifndef M_PI -#define M_PI 3.14159265 +#define M_PI 3.14159265359 #endif /** diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index 443835c77..542aac57e 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -13,6 +13,13 @@ extern "C" { #endif +/*! + * @brief Get a color difference for shadow + * @param handle Widget + * @return Color difference + */ +MWDECL int MWAPI MwGetColorDifference(MwWidget handle); + /*! * @brief Parses a color text * @param handle Widget diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 4c98b24da..7313ce2f3 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -86,7 +86,7 @@ #endif #ifndef M_PI -#define M_PI 3.14159265 +#define M_PI 3.14159265359 #endif /* Windows */ diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index 9860990ca..7997bb670 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 6ad4e4647..39730db7d 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -54,6 +54,9 @@ #define MwNrowSpan "IrowSpan" #define MwNdisabled "Idisabled" #define MwNacceptsDnD "IacceptsDnD" +#define MwNhour "Ihour" +#define MwNminute "Iminute" +#define MwNsecond "Isecond" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/include/Mw/Widget/Clock.h b/include/Mw/Widget/Clock.h new file mode 100644 index 000000000..a8057fed5 --- /dev/null +++ b/include/Mw/Widget/Clock.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Clock.h + * @brief Clock widget + */ +#ifndef __MW_WIDGET_CLOCK_H__ +#define __MW_WIDGET_CLOCK_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Clock widget class + */ +MWDECL MwClass MwClockClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/milsko.xml b/milsko.xml index a94c847ca..573b84d2d 100644 --- a/milsko.xml +++ b/milsko.xml @@ -106,6 +106,9 @@ + + + @@ -654,6 +657,13 @@ + + + + + + + diff --git a/pl/rules.pl b/pl/rules.pl index afc9ef99d..220e550c0 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -66,7 +66,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - scan_wayland_protocol("staging", "fifo", "-v1"); + scan_wayland_protocol("staging", "fifo", "-v1"); scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); @@ -153,6 +153,8 @@ new_object("src/widget/box.c"); new_object("src/widget/button.c"); new_object("src/widget/calendar.c"); new_object("src/widget/checkbox.c"); +new_object("src/widget/chart.c"); +new_object("src/widget/clock.c"); new_object("src/widget/combobox.c"); new_object("src/widget/entry.c"); new_object("src/widget/frame.c"); diff --git a/src/abstract/charset.c b/src/abstract/charset.c index 2c339d594..4b831d543 100644 --- a/src/abstract/charset.c +++ b/src/abstract/charset.c @@ -2,8 +2,7 @@ char* MwACPTextToUTF8Text(const char* input) { #if defined(_WIN32) && defined(MW_HAS_WCHAR) - int mbbytes = (strlen(input) + 1) * 4; - int wbytes = 0; + int wbytes = 0; int len; wchar_t* wout; @@ -39,7 +38,6 @@ char* MwACPTextToUTF8Text(const char* input) { char* MwUTF8TextToACPText(const char* input) { #if defined(_WIN32) && defined(MW_HAS_WCHAR) int mbbytes = (strlen(input) + 1) * 4; - int wbytes = 0; int len; wchar_t* wout; diff --git a/src/core.c b/src/core.c index 318092249..2982c1ed9 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif - +#define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ diff --git a/src/draw.c b/src/draw.c index c7869e0fe..bbd02642b 100644 --- a/src/draw.c +++ b/src/draw.c @@ -11,7 +11,7 @@ #include "../external/stb_ds.h" -static int get_color_diff(MwWidget handle) { +int MwGetColorDifference(MwWidget handle) { if(MwGetInteger(handle, MwNmodernLook)) { return 40; } else { @@ -121,7 +121,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; int y; double darken = 0.; - int ColorDiff = get_color_diff(handle); + int ColorDiff = MwGetColorDifference(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz * 2); @@ -178,7 +178,7 @@ void MwDrawFrameWithBorder(MwWidget handle, MwRect* rect, MwLLColor color, int i if(MwGetInteger(handle, MwNmodernLook)) { MwDrawFrameEx(handle, rect, color, invert, border, 0, 0); } else { - int diff = get_color_diff(handle) / 3 * 2; + int diff = MwGetColorDifference(handle) / 3 * 2; if(border >= 2) { int i; @@ -236,7 +236,7 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwPoint p[6]; int border = MwDefaultBorderWidth(handle); - int ColorDiff = get_color_diff(handle) + (MwGetInteger(handle, MwNmodernLook) ? 48 : 0); + int ColorDiff = MwGetColorDifference(handle) + (MwGetInteger(handle, MwNmodernLook) ? 48 : 0); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); @@ -312,7 +312,7 @@ void MwDrawCircle(MwWidget handle, MwRect* rect, MwLLColor color, MwLLColor back double cx, cy, rx, ry; int border; int x, y; - int ColorDiff = (get_color_diff(handle)); + int ColorDiff = (MwGetColorDifference(handle)); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); MwLLColor base = MwLightenColor(handle, color, 0, 0, 0); @@ -385,6 +385,8 @@ void MwDrawCircle(MwWidget handle, MwRect* rect, MwLLColor color, MwLLColor back pout[2] = (MwU8)mixColor->common.blue; pout[3] = 255; + + MwLLFreeColor(mixColor); } } } @@ -402,7 +404,7 @@ void MwDrawCircle(MwWidget handle, MwRect* rect, MwLLColor color, MwLLColor back static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { MwPoint p[7]; - int ColorDiff = get_color_diff(handle); + int ColorDiff = MwGetColorDifference(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); color_set_disabled_if_disabled(handle, darker); @@ -499,7 +501,7 @@ static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighte } static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { - int ColorDiff = get_color_diff(handle); + int ColorDiff = MwGetColorDifference(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); MwRect r = *rect; @@ -539,7 +541,7 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction) { MwPoint p1[4], p2[4], p3[4], p4[3]; const int border = MwGetInteger(handle, MwNmodernLook) ? 2 : MwDefaultBorderWidth(handle); - int ColorDiff = get_color_diff(handle); + int ColorDiff = MwGetColorDifference(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); diff --git a/src/widget/chart.c b/src/widget/chart.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/widget/clock.c b/src/widget/clock.c new file mode 100644 index 000000000..547464afb --- /dev/null +++ b/src/widget/clock.c @@ -0,0 +1,138 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNhour, 0); + MwSetInteger(handle, MwNminute, 0); + MwSetInteger(handle, MwNsecond, 0); + return 0; +} + +static void hand(MwWidget handle, double x, double y, double width, double length, double angle, MwLLColor inside, MwLLColor border) { + double w = MwGetInteger(handle, MwNwidth); + double h = MwGetInteger(handle, MwNheight); + MwPoint p[5]; + int i; + double rad = (angle - 90) / 180 * M_PI; + double c = cos(rad); + double s = sin(rad); + double c2 = cos(rad - 0.5 * M_PI); + double s2 = sin(rad - 0.5 * M_PI); + double c3 = cos(rad - M_PI); + double s3 = sin(rad - M_PI); + + p[0].x = c2 * width / 2; + p[0].y = s2 * width / 2; + + p[1].x = c3 * width / 2 * 2; + p[1].y = s3 * width / 2 * 2; + + p[2].x = -c2 * width / 2; + p[2].y = -s2 * width / 2; + + p[3].x = c * length; + p[3].y = s * length; + + for(i = 0; i < 4; i++) { + p[i].x += w / 2 + x; + p[i].y += h / 2 + y; + } + + p[4] = p[0]; + + MwLLPolygon(handle->lowlevel, p, 4, inside); + MwLLLine(handle->lowlevel, &p[0], border); + MwLLLine(handle->lowlevel, &p[1], border); + MwLLLine(handle->lowlevel, &p[2], border); + MwLLLine(handle->lowlevel, &p[3], border); +} + +static void draw(MwWidget handle) { + int ColorDiff = MwGetColorDifference(handle); + int ShadowDist; + int BaseWidth; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor shadow = MwLightenColor(handle, base, -ColorDiff, -ColorDiff, -ColorDiff); + MwLLColor inside = MwParseColor(handle, MwGetText(handle, MwNsubBackground)); + MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNsubForeground)); + MwRect r; + int i; + double w; + double fs = (MwGetInteger(handle, MwNsecond) % 60); + double fm = (MwGetInteger(handle, MwNminute) % 60) + (MwGetInteger(handle, MwNsecond) % 60) / 60.0; + double s = (double)(MwGetInteger(handle, MwNsecond) % 60) / 60 * 360; + double m = ((double)(MwGetInteger(handle, MwNminute) % 60) + fs / 60.0) / 60 * 360; + double h = ((double)(MwGetInteger(handle, MwNhour) % 12) + fm / 60.0) / 12 * 360; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + + w = r.width < r.height ? r.width : r.height; + + BaseWidth = w / 10; + ShadowDist = BaseWidth / 3; + + for(i = 0; i < 12; i++) { + MwPoint p[2]; + double rad = i * 30 / 180.0 * M_PI; + double c = cos(rad); + double s = sin(rad); + double x, y; + double l = w / 2 / 5; + + x = r.width / 2 + c * w / 2 - l * c; + y = r.height / 2 + s * w / 2 - l * s; + + p[0].x = x + l * c / (i % 3 ? 2 : 1); + p[0].y = y + l * s / (i % 3 ? 2 : 1); + + p[1].x = x; + p[1].y = y; + + MwLLLine(handle->lowlevel, p, border); + } + + hand(handle, ShadowDist, ShadowDist, BaseWidth, w / 2 * 2 / 3, h, shadow, shadow); + hand(handle, ShadowDist, ShadowDist, BaseWidth, w / 2, m, shadow, shadow); + hand(handle, ShadowDist, ShadowDist, BaseWidth / 4, w / 2, s, shadow, shadow); + + hand(handle, 0, 0, w / 10, w / 2 * 2 / 3, h, inside, border); + hand(handle, 0, 0, BaseWidth, w / 2, m, inside, border); + hand(handle, 0, 0, BaseWidth / 4, w / 2, s, inside, border); + + MwLLFreeColor(border); + MwLLFreeColor(inside); + MwLLFreeColor(shadow); + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNhour) == 0 || strcmp(key, MwNminute) == 0 || strcmp(key, MwNsecond) == 0) MwForceRender(handle); +} + +MwClassRec MwClockClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwClockClass = &MwClockClassRec; From 827fd80ba01e2fc2384af33569460baecbc6dd2f Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 20:11:21 +0900 Subject: [PATCH 31/90] oops --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index 2982c1ed9..21b16eab6 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif -#define USE_CLASSIC_THEME +//#define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ From 2ae8f67b53465d677bd2439a0fc942b546bb3db7 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 20:17:48 +0900 Subject: [PATCH 32/90] regenerate makefiles --- NTMakefile | 6 ++++-- WatMakefile | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index 63a4a2c9d..2d41468ed 100644 --- a/NTMakefile +++ b/NTMakefile @@ -79,7 +79,9 @@ clean: del /f /q src\widget\box.obj del /f /q src\widget\button.obj del /f /q src\widget\calendar.obj + del /f /q src\widget\chart.obj del /f /q src\widget\checkbox.obj + del /f /q src\widget\clock.obj del /f /q src\widget\combobox.obj del /f /q src\widget\entry.obj del /f /q src\widget\frame.obj @@ -320,8 +322,8 @@ examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c -src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib +src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib .c.obj: diff --git a/WatMakefile b/WatMakefile index 4533f3c2f..0b4f73a50 100644 --- a/WatMakefile +++ b/WatMakefile @@ -78,7 +78,9 @@ clean: .SYMBOLIC %erase src/widget/box.obj %erase src/widget/button.obj %erase src/widget/calendar.obj + %erase src/widget/chart.obj %erase src/widget/checkbox.obj + %erase src/widget/clock.obj %erase src/widget/combobox.obj %erase src/widget/entry.obj %erase src/widget/frame.obj @@ -319,8 +321,8 @@ examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c -src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib +src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/chart.obj src/widget/checkbox.obj src/widget/clock.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/chart.obj file src/widget/checkbox.obj file src/widget/clock.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib @@ -462,8 +464,12 @@ src/widget/button.obj: src/widget/button.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/button.c src/widget/calendar.obj: src/widget/calendar.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/calendar.c +src/widget/chart.obj: src/widget/chart.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/chart.c src/widget/checkbox.obj: src/widget/checkbox.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/checkbox.c +src/widget/clock.obj: src/widget/clock.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/clock.c src/widget/combobox.obj: src/widget/combobox.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/combobox.c src/widget/entry.obj: src/widget/entry.c From efd1d32801d17265b78bf8cafc76d19c42a54532 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 13 Sep 2026 22:10:40 +0900 Subject: [PATCH 33/90] fix gdi and add dummy chart --- examples/basic/periodic.c | 37 +++++++++++++++++++++------- include/Mw/Milsko.h | 1 + include/Mw/Widget/Chart.h | 24 +++++++++++++++++++ src/backend/gdi.c | 4 ++-- src/backend/wayland/wayland.c | 2 +- src/core.c | 2 +- src/widget/chart.c | 45 +++++++++++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 include/Mw/Widget/Chart.h diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index 06a115b68..5b6526566 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -7,6 +7,7 @@ #define PaddingContent 2 MwWidget window, menu, table; +MwWidget wcal, wclock; MwMenu e; static void MWAPI resize(MwWidget handle, void* user, void* call) { @@ -21,6 +22,24 @@ static void MWAPI resize(MwWidget handle, void* user, void* call) { NULL); } +static void MWAPI tick(MwWidget handle, void* user, void* call) { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + + MwVaApply(wcal, + MwNyear, (int)tm.tm_year + 1900, + MwNmonth, (int)tm.tm_mon, + MwNdate, (int)tm.tm_mday, + MwNday, (int)tm.tm_wday, + NULL); + + MwVaApply(wclock, + MwNhour, (int)tm.tm_hour, + MwNminute, (int)tm.tm_min, + MwNsecond, (int)tm.tm_sec, + NULL); +} + static void MWAPI resize_content(MwWidget handle, void* user, void* call) { MwWidget* ws = MwGetChildren(handle); if(ws != NULL) { @@ -241,17 +260,15 @@ int main() { } } - f = frame("Calendar", -PaddingContent, -PaddingContent, MwCalendarClass, - MwNscale, 1, - NULL); + f = frame("Calendar", -PaddingContent, -PaddingContent, MwCalendarClass, + MwNscale, 1, + NULL); + wcal = child(f); - f = frame("Clock", -PaddingContent, -PaddingContent, MwClockClass, - MwNhour, 15, - MwNminute, 0, - MwNsecond, 10, - NULL); + f = frame("Clock", -PaddingContent, -PaddingContent, MwClockClass, NULL); + wclock = child(f); - f = frame("Chart", -PaddingContent, -PaddingContent, MwCalendarClass, + f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); @@ -321,7 +338,9 @@ int main() { NULL); MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + tick(window, NULL, NULL); resize(window, NULL, NULL); MwVaApply(table, diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index 7997bb670..abdc073d3 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Mw/Widget/Chart.h b/include/Mw/Widget/Chart.h new file mode 100644 index 000000000..6ab404b2a --- /dev/null +++ b/include/Mw/Widget/Chart.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Chart.h + * @brief Chart widget + */ +#ifndef __MW_WIDGET_CHART_H__ +#define __MW_WIDGET_CHART_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Chart widget class + */ +MWDECL MwClass MwChartClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/backend/gdi.c b/src/backend/gdi.c index eace1d382..660a0fc32 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -1000,11 +1000,11 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { RECT rc; int w, h; + GetClientRect(handle->gdi.hWnd, &rc); + SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp); SetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE, (LPARAM)WS_EX_TOOLWINDOW); - GetClientRect(handle->gdi.hWnd, &rc); - w = rc.right - rc.left; h = rc.bottom - rc.top; diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 2b5fce98f..3c2d9bd61 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1984,7 +1984,7 @@ static int MwLLWaylandCallInitImpl(void) { #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { - loadWayland = 1; + loadWayland = 0; } #endif diff --git a/src/core.c b/src/core.c index 21b16eab6..481fa340f 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif -//#define USE_CLASSIC_THEME +// #define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ diff --git a/src/widget/chart.c b/src/widget/chart.c index e69de29bb..46f248ef7 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -0,0 +1,45 @@ +#include + +static int wcreate(MwWidget handle) { + return 0; +} + +static void draw(MwWidget handle) { + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwRect r; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNhour) == 0 || strcmp(key, MwNminute) == 0 || strcmp(key, MwNsecond) == 0) MwForceRender(handle); +} + +MwClassRec MwChartClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwChartClass = &MwChartClassRec; From 120eb5baaf5124243203b9a8f84481bd71a3eab2 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 01:09:57 +0900 Subject: [PATCH 34/90] bar chart --- examples/basic/periodic.c | 5 + include/Mw/Constants.h | 4 + include/Mw/Draw.h | 8 ++ include/Mw/StringDefs.h | 1 + include/Mw/TypeDefs.h | 12 +++ include/Mw/Widget/Chart.h | 33 ++++++ include/Mw/Widget/ComboBox.h | 17 +++ milsko.xml | 51 ++++++++- src/core.c | 2 +- src/draw.c | 61 +++++++++-- src/widget/chart.c | 203 +++++++++++++++++++++++++++++++---- src/widget/combobox.c | 50 ++++++--- src/widget/treeview.c | 1 + src/widget/window.c | 1 + 14 files changed, 405 insertions(+), 44 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index 5b6526566..db833c67c 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -270,6 +270,11 @@ int main() { f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, NULL); + w = child(f); + MwChartAdd(w, -1, "A", -100, NULL); + MwChartAdd(w, -1, "B", 100, NULL); + MwChartAdd(w, -1, "C", 200, NULL); + MwChartAdd(w, -1, "D", 300, NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 15853ff7b..ad29792ef 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -113,6 +113,10 @@ enum MwCLIPBOARD { MwCLIPBOARD_PRIMARY, }; +enum MwCHART { + MwCHART_BAR = 0 +}; + enum MwMOUSE { MwMOUSE_LEFT = 1, MwMOUSE_MIDDLE, diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index 542aac57e..e3c6991f1 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -60,6 +60,14 @@ MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, i */ MWDECL void MWAPI MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); +/*! + * @brief Draws a rectangle + * @param handle Widget + * @param rect Rectangle area + * @param color Color + */ +MWDECL void MWAPI MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color); + /*! * @brief Draws a filled rectangle that fades to a darker color * @param handle Widget diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 39730db7d..d820ea470 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -57,6 +57,7 @@ #define MwNhour "Ihour" #define MwNminute "Iminute" #define MwNsecond "Isecond" +#define MwNtype "Itype" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index a9bc3cf90..0be60e855 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -30,6 +30,8 @@ typedef struct _MwBox* MwBox; typedef struct _MwSubWindow* MwSubWindow; typedef struct _MwTab* MwTab; typedef struct _MwTable* MwTable; +typedef struct _MwChartEntry MwChartEntry; +typedef struct _MwChart* MwChart; typedef struct _MwMouse MwMouse; typedef struct _MwTTFInfo* MwTTFInfo; #ifdef _MILSKO @@ -247,6 +249,16 @@ struct _MwTab { char** names; }; +struct _MwChartEntry { + char* name; + char* color; + double value; +}; + +struct _MwChart { + MwChartEntry* entries; +}; + struct _MwMouse { MwPoint point; int button; diff --git a/include/Mw/Widget/Chart.h b/include/Mw/Widget/Chart.h index 6ab404b2a..d0957a2b2 100644 --- a/include/Mw/Widget/Chart.h +++ b/include/Mw/Widget/Chart.h @@ -17,6 +17,39 @@ extern "C" { */ MWDECL MwClass MwChartClass; +/*! + * @brief Adds the entry to the chart + * @param handle Widget + * @param index Index + * @param text Text + * @param value Value + * @return Index + */ +MwInline int MwChartAdd(MwWidget handle, int index, const char* text, double value, const char* color) { + int out; + + MwVaWidgetExecute(handle, "mwChartAdd", (void*)&out, index, text, value, color); + + return out; +} + +/*! + * @brief Deletes item from the chart + * @param handle Widget + * @param index Index + */ +MwInline void MwChartDelete(MwWidget handle, int index) { + MwVaWidgetExecute(handle, "mwChartDelete", NULL, index); +} + +/*! + * @brief Resets the chart + * @param handle Widget + */ +MwInline void MwChartReset(MwWidget handle) { + MwVaWidgetExecute(handle, "mwChartReset", NULL); +} + #ifdef __cplusplus } #endif diff --git a/include/Mw/Widget/ComboBox.h b/include/Mw/Widget/ComboBox.h index 7b2dc2fca..fd5c3430d 100644 --- a/include/Mw/Widget/ComboBox.h +++ b/include/Mw/Widget/ComboBox.h @@ -41,6 +41,23 @@ MwInline const char* MwComboBoxGet(MwWidget handle, int index) { return text; } +/*! + * @brief Deletes the entry from combobox + * @param handle Widget + * @param index Index + */ +MwInline void MwComboBoxDelete(MwWidget handle, int index) { + MwVaWidgetExecute(handle, "mwComboBoxDelete", NULL, index); +} + +/*! + * @brief Resets the combobox + * @param handle Widget + */ +MwInline void MwComboBoxReset(MwWidget handle) { + MwVaWidgetExecute(handle, "mwComboBoxReset", NULL); +} + #ifdef __cplusplus } #endif diff --git a/milsko.xml b/milsko.xml index 573b84d2d..30efce111 100644 --- a/milsko.xml +++ b/milsko.xml @@ -1,10 +1,11 @@ @@ -228,6 +230,9 @@ 0 + + 0 + 1 @@ -649,6 +654,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -879,9 +907,26 @@ - - + + + + + + + + + + + + + + + + + + + diff --git a/src/core.c b/src/core.c index 481fa340f..2982c1ed9 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif -// #define USE_CLASSIC_THEME +#define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ diff --git a/src/draw.c b/src/draw.c index bbd02642b..5cbfd22b0 100644 --- a/src/draw.c +++ b/src/draw.c @@ -101,22 +101,67 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwPoint p[4]; + MwRect r = *rect; - p[0].x = rect->x; - p[0].y = rect->y; + if(r.width < 0) { + r.width *= -1; + r.x -= r.width; + } - p[1].x = rect->x + rect->width; - p[1].y = rect->y; + if(r.height < 0) { + r.height *= -1; + r.y -= r.height; + } - p[2].x = rect->x + rect->width; - p[2].y = rect->y + rect->height; + p[0].x = r.x; + p[0].y = r.y; - p[3].x = rect->x; - p[3].y = rect->y + rect->height; + p[1].x = r.x + r.width; + p[1].y = r.y; + + p[2].x = r.x + r.width; + p[2].y = r.y + r.height; + + p[3].x = r.x; + p[3].y = r.y + r.height; MwLLPolygon(handle->lowlevel, p, 4, color); } +void MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color) { + MwPoint p[5]; + MwRect r = *rect; + + if(r.width < 0) { + r.width *= -1; + r.x -= r.width; + } + + if(r.height < 0) { + r.height *= -1; + r.y -= r.height; + } + + p[0].x = r.x; + p[0].y = r.y; + + p[1].x = r.x + r.width; + p[1].y = r.y; + + p[2].x = r.x + r.width; + p[2].y = r.y + r.height; + + p[3].x = r.x; + p[3].y = r.y + r.height; + + p[4] = p[0]; + + MwLLLine(handle->lowlevel, &p[0], color); + MwLLLine(handle->lowlevel, &p[1], color); + MwLLLine(handle->lowlevel, &p[2], color); + MwLLLine(handle->lowlevel, &p[3], color); +} + void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; int y; diff --git a/src/widget/chart.c b/src/widget/chart.c index 46f248ef7..b01451383 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -1,12 +1,62 @@ #include +#include "../../external/stb_ds.h" + +static const char* palette0[] = { + "#800", + "#080", + "#880", + "#008", + "#808", + "#088", + "#888", + "#f00", + "#0f0", + "#ff0", + "#00f", + "#f0f", + "#0ff", + "#fff", + NULL}; + static int wcreate(MwWidget handle) { + MwChart c = malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + + handle->internal = c; + + MwSetDefault(handle); + return 0; } +static void destroy(MwWidget handle) { + MwChartReset(handle); + free(handle->internal); +} + static void draw(MwWidget handle) { - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r; + MwChart c = handle->internal; + int i; + const char** colors = palette0; + int n; + int gap; + int width; + MwRect node; + double min = 0xffffffff; + double max = -0xffffffff; + int space = MwTextHeight(handle, NULL, "M"); + MwPoint p[2]; + + for(n = 0; colors[n] != NULL; n++); + + for(i = 0; i < arrlen(c->entries); i++) { + if(min > c->entries[i].value) min = c->entries[i].value; + if(max < c->entries[i].value) max = c->entries[i].value; + } r.x = 0; r.y = 0; @@ -14,31 +64,144 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); + if(min > 0) { + min = 0; + } else if(min < 0) { + min -= r.height / 10; + } + + node.x = 16; + node.y = 0; + + width = (r.width - node.x) * 2 / (arrlen(c->entries) * 3 + 1); + gap = width / 2; + + p[0].x = node.x; + p[0].y = r.height - space; + + p[1].x = node.x + (width + gap) * arrlen(c->entries) + gap; + p[1].y = p[0].y; + MwLLLine(handle->lowlevel, &p[0], border); + + p[0].y = r.height - space - abs(min / (max - min) * (r.height - space)); + p[1].y = p[0].y; + MwLLLine(handle->lowlevel, &p[0], border); + MwDrawText(handle, NULL, p, "0", MwALIGNMENT_END, border); + + p[0].x = node.x; + p[0].y = 0; + + p[1].x = node.x; + p[1].y = r.height - space; + MwLLLine(handle->lowlevel, &p[0], border); + + node.width = width; + for(i = 0; i < arrlen(c->entries); i++) { + MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + + node.x += gap; + + node.height = c->entries[i].value / (max - min) * (r.height - space); + node.y = r.height - space - node.height - abs(min / (max - min) * (r.height - space)); + + MwDrawRect(handle, &node, color); + MwDrawRectLine(handle, &node, border); + + p[0].x = node.x + node.width / 2; + p[0].y = r.height - space / 2; + + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + + node.x += node.width; + + MwLLFreeColor(color); + } + + MwLLFreeColor(border); MwLLFreeColor(base); } static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNhour) == 0 || strcmp(key, MwNminute) == 0 || strcmp(key, MwNsecond) == 0) MwForceRender(handle); + if(strcmp(key, MwNtype) == 0) MwForceRender(handle); +} + +static int mwChartAddImpl(MwWidget handle, int index, const char* text, double value, const char* color) { + MwChart c = handle->internal; + MwChartEntry e; + + if(index == -1) index = arrlen(c->entries); + + e.name = MwStringDuplicate(text); + e.color = color == NULL ? NULL : MwStringDuplicate(color); + e.value = value; + + arrins(c->entries, index, e); + + MwForceRender(handle); + + return index; +} + +static void mwChartDeleteImpl(MwWidget handle, int index) { + MwChart c = handle->internal; + + if(index == -1) index = arrlen(c->entries) - 1; + + free(c->entries[index].name); + if(c->entries[index].color != NULL) free(c->entries[index].color); + arrdel(c->entries, index); + + MwForceRender(handle); +} + +static void mwChartResetImpl(MwWidget handle) { + MwChart c = handle->internal; + int i; + + for(i = 0; i < arrlen(c->entries); i++) { + free(c->entries[i].name); + if(c->entries[i].color != NULL) free(c->entries[i].color); + } + arrfree(c->entries); + + MwForceRender(handle); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwChartAdd") == 0) { + int index = va_arg(va, int); + const char* text = va_arg(va, const char*); + double value = va_arg(va, double); + const char* color = va_arg(va, const char*); + *(int*)out = mwChartAddImpl(handle, index, text, value, color); + } + if(strcmp(name, "mwChartDelete") == 0) { + int index = va_arg(va, int); + mwChartDeleteImpl(handle, index); + } + if(strcmp(name, "mwChartReset") == 0) { + mwChartResetImpl(handle); + } } MwClassRec MwChartClassRec = { - wcreate, /* create */ - NULL, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, /* props_change */ + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + MwForceRender, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ NULL, NULL, NULL}; diff --git a/src/widget/combobox.c b/src/widget/combobox.c index e53647dde..5502a0702 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -20,12 +20,8 @@ static int wcreate(MwWidget handle) { static void destroy(MwWidget handle) { MwComboBox cb = handle->internal; - int i; - for(i = 0; i < arrlen(cb->list); i++) { - free(cb->list[i]); - } - arrfree(cb->list); + MwComboBoxReset(handle); free(handle->internal); } @@ -145,6 +141,13 @@ static void prop_change(MwWidget handle, const char* prop) { } } +static void parent_resize(MwWidget handle) { + MwComboBox cb = handle->internal; + if(cb->opened) { + click(handle); + } +} + static void mwComboBoxAddImpl(MwWidget handle, int index, const char* text) { MwComboBox cb = handle->internal; char* t = MwStringDuplicate(text); @@ -153,7 +156,7 @@ static void mwComboBoxAddImpl(MwWidget handle, int index, const char* text) { arrins(cb->list, index, t); - if(index <= MwGetInteger(handle, MwNvalue)) MwForceRender(handle); + MwForceRender(handle); } static const char* mwComboBoxGetImpl(MwWidget handle, int index) { @@ -162,6 +165,29 @@ static const char* mwComboBoxGetImpl(MwWidget handle, int index) { return cb->list[index]; } +static void mwComboBoxDeleteImpl(MwWidget handle, int index) { + MwComboBox cb = handle->internal; + int n = MwGetInteger(handle, MwNvalue); + + free(cb->list[index]); + arrdel(cb->list, index); + + if(index < n && n > 0) { + MwSetInteger(handle, MwNvalue, n - 1); + } + + MwForceRender(handle); +} + +static void mwComboBoxResetImpl(MwWidget handle) { + MwComboBox cb = handle->internal; + + arrfree(cb->list); + MwSetInteger(handle, MwNvalue, 0); + + MwForceRender(handle); +} + static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwComboBoxAdd") == 0) { int index = va_arg(va, int); @@ -172,12 +198,12 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v int index = va_arg(va, int); *(const char**)out = mwComboBoxGetImpl(handle, index); } -} - -static void parent_resize(MwWidget handle) { - MwComboBox cb = handle->internal; - if(cb->opened) { - click(handle); + if(strcmp(name, "mwComboBoxDelete") == 0) { + int index = va_arg(va, int); + mwComboBoxDeleteImpl(handle, index); + } + if(strcmp(name, "mwComboBoxReset") == 0) { + mwComboBoxResetImpl(handle); } } diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 3fba309e5..d07d355e5 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -317,6 +317,7 @@ static int wcreate(MwWidget handle) { } static void destroy(MwWidget handle) { + MwTreeViewReset(handle); free(handle->internal); } diff --git a/src/widget/window.c b/src/widget/window.c index 3d0afe254..9ea16a304 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -51,6 +51,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v mwWindowShouldCloseImpl(handle, out); } } + MwClassRec MwWindowClassRec = { wcreate, /* create */ NULL, /* destroy */ From d87569d7c00e0d422f1d35b43073892c266ca3ee Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 02:51:00 +0900 Subject: [PATCH 35/90] things --- examples/basic/periodic.c | 18 ++-- include/Mw/Constants.h | 3 +- include/Mw/Draw.h | 7 ++ milsko.xml | 3 + src/core.c | 2 +- src/draw.c | 32 +++--- src/widget/chart.c | 198 ++++++++++++++++++++++++++++++-------- 7 files changed, 196 insertions(+), 67 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index db833c67c..e40994d90 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -269,12 +269,17 @@ int main() { wclock = child(f); f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, + MwNtype, MwCHART_3D_BAR, + MwNcolumnSpan, 2, NULL); w = child(f); - MwChartAdd(w, -1, "A", -100, NULL); - MwChartAdd(w, -1, "B", 100, NULL); - MwChartAdd(w, -1, "C", 200, NULL); - MwChartAdd(w, -1, "D", 300, NULL); + MwChartAdd(w, -1, "A", -400, NULL); + MwChartAdd(w, -1, "B", -200, NULL); + MwChartAdd(w, -1, "C", -100, NULL); + MwChartAdd(w, -1, "D", 100, NULL); + MwChartAdd(w, -1, "E", 200, NULL); + MwChartAdd(w, -1, "F", 400, NULL); + MwChartAdd(w, -1, "G", 800, NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); @@ -288,6 +293,7 @@ int main() { f = frame("Label", -PaddingContent, -PaddingContent, MwLabelClass, MwNtext, "Epic text\nNewline can be used too!", + MwNcolumnSpan, 2, NULL); f = frame("ListBox", -PaddingContent, -PaddingContent, MwListBoxClass, @@ -321,9 +327,7 @@ int main() { MwNtitle, "Sub window 2", NULL); - f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, - MwNcolumnSpan, 2, - NULL); + f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, NULL); w = child(f); MwSetText(MwTabAdd(w, "ABC"), MwNbackground, "#f00"); MwSetText(MwTabAdd(w, "DEF"), MwNbackground, "#0f0"); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index ad29792ef..6df447d43 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -114,7 +114,8 @@ enum MwCLIPBOARD { }; enum MwCHART { - MwCHART_BAR = 0 + MwCHART_BAR = 0, + MwCHART_3D_BAR, }; enum MwMOUSE { diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index e3c6991f1..ad13c6032 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -52,6 +52,13 @@ MWDECL void MWAPI MwColorTableInit(void); */ MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b); +/*! + * @brief Fix a rectangle + * @param handle Widget + * @param rect Rectangle area + */ +MWDECL void MWAPI MwFixRect(MwRect* rect); + /*! * @brief Draws a filled rectangle * @param handle Widget diff --git a/milsko.xml b/milsko.xml index 30efce111..6bf802b01 100644 --- a/milsko.xml +++ b/milsko.xml @@ -232,6 +232,7 @@ 0 + 1 @@ -657,6 +658,8 @@ + + diff --git a/src/core.c b/src/core.c index 2982c1ed9..481fa340f 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif -#define USE_CLASSIC_THEME +// #define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ diff --git a/src/draw.c b/src/draw.c index 5cbfd22b0..eb15c76ba 100644 --- a/src/draw.c +++ b/src/draw.c @@ -99,19 +99,23 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) return MwLLAllocColor(handle->lowlevel, cr, cg, cb); } +void MwFixRect(MwRect* rect) { + if(rect->width < 0) { + rect->width *= -1; + rect->x -= rect->width; + } + + if(rect->height < 0) { + rect->height *= -1; + rect->y -= rect->height; + } +} + void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwPoint p[4]; MwRect r = *rect; - if(r.width < 0) { - r.width *= -1; - r.x -= r.width; - } - - if(r.height < 0) { - r.height *= -1; - r.y -= r.height; - } + MwFixRect(&r); p[0].x = r.x; p[0].y = r.y; @@ -132,15 +136,7 @@ void MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color) { MwPoint p[5]; MwRect r = *rect; - if(r.width < 0) { - r.width *= -1; - r.x -= r.width; - } - - if(r.height < 0) { - r.height *= -1; - r.y -= r.height; - } + MwFixRect(&r); p[0].x = r.x; p[0].y = r.y; diff --git a/src/widget/chart.c b/src/widget/chart.c index b01451383..34d8f4e28 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -27,6 +27,8 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); + MwSetInteger(handle, MwNtype, MwCHART_BAR); + return 0; } @@ -35,6 +37,35 @@ static void destroy(MwWidget handle) { free(handle->internal); } +static void draw_line(MwWidget handle, const char* text, double x, double y, double width, double height, MwLLColor color) { + MwPoint p[2]; + int type = MwGetInteger(handle, MwNtype); + + p[0].x = x; + p[0].y = y; + + p[1].x = x + width; + p[1].y = p[0].y; + MwDrawText(handle, NULL, p, text, MwALIGNMENT_END, color); + + if(type == MwCHART_3D_BAR) { + MwPoint p2[2]; + + p2[0] = p[0]; + p2[1] = p[0]; + + p2[1].x += height; + p2[1].y -= height; + + MwLLLine(handle->lowlevel, &p2[0], color); + + p[0].x += height; + p[0].y -= height; + p[1].y -= height; + } + MwLLLine(handle->lowlevel, &p[0], color); +} + static void draw(MwWidget handle) { MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); @@ -46,75 +77,162 @@ static void draw(MwWidget handle) { int gap; int width; MwRect node; - double min = 0xffffffff; - double max = -0xffffffff; + double vmin = 0xffffffff; + double vmax = -0xffffffff; int space = MwTextHeight(handle, NULL, "M"); MwPoint p[2]; + int type = MwGetInteger(handle, MwNtype); for(n = 0; colors[n] != NULL; n++); for(i = 0; i < arrlen(c->entries); i++) { - if(min > c->entries[i].value) min = c->entries[i].value; - if(max < c->entries[i].value) max = c->entries[i].value; + if(vmin > c->entries[i].value) vmin = c->entries[i].value; + if(vmax < c->entries[i].value) vmax = c->entries[i].value; } + if(MwGetInteger(handle, MwNminValue) != MwDEFAULT) vmin = MwGetInteger(handle, MwNminValue); + if(MwGetInteger(handle, MwNmaxValue) != MwDEFAULT) vmax = MwGetInteger(handle, MwNmaxValue); + r.x = 0; r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); - if(min > 0) { - min = 0; - } else if(min < 0) { - min -= r.height / 10; - } + if(type == MwCHART_BAR || type == MwCHART_3D_BAR) { + double s = 1.5; + double ovmin = vmin; + double ovmax = vmax; + double twidth; + char buf[128]; - node.x = 16; - node.y = 0; + node.x = 128; + node.y = 0; - width = (r.width - node.x) * 2 / (arrlen(c->entries) * 3 + 1); - gap = width / 2; + width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); + gap = width / s; - p[0].x = node.x; - p[0].y = r.height - space; + twidth = (width + gap) * arrlen(c->entries) + gap; - p[1].x = node.x + (width + gap) * arrlen(c->entries) + gap; - p[1].y = p[0].y; - MwLLLine(handle->lowlevel, &p[0], border); + if(vmin > 0) { + vmin = 0; + } else if(vmin < 0) { + vmin -= (double)width / r.height * (vmax - vmin); + } - p[0].y = r.height - space - abs(min / (max - min) * (r.height - space)); - p[1].y = p[0].y; - MwLLLine(handle->lowlevel, &p[0], border); - MwDrawText(handle, NULL, p, "0", MwALIGNMENT_END, border); + if(vmax < 0) { + vmax = 0; + } else if(vmax > 0) { + vmax += (double)width / r.height * (vmax - vmin); + } - p[0].x = node.x; - p[0].y = 0; + sprintf(buf, "%.2f", ovmax); + draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - p[1].x = node.x; - p[1].y = r.height - space; - MwLLLine(handle->lowlevel, &p[0], border); + draw_line(handle, "0", node.x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - node.width = width; - for(i = 0; i < arrlen(c->entries); i++) { - MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + sprintf(buf, "%.2f", ovmin); + draw_line(handle, buf, node.x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - node.x += gap; + p[0].x = node.x; + p[0].y = 0; - node.height = c->entries[i].value / (max - min) * (r.height - space); - node.y = r.height - space - node.height - abs(min / (max - min) * (r.height - space)); + p[1].x = node.x; + p[1].y = r.height - space; + MwLLLine(handle->lowlevel, &p[0], border); - MwDrawRect(handle, &node, color); - MwDrawRectLine(handle, &node, border); + p[0].x = node.x; + p[0].y = r.height - space; - p[0].x = node.x + node.width / 2; - p[0].y = r.height - space / 2; + p[1].x = node.x + twidth; + p[1].y = p[0].y; + MwLLLine(handle->lowlevel, &p[0], border); - MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + node.width = width; + for(i = 0; i < arrlen(c->entries); i++) { + int ColorDiff = MwGetColorDifference(handle); + MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwPoint persp_top[5]; + MwPoint persp_right[5]; - node.x += node.width; + node.x += gap; - MwLLFreeColor(color); + node.height = -c->entries[i].value / (vmax - vmin) * (r.height - space); + node.y = (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space); + + MwDrawRect(handle, &node, color); + + if(type == MwCHART_3D_BAR) { + MwRect node2 = node; + + MwFixRect(&node2); + + persp_top[0] = *(MwPoint*)&node2; + persp_top[1] = *(MwPoint*)&node2; + persp_top[1].x += node2.width; + + persp_top[2] = persp_top[1]; + persp_top[3] = persp_top[0]; + + persp_top[2].x += node2.width / 2; + persp_top[2].y -= node2.width / 2; + + persp_top[3].x += node2.width / 2; + persp_top[3].y -= node2.width / 2; + + persp_top[4] = persp_top[0]; + + MwLLPolygon(handle->lowlevel, persp_top, 4, colorl); + + persp_right[0] = *(MwPoint*)&node2; + persp_right[1] = *(MwPoint*)&node2; + persp_right[0].x += node2.width; + persp_right[1].x += node2.width; + persp_right[1].y += node2.height; + + persp_right[2] = persp_right[1]; + persp_right[3] = persp_right[0]; + + persp_right[2].x += node2.width / 2; + persp_right[2].y -= node2.width / 2; + + persp_right[3].x += node2.width / 2; + persp_right[3].y -= node2.width / 2; + + persp_right[4] = persp_right[0]; + + MwLLPolygon(handle->lowlevel, persp_right, 4, colord); + } + + if(!MwGetInteger(handle, MwNmodernLook)) { + MwDrawRectLine(handle, &node, border); + + if(type == MwCHART_3D_BAR) { + MwLLLine(handle->lowlevel, &persp_top[0], border); + MwLLLine(handle->lowlevel, &persp_top[1], border); + MwLLLine(handle->lowlevel, &persp_top[2], border); + MwLLLine(handle->lowlevel, &persp_top[3], border); + + MwLLLine(handle->lowlevel, &persp_right[0], border); + MwLLLine(handle->lowlevel, &persp_right[1], border); + MwLLLine(handle->lowlevel, &persp_right[2], border); + MwLLLine(handle->lowlevel, &persp_right[3], border); + } + } + + p[0].x = node.x + node.width / 2; + p[0].y = r.height - space / 2; + + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + + node.x += node.width; + + MwLLFreeColor(colord); + MwLLFreeColor(colorl); + MwLLFreeColor(color); + } } MwLLFreeColor(border); From 51aaf52422d89440cb58987adb83863777b4c0da Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 02:55:14 +0900 Subject: [PATCH 36/90] fix --- src/widget/chart.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/widget/chart.c b/src/widget/chart.c index 34d8f4e28..cec1c9ae2 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -10,13 +10,6 @@ static const char* palette0[] = { "#808", "#088", "#888", - "#f00", - "#0f0", - "#ff0", - "#00f", - "#f0f", - "#0ff", - "#fff", NULL}; static int wcreate(MwWidget handle) { From b86fe4f306a1455ca6ff24899d5ff8c8b3008ba9 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 02:59:35 +0900 Subject: [PATCH 37/90] fix --- src/widget/chart.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/widget/chart.c b/src/widget/chart.c index cec1c9ae2..83e3a5e06 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -12,6 +12,8 @@ static const char* palette0[] = { "#888", NULL}; +#define NUMFMT "%.2f" + static int wcreate(MwWidget handle) { MwChart c = malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); @@ -99,7 +101,18 @@ static void draw(MwWidget handle) { double twidth; char buf[128]; - node.x = 128; + node.x = 0; + + for(i = 0; i < arrlen(c->entries); i++) { + int w; + + sprintf(buf, NUMFMT, c->entries[i].value); + + w = MwTextWidth(handle, NULL, buf); + + if(node.x < w) node.x = w; + } + node.y = 0; width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); @@ -119,12 +132,12 @@ static void draw(MwWidget handle) { vmax += (double)width / r.height * (vmax - vmin); } - sprintf(buf, "%.2f", ovmax); + sprintf(buf, NUMFMT, ovmax); draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); draw_line(handle, "0", node.x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - sprintf(buf, "%.2f", ovmin); + sprintf(buf, NUMFMT, ovmin); draw_line(handle, buf, node.x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); p[0].x = node.x; From 95a7db7f5449f753e7919d1775c818d833f09df1 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 03:07:25 +0900 Subject: [PATCH 38/90] ok --- examples/basic/periodic.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index e40994d90..c17cfd07d 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -273,13 +273,14 @@ int main() { MwNcolumnSpan, 2, NULL); w = child(f); - MwChartAdd(w, -1, "A", -400, NULL); - MwChartAdd(w, -1, "B", -200, NULL); - MwChartAdd(w, -1, "C", -100, NULL); - MwChartAdd(w, -1, "D", 100, NULL); - MwChartAdd(w, -1, "E", 200, NULL); - MwChartAdd(w, -1, "F", 400, NULL); - MwChartAdd(w, -1, "G", 800, NULL); + MwChartAdd(w, -1, "A", -800, NULL); + MwChartAdd(w, -1, "B", -400, NULL); + MwChartAdd(w, -1, "C", -200, NULL); + MwChartAdd(w, -1, "D", -100, NULL); + MwChartAdd(w, -1, "E", 100, NULL); + MwChartAdd(w, -1, "F", 200, NULL); + MwChartAdd(w, -1, "G", 400, NULL); + MwChartAdd(w, -1, "H", 800, NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); From 3ac6b8387cf0e18e7215736a0f9ed7f0ef98bcce Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 03:37:00 +0900 Subject: [PATCH 39/90] change font size --- resource/font/{7x14.bdf => 7x13.bdf} | 5122 ++++++++++++------------ resource/font/{7x14B.bdf => 7x13B.bdf} | 4991 ++++++++++++----------- src/default.c | 20 + src/text/font/boldfont.c | 512 +-- src/text/font/font.c | 514 +-- src/text/text.c | 4 +- 6 files changed, 5694 insertions(+), 5469 deletions(-) rename resource/font/{7x14.bdf => 7x13.bdf} (54%) rename resource/font/{7x14B.bdf => 7x13B.bdf} (53%) diff --git a/resource/font/7x14.bdf b/resource/font/7x13.bdf similarity index 54% rename from resource/font/7x14.bdf rename to resource/font/7x13.bdf index 6e6c13edc..c70134182 100644 --- a/resource/font/7x14.bdf +++ b/resource/font/7x13.bdf @@ -1,12 +1,27 @@ STARTFONT 2.1 -COMMENT -COMMENT Donated by H. Kagotani ; public domain -COMMENT font from Japan -COMMENT -FONT -Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-1 -SIZE 7 75 75 -FONTBOUNDINGBOX 7 14 0 -2 -STARTPROPERTIES 19 +COMMENT $XConsortium: 7x13.bdf,v 1.11 92/04/02 14:25:38 gildea Exp $ +COMMENT +COMMENT Copyright (c) 1990 Stephen Gildea +COMMENT +COMMENT Permission to use, copy, modify, and distribute this software for +COMMENT any purpose is hereby granted without fee, provided that the above +COMMENT copyright notice and this permission notice appear in all copies. +COMMENT The authors make no representations about the suitability of this +COMMENT software for any purpose. It is provided "as is" without express +COMMENT or implied warranty. +COMMENT +COMMENT Designed by Stephen Gildea +COMMENT Original design November 1989. +COMMENT Current version June 1990. +COMMENT +COMMENT Characters above 127 designed and made by +COMMENT Thomas Bagli (pyramid!pcsbst!tom@uunet.UU.NET) +COMMENT PCS Computer Systeme, West Germany +COMMENT +FONT -Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1 +SIZE 13 78 78 +FONTBOUNDINGBOX 7 13 0 -2 +STARTPROPERTIES 21 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" @@ -14,67 +29,247 @@ WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "" -PIXEL_SIZE 14 -POINT_SIZE 130 +PIXEL_SIZE 13 +POINT_SIZE 120 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 70 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" -DEFAULT_CHAR 32 +UNDERLINE_POSITION -1 +DESTINATION 1 +DEFAULT_CHAR 0 FONT_DESCENT 2 -FONT_ASCENT 12 -COPYRIGHT "Public domain font. Share and enjoy." +FONT_ASCENT 11 +DATE "June 1990" ENDPROPERTIES -CHARS 209 -STARTCHAR 0001 +CHARS 224 +STARTCHAR Error +ENCODING 0 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +78 +78 +78 +78 +78 +78 +78 +78 +78 +78 +78 +00 +ENDCHAR +STARTCHAR C001 ENCODING 1 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -18 -3C -3C -7E -7E -3C -3C -18 -18 +00 +00 +00 +20 +70 +f8 +70 +20 +00 00 00 ENDCHAR -STARTCHAR 0002 +STARTCHAR C002 ENCODING 2 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP +00 +a8 54 -AA +a8 54 -AA +a8 54 -AA +a8 54 -AA +a8 54 -AA +a8 54 -AA -54 -AA ENDCHAR -STARTCHAR 000b +STARTCHAR HT +ENCODING 3 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +90 +90 +f0 +90 +90 +1c +08 +08 +08 +08 +00 +ENDCHAR +STARTCHAR FF +ENCODING 4 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +f0 +80 +e0 +80 +80 +3c +20 +38 +20 +20 +00 +ENDCHAR +STARTCHAR CR +ENCODING 5 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +70 +80 +80 +80 +70 +38 +24 +38 +28 +24 +00 +ENDCHAR +STARTCHAR LF +ENCODING 6 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +80 +80 +80 +80 +f0 +3c +20 +38 +20 +20 +00 +ENDCHAR +STARTCHAR Degree +ENCODING 7 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +70 +88 +88 +70 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Plus/Minus +ENCODING 8 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +20 +20 +f8 +20 +20 +00 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR NL +ENCODING 9 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +90 +d0 +b0 +90 +90 +20 +20 +20 +20 +3c +00 +ENDCHAR +STARTCHAR VT +ENCODING 10 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +88 +88 +50 +50 +20 +7c +10 +10 +10 +10 +00 +ENDCHAR +STARTCHAR C013 ENCODING 11 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -82,8 +277,7 @@ BITMAP 10 10 10 -10 -F0 +f0 00 00 00 @@ -91,11 +285,11 @@ F0 00 00 ENDCHAR -STARTCHAR 000c +STARTCHAR C014 ENCODING 12 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -103,8 +297,7 @@ BITMAP 00 00 00 -00 -F0 +f0 10 10 10 @@ -112,11 +305,11 @@ F0 10 10 ENDCHAR -STARTCHAR 000d +STARTCHAR C015 ENCODING 13 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -124,8 +317,7 @@ BITMAP 00 00 00 -00 -1E +1e 10 10 10 @@ -133,11 +325,11 @@ BITMAP 10 10 ENDCHAR -STARTCHAR 000e +STARTCHAR C016 ENCODING 14 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -145,8 +337,7 @@ BITMAP 10 10 10 -10 -1E +1e 00 00 00 @@ -154,11 +345,11 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 000f +STARTCHAR C017 ENCODING 15 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -166,8 +357,7 @@ BITMAP 10 10 10 -10 -FE +fe 10 10 10 @@ -175,16 +365,15 @@ FE 10 10 ENDCHAR -STARTCHAR 0010 +STARTCHAR C020 ENCODING 16 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -FE -00 00 00 +fe 00 00 00 @@ -196,18 +385,17 @@ FE 00 00 ENDCHAR -STARTCHAR 0011 +STARTCHAR C021 ENCODING 17 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -FE -00 +fe 00 00 00 @@ -217,11 +405,11 @@ FE 00 00 ENDCHAR -STARTCHAR 0012 +STARTCHAR C022 ENCODING 18 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -229,8 +417,7 @@ BITMAP 00 00 00 -00 -FE +fe 00 00 00 @@ -238,11 +425,11 @@ FE 00 00 ENDCHAR -STARTCHAR 0013 +STARTCHAR C023 ENCODING 19 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -252,18 +439,17 @@ BITMAP 00 00 00 -00 -FE +fe 00 00 00 00 ENDCHAR -STARTCHAR 0014 +STARTCHAR C024 ENCODING 20 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -275,16 +461,15 @@ BITMAP 00 00 00 +fe 00 00 -00 -FE ENDCHAR -STARTCHAR 0015 +STARTCHAR C025 ENCODING 21 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -292,8 +477,7 @@ BITMAP 10 10 10 -10 -1E +1e 10 10 10 @@ -301,11 +485,11 @@ BITMAP 10 10 ENDCHAR -STARTCHAR 0016 +STARTCHAR C026 ENCODING 22 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -313,8 +497,7 @@ BITMAP 10 10 10 -10 -F0 +f0 10 10 10 @@ -322,11 +505,11 @@ F0 10 10 ENDCHAR -STARTCHAR 0017 +STARTCHAR C027 ENCODING 23 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -334,8 +517,7 @@ BITMAP 10 10 10 -10 -FE +fe 00 00 00 @@ -343,11 +525,11 @@ FE 00 00 ENDCHAR -STARTCHAR 0018 +STARTCHAR C030 ENCODING 24 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -355,8 +537,7 @@ BITMAP 00 00 00 -00 -FE +fe 10 10 10 @@ -364,11 +545,11 @@ FE 10 10 ENDCHAR -STARTCHAR 0019 +STARTCHAR C031 ENCODING 25 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 10 10 @@ -383,13 +564,132 @@ BITMAP 10 10 10 -10 ENDCHAR -STARTCHAR 0020 +STARTCHAR <= +ENCODING 26 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +04 +18 +60 +80 +60 +18 +04 +fc +00 +00 +ENDCHAR +STARTCHAR >= +ENCODING 27 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +80 +60 +18 +04 +18 +60 +80 +fc +00 +00 +ENDCHAR +STARTCHAR Pi +ENCODING 28 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +fc +48 +48 +48 +48 +88 +00 +00 +ENDCHAR +STARTCHAR Not Equal +ENCODING 29 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +04 +08 +fc +10 +20 +fc +40 +80 +00 +00 +ENDCHAR +STARTCHAR Pound Sterling +ENCODING 30 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +38 +44 +40 +40 +e0 +40 +40 +44 +b8 +00 +00 +ENDCHAR +STARTCHAR Cdot +ENCODING 31 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Space ENCODING 32 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -404,13 +704,12 @@ BITMAP 00 00 00 -00 ENDCHAR -STARTCHAR 0021 +STARTCHAR ! ENCODING 33 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -423,22 +722,20 @@ BITMAP 10 00 10 -10 00 00 ENDCHAR -STARTCHAR 0022 +STARTCHAR " ENCODING 34 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -6C -24 -24 -48 00 00 +28 +28 +28 00 00 00 @@ -448,102 +745,97 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 0023 +STARTCHAR # ENCODING 35 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -0A -0A -0A -7E -14 -14 -7E +00 28 28 +7c 28 +7c +28 +28 +00 00 00 ENDCHAR -STARTCHAR 0024 +STARTCHAR $ ENCODING 36 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -08 -3C -4A -4A -28 -1C -0A -4A -4A -3C -08 +00 +10 +3c +50 +38 +14 +78 +10 +00 +00 00 ENDCHAR -STARTCHAR 0025 +STARTCHAR % ENCODING 37 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -32 -4A -4C -38 -08 +44 +a4 +48 10 -1C -32 -52 -4C +10 +20 +48 +94 +88 00 00 ENDCHAR -STARTCHAR 0026 +STARTCHAR & ENCODING 38 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -24 -24 -24 -18 -32 -4A -44 -4C -32 +00 +00 +60 +90 +90 +60 +94 +88 +74 00 00 ENDCHAR -STARTCHAR 0027 +STARTCHAR ' ENCODING 39 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP +00 +00 +38 30 -10 -10 -20 -00 -00 +40 00 00 00 @@ -553,74 +845,71 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 0028 +STARTCHAR ( ENCODING 40 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -02 -04 -08 +00 08 10 10 -10 +20 +20 +20 10 10 08 -08 -04 -02 +00 +00 ENDCHAR -STARTCHAR 0029 +STARTCHAR ) ENCODING 41 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -40 +00 20 10 10 08 08 08 -08 -08 10 10 20 -40 +00 +00 ENDCHAR -STARTCHAR 002a +STARTCHAR * ENCODING 42 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -08 -2A -1C -08 -08 -1C -2A -08 +00 +48 +30 +fc +30 +48 +00 00 00 00 ENDCHAR -STARTCHAR 002b +STARTCHAR + ENCODING 43 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -628,20 +917,19 @@ BITMAP 00 10 10 -10 -7C -10 +7c 10 10 00 00 00 +00 ENDCHAR -STARTCHAR 002c +STARTCHAR , ENCODING 44 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -652,17 +940,16 @@ BITMAP 00 00 00 -00 +38 30 -10 -10 -20 +40 +00 ENDCHAR -STARTCHAR 002d +STARTCHAR - ENCODING 45 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -670,8 +957,7 @@ BITMAP 00 00 00 -00 -7E +fc 00 00 00 @@ -679,11 +965,11 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 002e +STARTCHAR . ENCODING 46 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -694,294 +980,279 @@ BITMAP 00 00 00 -00 10 +38 10 00 -00 ENDCHAR -STARTCHAR 002f +STARTCHAR / ENCODING 47 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -02 -02 +00 04 04 08 08 -08 -10 10 20 20 40 40 +00 +00 ENDCHAR -STARTCHAR 0030 +STARTCHAR 0 ENCODING 48 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -24 -42 -42 -42 -42 -42 -42 -24 -18 +30 +48 +84 +84 +84 +84 +84 +48 +30 00 00 ENDCHAR -STARTCHAR 0031 +STARTCHAR 1 ENCODING 49 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -08 -18 -28 -08 -08 -08 -08 -08 -08 -3E +10 +30 +50 +10 +10 +10 +10 +10 +7c 00 00 ENDCHAR -STARTCHAR 0032 +STARTCHAR 2 ENCODING 50 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -02 -04 +78 +84 +84 04 08 -10 -20 -7E +30 +40 +80 +fc 00 00 ENDCHAR -STARTCHAR 0033 +STARTCHAR 3 ENCODING 51 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -02 -1C -02 -02 -42 -42 -3C +fc +04 +08 +10 +38 +04 +04 +84 +78 00 00 ENDCHAR -STARTCHAR 0034 +STARTCHAR 4 ENCODING 52 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -04 -0C -14 -14 -24 -24 -44 -7E -04 -04 +08 +18 +28 +48 +88 +88 +fc +08 +08 00 00 ENDCHAR -STARTCHAR 0035 +STARTCHAR 5 ENCODING 53 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7E -40 -40 -7C -42 -02 -02 -42 -42 -3C +fc +80 +80 +b8 +c4 +04 +04 +84 +78 00 00 ENDCHAR -STARTCHAR 0036 +STARTCHAR 6 ENCODING 54 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1C -22 -42 +38 40 -5C -62 -42 -42 -42 -3C +80 +80 +b8 +c4 +84 +84 +78 00 00 ENDCHAR -STARTCHAR 0037 +STARTCHAR 7 ENCODING 55 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7E -42 -44 +fc 04 08 -08 -08 -08 -08 -08 +10 +10 +20 +20 +40 +40 00 00 ENDCHAR -STARTCHAR 0038 +STARTCHAR 8 ENCODING 56 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -24 -18 -24 -42 -42 -42 -3C +78 +84 +84 +84 +78 +84 +84 +84 +78 00 00 ENDCHAR -STARTCHAR 0039 +STARTCHAR 9 ENCODING 57 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -42 -46 -3A -02 -42 -44 -38 +78 +84 +84 +8c +74 +04 +04 +08 +70 00 00 ENDCHAR -STARTCHAR 003a +STARTCHAR : ENCODING 58 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 10 +38 10 00 00 -00 10 +38 10 00 -00 -00 ENDCHAR -STARTCHAR 003b +STARTCHAR ; ENCODING 59 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 10 +38 10 00 00 -00 +38 30 -10 -10 -20 +40 00 ENDCHAR -STARTCHAR 003c +STARTCHAR < ENCODING 60 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 04 08 10 @@ -994,36 +1265,34 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 003d +STARTCHAR = ENCODING 61 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -7E +fc 00 00 -7E -00 +fc 00 00 00 00 ENDCHAR -STARTCHAR 003e +STARTCHAR > ENCODING 62 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 40 20 10 @@ -1036,1342 +1305,1278 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 003f +STARTCHAR ? ENCODING 63 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 +78 +84 +84 04 08 -08 -08 +10 +10 00 -08 -08 +10 00 00 ENDCHAR -STARTCHAR 0040 +STARTCHAR @ ENCODING 64 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1C -22 -4E -52 -52 -52 -52 -4E -20 -1E +78 +84 +84 +9c +a4 +ac +94 +80 +78 00 00 ENDCHAR -STARTCHAR 0041 +STARTCHAR A ENCODING 65 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -10 -18 -28 -24 -44 -42 -7E -42 -42 -42 +30 +48 +84 +84 +84 +fc +84 +84 +84 00 00 ENDCHAR -STARTCHAR 0042 +STARTCHAR B ENCODING 66 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7C -42 -42 +f8 44 -7C -42 -42 -42 -42 -7C +44 +44 +78 +44 +44 +44 +f8 00 00 ENDCHAR -STARTCHAR 0043 +STARTCHAR C ENCODING 67 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -40 -40 -40 -40 -42 -42 -3C +78 +84 +80 +80 +80 +80 +80 +84 +78 00 00 ENDCHAR -STARTCHAR 0044 +STARTCHAR D ENCODING 68 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -78 +f8 44 -42 -42 -42 -42 -42 -42 44 -78 +44 +44 +44 +44 +44 +f8 00 00 ENDCHAR -STARTCHAR 0045 +STARTCHAR E ENCODING 69 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7E -40 -40 -40 -7C -40 -40 -40 -40 -7E +fc +80 +80 +80 +f0 +80 +80 +80 +fc 00 00 ENDCHAR -STARTCHAR 0046 +STARTCHAR F ENCODING 70 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7E -40 -40 -40 -7C -40 -40 -40 -40 -40 +fc +80 +80 +80 +f0 +80 +80 +80 +80 00 00 ENDCHAR -STARTCHAR 0047 +STARTCHAR G ENCODING 71 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -40 -40 -4E -42 -42 -42 -3C +78 +84 +80 +80 +80 +9c +84 +8c +74 00 00 ENDCHAR -STARTCHAR 0048 +STARTCHAR H ENCODING 72 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -42 -42 -42 -7E -42 -42 -42 -42 -42 +84 +84 +84 +84 +fc +84 +84 +84 +84 00 00 ENDCHAR -STARTCHAR 0049 +STARTCHAR I ENCODING 73 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3E -08 -08 -08 -08 -08 -08 -08 -08 -3E +f8 +20 +20 +20 +20 +20 +20 +20 +f8 00 00 ENDCHAR -STARTCHAR 004a +STARTCHAR J ENCODING 74 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -02 -02 -02 -02 -02 -02 -02 -42 -44 -38 +1c +08 +08 +08 +08 +08 +08 +88 +70 00 00 ENDCHAR -STARTCHAR 004b +STARTCHAR K ENCODING 75 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -44 -48 -50 -70 -48 -48 -44 -42 -42 +84 +88 +90 +a0 +c0 +a0 +90 +88 +84 00 00 ENDCHAR -STARTCHAR 004c +STARTCHAR L ENCODING 76 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -40 -40 -40 -40 -40 -40 -40 -40 -40 -7E +80 +80 +80 +80 +80 +80 +80 +80 +fc 00 00 ENDCHAR -STARTCHAR 004d +STARTCHAR M ENCODING 77 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -46 -66 -6A -5A -52 -52 -42 -42 -42 +84 +cc +cc +b4 +b4 +84 +84 +84 +84 00 00 ENDCHAR -STARTCHAR 004e +STARTCHAR N ENCODING 78 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -62 -62 -52 -52 -52 -4A -4A -4A -46 -46 +84 +84 +c4 +a4 +94 +8c +84 +84 +84 00 00 ENDCHAR -STARTCHAR 004f +STARTCHAR O ENCODING 79 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -42 -42 -42 -42 -42 -42 -3C +78 +84 +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR -STARTCHAR 0050 +STARTCHAR P ENCODING 80 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7C -42 -42 -42 -42 -7C -40 -40 -40 -40 +f8 +84 +84 +84 +f8 +80 +80 +80 +80 00 00 ENDCHAR -STARTCHAR 0051 +STARTCHAR Q ENCODING 81 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -42 -42 -42 -72 -4A -46 -3C +78 +84 +84 +84 +84 +84 +a4 +94 +78 04 -02 +00 ENDCHAR -STARTCHAR 0052 +STARTCHAR R ENCODING 82 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7C -42 -42 -42 -7C -44 -42 -42 -42 -42 +f8 +84 +84 +84 +f8 +a0 +90 +88 +84 00 00 ENDCHAR -STARTCHAR 0053 +STARTCHAR S ENCODING 83 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -20 -10 -08 +78 +84 +80 +80 +78 04 -42 -42 -3C +04 +84 +78 00 00 ENDCHAR -STARTCHAR 0054 +STARTCHAR T ENCODING 84 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7E -10 -10 -10 -10 -10 -10 -10 -10 -10 +f8 +20 +20 +20 +20 +20 +20 +20 +20 00 00 ENDCHAR -STARTCHAR 0055 +STARTCHAR U ENCODING 85 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -42 -42 -42 -42 -42 -42 -42 -42 -3C +84 +84 +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR -STARTCHAR 0056 +STARTCHAR V ENCODING 86 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -42 -42 -44 -24 -24 -28 -18 -10 -10 -00 -00 -ENDCHAR -STARTCHAR 0057 -ENCODING 87 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -4A -4A -4A -4A -4A -7E -24 -24 -24 -24 -00 -00 -ENDCHAR -STARTCHAR 0058 -ENCODING 88 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -42 -42 -24 -24 -18 -18 -24 -24 -42 -42 -00 -00 -ENDCHAR -STARTCHAR 0059 -ENCODING 89 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -42 -42 -44 -24 -28 -18 -10 -10 -10 -10 -00 -00 -ENDCHAR -STARTCHAR 005a -ENCODING 90 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -7E -02 -04 -08 -08 -10 -20 -20 -40 -7E -00 -00 -ENDCHAR -STARTCHAR 005b -ENCODING 91 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -1E -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -1E -ENDCHAR -STARTCHAR 005c -ENCODING 92 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -40 -40 -20 -20 -10 -10 -10 -08 -08 -04 -04 -02 -02 -ENDCHAR -STARTCHAR 005d -ENCODING 93 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -78 -08 -08 -08 -08 -08 -08 -08 -08 -08 -08 -08 -78 -ENDCHAR -STARTCHAR 005e -ENCODING 94 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -18 -24 -42 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -ENDCHAR -STARTCHAR 005f -ENCODING 95 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -7E -ENDCHAR -STARTCHAR 0060 -ENCODING 96 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -0C -08 -08 -04 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -ENDCHAR -STARTCHAR 0061 -ENCODING 97 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3C -42 -0E -32 -42 -46 -3A -00 -00 -ENDCHAR -STARTCHAR 0062 -ENCODING 98 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -40 -40 -40 -5C -62 -42 -42 -42 -62 -5C -00 -00 -ENDCHAR -STARTCHAR 0063 -ENCODING 99 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3C -42 -40 -40 -40 -42 -3C -00 -00 -ENDCHAR -STARTCHAR 0064 -ENCODING 100 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -02 -02 -02 -3A -46 -42 -42 -42 -46 -3A -00 -00 -ENDCHAR -STARTCHAR 0065 -ENCODING 101 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3C -42 -42 -7E -40 -42 -3C -00 -00 -ENDCHAR -STARTCHAR 0066 -ENCODING 102 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -0C -12 -10 -10 -7C -10 -10 -10 -10 -10 -00 -00 -ENDCHAR -STARTCHAR 0067 -ENCODING 103 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3A -44 -44 -44 -38 -20 -5C -42 -3C -ENDCHAR -STARTCHAR 0068 -ENCODING 104 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -40 -40 -40 -5C -62 -42 -42 -42 -42 -42 -00 -00 -ENDCHAR -STARTCHAR 0069 -ENCODING 105 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -10 -10 -00 -10 -10 -10 -10 -10 -10 -10 -00 -00 -ENDCHAR -STARTCHAR 006a -ENCODING 106 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -04 -04 -00 -04 -04 -04 -04 -04 -04 -04 -44 -38 -ENDCHAR -STARTCHAR 006b -ENCODING 107 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -40 -40 -40 -44 +84 +84 +84 48 -50 -70 48 -44 -42 -00 -00 -ENDCHAR -STARTCHAR 006c -ENCODING 108 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -00 -00 -ENDCHAR -STARTCHAR 006d -ENCODING 109 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -7C -52 -52 -52 -52 -52 -52 -00 -00 -ENDCHAR -STARTCHAR 006e -ENCODING 110 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -5C -62 -42 -42 -42 -42 -42 -00 -00 -ENDCHAR -STARTCHAR 006f -ENCODING 111 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3C -42 -42 -42 -42 -42 -3C -00 -00 -ENDCHAR -STARTCHAR 0070 -ENCODING 112 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -5C -62 -42 -42 -42 -62 -5C -40 -40 -ENDCHAR -STARTCHAR 0071 -ENCODING 113 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3A -46 -42 -42 -42 -46 -3A -02 -02 -ENDCHAR -STARTCHAR 0072 -ENCODING 114 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -5C -62 -42 -40 -40 -40 -40 -00 -00 -ENDCHAR -STARTCHAR 0073 -ENCODING 115 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3C -42 -20 -18 -04 -42 -3C -00 -00 -ENDCHAR -STARTCHAR 0074 -ENCODING 116 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -10 -10 -10 -7E -10 -10 -10 -10 -10 -0E -00 -00 -ENDCHAR -STARTCHAR 0075 -ENCODING 117 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -42 -42 -42 -42 -42 -46 -3A -00 -00 -ENDCHAR -STARTCHAR 0076 -ENCODING 118 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -42 -42 -22 -24 -14 -18 -08 -00 -00 -ENDCHAR -STARTCHAR 0077 -ENCODING 119 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -4A -4A -4A -7E -24 -24 -24 -00 -00 -ENDCHAR -STARTCHAR 0078 -ENCODING 120 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -42 -42 -24 -18 -24 -42 -42 -00 -00 -ENDCHAR -STARTCHAR 0079 -ENCODING 121 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -42 -42 -22 -24 -14 -1C -08 48 30 +30 +30 +00 +00 ENDCHAR -STARTCHAR 007a +STARTCHAR W +ENCODING 87 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +84 +84 +84 +84 +b4 +b4 +cc +cc +84 +00 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +84 +84 +48 +48 +30 +48 +48 +84 +84 +00 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +88 +88 +50 +50 +20 +20 +20 +20 +20 +00 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +fc +04 +08 +10 +30 +20 +40 +80 +fc +00 +00 +ENDCHAR +STARTCHAR [ +ENCODING 91 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +78 +40 +40 +40 +40 +40 +40 +40 +78 +00 +00 +ENDCHAR +STARTCHAR \ +ENCODING 92 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +40 +40 +20 +20 +10 +08 +08 +04 +04 +00 +00 +ENDCHAR +STARTCHAR ] +ENCODING 93 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +78 +08 +08 +08 +08 +08 +08 +08 +78 +00 +00 +ENDCHAR +STARTCHAR ^ +ENCODING 94 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +10 +28 +44 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR _ +ENCODING 95 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +fc +00 +ENDCHAR +STARTCHAR ` +ENCODING 96 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +70 +30 +08 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +04 +7c +84 +8c +74 +00 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +80 +80 +80 +b8 +c4 +84 +84 +c4 +b8 +00 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +84 +80 +80 +84 +78 +00 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +04 +04 +04 +74 +8c +84 +84 +8c +74 +00 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +84 +fc +80 +84 +78 +00 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +38 +44 +40 +40 +f0 +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +74 +88 +88 +70 +80 +78 +84 +78 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +80 +80 +80 +b8 +c4 +84 +84 +84 +84 +00 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +20 +00 +60 +20 +20 +20 +20 +f8 +00 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +08 +00 +18 +08 +08 +08 +08 +88 +88 +70 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +80 +80 +80 +88 +90 +e0 +90 +88 +84 +00 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +60 +20 +20 +20 +20 +20 +20 +20 +f8 +00 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +d0 +a8 +a8 +a8 +a8 +88 +00 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +b8 +c4 +84 +84 +84 +84 +00 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +84 +84 +84 +84 +78 +00 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +b8 +c4 +84 +c4 +b8 +80 +80 +80 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +74 +8c +84 +8c +74 +04 +04 +04 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +b8 +44 +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +84 +60 +18 +84 +78 +00 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +40 +40 +f0 +40 +40 +40 +44 +38 +00 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +84 +84 +84 +84 +8c +74 +00 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +88 +88 +88 +50 +50 +20 +00 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +88 +88 +a8 +a8 +a8 +50 +00 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +84 +48 +30 +30 +48 +84 +00 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +84 +84 +84 +8c +74 +04 +84 +78 +ENDCHAR +STARTCHAR z ENCODING 122 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -7E -04 +fc 08 10 -10 20 -7E +40 +fc 00 00 ENDCHAR -STARTCHAR 007b +STARTCHAR { ENCODING 123 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -06 -08 -08 -08 -08 -08 -10 -08 -08 -08 -08 -08 -06 -ENDCHAR -STARTCHAR 007c -ENCODING 124 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -ENDCHAR -STARTCHAR 007d -ENCODING 125 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -60 -10 -10 -10 -10 -10 -08 -10 -10 -10 -10 -10 -60 -ENDCHAR -STARTCHAR 007e -ENCODING 126 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP 00 +1c 20 -52 -4A -04 +20 +10 +60 +10 +20 +20 +1c 00 00 +ENDCHAR +STARTCHAR | +ENCODING 124 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +10 +10 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR } +ENCODING 125 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +70 +08 +08 +10 +0c +10 +08 +08 +70 +00 +00 +ENDCHAR +STARTCHAR ~ +ENCODING 126 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +24 +54 +48 +00 00 00 00 @@ -2380,11 +2585,11 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 007f +STARTCHAR (Blank) ENCODING 127 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2399,13 +2604,12 @@ BITMAP 00 00 00 -00 ENDCHAR STARTCHAR 00a0 ENCODING 160 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2420,18 +2624,16 @@ BITMAP 00 00 00 -00 ENDCHAR STARTCHAR 00a1 ENCODING 161 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 10 -10 00 10 10 @@ -2445,93 +2647,89 @@ BITMAP ENDCHAR STARTCHAR 00a2 ENCODING 162 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 +10 +38 +54 +50 +50 +54 +38 +10 00 00 -10 -3e -52 -50 -50 -50 -52 -3e -10 00 ENDCHAR STARTCHAR 00a3 ENCODING 163 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 -18 -24 -20 -20 -78 -20 -20 -78 -24 +38 +44 +40 +40 +e0 +40 +40 +44 +b8 00 00 ENDCHAR STARTCHAR 00a4 ENCODING 164 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -42 -3c -24 -24 -3c -42 -00 +84 +78 +48 +48 +78 +84 00 00 00 ENDCHAR STARTCHAR 00a5 ENCODING 165 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -24 -18 -7e -08 -08 -7e -08 -08 -08 +88 +88 +50 +50 +f8 +20 +f8 +20 +20 00 00 ENDCHAR STARTCHAR 00a6 ENCODING 166 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2540,7 +2738,6 @@ BITMAP 10 10 00 -00 10 10 10 @@ -2550,35 +2747,33 @@ BITMAP ENDCHAR STARTCHAR 00a7 ENCODING 167 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -42 -20 -18 -24 -42 -24 -18 -04 -42 -3c +30 +48 +40 +30 +48 +48 +30 +08 +48 +30 00 00 ENDCHAR STARTCHAR 00a8 ENCODING 168 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -48 -48 00 +6c 00 00 00 @@ -2592,41 +2787,39 @@ BITMAP ENDCHAR STARTCHAR 00a9 ENCODING 169 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -42 -5a -66 -62 -62 -62 -66 -5a -42 -3c +78 +84 +b4 +a4 +a4 +a4 +b4 +84 +78 +00 00 00 ENDCHAR STARTCHAR 00aa ENCODING 170 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -1c -22 -1e -22 -26 -1a 00 -3e +38 +04 +3c +44 +3c 00 +7c 00 00 00 @@ -2634,30 +2827,29 @@ BITMAP ENDCHAR STARTCHAR 00ab ENCODING 171 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -00 -00 -0a 14 28 50 +a0 +50 28 14 -0a +00 00 00 ENDCHAR STARTCHAR 00ac ENCODING 172 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2665,20 +2857,19 @@ BITMAP 00 00 00 +7c +04 +04 00 00 -f8 -08 -08 -08 00 00 ENDCHAR STARTCHAR 00ad ENCODING 173 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2686,10 +2877,9 @@ BITMAP 00 00 00 +7c 00 00 -f0 -00 00 00 00 @@ -2697,35 +2887,33 @@ f0 ENDCHAR STARTCHAR 00ae ENCODING 174 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -42 -7a -66 -66 -7a -66 -66 -66 -42 -3c +78 +84 +b4 +ac +ac +b4 +ac +84 +78 +00 00 00 ENDCHAR STARTCHAR 00af ENCODING 175 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -f0 -00 +7c 00 00 00 @@ -2739,11 +2927,12 @@ f0 ENDCHAR STARTCHAR 00b0 ENCODING 176 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +00 30 48 48 @@ -2755,44 +2944,40 @@ BITMAP 00 00 00 -00 -00 ENDCHAR STARTCHAR 00b1 ENCODING 177 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -00 -00 -00 10 10 7c 10 10 +00 7c 00 00 +00 ENDCHAR STARTCHAR 00b2 ENCODING 178 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -30 -48 -08 -10 +40 +a0 20 40 -78 +80 +e0 00 00 00 @@ -2802,18 +2987,17 @@ BITMAP ENDCHAR STARTCHAR 00b3 ENCODING 179 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -30 -48 -08 -30 -08 -48 -30 +e0 +20 +40 +20 +a0 +40 00 00 00 @@ -2823,15 +3007,14 @@ BITMAP ENDCHAR STARTCHAR 00b4 ENCODING 180 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -08 10 20 -40 +00 00 00 00 @@ -2844,51 +3027,49 @@ BITMAP ENDCHAR STARTCHAR 00b5 ENCODING 181 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 +84 +84 +84 +84 +cc +b4 +80 00 -44 -44 -44 -44 -6c -54 -40 -40 ENDCHAR STARTCHAR 00b6 ENCODING 182 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -54 -54 -54 -54 -34 -14 -14 -14 -14 -14 -1c +7c +e8 +e8 +e8 +68 +28 +28 +28 +28 +00 +00 ENDCHAR STARTCHAR 00b7 ENCODING 183 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2896,8 +3077,7 @@ BITMAP 00 00 00 -10 -00 +30 00 00 00 @@ -2907,9 +3087,9 @@ BITMAP ENDCHAR STARTCHAR 00b8 ENCODING 184 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2923,23 +3103,21 @@ BITMAP 00 00 10 -10 20 ENDCHAR STARTCHAR 00b9 ENCODING 185 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -20 -60 -20 -20 -20 -20 +40 +c0 +40 +40 +40 +e0 00 00 00 @@ -2949,19 +3127,18 @@ BITMAP ENDCHAR STARTCHAR 00ba ENCODING 186 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -24 -24 -18 -00 -3c +30 +48 +48 +30 00 +78 00 00 00 @@ -2970,732 +3147,697 @@ BITMAP ENDCHAR STARTCHAR 00bb ENCODING 187 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -00 -00 +a0 50 28 14 -0a -14 28 50 +a0 +00 00 00 ENDCHAR STARTCHAR 00bc ENCODING 188 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -20 -62 -24 -24 -28 -12 -16 -2a -4e -42 +40 +c0 +40 +40 +44 +ec +14 +14 +1c +04 00 00 ENDCHAR STARTCHAR 00bd ENCODING 189 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -20 -62 -24 -24 -28 -14 -1a -22 -44 -4e +40 +c0 +40 +40 +48 +f4 +04 +08 +10 +1c 00 00 ENDCHAR STARTCHAR 00be ENCODING 190 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -62 -12 -24 -18 -68 -12 -26 -2a -4e -02 +e0 +20 +40 +20 +a4 +4c +14 +14 +1c +04 00 00 ENDCHAR STARTCHAR 00bf ENCODING 191 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 +20 +00 +20 +20 +40 +80 +84 +84 +78 00 -08 -08 00 -08 -08 -08 -08 -04 -42 -42 -3c ENDCHAR STARTCHAR 00c0 ENCODING 192 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -20 -18 00 -18 -28 -24 -44 -42 -7E -42 -42 -42 +20 +10 +00 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c1 ENCODING 193 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 00 -18 -28 -24 -44 -42 -7E -42 -42 -42 +10 +20 +00 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c2 ENCODING 194 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -24 00 -18 -28 -24 -44 -42 -7E -42 -42 -42 +30 +48 +00 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c3 ENCODING 195 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -18 28 -24 -44 -42 -7E -42 -42 -42 +50 +00 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c4 ENCODING 196 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -24 +48 +48 00 -18 -28 -24 -44 -42 -7E -42 -42 -42 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c5 ENCODING 197 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -10 00 -10 -18 -28 -24 -44 -42 -7E -42 -42 -42 +30 +48 +30 +30 +48 +84 +84 +fc +84 +84 00 00 ENDCHAR STARTCHAR 00c6 ENCODING 198 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3E -50 -50 -50 -9C -f0 -90 -90 -90 -9E +5c +a0 +a0 +a0 +b8 +e0 +a0 +a0 +bc 00 00 ENDCHAR STARTCHAR 00c7 ENCODING 199 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3C -42 -42 -40 -40 -40 -40 -42 -42 -3C -08 +78 +84 +80 +80 +80 +80 +80 +84 +78 10 +20 ENDCHAR STARTCHAR 00c8 ENCODING 200 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -20 -18 00 -7e -40 -40 -40 -7c -40 -40 -40 -7E +20 +10 +00 +fc +80 +80 +f0 +80 +80 +fc 00 00 ENDCHAR STARTCHAR 00c9 ENCODING 201 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 00 -7e -40 -40 -40 -7c -40 -40 -40 -7E +10 +20 +00 +fc +80 +80 +f0 +80 +80 +fc 00 00 ENDCHAR STARTCHAR 00ca ENCODING 202 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -24 00 -7e -40 -40 -40 -7c -40 -40 -40 -7E +30 +48 +00 +fc +80 +80 +f0 +80 +80 +fc 00 00 ENDCHAR STARTCHAR 00cb ENCODING 203 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -24 +48 +48 00 -7e -40 -40 -40 -7c -40 -40 -40 -7E +fc +80 +80 +f0 +80 +80 +fc 00 00 ENDCHAR STARTCHAR 00cc ENCODING 204 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -10 -0c 00 -3e -08 -08 -08 -08 -08 -08 -08 -3E +20 +10 +00 +7c +10 +10 +10 +10 +10 +7c 00 00 ENDCHAR STARTCHAR 00cd ENCODING 205 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 00 -3e -08 -08 -08 -08 -08 -08 -08 -3E +10 +20 +00 +7c +10 +10 +10 +10 +10 +7c 00 00 ENDCHAR STARTCHAR 00ce ENCODING 206 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -08 -14 00 -3e -08 -08 -08 -08 -08 -08 -08 -3E +30 +48 +00 +7c +10 +10 +10 +10 +10 +7c 00 00 ENDCHAR STARTCHAR 00cf ENCODING 207 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -14 +28 +28 00 -3e -08 -08 -08 -08 -08 -08 -08 -3E +7c +10 +10 +10 +10 +10 +7c 00 00 ENDCHAR STARTCHAR 00d0 ENCODING 208 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -78 +f8 44 -42 -42 -e2 -42 -42 -42 44 -78 +44 +e4 +44 +44 +44 +f8 00 00 ENDCHAR STARTCHAR 00d1 ENCODING 209 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -62 -52 -52 -52 -4A -4A -4A -46 -46 +28 +50 +00 +84 +c4 +a4 +a4 +94 +8c +84 00 00 ENDCHAR STARTCHAR 00d2 ENCODING 210 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -20 -18 00 -3c -42 -42 -42 -42 -42 -42 -42 -3C +20 +10 +00 +78 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00d3 ENCODING 211 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 00 -3c -42 -42 -42 -42 -42 -42 -42 -3C +10 +20 +00 +78 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00d4 ENCODING 212 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -24 00 -3c -42 -42 -42 -42 -42 -42 -42 -3C +30 +48 +00 +78 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00d5 ENCODING 213 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -3c -42 -42 -42 -42 -42 -42 -42 -3C +28 +50 +00 +78 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00d6 ENCODING 214 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -24 +48 +48 00 -3c -42 -42 -42 -42 -42 -42 -42 -3C +78 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00d7 ENCODING 215 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 +84 +48 +30 +30 +48 +84 00 -82 -44 -28 -10 -28 -44 -82 00 00 ENDCHAR STARTCHAR 00d8 ENCODING 216 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -02 -02 -3C -46 -4a -4a -4a -52 -52 -52 -62 -3C -40 -40 +00 +04 +78 +8c +94 +94 +a4 +a4 +a4 +c4 +78 +80 +00 ENDCHAR STARTCHAR 00d9 ENCODING 217 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -20 -18 00 -42 -42 -42 -42 -42 -42 -42 -42 -3C +20 +10 +00 +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00da ENCODING 218 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 00 -42 -42 -42 -42 -42 -42 -42 -42 -3C +10 +20 +00 +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00db ENCODING 219 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -24 00 -42 -42 -42 -42 -42 -42 -42 -42 -3C +30 +48 +00 +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00dc ENCODING 220 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -24 +48 +48 00 -42 -42 -42 -42 -42 -42 -42 -42 -3C +84 +84 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00dd ENCODING 221 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -04 -18 -42 -42 +00 +10 +20 +00 +44 44 -24 28 -18 10 10 10 @@ -3705,716 +3847,682 @@ BITMAP ENDCHAR STARTCHAR 00de ENCODING 222 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -40 -40 -7c -42 -42 -42 -42 -7c -40 -40 +80 +f8 +84 +84 +84 +f8 +80 +80 +80 00 00 ENDCHAR STARTCHAR 00df ENCODING 223 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -24 -24 -24 -38 -24 -22 -22 -22 -7c 00 +78 +84 +84 +f8 +84 +84 +c4 +b8 +80 00 ENDCHAR STARTCHAR 00e0 ENCODING 224 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 20 10 -08 00 -3C -42 -0E -32 -42 -46 -3A +00 +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e1 ENCODING 225 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -04 -08 10 +20 00 -3C -42 -0E -32 -42 -46 -3A +00 +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e2 ENCODING 226 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +48 00 -18 -24 00 -3C -42 -0E -32 -42 -46 -3A +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e3 ENCODING 227 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -14 28 +50 00 -3C -42 -0E -32 -42 -46 -3A +00 +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e4 ENCODING 228 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +48 +48 00 00 -24 -00 -3C -42 -0E -32 -42 -46 -3A +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e5 ENCODING 229 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -10 -28 -10 +30 +48 +30 00 -3C -42 -0E -32 -42 -46 -3A +78 +04 +7c +84 +8c +74 00 00 ENDCHAR STARTCHAR 00e6 ENCODING 230 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -7C -92 -32 -5E +68 +14 +7c 90 -92 -7C +94 +68 00 00 ENDCHAR STARTCHAR 00e7 ENCODING 231 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3C -42 -40 -40 -40 -42 -3C -08 +78 +84 +80 +80 +84 +78 10 +20 ENDCHAR STARTCHAR 00e8 ENCODING 232 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 20 10 -08 00 -3C -42 -42 -7E -40 -42 -3C +00 +78 +84 +fc +80 +84 +78 00 00 ENDCHAR STARTCHAR 00e9 ENCODING 233 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -04 -08 10 +20 00 -3C -42 -42 -7E -40 -42 -3C +00 +78 +84 +fc +80 +84 +78 00 00 ENDCHAR STARTCHAR 00ea ENCODING 234 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +48 00 -18 -24 00 -3C -42 -42 -7E -40 -42 -3C +78 +84 +fc +80 +84 +78 00 00 ENDCHAR STARTCHAR 00eb ENCODING 235 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +48 +48 00 00 -24 -00 -3C -42 -42 -7E -40 -42 -3C +78 +84 +fc +80 +84 +78 00 00 ENDCHAR STARTCHAR 00ec ENCODING 236 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 20 10 -08 00 +00 +30 10 10 10 10 -10 -10 -10 +7c 00 00 ENDCHAR STARTCHAR 00ed ENCODING 237 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -08 10 20 00 +00 +30 10 10 10 10 -10 -10 -10 +7c 00 00 ENDCHAR STARTCHAR 00ee ENCODING 238 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +48 00 -10 -28 00 +30 10 10 10 10 -10 -10 -10 +7c 00 00 ENDCHAR STARTCHAR 00ef ENCODING 239 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +48 +48 00 00 -28 -00 -10 -10 -10 +30 10 10 10 10 +7c 00 00 ENDCHAR STARTCHAR 00f0 ENCODING 240 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -28 -10 -28 -04 -3c -44 -44 -44 -44 -44 -38 +48 +30 +50 +08 +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f1 ENCODING 241 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -14 28 +50 00 -5C -62 -42 -42 -42 -42 -42 +00 +b8 +c4 +84 +84 +84 +84 00 00 ENDCHAR STARTCHAR 00f2 ENCODING 242 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 20 10 -08 00 -3C -42 -42 -42 -42 -42 -3C +00 +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f3 ENCODING 243 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -04 -08 10 +20 00 -3C -42 -42 -42 -42 -42 -3C +00 +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f4 ENCODING 244 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +48 00 -18 -24 00 -3C -42 -42 -42 -42 -42 -3C +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f5 ENCODING 245 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -14 28 +50 00 -3C -42 -42 -42 -42 -42 -3C +00 +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f6 ENCODING 246 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +48 +48 00 00 -24 -00 -3C -42 -42 -42 -42 -42 -3C +78 +84 +84 +84 +84 +78 00 00 ENDCHAR STARTCHAR 00f7 ENCODING 247 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 +10 +10 00 +7c 00 +10 +10 00 00 -30 -00 -fc -00 -30 -00 00 ENDCHAR STARTCHAR 00f8 ENCODING 248 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -02 +00 04 -3C -4a -4a -52 -52 -62 -3C -40 -40 +78 +8c +94 +a4 +c4 +78 +80 +00 ENDCHAR STARTCHAR 00f9 ENCODING 249 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 20 10 -08 -42 -42 -42 -42 -42 -46 -3A +00 +00 +84 +84 +84 +84 +8c +74 00 00 ENDCHAR STARTCHAR 00fa ENCODING 250 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -04 -08 10 -42 -42 -42 -42 -42 -46 -3A +20 +00 +00 +84 +84 +84 +84 +8c +74 00 00 ENDCHAR STARTCHAR 00fb ENCODING 251 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +48 00 -18 -24 00 -42 -42 -42 -42 -42 -46 -3A +84 +84 +84 +84 +8c +74 00 00 ENDCHAR STARTCHAR 00fc ENCODING 252 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +48 +48 00 00 -24 -00 -42 -42 -42 -42 -42 -46 -3A +84 +84 +84 +84 +8c +74 00 00 ENDCHAR STARTCHAR 00fd ENCODING 253 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -04 -08 10 -42 -42 -22 -24 -14 -1C -08 -48 -30 +20 +00 +00 +84 +84 +84 +8c +74 +04 +84 +78 ENDCHAR STARTCHAR 00fe ENCODING 254 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -40 -40 -40 -5C -62 -42 -42 -42 -62 -5C -40 -40 +00 +80 +80 +b8 +c4 +84 +84 +c4 +b8 +80 +80 ENDCHAR STARTCHAR 00ff ENCODING 255 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -00 -24 -00 -42 -42 -22 -24 -14 -1C -08 48 -30 +48 +00 +00 +84 +84 +84 +8c +74 +04 +84 +78 ENDCHAR ENDFONT diff --git a/resource/font/7x14B.bdf b/resource/font/7x13B.bdf similarity index 53% rename from resource/font/7x14B.bdf rename to resource/font/7x13B.bdf index a99d925ab..ee3828cfd 100644 --- a/resource/font/7x14B.bdf +++ b/resource/font/7x13B.bdf @@ -1,12 +1,16 @@ STARTFONT 2.1 -COMMENT -COMMENT Donated by H. Kagotani ; public domain -COMMENT font from Japan -COMMENT -FONT -Misc-Fixed-Bold-R-Normal--14-130-75-75-C-70-ISO8859-1 -SIZE 7 75 75 -FONTBOUNDINGBOX 7 14 0 -2 -STARTPROPERTIES 19 +COMMENT "" +COMMENT Designed by Stephen Gildea from original designs. +COMMENT November 1989 +COMMENT "" +COMMENT Characters above 127 designed and made by +COMMENT Thomas Bagli (pyramid!pcsbst!tom@uunet.UU.NET) +COMMENT PCS Computer Systeme, West Germany +COMMENT "" +FONT -Misc-Fixed-Bold-R-Normal--13-120-75-75-C-70-ISO8859-1 +SIZE 13 78 78 +FONTBOUNDINGBOX 7 13 0 -2 +STARTPROPERTIES 21 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" @@ -14,88 +18,267 @@ WEIGHT_NAME "Bold" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "" -PIXEL_SIZE 14 -POINT_SIZE 130 +PIXEL_SIZE 13 +POINT_SIZE 120 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 70 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" -DEFAULT_CHAR 32 +UNDERLINE_POSITION -1 +DESTINATION 1 +DEFAULT_CHAR 0 FONT_DESCENT 2 -FONT_ASCENT 12 +FONT_ASCENT 11 COPYRIGHT "Public domain font. Share and enjoy." ENDPROPERTIES -CHARS 209 -STARTCHAR 0001 +CHARS 224 +STARTCHAR C000 +ENCODING 0 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +7c +7c +7c +7c +7c +7c +7c +7c +7c +7c +7c +00 +ENDCHAR +STARTCHAR C001 ENCODING 1 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -18 -3c -3c -7e -7e -3c -3c -18 -18 +00 +00 +00 +30 +78 +fc +78 +30 +00 00 00 ENDCHAR -STARTCHAR 0002 +STARTCHAR C002 ENCODING 2 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -76 -ee -dc -ba -76 -ee -dc -ba -76 -ee -dc -ba -76 -ee +00 +cc +30 +cc +30 +cc +30 +cc +30 +cc +30 +cc +00 ENDCHAR -STARTCHAR 000b +STARTCHAR C003 +ENCODING 3 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +d8 +d8 +f8 +d8 +d8 +00 +3c +18 +18 +18 +18 +00 +ENDCHAR +STARTCHAR C004 +ENCODING 4 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +f0 +c0 +e0 +c0 +c0 +00 +3c +30 +38 +30 +30 +00 +ENDCHAR +STARTCHAR C005 +ENCODING 5 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +70 +c0 +c0 +c0 +70 +00 +38 +34 +38 +34 +34 +00 +ENDCHAR +STARTCHAR C006 +ENCODING 6 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +c0 +c0 +c0 +c0 +f0 +00 +3c +30 +38 +30 +30 +00 +ENDCHAR +STARTCHAR C007 +ENCODING 7 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +78 +cc +cc +78 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C010 +ENCODING 8 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +30 +30 +fc +fc +30 +30 +00 +fc +fc +00 +00 +ENDCHAR +STARTCHAR C011 +ENCODING 9 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +cc +ec +fc +dc +cc +00 +30 +30 +30 +30 +3c +00 +ENDCHAR +STARTCHAR C012 +ENCODING 10 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +cc +cc +48 +78 +30 +00 +3c +18 +18 +18 +18 +00 +ENDCHAR +STARTCHAR C013 ENCODING 11 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 -f8 -f8 -00 +30 +30 +30 +30 +30 +30 +f0 +f0 00 00 00 00 00 ENDCHAR -STARTCHAR 000c +STARTCHAR C014 ENCODING 12 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -103,20 +286,19 @@ BITMAP 00 00 00 -f8 -f8 -18 -18 -18 -18 -18 -18 +f0 +f0 +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 000d +STARTCHAR C015 ENCODING 13 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -124,63 +306,62 @@ BITMAP 00 00 00 -1e -1e -18 -18 -18 -18 -18 -18 +3e +3e +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 000e +STARTCHAR C016 ENCODING 14 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 -1e -1e -00 +30 +30 +30 +30 +30 +30 +3e +3e 00 00 00 00 00 ENDCHAR -STARTCHAR 000f +STARTCHAR C017 ENCODING 15 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 fe fe -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 0010 +STARTCHAR C020 ENCODING 16 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP +00 +00 fe fe 00 @@ -192,19 +373,17 @@ fe 00 00 00 -00 -00 -00 ENDCHAR -STARTCHAR 0011 +STARTCHAR C021 ENCODING 17 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 +00 fe fe 00 @@ -214,14 +393,12 @@ fe 00 00 00 -00 -00 ENDCHAR -STARTCHAR 0012 +STARTCHAR C022 ENCODING 18 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -236,13 +413,12 @@ fe 00 00 00 -00 ENDCHAR -STARTCHAR 0013 +STARTCHAR C023 ENCODING 19 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -252,18 +428,17 @@ BITMAP 00 00 00 -00 fe fe 00 00 00 ENDCHAR -STARTCHAR 0014 +STARTCHAR C024 ENCODING 20 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -275,65 +450,62 @@ BITMAP 00 00 00 -00 -00 fe fe +00 ENDCHAR -STARTCHAR 0015 +STARTCHAR C025 ENCODING 21 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 -1e -1e -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 +3e +3e +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 0016 +STARTCHAR C026 ENCODING 22 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 -f8 -f8 -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 +f0 +f0 +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 0017 +STARTCHAR C027 ENCODING 23 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 fe fe 00 @@ -341,13 +513,12 @@ fe 00 00 00 -00 ENDCHAR -STARTCHAR 0018 +STARTCHAR C030 ENCODING 24 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -357,39 +528,157 @@ BITMAP 00 fe fe -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 0019 +STARTCHAR C031 ENCODING 25 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 ENDCHAR -STARTCHAR 0020 +STARTCHAR C032 +ENCODING 26 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +0c +18 +60 +c0 +60 +18 +0c +fc +fc +00 +00 +ENDCHAR +STARTCHAR C033 +ENCODING 27 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +c0 +60 +18 +0c +18 +60 +c0 +fc +fc +00 +00 +ENDCHAR +STARTCHAR C034 +ENCODING 28 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +fc +6c +6c +6c +ec +cc +00 +00 +ENDCHAR +STARTCHAR C035 +ENCODING 29 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +04 +0c +fc +fc +30 +fc +fc +c0 +80 +00 +00 +ENDCHAR +STARTCHAR C036 +ENCODING 30 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +38 +6c +60 +60 +f8 +60 +60 +6c +b8 +00 +00 +ENDCHAR +STARTCHAR C037 +ENCODING 31 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +30 +30 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C040 ENCODING 32 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -404,38 +693,37 @@ BITMAP 00 00 00 -00 ENDCHAR -STARTCHAR 0021 +STARTCHAR ! ENCODING 33 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 00 -18 -18 +30 +30 00 00 ENDCHAR -STARTCHAR 0022 +STARTCHAR " ENCODING 34 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -7e -36 -36 +00 +00 +6c +6c 6c 00 00 @@ -445,106 +733,99 @@ BITMAP 00 00 00 -00 -00 ENDCHAR -STARTCHAR 0023 +STARTCHAR # ENCODING 35 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1e -1e -1e -7e -3c -3c -7e -78 -78 -78 +28 +28 +7c +7c +28 +7c +7c +28 +28 00 00 ENDCHAR -STARTCHAR 0024 +STARTCHAR $ ENCODING 36 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -3c -5a -5a -38 -1c -1a -5a -5a -3c -18 +30 +78 +b4 +b0 +78 +34 +b4 +78 +30 +00 00 ENDCHAR -STARTCHAR 0025 +STARTCHAR % ENCODING 37 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -36 -6e -6c -38 -08 -10 -1c -36 -76 -6c +e4 +ac +e8 +18 +30 +60 +5c +d4 +9c 00 00 ENDCHAR -STARTCHAR 0026 +STARTCHAR & ENCODING 38 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1c -36 -36 -36 -1c -36 -6e -6c -6c -36 +70 +d8 +d8 +d8 +70 +d4 +dc +d8 +74 00 00 ENDCHAR -STARTCHAR 0027 +STARTCHAR ' ENCODING 39 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP +00 +00 +38 38 -18 -18 30 -00 -00 -00 +60 00 00 00 @@ -553,95 +834,91 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 0028 +STARTCHAR ( ENCODING 40 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -06 -0c -18 +00 18 30 30 -30 +60 +60 +60 30 30 18 -18 -0c -06 +00 +00 ENDCHAR -STARTCHAR 0029 +STARTCHAR ) ENCODING 41 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +00 60 30 +30 18 18 -0c -0c -0c -0c -0c -18 18 30 +30 60 +00 +00 ENDCHAR -STARTCHAR 002a +STARTCHAR * ENCODING 42 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -5a -5a -3c -18 -18 -3c -5a -5a +00 +48 +30 +fc +fc +30 +48 00 00 00 ENDCHAR -STARTCHAR 002b +STARTCHAR + ENCODING 43 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -18 -18 -18 -7e -18 -18 -18 +30 +30 +fc +fc +30 +30 00 00 00 ENDCHAR -STARTCHAR 002c +STARTCHAR , ENCODING 44 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -651,18 +928,17 @@ BITMAP 00 00 00 -00 -00 38 -18 -18 +38 30 +60 +00 ENDCHAR -STARTCHAR 002d +STARTCHAR - ENCODING 45 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -670,20 +946,19 @@ BITMAP 00 00 00 -7e -7e -00 +fc +fc 00 00 00 00 00 ENDCHAR -STARTCHAR 002e +STARTCHAR . ENCODING 46 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -694,1012 +969,963 @@ BITMAP 00 00 00 -00 -18 -18 -00 +30 +78 +30 00 ENDCHAR -STARTCHAR 002f +STARTCHAR / ENCODING 47 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -06 -06 -06 +00 0c 0c 18 18 -18 -30 30 60 60 -60 +c0 +c0 +00 +00 ENDCHAR -STARTCHAR 0030 +STARTCHAR 0 ENCODING 48 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -66 -66 -66 -66 -66 -66 -3c +30 +48 +cc +cc +cc +cc +cc +48 +30 00 00 ENDCHAR -STARTCHAR 0031 +STARTCHAR 1 ENCODING 49 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -38 -78 -18 -18 -18 -18 -18 -18 -7e +30 +70 +b0 +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR -STARTCHAR 0032 +STARTCHAR 2 ENCODING 50 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -06 +78 +cc +cc 0c -0c -18 -30 +38 60 -7e +c0 +c0 +fc 00 00 ENDCHAR -STARTCHAR 0033 +STARTCHAR 3 ENCODING 51 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -06 -1c -06 -06 -66 -66 -3c +fc +0c +18 +30 +78 +0c +0c +cc +78 00 00 ENDCHAR -STARTCHAR 0034 +STARTCHAR 4 ENCODING 52 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -04 -0c 0c 1c 3c -2c 6c -7e -04 -04 +cc +cc +fc +0c +0c 00 00 ENDCHAR -STARTCHAR 0035 +STARTCHAR 5 ENCODING 53 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -60 -60 -7c -66 -06 -06 -66 -66 -3c +fc +c0 +c0 +f8 +cc +0c +0c +cc +78 00 00 ENDCHAR -STARTCHAR 0036 +STARTCHAR 6 ENCODING 54 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1c -36 -66 -60 -7c -66 -66 -66 -66 -3c +78 +cc +c0 +c0 +f8 +cc +cc +cc +78 00 00 ENDCHAR -STARTCHAR 0037 +STARTCHAR 7 ENCODING 55 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -66 -6c +fc +0c 0c 18 18 -18 -18 -18 -18 +30 +30 +60 +60 00 00 ENDCHAR -STARTCHAR 0038 +STARTCHAR 8 ENCODING 56 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -3c -18 -3c -66 -66 -66 -3c +78 +cc +cc +cc +78 +cc +cc +cc +78 00 00 ENDCHAR -STARTCHAR 0039 +STARTCHAR 9 ENCODING 57 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -66 -66 -3e -06 -66 -6c -38 +78 +cc +cc +cc +7c +0c +0c +cc +78 00 00 ENDCHAR -STARTCHAR 003a +STARTCHAR : ENCODING 58 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -18 -18 -00 -00 -00 -18 -18 +30 +78 +30 00 00 +30 +78 +30 00 ENDCHAR -STARTCHAR 003b +STARTCHAR ; ENCODING 59 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -18 -18 -00 -00 -00 -38 -18 -18 +30 +78 30 00 +38 +38 +30 +60 +00 ENDCHAR -STARTCHAR 003c +STARTCHAR < ENCODING 60 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 -06 0c 18 30 60 +c0 +60 30 18 0c -06 00 00 ENDCHAR -STARTCHAR 003d +STARTCHAR = ENCODING 61 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -7e -7e -00 -7e -7e +fc +fc 00 +fc +fc 00 00 00 00 ENDCHAR -STARTCHAR 003e +STARTCHAR > ENCODING 62 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 +c0 60 30 18 0c -06 -0c 18 30 60 +c0 00 00 ENDCHAR -STARTCHAR 003f +STARTCHAR ? ENCODING 63 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 +78 +cc +cc 0c -18 -18 -18 +38 +30 00 -18 -18 +30 +30 00 00 ENDCHAR -STARTCHAR 0040 +STARTCHAR @ ENCODING 64 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1c -36 -6e -7a -7a -7a -7a -6e -30 -1e +78 +8c +8c +bc +ac +bc +80 +8c +78 00 00 ENDCHAR -STARTCHAR 0041 +STARTCHAR A ENCODING 65 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -7e -66 -66 -66 -66 -7e -66 -66 -66 +78 +cc +cc +cc +fc +cc +cc +cc +cc 00 00 ENDCHAR -STARTCHAR 0042 +STARTCHAR B ENCODING 66 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7c -66 -66 -64 -7c -66 -66 -66 -66 -7c +f8 +cc +cc +cc +f8 +cc +cc +cc +f8 00 00 ENDCHAR -STARTCHAR 0043 +STARTCHAR C ENCODING 67 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -60 -60 -60 -60 -66 -66 -3c +78 +cc +c0 +c0 +c0 +c0 +c0 +cc +78 00 00 ENDCHAR -STARTCHAR 0044 +STARTCHAR D ENCODING 68 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -78 -6c -66 -66 -66 -66 -66 -66 -6c -78 +f8 +cc +cc +cc +cc +cc +cc +cc +f8 00 00 ENDCHAR -STARTCHAR 0045 +STARTCHAR E ENCODING 69 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -60 -60 -60 -7c -60 -60 -60 -60 -7e +fc +c0 +c0 +c0 +f8 +c0 +c0 +c0 +fc 00 00 ENDCHAR -STARTCHAR 0046 +STARTCHAR F ENCODING 70 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -60 -60 -60 -7c -60 -60 -60 -60 -60 +fc +c0 +c0 +c0 +f8 +c0 +c0 +c0 +c0 00 00 ENDCHAR -STARTCHAR 0047 +STARTCHAR G ENCODING 71 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -60 -60 -6e -66 -66 -66 -3c +78 +cc +c0 +c0 +dc +cc +cc +cc +7c 00 00 ENDCHAR -STARTCHAR 0048 +STARTCHAR H ENCODING 72 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -66 -66 -7e -66 -66 -66 -66 -66 +cc +cc +cc +cc +fc +cc +cc +cc +cc 00 00 ENDCHAR -STARTCHAR 0049 +STARTCHAR I ENCODING 73 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -18 -18 -18 -18 -18 -18 -18 -18 -7e +fc +30 +30 +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR -STARTCHAR 004a +STARTCHAR J ENCODING 74 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -06 -06 -06 -06 -06 -06 -06 -66 -6c -38 +0c +0c +0c +0c +0c +0c +0c +cc +78 00 00 ENDCHAR -STARTCHAR 004b +STARTCHAR K ENCODING 75 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -6c -78 -70 -70 -78 -78 -6c -66 -66 +c4 +cc +d8 +f0 +e0 +f0 +d8 +cc +c4 00 00 ENDCHAR -STARTCHAR 004c +STARTCHAR L ENCODING 76 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -60 -60 -60 -60 -60 -60 -60 -7e +c0 +c0 +c0 +c0 +c0 +c0 +c0 +c0 +fc 00 00 ENDCHAR -STARTCHAR 004d +STARTCHAR M ENCODING 77 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -66 -66 -7e -7e -66 -66 -66 -66 -66 +84 +cc +fc +fc +cc +cc +cc +cc +cc 00 00 ENDCHAR -STARTCHAR 004e +STARTCHAR N ENCODING 78 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -76 -76 -76 -6e -6e -6e -66 -66 +cc +cc +ec +ec +fc +dc +dc +cc +cc 00 00 ENDCHAR -STARTCHAR 004f +STARTCHAR O ENCODING 79 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -66 -66 -66 -66 -66 -66 -3c +78 +cc +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR -STARTCHAR 0050 +STARTCHAR P ENCODING 80 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7c -66 -66 -66 -66 -7c -60 -60 -60 -60 +f8 +cc +cc +cc +f8 +c0 +c0 +c0 +c0 00 00 ENDCHAR -STARTCHAR 0051 +STARTCHAR Q ENCODING 81 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -66 -66 -66 -76 -6e -66 -3c -06 -02 +78 +cc +cc +cc +cc +cc +ec +dc +78 +0c +00 ENDCHAR -STARTCHAR 0052 +STARTCHAR R ENCODING 82 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7c -66 -66 -66 -7c -6c -66 -66 -66 -66 +f8 +cc +cc +cc +f8 +f0 +d8 +cc +c4 00 00 ENDCHAR -STARTCHAR 0053 +STARTCHAR S ENCODING 83 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -30 -18 -18 +78 +cc +c0 +c0 +78 0c -66 -66 -3c +0c +cc +78 00 00 ENDCHAR -STARTCHAR 0054 +STARTCHAR T ENCODING 84 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -18 -18 -18 -18 -18 -18 -18 -18 -18 +fc +30 +30 +30 +30 +30 +30 +30 +30 00 00 ENDCHAR -STARTCHAR 0055 +STARTCHAR U ENCODING 85 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -66 -66 -66 -66 -66 -66 -66 -3c +cc +cc +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR -STARTCHAR 0056 +STARTCHAR V ENCODING 86 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -66 -66 -66 -66 -66 -3c -3c -18 +cc +cc +cc +48 +48 +78 +30 +30 +30 00 00 ENDCHAR -STARTCHAR 0057 +STARTCHAR W ENCODING 87 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -66 -66 -66 -7e -7e -7e -7e -24 +cc +cc +cc +cc +cc +fc +fc +cc +84 00 00 ENDCHAR -STARTCHAR 0058 +STARTCHAR X ENCODING 88 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -3c -3c -18 -18 -3c -3c -66 -66 +84 +cc +48 +78 +30 +78 +48 +cc +84 00 00 ENDCHAR -STARTCHAR 0059 +STARTCHAR Y ENCODING 89 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -66 -66 -66 -3c -3c -18 -18 -18 -18 -18 +cc +cc +78 +78 +30 +30 +30 +30 +30 00 00 ENDCHAR -STARTCHAR 005a +STARTCHAR Z ENCODING 90 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -06 +fc 0c 0c 18 -18 -30 30 60 -7e +c0 +c0 +fc 00 00 ENDCHAR -STARTCHAR 005b +STARTCHAR [ ENCODING 91 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3e -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -3e +00 +78 +60 +60 +60 +60 +60 +60 +60 +78 +00 +00 ENDCHAR -STARTCHAR 005c +STARTCHAR \ ENCODING 92 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -60 +00 +c0 +c0 60 60 30 -30 -18 18 18 0c 0c -06 -06 -06 +00 +00 ENDCHAR -STARTCHAR 005d +STARTCHAR ] ENCODING 93 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -7c -0c -0c -0c -0c -0c -0c -0c -0c -0c -0c -0c -7c +00 +78 +18 +18 +18 +18 +18 +18 +18 +78 +00 +00 ENDCHAR -STARTCHAR 005e +STARTCHAR ^ ENCODING 94 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c -66 -00 -00 00 00 +30 +78 +cc +84 00 00 00 @@ -1708,11 +1934,11 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 005f +STARTCHAR _ ENCODING 95 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -1724,24 +1950,22 @@ BITMAP 00 00 00 +fc +fc 00 -00 -7e -7e ENDCHAR -STARTCHAR 0060 +STARTCHAR ` ENCODING 96 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c +00 +00 +70 +70 +30 18 -18 -0c -00 -00 -00 00 00 00 @@ -1750,200 +1974,191 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 0061 +STARTCHAR a ENCODING 97 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3c -66 -0e -36 -66 -66 -3e +78 +0c +7c +cc +cc +7c 00 00 ENDCHAR -STARTCHAR 0062 +STARTCHAR b ENCODING 98 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -60 -7c -66 -66 -66 -66 -66 -7c +c0 +c0 +c0 +f8 +cc +cc +cc +cc +f8 00 00 ENDCHAR -STARTCHAR 0063 +STARTCHAR c ENCODING 99 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3c -66 -60 -60 -60 -66 -3c +78 +cc +c0 +c0 +cc +78 00 00 ENDCHAR -STARTCHAR 0064 +STARTCHAR d ENCODING 100 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -06 -06 -06 -3e -66 -66 -66 -66 -66 -3e +0c +0c +0c +7c +cc +cc +cc +cc +7c 00 00 ENDCHAR -STARTCHAR 0065 +STARTCHAR e ENCODING 101 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3c -66 -66 -7e -60 -66 -3c +78 +cc +fc +c0 +cc +78 00 00 ENDCHAR -STARTCHAR 0066 +STARTCHAR f ENCODING 102 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -0c -1e -18 -18 -7e -18 -18 -18 -18 -18 +38 +6c +60 +60 +f0 +60 +60 +60 +60 00 00 ENDCHAR -STARTCHAR 0067 +STARTCHAR g ENCODING 103 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3a -6e -6c -6c -38 -20 -7c -66 -3c +74 +cc +cc +78 +c0 +78 +cc +78 ENDCHAR -STARTCHAR 0068 +STARTCHAR h ENCODING 104 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -60 -7c -66 -66 -66 -66 -66 -66 +c0 +c0 +c0 +f8 +cc +cc +cc +cc +cc 00 00 ENDCHAR -STARTCHAR 0069 +STARTCHAR i ENCODING 105 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -18 +30 +30 00 -18 -18 -18 -18 -18 -18 -18 +70 +30 +30 +30 +30 +fc 00 00 ENDCHAR -STARTCHAR 006a +STARTCHAR j ENCODING 106 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -1956,421 +2171,400 @@ BITMAP 0c 0c 0c -0c -6c -38 +cc +78 ENDCHAR -STARTCHAR 006b +STARTCHAR k ENCODING 107 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -60 -64 -6c -78 -78 -6c -66 -62 +c0 +c0 +c0 +cc +d8 +f0 +f0 +d8 +cc 00 00 ENDCHAR -STARTCHAR 006c +STARTCHAR l ENCODING 108 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -00 -00 -ENDCHAR -STARTCHAR 006d -ENCODING 109 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -6c -7e -7e -7e -7e -7e -7e -00 -00 -ENDCHAR -STARTCHAR 006e -ENCODING 110 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -7c -66 -66 -66 -66 -66 -66 -00 -00 -ENDCHAR -STARTCHAR 006f -ENCODING 111 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3c -66 -66 -66 -66 -66 -3c -00 -00 -ENDCHAR -STARTCHAR 0070 -ENCODING 112 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -7c -66 -66 -66 -66 -66 -7c -60 -60 -ENDCHAR -STARTCHAR 0071 -ENCODING 113 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3e -66 -66 -66 -66 -66 -3e -06 -06 -ENDCHAR -STARTCHAR 0072 -ENCODING 114 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -7c -66 -66 -60 -60 -60 -60 -00 -00 -ENDCHAR -STARTCHAR 0073 -ENCODING 115 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -3c -66 +70 30 -18 -0c -66 -3c +30 +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR -STARTCHAR 0074 +STARTCHAR m +ENCODING 109 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +d8 +fc +fc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +f8 +cc +cc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +f8 +cc +cc +cc +f8 +c0 +c0 +c0 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +7c +cc +cc +cc +7c +0c +0c +0c +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +f8 +cc +c0 +c0 +c0 +c0 +00 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +78 +cc +60 +18 +cc +78 +00 +00 +ENDCHAR +STARTCHAR t ENCODING 116 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -18 -18 -18 -7e -18 -18 -18 -18 -18 -0e -00 -00 -ENDCHAR -STARTCHAR 0075 -ENCODING 117 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -00 -00 -66 -66 -66 -66 -66 -66 -3e -00 -00 -ENDCHAR -STARTCHAR 0076 -ENCODING 118 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -66 -66 -66 -3c -3c -18 -18 -00 -00 -ENDCHAR -STARTCHAR 0077 -ENCODING 119 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -66 -66 -7e -7e -7e -7e -24 -00 -00 -ENDCHAR -STARTCHAR 0078 -ENCODING 120 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -66 -66 -3c -18 -3c -66 -66 -00 -00 -ENDCHAR -STARTCHAR 0079 -ENCODING 121 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -00 -00 -00 -00 -66 -66 -36 -36 -1c -1c -0c +60 +60 +f8 +60 +60 +60 6c 38 +00 +00 ENDCHAR -STARTCHAR 007a -ENCODING 122 -SWIDTH 480 0 +STARTCHAR u +ENCODING 117 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -7e -06 +cc +cc +cc +cc +cc +7c +00 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +cc +cc +cc +78 +78 +30 +00 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +cc +cc +cc +fc +fc +48 +00 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +cc +cc +78 +78 +cc +cc +00 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +cc +cc +cc +cc +7c +0c +cc +78 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +00 +00 +00 +fc 0c 18 +60 +c0 +fc +00 +00 +ENDCHAR +STARTCHAR { +ENCODING 123 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +38 +60 +60 30 60 -7e +30 +60 +60 +38 00 00 ENDCHAR -STARTCHAR 007b -ENCODING 123 -SWIDTH 480 0 +STARTCHAR | +ENCODING 124 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0e -18 -18 -18 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +00 +00 +ENDCHAR +STARTCHAR } +ENCODING 125 +SWIDTH 570 0 +DWIDTH 7 0 +BBX 7 13 0 -2 +BITMAP +00 +00 +70 18 18 30 18 -18 -18 -18 -18 -0e -ENDCHAR -STARTCHAR 007c -ENCODING 124 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -18 -ENDCHAR -STARTCHAR 007d -ENCODING 125 -SWIDTH 480 0 -DWIDTH 7 0 -BBX 7 14 0 -2 -BITMAP -00 -70 -18 -18 -18 -18 -18 -0c -18 -18 -18 +30 18 18 70 +00 +00 ENDCHAR -STARTCHAR 007e +STARTCHAR ~ ENCODING 126 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -20 -7e -7e -04 00 +64 +fc +98 00 00 00 @@ -2380,11 +2574,11 @@ BITMAP 00 00 ENDCHAR -STARTCHAR 007f +STARTCHAR C177 ENCODING 127 -SWIDTH 480 0 +SWIDTH 570 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2399,13 +2593,12 @@ BITMAP 00 00 00 -00 ENDCHAR STARTCHAR 00a0 ENCODING 160 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2420,160 +2613,152 @@ BITMAP 00 00 00 -00 ENDCHAR STARTCHAR 00a1 ENCODING 161 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +30 00 -18 -18 -00 -18 -18 -18 -18 -18 -18 -18 +30 +30 +30 +30 +30 +30 +30 00 00 ENDCHAR STARTCHAR 00a2 ENCODING 162 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 +10 +7c +d4 +d0 +d0 +d4 +7c +10 00 00 -18 -3e -5a -58 -58 -58 -5a -3e -18 00 ENDCHAR STARTCHAR 00a3 ENCODING 163 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -00 -1c -36 -30 -30 -78 -30 -30 -7c -36 +38 +6c +60 +60 +f8 +60 +60 +6c +b8 00 00 ENDCHAR STARTCHAR 00a4 ENCODING 164 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 -66 -3c -34 -2c -3c -66 -00 +cc +fc +48 +48 +fc +cc 00 00 00 ENDCHAR STARTCHAR 00a5 ENCODING 165 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -42 -66 -3c -7e -18 -18 -7e -18 -18 -18 +cc +cc +78 +78 +fc +30 +fc +30 +30 00 00 ENDCHAR STARTCHAR 00a6 ENCODING 166 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -18 -18 -18 -18 +30 +30 +30 +30 00 00 -18 -18 -18 -18 +30 +30 +30 +30 00 00 ENDCHAR STARTCHAR 00a7 ENCODING 167 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -66 -30 -18 -3c -66 -3c -18 +78 +cc +c0 +78 +cc +cc +78 0c -66 -3c +cc +78 00 00 ENDCHAR STARTCHAR 00a8 ENCODING 168 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 6c @@ -2588,45 +2773,42 @@ BITMAP 00 00 00 -00 ENDCHAR STARTCHAR 00a9 ENCODING 169 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -66 -7e -76 -76 -76 -76 -76 -7e -66 -3c +78 +cc +84 +b4 +e4 +e4 +b4 +84 +cc +78 00 00 ENDCHAR STARTCHAR 00aa ENCODING 170 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -1c -36 -1e -36 -36 -1e 00 -3e +78 +0c +7c +4c +7c 00 +7c 00 00 00 @@ -2634,62 +2816,59 @@ BITMAP ENDCHAR STARTCHAR 00ab ENCODING 171 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 +34 +68 +d0 +a0 +d0 +68 +34 00 00 -0e -1e -3c -78 -3c -1e -0e -00 00 ENDCHAR STARTCHAR 00ac ENCODING 172 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -00 -00 fc fc -0c -0c -0c +04 +04 +00 +00 00 00 ENDCHAR STARTCHAR 00ad ENCODING 173 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 +7c +7c 00 00 -f0 -f0 -00 00 00 00 @@ -2697,35 +2876,33 @@ f0 ENDCHAR STARTCHAR 00ae ENCODING 174 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -3c -66 -7e -76 -76 -7e -76 -76 -76 -66 -3c +78 +cc +84 +bc +ac +bc +b4 +ac +cc +78 00 00 ENDCHAR STARTCHAR 00af ENCODING 175 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -f0 -f0 +7c +7c 00 00 00 @@ -2739,17 +2916,16 @@ f0 ENDCHAR STARTCHAR 00b0 ENCODING 176 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -38 -6c -6c -38 -00 00 +78 +cc +cc +78 00 00 00 @@ -2760,39 +2936,37 @@ BITMAP ENDCHAR STARTCHAR 00b1 ENCODING 177 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 +30 +30 +fc +fc +30 +30 00 -00 -00 -00 -18 -18 -7e -18 -18 -7e +fc +fc 00 00 ENDCHAR STARTCHAR 00b2 ENCODING 178 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -38 -6c -0c -18 +e0 +b0 30 60 -7c +c0 +f0 00 00 00 @@ -2802,18 +2976,17 @@ BITMAP ENDCHAR STARTCHAR 00b3 ENCODING 179 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -38 -6c -0c -38 -0c -6c -38 +e0 +b0 +60 +30 +b0 +e0 00 00 00 @@ -2823,15 +2996,14 @@ BITMAP ENDCHAR STARTCHAR 00b4 ENCODING 180 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0c 18 30 -60 +00 00 00 00 @@ -2844,60 +3016,57 @@ BITMAP ENDCHAR STARTCHAR 00b5 ENCODING 181 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 +cc +cc +cc +cc +cc +fc +80 00 -66 -66 -66 -66 -6e -7e -60 -60 ENDCHAR STARTCHAR 00b6 ENCODING 182 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3e -76 -76 -76 -76 -36 -16 -16 -16 -16 -16 -1e +7c +fc +f4 +f4 +f4 +74 +34 +34 +34 +00 +00 ENDCHAR STARTCHAR 00b7 ENCODING 183 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -18 -18 -00 +30 +30 00 00 00 @@ -2907,9 +3076,9 @@ BITMAP ENDCHAR STARTCHAR 00b8 ENCODING 184 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 @@ -2922,24 +3091,22 @@ BITMAP 00 00 00 -18 -18 30 +60 ENDCHAR STARTCHAR 00b9 ENCODING 185 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -30 -70 -30 -30 -30 -30 +60 +e0 +60 +60 +60 +f0 00 00 00 @@ -2949,19 +3116,18 @@ BITMAP ENDCHAR STARTCHAR 00ba ENCODING 186 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +38 +7c +44 +7c +38 00 -1c -36 -36 -1c -00 -3e -00 +7c 00 00 00 @@ -2970,1451 +3136,1382 @@ BITMAP ENDCHAR STARTCHAR 00bb ENCODING 187 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 +b0 +58 +2c +14 +2c +58 +b0 00 00 -70 -38 -1c -0e -1c -38 -70 -00 00 ENDCHAR STARTCHAR 00bc ENCODING 188 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -32 -76 +60 +e0 +60 +60 +64 +fc +1c 34 3c -3c -1a -36 -2e -6e -46 +0c 00 00 ENDCHAR STARTCHAR 00bd ENCODING 189 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -32 -76 -34 +60 +e0 +60 +60 +78 +ec +0c +18 +30 3c -3c -1c -3a -26 -6c -4e 00 00 ENDCHAR STARTCHAR 00be ENCODING 190 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -00 -62 -36 -74 +e0 +b0 +60 +30 +b4 +ec +1c +34 3c -78 -1e -36 -6e -4e -06 +0c 00 00 ENDCHAR STARTCHAR 00bf ENCODING 191 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +30 +30 +00 +30 +30 +60 +c0 +cc +cc +78 00 00 -0c -0c -00 -0c -0c -0c -0c -0c -66 -66 -3c ENDCHAR STARTCHAR 00c0 ENCODING 192 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -38 -1c 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +30 +18 +00 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c1 ENCODING 193 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +18 +30 +00 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c2 ENCODING 194 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +70 +d8 +00 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c3 ENCODING 195 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +68 +b0 +00 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c4 ENCODING 196 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -24 -24 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +cc +cc +00 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c5 ENCODING 197 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -18 00 -3c -7e -66 -66 -66 -7e -66 -66 -66 +78 +48 +78 +30 +78 +cc +cc +fc +cc +cc 00 00 ENDCHAR STARTCHAR 00c6 ENCODING 198 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -7e -d8 +7c +f8 d8 d8 dc f8 d8 d8 -d8 -de +dc 00 00 ENDCHAR STARTCHAR 00c7 ENCODING 199 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -3c -66 -66 -60 -60 -60 -60 -66 -66 -3c -18 +78 +cc +c0 +c0 +c0 +c0 +c0 +cc +78 30 +60 ENDCHAR STARTCHAR 00c8 ENCODING 200 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -38 -1c 00 -7e -60 -60 -60 -7c -60 -60 -60 -7e +30 +18 +00 +fc +c0 +c0 +f0 +c0 +c0 +fc 00 00 ENDCHAR STARTCHAR 00c9 ENCODING 201 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -7e -60 -60 -60 -7c -60 -60 -60 -7e +18 +30 +00 +fc +c0 +c0 +f0 +c0 +c0 +fc 00 00 ENDCHAR STARTCHAR 00ca ENCODING 202 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c 00 -7e -60 -60 -60 -7c -60 -60 -60 -7e +70 +d8 +00 +fc +c0 +c0 +f0 +c0 +c0 +fc 00 00 ENDCHAR STARTCHAR 00cb ENCODING 203 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -24 -24 00 -7e -60 -60 -60 -7c -60 -60 -60 -7e +cc +cc +00 +fc +c0 +c0 +f0 +c0 +c0 +fc 00 00 ENDCHAR STARTCHAR 00cc ENCODING 204 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -38 -1c 00 -7e +30 18 -18 -18 -18 -18 -18 -18 -7e +00 +fc +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR STARTCHAR 00cd ENCODING 205 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -7e 18 -18 -18 -18 -18 -18 -18 -7e +30 +00 +fc +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR STARTCHAR 00ce ENCODING 206 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c 00 -7e -18 -18 -18 -18 -18 -18 -18 -7e +70 +d8 +00 +fc +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR STARTCHAR 00cf ENCODING 207 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -24 -24 00 -7e -18 -18 -18 -18 -18 -18 -18 -7e +cc +cc +00 +fc +30 +30 +30 +30 +30 +fc 00 00 ENDCHAR STARTCHAR 00d0 ENCODING 208 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -78 +f8 6c -66 -66 -fe -66 -66 -66 6c -78 +6c +ec +6c +6c +6c +f8 00 00 ENDCHAR STARTCHAR 00d1 ENCODING 209 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -66 -76 -76 -76 -6e -6e -6e -66 -66 +68 +b0 +00 +cc +cc +ec +fc +dc +cc +cc 00 00 ENDCHAR STARTCHAR 00d2 ENCODING 210 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -38 -1c 00 -3c -66 -66 -66 -66 -66 -66 -66 -3c +30 +18 +00 +78 +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00d3 ENCODING 211 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -3c -66 -66 -66 -66 -66 -66 -66 -3c +18 +30 +00 +78 +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00d4 ENCODING 212 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c 00 -3c -66 -66 -66 -66 -66 -66 -66 -3c +70 +d8 +00 +78 +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00d5 ENCODING 213 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -14 -28 00 -3c -66 -66 -66 -66 -66 -66 -66 -3c +68 +b0 +00 +78 +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00d6 ENCODING 214 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -24 -24 00 -3c -66 -66 -66 -66 -66 -66 -66 -3c +cc +cc +00 +78 +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00d7 ENCODING 215 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -c6 -6c -38 -38 -6c -c6 -82 +cc +78 +30 +78 +cc +00 00 00 ENDCHAR STARTCHAR 00d8 ENCODING 216 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -02 -02 -3c -6e -6e -6e -6e -76 -76 -76 -76 -3c -40 -40 +00 +00 +04 +78 +dc +dc +dc +ec +ec +ec +78 +80 +00 ENDCHAR STARTCHAR 00d9 ENCODING 217 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -38 -1c 00 -66 -66 -66 -66 -66 -66 -66 -66 -3c +30 +18 +00 +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00da ENCODING 218 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -66 -66 -66 -66 -66 -66 -66 -66 -3c +18 +30 +00 +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00db ENCODING 219 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -18 -3c 00 -66 -66 -66 -66 -66 -66 -66 -66 -3c +70 +d8 +00 +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00dc ENCODING 220 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -24 -24 00 -66 -66 -66 -66 -66 -66 -66 -66 -3c +cc +cc +00 +cc +cc +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00dd ENCODING 221 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP -1c -38 00 -66 -66 -66 -3c -3c -3c -18 -18 18 +30 +00 +cc +48 +78 +30 +30 +30 +30 00 00 ENDCHAR STARTCHAR 00de ENCODING 222 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -7c -66 -66 -66 -66 -7c -60 -60 +c0 +f8 +cc +cc +cc +f8 +c0 +c0 +c0 00 00 ENDCHAR STARTCHAR 00df ENCODING 223 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -1c -36 -36 -36 -3c -36 -36 -36 -36 -7c 00 +78 +cc +cc +f8 +cc +cc +cc +f8 +80 00 ENDCHAR STARTCHAR 00e0 ENCODING 224 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 30 18 -0c 00 -3c -66 -1e -36 -66 -66 -3e +00 +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e1 ENCODING 225 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0c 18 30 00 -3c -66 -1e -36 -66 -66 -3e +00 +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e2 ENCODING 226 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +70 +d8 00 -18 -3c 00 -3c -66 -1e -36 -66 -66 -3e +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e3 ENCODING 227 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +68 +b0 00 -14 -28 00 -3c -66 -1e -36 -66 -66 -3e +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e4 ENCODING 228 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -3c -66 -1e -36 -66 -66 -3e +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e5 ENCODING 229 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -18 -3c -18 +38 +28 +38 00 -3c -66 -1e -36 -66 -66 -3e +78 +0c +7c +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00e6 ENCODING 230 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 +78 +34 7c -da -3a -5e -d8 -de -7c +b0 +b4 +68 00 00 ENDCHAR STARTCHAR 00e7 ENCODING 231 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 00 00 -3c -66 -60 -60 -60 -66 -3c -18 +78 +cc +c0 +c0 +cc +78 30 +60 ENDCHAR STARTCHAR 00e8 ENCODING 232 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 30 18 -0c 00 -3c -66 -66 -7e -60 -66 -3c +00 +78 +cc +fc +c0 +cc +78 00 00 ENDCHAR STARTCHAR 00e9 ENCODING 233 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0c 18 30 00 -3c -66 -66 -7e -60 -66 -3c +00 +78 +cc +fc +c0 +cc +78 00 00 ENDCHAR STARTCHAR 00ea ENCODING 234 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +70 +d8 00 -18 -3c 00 -3c -66 -66 -7e -60 -66 -3c +78 +cc +fc +c0 +cc +78 00 00 ENDCHAR STARTCHAR 00eb ENCODING 235 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -3c -66 -66 -7e -60 -66 -3c +78 +cc +fc +c0 +cc +78 00 00 ENDCHAR STARTCHAR 00ec ENCODING 236 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 30 18 -0c 00 -18 -18 -18 -18 -18 -18 -18 +00 +70 +30 +30 +30 +30 +78 00 00 ENDCHAR STARTCHAR 00ed ENCODING 237 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0c 18 30 00 -18 -18 -18 -18 -18 -18 -18 +00 +70 +30 +30 +30 +30 +78 00 00 ENDCHAR STARTCHAR 00ee ENCODING 238 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +70 +d8 00 -18 -3c 00 -18 -18 -18 -18 -18 -18 -18 +70 +30 +30 +30 +30 +78 00 00 ENDCHAR STARTCHAR 00ef ENCODING 239 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -18 -18 -18 -18 -18 -18 -18 +70 +30 +30 +30 +30 +78 00 00 ENDCHAR STARTCHAR 00f0 ENCODING 240 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -28 -10 -2c -0c -3c -6c -6c -6c -6c -6c -38 +48 +30 +30 +50 +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f1 ENCODING 241 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +68 +b0 00 -14 -28 00 -7c -66 -66 -66 -66 -66 -66 +f8 +ec +cc +cc +cc +cc 00 00 ENDCHAR STARTCHAR 00f2 ENCODING 242 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 30 18 -0c 00 -3c -66 -66 -66 -66 -66 -3c +00 +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f3 ENCODING 243 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -0c 18 30 00 -3c -66 -66 -66 -66 -66 -3c +00 +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f4 ENCODING 244 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +70 +d8 00 -18 -3c 00 -3c -66 -66 -66 -66 -66 -3c +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f5 ENCODING 245 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +68 +b0 00 -14 -28 00 -3c -66 -66 -66 -66 -66 -3c +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f6 ENCODING 246 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -3c -66 -66 -66 -66 -66 -3c +78 +cc +cc +cc +cc +78 00 00 ENDCHAR STARTCHAR 00f7 ENCODING 247 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -00 -00 -00 -00 +30 30 00 fc 00 30 +30 +00 00 00 ENDCHAR STARTCHAR 00f8 ENCODING 248 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 00 -02 04 -3c -6e -6e -76 -76 -66 -3c -40 -40 +78 +cc +dc +cc +ec +cc +78 +80 +00 ENDCHAR STARTCHAR 00f9 ENCODING 249 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -20 30 18 -08 -66 -66 -66 -66 -66 -66 -3e +00 +00 +cc +cc +cc +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00fa ENCODING 250 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -04 -0c 18 -10 -66 -66 -66 -66 -66 -66 -3e +30 +00 +00 +cc +cc +cc +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00fb ENCODING 251 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +70 +d8 00 -18 -3c 00 -66 -66 -66 -66 -66 -66 -3e +cc +cc +cc +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00fc ENCODING 252 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -66 -66 -66 -66 -66 -66 -3e +cc +cc +cc +cc +dc +7c 00 00 ENDCHAR STARTCHAR 00fd ENCODING 253 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 -04 -0c 18 -10 -66 -66 -66 -3c -1c -1c -18 -78 30 +00 +00 +cc +cc +cc +dc +7c +0c +cc +78 ENDCHAR STARTCHAR 00fe ENCODING 254 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 00 -60 -60 -60 -7c -66 -66 -66 -66 -66 -7c -60 -60 +00 +c0 +c0 +f8 +ec +cc +cc +ec +f8 +c0 +c0 ENDCHAR STARTCHAR 00ff ENCODING 255 -SWIDTH 480 0 +SWIDTH 666 0 DWIDTH 7 0 -BBX 7 14 0 -2 +BBX 7 13 0 -2 BITMAP 00 +6c +6c 00 -24 -24 00 -66 -66 -66 -3c -1c -1c -18 +cc +cc +cc +dc +7c +0c +cc 78 -30 ENDCHAR ENDFONT diff --git a/src/default.c b/src/default.c index 44e4c4d6f..baeeb674d 100644 --- a/src/default.c +++ b/src/default.c @@ -1,18 +1,38 @@ #include +// #define USE_CATPPUCCIN + +#ifdef USE_CATPPUCCIN +const char* MwDefaultBackground = "#eff1f5"; +const char* MwDefaultForeground = "#4c4f69"; +const char* MwDefaultSubBackground = "#9ca0b0"; +const char* MwDefaultSubForeground = "#6c6f85"; +const char* MwDefaultTitleBackground = "#bcc0cc"; +const char* MwDefaultTitleForeground = "#5c5f77"; +#else const char* MwDefaultBackground = "#d2d2d2"; const char* MwDefaultForeground = "#000"; const char* MwDefaultSubBackground = "#fff"; const char* MwDefaultSubForeground = "#000"; const char* MwDefaultTitleBackground = "#008"; const char* MwDefaultTitleForeground = "#fff"; +#endif +#ifdef USE_CATPPUCCIN +const char* MwDefaultDarkBackground = "#1e1e2e"; +const char* MwDefaultDarkForeground = "#cdd6f4"; +const char* MwDefaultDarkSubBackground = "#313244"; +const char* MwDefaultDarkSubForeground = "#a6adc8"; +const char* MwDefaultDarkTitleBackground = "#45475a"; +const char* MwDefaultDarkTitleForeground = "#bac2de"; +#else const char* MwDefaultDarkBackground = "#333"; const char* MwDefaultDarkForeground = "#ddd"; const char* MwDefaultDarkSubBackground = "#333"; const char* MwDefaultDarkSubForeground = "#ddd"; const char* MwDefaultDarkTitleBackground = "#008"; const char* MwDefaultDarkTitleForeground = "#fff"; +#endif const int MwDefaultShadow = -32; diff --git a/src/text/font/boldfont.c b/src/text/font/boldfont.c index c63be2c4e..b021adaf8 100644 --- a/src/text/font/boldfont.c +++ b/src/text/font/boldfont.c @@ -5,260 +5,260 @@ * "Public domain font. Share and enjoy." */ MwFont MwBoldFontData[] = { - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0 */ - {0, 12, {0, 0, 12, 12, 30, 30, 63, 63, 30, 30, 12, 12, 0, 0}}, /* 1 */ - {0, 12, {59, 119, 110, 93, 59, 119, 110, 93, 59, 119, 110, 93, 59, 119}}, /* 2 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 3 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 4 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 5 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 6 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 8 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 9 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 10 */ - {0, 12, {12, 12, 12, 12, 12, 12, 124, 124, 0, 0, 0, 0, 0, 0}}, /* 11 */ - {0, 12, {0, 0, 0, 0, 0, 0, 124, 124, 12, 12, 12, 12, 12, 12}}, /* 12 */ - {0, 12, {0, 0, 0, 0, 0, 0, 15, 15, 12, 12, 12, 12, 12, 12}}, /* 13 */ - {0, 12, {12, 12, 12, 12, 12, 12, 15, 15, 0, 0, 0, 0, 0, 0}}, /* 14 */ - {0, 12, {12, 12, 12, 12, 12, 12, 127, 127, 12, 12, 12, 12, 12, 12}}, /* 15 */ - {0, 12, {127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ - {0, 12, {0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ - {0, 12, {0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0}}, /* 18 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0}}, /* 19 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127}}, /* 20 */ - {0, 12, {12, 12, 12, 12, 12, 12, 15, 15, 12, 12, 12, 12, 12, 12}}, /* 21 */ - {0, 12, {12, 12, 12, 12, 12, 12, 124, 124, 12, 12, 12, 12, 12, 12}}, /* 22 */ - {0, 12, {12, 12, 12, 12, 12, 12, 127, 127, 0, 0, 0, 0, 0, 0}}, /* 23 */ - {0, 12, {0, 0, 0, 0, 0, 0, 127, 127, 12, 12, 12, 12, 12, 12}}, /* 24 */ - {0, 12, {12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}}, /* 25 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 26 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 27 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 28 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 29 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 30 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 31 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ - {0, 12, {0, 0, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 0, 0}}, /* 33 */ - {0, 12, {63, 27, 27, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ - {0, 12, {0, 0, 15, 15, 15, 63, 30, 30, 63, 60, 60, 60, 0, 0}}, /* 35 */ - {0, 12, {0, 0, 12, 30, 45, 45, 28, 14, 13, 45, 45, 30, 12, 0}}, /* 36 */ - {0, 12, {0, 0, 27, 55, 54, 28, 4, 8, 14, 27, 59, 54, 0, 0}}, /* 37 */ - {0, 12, {0, 0, 14, 27, 27, 27, 14, 27, 55, 54, 54, 27, 0, 0}}, /* 38 */ - {0, 12, {28, 12, 12, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ - {0, 12, {0, 3, 6, 12, 12, 24, 24, 24, 24, 24, 12, 12, 6, 3}}, /* 40 */ - {0, 12, {0, 48, 24, 12, 12, 6, 6, 6, 6, 6, 12, 12, 24, 48}}, /* 41 */ - {0, 12, {0, 0, 0, 45, 45, 30, 12, 12, 30, 45, 45, 0, 0, 0}}, /* 42 */ - {0, 12, {0, 0, 0, 0, 12, 12, 12, 63, 12, 12, 12, 0, 0, 0}}, /* 43 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 12, 12, 24}}, /* 44 */ - {0, 12, {0, 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0, 0}}, /* 45 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0}}, /* 46 */ - {0, 12, {0, 3, 3, 3, 6, 6, 12, 12, 12, 24, 24, 48, 48, 48}}, /* 47 */ - {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 48 */ - {0, 12, {0, 0, 12, 28, 60, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 49 */ - {0, 12, {0, 0, 30, 51, 51, 3, 6, 6, 12, 24, 48, 63, 0, 0}}, /* 50 */ - {0, 12, {0, 0, 30, 51, 51, 3, 14, 3, 3, 51, 51, 30, 0, 0}}, /* 51 */ - {0, 12, {0, 0, 2, 6, 6, 14, 30, 22, 54, 63, 2, 2, 0, 0}}, /* 52 */ - {0, 12, {0, 0, 63, 48, 48, 62, 51, 3, 3, 51, 51, 30, 0, 0}}, /* 53 */ - {0, 12, {0, 0, 14, 27, 51, 48, 62, 51, 51, 51, 51, 30, 0, 0}}, /* 54 */ - {0, 12, {0, 0, 63, 51, 54, 6, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 55 */ - {0, 12, {0, 0, 30, 51, 51, 30, 12, 30, 51, 51, 51, 30, 0, 0}}, /* 56 */ - {0, 12, {0, 0, 30, 51, 51, 51, 51, 31, 3, 51, 54, 28, 0, 0}}, /* 57 */ - {0, 12, {0, 0, 0, 0, 12, 12, 0, 0, 0, 12, 12, 0, 0, 0}}, /* 58 */ - {0, 12, {0, 0, 0, 0, 12, 12, 0, 0, 0, 28, 12, 12, 24, 0}}, /* 59 */ - {0, 12, {0, 0, 0, 3, 6, 12, 24, 48, 24, 12, 6, 3, 0, 0}}, /* 60 */ - {0, 12, {0, 0, 0, 0, 63, 63, 0, 63, 63, 0, 0, 0, 0, 0}}, /* 61 */ - {0, 12, {0, 0, 0, 48, 24, 12, 6, 3, 6, 12, 24, 48, 0, 0}}, /* 62 */ - {0, 12, {0, 0, 30, 51, 51, 6, 12, 12, 12, 0, 12, 12, 0, 0}}, /* 63 */ - {0, 12, {0, 0, 14, 27, 55, 61, 61, 61, 61, 55, 24, 15, 0, 0}}, /* 64 */ - {0, 12, {0, 0, 30, 63, 51, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 65 */ - {0, 12, {0, 0, 62, 51, 51, 50, 62, 51, 51, 51, 51, 62, 0, 0}}, /* 66 */ - {0, 12, {0, 0, 30, 51, 51, 48, 48, 48, 48, 51, 51, 30, 0, 0}}, /* 67 */ - {0, 12, {0, 0, 60, 54, 51, 51, 51, 51, 51, 51, 54, 60, 0, 0}}, /* 68 */ - {0, 12, {0, 0, 63, 48, 48, 48, 62, 48, 48, 48, 48, 63, 0, 0}}, /* 69 */ - {0, 12, {0, 0, 63, 48, 48, 48, 62, 48, 48, 48, 48, 48, 0, 0}}, /* 70 */ - {0, 12, {0, 0, 30, 51, 51, 48, 48, 55, 51, 51, 51, 30, 0, 0}}, /* 71 */ - {0, 12, {0, 0, 51, 51, 51, 51, 63, 51, 51, 51, 51, 51, 0, 0}}, /* 72 */ - {0, 12, {0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 73 */ - {0, 12, {0, 0, 3, 3, 3, 3, 3, 3, 3, 51, 54, 28, 0, 0}}, /* 74 */ - {0, 12, {0, 0, 51, 54, 60, 56, 56, 60, 60, 54, 51, 51, 0, 0}}, /* 75 */ - {0, 12, {0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 63, 0, 0}}, /* 76 */ - {0, 12, {0, 0, 33, 51, 51, 63, 63, 51, 51, 51, 51, 51, 0, 0}}, /* 77 */ - {0, 12, {0, 0, 51, 51, 59, 59, 59, 55, 55, 55, 51, 51, 0, 0}}, /* 78 */ - {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 79 */ - {0, 12, {0, 0, 62, 51, 51, 51, 51, 62, 48, 48, 48, 48, 0, 0}}, /* 80 */ - {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 59, 55, 51, 30, 3, 1}}, /* 81 */ - {0, 12, {0, 0, 62, 51, 51, 51, 62, 54, 51, 51, 51, 51, 0, 0}}, /* 82 */ - {0, 12, {0, 0, 30, 51, 51, 24, 12, 12, 6, 51, 51, 30, 0, 0}}, /* 83 */ - {0, 12, {0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 84 */ - {0, 12, {0, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 85 */ - {0, 12, {0, 0, 51, 51, 51, 51, 51, 51, 51, 30, 30, 12, 0, 0}}, /* 86 */ - {0, 12, {0, 0, 51, 51, 51, 51, 51, 63, 63, 63, 63, 18, 0, 0}}, /* 87 */ - {0, 12, {0, 0, 51, 51, 30, 30, 12, 12, 30, 30, 51, 51, 0, 0}}, /* 88 */ - {0, 12, {0, 0, 51, 51, 51, 30, 30, 12, 12, 12, 12, 12, 0, 0}}, /* 89 */ - {0, 12, {0, 0, 63, 3, 6, 6, 12, 12, 24, 24, 48, 63, 0, 0}}, /* 90 */ - {0, 12, {0, 31, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 31}}, /* 91 */ - {0, 12, {0, 48, 48, 48, 24, 24, 12, 12, 12, 6, 6, 3, 3, 3}}, /* 92 */ - {0, 12, {0, 62, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 62}}, /* 93 */ - {0, 12, {12, 30, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 63}}, /* 95 */ - {0, 12, {14, 12, 12, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 7, 27, 51, 51, 31, 0, 0}}, /* 97 */ - {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 62, 0, 0}}, /* 98 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 48, 48, 48, 51, 30, 0, 0}}, /* 99 */ - {0, 12, {0, 0, 3, 3, 3, 31, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 100 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 101 */ - {0, 12, {0, 0, 6, 15, 12, 12, 63, 12, 12, 12, 12, 12, 0, 0}}, /* 102 */ - {0, 12, {0, 0, 0, 0, 0, 29, 55, 54, 54, 28, 16, 62, 51, 30}}, /* 103 */ - {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 104 */ - {0, 12, {0, 0, 12, 12, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 105 */ - {0, 12, {0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 54, 28}}, /* 106 */ - {0, 12, {0, 0, 48, 48, 48, 50, 54, 60, 60, 54, 51, 49, 0, 0}}, /* 107 */ - {0, 12, {0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 108 */ - {0, 12, {0, 0, 0, 0, 0, 54, 63, 63, 63, 63, 63, 63, 0, 0}}, /* 109 */ - {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 110 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 111 */ - {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 51, 51, 51, 62, 48, 48}}, /* 112 */ - {0, 12, {0, 0, 0, 0, 0, 31, 51, 51, 51, 51, 51, 31, 3, 3}}, /* 113 */ - {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 48, 48, 48, 48, 0, 0}}, /* 114 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 24, 12, 6, 51, 30, 0, 0}}, /* 115 */ - {0, 12, {0, 0, 12, 12, 12, 63, 12, 12, 12, 12, 12, 7, 0, 0}}, /* 116 */ - {0, 12, {0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 117 */ - {0, 12, {0, 0, 0, 0, 0, 51, 51, 51, 30, 30, 12, 12, 0, 0}}, /* 118 */ - {0, 12, {0, 0, 0, 0, 0, 51, 51, 63, 63, 63, 63, 18, 0, 0}}, /* 119 */ - {0, 12, {0, 0, 0, 0, 0, 51, 51, 30, 12, 30, 51, 51, 0, 0}}, /* 120 */ - {0, 12, {0, 0, 0, 0, 0, 51, 51, 27, 27, 14, 14, 6, 54, 28}}, /* 121 */ - {0, 12, {0, 0, 0, 0, 0, 63, 3, 6, 12, 24, 48, 63, 0, 0}}, /* 122 */ - {0, 12, {0, 7, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 7}}, /* 123 */ - {0, 12, {0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}}, /* 124 */ - {0, 12, {0, 56, 12, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, 56}}, /* 125 */ - {0, 12, {0, 16, 63, 63, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 128 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 129 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 130 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 131 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 132 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 133 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 134 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 135 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 136 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 137 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 138 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 139 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 140 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 141 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 142 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 143 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 144 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 145 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 146 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 147 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 148 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 149 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 150 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 151 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 152 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 153 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 154 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 155 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 156 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 157 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 158 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 159 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ - {0, 12, {0, 0, 12, 12, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 161 */ - {0, 12, {0, 0, 0, 0, 12, 31, 45, 44, 44, 44, 45, 31, 12, 0}}, /* 162 */ - {0, 12, {0, 0, 0, 14, 27, 24, 24, 60, 24, 24, 62, 27, 0, 0}}, /* 163 */ - {0, 12, {0, 0, 0, 0, 51, 30, 26, 22, 30, 51, 0, 0, 0, 0}}, /* 164 */ - {0, 12, {0, 0, 33, 51, 30, 63, 12, 12, 63, 12, 12, 12, 0, 0}}, /* 165 */ - {0, 12, {0, 0, 12, 12, 12, 12, 0, 0, 12, 12, 12, 12, 0, 0}}, /* 166 */ - {0, 12, {0, 30, 51, 24, 12, 30, 51, 30, 12, 6, 51, 30, 0, 0}}, /* 167 */ - {0, 12, {0, 54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ - {0, 12, {0, 30, 51, 63, 59, 59, 59, 59, 59, 63, 51, 30, 0, 0}}, /* 169 */ - {0, 12, {0, 14, 27, 15, 27, 27, 15, 0, 31, 0, 0, 0, 0, 0}}, /* 170 */ - {0, 12, {0, 0, 0, 0, 0, 7, 15, 30, 60, 30, 15, 7, 0, 0}}, /* 171 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 126, 126, 6, 6, 6, 0, 0}}, /* 172 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 120, 120, 0, 0, 0, 0, 0}}, /* 173 */ - {0, 12, {0, 30, 51, 63, 59, 59, 63, 59, 59, 59, 51, 30, 0, 0}}, /* 174 */ - {0, 12, {0, 0, 120, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ - {0, 12, {0, 28, 54, 54, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ - {0, 12, {0, 0, 0, 0, 0, 0, 12, 12, 63, 12, 12, 63, 0, 0}}, /* 177 */ - {0, 12, {0, 28, 54, 6, 12, 24, 48, 62, 0, 0, 0, 0, 0, 0}}, /* 178 */ - {0, 12, {0, 28, 54, 6, 28, 6, 54, 28, 0, 0, 0, 0, 0, 0}}, /* 179 */ - {0, 12, {0, 6, 12, 24, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ - {0, 12, {0, 0, 0, 0, 0, 0, 51, 51, 51, 51, 55, 63, 48, 48}}, /* 181 */ - {0, 12, {0, 0, 31, 59, 59, 59, 59, 27, 11, 11, 11, 11, 11, 15}}, /* 182 */ - {0, 12, {0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0}}, /* 183 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 24}}, /* 184 */ - {0, 12, {0, 0, 24, 56, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0}}, /* 185 */ - {0, 12, {0, 0, 14, 27, 27, 14, 0, 31, 0, 0, 0, 0, 0, 0}}, /* 186 */ - {0, 12, {0, 0, 0, 0, 0, 56, 28, 14, 7, 14, 28, 56, 0, 0}}, /* 187 */ - {0, 12, {0, 0, 25, 59, 26, 30, 30, 13, 27, 23, 55, 35, 0, 0}}, /* 188 */ - {0, 12, {0, 0, 25, 59, 26, 30, 30, 14, 29, 19, 54, 39, 0, 0}}, /* 189 */ - {0, 12, {0, 0, 49, 27, 58, 30, 60, 15, 27, 55, 39, 3, 0, 0}}, /* 190 */ - {0, 12, {0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 51, 51, 30}}, /* 191 */ - {0, 12, {28, 14, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 192 */ - {0, 12, {14, 28, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 193 */ - {0, 12, {12, 30, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 194 */ - {0, 12, {10, 20, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 195 */ - {0, 12, {18, 18, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 196 */ - {0, 12, {12, 12, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 197 */ - {0, 12, {0, 0, 63, 108, 108, 108, 110, 124, 108, 108, 108, 111, 0, 0}}, /* 198 */ - {0, 12, {0, 0, 30, 51, 51, 48, 48, 48, 48, 51, 51, 30, 12, 24}}, /* 199 */ - {0, 12, {28, 14, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 200 */ - {0, 12, {14, 28, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 201 */ - {0, 12, {12, 30, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 202 */ - {0, 12, {18, 18, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 203 */ - {0, 12, {28, 14, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 204 */ - {0, 12, {14, 28, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 205 */ - {0, 12, {12, 30, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 206 */ - {0, 12, {18, 18, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 207 */ - {0, 12, {0, 0, 60, 54, 51, 51, 127, 51, 51, 51, 54, 60, 0, 0}}, /* 208 */ - {0, 12, {10, 20, 0, 51, 59, 59, 59, 55, 55, 55, 51, 51, 0, 0}}, /* 209 */ - {0, 12, {28, 14, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 210 */ - {0, 12, {14, 28, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 211 */ - {0, 12, {12, 30, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 212 */ - {0, 12, {10, 20, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 213 */ - {0, 12, {18, 18, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 214 */ - {0, 12, {0, 0, 0, 0, 0, 99, 54, 28, 28, 54, 99, 65, 0, 0}}, /* 215 */ - {0, 12, {1, 1, 30, 55, 55, 55, 55, 59, 59, 59, 59, 30, 32, 32}}, /* 216 */ - {0, 12, {28, 14, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 217 */ - {0, 12, {14, 28, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 218 */ - {0, 12, {12, 30, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 219 */ - {0, 12, {18, 18, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 220 */ - {0, 12, {14, 28, 0, 51, 51, 51, 30, 30, 30, 12, 12, 12, 0, 0}}, /* 221 */ - {0, 12, {0, 0, 48, 48, 62, 51, 51, 51, 51, 62, 48, 48, 0, 0}}, /* 222 */ - {0, 12, {0, 0, 14, 27, 27, 27, 30, 27, 27, 27, 27, 62, 0, 0}}, /* 223 */ - {0, 12, {0, 24, 12, 6, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 224 */ - {0, 12, {0, 6, 12, 24, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 225 */ - {0, 12, {0, 0, 12, 30, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 226 */ - {0, 12, {0, 0, 10, 20, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 227 */ - {0, 12, {0, 0, 18, 18, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 228 */ - {0, 12, {0, 12, 30, 12, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 229 */ - {0, 12, {0, 0, 0, 0, 0, 62, 109, 29, 47, 108, 111, 62, 0, 0}}, /* 230 */ - {0, 12, {0, 0, 0, 0, 0, 30, 51, 48, 48, 48, 51, 30, 12, 24}}, /* 231 */ - {0, 12, {0, 24, 12, 6, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 232 */ - {0, 12, {0, 6, 12, 24, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 233 */ - {0, 12, {0, 0, 12, 30, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 234 */ - {0, 12, {0, 0, 18, 18, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 235 */ - {0, 12, {0, 24, 12, 6, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 236 */ - {0, 12, {0, 6, 12, 24, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 237 */ - {0, 12, {0, 0, 12, 30, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 238 */ - {0, 12, {0, 0, 18, 18, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 239 */ - {0, 12, {0, 20, 8, 22, 6, 30, 54, 54, 54, 54, 54, 28, 0, 0}}, /* 240 */ - {0, 12, {0, 0, 10, 20, 0, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 241 */ - {0, 12, {0, 24, 12, 6, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 242 */ - {0, 12, {0, 6, 12, 24, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 243 */ - {0, 12, {0, 0, 12, 30, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 244 */ - {0, 12, {0, 0, 10, 20, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 245 */ - {0, 12, {0, 0, 18, 18, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 246 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 24, 0, 126, 0, 24, 0, 0}}, /* 247 */ - {0, 12, {0, 0, 0, 1, 2, 30, 55, 55, 59, 59, 51, 30, 32, 32}}, /* 248 */ - {0, 12, {0, 16, 24, 12, 4, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 249 */ - {0, 12, {0, 2, 6, 12, 8, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 250 */ - {0, 12, {0, 0, 12, 30, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 251 */ - {0, 12, {0, 0, 18, 18, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 252 */ - {0, 12, {0, 2, 6, 12, 8, 51, 51, 51, 30, 14, 14, 12, 60, 24}}, /* 253 */ - {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 62, 48, 48}}, /* 254 */ - {0, 12, {0, 0, 18, 18, 0, 51, 51, 51, 30, 14, 14, 12, 60, 24}} /* 255 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 0 */ + {0, 11, {0, 0, 0, 0, 0, 24, 60, 126, 60, 24, 0, 0, 0}}, /* 1 */ + {0, 11, {0, 102, 24, 102, 24, 102, 24, 102, 24, 102, 24, 102, 0}}, /* 2 */ + {0, 11, {0, 108, 108, 124, 108, 108, 0, 30, 12, 12, 12, 12, 0}}, /* 3 */ + {0, 11, {0, 120, 96, 112, 96, 96, 0, 30, 24, 28, 24, 24, 0}}, /* 4 */ + {0, 11, {0, 56, 96, 96, 96, 56, 0, 28, 26, 28, 26, 26, 0}}, /* 5 */ + {0, 11, {0, 96, 96, 96, 96, 120, 0, 30, 24, 28, 24, 24, 0}}, /* 6 */ + {0, 11, {0, 0, 60, 102, 102, 60, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ + {0, 11, {0, 0, 24, 24, 126, 126, 24, 24, 0, 126, 126, 0, 0}}, /* 8 */ + {0, 11, {0, 102, 118, 126, 110, 102, 0, 24, 24, 24, 24, 30, 0}}, /* 9 */ + {0, 11, {0, 102, 102, 36, 60, 24, 0, 30, 12, 12, 12, 12, 0}}, /* 10 */ + {0, 11, {24, 24, 24, 24, 24, 24, 120, 120, 0, 0, 0, 0, 0}}, /* 11 */ + {0, 11, {0, 0, 0, 0, 0, 0, 120, 120, 24, 24, 24, 24, 24}}, /* 12 */ + {0, 11, {0, 0, 0, 0, 0, 0, 31, 31, 24, 24, 24, 24, 24}}, /* 13 */ + {0, 11, {24, 24, 24, 24, 24, 24, 31, 31, 0, 0, 0, 0, 0}}, /* 14 */ + {0, 11, {24, 24, 24, 24, 24, 24, 127, 127, 24, 24, 24, 24, 24}}, /* 15 */ + {0, 11, {0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ + {0, 11, {0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ + {0, 11, {0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0}}, /* 18 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0}}, /* 19 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0}}, /* 20 */ + {0, 11, {24, 24, 24, 24, 24, 24, 31, 31, 24, 24, 24, 24, 24}}, /* 21 */ + {0, 11, {24, 24, 24, 24, 24, 24, 120, 120, 24, 24, 24, 24, 24}}, /* 22 */ + {0, 11, {24, 24, 24, 24, 24, 24, 127, 127, 0, 0, 0, 0, 0}}, /* 23 */ + {0, 11, {0, 0, 0, 0, 0, 0, 127, 127, 24, 24, 24, 24, 24}}, /* 24 */ + {0, 11, {24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24}}, /* 25 */ + {0, 11, {0, 0, 6, 12, 48, 96, 48, 12, 6, 126, 126, 0, 0}}, /* 26 */ + {0, 11, {0, 0, 96, 48, 12, 6, 12, 48, 96, 126, 126, 0, 0}}, /* 27 */ + {0, 11, {0, 0, 0, 0, 0, 126, 54, 54, 54, 118, 102, 0, 0}}, /* 28 */ + {0, 11, {0, 0, 2, 6, 126, 126, 24, 126, 126, 96, 64, 0, 0}}, /* 29 */ + {0, 11, {0, 0, 28, 54, 48, 48, 124, 48, 48, 54, 92, 0, 0}}, /* 30 */ + {0, 11, {0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0}}, /* 31 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ + {0, 11, {0, 0, 24, 24, 24, 24, 24, 24, 0, 24, 24, 0, 0}}, /* 33 */ + {0, 11, {0, 0, 54, 54, 54, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ + {0, 11, {0, 0, 20, 20, 62, 62, 20, 62, 62, 20, 20, 0, 0}}, /* 35 */ + {0, 11, {0, 0, 24, 60, 90, 88, 60, 26, 90, 60, 24, 0, 0}}, /* 36 */ + {0, 11, {0, 0, 114, 86, 116, 12, 24, 48, 46, 106, 78, 0, 0}}, /* 37 */ + {0, 11, {0, 0, 56, 108, 108, 108, 56, 106, 110, 108, 58, 0, 0}}, /* 38 */ + {0, 11, {0, 0, 28, 28, 24, 48, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ + {0, 11, {0, 0, 12, 24, 24, 48, 48, 48, 24, 24, 12, 0, 0}}, /* 40 */ + {0, 11, {0, 0, 48, 24, 24, 12, 12, 12, 24, 24, 48, 0, 0}}, /* 41 */ + {0, 11, {0, 0, 0, 0, 36, 24, 126, 126, 24, 36, 0, 0, 0}}, /* 42 */ + {0, 11, {0, 0, 0, 0, 24, 24, 126, 126, 24, 24, 0, 0, 0}}, /* 43 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 28, 28, 24, 48, 0}}, /* 44 */ + {0, 11, {0, 0, 0, 0, 0, 0, 126, 126, 0, 0, 0, 0, 0}}, /* 45 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 60, 24, 0}}, /* 46 */ + {0, 11, {0, 0, 6, 6, 12, 12, 24, 48, 48, 96, 96, 0, 0}}, /* 47 */ + {0, 11, {0, 0, 24, 36, 102, 102, 102, 102, 102, 36, 24, 0, 0}}, /* 48 */ + {0, 11, {0, 0, 24, 56, 88, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 49 */ + {0, 11, {0, 0, 60, 102, 102, 6, 28, 48, 96, 96, 126, 0, 0}}, /* 50 */ + {0, 11, {0, 0, 126, 6, 12, 24, 60, 6, 6, 102, 60, 0, 0}}, /* 51 */ + {0, 11, {0, 0, 6, 14, 30, 54, 102, 102, 126, 6, 6, 0, 0}}, /* 52 */ + {0, 11, {0, 0, 126, 96, 96, 124, 102, 6, 6, 102, 60, 0, 0}}, /* 53 */ + {0, 11, {0, 0, 60, 102, 96, 96, 124, 102, 102, 102, 60, 0, 0}}, /* 54 */ + {0, 11, {0, 0, 126, 6, 6, 12, 12, 24, 24, 48, 48, 0, 0}}, /* 55 */ + {0, 11, {0, 0, 60, 102, 102, 102, 60, 102, 102, 102, 60, 0, 0}}, /* 56 */ + {0, 11, {0, 0, 60, 102, 102, 102, 62, 6, 6, 102, 60, 0, 0}}, /* 57 */ + {0, 11, {0, 0, 0, 0, 24, 60, 24, 0, 0, 24, 60, 24, 0}}, /* 58 */ + {0, 11, {0, 0, 0, 0, 24, 60, 24, 0, 28, 28, 24, 48, 0}}, /* 59 */ + {0, 11, {0, 0, 6, 12, 24, 48, 96, 48, 24, 12, 6, 0, 0}}, /* 60 */ + {0, 11, {0, 0, 0, 0, 126, 126, 0, 126, 126, 0, 0, 0, 0}}, /* 61 */ + {0, 11, {0, 0, 96, 48, 24, 12, 6, 12, 24, 48, 96, 0, 0}}, /* 62 */ + {0, 11, {0, 0, 60, 102, 102, 6, 28, 24, 0, 24, 24, 0, 0}}, /* 63 */ + {0, 11, {0, 0, 60, 70, 70, 94, 86, 94, 64, 70, 60, 0, 0}}, /* 64 */ + {0, 11, {0, 0, 60, 102, 102, 102, 126, 102, 102, 102, 102, 0, 0}}, /* 65 */ + {0, 11, {0, 0, 124, 102, 102, 102, 124, 102, 102, 102, 124, 0, 0}}, /* 66 */ + {0, 11, {0, 0, 60, 102, 96, 96, 96, 96, 96, 102, 60, 0, 0}}, /* 67 */ + {0, 11, {0, 0, 124, 102, 102, 102, 102, 102, 102, 102, 124, 0, 0}}, /* 68 */ + {0, 11, {0, 0, 126, 96, 96, 96, 124, 96, 96, 96, 126, 0, 0}}, /* 69 */ + {0, 11, {0, 0, 126, 96, 96, 96, 124, 96, 96, 96, 96, 0, 0}}, /* 70 */ + {0, 11, {0, 0, 60, 102, 96, 96, 110, 102, 102, 102, 62, 0, 0}}, /* 71 */ + {0, 11, {0, 0, 102, 102, 102, 102, 126, 102, 102, 102, 102, 0, 0}}, /* 72 */ + {0, 11, {0, 0, 126, 24, 24, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 73 */ + {0, 11, {0, 0, 6, 6, 6, 6, 6, 6, 6, 102, 60, 0, 0}}, /* 74 */ + {0, 11, {0, 0, 98, 102, 108, 120, 112, 120, 108, 102, 98, 0, 0}}, /* 75 */ + {0, 11, {0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 126, 0, 0}}, /* 76 */ + {0, 11, {0, 0, 66, 102, 126, 126, 102, 102, 102, 102, 102, 0, 0}}, /* 77 */ + {0, 11, {0, 0, 102, 102, 118, 118, 126, 110, 110, 102, 102, 0, 0}}, /* 78 */ + {0, 11, {0, 0, 60, 102, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 79 */ + {0, 11, {0, 0, 124, 102, 102, 102, 124, 96, 96, 96, 96, 0, 0}}, /* 80 */ + {0, 11, {0, 0, 60, 102, 102, 102, 102, 102, 118, 110, 60, 6, 0}}, /* 81 */ + {0, 11, {0, 0, 124, 102, 102, 102, 124, 120, 108, 102, 98, 0, 0}}, /* 82 */ + {0, 11, {0, 0, 60, 102, 96, 96, 60, 6, 6, 102, 60, 0, 0}}, /* 83 */ + {0, 11, {0, 0, 126, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0}}, /* 84 */ + {0, 11, {0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 85 */ + {0, 11, {0, 0, 102, 102, 102, 36, 36, 60, 24, 24, 24, 0, 0}}, /* 86 */ + {0, 11, {0, 0, 102, 102, 102, 102, 102, 126, 126, 102, 66, 0, 0}}, /* 87 */ + {0, 11, {0, 0, 66, 102, 36, 60, 24, 60, 36, 102, 66, 0, 0}}, /* 88 */ + {0, 11, {0, 0, 102, 102, 60, 60, 24, 24, 24, 24, 24, 0, 0}}, /* 89 */ + {0, 11, {0, 0, 126, 6, 6, 12, 24, 48, 96, 96, 126, 0, 0}}, /* 90 */ + {0, 11, {0, 0, 60, 48, 48, 48, 48, 48, 48, 48, 60, 0, 0}}, /* 91 */ + {0, 11, {0, 0, 96, 96, 48, 48, 24, 12, 12, 6, 6, 0, 0}}, /* 92 */ + {0, 11, {0, 0, 60, 12, 12, 12, 12, 12, 12, 12, 60, 0, 0}}, /* 93 */ + {0, 11, {0, 0, 24, 60, 102, 66, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 126, 0}}, /* 95 */ + {0, 11, {0, 0, 56, 56, 24, 12, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ + {0, 11, {0, 0, 0, 0, 0, 60, 6, 62, 102, 102, 62, 0, 0}}, /* 97 */ + {0, 11, {0, 0, 96, 96, 96, 124, 102, 102, 102, 102, 124, 0, 0}}, /* 98 */ + {0, 11, {0, 0, 0, 0, 0, 60, 102, 96, 96, 102, 60, 0, 0}}, /* 99 */ + {0, 11, {0, 0, 6, 6, 6, 62, 102, 102, 102, 102, 62, 0, 0}}, /* 100 */ + {0, 11, {0, 0, 0, 0, 0, 60, 102, 126, 96, 102, 60, 0, 0}}, /* 101 */ + {0, 11, {0, 0, 28, 54, 48, 48, 120, 48, 48, 48, 48, 0, 0}}, /* 102 */ + {0, 11, {0, 0, 0, 0, 0, 58, 102, 102, 60, 96, 60, 102, 60}}, /* 103 */ + {0, 11, {0, 0, 96, 96, 96, 124, 102, 102, 102, 102, 102, 0, 0}}, /* 104 */ + {0, 11, {0, 0, 24, 24, 0, 56, 24, 24, 24, 24, 126, 0, 0}}, /* 105 */ + {0, 11, {0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 102, 60}}, /* 106 */ + {0, 11, {0, 0, 96, 96, 96, 102, 108, 120, 120, 108, 102, 0, 0}}, /* 107 */ + {0, 11, {0, 0, 56, 24, 24, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 108 */ + {0, 11, {0, 0, 0, 0, 0, 108, 126, 126, 102, 102, 102, 0, 0}}, /* 109 */ + {0, 11, {0, 0, 0, 0, 0, 124, 102, 102, 102, 102, 102, 0, 0}}, /* 110 */ + {0, 11, {0, 0, 0, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 111 */ + {0, 11, {0, 0, 0, 0, 0, 124, 102, 102, 102, 124, 96, 96, 96}}, /* 112 */ + {0, 11, {0, 0, 0, 0, 0, 62, 102, 102, 102, 62, 6, 6, 6}}, /* 113 */ + {0, 11, {0, 0, 0, 0, 0, 124, 102, 96, 96, 96, 96, 0, 0}}, /* 114 */ + {0, 11, {0, 0, 0, 0, 0, 60, 102, 48, 12, 102, 60, 0, 0}}, /* 115 */ + {0, 11, {0, 0, 0, 48, 48, 124, 48, 48, 48, 54, 28, 0, 0}}, /* 116 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 62, 0, 0}}, /* 117 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 102, 60, 60, 24, 0, 0}}, /* 118 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 102, 126, 126, 36, 0, 0}}, /* 119 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 60, 60, 102, 102, 0, 0}}, /* 120 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 102, 102, 62, 6, 102, 60}}, /* 121 */ + {0, 11, {0, 0, 0, 0, 0, 126, 6, 12, 48, 96, 126, 0, 0}}, /* 122 */ + {0, 11, {0, 0, 28, 48, 48, 24, 48, 24, 48, 48, 28, 0, 0}}, /* 123 */ + {0, 11, {0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0}}, /* 124 */ + {0, 11, {0, 0, 56, 12, 12, 24, 12, 24, 12, 12, 56, 0, 0}}, /* 125 */ + {0, 11, {0, 0, 50, 126, 76, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 128 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 129 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 130 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 131 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 132 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 133 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 134 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 135 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 136 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 137 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 138 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 139 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 140 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 141 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 142 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 143 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 144 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 145 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 146 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 147 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 148 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 149 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 150 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 151 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 152 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 153 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 154 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 155 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 156 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 157 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 158 */ + {0, 11, {0, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 0}}, /* 159 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ + {0, 11, {0, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0}}, /* 161 */ + {0, 11, {0, 0, 8, 62, 106, 104, 104, 106, 62, 8, 0, 0, 0}}, /* 162 */ + {0, 11, {0, 0, 28, 54, 48, 48, 124, 48, 48, 54, 92, 0, 0}}, /* 163 */ + {0, 11, {0, 0, 0, 0, 102, 126, 36, 36, 126, 102, 0, 0, 0}}, /* 164 */ + {0, 11, {0, 0, 102, 102, 60, 60, 126, 24, 126, 24, 24, 0, 0}}, /* 165 */ + {0, 11, {0, 24, 24, 24, 24, 0, 0, 24, 24, 24, 24, 0, 0}}, /* 166 */ + {0, 11, {0, 60, 102, 96, 60, 102, 102, 60, 6, 102, 60, 0, 0}}, /* 167 */ + {0, 11, {0, 54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ + {0, 11, {0, 60, 102, 66, 90, 114, 114, 90, 66, 102, 60, 0, 0}}, /* 169 */ + {0, 11, {0, 0, 60, 6, 62, 38, 62, 0, 62, 0, 0, 0, 0}}, /* 170 */ + {0, 11, {0, 0, 0, 26, 52, 104, 80, 104, 52, 26, 0, 0, 0}}, /* 171 */ + {0, 11, {0, 0, 0, 0, 0, 126, 126, 2, 2, 0, 0, 0, 0}}, /* 172 */ + {0, 11, {0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0}}, /* 173 */ + {0, 11, {0, 60, 102, 66, 94, 86, 94, 90, 86, 102, 60, 0, 0}}, /* 174 */ + {0, 11, {0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ + {0, 11, {0, 0, 60, 102, 102, 60, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ + {0, 11, {0, 0, 24, 24, 126, 126, 24, 24, 0, 126, 126, 0, 0}}, /* 177 */ + {0, 11, {0, 112, 88, 24, 48, 96, 120, 0, 0, 0, 0, 0, 0}}, /* 178 */ + {0, 11, {0, 112, 88, 48, 24, 88, 112, 0, 0, 0, 0, 0, 0}}, /* 179 */ + {0, 11, {0, 12, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ + {0, 11, {0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 126, 64, 0}}, /* 181 */ + {0, 11, {0, 0, 62, 126, 122, 122, 122, 58, 26, 26, 26, 0, 0}}, /* 182 */ + {0, 11, {0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0}}, /* 183 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 48}}, /* 184 */ + {0, 11, {0, 48, 112, 48, 48, 48, 120, 0, 0, 0, 0, 0, 0}}, /* 185 */ + {0, 11, {0, 28, 62, 34, 62, 28, 0, 62, 0, 0, 0, 0, 0}}, /* 186 */ + {0, 11, {0, 0, 0, 88, 44, 22, 10, 22, 44, 88, 0, 0, 0}}, /* 187 */ + {0, 11, {0, 48, 112, 48, 48, 50, 126, 14, 26, 30, 6, 0, 0}}, /* 188 */ + {0, 11, {0, 48, 112, 48, 48, 60, 118, 6, 12, 24, 30, 0, 0}}, /* 189 */ + {0, 11, {0, 112, 88, 48, 24, 90, 118, 14, 26, 30, 6, 0, 0}}, /* 190 */ + {0, 11, {0, 24, 24, 0, 24, 24, 48, 96, 102, 102, 60, 0, 0}}, /* 191 */ + {0, 11, {0, 24, 12, 0, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 192 */ + {0, 11, {0, 12, 24, 0, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 193 */ + {0, 11, {0, 56, 108, 0, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 194 */ + {0, 11, {0, 52, 88, 0, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 195 */ + {0, 11, {0, 102, 102, 0, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 196 */ + {0, 11, {0, 60, 36, 60, 24, 60, 102, 102, 126, 102, 102, 0, 0}}, /* 197 */ + {0, 11, {0, 0, 62, 124, 108, 108, 110, 124, 108, 108, 110, 0, 0}}, /* 198 */ + {0, 11, {0, 0, 60, 102, 96, 96, 96, 96, 96, 102, 60, 24, 48}}, /* 199 */ + {0, 11, {0, 24, 12, 0, 126, 96, 96, 120, 96, 96, 126, 0, 0}}, /* 200 */ + {0, 11, {0, 12, 24, 0, 126, 96, 96, 120, 96, 96, 126, 0, 0}}, /* 201 */ + {0, 11, {0, 56, 108, 0, 126, 96, 96, 120, 96, 96, 126, 0, 0}}, /* 202 */ + {0, 11, {0, 102, 102, 0, 126, 96, 96, 120, 96, 96, 126, 0, 0}}, /* 203 */ + {0, 11, {0, 24, 12, 0, 126, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 204 */ + {0, 11, {0, 12, 24, 0, 126, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 205 */ + {0, 11, {0, 56, 108, 0, 126, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 206 */ + {0, 11, {0, 102, 102, 0, 126, 24, 24, 24, 24, 24, 126, 0, 0}}, /* 207 */ + {0, 11, {0, 0, 124, 54, 54, 54, 118, 54, 54, 54, 124, 0, 0}}, /* 208 */ + {0, 11, {0, 52, 88, 0, 102, 102, 118, 126, 110, 102, 102, 0, 0}}, /* 209 */ + {0, 11, {0, 24, 12, 0, 60, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 210 */ + {0, 11, {0, 12, 24, 0, 60, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 211 */ + {0, 11, {0, 56, 108, 0, 60, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 212 */ + {0, 11, {0, 52, 88, 0, 60, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 213 */ + {0, 11, {0, 102, 102, 0, 60, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 214 */ + {0, 11, {0, 0, 0, 0, 0, 102, 60, 24, 60, 102, 0, 0, 0}}, /* 215 */ + {0, 11, {0, 0, 2, 60, 110, 110, 110, 118, 118, 118, 60, 64, 0}}, /* 216 */ + {0, 11, {0, 24, 12, 0, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 217 */ + {0, 11, {0, 12, 24, 0, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 218 */ + {0, 11, {0, 56, 108, 0, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 219 */ + {0, 11, {0, 102, 102, 0, 102, 102, 102, 102, 102, 102, 60, 0, 0}}, /* 220 */ + {0, 11, {0, 12, 24, 0, 102, 36, 60, 24, 24, 24, 24, 0, 0}}, /* 221 */ + {0, 11, {0, 0, 96, 124, 102, 102, 102, 124, 96, 96, 96, 0, 0}}, /* 222 */ + {0, 11, {0, 0, 0, 60, 102, 102, 124, 102, 102, 102, 124, 64, 0}}, /* 223 */ + {0, 11, {0, 24, 12, 0, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 224 */ + {0, 11, {0, 12, 24, 0, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 225 */ + {0, 11, {0, 56, 108, 0, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 226 */ + {0, 11, {0, 52, 88, 0, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 227 */ + {0, 11, {0, 54, 54, 0, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 228 */ + {0, 11, {0, 28, 20, 28, 0, 60, 6, 62, 102, 110, 62, 0, 0}}, /* 229 */ + {0, 11, {0, 0, 0, 0, 0, 60, 26, 62, 88, 90, 52, 0, 0}}, /* 230 */ + {0, 11, {0, 0, 0, 0, 0, 60, 102, 96, 96, 102, 60, 24, 48}}, /* 231 */ + {0, 11, {0, 24, 12, 0, 0, 60, 102, 126, 96, 102, 60, 0, 0}}, /* 232 */ + {0, 11, {0, 12, 24, 0, 0, 60, 102, 126, 96, 102, 60, 0, 0}}, /* 233 */ + {0, 11, {0, 56, 108, 0, 0, 60, 102, 126, 96, 102, 60, 0, 0}}, /* 234 */ + {0, 11, {0, 54, 54, 0, 0, 60, 102, 126, 96, 102, 60, 0, 0}}, /* 235 */ + {0, 11, {0, 24, 12, 0, 0, 56, 24, 24, 24, 24, 60, 0, 0}}, /* 236 */ + {0, 11, {0, 12, 24, 0, 0, 56, 24, 24, 24, 24, 60, 0, 0}}, /* 237 */ + {0, 11, {0, 56, 108, 0, 0, 56, 24, 24, 24, 24, 60, 0, 0}}, /* 238 */ + {0, 11, {0, 54, 54, 0, 0, 56, 24, 24, 24, 24, 60, 0, 0}}, /* 239 */ + {0, 11, {0, 36, 24, 24, 40, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 240 */ + {0, 11, {0, 52, 88, 0, 0, 124, 118, 102, 102, 102, 102, 0, 0}}, /* 241 */ + {0, 11, {0, 24, 12, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 242 */ + {0, 11, {0, 12, 24, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 243 */ + {0, 11, {0, 56, 108, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 244 */ + {0, 11, {0, 52, 88, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 245 */ + {0, 11, {0, 54, 54, 0, 0, 60, 102, 102, 102, 102, 60, 0, 0}}, /* 246 */ + {0, 11, {0, 0, 0, 24, 24, 0, 126, 0, 24, 24, 0, 0, 0}}, /* 247 */ + {0, 11, {0, 0, 0, 2, 60, 102, 110, 102, 118, 102, 60, 64, 0}}, /* 248 */ + {0, 11, {0, 24, 12, 0, 0, 102, 102, 102, 102, 110, 62, 0, 0}}, /* 249 */ + {0, 11, {0, 12, 24, 0, 0, 102, 102, 102, 102, 110, 62, 0, 0}}, /* 250 */ + {0, 11, {0, 56, 108, 0, 0, 102, 102, 102, 102, 110, 62, 0, 0}}, /* 251 */ + {0, 11, {0, 54, 54, 0, 0, 102, 102, 102, 102, 110, 62, 0, 0}}, /* 252 */ + {0, 11, {0, 12, 24, 0, 0, 102, 102, 102, 110, 62, 6, 102, 60}}, /* 253 */ + {0, 11, {0, 0, 0, 96, 96, 124, 118, 102, 102, 118, 124, 96, 96}}, /* 254 */ + {0, 11, {0, 54, 54, 0, 0, 102, 102, 102, 110, 62, 6, 102, 60}} /* 255 */ }; diff --git a/src/text/font/font.c b/src/text/font/font.c index e1c5d89fb..039db2619 100644 --- a/src/text/font/font.c +++ b/src/text/font/font.c @@ -2,263 +2,263 @@ /** * Copyright notice: - * "Public domain font. Share and enjoy." + * "(null)" */ MwFont MwFontData[] = { - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0 */ - {0, 12, {0, 0, 12, 12, 30, 30, 63, 63, 30, 30, 12, 12, 0, 0}}, /* 1 */ - {0, 12, {42, 85, 42, 85, 42, 85, 42, 85, 42, 85, 42, 85, 42, 85}}, /* 2 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 3 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 4 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 5 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 6 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 8 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 9 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 10 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 120, 0, 0, 0, 0, 0, 0}}, /* 11 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 120, 8, 8, 8, 8, 8, 8}}, /* 12 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 15, 8, 8, 8, 8, 8, 8}}, /* 13 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 15, 0, 0, 0, 0, 0, 0}}, /* 14 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 127, 8, 8, 8, 8, 8, 8}}, /* 15 */ - {0, 12, {127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ - {0, 12, {0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0}}, /* 18 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0}}, /* 19 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127}}, /* 20 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8}}, /* 21 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8}}, /* 22 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 127, 0, 0, 0, 0, 0, 0}}, /* 23 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 127, 8, 8, 8, 8, 8, 8}}, /* 24 */ - {0, 12, {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, /* 25 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 26 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 27 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 28 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 29 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 30 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 31 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ - {0, 12, {0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0}}, /* 33 */ - {0, 12, {54, 18, 18, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ - {0, 12, {0, 0, 5, 5, 5, 63, 10, 10, 63, 20, 20, 20, 0, 0}}, /* 35 */ - {0, 12, {0, 0, 4, 30, 37, 37, 20, 14, 5, 37, 37, 30, 4, 0}}, /* 36 */ - {0, 12, {0, 0, 25, 37, 38, 28, 4, 8, 14, 25, 41, 38, 0, 0}}, /* 37 */ - {0, 12, {0, 0, 12, 18, 18, 18, 12, 25, 37, 34, 38, 25, 0, 0}}, /* 38 */ - {0, 12, {24, 8, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ - {0, 12, {0, 1, 2, 4, 4, 8, 8, 8, 8, 8, 4, 4, 2, 1}}, /* 40 */ - {0, 12, {0, 32, 16, 8, 8, 4, 4, 4, 4, 4, 8, 8, 16, 32}}, /* 41 */ - {0, 12, {0, 0, 0, 4, 21, 14, 4, 4, 14, 21, 4, 0, 0, 0}}, /* 42 */ - {0, 12, {0, 0, 0, 0, 8, 8, 8, 62, 8, 8, 8, 0, 0, 0}}, /* 43 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 8, 16}}, /* 44 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0}}, /* 45 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0}}, /* 46 */ - {0, 12, {0, 1, 1, 2, 2, 4, 4, 4, 8, 8, 16, 16, 32, 32}}, /* 47 */ - {0, 12, {0, 0, 12, 18, 33, 33, 33, 33, 33, 33, 18, 12, 0, 0}}, /* 48 */ - {0, 12, {0, 0, 4, 12, 20, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 49 */ - {0, 12, {0, 0, 30, 33, 33, 1, 2, 2, 4, 8, 16, 63, 0, 0}}, /* 50 */ - {0, 12, {0, 0, 30, 33, 33, 1, 14, 1, 1, 33, 33, 30, 0, 0}}, /* 51 */ - {0, 12, {0, 0, 2, 6, 10, 10, 18, 18, 34, 63, 2, 2, 0, 0}}, /* 52 */ - {0, 12, {0, 0, 63, 32, 32, 62, 33, 1, 1, 33, 33, 30, 0, 0}}, /* 53 */ - {0, 12, {0, 0, 14, 17, 33, 32, 46, 49, 33, 33, 33, 30, 0, 0}}, /* 54 */ - {0, 12, {0, 0, 63, 33, 34, 2, 4, 4, 4, 4, 4, 4, 0, 0}}, /* 55 */ - {0, 12, {0, 0, 30, 33, 33, 18, 12, 18, 33, 33, 33, 30, 0, 0}}, /* 56 */ - {0, 12, {0, 0, 30, 33, 33, 33, 35, 29, 1, 33, 34, 28, 0, 0}}, /* 57 */ - {0, 12, {0, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0}}, /* 58 */ - {0, 12, {0, 0, 0, 0, 8, 8, 0, 0, 0, 24, 8, 8, 16, 0}}, /* 59 */ - {0, 12, {0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}}, /* 60 */ - {0, 12, {0, 0, 0, 0, 0, 63, 0, 0, 63, 0, 0, 0, 0, 0}}, /* 61 */ - {0, 12, {0, 0, 0, 32, 16, 8, 4, 2, 4, 8, 16, 32, 0, 0}}, /* 62 */ - {0, 12, {0, 0, 30, 33, 33, 2, 4, 4, 4, 0, 4, 4, 0, 0}}, /* 63 */ - {0, 12, {0, 0, 14, 17, 39, 41, 41, 41, 41, 39, 16, 15, 0, 0}}, /* 64 */ - {0, 12, {0, 0, 8, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 65 */ - {0, 12, {0, 0, 62, 33, 33, 34, 62, 33, 33, 33, 33, 62, 0, 0}}, /* 66 */ - {0, 12, {0, 0, 30, 33, 33, 32, 32, 32, 32, 33, 33, 30, 0, 0}}, /* 67 */ - {0, 12, {0, 0, 60, 34, 33, 33, 33, 33, 33, 33, 34, 60, 0, 0}}, /* 68 */ - {0, 12, {0, 0, 63, 32, 32, 32, 62, 32, 32, 32, 32, 63, 0, 0}}, /* 69 */ - {0, 12, {0, 0, 63, 32, 32, 32, 62, 32, 32, 32, 32, 32, 0, 0}}, /* 70 */ - {0, 12, {0, 0, 30, 33, 33, 32, 32, 39, 33, 33, 33, 30, 0, 0}}, /* 71 */ - {0, 12, {0, 0, 33, 33, 33, 33, 63, 33, 33, 33, 33, 33, 0, 0}}, /* 72 */ - {0, 12, {0, 0, 31, 4, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 73 */ - {0, 12, {0, 0, 1, 1, 1, 1, 1, 1, 1, 33, 34, 28, 0, 0}}, /* 74 */ - {0, 12, {0, 0, 33, 34, 36, 40, 56, 36, 36, 34, 33, 33, 0, 0}}, /* 75 */ - {0, 12, {0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 63, 0, 0}}, /* 76 */ - {0, 12, {0, 0, 33, 35, 51, 53, 45, 41, 41, 33, 33, 33, 0, 0}}, /* 77 */ - {0, 12, {0, 0, 49, 49, 41, 41, 41, 37, 37, 37, 35, 35, 0, 0}}, /* 78 */ - {0, 12, {0, 0, 30, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 79 */ - {0, 12, {0, 0, 62, 33, 33, 33, 33, 62, 32, 32, 32, 32, 0, 0}}, /* 80 */ - {0, 12, {0, 0, 30, 33, 33, 33, 33, 33, 57, 37, 35, 30, 2, 1}}, /* 81 */ - {0, 12, {0, 0, 62, 33, 33, 33, 62, 34, 33, 33, 33, 33, 0, 0}}, /* 82 */ - {0, 12, {0, 0, 30, 33, 33, 16, 8, 4, 2, 33, 33, 30, 0, 0}}, /* 83 */ - {0, 12, {0, 0, 63, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 84 */ - {0, 12, {0, 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 85 */ - {0, 12, {0, 0, 33, 33, 33, 34, 18, 18, 20, 12, 8, 8, 0, 0}}, /* 86 */ - {0, 12, {0, 0, 37, 37, 37, 37, 37, 63, 18, 18, 18, 18, 0, 0}}, /* 87 */ - {0, 12, {0, 0, 33, 33, 18, 18, 12, 12, 18, 18, 33, 33, 0, 0}}, /* 88 */ - {0, 12, {0, 0, 33, 33, 34, 18, 20, 12, 8, 8, 8, 8, 0, 0}}, /* 89 */ - {0, 12, {0, 0, 63, 1, 2, 4, 4, 8, 16, 16, 32, 63, 0, 0}}, /* 90 */ - {0, 12, {0, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 15}}, /* 91 */ - {0, 12, {0, 32, 32, 16, 16, 8, 8, 8, 4, 4, 2, 2, 1, 1}}, /* 92 */ - {0, 12, {0, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 60}}, /* 93 */ - {0, 12, {12, 18, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63}}, /* 95 */ - {0, 12, {6, 4, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 97 */ - {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 49, 46, 0, 0}}, /* 98 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 32, 32, 32, 33, 30, 0, 0}}, /* 99 */ - {0, 12, {0, 0, 1, 1, 1, 29, 35, 33, 33, 33, 35, 29, 0, 0}}, /* 100 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 101 */ - {0, 12, {0, 0, 6, 9, 8, 8, 62, 8, 8, 8, 8, 8, 0, 0}}, /* 102 */ - {0, 12, {0, 0, 0, 0, 0, 29, 34, 34, 34, 28, 16, 46, 33, 30}}, /* 103 */ - {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 104 */ - {0, 12, {0, 0, 8, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 105 */ - {0, 12, {0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 34, 28}}, /* 106 */ - {0, 12, {0, 0, 32, 32, 32, 34, 36, 40, 56, 36, 34, 33, 0, 0}}, /* 107 */ - {0, 12, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 108 */ - {0, 12, {0, 0, 0, 0, 0, 62, 41, 41, 41, 41, 41, 41, 0, 0}}, /* 109 */ - {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 110 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 111 */ - {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 33, 33, 49, 46, 32, 32}}, /* 112 */ - {0, 12, {0, 0, 0, 0, 0, 29, 35, 33, 33, 33, 35, 29, 1, 1}}, /* 113 */ - {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 32, 32, 32, 32, 0, 0}}, /* 114 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 16, 12, 2, 33, 30, 0, 0}}, /* 115 */ - {0, 12, {0, 0, 8, 8, 8, 63, 8, 8, 8, 8, 8, 7, 0, 0}}, /* 116 */ - {0, 12, {0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 117 */ - {0, 12, {0, 0, 0, 0, 0, 33, 33, 17, 18, 10, 12, 4, 0, 0}}, /* 118 */ - {0, 12, {0, 0, 0, 0, 0, 37, 37, 37, 63, 18, 18, 18, 0, 0}}, /* 119 */ - {0, 12, {0, 0, 0, 0, 0, 33, 33, 18, 12, 18, 33, 33, 0, 0}}, /* 120 */ - {0, 12, {0, 0, 0, 0, 0, 33, 33, 17, 18, 10, 14, 4, 36, 24}}, /* 121 */ - {0, 12, {0, 0, 0, 0, 0, 63, 2, 4, 8, 8, 16, 63, 0, 0}}, /* 122 */ - {0, 12, {0, 3, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 3}}, /* 123 */ - {0, 12, {0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, /* 124 */ - {0, 12, {0, 48, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 48}}, /* 125 */ - {0, 12, {0, 16, 41, 37, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 128 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 129 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 130 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 131 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 132 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 133 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 134 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 135 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 136 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 137 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 138 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 139 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 140 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 141 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 142 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 143 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 144 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 145 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 146 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 147 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 148 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 149 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 150 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 151 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 152 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 153 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 154 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 155 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 156 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 157 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 158 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 159 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ - {0, 12, {0, 0, 8, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 161 */ - {0, 12, {0, 0, 0, 0, 8, 31, 41, 40, 40, 40, 41, 31, 8, 0}}, /* 162 */ - {0, 12, {0, 0, 0, 12, 18, 16, 16, 60, 16, 16, 60, 18, 0, 0}}, /* 163 */ - {0, 12, {0, 0, 0, 0, 33, 30, 18, 18, 30, 33, 0, 0, 0, 0}}, /* 164 */ - {0, 12, {0, 0, 33, 18, 12, 63, 4, 4, 63, 4, 4, 4, 0, 0}}, /* 165 */ - {0, 12, {0, 0, 8, 8, 8, 8, 0, 0, 8, 8, 8, 8, 0, 0}}, /* 166 */ - {0, 12, {0, 30, 33, 16, 12, 18, 33, 18, 12, 2, 33, 30, 0, 0}}, /* 167 */ - {0, 12, {0, 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ - {0, 12, {0, 30, 33, 45, 51, 49, 49, 49, 51, 45, 33, 30, 0, 0}}, /* 169 */ - {0, 12, {0, 14, 17, 15, 17, 19, 13, 0, 31, 0, 0, 0, 0, 0}}, /* 170 */ - {0, 12, {0, 0, 0, 0, 0, 5, 10, 20, 40, 20, 10, 5, 0, 0}}, /* 171 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 124, 4, 4, 4, 0, 0}}, /* 172 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0}}, /* 173 */ - {0, 12, {0, 30, 33, 61, 51, 51, 61, 51, 51, 51, 33, 30, 0, 0}}, /* 174 */ - {0, 12, {0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ - {0, 12, {0, 24, 36, 36, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ - {0, 12, {0, 0, 0, 0, 0, 0, 8, 8, 62, 8, 8, 62, 0, 0}}, /* 177 */ - {0, 12, {0, 24, 36, 4, 8, 16, 32, 60, 0, 0, 0, 0, 0, 0}}, /* 178 */ - {0, 12, {0, 24, 36, 4, 24, 4, 36, 24, 0, 0, 0, 0, 0, 0}}, /* 179 */ - {0, 12, {0, 4, 8, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ - {0, 12, {0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 54, 42, 32, 32}}, /* 181 */ - {0, 12, {0, 0, 30, 42, 42, 42, 42, 26, 10, 10, 10, 10, 10, 14}}, /* 182 */ - {0, 12, {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0}}, /* 183 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 16}}, /* 184 */ - {0, 12, {0, 0, 16, 48, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0}}, /* 185 */ - {0, 12, {0, 0, 12, 18, 18, 12, 0, 30, 0, 0, 0, 0, 0, 0}}, /* 186 */ - {0, 12, {0, 0, 0, 0, 0, 40, 20, 10, 5, 10, 20, 40, 0, 0}}, /* 187 */ - {0, 12, {0, 0, 16, 49, 18, 18, 20, 9, 11, 21, 39, 33, 0, 0}}, /* 188 */ - {0, 12, {0, 0, 16, 49, 18, 18, 20, 10, 13, 17, 34, 39, 0, 0}}, /* 189 */ - {0, 12, {0, 0, 49, 9, 18, 12, 52, 9, 19, 21, 39, 1, 0, 0}}, /* 190 */ - {0, 12, {0, 0, 0, 4, 4, 0, 4, 4, 4, 4, 2, 33, 33, 30}}, /* 191 */ - {0, 12, {16, 12, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 192 */ - {0, 12, {2, 12, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 193 */ - {0, 12, {12, 18, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 194 */ - {0, 12, {10, 20, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 195 */ - {0, 12, {0, 18, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 196 */ - {0, 12, {8, 0, 8, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 197 */ - {0, 12, {0, 0, 31, 40, 40, 40, 78, 120, 72, 72, 72, 79, 0, 0}}, /* 198 */ - {0, 12, {0, 0, 30, 33, 33, 32, 32, 32, 32, 33, 33, 30, 4, 8}}, /* 199 */ - {0, 12, {16, 12, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 200 */ - {0, 12, {2, 12, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 201 */ - {0, 12, {12, 18, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 202 */ - {0, 12, {0, 18, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 203 */ - {0, 12, {8, 6, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 204 */ - {0, 12, {2, 12, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 205 */ - {0, 12, {4, 10, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 206 */ - {0, 12, {0, 10, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 207 */ - {0, 12, {0, 0, 60, 34, 33, 33, 113, 33, 33, 33, 34, 60, 0, 0}}, /* 208 */ - {0, 12, {10, 20, 0, 49, 41, 41, 41, 37, 37, 37, 35, 35, 0, 0}}, /* 209 */ - {0, 12, {16, 12, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 210 */ - {0, 12, {2, 12, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 211 */ - {0, 12, {12, 18, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 212 */ - {0, 12, {10, 20, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 213 */ - {0, 12, {0, 18, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 214 */ - {0, 12, {0, 0, 0, 0, 0, 65, 34, 20, 8, 20, 34, 65, 0, 0}}, /* 215 */ - {0, 12, {1, 1, 30, 35, 37, 37, 37, 41, 41, 41, 49, 30, 32, 32}}, /* 216 */ - {0, 12, {16, 12, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 217 */ - {0, 12, {2, 12, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 218 */ - {0, 12, {12, 18, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 219 */ - {0, 12, {0, 18, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 220 */ - {0, 12, {2, 12, 33, 33, 34, 18, 20, 12, 8, 8, 8, 8, 0, 0}}, /* 221 */ - {0, 12, {0, 0, 32, 32, 62, 33, 33, 33, 33, 62, 32, 32, 0, 0}}, /* 222 */ - {0, 12, {0, 0, 12, 18, 18, 18, 28, 18, 17, 17, 17, 62, 0, 0}}, /* 223 */ - {0, 12, {0, 16, 8, 4, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 224 */ - {0, 12, {0, 2, 4, 8, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 225 */ - {0, 12, {0, 0, 12, 18, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 226 */ - {0, 12, {0, 0, 10, 20, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 227 */ - {0, 12, {0, 0, 0, 18, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 228 */ - {0, 12, {0, 8, 20, 8, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 229 */ - {0, 12, {0, 0, 0, 0, 0, 62, 73, 25, 47, 72, 73, 62, 0, 0}}, /* 230 */ - {0, 12, {0, 0, 0, 0, 0, 30, 33, 32, 32, 32, 33, 30, 4, 8}}, /* 231 */ - {0, 12, {0, 16, 8, 4, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 232 */ - {0, 12, {0, 2, 4, 8, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 233 */ - {0, 12, {0, 0, 12, 18, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 234 */ - {0, 12, {0, 0, 0, 18, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 235 */ - {0, 12, {0, 16, 8, 4, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 236 */ - {0, 12, {0, 4, 8, 16, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 237 */ - {0, 12, {0, 0, 8, 20, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 238 */ - {0, 12, {0, 0, 0, 20, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 239 */ - {0, 12, {0, 20, 8, 20, 2, 30, 34, 34, 34, 34, 34, 28, 0, 0}}, /* 240 */ - {0, 12, {0, 0, 10, 20, 0, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 241 */ - {0, 12, {0, 16, 8, 4, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 242 */ - {0, 12, {0, 2, 4, 8, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 243 */ - {0, 12, {0, 0, 12, 18, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 244 */ - {0, 12, {0, 0, 10, 20, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 245 */ - {0, 12, {0, 0, 0, 18, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 246 */ - {0, 12, {0, 0, 0, 0, 0, 0, 0, 24, 0, 126, 0, 24, 0, 0}}, /* 247 */ - {0, 12, {0, 0, 0, 1, 2, 30, 37, 37, 41, 41, 49, 30, 32, 32}}, /* 248 */ - {0, 12, {0, 0, 16, 8, 4, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 249 */ - {0, 12, {0, 0, 2, 4, 8, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 250 */ - {0, 12, {0, 0, 12, 18, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 251 */ - {0, 12, {0, 0, 0, 18, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 252 */ - {0, 12, {0, 0, 2, 4, 8, 33, 33, 17, 18, 10, 14, 4, 36, 24}}, /* 253 */ - {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 49, 46, 32, 32}}, /* 254 */ - {0, 12, {0, 0, 0, 18, 0, 33, 33, 17, 18, 10, 14, 4, 36, 24}} /* 255 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 0 */ + {0, 11, {0, 0, 0, 0, 0, 16, 56, 124, 56, 16, 0, 0, 0}}, /* 1 */ + {0, 11, {0, 84, 42, 84, 42, 84, 42, 84, 42, 84, 42, 84, 42}}, /* 2 */ + {0, 11, {0, 0, 72, 72, 120, 72, 72, 14, 4, 4, 4, 4, 0}}, /* 3 */ + {0, 11, {0, 0, 120, 64, 112, 64, 64, 30, 16, 28, 16, 16, 0}}, /* 4 */ + {0, 11, {0, 0, 56, 64, 64, 64, 56, 28, 18, 28, 20, 18, 0}}, /* 5 */ + {0, 11, {0, 0, 64, 64, 64, 64, 120, 30, 16, 28, 16, 16, 0}}, /* 6 */ + {0, 11, {0, 0, 56, 68, 68, 56, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ + {0, 11, {0, 0, 0, 16, 16, 124, 16, 16, 0, 124, 0, 0, 0}}, /* 8 */ + {0, 11, {0, 0, 72, 104, 88, 72, 72, 16, 16, 16, 16, 30, 0}}, /* 9 */ + {0, 11, {0, 0, 68, 68, 40, 40, 16, 62, 8, 8, 8, 8, 0}}, /* 10 */ + {0, 11, {8, 8, 8, 8, 8, 8, 120, 0, 0, 0, 0, 0, 0}}, /* 11 */ + {0, 11, {0, 0, 0, 0, 0, 0, 120, 8, 8, 8, 8, 8, 8}}, /* 12 */ + {0, 11, {0, 0, 0, 0, 0, 0, 15, 8, 8, 8, 8, 8, 8}}, /* 13 */ + {0, 11, {8, 8, 8, 8, 8, 8, 15, 0, 0, 0, 0, 0, 0}}, /* 14 */ + {0, 11, {8, 8, 8, 8, 8, 8, 127, 8, 8, 8, 8, 8, 8}}, /* 15 */ + {0, 11, {0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ + {0, 11, {0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ + {0, 11, {0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0}}, /* 18 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0}}, /* 19 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0}}, /* 20 */ + {0, 11, {8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8}}, /* 21 */ + {0, 11, {8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8}}, /* 22 */ + {0, 11, {8, 8, 8, 8, 8, 8, 127, 0, 0, 0, 0, 0, 0}}, /* 23 */ + {0, 11, {0, 0, 0, 0, 0, 0, 127, 8, 8, 8, 8, 8, 8}}, /* 24 */ + {0, 11, {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, /* 25 */ + {0, 11, {0, 0, 0, 2, 12, 48, 64, 48, 12, 2, 126, 0, 0}}, /* 26 */ + {0, 11, {0, 0, 0, 64, 48, 12, 2, 12, 48, 64, 126, 0, 0}}, /* 27 */ + {0, 11, {0, 0, 0, 0, 0, 126, 36, 36, 36, 36, 68, 0, 0}}, /* 28 */ + {0, 11, {0, 0, 0, 2, 4, 126, 8, 16, 126, 32, 64, 0, 0}}, /* 29 */ + {0, 11, {0, 0, 28, 34, 32, 32, 112, 32, 32, 34, 92, 0, 0}}, /* 30 */ + {0, 11, {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0}}, /* 31 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ + {0, 11, {0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 8, 0, 0}}, /* 33 */ + {0, 11, {0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ + {0, 11, {0, 0, 0, 20, 20, 62, 20, 62, 20, 20, 0, 0, 0}}, /* 35 */ + {0, 11, {0, 0, 0, 8, 30, 40, 28, 10, 60, 8, 0, 0, 0}}, /* 36 */ + {0, 11, {0, 0, 34, 82, 36, 8, 8, 16, 36, 74, 68, 0, 0}}, /* 37 */ + {0, 11, {0, 0, 0, 0, 48, 72, 72, 48, 74, 68, 58, 0, 0}}, /* 38 */ + {0, 11, {0, 0, 28, 24, 32, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ + {0, 11, {0, 0, 4, 8, 8, 16, 16, 16, 8, 8, 4, 0, 0}}, /* 40 */ + {0, 11, {0, 0, 16, 8, 8, 4, 4, 4, 8, 8, 16, 0, 0}}, /* 41 */ + {0, 11, {0, 0, 0, 0, 36, 24, 126, 24, 36, 0, 0, 0, 0}}, /* 42 */ + {0, 11, {0, 0, 0, 0, 8, 8, 62, 8, 8, 0, 0, 0, 0}}, /* 43 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 24, 32, 0}}, /* 44 */ + {0, 11, {0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 0}}, /* 45 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 28, 8, 0}}, /* 46 */ + {0, 11, {0, 0, 2, 2, 4, 4, 8, 16, 16, 32, 32, 0, 0}}, /* 47 */ + {0, 11, {0, 0, 24, 36, 66, 66, 66, 66, 66, 36, 24, 0, 0}}, /* 48 */ + {0, 11, {0, 0, 8, 24, 40, 8, 8, 8, 8, 8, 62, 0, 0}}, /* 49 */ + {0, 11, {0, 0, 60, 66, 66, 2, 4, 24, 32, 64, 126, 0, 0}}, /* 50 */ + {0, 11, {0, 0, 126, 2, 4, 8, 28, 2, 2, 66, 60, 0, 0}}, /* 51 */ + {0, 11, {0, 0, 4, 12, 20, 36, 68, 68, 126, 4, 4, 0, 0}}, /* 52 */ + {0, 11, {0, 0, 126, 64, 64, 92, 98, 2, 2, 66, 60, 0, 0}}, /* 53 */ + {0, 11, {0, 0, 28, 32, 64, 64, 92, 98, 66, 66, 60, 0, 0}}, /* 54 */ + {0, 11, {0, 0, 126, 2, 4, 8, 8, 16, 16, 32, 32, 0, 0}}, /* 55 */ + {0, 11, {0, 0, 60, 66, 66, 66, 60, 66, 66, 66, 60, 0, 0}}, /* 56 */ + {0, 11, {0, 0, 60, 66, 66, 70, 58, 2, 2, 4, 56, 0, 0}}, /* 57 */ + {0, 11, {0, 0, 0, 0, 8, 28, 8, 0, 0, 8, 28, 8, 0}}, /* 58 */ + {0, 11, {0, 0, 0, 0, 8, 28, 8, 0, 0, 28, 24, 32, 0}}, /* 59 */ + {0, 11, {0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}}, /* 60 */ + {0, 11, {0, 0, 0, 0, 0, 126, 0, 0, 126, 0, 0, 0, 0}}, /* 61 */ + {0, 11, {0, 0, 32, 16, 8, 4, 2, 4, 8, 16, 32, 0, 0}}, /* 62 */ + {0, 11, {0, 0, 60, 66, 66, 2, 4, 8, 8, 0, 8, 0, 0}}, /* 63 */ + {0, 11, {0, 0, 60, 66, 66, 78, 82, 86, 74, 64, 60, 0, 0}}, /* 64 */ + {0, 11, {0, 0, 24, 36, 66, 66, 66, 126, 66, 66, 66, 0, 0}}, /* 65 */ + {0, 11, {0, 0, 124, 34, 34, 34, 60, 34, 34, 34, 124, 0, 0}}, /* 66 */ + {0, 11, {0, 0, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}}, /* 67 */ + {0, 11, {0, 0, 124, 34, 34, 34, 34, 34, 34, 34, 124, 0, 0}}, /* 68 */ + {0, 11, {0, 0, 126, 64, 64, 64, 120, 64, 64, 64, 126, 0, 0}}, /* 69 */ + {0, 11, {0, 0, 126, 64, 64, 64, 120, 64, 64, 64, 64, 0, 0}}, /* 70 */ + {0, 11, {0, 0, 60, 66, 64, 64, 64, 78, 66, 70, 58, 0, 0}}, /* 71 */ + {0, 11, {0, 0, 66, 66, 66, 66, 126, 66, 66, 66, 66, 0, 0}}, /* 72 */ + {0, 11, {0, 0, 124, 16, 16, 16, 16, 16, 16, 16, 124, 0, 0}}, /* 73 */ + {0, 11, {0, 0, 14, 4, 4, 4, 4, 4, 4, 68, 56, 0, 0}}, /* 74 */ + {0, 11, {0, 0, 66, 68, 72, 80, 96, 80, 72, 68, 66, 0, 0}}, /* 75 */ + {0, 11, {0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 126, 0, 0}}, /* 76 */ + {0, 11, {0, 0, 66, 102, 102, 90, 90, 66, 66, 66, 66, 0, 0}}, /* 77 */ + {0, 11, {0, 0, 66, 66, 98, 82, 74, 70, 66, 66, 66, 0, 0}}, /* 78 */ + {0, 11, {0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 79 */ + {0, 11, {0, 0, 124, 66, 66, 66, 124, 64, 64, 64, 64, 0, 0}}, /* 80 */ + {0, 11, {0, 0, 60, 66, 66, 66, 66, 66, 82, 74, 60, 2, 0}}, /* 81 */ + {0, 11, {0, 0, 124, 66, 66, 66, 124, 80, 72, 68, 66, 0, 0}}, /* 82 */ + {0, 11, {0, 0, 60, 66, 64, 64, 60, 2, 2, 66, 60, 0, 0}}, /* 83 */ + {0, 11, {0, 0, 124, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0}}, /* 84 */ + {0, 11, {0, 0, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 85 */ + {0, 11, {0, 0, 66, 66, 66, 36, 36, 36, 24, 24, 24, 0, 0}}, /* 86 */ + {0, 11, {0, 0, 66, 66, 66, 66, 90, 90, 102, 102, 66, 0, 0}}, /* 87 */ + {0, 11, {0, 0, 66, 66, 36, 36, 24, 36, 36, 66, 66, 0, 0}}, /* 88 */ + {0, 11, {0, 0, 68, 68, 40, 40, 16, 16, 16, 16, 16, 0, 0}}, /* 89 */ + {0, 11, {0, 0, 126, 2, 4, 8, 24, 16, 32, 64, 126, 0, 0}}, /* 90 */ + {0, 11, {0, 0, 60, 32, 32, 32, 32, 32, 32, 32, 60, 0, 0}}, /* 91 */ + {0, 11, {0, 0, 32, 32, 16, 16, 8, 4, 4, 2, 2, 0, 0}}, /* 92 */ + {0, 11, {0, 0, 60, 4, 4, 4, 4, 4, 4, 4, 60, 0, 0}}, /* 93 */ + {0, 11, {0, 0, 8, 20, 34, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0}}, /* 95 */ + {0, 11, {0, 0, 56, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ + {0, 11, {0, 0, 0, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 97 */ + {0, 11, {0, 0, 64, 64, 64, 92, 98, 66, 66, 98, 92, 0, 0}}, /* 98 */ + {0, 11, {0, 0, 0, 0, 0, 60, 66, 64, 64, 66, 60, 0, 0}}, /* 99 */ + {0, 11, {0, 0, 2, 2, 2, 58, 70, 66, 66, 70, 58, 0, 0}}, /* 100 */ + {0, 11, {0, 0, 0, 0, 0, 60, 66, 126, 64, 66, 60, 0, 0}}, /* 101 */ + {0, 11, {0, 0, 28, 34, 32, 32, 120, 32, 32, 32, 32, 0, 0}}, /* 102 */ + {0, 11, {0, 0, 0, 0, 0, 58, 68, 68, 56, 64, 60, 66, 60}}, /* 103 */ + {0, 11, {0, 0, 64, 64, 64, 92, 98, 66, 66, 66, 66, 0, 0}}, /* 104 */ + {0, 11, {0, 0, 0, 16, 0, 48, 16, 16, 16, 16, 124, 0, 0}}, /* 105 */ + {0, 11, {0, 0, 0, 4, 0, 12, 4, 4, 4, 4, 68, 68, 56}}, /* 106 */ + {0, 11, {0, 0, 64, 64, 64, 68, 72, 112, 72, 68, 66, 0, 0}}, /* 107 */ + {0, 11, {0, 0, 48, 16, 16, 16, 16, 16, 16, 16, 124, 0, 0}}, /* 108 */ + {0, 11, {0, 0, 0, 0, 0, 104, 84, 84, 84, 84, 68, 0, 0}}, /* 109 */ + {0, 11, {0, 0, 0, 0, 0, 92, 98, 66, 66, 66, 66, 0, 0}}, /* 110 */ + {0, 11, {0, 0, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 111 */ + {0, 11, {0, 0, 0, 0, 0, 92, 98, 66, 98, 92, 64, 64, 64}}, /* 112 */ + {0, 11, {0, 0, 0, 0, 0, 58, 70, 66, 70, 58, 2, 2, 2}}, /* 113 */ + {0, 11, {0, 0, 0, 0, 0, 92, 34, 32, 32, 32, 32, 0, 0}}, /* 114 */ + {0, 11, {0, 0, 0, 0, 0, 60, 66, 48, 12, 66, 60, 0, 0}}, /* 115 */ + {0, 11, {0, 0, 0, 32, 32, 120, 32, 32, 32, 34, 28, 0, 0}}, /* 116 */ + {0, 11, {0, 0, 0, 0, 0, 66, 66, 66, 66, 70, 58, 0, 0}}, /* 117 */ + {0, 11, {0, 0, 0, 0, 0, 68, 68, 68, 40, 40, 16, 0, 0}}, /* 118 */ + {0, 11, {0, 0, 0, 0, 0, 68, 68, 84, 84, 84, 40, 0, 0}}, /* 119 */ + {0, 11, {0, 0, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0}}, /* 120 */ + {0, 11, {0, 0, 0, 0, 0, 66, 66, 66, 70, 58, 2, 66, 60}}, /* 121 */ + {0, 11, {0, 0, 0, 0, 0, 126, 4, 8, 16, 32, 126, 0, 0}}, /* 122 */ + {0, 11, {0, 0, 14, 16, 16, 8, 48, 8, 16, 16, 14, 0, 0}}, /* 123 */ + {0, 11, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 124 */ + {0, 11, {0, 0, 56, 4, 4, 8, 6, 8, 4, 4, 56, 0, 0}}, /* 125 */ + {0, 11, {0, 0, 18, 42, 36, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 128 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 129 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 130 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 131 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 132 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 133 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 134 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 135 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 136 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 137 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 138 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 139 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 140 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 141 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 142 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 143 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 144 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 145 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 146 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 147 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 148 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 149 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 150 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 151 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 152 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 153 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 154 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 155 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 156 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 157 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 158 */ + {0, 11, {0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 0}}, /* 159 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ + {0, 11, {0, 0, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 161 */ + {0, 11, {0, 0, 8, 28, 42, 40, 40, 42, 28, 8, 0, 0, 0}}, /* 162 */ + {0, 11, {0, 0, 28, 34, 32, 32, 112, 32, 32, 34, 92, 0, 0}}, /* 163 */ + {0, 11, {0, 0, 0, 0, 66, 60, 36, 36, 60, 66, 0, 0, 0}}, /* 164 */ + {0, 11, {0, 0, 68, 68, 40, 40, 124, 16, 124, 16, 16, 0, 0}}, /* 165 */ + {0, 11, {0, 0, 8, 8, 8, 8, 0, 8, 8, 8, 8, 0, 0}}, /* 166 */ + {0, 11, {0, 24, 36, 32, 24, 36, 36, 24, 4, 36, 24, 0, 0}}, /* 167 */ + {0, 11, {0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ + {0, 11, {0, 60, 66, 90, 82, 82, 82, 90, 66, 60, 0, 0, 0}}, /* 169 */ + {0, 11, {0, 0, 28, 2, 30, 34, 30, 0, 62, 0, 0, 0, 0}}, /* 170 */ + {0, 11, {0, 0, 0, 10, 20, 40, 80, 40, 20, 10, 0, 0, 0}}, /* 171 */ + {0, 11, {0, 0, 0, 0, 0, 0, 62, 2, 2, 0, 0, 0, 0}}, /* 172 */ + {0, 11, {0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0}}, /* 173 */ + {0, 11, {0, 60, 66, 90, 86, 86, 90, 86, 66, 60, 0, 0, 0}}, /* 174 */ + {0, 11, {0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ + {0, 11, {0, 0, 24, 36, 36, 24, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ + {0, 11, {0, 0, 0, 8, 8, 62, 8, 8, 0, 62, 0, 0, 0}}, /* 177 */ + {0, 11, {0, 32, 80, 16, 32, 64, 112, 0, 0, 0, 0, 0, 0}}, /* 178 */ + {0, 11, {0, 112, 16, 32, 16, 80, 32, 0, 0, 0, 0, 0, 0}}, /* 179 */ + {0, 11, {0, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ + {0, 11, {0, 0, 0, 0, 0, 66, 66, 66, 66, 102, 90, 64, 0}}, /* 181 */ + {0, 11, {0, 0, 62, 116, 116, 116, 52, 20, 20, 20, 20, 0, 0}}, /* 182 */ + {0, 11, {0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}}, /* 183 */ + {0, 11, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16}}, /* 184 */ + {0, 11, {0, 32, 96, 32, 32, 32, 112, 0, 0, 0, 0, 0, 0}}, /* 185 */ + {0, 11, {0, 0, 24, 36, 36, 24, 0, 60, 0, 0, 0, 0, 0}}, /* 186 */ + {0, 11, {0, 0, 0, 80, 40, 20, 10, 20, 40, 80, 0, 0, 0}}, /* 187 */ + {0, 11, {0, 32, 96, 32, 32, 34, 118, 10, 10, 14, 2, 0, 0}}, /* 188 */ + {0, 11, {0, 32, 96, 32, 32, 36, 122, 2, 4, 8, 14, 0, 0}}, /* 189 */ + {0, 11, {0, 112, 16, 32, 16, 82, 38, 10, 10, 14, 2, 0, 0}}, /* 190 */ + {0, 11, {0, 0, 16, 0, 16, 16, 32, 64, 66, 66, 60, 0, 0}}, /* 191 */ + {0, 11, {0, 16, 8, 0, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 192 */ + {0, 11, {0, 8, 16, 0, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 193 */ + {0, 11, {0, 24, 36, 0, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 194 */ + {0, 11, {0, 20, 40, 0, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 195 */ + {0, 11, {0, 36, 36, 0, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 196 */ + {0, 11, {0, 24, 36, 24, 24, 36, 66, 66, 126, 66, 66, 0, 0}}, /* 197 */ + {0, 11, {0, 0, 46, 80, 80, 80, 92, 112, 80, 80, 94, 0, 0}}, /* 198 */ + {0, 11, {0, 0, 60, 66, 64, 64, 64, 64, 64, 66, 60, 8, 16}}, /* 199 */ + {0, 11, {0, 16, 8, 0, 126, 64, 64, 120, 64, 64, 126, 0, 0}}, /* 200 */ + {0, 11, {0, 8, 16, 0, 126, 64, 64, 120, 64, 64, 126, 0, 0}}, /* 201 */ + {0, 11, {0, 24, 36, 0, 126, 64, 64, 120, 64, 64, 126, 0, 0}}, /* 202 */ + {0, 11, {0, 36, 36, 0, 126, 64, 64, 120, 64, 64, 126, 0, 0}}, /* 203 */ + {0, 11, {0, 16, 8, 0, 62, 8, 8, 8, 8, 8, 62, 0, 0}}, /* 204 */ + {0, 11, {0, 8, 16, 0, 62, 8, 8, 8, 8, 8, 62, 0, 0}}, /* 205 */ + {0, 11, {0, 24, 36, 0, 62, 8, 8, 8, 8, 8, 62, 0, 0}}, /* 206 */ + {0, 11, {0, 20, 20, 0, 62, 8, 8, 8, 8, 8, 62, 0, 0}}, /* 207 */ + {0, 11, {0, 0, 124, 34, 34, 34, 114, 34, 34, 34, 124, 0, 0}}, /* 208 */ + {0, 11, {0, 20, 40, 0, 66, 98, 82, 82, 74, 70, 66, 0, 0}}, /* 209 */ + {0, 11, {0, 16, 8, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 210 */ + {0, 11, {0, 8, 16, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 211 */ + {0, 11, {0, 24, 36, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 212 */ + {0, 11, {0, 20, 40, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 213 */ + {0, 11, {0, 36, 36, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 214 */ + {0, 11, {0, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0}}, /* 215 */ + {0, 11, {0, 2, 60, 70, 74, 74, 82, 82, 82, 98, 60, 64, 0}}, /* 216 */ + {0, 11, {0, 16, 8, 0, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 217 */ + {0, 11, {0, 8, 16, 0, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 218 */ + {0, 11, {0, 24, 36, 0, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 219 */ + {0, 11, {0, 36, 36, 0, 66, 66, 66, 66, 66, 66, 60, 0, 0}}, /* 220 */ + {0, 11, {0, 8, 16, 0, 34, 34, 20, 8, 8, 8, 8, 0, 0}}, /* 221 */ + {0, 11, {0, 0, 64, 124, 66, 66, 66, 124, 64, 64, 64, 0, 0}}, /* 222 */ + {0, 11, {0, 0, 0, 60, 66, 66, 124, 66, 66, 98, 92, 64, 0}}, /* 223 */ + {0, 11, {0, 16, 8, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 224 */ + {0, 11, {0, 8, 16, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 225 */ + {0, 11, {0, 24, 36, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 226 */ + {0, 11, {0, 20, 40, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 227 */ + {0, 11, {0, 36, 36, 0, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 228 */ + {0, 11, {0, 24, 36, 24, 0, 60, 2, 62, 66, 70, 58, 0, 0}}, /* 229 */ + {0, 11, {0, 0, 0, 0, 0, 52, 10, 62, 72, 74, 52, 0, 0}}, /* 230 */ + {0, 11, {0, 0, 0, 0, 0, 60, 66, 64, 64, 66, 60, 8, 16}}, /* 231 */ + {0, 11, {0, 16, 8, 0, 0, 60, 66, 126, 64, 66, 60, 0, 0}}, /* 232 */ + {0, 11, {0, 8, 16, 0, 0, 60, 66, 126, 64, 66, 60, 0, 0}}, /* 233 */ + {0, 11, {0, 24, 36, 0, 0, 60, 66, 126, 64, 66, 60, 0, 0}}, /* 234 */ + {0, 11, {0, 36, 36, 0, 0, 60, 66, 126, 64, 66, 60, 0, 0}}, /* 235 */ + {0, 11, {0, 16, 8, 0, 0, 24, 8, 8, 8, 8, 62, 0, 0}}, /* 236 */ + {0, 11, {0, 8, 16, 0, 0, 24, 8, 8, 8, 8, 62, 0, 0}}, /* 237 */ + {0, 11, {0, 24, 36, 0, 0, 24, 8, 8, 8, 8, 62, 0, 0}}, /* 238 */ + {0, 11, {0, 36, 36, 0, 0, 24, 8, 8, 8, 8, 62, 0, 0}}, /* 239 */ + {0, 11, {0, 36, 24, 40, 4, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 240 */ + {0, 11, {0, 20, 40, 0, 0, 92, 98, 66, 66, 66, 66, 0, 0}}, /* 241 */ + {0, 11, {0, 16, 8, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 242 */ + {0, 11, {0, 8, 16, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 243 */ + {0, 11, {0, 24, 36, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 244 */ + {0, 11, {0, 20, 40, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 245 */ + {0, 11, {0, 36, 36, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0}}, /* 246 */ + {0, 11, {0, 0, 0, 8, 8, 0, 62, 0, 8, 8, 0, 0, 0}}, /* 247 */ + {0, 11, {0, 0, 0, 0, 2, 60, 70, 74, 82, 98, 60, 64, 0}}, /* 248 */ + {0, 11, {0, 16, 8, 0, 0, 66, 66, 66, 66, 70, 58, 0, 0}}, /* 249 */ + {0, 11, {0, 8, 16, 0, 0, 66, 66, 66, 66, 70, 58, 0, 0}}, /* 250 */ + {0, 11, {0, 24, 36, 0, 0, 66, 66, 66, 66, 70, 58, 0, 0}}, /* 251 */ + {0, 11, {0, 36, 36, 0, 0, 66, 66, 66, 66, 70, 58, 0, 0}}, /* 252 */ + {0, 11, {0, 8, 16, 0, 0, 66, 66, 66, 70, 58, 2, 66, 60}}, /* 253 */ + {0, 11, {0, 0, 0, 64, 64, 92, 98, 66, 66, 98, 92, 64, 64}}, /* 254 */ + {0, 11, {0, 36, 36, 0, 0, 66, 66, 66, 70, 58, 2, 66, 60}} /* 255 */ }; diff --git a/src/text/text.c b/src/text/text.c index 2bb89b646..45e588602 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -12,7 +12,7 @@ void (*MwFLFontFree)(void* handle) = NULL; #endif #define FontWidth 7 -#define FontHeight 14 +#define FontHeight 13 static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, MwLLColor color); @@ -240,7 +240,7 @@ int MwTextHeight(MwWidget handle, MwFLFont ttf, const char* text) { void* MwFontLoad(unsigned char* data, unsigned int size) { if(MwFLFontLoad) - return MwFLFontLoad(data, size, 14); + return MwFLFontLoad(data, size, 13); return NULL; } From 421cf1557426d9014f4593e96d08544542da43d1 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 03:50:13 +0900 Subject: [PATCH 40/90] fix --- src/abstract/directory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/abstract/directory.c b/src/abstract/directory.c index d7b364ff0..63146b1e6 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -206,11 +206,13 @@ static void MwDirectoryJoinSingle(char* target, char* p) { } char* MwDirectoryJoin(char* a, char* b) { - char* p = MwStringDuplicate(a); + char* p = malloc(strlen(a) + 3 + strlen(b)); char* bdup = MwStringDuplicate(b); char* b2 = bdup; int i; + strcpy(p, a); + for(i = strlen(p) - 1; i >= 0; i--) { if(p[i] == DIRSEP) { p[i] = 0; From cf0eda33f2dcf7fe54dc4b13ec64f33dc2466626 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 04:24:11 +0900 Subject: [PATCH 41/90] ok --- src/default.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/default.c b/src/default.c index baeeb674d..2cb163342 100644 --- a/src/default.c +++ b/src/default.c @@ -1,8 +1,8 @@ #include -// #define USE_CATPPUCCIN +#define USE_CATPPUCCIN_DARK -#ifdef USE_CATPPUCCIN +#ifdef USE_CATPPUCCIN_LIGHT const char* MwDefaultBackground = "#eff1f5"; const char* MwDefaultForeground = "#4c4f69"; const char* MwDefaultSubBackground = "#9ca0b0"; @@ -18,7 +18,7 @@ const char* MwDefaultTitleBackground = "#008"; const char* MwDefaultTitleForeground = "#fff"; #endif -#ifdef USE_CATPPUCCIN +#ifdef USE_CATPPUCCIN_DARK const char* MwDefaultDarkBackground = "#1e1e2e"; const char* MwDefaultDarkForeground = "#cdd6f4"; const char* MwDefaultDarkSubBackground = "#313244"; From 9f3332766f8a9b5712c788ddc3b230de822c6c7e Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 04:42:13 +0900 Subject: [PATCH 42/90] limit --- src/widget/clock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/clock.c b/src/widget/clock.c index 547464afb..70471c62f 100644 --- a/src/widget/clock.c +++ b/src/widget/clock.c @@ -22,6 +22,8 @@ static void hand(MwWidget handle, double x, double y, double width, double lengt double c3 = cos(rad - M_PI); double s3 = sin(rad - M_PI); + if(width < width / 10) width = width / 10; + p[0].x = c2 * width / 2; p[0].y = s2 * width / 2; @@ -42,6 +44,7 @@ static void hand(MwWidget handle, double x, double y, double width, double lengt p[4] = p[0]; MwLLPolygon(handle->lowlevel, p, 4, inside); + MwLLLine(handle->lowlevel, &p[0], border); MwLLLine(handle->lowlevel, &p[1], border); MwLLLine(handle->lowlevel, &p[2], border); From a2ae35c794be6509eae858e7f793bb8d5f1f1d7c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 12:57:41 -0700 Subject: [PATCH 43/90] wayland: don't force render if buffer isn't configured --- src/backend/wayland/wayland.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 3c2d9bd61..49b601904 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1610,6 +1610,11 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { static void MwLLForceRenderImpl(MwLL handle) { WIDGET_CHECK(handle); + + if(!handle->wayland.configured) { + return; + } + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); handle->wayland.force_render = MwTRUE; From 9c4dd06fa405dc9e820abf051b20f09fa8669ff5 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 13:04:41 -0700 Subject: [PATCH 44/90] roundtrip before and after destroying a widget --- src/backend/wayland/wayland.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 49b601904..958d9efc4 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -734,6 +734,12 @@ static void destroy_widget(MwLL handle) { MwLLShow(handle, MwFALSE); + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + switch(handle->wayland.type) { case MwLL_WAYLAND_TOPLEVEL: destroy_toplevel(handle); From 6e0bbc33b977bb36a182d7dcc8921239431b3ebd Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 14:02:40 -0700 Subject: [PATCH 45/90] =?UTF-8?q?=F0=9F=A6=80=F0=9F=A6=80=F0=9F=A6=80=20DE?= =?UTF-8?q?STROYED=20TABLE=20MUTEX=20IS=20GONE=20=F0=9F=A6=80=F0=9F=A6=80?= =?UTF-8?q?=F0=9F=A6=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Mw/LowLevel/Wayland.h | 16 +----- src/backend/wayland/interfaces.c | 57 +++++++++++++----- src/backend/wayland/wayland.c | 99 ++++++-------------------------- 3 files changed, 63 insertions(+), 109 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 3e9d671e9..305f8bc68 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -500,10 +500,6 @@ int MwLLWaylandHyprlandGetRoundness(void); void MwLLWaylandHangUntilConfigured(MwLL handle); -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); -void MwLLWaylandWidgetUndestroy(MwLL self); -void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)); - /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); @@ -515,18 +511,10 @@ void MwLLWaylandFlush(MwLL handle); void MwLLWaylandCascadeChildren(MwLL handle); /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) \ - if(MwLLWaylandWidgetIsDestroyed(self)) { \ - return; \ - } +#define WAYLAND_EVENT_OP_START(self) pthread_mutex_lock(&self->wayland.eventsMutex); /* Footer for WAYLAND_EVENT_OP_START */ -#define WAYLAND_EVENT_OP_END(self) - -#define WIDGET_CHECK(handle) \ - if(!handle->wayland.valid) { \ - return; \ - } +#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 0ab3f43ac..247919c1d 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -720,8 +720,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLL self = data; MwMouse p; MwLL topmost_parent = self; - int i; - MwBool inArea = MwFALSE; + MwBool inArea = MwFALSE; (void)wl_pointer; (void)serial; @@ -753,9 +752,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { - arrdel(self->wayland.currentlyHeldWidgets, i); - } + arrsetlen(self->wayland.currentlyHeldWidgets, 0); mouse_dispatch(self, p, state); } if(self->wayland.backbuffer.surface) { @@ -1092,21 +1089,30 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, WAYLAND_EVENT_OP_START(self); + /* Always remember the seat itself, regardless of which capabilities it has - this is + * both what setup_clipboard()/setup_zwp_clipboard() below use, and what lets + * wl_seat_interface_destroy() release it later even on a keyboard-only seat. */ + self->wayland.pointer_seat = wl_seat; + if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - self->wayland.pointer_seat = wl_seat; - self->wayland.pointer = wl_seat_get_pointer(wl_seat); + self->wayland.pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } WAYLAND_EVENT_OP_END(self); - if(self->wayland.clipboard_manager.wl) - setup_clipboard(self, self->wayland.pointer_seat); - if(self->wayland.clipboard_manager.zwp) - setup_zwp_clipboard(self, self->wayland.pointer_seat); + /* Only hooked up if this seat actually has a pointer: wl_data_device.get_data_device() + * requires a non-null seat, and pointer_seat is only ever null before the first + * capabilities event has arrived at all. */ + if(capabilities & WL_SEAT_CAPABILITY_POINTER) { + if(self->wayland.clipboard_manager.wl) + setup_clipboard(self, self->wayland.pointer_seat); + if(self->wayland.clipboard_manager.zwp) + setup_zwp_clipboard(self, self->wayland.pointer_seat); + } }; static void output_geometry(void* data, @@ -1160,8 +1166,9 @@ void xdg_wm_base_ping(void* data, /* wl_seat setup function */ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll, MwU32 version) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - MwU32 ver = (version >= 4) ? 4 : 1; + MwU32 ver = (version >= 4) ? 4 : 1; /* version 4 needed for wl_seat_release */ proto->listener = malloc(sizeof(struct wl_seat_listener)); + proto->context = NULL; ((struct wl_seat_listener*)proto->listener)->name = wl_seat_name; ((struct wl_seat_listener*)proto->listener)->capabilities = wl_seat_capabilities; @@ -1172,7 +1179,31 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll, MwU32 version) { } static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; + if(wayland->pointer != NULL) { + if(wl_proxy_get_version((struct wl_proxy*)wayland->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) { + wl_pointer_release(wayland->pointer); + } else { + wl_pointer_destroy(wayland->pointer); + } + wayland->pointer = NULL; + } + if(wayland->keyboard != NULL) { + if(wl_proxy_get_version((struct wl_proxy*)wayland->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) { + wl_keyboard_release(wayland->keyboard); + } else { + wl_keyboard_destroy(wayland->keyboard); + } + wayland->keyboard = NULL; + } + if(wayland->pointer_seat != NULL) { + if(wl_proxy_get_version((struct wl_proxy*)wayland->pointer_seat) >= WL_SEAT_RELEASE_SINCE_VERSION) { + wl_seat_release(wayland->pointer_seat); + } else { + wl_seat_destroy(wayland->pointer_seat); + } + wayland->pointer_seat = NULL; + } + free(data->listener); free(data); } diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 958d9efc4..7253c0052 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -12,39 +12,6 @@ MwBool MwWaylandVulkan = MwFALSE; MwBool MwWaylandCairoOnly = MwFALSE; -static pthread_mutex_t destroyedWidgetsTableMutex; -/* - * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. - * - * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. - */ -static MwLL* destroyedWidgetsTable; - -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwTRUE; - } - } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwFALSE; -} -void MwLLWaylandWidgetUndestroy(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - arrdel(destroyedWidgetsTable, i); - break; - } - } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return; -} - void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) { if(handle->common.user) { MwWidget w = handle->common.user; @@ -76,7 +43,6 @@ static void recursive_dispatch_resize(MwLL handle) { static void recursive_render(MwLL handle) { int i; - WIDGET_CHECK(handle); for(i = 0; i < arrlen(((MwWidget)handle->common.user)->children); i++) recursive_render(((MwWidget)handle->common.user)->children[i]->lowlevel); @@ -386,8 +352,9 @@ static void destroy_toplevel(MwLL r) { xkb_context_unref(r->wayland.xkb_context); - wl_pointer_destroy(r->wayland.pointer); - wl_keyboard_destroy(r->wayland.keyboard); + /* wl_pointer/wl_keyboard/wl_seat are torn down centrally in wl_seat_interface_destroy, + * after this function returns, so every widget type that binds a seat (toplevel, popup, + * layer surface) releases them the same way instead of leaking or double-freeing them. */ MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); MwLLWaylandFifoSurfaceDestroy(&r->wayland.backbuffer); @@ -883,12 +850,7 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh r->wayland.x = x; r->wayland.y = y; r->wayland.parent = parent; - if(MwLLWaylandWidgetIsDestroyed(parent)) { - r->wayland.valid = MwFALSE; - return; - } else { - r->wayland.valid = MwTRUE; - } + r->wayland.valid = MwTRUE; if(ty == MwLL_WAYLAND_UNKNOWN) { if(parent == NULL) { @@ -925,8 +887,6 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } - WIDGET_CHECK(r); - r->wayland.region = wl_compositor_create_region(r->wayland.compositor); r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); MwLLWaylandRegionSetup(r); @@ -1025,12 +985,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); + pthread_mutex_init(&r->wayland.eventsMutex, NULL); MwLLCreateCommon(r); - if(MwLLWaylandWidgetIsDestroyed(r)) { - MwLLWaylandWidgetUndestroy(r); - } - r->wayland.is_toplevel = parent == NULL; r->wayland.is_clipping = 0; @@ -1067,8 +1024,6 @@ static void MwLLDestroyImpl(MwLL handle) { select_ret = select(1, NULL, NULL, NULL, &tv); } while((select_ret == -1) && (errno == EINTR)); - pthread_mutex_destroy(&handle->wayland.eventsMutex); - #ifdef USE_DBUS if(!wl_call_tbl.has_dbus) { MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); @@ -1094,9 +1049,7 @@ static void MwLLDestroyImpl(MwLL handle) { printf("widget invalid\n"); } - pthread_mutex_lock(&destroyedWidgetsTableMutex); - arrput(destroyedWidgetsTable, handle); - pthread_mutex_unlock(&destroyedWidgetsTableMutex); + pthread_mutex_destroy(&handle->wayland.eventsMutex); free(handle); } @@ -1116,7 +1069,7 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - WIDGET_CHECK(handle); + MwLLWaylandRegionInvalidate(handle); if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { @@ -1181,7 +1134,6 @@ static void actually_set_wh(MwLL handle) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - WIDGET_CHECK(handle); if(handle->wayland.ww == w && handle->wayland.wh == h) { return; @@ -1219,7 +1171,7 @@ const float_color one = {.2627451, .37254902, .49411765}; const float_color two = {.05490196, .17254902, .30588235}; static void MwLLBeginDrawImpl(MwLL handle) { - WIDGET_CHECK(handle); + cairo_save(handle->wayland.cairo.front_cairo); cairo_set_source_rgba(handle->wayland.cairo.front_cairo, 0, 0, 0, 0); cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_SOURCE); @@ -1373,7 +1325,6 @@ static void MwLLEndDrawImpl(MwLL handle) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - WIDGET_CHECK(handle); clip(handle); @@ -1384,7 +1335,6 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { int i; - WIDGET_CHECK(handle); clip(handle); @@ -1426,10 +1376,6 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { - return 0; - } - handle->wayland.resizing = 0; if(handle->wayland.setting_wh) { @@ -1502,7 +1448,6 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - WIDGET_CHECK(handle); if(!MwWaylandVulkan) { if(handle->wayland.did_event_loop_early) { @@ -1525,7 +1470,7 @@ static void MwLLNextEventImpl(MwLL handle) { } static void MwLLSetTitleImpl(MwLL handle, const char* title) { - WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); } @@ -1551,7 +1496,6 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - WIDGET_CHECK(handle); clip(handle); @@ -1561,7 +1505,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; @@ -1615,7 +1559,6 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { - WIDGET_CHECK(handle); if(!handle->wayland.configured) { return; @@ -1632,8 +1575,6 @@ static void MwLLForceRenderImpl(MwLL handle) { static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { int x, y, xs, ys; - WIDGET_CHECK(handle); - if(handle->wayland.cursor.setup) { MwLLWaylandBufferDestroy(&handle->wayland.cursor); wl_surface_destroy(handle->wayland.cursor.surface); @@ -1684,7 +1625,7 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { static void MwLLDetachImpl(MwLL handle, MwPoint* point) { MwLL p = handle->wayland.parent; int x = 0, y = 0; - WIDGET_CHECK(handle); + while(p != NULL) { if(p->wayland.type != MwLL_WAYLAND_TOPLEVEL) { x += p->wayland.x; @@ -1706,7 +1647,7 @@ static void MwLLShowImpl(MwLL handle, int show) { if(!handle->wayland.configured) { return; } - WIDGET_CHECK(handle); + /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ if(handle->wayland.framebuffer.surface) { wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); @@ -1725,7 +1666,7 @@ static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); @@ -1736,7 +1677,7 @@ static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; @@ -1763,7 +1704,7 @@ static void MwLLFocusImpl(MwLL handle) { static void MwLLGrabPointerImpl(MwLL handle, int toggle) { MwLL topmost_parent = handle; - WIDGET_CHECK(handle); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { if(toggle) { @@ -1790,7 +1731,6 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { int i; - WIDGET_CHECK(handle); if(handle->wayland.clipboard_buffer != NULL) { free(handle->wayland.clipboard_buffer); @@ -1817,7 +1757,7 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { int i; - WIDGET_CHECK(handle); + if(clipboard_type == MwCLIPBOARD_PRIMARY) { if(handle->wayland.supports_zwp) { for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { @@ -1839,8 +1779,6 @@ static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { static void MwLLMakeToolWindowImpl(MwLL handle) { MwBool can_do_layer_surface = MwFALSE; - WIDGET_CHECK(handle); - can_do_layer_surface = (WAYLAND_GET_INTERFACE(handle->wayland, zwlr_layer_shell_v1) != NULL); if(!handle->wayland.parent && can_do_layer_surface) { @@ -1855,14 +1793,12 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { MwLL topmost_parent = handle; - WIDGET_CHECK(handle); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; *point = topmost_parent->wayland.cur_mouse_pos; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - WIDGET_CHECK(handle); rect->x = 0; rect->y = 0; @@ -1882,7 +1818,6 @@ static void MwLLBeginStateChangeImpl(MwLL handle) { static void MwLLEndStateChangeImpl(MwLL handle) { MwLL topmost_parent; int x, y; - WIDGET_CHECK(handle); if(!handle->wayland.changing) { return; @@ -1942,7 +1877,7 @@ static MwBool MwLLDoModernImpl(MwLL handle) { static void MwLLRaiseImpl(MwLL handle) { (void)handle; - /* WIDGET_CHECK(handle); + /* if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) { MwLL topmost_parent = handle; From d8886d6860069db36786baf0cf69882477a477ac Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 13 Sep 2026 14:04:34 -0700 Subject: [PATCH 46/90] remove unnecessary mutex locks --- include/Mw/LowLevel/Wayland.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 305f8bc68..b9cbf5213 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -511,10 +511,10 @@ void MwLLWaylandFlush(MwLL handle); void MwLLWaylandCascadeChildren(MwLL handle); /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) pthread_mutex_lock(&self->wayland.eventsMutex); +#define WAYLAND_EVENT_OP_START(self) /* Footer for WAYLAND_EVENT_OP_START */ -#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); +#define WAYLAND_EVENT_OP_END(self) /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { From 12483e997841af289986d3d9b547fe2d6ab28631 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 06:01:54 +0900 Subject: [PATCH 47/90] pie graph --- examples/basic/periodic.c | 2 +- include/Mw/Constants.h | 1 + milsko.xml | 1 + src/widget/chart.c | 55 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index c17cfd07d..e53d66bce 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -269,7 +269,7 @@ int main() { wclock = child(f); f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, - MwNtype, MwCHART_3D_BAR, + MwNtype, MwCHART_PIE, MwNcolumnSpan, 2, NULL); w = child(f); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 6df447d43..42f147110 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -116,6 +116,7 @@ enum MwCLIPBOARD { enum MwCHART { MwCHART_BAR = 0, MwCHART_3D_BAR, + MwCHART_PIE }; enum MwMOUSE { diff --git a/milsko.xml b/milsko.xml index 6bf802b01..0652a552f 100644 --- a/milsko.xml +++ b/milsko.xml @@ -233,6 +233,7 @@ 0 + 1 diff --git a/src/widget/chart.c b/src/widget/chart.c index 83e3a5e06..4079e8b83 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -13,6 +13,7 @@ static const char* palette0[] = { NULL}; #define NUMFMT "%.2f" +#define PIE_DIV 4 static int wcreate(MwWidget handle) { MwChart c = malloc(sizeof(*c)); @@ -239,6 +240,60 @@ static void draw(MwWidget handle) { MwLLFreeColor(colorl); MwLLFreeColor(color); } + } else if(type == MwCHART_PIE) { + double sum = 0; + int radius = r.width < r.height ? r.width : r.height; + double cangle = 0; + int k; + + for(i = 0; i < arrlen(c->entries); i++) { + if(c->entries[i].value > 0) sum += c->entries[i].value; + } + + for(k = 0; k < 2; k++) { + for(i = 0; i < arrlen(c->entries); i++) { + MwLLColor color; + double angle = c->entries[i].value / sum * 360; + MwPoint p[360 + 1 + 1]; + int div = angle / PIE_DIV; + int j; + int count; + + if(c->entries[i].value <= 0) continue; + + color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + + p[0].x = r.width / 2; + p[0].y = r.height / 2; + for(j = 0; j <= div; j++) { + double a = angle / div * j; + + p[div - j + 1].x = p[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; + p[div - j + 1].y = p[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2; + } + + count = j + 1; + + if(k == 0) { + MwLLPolygon(handle->lowlevel, p, count, color); + } else { + int j; + + p[count] = p[0]; + for(j = 0; j < count; j++) { + MwLLLine(handle->lowlevel, &p[j], border); + } + + p[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; + p[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + } + + cangle += angle; + + MwLLFreeColor(color); + } + } } MwLLFreeColor(border); From d2cbe88cb3e4c0314945a5305ccc087fd2ca3b41 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 06:59:15 +0900 Subject: [PATCH 48/90] 3d pie --- examples/basic/periodic.c | 18 ++++++-- include/Mw/Constants.h | 3 +- milsko.xml | 1 + src/widget/chart.c | 94 +++++++++++++++++++++++++++++---------- 4 files changed, 88 insertions(+), 28 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index e53d66bce..adaf35b63 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -268,9 +268,8 @@ int main() { f = frame("Clock", -PaddingContent, -PaddingContent, MwClockClass, NULL); wclock = child(f); - f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, - MwNtype, MwCHART_PIE, - MwNcolumnSpan, 2, + f = frame("3D Bar Chart", -PaddingContent, -PaddingContent, MwChartClass, + MwNtype, MwCHART_3D_BAR, NULL); w = child(f); MwChartAdd(w, -1, "A", -800, NULL); @@ -282,6 +281,19 @@ int main() { MwChartAdd(w, -1, "G", 400, NULL); MwChartAdd(w, -1, "H", 800, NULL); + f = frame("3D Pie Chart", -PaddingContent, -PaddingContent, MwChartClass, + MwNtype, MwCHART_3D_PIE, + NULL); + w = child(f); + MwChartAdd(w, -1, "A", 10, NULL); + MwChartAdd(w, -1, "B", 20, NULL); + MwChartAdd(w, -1, "C", 30, NULL); + MwChartAdd(w, -1, "D", 10, NULL); + MwChartAdd(w, -1, "E", 20, NULL); + MwChartAdd(w, -1, "F", 30, NULL); + MwChartAdd(w, -1, "G", 10, NULL); + MwChartAdd(w, -1, "H", 20, NULL); + f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); MwComboBoxAdd(w, -1, "Hello!"); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 42f147110..6379fef4a 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -116,7 +116,8 @@ enum MwCLIPBOARD { enum MwCHART { MwCHART_BAR = 0, MwCHART_3D_BAR, - MwCHART_PIE + MwCHART_PIE, + MwCHART_3D_PIE }; enum MwMOUSE { diff --git a/milsko.xml b/milsko.xml index 0652a552f..084f82594 100644 --- a/milsko.xml +++ b/milsko.xml @@ -234,6 +234,7 @@ 0 + 1 diff --git a/src/widget/chart.c b/src/widget/chart.c index 4079e8b83..9c87e3fce 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -13,7 +13,7 @@ static const char* palette0[] = { NULL}; #define NUMFMT "%.2f" -#define PIE_DIV 4 +#define PIE_DIV 10 static int wcreate(MwWidget handle) { MwChart c = malloc(sizeof(*c)); @@ -63,8 +63,9 @@ static void draw_line(MwWidget handle, const char* text, double x, double y, dou } static void draw(MwWidget handle) { - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int ColorDiff = MwGetColorDifference(handle); + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); MwRect r; MwChart c = handle->internal; int i; @@ -77,7 +78,8 @@ static void draw(MwWidget handle) { double vmax = -0xffffffff; int space = MwTextHeight(handle, NULL, "M"); MwPoint p[2]; - int type = MwGetInteger(handle, MwNtype); + int type = MwGetInteger(handle, MwNtype); + int modern = MwGetInteger(handle, MwNmodernLook); for(n = 0; colors[n] != NULL; n++); @@ -157,10 +159,9 @@ static void draw(MwWidget handle) { node.width = width; for(i = 0; i < arrlen(c->entries); i++) { - int ColorDiff = MwGetColorDifference(handle); - MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); - MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwPoint persp_top[5]; MwPoint persp_right[5]; @@ -213,7 +214,7 @@ static void draw(MwWidget handle) { MwLLPolygon(handle->lowlevel, persp_right, 4, colord); } - if(!MwGetInteger(handle, MwNmodernLook)) { + if(!modern) { MwDrawRectLine(handle, &node, border); if(type == MwCHART_3D_BAR) { @@ -240,28 +241,32 @@ static void draw(MwWidget handle) { MwLLFreeColor(colorl); MwLLFreeColor(color); } - } else if(type == MwCHART_PIE) { - double sum = 0; - int radius = r.width < r.height ? r.width : r.height; - double cangle = 0; - int k; + } else if(type == MwCHART_PIE || type == MwCHART_3D_PIE) { + double sum = 0; + int radius = r.width < r.height ? r.width : r.height; + double cangle = 0; + int k; + double vsquish = type == MwCHART_3D_PIE ? 2 : 1; + MwPoint p[360 + 1 + 1]; for(i = 0; i < arrlen(c->entries); i++) { if(c->entries[i].value > 0) sum += c->entries[i].value; } - for(k = 0; k < 2; k++) { + for(k = 0; k < 4; k++) { for(i = 0; i < arrlen(c->entries); i++) { MwLLColor color; + MwLLColor colorl; double angle = c->entries[i].value / sum * 360; - MwPoint p[360 + 1 + 1]; - int div = angle / PIE_DIV; + int div = angle / PIE_DIV; int j; int count; if(c->entries[i].value <= 0) continue; + if((k == 0 || k == 1) && type == MwCHART_PIE) continue; - color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); p[0].x = r.width / 2; p[0].y = r.height / 2; @@ -269,31 +274,72 @@ static void draw(MwWidget handle) { double a = angle / div * j; p[div - j + 1].x = p[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; - p[div - j + 1].y = p[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2; + p[div - j + 1].y = p[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2 / vsquish; } count = j + 1; - if(k == 0) { - MwLLPolygon(handle->lowlevel, p, count, color); - } else { + if((k == 0 || k == 1) && type == MwCHART_3D_PIE) { + int j; + MwPoint p2[360 + 1 + 1]; + int d = 0; + + for(d = 1; d <= 2; d++) { + for(j = 0; j < count - 1; j++) { + p2[3 + j] = p[1 + j]; + p2[3 + j].y += radius / 8 / d; + } + + p2[0] = p[count - 1]; + p2[1] = p[0]; + p2[2] = p[1]; + + if(k == 0) { + MwLLPolygon(handle->lowlevel, p2, count + 2, color); + } else if(d == 1 && k == 1) { + for(j = 3; j < count + 1; j++) { + if(!modern) MwLLLine(handle->lowlevel, &p2[j], border); + } + + p[0] = p[1]; + p[0].y += radius / 8; + if(!modern) MwLLLine(handle->lowlevel, p, border); + } + } + } + + if(k == 2) { + MwLLPolygon(handle->lowlevel, p, count, type == MwCHART_3D_PIE ? colorl : color); + } else if(k == 3) { int j; p[count] = p[0]; for(j = 0; j < count; j++) { - MwLLLine(handle->lowlevel, &p[j], border); + if(!modern) MwLLLine(handle->lowlevel, &p[j], border); } p[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; - p[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; + p[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); } cangle += angle; + MwLLFreeColor(colorl); MwLLFreeColor(color); } } + + if(!modern && type == MwCHART_3D_PIE) { + p[0].x = r.width / 2 - radius / 2; + p[0].y = r.height / 2; + p[1] = p[0]; + p[1].y += radius / 8; + MwLLLine(handle->lowlevel, p, border); + + p[0].x = p[1].x = r.width / 2 + radius / 2; + MwLLLine(handle->lowlevel, p, border); + } } MwLLFreeColor(border); From f0fc3fa174d8e2b61a7d96f74136402e3e06059f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 14 Sep 2026 07:09:43 +0900 Subject: [PATCH 49/90] wayland backend now doublebuffered! --- CMakeLists.txt | 1 - include/Mw/LowLevel/Cairo.h | 2 + include/Mw/LowLevel/Wayland.h | 17 ----- pl/rules.pl | 1 - src/backend/cairo.c | 55 +++++++------- src/backend/wayland/buffer.c | 33 --------- src/backend/wayland/interfaces.c | 1 - src/backend/wayland/wayland.c | 120 ++++++++++++++----------------- src/widget/opengl.c | 5 -- 9 files changed, 86 insertions(+), 149 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ec1ed85e..534614f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,7 +261,6 @@ if(MW_USE_WAYLAND) scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") - scan_wayland_protocol("staging" "fifo" "-v1") scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") target_sources( diff --git a/include/Mw/LowLevel/Cairo.h b/include/Mw/LowLevel/Cairo.h index dd2cfa322..680c651fc 100644 --- a/include/Mw/LowLevel/Cairo.h +++ b/include/Mw/LowLevel/Cairo.h @@ -188,8 +188,10 @@ struct _MwLLCairo { struct _MwLLCommon common; cairo_surface_t* front_cs; + cairo_surface_t* front_cs_back; cairo_surface_t* back_cs; cairo_t* front_cairo; + cairo_t* front_cairo_back; cairo_t* back_cairo; /* The cairo to actually use for draw operations. Typically is front_cairo, but wayland's MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ cairo_t* selected_cairo; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index b9cbf5213..fd9717802 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -207,7 +207,6 @@ MwInline int wayland_load_funcs() { #include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #include "Wayland/wlr-layer-shell-client-protocol.h" -#include "Wayland/fifo-client-protocol.h" #endif typedef struct wayland_protocol { @@ -266,7 +265,6 @@ struct _MwLLWaylandShmBuffer { struct wl_buffer* shm_buffer_back; struct wl_surface* surface; struct wl_output* output; - struct wp_fifo_v1* fifo; MwU8* buf; MwU8* buf_back; @@ -436,8 +434,6 @@ struct _MwLLWayland { struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; - MwBool fifo_wait; - MwBool disable_fifo; MwLLPixmap icon_pixmap; @@ -475,17 +471,6 @@ void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland); /* Destroy the backbuffer */ void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* handle); -/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ -void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer); -/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ -void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer); -/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ -void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer); - -#ifdef MW_VULKAN -#warning Wayland backend currently disabled by default when Vulkan enabled. Use with caution (MW_BACKEND=wayland to override). -#endif - void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height); void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer); void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); @@ -508,8 +493,6 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ /* Flush Wayland events */ void MwLLWaylandFlush(MwLL handle); -void MwLLWaylandCascadeChildren(MwLL handle); - /* Standard procedure before event callbacks in Wayland */ #define WAYLAND_EVENT_OP_START(self) diff --git a/pl/rules.pl b/pl/rules.pl index 220e550c0..9d2081c87 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -66,7 +66,6 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - scan_wayland_protocol("staging", "fifo", "-v1"); scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 65380fbaf..0b74b4222 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -6,38 +6,38 @@ cairo_call_table_t cairo_call_tbl; void MwLLCairoPolygon(struct _MwLLCairo handle, MwPoint* points, int points_count, MwLLColor color) { int i; - cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); - cairo_new_path(handle.front_cairo); + cairo_set_source_rgba(handle.front_cairo_back, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo_back); for(i = 0; i < points_count; i++) { if(i == 0) { - cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + cairo_move_to(handle.front_cairo_back, points[i].x, points[i].y); } else { - cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + cairo_line_to(handle.front_cairo_back, points[i].x, points[i].y); } } - cairo_close_path(handle.front_cairo); + cairo_close_path(handle.front_cairo_back); - cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_SOURCE); - cairo_fill(handle.front_cairo); - cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); + cairo_set_operator(handle.front_cairo_back, CAIRO_OPERATOR_SOURCE); + cairo_fill(handle.front_cairo_back); + cairo_set_operator(handle.front_cairo_back, CAIRO_OPERATOR_OVER); }; void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { int i; - cairo_set_antialias(handle.front_cairo, CAIRO_ANTIALIAS_NONE); - cairo_set_line_cap(handle.front_cairo, CAIRO_LINE_CAP_SQUARE); - cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); - cairo_new_path(handle.front_cairo); + cairo_set_antialias(handle.front_cairo_back, CAIRO_ANTIALIAS_NONE); + cairo_set_line_cap(handle.front_cairo_back, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgba(handle.front_cairo_back, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo_back); for(i = 0; i < 2; i++) { if(i == 0) { - cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + cairo_move_to(handle.front_cairo_back, points[i].x, points[i].y); } else { - cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + cairo_line_to(handle.front_cairo_back, points[i].x, points[i].y); } } - cairo_close_path(handle.front_cairo); - cairo_stroke(handle.front_cairo); + cairo_close_path(handle.front_cairo_back); + cairo_stroke(handle.front_cairo_back); }; MwLLPixmap MwLLCairoCreatePixmap(struct _MwLLCairo handle, unsigned char* data, int width, int height) { @@ -88,7 +88,7 @@ void MwLLCairoDestroyPixmap(MwLLPixmap pixmap) { void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; - cairo_t* selected_cairo = handle.selected_cairo ? handle.selected_cairo : handle.front_cairo; + cairo_t* selected_cairo = handle.selected_cairo ? handle.selected_cairo : handle.front_cairo_back; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); @@ -101,7 +101,7 @@ void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixm cairo_set_source_surface(c, pixmap->cairo.cs, 0, 0); cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); + cairo_set_operator(handle.front_cairo_back, CAIRO_OPERATOR_OVER); cairo_paint(c); @@ -118,7 +118,9 @@ void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU3 } else { cairo->front_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); } - cairo->front_cairo = cairo_create(cairo->front_cs); + cairo->front_cs_back = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo->front_cairo_back = cairo_create(cairo->front_cs_back); + cairo->front_cairo = cairo_create(cairo->front_cs); } void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { @@ -132,6 +134,7 @@ void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo) { cairo_destroy(cairo->front_cairo); + cairo_destroy(cairo->front_cairo_back); cairo_surface_destroy(cairo->front_cs); }; void MwLLCairoBackDestroy(struct _MwLLCairo* cairo) { @@ -169,7 +172,7 @@ static void MwLLDestroyImpl(MwLL handle) { } static void MwLLBeginDrawImpl(MwLL handle) { - handle->cairo.selected_cairo = handle->cairo.front_cairo; + handle->cairo.selected_cairo = handle->cairo.front_cairo_back; } static void MwLLEndDrawImpl(MwLL handle) { } @@ -212,8 +215,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -257,10 +260,10 @@ static void MwLLRaiseImpl(MwLL handle) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {} static int MwLLCairoCallInitImpl(void) { - if(cairo_load_funcs() != 0) { - return 1; - } - return 0; + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; } #include "call.c" CALL(Cairo); diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c index 3ee5e3ca0..cb1eca5f0 100644 --- a/src/backend/wayland/buffer.c +++ b/src/backend/wayland/buffer.c @@ -2,39 +2,6 @@ #include #include "../../../external/stb_ds.h" -/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ -void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer) { - wayland_protocol_t* fifo_manager; - - if(buffer->fifo || !buffer->surface) { - return; - } - - fifo_manager = shget(wayland->wl_protocol_map, wp_fifo_manager_v1_interface.name); - if(!fifo_manager) { - return; - } - - buffer->fifo = wp_fifo_manager_v1_get_fifo(fifo_manager->context, buffer->surface); -} - -/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ -void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer) { - if(buffer->fifo) { - wp_fifo_v1_destroy(buffer->fifo); - buffer->fifo = NULL; - } -} - -/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ -void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer) { - if(buffer->fifo) { - wp_fifo_v1_set_barrier(buffer->fifo); - wp_fifo_v1_wait_barrier(buffer->fifo); - } - wl_surface_commit(buffer->surface); -} - void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { MwLLWaylandBufferSetup(&wayland->framebuffer, wayland->ww, wayland->wh); diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 247919c1d..cbab2ad06 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -600,7 +600,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLLDispatch(currentlyHeldWidgets[i], move, &p); } - MwLLWaylandCascadeChildren(self); } if(self->wayland.backbuffer.surface) { wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 7253c0052..61546646c 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -225,11 +225,8 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { // Yes this is needed every time, it's how we fix weston. if(self->wayland.configured) wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - if(self->wayland.fifo_wait) { - MwLLWaylandFifoCommit(buffer); - } else { - wl_surface_commit(buffer->surface); - } + + wl_surface_commit(buffer->surface); } } } @@ -278,9 +275,7 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.backbuffer); - r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); wl_subsurface_set_desync(r->wayland.toplevel->ssurface); r->wayland.toplevel->xdg_surface = @@ -356,8 +351,6 @@ static void destroy_toplevel(MwLL r) { * after this function returns, so every widget type that binds a seat (toplevel, popup, * layer surface) releases them the same way instead of leaking or double-freeing them. */ - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - MwLLWaylandFifoSurfaceDestroy(&r->wayland.backbuffer); wl_surface_destroy(r->wayland.framebuffer.surface); free(r->wayland.toplevel); @@ -521,7 +514,6 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { r->wayland.xkb_state = topmost_parent->wayland.xkb_state; r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.popup->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); @@ -563,8 +555,6 @@ static void destroy_popup(MwLL r) { xdg_positioner_destroy(r->wayland.popup->xdg_positioner); - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - wl_surface_destroy(r->wayland.framebuffer.surface); wl_registry_destroy(r->wayland.registry); @@ -648,7 +638,6 @@ static void setup_layer_surface(MwLL r, int x, int y, int width, int height) { r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.layer_surface->surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, r->wayland.framebuffer.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "milsko-surfaces"); @@ -679,8 +668,6 @@ static void destroy_layer_surface(MwLL r) { zxdg_decoration_manager_v1_destroy(dec->manager); } - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - wl_surface_destroy(r->wayland.framebuffer.surface); wl_compositor_destroy(r->wayland.compositor); @@ -810,15 +797,15 @@ static void clip(MwLL handle) { handle->wayland.clipping_rect.height = my - cy; MwLLWaylandRegionSetup(handle); - cairo_reset_clip(handle->wayland.cairo.front_cairo); + cairo_reset_clip(handle->wayland.cairo.front_cairo_back); if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && !handle->wayland.is_toplevel) { - cairo_rectangle(handle->wayland.cairo.front_cairo, cx - x, cy - y, mx - cx, my - cy); - cairo_clip(handle->wayland.cairo.front_cairo); + cairo_rectangle(handle->wayland.cairo.front_cairo_back, cx - x, cy - y, mx - cx, my - cy); + cairo_clip(handle->wayland.cairo.front_cairo_back); } if(handle->wayland.is_clipping) { - cairo_rectangle(handle->wayland.cairo.front_cairo, handle->wayland.clip.x, handle->wayland.clip.y, handle->wayland.clip.width, handle->wayland.clip.height); - cairo_clip(handle->wayland.cairo.front_cairo); + cairo_rectangle(handle->wayland.cairo.front_cairo_back, handle->wayland.clip.x, handle->wayland.clip.y, handle->wayland.clip.width, handle->wayland.clip.height); + cairo_clip(handle->wayland.cairo.front_cairo_back); } } } @@ -933,22 +920,31 @@ static void draw_children(MwLL handle); static void draw_child(MwLL handle, MwLL child) { cairo_t* c; cairo_surface_t* cs; - cairo_t* selected_cairo = handle->wayland.cairo.front_cairo; + cairo_t* selected_cairo; + MwLL topmost_parent = handle; + + if(topmost_parent->wayland.type != MwLL_WAYLAND_POPUP) { + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + } + } wl_surface_commit(child->wayland.framebuffer.surface); cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, child->wayland.ww, child->wayland.wh); c = cairo_create(cs); - cairo_set_source_surface(c, child->wayland.cairo.front_cs, 0, 0); + cairo_set_source_surface(c, child->wayland.cairo.front_cs_back, 0, 0); cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_OVER); + cairo_set_operator(handle->wayland.cairo.front_cairo_back, CAIRO_OPERATOR_OVER); cairo_paint(c); - cairo_set_source_surface(selected_cairo, cs, child->wayland.x, child->wayland.y); - cairo_paint(selected_cairo); + // printf("%d %d\n", child->wayland.x, child->wayland.y); + + cairo_set_source_surface(handle->wayland.cairo.front_cairo_back, cs, child->wayland.x, child->wayland.y); + cairo_paint(handle->wayland.cairo.front_cairo_back); cairo_destroy(c); cairo_surface_destroy(cs); @@ -965,20 +961,25 @@ static void draw_children(MwLL handle) { handle->wayland.events_pending = MwFALSE; } -static void cascade_child(MwLL handle, MwLL child) { - child->wayland.do_cascading_draw = 10; -} +static void frontbuffer_draw(MwLL handle) { + cairo_t* c; + cairo_surface_t* cs; -static void count_child(MwLL handle, MwLL child) { - handle->wayland.cascading_child_num++; -} + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, handle->wayland.ww, handle->wayland.wh); + c = cairo_create(cs); -void MwLLWaylandCascadeChildren(MwLL handle) { - handle->wayland.cascading_child_num = 0; - MwLLWaylandChildrenIterate(handle, count_child); + cairo_set_source_surface(c, handle->wayland.cairo.front_cs_back, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - handle->wayland.do_cascading_draw = handle->wayland.cascading_child_num * 10; - MwLLWaylandChildrenIterate(handle, cascade_child); + cairo_set_operator(handle->wayland.cairo.front_cairo_back, CAIRO_OPERATOR_OVER); + + cairo_paint(c); + + cairo_set_source_surface(handle->wayland.cairo.front_cairo, cs, 0, 0); + cairo_paint(handle->wayland.cairo.front_cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -1069,7 +1070,6 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MwLLWaylandRegionInvalidate(handle); if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { @@ -1082,8 +1082,11 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { /* toplevels cannot be moved */ break; case MwLL_WAYLAND_SUBLEVEL: - /* sublevels are drawn according to their own x/y */ + { + if(handle->wayland.parent) + MwLLForceRender(handle->wayland.parent); break; + } case MwLL_WAYLAND_POPUP: xdg_positioner_set_anchor_rect(handle->wayland.popup->xdg_positioner, handle->wayland.parent->wayland.x, handle->wayland.parent->wayland.y, handle->wayland.ww, handle->wayland.wh); xdg_positioner_set_offset(handle->wayland.popup->xdg_positioner, x, y); @@ -1171,16 +1174,15 @@ const float_color one = {.2627451, .37254902, .49411765}; const float_color two = {.05490196, .17254902, .30588235}; static void MwLLBeginDrawImpl(MwLL handle) { - - cairo_save(handle->wayland.cairo.front_cairo); - cairo_set_source_rgba(handle->wayland.cairo.front_cairo, 0, 0, 0, 0); - cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_SOURCE); - cairo_rectangle(handle->wayland.cairo.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); - cairo_fill(handle->wayland.cairo.front_cairo); - cairo_restore(handle->wayland.cairo.front_cairo); + cairo_save(handle->wayland.cairo.front_cairo_back); + cairo_set_source_rgba(handle->wayland.cairo.front_cairo_back, 0, 0, 0, 0); + cairo_set_operator(handle->wayland.cairo.front_cairo_back, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(handle->wayland.cairo.front_cairo_back, 0, 0, handle->wayland.ww, handle->wayland.wh); + cairo_fill(handle->wayland.cairo.front_cairo_back); + cairo_restore(handle->wayland.cairo.front_cairo_back); if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { - handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo_back; return; } @@ -1310,7 +1312,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } - handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo_back; } static void MwLLEndDrawImpl(MwLL handle) { @@ -1320,7 +1322,9 @@ static void MwLLEndDrawImpl(MwLL handle) { } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - MwLLWaylandCascadeChildren(handle); + if(handle->wayland.type != MwLL_WAYLAND_SUBLEVEL) { + handle->wayland.do_cascading_draw = 1; + } } } @@ -1385,8 +1389,7 @@ static int MwLLPendingImpl(MwLL handle) { if(handle->wayland.do_cascading_draw) { draw_children(handle); - if(handle->wayland.do_cascading_draw > 0) - handle->wayland.do_cascading_draw--; + frontbuffer_draw(handle); } handle->wayland.end_time = MwTimeGetTick(); @@ -1437,12 +1440,10 @@ static int MwLLPendingImpl(MwLL handle) { return pending; } - if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwTRUE; MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } - if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwFALSE; return handle->wayland.force_render || handle->wayland.events_pending || pending; } @@ -1458,11 +1459,9 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.force_render) { - handle->wayland.fifo_wait = MwTRUE; MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); handle->wayland.force_render = 0; - handle->wayland.fifo_wait = MwFALSE; } if(handle->wayland.events_pending) { handle->wayland.events_pending = 0; @@ -1559,7 +1558,6 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { - if(!handle->wayland.configured) { return; } @@ -1567,9 +1565,6 @@ static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); handle->wayland.force_render = MwTRUE; - if(handle->wayland.parent) { - handle->wayland.parent->wayland.force_render = MwTRUE; - } } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { @@ -1919,14 +1914,9 @@ static int MwLLWaylandCallInitImpl(void) { } else { loadWayland |= (strcmp(mw_backend_env, "wayland") == 0); } - } - - /* NOTE: when vulkan is enabled, refuse to default to wayland. Remove this if I ever get Vulkan widget working with the new surfaces system. */ -#ifndef MW_VULKAN - else if(getenv("WAYLAND_DISPLAY")) { + } else if(getenv("WAYLAND_DISPLAY")) { loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); } -#endif #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 9e1b91e84..c9bb3f496 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -240,11 +240,6 @@ static int wcreate(MwWidget handle) { waylandopengl_t* o = r = malloc(sizeof(*o)); int gbm_format = 0; EGLConfig egl_configs[1024]; - MwWidget topmost_parent = handle; - - /* Disable fifo waiting when we have an OpenGL widget */ - while(topmost_parent->parent) topmost_parent = topmost_parent->parent; - topmost_parent->lowlevel->wayland.disable_fifo = MwTRUE; memset(o, 0, sizeof(waylandopengl_t)); From 66ea53f5231baa8230c98c155505ea05fa27807a Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:15:12 +0900 Subject: [PATCH 50/90] fix --- src/backend/cairo.c | 1 + src/backend/wayland/wayland.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 0b74b4222..7f421ac8d 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -27,6 +27,7 @@ void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { cairo_set_antialias(handle.front_cairo_back, CAIRO_ANTIALIAS_NONE); cairo_set_line_cap(handle.front_cairo_back, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_width(handle.front_cairo_back, 1); cairo_set_source_rgba(handle.front_cairo_back, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); cairo_new_path(handle.front_cairo_back); for(i = 0; i < 2; i++) { diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 61546646c..0c771ab01 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1920,7 +1920,7 @@ static int MwLLWaylandCallInitImpl(void) { #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { - loadWayland = 0; + //loadWayland = 0; } #endif From bf803f0ad5b08a5cfdf44ece752de62b4adc1adb Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:20:17 +0900 Subject: [PATCH 51/90] ok --- src/backend/cairo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 7f421ac8d..38345ebc7 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -34,7 +34,7 @@ void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { if(i == 0) { cairo_move_to(handle.front_cairo_back, points[i].x, points[i].y); } else { - cairo_line_to(handle.front_cairo_back, points[i].x, points[i].y); + cairo_line_to(handle.front_cairo_back, points[i].x + 1, points[i].y + 1); } } cairo_close_path(handle.front_cairo_back); From 98536a07db9fefa608a239b7ab5d976122a43feb Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:21:14 +0900 Subject: [PATCH 52/90] fix --- src/widget/chart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/chart.c b/src/widget/chart.c index 9c87e3fce..eaaea550f 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -320,6 +320,9 @@ static void draw(MwWidget handle) { p[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; p[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; + + handle->bgcolor = type == MwCHART_3D_PIE ? colorl : color; + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); } From e73734c97bb756cd78912b86f51740da329d0bb6 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:21:37 +0900 Subject: [PATCH 53/90] revive wsl hack --- src/backend/wayland/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 0c771ab01..61546646c 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1920,7 +1920,7 @@ static int MwLLWaylandCallInitImpl(void) { #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { - //loadWayland = 0; + loadWayland = 0; } #endif From 02347fb70549f1a23e8079547c65da934e58f4e7 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:27:35 +0900 Subject: [PATCH 56/90] fix --- src/backend/cairo.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 38345ebc7..62fa6ba23 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -29,15 +29,13 @@ void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { cairo_set_line_cap(handle.front_cairo_back, CAIRO_LINE_CAP_SQUARE); cairo_set_line_width(handle.front_cairo_back, 1); cairo_set_source_rgba(handle.front_cairo_back, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); - cairo_new_path(handle.front_cairo_back); for(i = 0; i < 2; i++) { if(i == 0) { cairo_move_to(handle.front_cairo_back, points[i].x, points[i].y); } else { - cairo_line_to(handle.front_cairo_back, points[i].x + 1, points[i].y + 1); + cairo_line_to(handle.front_cairo_back, points[i].x, points[i].y); } } - cairo_close_path(handle.front_cairo_back); cairo_stroke(handle.front_cairo_back); }; From b54721a323ebe1a7fbb01522c2a846bf26c99c42 Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 07:58:11 +0900 Subject: [PATCH 57/90] wip line chart --- examples/basic/periodic.c | 14 ++++- include/Mw/Constants.h | 3 +- src/backend/cairo.c | 12 ++-- src/widget/chart.c | 129 +++++++++++++++++++++++++++----------- 4 files changed, 112 insertions(+), 46 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index adaf35b63..f7148daf2 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -294,6 +294,19 @@ int main() { MwChartAdd(w, -1, "G", 10, NULL); MwChartAdd(w, -1, "H", 20, NULL); + f = frame("Line Chart", -PaddingContent, -PaddingContent, MwChartClass, + MwNtype, MwCHART_LINE, + NULL); + w = child(f); + MwChartAdd(w, -1, "A", -800, NULL); + MwChartAdd(w, -1, "B", -400, NULL); + MwChartAdd(w, -1, "C", -200, NULL); + MwChartAdd(w, -1, "D", -100, NULL); + MwChartAdd(w, -1, "E", 100, NULL); + MwChartAdd(w, -1, "F", 200, NULL); + MwChartAdd(w, -1, "G", 400, NULL); + MwChartAdd(w, -1, "H", 800, NULL); + f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); MwComboBoxAdd(w, -1, "Hello!"); @@ -306,7 +319,6 @@ int main() { f = frame("Label", -PaddingContent, -PaddingContent, MwLabelClass, MwNtext, "Epic text\nNewline can be used too!", - MwNcolumnSpan, 2, NULL); f = frame("ListBox", -PaddingContent, -PaddingContent, MwListBoxClass, diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 6379fef4a..acd6b0539 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -117,7 +117,8 @@ enum MwCHART { MwCHART_BAR = 0, MwCHART_3D_BAR, MwCHART_PIE, - MwCHART_3D_PIE + MwCHART_3D_PIE, + MwCHART_LINE }; enum MwMOUSE { diff --git a/src/backend/cairo.c b/src/backend/cairo.c index 62fa6ba23..3683ca885 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -214,8 +214,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -259,10 +259,10 @@ static void MwLLRaiseImpl(MwLL handle) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {} static int MwLLCairoCallInitImpl(void) { - if(cairo_load_funcs() != 0) { - return 1; - } - return 0; + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; } #include "call.c" CALL(Cairo); diff --git a/src/widget/chart.c b/src/widget/chart.c index eaaea550f..d66cc6199 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -62,6 +62,19 @@ static void draw_line(MwWidget handle, const char* text, double x, double y, dou MwLLLine(handle->lowlevel, &p[0], color); } +#define CALC_VMIN_VMAX \ + if(vmin > 0) { \ + vmin = 0; \ + } else if(vmin < 0) { \ + vmin -= (double)width / r.height * (vmax - vmin); \ + } \ +\ + if(vmax < 0) { \ + vmax = 0; \ + } else if(vmax > 0) { \ + vmax += (double)width / r.height * (vmax - vmin); \ + } + static void draw(MwWidget handle) { int ColorDiff = MwGetColorDifference(handle); MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); @@ -73,13 +86,14 @@ static void draw(MwWidget handle) { int n; int gap; int width; - MwRect node; double vmin = 0xffffffff; double vmax = -0xffffffff; int space = MwTextHeight(handle, NULL, "M"); MwPoint p[2]; int type = MwGetInteger(handle, MwNtype); int modern = MwGetInteger(handle, MwNmodernLook); + double ovmin; + double ovmax; for(n = 0; colors[n] != NULL; n++); @@ -91,6 +105,9 @@ static void draw(MwWidget handle) { if(MwGetInteger(handle, MwNminValue) != MwDEFAULT) vmin = MwGetInteger(handle, MwNminValue); if(MwGetInteger(handle, MwNmaxValue) != MwDEFAULT) vmax = MwGetInteger(handle, MwNmaxValue); + ovmin = vmin; + ovmax = vmax; + r.x = 0; r.y = 0; r.width = MwGetInteger(handle, MwNwidth); @@ -98,11 +115,10 @@ static void draw(MwWidget handle) { MwDrawRect(handle, &r, base); if(type == MwCHART_BAR || type == MwCHART_3D_BAR) { - double s = 1.5; - double ovmin = vmin; - double ovmax = vmax; + double s = 1.5; double twidth; char buf[128]; + MwRect node; node.x = 0; @@ -121,20 +137,10 @@ static void draw(MwWidget handle) { width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); gap = width / s; + CALC_VMIN_VMAX; + twidth = (width + gap) * arrlen(c->entries) + gap; - if(vmin > 0) { - vmin = 0; - } else if(vmin < 0) { - vmin -= (double)width / r.height * (vmax - vmin); - } - - if(vmax < 0) { - vmax = 0; - } else if(vmax > 0) { - vmax += (double)width / r.height * (vmax - vmin); - } - sprintf(buf, NUMFMT, ovmax); draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); @@ -247,7 +253,7 @@ static void draw(MwWidget handle) { double cangle = 0; int k; double vsquish = type == MwCHART_3D_PIE ? 2 : 1; - MwPoint p[360 + 1 + 1]; + MwPoint p2[360 + 1 + 1]; for(i = 0; i < arrlen(c->entries); i++) { if(c->entries[i].value > 0) sum += c->entries[i].value; @@ -268,62 +274,62 @@ static void draw(MwWidget handle) { color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - p[0].x = r.width / 2; - p[0].y = r.height / 2; + p2[0].x = r.width / 2; + p2[0].y = r.height / 2; for(j = 0; j <= div; j++) { double a = angle / div * j; - p[div - j + 1].x = p[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; - p[div - j + 1].y = p[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2 / vsquish; + p2[div - j + 1].x = p2[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; + p2[div - j + 1].y = p2[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2 / vsquish; } count = j + 1; if((k == 0 || k == 1) && type == MwCHART_3D_PIE) { int j; - MwPoint p2[360 + 1 + 1]; + MwPoint p3[360 + 1 + 1]; int d = 0; for(d = 1; d <= 2; d++) { for(j = 0; j < count - 1; j++) { - p2[3 + j] = p[1 + j]; - p2[3 + j].y += radius / 8 / d; + p3[3 + j] = p2[1 + j]; + p3[3 + j].y += radius / 8 / d; } - p2[0] = p[count - 1]; - p2[1] = p[0]; - p2[2] = p[1]; + p3[0] = p2[count - 1]; + p3[1] = p2[0]; + p3[2] = p2[1]; if(k == 0) { - MwLLPolygon(handle->lowlevel, p2, count + 2, color); + MwLLPolygon(handle->lowlevel, p3, count + 2, color); } else if(d == 1 && k == 1) { for(j = 3; j < count + 1; j++) { - if(!modern) MwLLLine(handle->lowlevel, &p2[j], border); + if(!modern) MwLLLine(handle->lowlevel, &p3[j], border); } - p[0] = p[1]; - p[0].y += radius / 8; - if(!modern) MwLLLine(handle->lowlevel, p, border); + p2[0] = p2[1]; + p2[0].y += radius / 8; + if(!modern) MwLLLine(handle->lowlevel, p2, border); } } } if(k == 2) { - MwLLPolygon(handle->lowlevel, p, count, type == MwCHART_3D_PIE ? colorl : color); + MwLLPolygon(handle->lowlevel, p2, count, type == MwCHART_3D_PIE ? colorl : color); } else if(k == 3) { int j; - p[count] = p[0]; + p[count] = p2[0]; for(j = 0; j < count; j++) { - if(!modern) MwLLLine(handle->lowlevel, &p[j], border); + if(!modern) MwLLLine(handle->lowlevel, &p2[j], border); } - p[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; - p[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; + p2[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; + p2[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; handle->bgcolor = type == MwCHART_3D_PIE ? colorl : color; - MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + MwDrawText(handle, NULL, p2, c->entries[i].name, MwALIGNMENT_CENTER, border); } cangle += angle; @@ -341,6 +347,53 @@ static void draw(MwWidget handle) { MwLLLine(handle->lowlevel, p, border); p[0].x = p[1].x = r.width / 2 + radius / 2; + MwLLLine(handle->lowlevel, p, border); + } + } else if(type == MwCHART_LINE) { + char buf[128]; + MwRect node; + double twidth; + double x = 0; + + for(i = 0; i < arrlen(c->entries); i++) { + int w; + + sprintf(buf, NUMFMT, c->entries[i].value); + + w = MwTextWidth(handle, NULL, buf); + + if(x < w) x = w; + } + + width = 16; + twidth = r.width - x; + + CALC_VMIN_VMAX; + + sprintf(buf, NUMFMT, ovmax); + draw_line(handle, buf, x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + draw_line(handle, "0", x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + sprintf(buf, NUMFMT, ovmin); + draw_line(handle, buf, x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + draw_line(handle, "", x, (r.height - space) - (vmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + p[0].x = x; + p[0].y = 0; + + p[1] = p[0]; + p[1].y = r.height - space; + + MwLLLine(handle->lowlevel, p, border); + + for(i = 1; i < arrlen(c->entries); i++) { + p[0].x = x + (r.width - x) / (arrlen(c->entries) + 1) * i; + p[0].y = (r.height - space) - (c->entries[i - 1].value - vmin) / (vmax - vmin) * (r.height - space); + p[1].x = x + (r.width - x) / (arrlen(c->entries) + 1) * (i + 1); + p[1].y = (r.height - space) - (c->entries[i].value - vmin) / (vmax - vmin) * (r.height - space); + MwLLLine(handle->lowlevel, p, border); } } From ef7d7451341727ea8db240d8079e8d139e4c2c2e Mon Sep 17 00:00:00 2001 From: Nishi Date: Mon, 14 Sep 2026 08:59:55 +0900 Subject: [PATCH 58/90] safety and separation --- src/widget/chart.c | 629 ++++++++++++++++++++++++--------------------- 1 file changed, 334 insertions(+), 295 deletions(-) diff --git a/src/widget/chart.c b/src/widget/chart.c index d66cc6199..67753c998 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -75,25 +75,337 @@ static void draw_line(MwWidget handle, const char* text, double x, double y, dou vmax += (double)width / r.height * (vmax - vmin); \ } +static void bar_chart(MwWidget handle, MwRect* _r, double vmin, double vmax, int space, const char** colors, int n, MwLLColor border) { + int ColorDiff = MwGetColorDifference(handle); + MwChart c = handle->internal; + double s = 1.5; + double twidth; + char buf[128]; + MwRect node; + MwPoint p[2]; + int i; + int width; + int gap; + MwRect r = *_r; + double ovmin = vmin; + double ovmax = vmax; + int type = MwGetInteger(handle, MwNtype); + int modern = MwGetInteger(handle, MwNmodernLook); + + node.x = 0; + + for(i = 0; i < arrlen(c->entries); i++) { + int w; + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, c->entries[i].value); + + w = MwTextWidth(handle, NULL, buf); + + if(node.x < w) node.x = w; + } + + node.y = 0; + + width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); + gap = width / s; + + CALC_VMIN_VMAX; + + twidth = (width + gap) * arrlen(c->entries) + gap; + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, ovmax); + draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + draw_line(handle, "0", node.x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, ovmin); + draw_line(handle, buf, node.x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + p[0].x = node.x; + p[0].y = 0; + + p[1].x = node.x; + p[1].y = r.height - space; + MwLLLine(handle->lowlevel, &p[0], border); + + p[0].x = node.x; + p[0].y = r.height - space; + + p[1].x = node.x + twidth; + p[1].y = p[0].y; + MwLLLine(handle->lowlevel, &p[0], border); + + node.width = width; + for(i = 0; i < arrlen(c->entries); i++) { + MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwPoint persp_top[5]; + MwPoint persp_right[5]; + + node.x += gap; + + node.height = -c->entries[i].value / (vmax - vmin) * (r.height - space); + node.y = (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space); + + MwDrawRect(handle, &node, color); + + if(type == MwCHART_3D_BAR) { + MwRect node2 = node; + + MwFixRect(&node2); + + persp_top[0] = *(MwPoint*)&node2; + persp_top[1] = *(MwPoint*)&node2; + persp_top[1].x += node2.width; + + persp_top[2] = persp_top[1]; + persp_top[3] = persp_top[0]; + + persp_top[2].x += node2.width / 2; + persp_top[2].y -= node2.width / 2; + + persp_top[3].x += node2.width / 2; + persp_top[3].y -= node2.width / 2; + + persp_top[4] = persp_top[0]; + + MwLLPolygon(handle->lowlevel, persp_top, 4, colorl); + + persp_right[0] = *(MwPoint*)&node2; + persp_right[1] = *(MwPoint*)&node2; + persp_right[0].x += node2.width; + persp_right[1].x += node2.width; + persp_right[1].y += node2.height; + + persp_right[2] = persp_right[1]; + persp_right[3] = persp_right[0]; + + persp_right[2].x += node2.width / 2; + persp_right[2].y -= node2.width / 2; + + persp_right[3].x += node2.width / 2; + persp_right[3].y -= node2.width / 2; + + persp_right[4] = persp_right[0]; + + MwLLPolygon(handle->lowlevel, persp_right, 4, colord); + } + + if(!modern) { + MwDrawRectLine(handle, &node, border); + + if(type == MwCHART_3D_BAR) { + MwLLLine(handle->lowlevel, &persp_top[0], border); + MwLLLine(handle->lowlevel, &persp_top[1], border); + MwLLLine(handle->lowlevel, &persp_top[2], border); + MwLLLine(handle->lowlevel, &persp_top[3], border); + + MwLLLine(handle->lowlevel, &persp_right[0], border); + MwLLLine(handle->lowlevel, &persp_right[1], border); + MwLLLine(handle->lowlevel, &persp_right[2], border); + MwLLLine(handle->lowlevel, &persp_right[3], border); + } + } + + p[0].x = node.x + node.width / 2; + p[0].y = r.height - space / 2; + + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + + node.x += node.width; + + MwLLFreeColor(colord); + MwLLFreeColor(colorl); + MwLLFreeColor(color); + } +} + +static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, MwLLColor border) { + int ColorDiff = MwGetColorDifference(handle); + MwChart c = handle->internal; + double sum = 0; + MwRect r = *_r; + int radius = r.width < r.height ? r.width : r.height; + double cangle = 0; + int k; + int type = MwGetInteger(handle, MwNtype); + int modern = MwGetInteger(handle, MwNmodernLook); + double vsquish = type == MwCHART_3D_PIE ? 2 : 1; + int i; + MwPoint p[2]; + MwPoint p2[360 + 1 + 1]; + + for(i = 0; i < arrlen(c->entries); i++) { + if(c->entries[i].value > 0) sum += c->entries[i].value; + } + + for(k = 0; k < 4; k++) { + for(i = 0; i < arrlen(c->entries); i++) { + MwLLColor color; + MwLLColor colorl; + double angle = c->entries[i].value / sum * 360; + int div = angle / PIE_DIV; + int j; + int count; + + if(c->entries[i].value <= 0) continue; + if((k == 0 || k == 1) && type == MwCHART_PIE) continue; + + color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + + p2[0].x = r.width / 2; + p2[0].y = r.height / 2; + for(j = 0; j <= div; j++) { + double a = angle / div * j; + + p2[div - j + 1].x = p2[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; + p2[div - j + 1].y = p2[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2 / vsquish; + } + + count = j + 1; + + if((k == 0 || k == 1) && type == MwCHART_3D_PIE) { + int j; + MwPoint p3[360 + 1 + 1]; + int d = 0; + + for(d = 1; d <= 2; d++) { + for(j = 0; j < count - 1; j++) { + p3[3 + j] = p2[1 + j]; + p3[3 + j].y += radius / 8 / d; + } + + p3[0] = p2[count - 1]; + p3[1] = p2[0]; + p3[2] = p2[1]; + + if(k == 0) { + MwLLPolygon(handle->lowlevel, p3, count + 2, color); + } else if(d == 1 && k == 1) { + for(j = 3; j < count + 1; j++) { + if(!modern) MwLLLine(handle->lowlevel, &p3[j], border); + } + + p2[0] = p2[1]; + p2[0].y += radius / 8; + if(!modern) MwLLLine(handle->lowlevel, p2, border); + } + } + } + + if(k == 2) { + MwLLPolygon(handle->lowlevel, p2, count, type == MwCHART_3D_PIE ? colorl : color); + } else if(k == 3) { + int j; + + p2[count] = p2[0]; + for(j = 0; j < count; j++) { + if(!modern) MwLLLine(handle->lowlevel, &p2[j], border); + } + + p2[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; + p2[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; + + handle->bgcolor = type == MwCHART_3D_PIE ? colorl : color; + + MwDrawText(handle, NULL, p2, c->entries[i].name, MwALIGNMENT_CENTER, border); + } + + cangle += angle; + + MwLLFreeColor(colorl); + MwLLFreeColor(color); + } + } + + if(!modern && type == MwCHART_3D_PIE) { + p[0].x = r.width / 2 - radius / 2; + p[0].y = r.height / 2; + p[1] = p[0]; + p[1].y += radius / 8; + MwLLLine(handle->lowlevel, p, border); + + p[0].x = p[1].x = r.width / 2 + radius / 2; + MwLLLine(handle->lowlevel, p, border); + } +} + +static void line_chart(MwWidget handle, MwRect* _r, double vmin, double vmax, int space, MwLLColor border) { + MwChart c = handle->internal; + char buf[128]; + double twidth; + double x = 0; + int j; + MwPoint p[2]; + MwRect r = *_r; + double ovmin = vmin; + double ovmax = vmax; + int i; + int width; + + for(i = 0; i < arrlen(c->entries); i++) { + int w; + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, c->entries[i].value); + + w = MwTextWidth(handle, NULL, buf); + + if(x < w) x = w; + } + + width = 16; + twidth = r.width - x; + + CALC_VMIN_VMAX; + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, ovmax); + draw_line(handle, buf, x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + draw_line(handle, "0", x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + MwStringPrintIntoBuffer(buf, sizeof(buf), NUMFMT, ovmin); + draw_line(handle, buf, x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + draw_line(handle, "", x, (r.height - space) - (vmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); + + p[0].x = x; + p[0].y = 0; + + p[1] = p[0]; + p[1].y = r.height - space; + + MwLLLine(handle->lowlevel, p, border); + + for(j = 0; j < 2; j++) { + for(i = j == 0 ? 1 : 0; i < arrlen(c->entries); i++) { + p[0].x = x + (r.width - x) / (arrlen(c->entries) + 1) * i; + p[0].y = (r.height - space) - (c->entries[i - 1].value - vmin) / (vmax - vmin) * (r.height - space); + p[1].x = x + (r.width - x) / (arrlen(c->entries) + 1) * (i + 1); + p[1].y = (r.height - space) - (c->entries[i].value - vmin) / (vmax - vmin) * (r.height - space); + + if(j == 0) { + MwLLLine(handle->lowlevel, p, border); + } else { + MwDrawText(handle, NULL, &p[1], c->entries[i].name, MwALIGNMENT_CENTER, border); + } + } + } +} + static void draw(MwWidget handle) { - int ColorDiff = MwGetColorDifference(handle); - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); MwRect r; MwChart c = handle->internal; int i; const char** colors = palette0; int n; - int gap; - int width; double vmin = 0xffffffff; double vmax = -0xffffffff; int space = MwTextHeight(handle, NULL, "M"); - MwPoint p[2]; - int type = MwGetInteger(handle, MwNtype); - int modern = MwGetInteger(handle, MwNmodernLook); - double ovmin; - double ovmax; + int type = MwGetInteger(handle, MwNtype); for(n = 0; colors[n] != NULL; n++); @@ -105,297 +417,24 @@ static void draw(MwWidget handle) { if(MwGetInteger(handle, MwNminValue) != MwDEFAULT) vmin = MwGetInteger(handle, MwNminValue); if(MwGetInteger(handle, MwNmaxValue) != MwDEFAULT) vmax = MwGetInteger(handle, MwNmaxValue); - ovmin = vmin; - ovmax = vmax; - r.x = 0; r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); - if(type == MwCHART_BAR || type == MwCHART_3D_BAR) { - double s = 1.5; - double twidth; - char buf[128]; - MwRect node; - - node.x = 0; - - for(i = 0; i < arrlen(c->entries); i++) { - int w; - - sprintf(buf, NUMFMT, c->entries[i].value); - - w = MwTextWidth(handle, NULL, buf); - - if(node.x < w) node.x = w; - } - - node.y = 0; - - width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); - gap = width / s; - - CALC_VMIN_VMAX; - - twidth = (width + gap) * arrlen(c->entries) + gap; - - sprintf(buf, NUMFMT, ovmax); - draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - draw_line(handle, "0", node.x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - sprintf(buf, NUMFMT, ovmin); - draw_line(handle, buf, node.x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - p[0].x = node.x; - p[0].y = 0; - - p[1].x = node.x; - p[1].y = r.height - space; - MwLLLine(handle->lowlevel, &p[0], border); - - p[0].x = node.x; - p[0].y = r.height - space; - - p[1].x = node.x + twidth; - p[1].y = p[0].y; - MwLLLine(handle->lowlevel, &p[0], border); - - node.width = width; - for(i = 0; i < arrlen(c->entries); i++) { - MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); - MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); - MwPoint persp_top[5]; - MwPoint persp_right[5]; - - node.x += gap; - - node.height = -c->entries[i].value / (vmax - vmin) * (r.height - space); - node.y = (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space); - - MwDrawRect(handle, &node, color); - - if(type == MwCHART_3D_BAR) { - MwRect node2 = node; - - MwFixRect(&node2); - - persp_top[0] = *(MwPoint*)&node2; - persp_top[1] = *(MwPoint*)&node2; - persp_top[1].x += node2.width; - - persp_top[2] = persp_top[1]; - persp_top[3] = persp_top[0]; - - persp_top[2].x += node2.width / 2; - persp_top[2].y -= node2.width / 2; - - persp_top[3].x += node2.width / 2; - persp_top[3].y -= node2.width / 2; - - persp_top[4] = persp_top[0]; - - MwLLPolygon(handle->lowlevel, persp_top, 4, colorl); - - persp_right[0] = *(MwPoint*)&node2; - persp_right[1] = *(MwPoint*)&node2; - persp_right[0].x += node2.width; - persp_right[1].x += node2.width; - persp_right[1].y += node2.height; - - persp_right[2] = persp_right[1]; - persp_right[3] = persp_right[0]; - - persp_right[2].x += node2.width / 2; - persp_right[2].y -= node2.width / 2; - - persp_right[3].x += node2.width / 2; - persp_right[3].y -= node2.width / 2; - - persp_right[4] = persp_right[0]; - - MwLLPolygon(handle->lowlevel, persp_right, 4, colord); - } - - if(!modern) { - MwDrawRectLine(handle, &node, border); - - if(type == MwCHART_3D_BAR) { - MwLLLine(handle->lowlevel, &persp_top[0], border); - MwLLLine(handle->lowlevel, &persp_top[1], border); - MwLLLine(handle->lowlevel, &persp_top[2], border); - MwLLLine(handle->lowlevel, &persp_top[3], border); - - MwLLLine(handle->lowlevel, &persp_right[0], border); - MwLLLine(handle->lowlevel, &persp_right[1], border); - MwLLLine(handle->lowlevel, &persp_right[2], border); - MwLLLine(handle->lowlevel, &persp_right[3], border); - } - } - - p[0].x = node.x + node.width / 2; - p[0].y = r.height - space / 2; - - MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); - - node.x += node.width; - - MwLLFreeColor(colord); - MwLLFreeColor(colorl); - MwLLFreeColor(color); - } - } else if(type == MwCHART_PIE || type == MwCHART_3D_PIE) { - double sum = 0; - int radius = r.width < r.height ? r.width : r.height; - double cangle = 0; - int k; - double vsquish = type == MwCHART_3D_PIE ? 2 : 1; - MwPoint p2[360 + 1 + 1]; - - for(i = 0; i < arrlen(c->entries); i++) { - if(c->entries[i].value > 0) sum += c->entries[i].value; - } - - for(k = 0; k < 4; k++) { - for(i = 0; i < arrlen(c->entries); i++) { - MwLLColor color; - MwLLColor colorl; - double angle = c->entries[i].value / sum * 360; - int div = angle / PIE_DIV; - int j; - int count; - - if(c->entries[i].value <= 0) continue; - if((k == 0 || k == 1) && type == MwCHART_PIE) continue; - - color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); - colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); - - p2[0].x = r.width / 2; - p2[0].y = r.height / 2; - for(j = 0; j <= div; j++) { - double a = angle / div * j; - - p2[div - j + 1].x = p2[0].x + cos((cangle + a - 90) / 180 * M_PI) * radius / 2; - p2[div - j + 1].y = p2[0].y + sin((cangle + a - 90) / 180 * M_PI) * radius / 2 / vsquish; - } - - count = j + 1; - - if((k == 0 || k == 1) && type == MwCHART_3D_PIE) { - int j; - MwPoint p3[360 + 1 + 1]; - int d = 0; - - for(d = 1; d <= 2; d++) { - for(j = 0; j < count - 1; j++) { - p3[3 + j] = p2[1 + j]; - p3[3 + j].y += radius / 8 / d; - } - - p3[0] = p2[count - 1]; - p3[1] = p2[0]; - p3[2] = p2[1]; - - if(k == 0) { - MwLLPolygon(handle->lowlevel, p3, count + 2, color); - } else if(d == 1 && k == 1) { - for(j = 3; j < count + 1; j++) { - if(!modern) MwLLLine(handle->lowlevel, &p3[j], border); - } - - p2[0] = p2[1]; - p2[0].y += radius / 8; - if(!modern) MwLLLine(handle->lowlevel, p2, border); - } - } - } - - if(k == 2) { - MwLLPolygon(handle->lowlevel, p2, count, type == MwCHART_3D_PIE ? colorl : color); - } else if(k == 3) { - int j; - - p[count] = p2[0]; - for(j = 0; j < count; j++) { - if(!modern) MwLLLine(handle->lowlevel, &p2[j], border); - } - - p2[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; - p2[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; - - handle->bgcolor = type == MwCHART_3D_PIE ? colorl : color; - - MwDrawText(handle, NULL, p2, c->entries[i].name, MwALIGNMENT_CENTER, border); - } - - cangle += angle; - - MwLLFreeColor(colorl); - MwLLFreeColor(color); - } - } - - if(!modern && type == MwCHART_3D_PIE) { - p[0].x = r.width / 2 - radius / 2; - p[0].y = r.height / 2; - p[1] = p[0]; - p[1].y += radius / 8; - MwLLLine(handle->lowlevel, p, border); - - p[0].x = p[1].x = r.width / 2 + radius / 2; - MwLLLine(handle->lowlevel, p, border); - } - } else if(type == MwCHART_LINE) { - char buf[128]; - MwRect node; - double twidth; - double x = 0; - - for(i = 0; i < arrlen(c->entries); i++) { - int w; - - sprintf(buf, NUMFMT, c->entries[i].value); - - w = MwTextWidth(handle, NULL, buf); - - if(x < w) x = w; - } - - width = 16; - twidth = r.width - x; - - CALC_VMIN_VMAX; - - sprintf(buf, NUMFMT, ovmax); - draw_line(handle, buf, x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - draw_line(handle, "0", x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - sprintf(buf, NUMFMT, ovmin); - draw_line(handle, buf, x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - draw_line(handle, "", x, (r.height - space) - (vmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - - p[0].x = x; - p[0].y = 0; - - p[1] = p[0]; - p[1].y = r.height - space; - - MwLLLine(handle->lowlevel, p, border); - - for(i = 1; i < arrlen(c->entries); i++) { - p[0].x = x + (r.width - x) / (arrlen(c->entries) + 1) * i; - p[0].y = (r.height - space) - (c->entries[i - 1].value - vmin) / (vmax - vmin) * (r.height - space); - p[1].x = x + (r.width - x) / (arrlen(c->entries) + 1) * (i + 1); - p[1].y = (r.height - space) - (c->entries[i].value - vmin) / (vmax - vmin) * (r.height - space); - - MwLLLine(handle->lowlevel, p, border); - } + switch(type) { + case MwCHART_BAR: + case MwCHART_3D_BAR: + bar_chart(handle, &r, vmin, vmax, space, colors, n, border); + break; + case MwCHART_PIE: + case MwCHART_3D_PIE: + pie_chart(handle, &r, colors, n, border); + break; + case MwCHART_LINE: + line_chart(handle, &r, vmin, vmax, space, border); + break; } MwLLFreeColor(border); From 8d3b707d9e598e9ef08b8edac7d365662c3d0ba2 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:14:36 +0900 Subject: [PATCH 59/90] ok --- NTMakefile | 6 +- WatMakefile | 10 +- examples/basic/document.c | 45 + external/md4c.c | 7386 ++++++++++++++++++++++++++++++++++ external/md4c.h | 495 +++ include/Mw/Milsko.h | 1 + include/Mw/StringDefs.h | 1 + include/Mw/Widget/Document.h | 24 + milsko.xml | 1 + pl/rules.pl | 2 + src/widget/document.c | 54 + tools/genmk.pl | 2 +- 12 files changed, 8022 insertions(+), 5 deletions(-) create mode 100644 examples/basic/document.c create mode 100644 external/md4c.c create mode 100644 external/md4c.h create mode 100644 include/Mw/Widget/Document.h create mode 100644 src/widget/document.c diff --git a/NTMakefile b/NTMakefile index 2d41468ed..d0fc4638a 100644 --- a/NTMakefile +++ b/NTMakefile @@ -25,6 +25,7 @@ clean: del /f /q external\libz\src\trees.obj del /f /q external\libz\src\uncompr.obj del /f /q external\libz\src\zutil.obj + del /f /q external\md4c.obj del /f /q external\stb_ds.obj del /f /q external\stb_image.obj del /f /q external\stb_truetype.obj @@ -83,6 +84,7 @@ clean: del /f /q src\widget\checkbox.obj del /f /q src\widget\clock.obj del /f /q src\widget\combobox.obj + del /f /q src\widget\document.obj del /f /q src\widget\entry.obj del /f /q src\widget\frame.obj del /f /q src\widget\image.obj @@ -322,8 +324,8 @@ examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c -src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib +src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib .c.obj: diff --git a/WatMakefile b/WatMakefile index 0b4f73a50..ce6792bfa 100644 --- a/WatMakefile +++ b/WatMakefile @@ -24,6 +24,7 @@ clean: .SYMBOLIC %erase external/libz/src/trees.obj %erase external/libz/src/uncompr.obj %erase external/libz/src/zutil.obj + %erase external/md4c.obj %erase external/stb_ds.obj %erase external/stb_image.obj %erase external/stb_truetype.obj @@ -82,6 +83,7 @@ clean: .SYMBOLIC %erase src/widget/checkbox.obj %erase src/widget/clock.obj %erase src/widget/combobox.obj + %erase src/widget/document.obj %erase src/widget/entry.obj %erase src/widget/frame.obj %erase src/widget/image.obj @@ -321,8 +323,8 @@ examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c -src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/chart.obj src/widget/checkbox.obj src/widget/clock.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/chart.obj file src/widget/checkbox.obj file src/widget/clock.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib +src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/md4c.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/chart.obj src/widget/checkbox.obj src/widget/clock.obj src/widget/combobox.obj src/widget/document.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/md4c.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/chart.obj file src/widget/checkbox.obj file src/widget/clock.obj file src/widget/combobox.obj file src/widget/document.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib @@ -356,6 +358,8 @@ external/libz/src/uncompr.obj: external/libz/src/uncompr.c $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/uncompr.c external/libz/src/zutil.obj: external/libz/src/zutil.c $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/zutil.c +external/md4c.obj: external/md4c.c + $(CC) $(MW_CFLAGS) -fo=$@ external/md4c.c external/stb_ds.obj: external/stb_ds.c $(CC) $(MW_CFLAGS) -fo=$@ external/stb_ds.c external/stb_image.obj: external/stb_image.c @@ -472,6 +476,8 @@ src/widget/clock.obj: src/widget/clock.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/clock.c src/widget/combobox.obj: src/widget/combobox.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/combobox.c +src/widget/document.obj: src/widget/document.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/document.c src/widget/entry.obj: src/widget/entry.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/entry.c src/widget/frame.obj: src/widget/frame.c diff --git a/examples/basic/document.c b/examples/basic/document.c new file mode 100644 index 000000000..e53339c78 --- /dev/null +++ b/examples/basic/document.c @@ -0,0 +1,45 @@ +#include + +MwWidget window, viewport, document; + +static void MWAPI resize_window(MwWidget handle, void* user, void* call) { + int width = MwGetInteger(window, MwNwidth); + int height = MwGetInteger(window, MwNheight); + + MwVaApply(viewport, + MwNx, 10, + MwNy, 10, + MwNwidth, width - 20, + MwNheight, height - 20, + NULL); +} + +static void MWAPI resize_document(MwWidget handle, void* user, void* call) { + MwViewportSetSize(viewport, MwGetInteger(document, MwNwidth), MwGetInteger(document, MwNheight)); +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, + MwNtitle, "markdown document", + NULL); + + viewport = MwCreateWidget(MwViewportClass, "viewport", window, 0, 0, 0, 0); + + MwVaApply(MwGetParent(MwViewportGetViewport(viewport)), + MwNbackground, "#fff", + MwNforeground, "#000", + NULL); + + document = MwVaCreateWidget(MwDocumentClass, "document", MwViewportGetViewport(viewport), 0, 0, 0, 0, + MwNtext, "# Hello world!\nThis is a test text...", + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize_window, NULL); + MwAddUserHandler(document, MwNresizeHandler, resize_document, NULL); + + resize_window(window, NULL, NULL); + + MwLoop(window); +} diff --git a/external/md4c.c b/external/md4c.c new file mode 100644 index 000000000..22ab420d1 --- /dev/null +++ b/external/md4c.c @@ -0,0 +1,7386 @@ +/* + * MD4C: Markdown parser for C + * (https://github.com/mity/md4c) + * + * Copyright (c) 2016-2026 Martin Mitáš + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "md4c.h" + + +/***************************** + *** Miscellaneous Stuff *** + *****************************/ + +/* Make the UTF-8 support the default. */ +#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16 + #define MD4C_USE_UTF8 +#endif + +/* Magic for making wide literals with MD4C_USE_UTF16. */ +#ifdef _T + #undef _T +#endif +#if defined MD4C_USE_UTF16 + #define _T(x) L##x +#else + #define _T(x) x +#endif + +/* Misc. macros. */ +#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) + +#define STRINGIZE_(x) #x +#define STRINGIZE(x) STRINGIZE_(x) + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define MD_LOG(msg) \ + do { \ + if(ctx->parser.debug_log != NULL) \ + ctx->parser.debug_log((msg), ctx->userdata); \ + } while(0) + +#ifdef DEBUG + #define MD_ASSERT(cond) \ + do { \ + if(!(cond)) { \ + MD_LOG(__FILE__ ":" STRINGIZE(__LINE__) ": " \ + "Assertion '" STRINGIZE(cond) "' failed."); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + + #define MD_UNREACHABLE() MD_ASSERT(1 == 0) +#else + #ifdef __GNUC__ + #define MD_ASSERT(cond) do { if(!(cond)) __builtin_unreachable(); } while(0) + #define MD_UNREACHABLE() do { __builtin_unreachable(); } while(0) + #elif defined _MSC_VER && _MSC_VER > 120 + #define MD_ASSERT(cond) do { __assume(cond); } while(0) + #define MD_UNREACHABLE() do { __assume(0); } while(0) + #else + #define MD_ASSERT(cond) do {} while(0) + #define MD_UNREACHABLE() do {} while(0) + #endif +#endif + +/* For falling through case labels in switch statements. */ +#if defined __clang__ && __clang_major__ >= 12 + #define MD_FALLTHROUGH() ;__attribute__((fallthrough)) +#elif defined __GNUC__ && __GNUC__ >= 7 + #define MD_FALLTHROUGH() ;__attribute__((fallthrough)) +#else + #define MD_FALLTHROUGH() ((void)0) +#endif + +/* Suppress "unused parameter" warnings. */ +#define MD_UNUSED(x) ((void)x) + + +/****************************** + *** Some internal limits *** + ******************************/ + +/* We limit code span marks to lower than 32 backticks. This solves the + * pathologic case of too many openers, each of different length: Their + * resolving would be then O(n^2). */ +#define CODESPAN_MARK_MAXLEN 32 + + +/************************ + *** Internal Types *** + ************************/ + +/* These are omnipresent so lets save some typing. */ +#define CHAR MD_CHAR +#define SZ MD_SIZE +#define OFF MD_OFFSET + +typedef struct MD_MARK_tag MD_MARK; +typedef struct MD_BLOCK_tag MD_BLOCK; +typedef struct MD_CONTAINER_tag MD_CONTAINER; +typedef struct MD_REF_DEF_tag MD_REF_DEF; +typedef struct MD_FOOTNOTE_DEF_tag MD_FOOTNOTE_DEF; + +/* Forward declaration; full definition is below with MD_LINE_tag. */ +typedef struct MD_LINE_tag MD_LINE; + +typedef struct MD_LABEL_HASH_ENTRY_tag MD_LABEL_HASH_ENTRY; +struct MD_LABEL_HASH_ENTRY_tag { + const CHAR* label; + SZ label_size; + unsigned hash; +}; + +typedef struct MD_LABEL_HASH_TABLE_tag MD_LABEL_HASH_TABLE; +struct MD_LABEL_HASH_TABLE_tag { + /* Flat array of all records. */ + union { + void* defs; + MD_REF_DEF* ref_defs; + MD_FOOTNOTE_DEF* footnote_defs; + }; + unsigned def_size; + unsigned n_defs; + unsigned alloc_defs; + + /* The hashtable itself, where the actual entries are pointers into the + * array defs[] above. */ + void** buckets; + unsigned n_buckets; +}; + + +/* During analyzes of inline marks, we need to manage stacks of unresolved + * openers of the given type. + * The stack connects the marks via MD_MARK::next; + */ +typedef struct MD_MARKSTACK_tag MD_MARKSTACK; +struct MD_MARKSTACK_tag { + int top; /* -1 if empty. */ +}; + +/* Context propagated through all the parsing. */ +typedef struct MD_CTX_tag MD_CTX; +struct MD_CTX_tag { + /* Immutable stuff (parameters of md_parse()). */ + const CHAR* text; + SZ size; + MD_PARSER parser; + void* userdata; + + /* When this is true, it allows some optimizations. */ + int doc_ends_with_newline; + + /* Helper temporary growing buffer. */ + CHAR* buffer; + unsigned alloc_buffer; + + /* Reference definitions. */ + MD_LABEL_HASH_TABLE ref_def_hashtable; + SZ max_ref_def_output; + + /* Footnote definitions. */ + MD_LABEL_HASH_TABLE footnote_hashtable; + unsigned next_footnote_index; /* 1-based counter for sequential numbering */ + + /* Stack of inline/span markers. + * This is only used for parsing a single block contents but by storing it + * here we may reuse the stack for subsequent blocks; i.e. we have fewer + * (re)allocations. */ + MD_MARK* marks; + int n_marks; + int alloc_marks; + +#if defined MD4C_USE_UTF16 + char mark_char_map[128]; +#else + char mark_char_map[256]; +#endif + + /* For resolving of inline spans. */ + MD_MARKSTACK opener_stacks[20]; +#define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0]) /* Opener-only */ +#define ASTERISK_OPENERS_oo_mod3_1 (ctx->opener_stacks[1]) +#define ASTERISK_OPENERS_oo_mod3_2 (ctx->opener_stacks[2]) +#define ASTERISK_OPENERS_oc_mod3_0 (ctx->opener_stacks[3]) /* Both opener and closer candidate */ +#define ASTERISK_OPENERS_oc_mod3_1 (ctx->opener_stacks[4]) +#define ASTERISK_OPENERS_oc_mod3_2 (ctx->opener_stacks[5]) +#define UNDERSCORE_OPENERS_oo_mod3_0 (ctx->opener_stacks[6]) /* Opener-only */ +#define UNDERSCORE_OPENERS_oo_mod3_1 (ctx->opener_stacks[7]) +#define UNDERSCORE_OPENERS_oo_mod3_2 (ctx->opener_stacks[8]) +#define UNDERSCORE_OPENERS_oc_mod3_0 (ctx->opener_stacks[9]) /* Both opener and closer candidate */ +#define UNDERSCORE_OPENERS_oc_mod3_1 (ctx->opener_stacks[10]) +#define UNDERSCORE_OPENERS_oc_mod3_2 (ctx->opener_stacks[11]) +#define TILDE_OPENERS_1 (ctx->opener_stacks[12]) +#define TILDE_OPENERS_2 (ctx->opener_stacks[13]) +#define BRACKET_OPENERS (ctx->opener_stacks[14]) +#define DOLLAR_OPENERS (ctx->opener_stacks[15]) +#define PIPE_OPENERS (ctx->opener_stacks[16]) +#define CARET_OPENERS (ctx->opener_stacks[17]) +#define EQUAL_OPENERS (ctx->opener_stacks[18]) +#define PLUS_OPENERS (ctx->opener_stacks[19]) + + /* Stack of dummies which need to call free() for pointers stored in them. + * These are constructed during inline parsing and freed after all the block + * is processed (i.e. all callbacks referring those strings are called). */ + MD_MARKSTACK ptr_stack; + + /* For resolving table rows. */ + int n_table_cell_boundaries; + int table_cell_boundaries_head; + int table_cell_boundaries_tail; + + /* For resolving links. */ + int unresolved_link_head; + int unresolved_link_tail; + + /* For resolving raw HTML. */ + OFF html_comment_horizon; + OFF html_proc_instr_horizon; + OFF html_decl_horizon; + OFF html_cdata_horizon; + + /* For block analysis. + * Notes: + * -- It holds MD_BLOCK as well as MD_LINE structures. After each + * MD_BLOCK, its (multiple) MD_LINE(s) follow. + * -- For MD_BLOCK_HTML and MD_BLOCK_CODE, MD_VERBATIMLINE(s) are used + * instead of MD_LINE(s). + */ + void* block_bytes; + MD_BLOCK* current_block; + int n_block_bytes; + int alloc_block_bytes; + + /* Pending count of blank lines not yet reported as MD_BLOCK_BLANK. + * Used only with MD_FLAG_PRESERVEBLANKLINES. */ + unsigned n_blank_lines; + + /* For container block analysis. */ + MD_CONTAINER* containers; + int n_containers; + int alloc_containers; + + /* Minimal indentation to call the block "indented code block". */ + unsigned code_indent_offset; + + /* Contextual info for line analysis. */ + SZ code_fence_length; /* For checking closing fence length. */ + int html_block_type; /* For checking closing raw HTML condition. */ + int last_line_has_list_loosening_effect; + int consecutive_blank_lines; +}; + +enum MD_LINETYPE_tag { + MD_LINE_BLANK, + MD_LINE_HR, + MD_LINE_ATXHEADER, + MD_LINE_SETEXTHEADER, + MD_LINE_SETEXTUNDERLINE, + MD_LINE_INDENTEDCODE, + MD_LINE_FENCEDCODE, + MD_LINE_HTML, + MD_LINE_TEXT, + MD_LINE_TABLE, + MD_LINE_TABLEUNDERLINE +}; +typedef enum MD_LINETYPE_tag MD_LINETYPE; + +typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS; +struct MD_LINE_ANALYSIS_tag { + MD_LINETYPE type; + unsigned data; + int enforce_new_block; + OFF beg; + OFF end; + unsigned indent; /* Indentation level. */ +}; + +struct MD_LINE_tag { + OFF beg; + OFF end; +}; + +typedef struct MD_VERBATIMLINE_tag MD_VERBATIMLINE; +struct MD_VERBATIMLINE_tag { + OFF beg; + OFF end; + OFF indent; +}; + + +/***************** + *** Helpers *** + *****************/ + +/* Character accessors. */ +#define CH(off) (ctx->text[(off)]) +#define STR(off) (ctx->text + (off)) + +/* Character classification. + * Note we assume ASCII compatibility of code points < 128 here. */ +#define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max)) +#define ISANYOF_(ch, palette) ((ch) != _T('\0') && md_strchr((palette), (ch)) != NULL) +#define ISANYOF2_(ch, ch1, ch2) ((ch) == (ch1) || (ch) == (ch2)) +#define ISANYOF3_(ch, ch1, ch2, ch3) ((ch) == (ch1) || (ch) == (ch2) || (ch) == (ch3)) +#define ISASCII_(ch) ((unsigned)(ch) <= 127) +#define ISBLANK_(ch) (ISANYOF2_((ch), _T(' '), _T('\t'))) +#define ISNEWLINE_(ch) (ISANYOF2_((ch), _T('\r'), _T('\n'))) +#define ISWHITESPACE_(ch) (ISBLANK_(ch) || ISANYOF2_((ch), _T('\v'), _T('\f'))) +#define ISCNTRL_(ch) ((unsigned)(ch) <= 31 || (unsigned)(ch) == 127) +#define ISPUNCT_(ch) (ISIN_(ch, 33, 47) || ISIN_(ch, 58, 64) || ISIN_(ch, 91, 96) || ISIN_(ch, 123, 126)) +#define ISUPPER_(ch) (ISIN_(ch, _T('A'), _T('Z'))) +#define ISLOWER_(ch) (ISIN_(ch, _T('a'), _T('z'))) +#define ISALPHA_(ch) (ISUPPER_(ch) || ISLOWER_(ch)) +#define ISDIGIT_(ch) (ISIN_(ch, _T('0'), _T('9'))) +#define ISXDIGIT_(ch) (ISDIGIT_(ch) || ISIN_(ch, _T('A'), _T('F')) || ISIN_(ch, _T('a'), _T('f'))) +#define ISALNUM_(ch) (ISALPHA_(ch) || ISDIGIT_(ch)) + +#define ISANYOF(off, palette) ISANYOF_(CH(off), (palette)) +#define ISANYOF2(off, ch1, ch2) ISANYOF2_(CH(off), (ch1), (ch2)) +#define ISANYOF3(off, ch1, ch2, ch3) ISANYOF3_(CH(off), (ch1), (ch2), (ch3)) +#define ISASCII(off) ISASCII_(CH(off)) +#define ISBLANK(off) ISBLANK_(CH(off)) +#define ISNEWLINE(off) ISNEWLINE_(CH(off)) +#define ISWHITESPACE(off) ISWHITESPACE_(CH(off)) +#define ISCNTRL(off) ISCNTRL_(CH(off)) +#define ISPUNCT(off) ISPUNCT_(CH(off)) +#define ISUPPER(off) ISUPPER_(CH(off)) +#define ISLOWER(off) ISLOWER_(CH(off)) +#define ISALPHA(off) ISALPHA_(CH(off)) +#define ISDIGIT(off) ISDIGIT_(CH(off)) +#define ISXDIGIT(off) ISXDIGIT_(CH(off)) +#define ISALNUM(off) ISALNUM_(CH(off)) + + +#if defined MD4C_USE_UTF16 + #define md_strchr wcschr + #define md_strlen wcslen +#else + #define md_strchr strchr + #define md_strlen strlen +#endif + + +/* Case insensitive check of string equality. */ +static inline int +md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + OFF i; + for(i = 0; i < n; i++) { + CHAR ch1 = s1[i]; + CHAR ch2 = s2[i]; + + if(ISLOWER_(ch1)) + ch1 += ('A'-'a'); + if(ISLOWER_(ch2)) + ch2 += ('A'-'a'); + if(ch1 != ch2) + return false; + } + return true; +} + +static inline int +md_ascii_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + return memcmp(s1, s2, n * sizeof(CHAR)) == 0; +} + +static int +md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ size) +{ + OFF off = 0; + int ret = 0; + + while(1) { + while(off < size && str[off] != _T('\0')) + off++; + + if(off > 0) { + ret = ctx->parser.text(type, str, off, ctx->userdata); + if(ret != 0) + return ret; + + str += off; + size -= off; + off = 0; + } + + if(off >= size) + return 0; + + ret = ctx->parser.text(MD_TEXT_NULLCHAR, _T(""), 1, ctx->userdata); + if(ret != 0) + return ret; + off++; + } +} + + +#define MD_CHECK(func) \ + do { \ + ret = (func); \ + if(ret != 0) \ + goto abort; \ + } while(0) + + +#define MD_TEMP_BUFFER(sz) \ + do { \ + if(sz > ctx->alloc_buffer) { \ + CHAR* new_buffer; \ + SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ + \ + new_buffer = realloc(ctx->buffer, new_size); \ + if(new_buffer == NULL) { \ + MD_LOG("realloc() failed."); \ + ret = -1; \ + goto abort; \ + } \ + \ + ctx->buffer = new_buffer; \ + ctx->alloc_buffer = new_size; \ + } \ + } while(0) + + +#define MD_ENTER_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_ENTER_SPAN(type, arg) \ + do { \ + ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_SPAN(type, arg) \ + do { \ + ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_TEXT(type, str, size) \ + do { \ + if(size > 0) { \ + ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + +#define MD_TEXT_INSECURE(type, str, size) \ + do { \ + if(size > 0) { \ + ret = md_text_with_null_replacement(ctx, type, str, size); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + + +/* If the offset falls into a gap between line, we return the following + * line. */ +static const MD_LINE* +md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_index) +{ + MD_SIZE lo, hi; + MD_SIZE pivot; + const MD_LINE* line; + + lo = 0; + hi = n_lines - 1; + while(lo <= hi) { + pivot = (lo + hi) / 2; + line = &lines[pivot]; + + if(off < line->beg) { + if(hi == 0 || lines[hi-1].end < off) { + if(p_line_index != NULL) + *p_line_index = pivot; + return line; + } + hi = pivot - 1; + } else if(off > line->end) { + lo = pivot + 1; + } else { + if(p_line_index != NULL) + *p_line_index = pivot; + return line; + } + } + + return NULL; +} + + +/************************* + *** Unicode Support *** + *************************/ + +typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO; +struct MD_UNICODE_FOLD_INFO_tag { + unsigned codepoints[3]; + unsigned n_codepoints; +}; + + +#if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8 + /* Binary search over sorted "map" of codepoints. Consecutive sequences + * of codepoints may be encoded in the map by just using the + * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000). + * + * Returns index of the found record in the map (in the case of ranges, + * the minimal value is used); or -1 on failure. */ + static int + md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size) + { + int beg, end; + int pivot_beg, pivot_end; + + beg = 0; + end = (int) map_size-1; + while(beg <= end) { + /* Pivot may be a range, not just a single value. */ + pivot_beg = pivot_end = (beg + end) / 2; + if(map[pivot_end] & 0x40000000) + pivot_end++; + if(map[pivot_beg] & 0x80000000) + pivot_beg--; + + if(codepoint < (map[pivot_beg] & 0x00ffffff)) + end = pivot_beg - 1; + else if(codepoint > (map[pivot_end] & 0x00ffffff)) + beg = pivot_end + 1; + else + return pivot_beg; + } + + return -1; + } + + static int + md_is_unicode_whitespace__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Zs" category. + * (generated by scripts/build_whitespace_map.py) */ + static const unsigned WHITESPACE_MAP[] = { + S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISWHITESPACE_(codepoint); + + return (md_unicode_bsearch__(codepoint, WHITESPACE_MAP, SIZEOF_ARRAY(WHITESPACE_MAP)) >= 0); + } + + static int + md_is_unicode_punct__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode general "P" and "S" categories. + * (generated by scripts/build_punct_map.py) */ + static const unsigned PUNCT_MAP[] = { + R(0x0021,0x002f), R(0x003a,0x0040), R(0x005b,0x0060), R(0x007b,0x007e), R(0x00a1,0x00a9), + R(0x00ab,0x00ac), R(0x00ae,0x00b1), S(0x00b4), R(0x00b6,0x00b8), S(0x00bb), S(0x00bf), S(0x00d7), + S(0x00f7), R(0x02c2,0x02c5), R(0x02d2,0x02df), R(0x02e5,0x02eb), S(0x02ed), R(0x02ef,0x02ff), S(0x0375), + S(0x037e), R(0x0384,0x0385), S(0x0387), S(0x03f6), S(0x0482), R(0x055a,0x055f), R(0x0589,0x058a), + R(0x058d,0x058f), S(0x05be), S(0x05c0), S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0606,0x060f), + S(0x061b), R(0x061d,0x061f), R(0x066a,0x066d), S(0x06d4), S(0x06de), S(0x06e9), R(0x06fd,0x06fe), + R(0x0700,0x070d), R(0x07f6,0x07f9), R(0x07fe,0x07ff), R(0x0830,0x083e), S(0x085e), S(0x0888), + R(0x0964,0x0965), S(0x0970), R(0x09f2,0x09f3), R(0x09fa,0x09fb), S(0x09fd), S(0x0a76), R(0x0af0,0x0af1), + S(0x0b70), R(0x0bf3,0x0bfa), S(0x0c77), S(0x0c7f), S(0x0c84), S(0x0d4f), S(0x0d79), S(0x0df4), S(0x0e3f), + S(0x0e4f), R(0x0e5a,0x0e5b), R(0x0f01,0x0f17), R(0x0f1a,0x0f1f), S(0x0f34), S(0x0f36), S(0x0f38), + R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fbe,0x0fc5), R(0x0fc7,0x0fcc), R(0x0fce,0x0fda), R(0x104a,0x104f), + R(0x109e,0x109f), S(0x10fb), R(0x1360,0x1368), R(0x1390,0x1399), S(0x1400), R(0x166d,0x166e), + R(0x169b,0x169c), R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17db), + R(0x1800,0x180a), S(0x1940), R(0x1944,0x1945), R(0x19de,0x19ff), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6), + R(0x1aa8,0x1aad), R(0x1b4e,0x1b4f), R(0x1b5a,0x1b6a), R(0x1b74,0x1b7f), R(0x1bfc,0x1bff), + R(0x1c3b,0x1c3f), R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), S(0x1fbd), R(0x1fbf,0x1fc1), + R(0x1fcd,0x1fcf), R(0x1fdd,0x1fdf), R(0x1fed,0x1fef), R(0x1ffd,0x1ffe), R(0x2010,0x2027), + R(0x2030,0x205e), R(0x207a,0x207e), R(0x208a,0x208e), R(0x20a0,0x20c4), R(0x2100,0x2101), + R(0x2103,0x2106), R(0x2108,0x2109), S(0x2114), R(0x2116,0x2118), R(0x211e,0x2123), S(0x2125), S(0x2127), + S(0x2129), S(0x212e), R(0x213a,0x213b), R(0x2140,0x2144), R(0x214a,0x214d), S(0x214f), R(0x218a,0x218b), + R(0x2190,0x2429), R(0x2440,0x244a), R(0x249c,0x24e9), R(0x2500,0x2775), R(0x2794,0x2b73), + R(0x2b76,0x2bff), R(0x2ce5,0x2cea), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70), R(0x2e00,0x2e2e), + R(0x2e30,0x2e5d), R(0x2e60,0x2e63), R(0x2e80,0x2e99), R(0x2e9b,0x2ef3), R(0x2f00,0x2fd5), + R(0x2ff0,0x2fff), R(0x3001,0x3004), R(0x3008,0x3020), S(0x3030), R(0x3036,0x3037), R(0x303d,0x303f), + R(0x309b,0x309c), S(0x30a0), S(0x30fb), R(0x3190,0x3191), R(0x3196,0x319f), R(0x31c0,0x31e5), S(0x31ef), + R(0x3200,0x321e), R(0x322a,0x3247), S(0x3250), R(0x3260,0x327f), R(0x328a,0x32b0), R(0x32c0,0x33ff), + R(0x4dc0,0x4dff), R(0xa490,0xa4c6), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e), + R(0xa6f2,0xa6f7), R(0xa700,0xa716), R(0xa720,0xa721), R(0xa789,0xa78a), R(0xa828,0xa82b), + R(0xa836,0xa839), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f), + S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaa77,0xaa79), R(0xaade,0xaadf), + R(0xaaf0,0xaaf1), S(0xab5b), R(0xab6a,0xab6b), S(0xabeb), S(0xfb29), R(0xfbb2,0xfbd2), R(0xfd3e,0xfd4f), + R(0xfd90,0xfd91), R(0xfdc8,0xfdcf), R(0xfdfc,0xfdff), R(0xfe10,0xfe19), R(0xfe30,0xfe52), + R(0xfe54,0xfe66), R(0xfe68,0xfe6b), R(0xff01,0xff0f), R(0xff1a,0xff20), R(0xff3b,0xff40), + R(0xff5b,0xff65), R(0xffe0,0xffe6), R(0xffe8,0xffee), R(0xfffc,0xfffd), R(0x10100,0x10102), + R(0x10137,0x1013f), R(0x10179,0x10189), R(0x1018c,0x1018e), R(0x10190,0x1019c), S(0x101a0), + R(0x101d0,0x101fc), S(0x1039f), S(0x103d0), S(0x1056f), S(0x10857), R(0x10877,0x10878), S(0x1091f), + S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f), S(0x10ac8), R(0x10af0,0x10af6), R(0x10b39,0x10b3f), + R(0x10b99,0x10b9c), S(0x10d6e), R(0x10d8e,0x10d8f), S(0x10ead), R(0x10ec9,0x10eca), R(0x10ed0,0x10ed8), + R(0x10f55,0x10f59), R(0x10f86,0x10f89), R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), + R(0x11140,0x11143), R(0x11174,0x11175), R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), + R(0x11238,0x1123d), S(0x112a9), R(0x113d4,0x113d5), R(0x113d7,0x113d8), R(0x1144b,0x1144f), + R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7), R(0x11641,0x11643), R(0x11660,0x1166c), + S(0x116b9), R(0x1173c,0x1173f), S(0x1183b), R(0x11944,0x11946), S(0x119e2), R(0x11a3f,0x11a46), + R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11b00,0x11b09), S(0x11be1), R(0x11c41,0x11c45), + R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), R(0x11f43,0x11f4f), R(0x11fd5,0x11ff1), S(0x11fff), + R(0x12470,0x12474), R(0x12ff1,0x12ff2), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3f), + R(0x16b44,0x16b45), R(0x16d6d,0x16d6f), R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9c), S(0x1bc9f), + R(0x1cc00,0x1ccef), R(0x1ccfa,0x1ccfc), R(0x1cd00,0x1ceb3), R(0x1ceba,0x1ced0), R(0x1ced2,0x1ced4), + R(0x1cedd,0x1cefd), R(0x1cf50,0x1cfc3), R(0x1d000,0x1d0f5), R(0x1d100,0x1d126), R(0x1d129,0x1d164), + R(0x1d16a,0x1d16c), R(0x1d183,0x1d184), R(0x1d18c,0x1d1a9), R(0x1d1ae,0x1d241), S(0x1d245), + R(0x1d253,0x1d25a), R(0x1d25d,0x1d25e), R(0x1d260,0x1d27f), R(0x1d300,0x1d356), S(0x1d6c1), S(0x1d6db), + S(0x1d6fb), S(0x1d715), S(0x1d735), S(0x1d74f), S(0x1d76f), S(0x1d789), S(0x1d7a9), S(0x1d7c3), + R(0x1d800,0x1d9ff), R(0x1da37,0x1da3a), R(0x1da6d,0x1da74), R(0x1da76,0x1da83), R(0x1da85,0x1da8b), + R(0x1db00,0x1db1c), S(0x1e14f), S(0x1e2ff), S(0x1e5ff), R(0x1e95e,0x1e95f), S(0x1ecac), S(0x1ecb0), + S(0x1ed2e), R(0x1eef0,0x1eef1), R(0x1f000,0x1f02b), R(0x1f030,0x1f093), R(0x1f0a0,0x1f0ae), + R(0x1f0b1,0x1f0bf), R(0x1f0c1,0x1f0cf), R(0x1f0d1,0x1f0f5), R(0x1f10d,0x1f1ae), R(0x1f1e6,0x1f202), + R(0x1f210,0x1f23b), R(0x1f240,0x1f248), R(0x1f250,0x1f251), R(0x1f260,0x1f265), R(0x1f300,0x1f6d9), + R(0x1f6dc,0x1f6ec), R(0x1f6f0,0x1f6fc), R(0x1f700,0x1f7db), R(0x1f7e0,0x1f7eb), R(0x1f7f0,0x1f80b), + R(0x1f810,0x1f847), R(0x1f850,0x1f859), R(0x1f860,0x1f887), R(0x1f890,0x1f8ad), R(0x1f8b0,0x1f8bb), + R(0x1f8c0,0x1f8c1), R(0x1f8d0,0x1f8d8), R(0x1f900,0x1fa57), R(0x1fa60,0x1fa6d), R(0x1fa70,0x1fa7c), + R(0x1fa80,0x1fac6), S(0x1fac8), R(0x1facc,0x1fadd), R(0x1fadf,0x1faeb), R(0x1faef,0x1fafa), + R(0x1fb00,0x1fb92), R(0x1fb94,0x1fbef), S(0x1fbfa) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISPUNCT_(codepoint); + + return (md_unicode_bsearch__(codepoint, PUNCT_MAP, SIZEOF_ARRAY(PUNCT_MAP)) >= 0); + } + + static void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_folding_map.py) */ + static const unsigned FOLD_MAP_1[] = { + R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136), + R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182), + S(0x0184), S(0x0186), S(0x0187), S(0x0189), S(0x018a), S(0x018b), S(0x018e), S(0x018f), S(0x0190), + S(0x0191), S(0x0193), S(0x0194), S(0x0196), S(0x0197), S(0x0198), S(0x019c), S(0x019d), S(0x019f), + R(0x01a0,0x01a4), S(0x01a6), S(0x01a7), S(0x01a9), S(0x01ac), S(0x01ae), S(0x01af), S(0x01b1), S(0x01b2), + S(0x01b3), S(0x01b5), S(0x01b7), S(0x01b8), S(0x01bc), S(0x01c4), S(0x01c5), S(0x01c7), S(0x01c8), + S(0x01ca), R(0x01cb,0x01db), R(0x01de,0x01ee), S(0x01f1), S(0x01f2), S(0x01f4), S(0x01f6), S(0x01f7), + R(0x01f8,0x021e), S(0x0220), R(0x0222,0x0232), S(0x023a), S(0x023b), S(0x023d), S(0x023e), S(0x0241), + S(0x0243), S(0x0244), S(0x0245), R(0x0246,0x024e), S(0x0345), S(0x0370), S(0x0372), S(0x0376), S(0x037f), + S(0x0386), R(0x0388,0x038a), S(0x038c), S(0x038e), S(0x038f), R(0x0391,0x03a1), R(0x03a3,0x03ab), + S(0x03c2), S(0x03cf), S(0x03d0), S(0x03d1), S(0x03d5), S(0x03d6), R(0x03d8,0x03ee), S(0x03f0), S(0x03f1), + S(0x03f4), S(0x03f5), S(0x03f7), S(0x03f9), S(0x03fa), R(0x03fd,0x03ff), R(0x0400,0x040f), + R(0x0410,0x042f), R(0x0460,0x0480), R(0x048a,0x04be), S(0x04c0), R(0x04c1,0x04cd), R(0x04d0,0x052e), + R(0x0531,0x0556), R(0x10a0,0x10c5), S(0x10c7), S(0x10cd), R(0x13f8,0x13fd), S(0x1c80), S(0x1c81), + S(0x1c82), S(0x1c83), S(0x1c84), S(0x1c85), S(0x1c86), S(0x1c87), S(0x1c88), S(0x1c89), R(0x1c90,0x1cba), + R(0x1cbd,0x1cbf), R(0x1e00,0x1e94), S(0x1e9b), R(0x1ea0,0x1efe), R(0x1f08,0x1f0f), R(0x1f18,0x1f1d), + R(0x1f28,0x1f2f), R(0x1f38,0x1f3f), R(0x1f48,0x1f4d), S(0x1f59), S(0x1f5b), S(0x1f5d), S(0x1f5f), + R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fb9), S(0x1fba), S(0x1fbb), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8), + S(0x1fd9), S(0x1fda), S(0x1fdb), S(0x1fe8), S(0x1fe9), S(0x1fea), S(0x1feb), S(0x1fec), S(0x1ff8), + S(0x1ff9), S(0x1ffa), S(0x1ffb), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), S(0x2183), + R(0x24b6,0x24cf), R(0x2c00,0x2c2f), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b), + S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), S(0x2c7f), R(0x2c80,0x2ce2), + S(0x2ceb), S(0x2ced), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), R(0xa732,0xa76e), + S(0xa779), S(0xa77b), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), S(0xa792), + R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2), + S(0xa7b3), R(0xa7b4,0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7cb), + R(0xa7cc,0xa7da), S(0xa7dc), S(0xa7dd), S(0xa7e2), S(0xa7f5), S(0xab6c), S(0xab6d), R(0xab70,0xabbf), + R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3), R(0x10570,0x1057a), R(0x1057c,0x1058a), + R(0x1058c,0x10592), S(0x10594), S(0x10595), R(0x10c80,0x10cb2), R(0x10d50,0x10d65), R(0x118a0,0x118bf), + R(0x16e40,0x16e5f), R(0x16ea0,0x16eb8), S(0x1df40), S(0x1df48), S(0x1df4a), S(0x1df4d), S(0x1df51), + R(0x1df68,0x1df6e), R(0x1df72,0x1df7e), R(0x1e900,0x1e921) + }; + static const unsigned FOLD_MAP_1_DATA[] = { + 0x0061, 0x007a, 0x03bc, 0x00e0, 0x00f6, 0x00f8, 0x00fe, 0x0101, 0x012f, 0x0133, 0x0137, 0x013a, 0x0148, + 0x014b, 0x0177, 0x00ff, 0x017a, 0x017e, 0x0073, 0x0253, 0x0183, 0x0185, 0x0254, 0x0188, 0x0256, 0x0257, + 0x018c, 0x01dd, 0x0259, 0x025b, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268, 0x0199, 0x026f, 0x0272, 0x0275, + 0x01a1, 0x01a5, 0x0280, 0x01a8, 0x0283, 0x01ad, 0x0288, 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b6, 0x0292, + 0x01b9, 0x01bd, 0x01c6, 0x01c6, 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01dc, 0x01df, 0x01ef, 0x01f3, 0x01f3, + 0x01f5, 0x0195, 0x01bf, 0x01f9, 0x021f, 0x019e, 0x0223, 0x0233, 0x2c65, 0x023c, 0x019a, 0x2c66, 0x0242, + 0x0180, 0x0289, 0x028c, 0x0247, 0x024f, 0x03b9, 0x0371, 0x0373, 0x0377, 0x03f3, 0x03ac, 0x03ad, 0x03af, + 0x03cc, 0x03cd, 0x03ce, 0x03b1, 0x03c1, 0x03c3, 0x03cb, 0x03c3, 0x03d7, 0x03b2, 0x03b8, 0x03c6, 0x03c0, + 0x03d9, 0x03ef, 0x03ba, 0x03c1, 0x03b8, 0x03b5, 0x03f8, 0x03f2, 0x03fb, 0x037b, 0x037d, 0x0450, 0x045f, + 0x0430, 0x044f, 0x0461, 0x0481, 0x048b, 0x04bf, 0x04cf, 0x04c2, 0x04ce, 0x04d1, 0x052f, 0x0561, 0x0586, + 0x2d00, 0x2d25, 0x2d27, 0x2d2d, 0x13f0, 0x13f5, 0x0432, 0x0434, 0x043e, 0x0441, 0x0442, 0x0442, 0x044a, + 0x0463, 0xa64b, 0x1c8a, 0x10d0, 0x10fa, 0x10fd, 0x10ff, 0x1e01, 0x1e95, 0x1e61, 0x1ea1, 0x1eff, 0x1f00, + 0x1f07, 0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, + 0x1f60, 0x1f67, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x03c9, 0x006b, 0x00e5, 0x214e, + 0x2170, 0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5f, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, + 0x0251, 0x0271, 0x0250, 0x0252, 0x2c73, 0x2c76, 0x023f, 0x0240, 0x2c81, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, + 0xa641, 0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, 0xa733, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa787, + 0xa78c, 0x0265, 0xa791, 0xa793, 0xa797, 0xa7a9, 0x0266, 0x025c, 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, + 0x029d, 0xab53, 0xa7b5, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0x0264, 0xa7cd, 0xa7db, 0x019b, + 0x0277, 0x027c, 0xa7f6, 0xab4b, 0xab4c, 0x13a0, 0x13ef, 0xff41, 0xff5a, 0x10428, 0x1044f, 0x104d8, + 0x104fb, 0x10597, 0x105a1, 0x105a3, 0x105b1, 0x105b3, 0x105b9, 0x105bb, 0x105bc, 0x10cc0, 0x10cf2, + 0x10d70, 0x10d85, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x16ebb, 0x16ed3, 0x1df41, 0x1df49, 0x1df4b, + 0x1df4e, 0x1df52, 0x1df69, 0x1df6f, 0x1df73, 0x1df7f, 0x1e922, 0x1e943 + }; + static const unsigned FOLD_MAP_2[] = { + S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99), + S(0x1e9a), S(0x1e9e), S(0x1f50), R(0x1f80,0x1f87), R(0x1f88,0x1f8f), R(0x1f90,0x1f97), R(0x1f98,0x1f9f), + R(0x1fa0,0x1fa7), R(0x1fa8,0x1faf), S(0x1fb2), S(0x1fb3), S(0x1fb4), S(0x1fb6), S(0x1fbc), S(0x1fc2), + S(0x1fc3), S(0x1fc4), S(0x1fc6), S(0x1fcc), S(0x1fd6), S(0x1fe4), S(0x1fe6), S(0x1ff2), S(0x1ff3), + S(0x1ff4), S(0x1ff6), S(0x1ffc), S(0xfb00), S(0xfb01), S(0xfb02), S(0xfb05), S(0xfb06), S(0xfb13), + S(0xfb14), S(0xfb15), S(0xfb16), S(0xfb17), S(0x1df95) + }; + static const unsigned FOLD_MAP_2_DATA[] = { + 0x0073,0x0073, 0x0069,0x0307, 0x02bc,0x006e, 0x006a,0x030c, 0x0565,0x0582, 0x0068,0x0331, 0x0074,0x0308, + 0x0077,0x030a, 0x0079,0x030a, 0x0061,0x02be, 0x0073,0x0073, 0x03c5,0x0313, 0x1f00,0x03b9, 0x1f07,0x03b9, + 0x1f00,0x03b9, 0x1f07,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f60,0x03b9, + 0x1f67,0x03b9, 0x1f60,0x03b9, 0x1f67,0x03b9, 0x1f70,0x03b9, 0x03b1,0x03b9, 0x03ac,0x03b9, 0x03b1,0x0342, + 0x03b1,0x03b9, 0x1f74,0x03b9, 0x03b7,0x03b9, 0x03ae,0x03b9, 0x03b7,0x0342, 0x03b7,0x03b9, 0x03b9,0x0342, + 0x03c1,0x0313, 0x03c5,0x0342, 0x1f7c,0x03b9, 0x03c9,0x03b9, 0x03ce,0x03b9, 0x03c9,0x0342, 0x03c9,0x03b9, + 0x0066,0x0066, 0x0066,0x0069, 0x0066,0x006c, 0x0073,0x0074, 0x0073,0x0074, 0x0574,0x0576, 0x0574,0x0565, + 0x0574,0x056b, 0x057e,0x0576, 0x0574,0x056d, 0x0073,0x0073 + }; + static const unsigned FOLD_MAP_3[] = { + S(0x0390), S(0x03b0), S(0x1f52), S(0x1f54), S(0x1f56), S(0x1fb7), S(0x1fc7), S(0x1fd2), S(0x1fd3), + S(0x1fd7), S(0x1fe2), S(0x1fe3), S(0x1fe7), S(0x1ff7), S(0xfb03), S(0xfb04) + }; + static const unsigned FOLD_MAP_3_DATA[] = { + 0x03b9,0x0308,0x0301, 0x03c5,0x0308,0x0301, 0x03c5,0x0313,0x0300, 0x03c5,0x0313,0x0301, + 0x03c5,0x0313,0x0342, 0x03b1,0x0342,0x03b9, 0x03b7,0x0342,0x03b9, 0x03b9,0x0308,0x0300, + 0x03b9,0x0308,0x0301, 0x03b9,0x0308,0x0342, 0x03c5,0x0308,0x0300, 0x03c5,0x0308,0x0301, + 0x03c5,0x0308,0x0342, 0x03c9,0x0342,0x03b9, 0x0066,0x0066,0x0069, 0x0066,0x0066,0x006c + }; +#undef R +#undef S + static const struct { + const unsigned* map; + const unsigned* data; + size_t map_size; + unsigned n_codepoints; + } FOLD_MAP_LIST[] = { + { FOLD_MAP_1, FOLD_MAP_1_DATA, SIZEOF_ARRAY(FOLD_MAP_1), 1 }, + { FOLD_MAP_2, FOLD_MAP_2_DATA, SIZEOF_ARRAY(FOLD_MAP_2), 2 }, + { FOLD_MAP_3, FOLD_MAP_3_DATA, SIZEOF_ARRAY(FOLD_MAP_3), 3 } + }; + + int i; + + /* Fast path for ASCII characters. */ + if(codepoint <= 0x7f) { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + return; + } + + /* Try to locate the codepoint in any of the maps. */ + for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) { + int index; + + index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size); + if(index >= 0) { + /* Found the mapping. */ + unsigned n_codepoints = FOLD_MAP_LIST[i].n_codepoints; + const unsigned* map = FOLD_MAP_LIST[i].map; + const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints); + + memcpy(info->codepoints, codepoints, sizeof(unsigned) * n_codepoints); + info->n_codepoints = n_codepoints; + + if(FOLD_MAP_LIST[i].map[index] != codepoint) { + /* The found mapping maps whole range of codepoints, + * i.e. we have to offset info->codepoints[0] accordingly. */ + if((map[index] & 0x00ffffff)+1 == codepoints[0]) { + /* Alternating type of the range. */ + info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0); + } else { + /* Range to range kind of mapping. */ + info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff)); + } + } + + return; + } + } + + /* No mapping found. Map the codepoint to itself. */ + info->codepoints[0] = codepoint; + info->n_codepoints = 1; + } +#endif + + +#if defined MD4C_USE_UTF16 + #define IS_UTF16_SURROGATE_HI(word) (((WORD)(word) & 0xfc00) == 0xd800) + #define IS_UTF16_SURROGATE_LO(word) (((WORD)(word) & 0xfc00) == 0xdc00) + #define UTF16_DECODE_SURROGATE(hi, lo) (0x10000 + ((((unsigned)(hi) & 0x3ff) << 10) | (((unsigned)(lo) & 0x3ff) << 0))) + + static unsigned + md_decode_utf16le__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(IS_UTF16_SURROGATE_HI(str[0])) { + if(1 < str_size && IS_UTF16_SURROGATE_LO(str[1])) { + if(p_size != NULL) + *p_size = 2; + return UTF16_DECODE_SURROGATE(str[0], str[1]); + } + } + + if(p_size != NULL) + *p_size = 1; + return str[0]; + } + + static unsigned + md_decode_utf16le_before__(MD_CTX* ctx, OFF off) + { + if(off > 2 && IS_UTF16_SURROGATE_HI(CH(off-2)) && IS_UTF16_SURROGATE_LO(CH(off-1))) + return UTF16_DECODE_SURROGATE(CH(off-2), CH(off-1)); + + return CH(off-1); + } + + /* No whitespace uses surrogates, so no decoding needed here. */ + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(CH(off)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(CH((off)-1)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf16le__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf16le_before__(ctx, off)) + + static inline int + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf16le__(str+off, str_size-off, p_char_size); + } +#elif defined MD4C_USE_UTF8 + #define IS_UTF8_LEAD1(byte) ((unsigned char)(byte) <= 0x7f) + #define IS_UTF8_LEAD2(byte) (((unsigned char)(byte) & 0xe0) == 0xc0) + #define IS_UTF8_LEAD3(byte) (((unsigned char)(byte) & 0xf0) == 0xe0) + #define IS_UTF8_LEAD4(byte) (((unsigned char)(byte) & 0xf8) == 0xf0) + #define IS_UTF8_TAIL(byte) (((unsigned char)(byte) & 0xc0) == 0x80) + + static unsigned + md_decode_utf8__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(!IS_UTF8_LEAD1(str[0])) { + if(IS_UTF8_LEAD2(str[0])) { + if(1 < str_size && IS_UTF8_TAIL(str[1])) { + if(p_size != NULL) + *p_size = 2; + + return (((unsigned int)str[0] & 0x1f) << 6) | + (((unsigned int)str[1] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD3(str[0])) { + if(2 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2])) { + if(p_size != NULL) + *p_size = 3; + + return (((unsigned int)str[0] & 0x0f) << 12) | + (((unsigned int)str[1] & 0x3f) << 6) | + (((unsigned int)str[2] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD4(str[0])) { + if(3 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2]) && IS_UTF8_TAIL(str[3])) { + if(p_size != NULL) + *p_size = 4; + + return (((unsigned int)str[0] & 0x07) << 18) | + (((unsigned int)str[1] & 0x3f) << 12) | + (((unsigned int)str[2] & 0x3f) << 6) | + (((unsigned int)str[3] & 0x3f) << 0); + } + } + } + + if(p_size != NULL) + *p_size = 1; + return (unsigned) str[0]; + } + + static unsigned + md_decode_utf8_before__(MD_CTX* ctx, OFF off) + { + if(!IS_UTF8_LEAD1(CH(off-1))) { + if(off > 1 && IS_UTF8_LEAD2(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-2) & 0x1f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 2 && IS_UTF8_LEAD3(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-3) & 0x0f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 3 && IS_UTF8_LEAD4(CH(off-4)) && IS_UTF8_TAIL(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-4) & 0x07) << 18) | + (((unsigned int)CH(off-3) & 0x3f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + } + + return (unsigned) CH(off-1); + } + + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(md_decode_utf8_before__(ctx, off)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf8_before__(ctx, off)) + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf8__(str+off, str_size-off, p_char_size); + } +#else + #define ISUNICODEWHITESPACE_(codepoint) ISWHITESPACE_(codepoint) + #define ISUNICODEWHITESPACE(off) ISWHITESPACE(off) + #define ISUNICODEWHITESPACEBEFORE(off) ISWHITESPACE((off)-1) + + #define ISUNICODEPUNCT(off) ISPUNCT(off) + #define ISUNICODEPUNCTBEFORE(off) ISPUNCT((off)-1) + + static inline void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + } + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size) + { + MD_UNUSED(str_size); + *p_size = 1; + return (unsigned) str[off]; + } +#endif + + +/************************************* + *** Helper string manipulations *** + *************************************/ + +/* Fill buffer with copy of the string between 'beg' and 'end' but replace any + * line breaks with given replacement character. + * + * NOTE: Caller is responsible to make sure the buffer is large enough. + * (Given the output is always shorter than input, (end - beg) is good idea + * what the caller should allocate.) + */ +static void +md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines, + CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size) +{ + CHAR* ptr = buffer; + int line_index = 0; + OFF off = beg; + + MD_UNUSED(n_lines); + + while(1) { + const MD_LINE* line = &lines[line_index]; + OFF line_end = line->end; + if(end < line_end) + line_end = end; + + while(off < line_end) { + *ptr = CH(off); + ptr++; + off++; + } + + if(off >= end) { + *p_size = (MD_SIZE)(ptr - buffer); + return; + } + + *ptr = line_break_replacement_char; + ptr++; + + line_index++; + off = lines[line_index].beg; + } +} + +/* Wrapper of md_merge_lines() which allocates new buffer for the output string. + */ +static int +md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines, + CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size) +{ + CHAR* buffer; + + buffer = (CHAR*) malloc(sizeof(CHAR) * (end - beg)); + if(buffer == NULL) { + MD_LOG("malloc() failed."); + return -1; + } + + md_merge_lines(ctx, beg, end, lines, n_lines, + line_break_replacement_char, buffer, p_size); + + *p_str = buffer; + return 0; +} + +static OFF +md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size) +{ + SZ char_size; + unsigned codepoint; + + while(off < size) { + codepoint = md_decode_unicode(label, off, size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint) && !ISNEWLINE_(label[off])) + break; + off += char_size; + } + + return off; +} + + +/****************************** + *** Recognizing raw HTML *** + ******************************/ + +/* md_is_html_tag() may be called when processing inlines (inline raw HTML) + * or when breaking document to blocks (checking for start of HTML block type 7). + * + * When breaking document to blocks, we do not yet know line boundaries, but + * in that case the whole tag has to live on a single line. We distinguish this + * by n_lines == 0. + */ +static int +md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + int attr_state; + OFF off = beg; + OFF line_end = (n_lines > 0) ? lines[0].end : ctx->size; + MD_SIZE line_index = 0; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 1 >= line_end) + return false; + off++; + + /* For parsing attributes, we need a little state automaton below. + * State -1: no attributes are allowed. + * State 0: attribute could follow after some whitespace. + * State 1: after a whitespace (attribute name may follow). + * State 2: after attribute name ('=' MAY follow). + * State 3: after '=' (value specification MUST follow). + * State 41: in middle of unquoted attribute value. + * State 42: in middle of single-quoted attribute value. + * State 43: in middle of double-quoted attribute value. + */ + attr_state = 0; + + if(CH(off) == _T('/')) { + /* Closer tag "". No attributes may be present. */ + attr_state = -1; + off++; + } + + /* Tag name */ + if(off >= line_end || !ISALPHA(off)) + return false; + off++; + while(off < line_end && (ISALNUM(off) || CH(off) == _T('-'))) + off++; + + /* (Optional) attributes (if not closer), (optional) '/' (if not closer) + * and final '>'. */ + while(1) { + while(off < line_end && !ISNEWLINE(off)) { + if(attr_state > 40) { + if(attr_state == 41 && (ISBLANK(off) || ISANYOF(off, _T("\"'=<>`")))) { + attr_state = 0; + off--; /* Put the char back for re-inspection in the new state. */ + } else if(attr_state == 42 && CH(off) == _T('\'')) { + attr_state = 0; + } else if(attr_state == 43 && CH(off) == _T('"')) { + attr_state = 0; + } + off++; + } else if(ISWHITESPACE(off)) { + if(attr_state == 0) + attr_state = 1; + off++; + } else if(attr_state <= 2 && CH(off) == _T('>')) { + /* End. */ + goto done; + } else if(attr_state <= 2 && CH(off) == _T('/') && off+1 < line_end && CH(off+1) == _T('>')) { + /* End with digraph '/>' */ + off++; + goto done; + } else if((attr_state == 1 || attr_state == 2) && (ISALPHA(off) || CH(off) == _T('_') || CH(off) == _T(':'))) { + off++; + /* Attribute name */ + while(off < line_end && (ISALNUM(off) || ISANYOF(off, _T("_.:-")))) + off++; + attr_state = 2; + } else if(attr_state == 2 && CH(off) == _T('=')) { + /* Attribute assignment sign */ + off++; + attr_state = 3; + } else if(attr_state == 3) { + /* Expecting start of attribute value. */ + if(CH(off) == _T('"')) + attr_state = 43; + else if(CH(off) == _T('\'')) + attr_state = 42; + else if(!ISANYOF(off, _T("\"'=<>`")) && !ISNEWLINE(off)) + attr_state = 41; + else + return false; + off++; + } else { + /* Anything unexpected. */ + return false; + } + } + + /* We have to be on a single line. See definition of start condition + * of HTML block, type 7. */ + if(n_lines == 0) + return false; + + line_index++; + if(line_index >= n_lines) + return false; + + off = lines[line_index].beg; + line_end = lines[line_index].end; + + if(attr_state == 0 || attr_state == 41) + attr_state = 1; + + if(off >= max_end) + return false; + } + +done: + if(off >= max_end) + return false; + + *p_end = off+1; + return true; +} + +static int +md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, + const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF max_end, OFF* p_end, + OFF* p_scan_horizon) +{ + OFF off = beg; + MD_SIZE line_index = 0; + + if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) { + /* We have already scanned the range up to the max_end so we know + * there is nothing to see. */ + return false; + } + + while(true) { + while(off + len <= lines[line_index].end && off + len <= max_end) { + if(md_ascii_eq(STR(off), str, len)) { + /* Success. */ + *p_end = off + len; + return true; + } + off++; + } + + line_index++; + if(off >= max_end || line_index >= n_lines) { + /* Failure. */ + *p_scan_horizon = off; + return false; + } + + off = lines[line_index].beg; + } +} + +static int +md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 4 >= lines[0].end) + return false; + if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) + return false; + + /* Skip only "" or "" */ + off += 2; + + /* Scan for ordinary comment closer "-->". */ + return md_scan_for_html_closer(ctx, _T("-->"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon); +} + +static int +md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return false; + if(CH(off+1) != _T('?')) + return false; + off += 2; + + return md_scan_for_html_closer(ctx, _T("?>"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_proc_instr_horizon); +} + +static int +md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return false; + if(CH(off+1) != _T('!')) + return false; + off += 2; + + /* Declaration name. */ + if(off >= lines[0].end || !ISALPHA(off)) + return false; + off++; + while(off < lines[0].end && ISALPHA(off)) + off++; + + return md_scan_for_html_closer(ctx, _T(">"), 1, + lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon); +} + +static int +md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + static const CHAR open_str[] = _T("= lines[0].end) + return false; + if(memcmp(STR(off), open_str, open_size * sizeof(CHAR)) != 0) + return false; + off += open_size; + + return md_scan_for_html_closer(ctx, _T("]]>"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon); +} + +static int +md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + MD_ASSERT(CH(beg) == _T('<')); + return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end)); +} + + +/**************************** + *** Recognizing Entity *** + ****************************/ + +static int +md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISXDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 6) { + *p_end = off; + return true; + } else { + return false; + } +} + +static int +md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 7) { + *p_end = off; + return true; + } else { + return false; + } +} + +static int +md_is_named_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + if(off < max_end && ISALPHA_(text[off])) + off++; + else + return false; + + while(off < max_end && ISALNUM_(text[off]) && off - beg <= 48) + off++; + + if(2 <= off - beg && off - beg <= 48) { + *p_end = off; + return true; + } else { + return false; + } +} + +static int +md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + int is_contents; + OFF off = beg; + + MD_ASSERT(text[off] == _T('&')); + off++; + + if(off+2 < max_end && text[off] == _T('#') && (text[off+1] == _T('x') || text[off+1] == _T('X'))) + is_contents = md_is_hex_entity_contents(ctx, text, off+2, max_end, &off); + else if(off+1 < max_end && text[off] == _T('#')) + is_contents = md_is_dec_entity_contents(ctx, text, off+1, max_end, &off); + else + is_contents = md_is_named_entity_contents(ctx, text, off, max_end, &off); + + if(is_contents && off < max_end && text[off] == _T(';')) { + *p_end = off+1; + return true; + } else { + return false; + } +} + +static inline int +md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end); +} + + +/****************************** + *** Attribute Management *** + ******************************/ + +typedef struct MD_ATTRIBUTE_BUILD_tag MD_ATTRIBUTE_BUILD; +struct MD_ATTRIBUTE_BUILD_tag { + CHAR* text; + MD_TEXTTYPE* substr_types; + OFF* substr_offsets; + SZ substr_count; + SZ substr_alloc; + MD_TEXTTYPE trivial_types[1]; + OFF trivial_offsets[2]; +}; + + +#define MD_BUILD_ATTR_NO_ESCAPES 0x0001 + +static int +md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build, + MD_TEXTTYPE type, OFF off) +{ + if(build->substr_count >= build->substr_alloc) { + MD_TEXTTYPE* new_substr_types; + OFF* new_substr_offsets; + SZ new_alloc = (build->substr_alloc > 0 + ? build->substr_alloc + build->substr_alloc / 2 + : 8); + + new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types, + new_alloc * sizeof(MD_TEXTTYPE)); + if(new_substr_types == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + build->substr_types = new_substr_types; + + /* Note +1 to reserve space for final offset (== raw_size). */ + new_substr_offsets = (OFF*) realloc(build->substr_offsets, + (new_alloc+1) * sizeof(OFF)); + if(new_substr_offsets == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + build->substr_offsets = new_substr_offsets; + build->substr_alloc = new_alloc; + } + + build->substr_types[build->substr_count] = type; + build->substr_offsets[build->substr_count] = off; + build->substr_count++; + return 0; +} + +static void +md_free_attribute(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build) +{ + MD_UNUSED(ctx); + + /* A trivial build aliases caller-owned storage and must not be freed. + * Every other build owns all three pointers from the moment + * md_build_attribute() leaves the trivial branch, even if a growth + * realloc later failed while substr_alloc was still 0. Clearing them + * keeps this idempotent, which matters because md_build_attribute() + * frees on its own abort path before the caller frees again. */ + if(build->substr_types != build->trivial_types) { + free(build->text); + free(build->substr_types); + free(build->substr_offsets); + build->text = NULL; + build->substr_types = NULL; + build->substr_offsets = NULL; + build->substr_alloc = 0; + build->substr_count = 0; + } +} + +static int +md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size, + unsigned flags, MD_ATTRIBUTE* attr, MD_ATTRIBUTE_BUILD* build) +{ + OFF raw_off, off; + int is_trivial; + int ret = 0; + + memset(build, 0, sizeof(MD_ATTRIBUTE_BUILD)); + + /* If there is no backslash and no ampersand, build trivial attribute + * without any malloc(). */ + is_trivial = true; + for(raw_off = 0; raw_off < raw_size; raw_off++) { + if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) { + is_trivial = false; + break; + } + } + + if(is_trivial) { + build->text = (CHAR*) (raw_size ? raw_text : NULL); + build->substr_types = build->trivial_types; + build->substr_offsets = build->trivial_offsets; + build->substr_count = 1; + build->substr_alloc = 0; + build->trivial_types[0] = MD_TEXT_NORMAL; + build->trivial_offsets[0] = 0; + build->trivial_offsets[1] = raw_size; + off = raw_size; + } else { + build->text = (CHAR*) malloc(raw_size * sizeof(CHAR)); + if(build->text == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + + raw_off = 0; + off = 0; + + while(raw_off < raw_size) { + if(raw_text[raw_off] == _T('\0')) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NULLCHAR, off)); + memcpy(build->text + off, raw_text + raw_off, sizeof(CHAR)); + off++; + raw_off++; + continue; + } + + if(raw_text[raw_off] == _T('&')) { + OFF ent_end; + + if(md_is_entity_str(ctx, raw_text, raw_off, raw_size, &ent_end)) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_ENTITY, off)); + memcpy(build->text + off, raw_text + raw_off, (ent_end - raw_off) * sizeof(CHAR)); + off += ent_end - raw_off; + raw_off = ent_end; + continue; + } + } + + if(build->substr_count == 0 || build->substr_types[build->substr_count-1] != MD_TEXT_NORMAL) + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NORMAL, off)); + + if(!(flags & MD_BUILD_ATTR_NO_ESCAPES) && + raw_text[raw_off] == _T('\\') && raw_off+1 < raw_size && + (ISPUNCT_(raw_text[raw_off+1]) || ISNEWLINE_(raw_text[raw_off+1]))) + raw_off++; + + build->text[off++] = raw_text[raw_off++]; + } + build->substr_offsets[build->substr_count] = off; + } + + attr->text = build->text; + attr->size = off; + attr->substr_offsets = build->substr_offsets; + attr->substr_types = build->substr_types; + return 0; + +abort: + md_free_attribute(ctx, build); + return -1; +} + + +/************************************************** + *** Hashtable (with a text label as its key) *** + **************************************************/ + +#define MD_FNV1A_BASE 2166136261U +#define MD_FNV1A_PRIME 16777619U + +static inline unsigned +md_fnv1a(unsigned base, const void* data, size_t n) +{ + const unsigned char* buf = (const unsigned char*) data; + unsigned hash = base; + size_t i; + + for(i = 0; i < n; i++) { + hash ^= buf[i]; + hash *= MD_FNV1A_PRIME; + } + + return hash; +} + +/* Label equivalence is quite complicated with regards to whitespace and case + * folding. This complicates computing a hash of it as well as direct comparison + * of two labels. */ + +static unsigned +md_label_hash(const CHAR* label, SZ size) +{ + unsigned hash = MD_FNV1A_BASE; + OFF off; + unsigned codepoint; + int is_whitespace = false; + + off = md_skip_unicode_whitespace(label, 0, size); + while(off < size) { + SZ char_size; + + codepoint = md_decode_unicode(label, off, size, &char_size); + is_whitespace = ISUNICODEWHITESPACE_(codepoint) || ISNEWLINE_(label[off]); + + if(is_whitespace) { + codepoint = ' '; + hash = md_fnv1a(hash, &codepoint, sizeof(unsigned)); + off = md_skip_unicode_whitespace(label, off, size); + } else { + MD_UNICODE_FOLD_INFO fold_info; + + md_get_unicode_fold_info(codepoint, &fold_info); + hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(unsigned)); + off += char_size; + } + } + + return hash; +} + +static OFF +md_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, + MD_UNICODE_FOLD_INFO* fold_info) +{ + unsigned codepoint; + SZ char_size; + + if(off >= size) { + /* Treat end of a link label as a whitespace. */ + goto whitespace; + } + + codepoint = md_decode_unicode(label, off, size, &char_size); + off += char_size; + if(ISUNICODEWHITESPACE_(codepoint)) { + /* Treat all whitespace as equivalent */ + goto whitespace; + } + + /* Get real folding info. */ + md_get_unicode_fold_info(codepoint, fold_info); + return off; + +whitespace: + fold_info->codepoints[0] = _T(' '); + fold_info->n_codepoints = 1; + return md_skip_unicode_whitespace(label, off, size); +} + +static int +md_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size) +{ + OFF a_off; + OFF b_off; + MD_UNICODE_FOLD_INFO a_fi = { { 0 }, 0 }; + MD_UNICODE_FOLD_INFO b_fi = { { 0 }, 0 }; + OFF a_fi_off = 0; + OFF b_fi_off = 0; + int cmp; + + a_off = md_skip_unicode_whitespace(a_label, 0, a_size); + b_off = md_skip_unicode_whitespace(b_label, 0, b_size); + while(a_off < a_size || a_fi_off < a_fi.n_codepoints || + b_off < b_size || b_fi_off < b_fi.n_codepoints) + { + /* If needed, load fold info for next char. */ + if(a_fi_off >= a_fi.n_codepoints) { + a_fi_off = 0; + a_off = md_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi); + } + if(b_fi_off >= b_fi.n_codepoints) { + b_fi_off = 0; + b_off = md_label_cmp_load_fold_info(b_label, b_off, b_size, &b_fi); + } + + cmp = b_fi.codepoints[b_fi_off] - a_fi.codepoints[a_fi_off]; + if(cmp != 0) + return cmp; + + a_fi_off++; + b_fi_off++; + } + + return 0; +} + +typedef struct MD_LABEL_HASH_LIST_tag MD_LABEL_HASH_LIST; +struct MD_LABEL_HASH_LIST_tag { + unsigned n_entries; + unsigned alloc_entries; + MD_LABEL_HASH_ENTRY* entries[]; +}; + +static int +md_label_hash_entry_cmp(const void* a, const void* b) +{ + const MD_LABEL_HASH_ENTRY* a_entry = *(const MD_LABEL_HASH_ENTRY**)a; + const MD_LABEL_HASH_ENTRY* b_entry = *(const MD_LABEL_HASH_ENTRY**)b; + + if(a_entry->hash < b_entry->hash) + return -1; + else if(a_entry->hash > b_entry->hash) + return +1; + else + return md_label_cmp(a_entry->label, a_entry->label_size, + b_entry->label, b_entry->label_size); +} + +static int +md_label_hash_entry_cmp_for_sort(const void* a, const void* b) +{ + int cmp; + + cmp = md_label_hash_entry_cmp(a, b); + + /* Ensure stability of the sorting. */ + if(cmp == 0) { + const MD_LABEL_HASH_ENTRY* a_entry = *(const MD_LABEL_HASH_ENTRY**)a; + const MD_LABEL_HASH_ENTRY* b_entry = *(const MD_LABEL_HASH_ENTRY**)b; + + if(a_entry < b_entry) + cmp = -1; + else if(a_entry > b_entry) + cmp = +1; + } + + return cmp; +} + +static int +md_is_complex_label_bucket(MD_LABEL_HASH_TABLE* table, void* bucket) +{ + if(bucket == NULL) + return false; + + return (MD_LABEL_HASH_ENTRY*) bucket < (MD_LABEL_HASH_ENTRY*) table->defs || + (MD_LABEL_HASH_ENTRY*) bucket >= (MD_LABEL_HASH_ENTRY*)((char*)table->defs + table->n_defs * table->def_size); +} + +static int +md_build_label_hashtable(MD_CTX* ctx, MD_LABEL_HASH_TABLE* table) +{ + unsigned i, j; + + if(table->n_defs == 0) + return 0; + + table->n_buckets = (table->n_defs * 5) / 4; + table->buckets = malloc(table->n_buckets * sizeof(void*)); + if(table->buckets == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + memset(table->buckets, 0, table->n_buckets * sizeof(void*)); + + /* Each member of table->buckets[] can be: + * -- NULL, + * -- pointer to the MD_LABEL_HASH_ENTRY, or + * -- pointer to a MD_LABEL_HASH_LIST, which holds multiple pointers to + * such entries. + */ + for(i = 0; i < table->n_defs; i++) { + MD_LABEL_HASH_ENTRY* entry = (MD_LABEL_HASH_ENTRY*) ((char*) table->defs + i * table->def_size); + void** p_bucket = &table->buckets[entry->hash % table->n_buckets]; + MD_LABEL_HASH_LIST* list; + + if(*p_bucket == NULL) { + /* The bucket is empty. Make it just point to the entry. */ + *p_bucket = entry; + continue; + } + + if(!md_is_complex_label_bucket(table, *p_bucket)) + { + /* The bucket already contains one entry. Lets see whether it is the + * same label (duplicate) or different one (hash conflict). */ + MD_LABEL_HASH_ENTRY* old_entry = (MD_LABEL_HASH_ENTRY*) *p_bucket; + + if(md_label_cmp(entry->label, entry->label_size, + old_entry->label, old_entry->label_size) == 0) { + /* Duplicate label: We may ignore this definition. */ + continue; + } + + /* Make the bucket complex, i.e. able to hold more entries. */ + list = (MD_LABEL_HASH_LIST*) malloc(sizeof(MD_LABEL_HASH_LIST) + + 2 * sizeof(MD_LABEL_HASH_ENTRY*)); + if(list == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + list->entries[0] = old_entry; + list->entries[1] = entry; + list->n_entries = 2; + list->alloc_entries = 2; + *p_bucket = list; + continue; + } + + /* Append the entry to the complex bucket list. + * + * Note in this case we ignore potential duplicates to avoid expensive + * iterating over the complex bucket. Below, we revisit all the complex + * buckets and handle it more cheaply after the complex bucket contents + * is sorted. */ + list = (MD_LABEL_HASH_LIST*) *p_bucket; + if(list->n_entries >= list->alloc_entries) { + size_t alloc_entries = list->alloc_entries + list->alloc_entries / 2; + MD_LABEL_HASH_LIST* list_tmp = (MD_LABEL_HASH_LIST*) realloc(list, + sizeof(MD_LABEL_HASH_LIST) + alloc_entries * sizeof(MD_LABEL_HASH_ENTRY*)); + if(list_tmp == NULL) { + MD_LOG("realloc() failed."); + goto abort; + } + list = list_tmp; + list->alloc_entries = (unsigned) alloc_entries; + table->buckets[entry->hash % table->n_buckets] = list; + } + + list->entries[list->n_entries] = entry; + list->n_entries++; + } + + /* Sort the complex buckets so we can use bsearch() with them. */ + for(i = 0; i < table->n_buckets; i++) { + void* bucket = table->buckets[i]; + MD_LABEL_HASH_LIST* list; + + if(bucket == NULL) + continue; + + if(!md_is_complex_label_bucket(table, bucket)) + continue; + + list = (MD_LABEL_HASH_LIST*) bucket; + qsort(list->entries, list->n_entries, sizeof(MD_LABEL_HASH_ENTRY*), + md_label_hash_entry_cmp_for_sort); + + /* Disable all duplicates in the complex bucket by forcing all such + * records to point to the 1st such entry. I.e. no matter which + * record is found during the lookup, it will always point to the right + * definition. */ + for(j = 1; j < list->n_entries; j++) { + if(md_label_hash_entry_cmp(&list->entries[j-1], &list->entries[j]) == 0) + list->entries[j] = list->entries[j-1]; + } + } + + return 0; + +abort: + return -1; +} + +static void +md_free_label_hashtable(MD_CTX* ctx, MD_LABEL_HASH_TABLE* table) +{ + MD_UNUSED(ctx); + + if(table->buckets != NULL) { + unsigned i; + + for(i = 0; i < table->n_buckets; i++) { + void* bucket = table->buckets[i]; + if(md_is_complex_label_bucket(table, bucket)) + free(bucket); + } + + free(table->buckets); + } +} + +static const MD_LABEL_HASH_ENTRY* +md_lookup_label_hashtable(MD_CTX* ctx, MD_LABEL_HASH_TABLE* table, const CHAR* label, SZ label_size) +{ + unsigned hash; + void* bucket; + + MD_UNUSED(ctx); + + if(table->n_buckets == 0) + return NULL; + + hash = md_label_hash(label, label_size); + bucket = table->buckets[hash % table->n_buckets]; + + if(bucket == NULL) { + return NULL; + } else if(!md_is_complex_label_bucket(table, bucket)) { + MD_LABEL_HASH_ENTRY* entry = (MD_LABEL_HASH_ENTRY*) bucket; + + if(entry->hash == hash && + md_label_cmp(entry->label, entry->label_size, label, label_size) == 0) + return entry; + else + return NULL; + } else { + MD_LABEL_HASH_LIST* list = (MD_LABEL_HASH_LIST*) bucket; + MD_LABEL_HASH_ENTRY key_buf; + const MD_LABEL_HASH_ENTRY* key = &key_buf; + MD_LABEL_HASH_ENTRY** ret; + + key_buf.label = (CHAR*) label; + key_buf.label_size = label_size; + key_buf.hash = hash; + + ret = (MD_LABEL_HASH_ENTRY**) bsearch(&key, list->entries, + list->n_entries, sizeof(MD_LABEL_HASH_ENTRY*), md_label_hash_entry_cmp); + if(ret != NULL) + return *ret; + else + return NULL; + } +} + +static void* +md_add_label_def(MD_CTX* ctx, MD_LABEL_HASH_TABLE* table, const CHAR* label, SZ label_size) +{ + MD_LABEL_HASH_ENTRY* entry; + + if(table->n_defs >= table->alloc_defs) { + size_t new_alloc_defs; + void* new_defs; + + new_alloc_defs = (table->alloc_defs > 0 + ? table->alloc_defs + table->alloc_defs / 2 + : 8); + new_defs = realloc(table->defs, new_alloc_defs * table->def_size); + if(new_defs == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + table->defs = new_defs; + table->alloc_defs = (unsigned) new_alloc_defs; + } + + entry = (MD_LABEL_HASH_ENTRY*)((char*)table->defs + table->n_defs * table->def_size); + memset(entry, 0, table->def_size); + entry->label = label; + entry->label_size = label_size; + entry->hash = md_label_hash(label, label_size); + + table->n_defs++; + + return entry; +} + + +/************************************ + *** Link Reference Definitions *** + ************************************/ + +struct MD_REF_DEF_tag { + MD_LABEL_HASH_ENTRY entry; + CHAR* title; + SZ title_size; + OFF dest_beg; + OFF dest_end; + unsigned char label_needs_free : 1; + unsigned char title_needs_free : 1; +}; + +static int +md_build_ref_def_hashtable(MD_CTX* ctx) +{ + return md_build_label_hashtable(ctx, &ctx->ref_def_hashtable); +} + +static const MD_REF_DEF* +md_lookup_ref_def(MD_CTX* ctx, const CHAR* label, SZ label_size) +{ + return (const MD_REF_DEF*) md_lookup_label_hashtable(ctx, + &ctx->ref_def_hashtable, label, label_size); +} + + +/******************************* + *** Footnote Definitions *** + *******************************/ + +struct MD_FOOTNOTE_DEF_tag { + MD_LABEL_HASH_ENTRY entry; + unsigned int index; /* 0 = unreferenced; 1-based order of first reference */ + unsigned int ref_count; /* Number of references to this footnote. */ + MD_LINE* content_lines; /* always heap-allocated; freed by md_free_footnote_defs */ + MD_SIZE n_content_lines; +}; + +static int +md_is_footnote_label(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + OFF end = beg; + + /* No whitespace, no nested square brackets and length below 75 characters. + * See https://github.com/mity/md4c/issues/380 */ + while(end < ctx->size && end - beg <= 75 && + !ISWHITESPACE(end) && !ISANYOF2(end, _T('['), _T(']'))) + end++; + + if(end - beg > 0 && end < ctx->size && CH(end) == _T(']')) { + if(p_end != NULL) + *p_end = end; + return true; + } else { + return false; + } +} + +/* Returns 0 if not a footnote definition. + * Returns N > 0 (number of lines consumed) if it is one and the definition + * was stored successfully. + * Returns -1 on memory allocation error. + */ +static int +md_is_footnote_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + OFF off; + OFF label_beg, label_end; + MD_LINE* content_lines = NULL; + MD_FOOTNOTE_DEF* def; + MD_SIZE n; + MD_SIZE n_content_lines; + int ret = 0; + + /* Caller guarantees: n_lines >= 1 and lines[0] starts with [^. */ + MD_ASSERT(n_lines >= 1); + off = lines[0].beg; + MD_ASSERT(CH(off) == _T('[') && CH(off+1) == _T('^')); + off += 2; + + label_beg = off; + if(!md_is_footnote_label(ctx, label_beg, &off)) + return false; + label_end = off; + + /* Closing bracket. */ + if(off >= lines[0].end || CH(off) != _T(']')) + return false; + off++; + + /* Colon. */ + if(off >= lines[0].end || CH(off) != _T(':')) + return false; + off++; + + /* Skip optional whitespace after colon on the first line. */ + while(off < lines[0].end && ISWHITESPACE(off)) + off++; + + /* Count continuation lines. GitHub-style footnotes allow the rest of the + * paragraph block to form the footnote body, including unindented lines. + * + * Blank lines cannot appear inside a paragraph block (they always trigger + * a block boundary), so we do not need to handle them here. Stop before a + * following line which itself starts a new footnote definition. */ + n = 1; + while(n < n_lines) { + OFF def_off = lines[n].beg; + + if(def_off + 3 < lines[n].end && CH(def_off) == _T('[') && CH(def_off+1) == _T('^')) { + OFF tmp = def_off + 2; + + while(tmp < lines[n].end && CH(tmp) != _T(']') && + !ISWHITESPACE(tmp) && CH(tmp) != _T('[')) + tmp++; + + if(tmp > def_off + 2 && tmp + 1 < lines[n].end && + CH(tmp) == _T(']') && CH(tmp+1) == _T(':')) + break; + } + + n++; + } + + /* Build content_lines array. + * Line 0 content starts after the "[^label]: " prefix. + * Lines 1..n-1 are stored verbatim (md4c strips indentation before + * handing us MD_LINE, so no further adjustment is needed). */ + n_content_lines = (off >= lines[0].end && n > 1) ? n - 1 : n; + content_lines = (MD_LINE*) malloc(n_content_lines * sizeof(MD_LINE)); + if(content_lines == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + + if(n_content_lines < n) { + memcpy(content_lines, lines + 1, n_content_lines * sizeof(MD_LINE)); + } else { + content_lines[0].beg = off; + content_lines[0].end = lines[0].end; + if(n > 1) + memcpy(content_lines + 1, lines + 1, (n - 1) * sizeof(MD_LINE)); + } + + def = (MD_FOOTNOTE_DEF*) md_add_label_def(ctx, &ctx->footnote_hashtable, + (CHAR*) STR(label_beg), label_end - label_beg); + if(def == NULL) { + ret = -1; + goto abort; + } + def->content_lines = content_lines; + def->n_content_lines = n_content_lines; + + return (int) n; + +abort: + free(content_lines); + return ret; +} + +static MD_FOOTNOTE_DEF* +md_lookup_footnote_def(MD_CTX* ctx, const CHAR* label, SZ label_size) +{ + return (MD_FOOTNOTE_DEF*) md_lookup_label_hashtable(ctx, + &ctx->footnote_hashtable, label, label_size); +} + +static int +md_build_footnote_def_hashtable(MD_CTX* ctx) +{ + return md_build_label_hashtable(ctx, &ctx->footnote_hashtable); +} + +static void +md_free_footnote_defs(MD_CTX* ctx) +{ + unsigned i; + + md_free_label_hashtable(ctx, &ctx->footnote_hashtable); + + for(i = 0; i < ctx->footnote_hashtable.n_defs; i++) + free(ctx->footnote_hashtable.footnote_defs[i].content_lines); + free(ctx->footnote_hashtable.footnote_defs); +} + + +/*************************** + *** Recognizing Links *** + ***************************/ + +/* Note this code is partially shared between processing inlines and blocks + * as reference definitions and links share some helper parser functions. + */ + +typedef struct MD_LINK_ATTR_tag MD_LINK_ATTR; +struct MD_LINK_ATTR_tag { + OFF dest_beg; + OFF dest_end; + + CHAR* title; + SZ title_size; + int title_needs_free; +}; + + +static int +md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + OFF contents_beg = 0; + OFF contents_end = 0; + MD_SIZE line_index = 0; + int len = 0; + + *p_beg_line_index = 0; + + if(CH(off) != _T('[')) + return false; + off++; + + while(1) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + 2; + off += 2; + } else if(CH(off) == _T('[')) { + return false; + } else if(CH(off) == _T(']')) { + if(contents_beg < contents_end) { + /* Success. */ + *p_contents_beg = contents_beg; + *p_contents_end = contents_end; + *p_end = off+1; + *p_end_line_index = line_index; + return true; + } else { + /* Link label must have some non-whitespace contents. */ + return false; + } + } else { + unsigned codepoint; + SZ char_size; + + codepoint = md_decode_unicode(ctx->text, off, ctx->size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint)) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + char_size; + } + + off += char_size; + } + + len++; + if(len > 999) + return false; + } + + line_index++; + len++; + if(line_index < n_lines) + off = lines[line_index].beg; + else + break; + } + + return false; +} + +static int +md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + + if(off >= max_end || CH(off) != _T('<')) + return false; + off++; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISNEWLINE(off) || CH(off) == _T('<')) + return false; + + if(CH(off) == _T('>')) { + /* Success. */ + *p_contents_beg = beg+1; + *p_contents_end = off; + *p_end = off+1; + return true; + } + + off++; + } + + return false; +} + +static int +md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + int parenthesis_level = 0; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISWHITESPACE(off) || ISCNTRL(off)) + break; + + /* Link destination may include balanced pairs of unescaped '(' ')'. + * Note we limit the maximal nesting level by 32 to protect us from + * https://github.com/jgm/cmark/issues/214 */ + if(CH(off) == _T('(')) { + parenthesis_level++; + if(parenthesis_level > 32) + return false; + } else if(CH(off) == _T(')')) { + if(parenthesis_level == 0) + break; + parenthesis_level--; + } + + off++; + } + + if(parenthesis_level != 0 || off == beg) + return false; + + /* Success. */ + *p_contents_beg = beg; + *p_contents_end = off; + *p_end = off; + return true; +} + +static inline int +md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + if(CH(beg) == _T('<')) + return md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); + else + return md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); +} + +static int +md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + CHAR closer_char; + MD_SIZE line_index = 0; + + /* White space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return false; + off = lines[line_index].beg; + } + if(off == beg) + return false; + + *p_beg_line_index = line_index; + + /* First char determines how to detect end of it. */ + switch(CH(off)) { + case _T('"'): closer_char = _T('"'); break; + case _T('\''): closer_char = _T('\''); break; + case _T('('): closer_char = _T(')'); break; + default: return false; + } + off++; + + *p_contents_beg = off; + + while(line_index < n_lines) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + off++; + } else if(CH(off) == closer_char) { + /* Success. */ + *p_contents_end = off; + *p_end = off+1; + *p_end_line_index = line_index; + return true; + } else if(closer_char == _T(')') && CH(off) == _T('(')) { + /* ()-style title cannot contain (unescaped '(')) */ + return false; + } + + off++; + } + + line_index++; + } + + return false; +} + +/* Returns 0 if it is not a reference definition. + * + * Returns N > 0 if it is a reference definition. N then corresponds to the + * number of lines forming it). In this case the definition is stored for + * resolving any links referring to it. + * + * Returns -1 in case of an error (out of memory). + */ +static int +md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + OFF label_contents_beg; + OFF label_contents_end; + MD_SIZE label_contents_line_index; + int label_is_multiline = false; + OFF dest_contents_beg; + OFF dest_contents_end; + OFF title_contents_beg; + OFF title_contents_end; + MD_SIZE title_contents_line_index; + int title_is_multiline = false; + OFF off; + MD_SIZE line_index = 0; + MD_SIZE tmp_line_index; + MD_REF_DEF* def = NULL; + int ret = 0; + + /* Link label. */ + if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg, + &off, &label_contents_line_index, &line_index, + &label_contents_beg, &label_contents_end)) + return false; + label_is_multiline = (label_contents_line_index != line_index); + + /* Colon. */ + if(off >= lines[line_index].end || CH(off) != _T(':')) + return false; + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return false; + off = lines[line_index].beg; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &dest_contents_beg, &dest_contents_end)) + return false; + + /* (Optional) title. Note we interpret it as an title only if nothing + * more follows on its last line. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end) + && off >= lines[line_index + tmp_line_index].end) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = false; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Nothing more can follow on the last line. */ + if(off < lines[line_index].end) + return false; + + if(label_is_multiline) { + CHAR* label; + SZ label_size; + + MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end, + lines + label_contents_line_index, n_lines - label_contents_line_index, + _T(' '), &label, &label_size)); + def = (MD_REF_DEF*) md_add_label_def(ctx, &ctx->ref_def_hashtable, label, label_size); + if(def == NULL) { + ret = -1; + free(label); + goto abort; + } + def->label_needs_free = true; + } else { + def = (MD_REF_DEF*) md_add_label_def(ctx, &ctx->ref_def_hashtable, + STR(label_contents_beg), label_contents_end - label_contents_beg); + if(def == NULL) { + ret = -1; + goto abort; + } + } + + if(title_is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &def->title, &def->title_size)); + def->title_needs_free = true; + } else { + def->title = (CHAR*) STR(title_contents_beg); + def->title_size = title_contents_end - title_contents_beg; + } + + def->dest_beg = dest_contents_beg; + def->dest_end = dest_contents_end; + + /* Success. */ + return line_index + 1; + +abort: + /* Failure. A non-NULL def is already committed to ctx->ref_def_hashtable, + * which owns its label and title and frees them in md_free_ref_defs(). + * The def == NULL path frees its local label itself, above. */ + return ret; +} + +static int +md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF end, MD_LINK_ATTR* attr) +{ + const MD_REF_DEF* def; + const MD_LINE* beg_line; + int is_multiline; + CHAR* label; + SZ label_size; + int ret = false; + + MD_ASSERT(CH(beg) == _T('[') || CH(beg) == _T('!')); + MD_ASSERT(CH(end-1) == _T(']')); + + if(ctx->max_ref_def_output == 0) + return false; + + beg += (CH(beg) == _T('!') ? 2 : 1); + end--; + + /* Find lines corresponding to the beg and end positions. */ + beg_line = md_lookup_line(beg, lines, n_lines, NULL); + is_multiline = (end > beg_line->end); + + if(is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line, + (int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size)); + } else { + label = (CHAR*) STR(beg); + label_size = end - beg; + } + + def = md_lookup_ref_def(ctx, label, label_size); + if(def != NULL) { + attr->dest_beg = def->dest_beg; + attr->dest_end = def->dest_end; + attr->title = def->title; + attr->title_size = def->title_size; + attr->title_needs_free = false; + } + + if(is_multiline) + free(label); + + if(def != NULL) { + /* See https://github.com/mity/md4c/issues/238 */ + MD_SIZE output_size_estimation = def->entry.label_size + def->title_size + def->dest_end - def->dest_beg; + if(output_size_estimation < ctx->max_ref_def_output) { + ctx->max_ref_def_output -= output_size_estimation; + ret = true; + } else { + MD_LOG("Too many link reference definition instantiations."); + ctx->max_ref_def_output = 0; + } + } + +abort: + return ret; +} + +static int +md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF* p_end, MD_LINK_ATTR* attr) +{ + MD_SIZE line_index = 0; + MD_SIZE tmp_line_index; + OFF title_contents_beg; + OFF title_contents_end; + MD_SIZE title_contents_line_index; + int title_is_multiline; + OFF off = beg; + int ret = false; + + md_lookup_line(off, lines, n_lines, &line_index); + + MD_ASSERT(CH(off) == _T('(')); + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end && (off >= ctx->size || ISNEWLINE(off))) { + line_index++; + if(line_index >= n_lines) + return false; + off = lines[line_index].beg; + } + + /* Link destination may be omitted, but only when not also having a title. */ + if(off < ctx->size && CH(off) == _T(')')) { + attr->dest_beg = off; + attr->dest_end = off; + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = false; + off++; + *p_end = off; + return true; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &attr->dest_beg, &attr->dest_end)) + return false; + + /* (Optional) title. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end)) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = false; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Optional whitespace followed with final ')'. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return false; + off = lines[line_index].beg; + } + if(CH(off) != _T(')')) + goto abort; + off++; + + if(title_contents_beg >= title_contents_end) { + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = false; + } else if(!title_is_multiline) { + attr->title = (CHAR*) STR(title_contents_beg); + attr->title_size = title_contents_end - title_contents_beg; + attr->title_needs_free = false; + } else { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &attr->title, &attr->title_size)); + attr->title_needs_free = true; + } + + *p_end = off; + ret = true; + +abort: + return ret; +} + +static void +md_free_ref_defs(MD_CTX* ctx) +{ + unsigned i; + + md_free_label_hashtable(ctx, &ctx->ref_def_hashtable); + + for(i = 0; i < ctx->ref_def_hashtable.n_defs; i++) { + MD_REF_DEF* def = &ctx->ref_def_hashtable.ref_defs[i]; + + if(def->label_needs_free) + free((void*) def->entry.label); + if(def->title_needs_free) + free(def->title); + } + + free(ctx->ref_def_hashtable.ref_defs); +} + + +/****************************************** + *** Processing Inlines (a.k.a Spans) *** + ******************************************/ + +/* We process inlines in few phases: + * + * (1) We go through the block text and collect all significant characters + * which may start/end a span or some other significant position into + * ctx->marks[]. Core of this is what md_collect_marks() does. + * + * We also do some very brief preliminary context-less analysis, whether + * it might be opener or closer (e.g. of an emphasis span). + * + * This speeds the other steps as we do not need to re-iterate over all + * characters anymore. + * + * (2) We analyze each potential mark types, in order by their precedence. + * + * In each md_analyze_XXX() function, we re-iterate list of the marks, + * skipping already resolved regions (in preceding precedences) and try to + * resolve them. + * + * (2.1) For trivial marks, which are single (e.g. HTML entity), we just mark + * them as resolved. + * + * (2.2) For range-type marks, we analyze whether the mark could be closer + * and, if yes, whether there is some preceding opener it could satisfy. + * + * If not we check whether it could be really an opener and if yes, we + * remember it so subsequent closers may resolve it. + * + * (3) Finally, when all marks were analyzed, we render the block contents + * by calling MD_RENDERER::text() callback, interrupting by ::enter_span() + * or ::close_span() whenever we reach a resolved mark. + */ + + +/* The mark structure. + * + * '\\': Maybe escape sequence. + * '\0': NULL char. + * '*': Maybe (strong) emphasis start/end. + * '_': Maybe (strong) emphasis start/end. + * '~': Maybe strikethrough start/end (needs MD_FLAG_STRIKETHROUGH). + * '+': Maybe insert start/end (needs MD_FLAG_INSERT) + * '`': Maybe code span start/end. + * '&': Maybe start of entity. + * ';': Maybe end of entity. + * '<': Maybe start of raw HTML or autolink. + * '>': Maybe end of raw HTML or autolink. + * '=': Maybe highlight start/end (needs MD_FLAG_HIGHLIGHT). + * '[': Maybe start of link label or link text. + * '!': Equivalent of '[' for image. + * ']': Maybe end of link label or link text. + * '@': Maybe permissive e-mail auto-link (needs MD_FLAG_PERMISSIVEEMAILAUTOLINKS). + * ':': Maybe permissive URL auto-link (needs MD_FLAG_PERMISSIVEURLAUTOLINKS). + * '.': Maybe permissive WWW auto-link (needs MD_FLAG_PERMISSIVEWWWAUTOLINKS). + * 'D': Dummy mark, it reserves a space for splitting a previous mark + * (e.g. emphasis) or to make more space for storing some special data + * related to the preceding mark (e.g. link). + * + * Note that not all instances of these chars in the text imply creation of the + * structure. Only those which have (or may have, after we see more context) + * the special meaning. + * + * (Keep this struct as small as possible to fit as much of them into CPU + * cache line.) + */ +struct MD_MARK_tag { + union { + struct { + OFF beg; + OFF end; + }; + void* pointer; /* Dummy marks can sometimes store a pointer */ + }; + + /* For unresolved openers, 'next' may be used to form a stack of + * unresolved open openers. + * + * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the + * respective closer/opener. + */ + int prev; + int next; + CHAR ch; + unsigned char flags; +}; + +/* Mark flags (these apply to ALL mark types). */ +#define MD_MARK_POTENTIAL_OPENER 0x01 /* Maybe opener. */ +#define MD_MARK_POTENTIAL_CLOSER 0x02 /* Maybe closer. */ +#define MD_MARK_OPENER 0x04 /* Definitely opener. */ +#define MD_MARK_CLOSER 0x08 /* Definitely closer. */ +#define MD_MARK_RESOLVED 0x10 /* Resolved in any definite way. */ + +/* Mark flags specific for just some mark type(s) (so the bits can be reused). */ +#define MD_MARK_EMPH_OC 0x20 /* Opener/closer mixed candidate. Helper for the "rule of 3". */ +#define MD_MARK_EMPH_MOD3_0 0x40 +#define MD_MARK_EMPH_MOD3_1 0x80 +#define MD_MARK_EMPH_MOD3_2 (0x40 | 0x80) +#define MD_MARK_EMPH_MOD3_MASK (0x40 | 0x80) +#define MD_MARK_AUTOLINK 0x20 /* Distinguisher for '<', '>'. */ +#define MD_MARK_AUTOLINK_MISSING_MAILTO 0x40 /* For '@' */ +#define MD_MARK_VALIDPERMISSIVEAUTOLINK 0x20 /* For '@', ':', '.'. */ +#define MD_MARK_BRACKET_CANBEIMAGE 0x20 /* For '[', if can be expanded to the left to eat '!'. */ +#define MD_MARK_BRACKET_HASNESTED 0x40 /* For '[' to rule out invalid link labels early. */ +#define MD_MARK_BRACKET_FOOTNOTEREF 0x80 /* For '[', To distinguish footnotes. */ + +static MD_MARKSTACK* +md_emph_stack(MD_CTX* ctx, MD_CHAR ch, unsigned flags) +{ + MD_MARKSTACK* stack; + + switch(ch) { + case '*': stack = &ASTERISK_OPENERS_oo_mod3_0; break; + case '_': stack = &UNDERSCORE_OPENERS_oo_mod3_0; break; + default: MD_UNREACHABLE(); + } + + if(flags & MD_MARK_EMPH_OC) + stack += 3; + + switch(flags & MD_MARK_EMPH_MOD3_MASK) { + case MD_MARK_EMPH_MOD3_0: stack += 0; break; + case MD_MARK_EMPH_MOD3_1: stack += 1; break; + case MD_MARK_EMPH_MOD3_2: stack += 2; break; + default: MD_UNREACHABLE(); + } + + return stack; +} + +static MD_MARKSTACK* +md_opener_stack(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + switch(mark->ch) { + case _T('*'): + case _T('_'): return md_emph_stack(ctx, mark->ch, mark->flags); + + case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2; + + case _T('!'): + case _T('['): return &BRACKET_OPENERS; + + default: MD_UNREACHABLE(); + } +} + +static MD_MARK* +md_add_mark(MD_CTX* ctx) +{ + if(ctx->n_marks >= ctx->alloc_marks) { + MD_MARK* new_marks; + + ctx->alloc_marks = (ctx->alloc_marks > 0 + ? ctx->alloc_marks + ctx->alloc_marks / 2 + : 64); + new_marks = realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK)); + if(new_marks == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + ctx->marks = new_marks; + } + + return &ctx->marks[ctx->n_marks++]; +} + +#define ADD_MARK_() \ + do { \ + mark = md_add_mark(ctx); \ + if(mark == NULL) { \ + ret = -1; \ + goto abort; \ + } \ + } while(0) + +#define ADD_MARK(ch_, beg_, end_, flags_) \ + do { \ + ADD_MARK_(); \ + mark->beg = (beg_); \ + mark->end = (end_); \ + mark->prev = -1; \ + mark->next = -1; \ + mark->ch = (char)(ch_); \ + mark->flags = (flags_); \ + } while(0) + + +static inline void +md_mark_stack_push(MD_CTX* ctx, MD_MARKSTACK* stack, int mark_index) +{ + ctx->marks[mark_index].next = stack->top; + stack->top = mark_index; +} + +static inline int +md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) +{ + int top = stack->top; + if(top >= 0) + stack->top = ctx->marks[top].next; + return top; +} + +/* Sometimes, we need to store a pointer into the mark. It can only happen + * for dummy marks. */ +static inline void +md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) +{ + MD_ASSERT(ctx->marks[mark_index].ch == 'D'); + ctx->marks[mark_index].pointer = ptr; +} + +static inline void* +md_mark_get_ptr(MD_CTX* ctx, int mark_index) +{ + MD_ASSERT(ctx->marks[mark_index].ch == 'D'); + return ctx->marks[mark_index].pointer; +} + +static inline void +md_resolve_range(MD_CTX* ctx, int opener_index, int closer_index) +{ + MD_MARK* opener = &ctx->marks[opener_index]; + MD_MARK* closer = &ctx->marks[closer_index]; + + /* Interconnect opener and closer and mark both as resolved. */ + opener->next = closer_index; + closer->prev = opener_index; + + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; +} + +/* Pop all opener records in the activated chains after the given mark. + * This makes sure, we have no crossing ranges. */ +static void +md_pop_openers(MD_CTX* ctx, int opener_index) +{ + int i; + + for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) { + MD_MARKSTACK* stack = &ctx->opener_stacks[i]; + while(stack->top >= opener_index) + md_mark_stack_pop(ctx, stack); + } +} + +static void +md_disable_marks(MD_CTX* ctx, int mark_index0, int mark_index1) +{ + int i; + + for(i = mark_index0; i < mark_index1; i++) { + MD_MARK* mark = &ctx->marks[i]; + + mark->ch = 'D'; + mark->flags = 0; + } +} + +static void +md_build_mark_char_map(MD_CTX* ctx) +{ + memset(ctx->mark_char_map, 0, sizeof(ctx->mark_char_map)); + + ctx->mark_char_map['\\'] = 1; + ctx->mark_char_map['*'] = 1; + ctx->mark_char_map['_'] = 1; + ctx->mark_char_map['`'] = 1; + ctx->mark_char_map['&'] = 1; + ctx->mark_char_map[';'] = 1; + ctx->mark_char_map['<'] = 1; + ctx->mark_char_map['>'] = 1; + ctx->mark_char_map['['] = 1; + ctx->mark_char_map['!'] = 1; + ctx->mark_char_map[']'] = 1; + ctx->mark_char_map['\0'] = 1; + + if(ctx->parser.flags & (MD_FLAG_STRIKETHROUGH | MD_FLAG_SUBSCRIPTS)) + ctx->mark_char_map['~'] = 1; + + if(ctx->parser.flags & MD_FLAG_SUPERSCRIPTS) + ctx->mark_char_map['^'] = 1; + + if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS) + ctx->mark_char_map['$'] = 1; + + if(ctx->parser.flags & MD_FLAG_HIGHLIGHT) + ctx->mark_char_map['='] = 1; + + if(ctx->parser.flags & MD_FLAG_INSERT) + ctx->mark_char_map['+'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS) + ctx->mark_char_map['@'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS) + ctx->mark_char_map[':'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) + ctx->mark_char_map['.'] = 1; + + if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS) || + (ctx->parser.flags & MD_FLAG_SPOILERS)) + ctx->mark_char_map['|'] = 1; + + if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { + int i; + + for(i = 0; i < (int) sizeof(ctx->mark_char_map); i++) { + if(ISWHITESPACE_(i)) + ctx->mark_char_map[i] = 1; + } + } +} + +static int +md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + MD_MARK* opener, MD_MARK* closer, + OFF last_potential_closers[CODESPAN_MARK_MAXLEN], + int* p_reached_paragraph_end) +{ + OFF opener_beg = beg; + OFF opener_end; + OFF closer_beg; + OFF closer_end; + SZ mark_len; + OFF line_end; + int has_space_after_opener = false; + int has_eol_after_opener = false; + int has_space_before_closer = false; + int has_eol_before_closer = false; + int has_only_space = true; + MD_SIZE line_index = 0; + + line_end = lines[0].end; + opener_end = opener_beg; + while(opener_end < line_end && CH(opener_end) == _T('`')) + opener_end++; + has_space_after_opener = (opener_end < line_end && CH(opener_end) == _T(' ')); + has_eol_after_opener = (opener_end == line_end); + + /* The caller needs to know end of the opening mark even if we fail. */ + opener->end = opener_end; + + mark_len = opener_end - opener_beg; + if(mark_len > CODESPAN_MARK_MAXLEN) + return false; + + /* Check whether we already know there is no closer of this length. + * If so, re-scan does no sense. This fixes issue #59. */ + if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end || + (*p_reached_paragraph_end && last_potential_closers[mark_len-1] < opener_end)) + return false; + + closer_beg = opener_end; + closer_end = opener_end; + + /* Find closer mark. */ + while(true) { + while(closer_beg < line_end && CH(closer_beg) != _T('`')) { + if(CH(closer_beg) != _T(' ')) + has_only_space = false; + closer_beg++; + } + closer_end = closer_beg; + while(closer_end < line_end && CH(closer_end) == _T('`')) + closer_end++; + + if(closer_end - closer_beg == mark_len) { + /* Success. */ + has_space_before_closer = (closer_beg > lines[line_index].beg && CH(closer_beg-1) == _T(' ')); + has_eol_before_closer = (closer_beg == lines[line_index].beg); + break; + } + + if(closer_end - closer_beg > 0) { + /* We have found a back-tick which is not part of the closer. */ + has_only_space = false; + + /* But if we eventually fail, remember it as a potential closer + * of its own length for future attempts. This mitigates needs for + * rescans. */ + if(closer_end - closer_beg < CODESPAN_MARK_MAXLEN) { + if(closer_beg > last_potential_closers[closer_end - closer_beg - 1]) + last_potential_closers[closer_end - closer_beg - 1] = closer_beg; + } + } + + if(closer_end >= line_end) { + line_index++; + if(line_index >= n_lines) { + /* Reached end of the paragraph and still nothing. */ + *p_reached_paragraph_end = true; + return false; + } + /* Try on the next line. */ + line_end = lines[line_index].end; + closer_beg = lines[line_index].beg; + } else { + closer_beg = closer_end; + } + } + + /* If there is a space or a new line both after and before the opener + * (and if the code span is not made of spaces only), consume one initial + * and one trailing space as part of the marks. */ + if(!has_only_space && + (has_space_after_opener || has_eol_after_opener) && + (has_space_before_closer || has_eol_before_closer)) + { + if(has_space_after_opener) + opener_end++; + else + opener_end = lines[1].beg; + + if(has_space_before_closer) + closer_beg--; + else { + /* Go back to the end of prev line */ + closer_beg = lines[line_index-1].end; + /* But restore any trailing whitespace */ + while(closer_beg < ctx->size && ISBLANK(closer_beg)) + closer_beg++; + } + } + + opener->ch = _T('`'); + opener->beg = opener_beg; + opener->end = opener_end; + opener->flags = MD_MARK_POTENTIAL_OPENER; + closer->ch = _T('`'); + closer->beg = closer_beg; + closer->end = closer_end; + closer->flags = MD_MARK_POTENTIAL_CLOSER; + return true; +} + +static int +md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg+1; + + MD_ASSERT(CH(beg) == _T('<')); + + /* Check for scheme. */ + if(off >= max_end || !ISALNUM(off)) + return false; + off++; + while(1) { + if(off >= max_end) + return false; + if(off - beg > 32) + return false; + if(CH(off) == _T(':') && off - beg >= 3) + break; + if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) + return false; + off++; + } + + /* Check the path after the scheme. */ + while(off < max_end && CH(off) != _T('>')) { + if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<')) + return false; + off++; + } + + if(off >= max_end) + return false; + + MD_ASSERT(CH(off) == _T('>')); + *p_end = off+1; + return true; +} + +static int +md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg + 1; + int label_len; + + MD_ASSERT(CH(beg) == _T('<')); + + /* The code should correspond to this regexp: + /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+ + @[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + */ + + /* Username (before '@'). */ + while(off < max_end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) + off++; + if(off <= beg+1) + return false; + + /* '@' */ + if(off >= max_end || CH(off) != _T('@')) + return false; + off++; + + /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum + * characters or '-', but '-' is not allowed as first or last char. */ + label_len = 0; + while(off < max_end) { + if(ISALNUM(off)) + label_len++; + else if(CH(off) == _T('-') && label_len > 0) + label_len++; + else if(CH(off) == _T('.') && label_len > 0 && CH(off-1) != _T('-')) + label_len = 0; + else + break; + + if(label_len > 63) + return false; + + off++; + } + + if(label_len <= 0 || off >= max_end || CH(off) != _T('>') || CH(off-1) == _T('-')) + return false; + + *p_end = off+1; + return true; +} + +static int +md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto) +{ + if(md_is_autolink_uri(ctx, beg, max_end, p_end)) { + *p_missing_mailto = false; + return true; + } + + if(md_is_autolink_email(ctx, beg, max_end, p_end)) { + *p_missing_mailto = true; + return true; + } + + return false; +} + +static int +md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) +{ + MD_SIZE line_index; + int ret = 0; + MD_MARK* mark; + OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 }; + int codespan_scanned_till_paragraph_end = false; + + for(line_index = 0; line_index < n_lines; line_index++) { + const MD_LINE* line = &lines[line_index]; + OFF off = line->beg; + + while(true) { + CHAR ch; + +#ifdef MD4C_USE_UTF16 + /* For UTF-16, mark_char_map[] covers only ASCII. */ + #define IS_MARK_CHAR(off) ((CH(off) < SIZEOF_ARRAY(ctx->mark_char_map)) && \ + (ctx->mark_char_map[(unsigned char) CH(off)])) +#else + /* For 8-bit encodings, mark_char_map[] covers all 256 elements. */ + #define IS_MARK_CHAR(off) (ctx->mark_char_map[(unsigned char) CH(off)]) +#endif + + /* Optimization: Use some loop unrolling. */ + while(off + 3 < line->end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1) + && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3)) + off += 4; + while(off < line->end && !IS_MARK_CHAR(off+0)) + off++; + + if(off >= line->end) + break; + + ch = CH(off); + + /* A backslash escape. + * It can go beyond line->end as it may involve escaped new + * line to form a hard break. */ + if(ch == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + /* Hard-break cannot be on the last line of the block. */ + if(!ISNEWLINE(off+1) || line_index+1 < n_lines) + ADD_MARK(ch, off, off+2, MD_MARK_RESOLVED); + off += 2; + continue; + } + + /* A potential (string) emphasis start/end. */ + if(ch == _T('*') || ch == _T('_')) { + OFF tmp = off+1; + int left_level; /* What precedes: 0 = whitespace; 1 = punctuation; 2 = other char. */ + int right_level; /* What follows: 0 = whitespace; 1 = punctuation; 2 = other char. */ + + while(tmp < line->end && CH(tmp) == ch) + tmp++; + + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + left_level = 0; + else if(ISUNICODEPUNCTBEFORE(off)) + left_level = 1; + else + left_level = 2; + + if(tmp == line->end || ISUNICODEWHITESPACE(tmp)) + right_level = 0; + else if(ISUNICODEPUNCT(tmp)) + right_level = 1; + else + right_level = 2; + + /* Intra-word underscore doesn't have special meaning. */ + if(ch == _T('_') && left_level == 2 && right_level == 2) { + left_level = 0; + right_level = 0; + } + + if(left_level != 0 || right_level != 0) { + unsigned flags = 0; + + if(left_level > 0 && left_level >= right_level) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(right_level > 0 && right_level >= left_level) + flags |= MD_MARK_POTENTIAL_OPENER; + if(flags == (MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER)) + flags |= MD_MARK_EMPH_OC; + + /* For "the rule of three" we need to remember the original + * size of the mark (modulo three), before we potentially + * split the mark when being later resolved partially by some + * shorter closer. */ + switch((tmp - off) % 3) { + case 0: flags |= MD_MARK_EMPH_MOD3_0; break; + case 1: flags |= MD_MARK_EMPH_MOD3_1; break; + case 2: flags |= MD_MARK_EMPH_MOD3_2; break; + } + + ADD_MARK(ch, off, tmp, flags); + + /* During resolving, multiple asterisks may have to be + * split into independent span start/ends. Consider e.g. + * "**foo* bar*". Therefore we push also some empty dummy + * marks to have enough space for that. */ + off++; + while(off < tmp) { + ADD_MARK('D', off, off, 0); + off++; + } + continue; + } + + off = tmp; + continue; + } + + /* A potential code span start/end. */ + if(ch == _T('`')) { + MD_MARK opener; + MD_MARK closer; + int is_code_span; + + is_code_span = md_is_code_span(ctx, line, n_lines - line_index, off, + &opener, &closer, codespan_last_potential_closers, + &codespan_scanned_till_paragraph_end); + if(is_code_span) { + ADD_MARK(opener.ch, opener.beg, opener.end, opener.flags); + ADD_MARK(closer.ch, closer.beg, closer.end, closer.flags); + md_resolve_range(ctx, ctx->n_marks-2, ctx->n_marks-1); + off = closer.end; + + /* Advance the current line accordingly. */ + if(off > line->end) + line = md_lookup_line(off, lines, n_lines, &line_index); + continue; + } + + off = opener.end; + continue; + } + + /* A potential entity start. */ + if(ch == _T('&')) { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + off++; + continue; + } + + /* A potential entity end. */ + if(ch == _T(';')) { + /* We surely cannot be entity unless the previous mark is '&'. */ + if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].ch == _T('&')) + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + + off++; + continue; + } + + /* A potential autolink or raw HTML start/end. */ + if(ch == _T('<')) { + int is_autolink; + OFF autolink_end; + int missing_mailto; + + if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) { + int is_html; + OFF html_end; + + /* Given the nature of the raw HTML, we have to recognize + * it here. Doing so later in md_analyze_lt_gt() could + * open can of worms of quadratic complexity. */ + is_html = md_is_html_any(ctx, line, n_lines - line_index, off, + lines[n_lines-1].end, &html_end); + if(is_html) { + ADD_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED); + ADD_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = html_end; + + /* Advance the current line accordingly. */ + if(off > line->end) + line = md_lookup_line(off, lines, n_lines, &line_index); + continue; + } + } + + is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end, + &autolink_end, &missing_mailto); + if(is_autolink) { + unsigned flags = MD_MARK_RESOLVED | MD_MARK_AUTOLINK; + if(missing_mailto) + flags |= MD_MARK_AUTOLINK_MISSING_MAILTO; + + ADD_MARK(_T('<'), off, off+1, MD_MARK_OPENER | flags); + ADD_MARK(_T('>'), autolink_end-1, autolink_end, MD_MARK_CLOSER | flags); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = autolink_end; + continue; + } + + off++; + continue; + } + + /* A potential link, footnote and similar or its part. */ + if(ch == _T('[') || (ch == _T('!') && off+1 < line->end && CH(off+1) == _T('['))) { + if(ch == _T('!')) { + ADD_MARK(ch, off+1, off+2, MD_MARK_POTENTIAL_OPENER | MD_MARK_BRACKET_CANBEIMAGE); + off += 2; + } else { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + off += 1; + } + + /* Two dummies to make enough place for data we need if it is + * a link. */ + ADD_MARK('D', off, off, 0); + ADD_MARK('D', off, off, 0); + continue; + } + if(ch == _T(']')) { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + off++; + continue; + } + + /* A potential permissive e-mail autolink. */ + if(ch == _T('@')) { + if(line->beg + 1 <= off && ISALNUM(off-1) && + off + 3 < line->end && ISALNUM(off+1)) + { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + } + + off++; + continue; + } + + /* A potential permissive URL autolink. */ + if(ch == _T(':')) { + static const struct { + const CHAR* scheme; + SZ scheme_size; + const CHAR* suffix; + SZ suffix_size; + } scheme_map[] = { + /* In the order from the most frequently used, arguably. */ + { _T("http"), 4, _T("//"), 2 }, + { _T("https"), 5, _T("//"), 2 }, + { _T("ftp"), 3, _T("//"), 2 } + }; + int scheme_index; + + for(scheme_index = 0; scheme_index < (int) SIZEOF_ARRAY(scheme_map); scheme_index++) { + const CHAR* scheme = scheme_map[scheme_index].scheme; + const SZ scheme_size = scheme_map[scheme_index].scheme_size; + const CHAR* suffix = scheme_map[scheme_index].suffix; + const SZ suffix_size = scheme_map[scheme_index].suffix_size; + + if(line->beg + scheme_size <= off && md_ascii_eq(STR(off-scheme_size), scheme, scheme_size) && + off + 1 + suffix_size < line->end && md_ascii_eq(STR(off+1), suffix, suffix_size)) + { + ADD_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + off += 1 + suffix_size; + break; + } + } + + off++; + continue; + } + + /* A potential permissive WWW autolink. */ + if(ch == _T('.')) { + if(line->beg + 3 <= off && md_ascii_eq(STR(off-3), _T("www"), 3) && + (off-3 == line->beg || ISUNICODEWHITESPACEBEFORE(off-3) || ISUNICODEPUNCTBEFORE(off-3))) + { + ADD_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + off++; + continue; + } + + off++; + continue; + } + + /* We may need pipes for tables (cell delimiter), for wiki-links + * Note we coalesce spans of pipes into a single mark. + * + * - Tables may use spans of any length. + * - Wiki-links use only (unresolved) spans of length 1. + * - Spoilers use use only (unresolved) spans of length 2. + */ + if(ch == _T('|')) { + OFF tmp = off + 1; + while(tmp < line->end && CH(tmp) == _T('|')) + tmp++; + if(table_mode || + (tmp - off == 1 && (ctx->parser.flags & MD_FLAG_WIKILINKS)) || + (tmp - off == 2 && (ctx->parser.flags & MD_FLAG_SPOILERS))) + ADD_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); + off = tmp; + continue; + } + + /* A potential superscript start/end: ^text^ */ + if(ch == _T('^') && (ctx->parser.flags & MD_FLAG_SUPERSCRIPTS)) { + OFF tmp = off + 1; + + while(tmp < line->end && CH(tmp) == _T('^')) + tmp++; + + /* Only a single caret is a superscript delimiter; longer runs are literal. */ + if(tmp - off == 1) { + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + /* Cannot open before whitespace; cannot close after whitespace. */ + if(off + 1 >= line->end || ISUNICODEWHITESPACE(off + 1)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, off + 1, flags); + } + + off = tmp; + continue; + } + + /* A potential highlight start/end: ==text== */ + if(ch == _T('=') && (ctx->parser.flags & MD_FLAG_HIGHLIGHT)) { + OFF tmp = off + 1; + + while(tmp < line->end && CH(tmp) == _T('=')) + tmp++; + + /* Only exactly two equals signs form a highlight delimiter. */ + if(tmp - off == 2) { + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + /* Cannot open before whitespace; cannot close after whitespace. */ + if(tmp >= line->end || ISUNICODEWHITESPACE(tmp)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* A potential insert start/end: ++text++ */ + if(ch == _T('+') && (ctx->parser.flags & MD_FLAG_INSERT)) { + OFF tmp = off + 1; + + while(tmp < line->end && CH(tmp) == _T('+')) + tmp++; + + /* Only exactly two plus signs form a insert delimiter. */ + if(tmp - off == 2) { + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + /* Cannot open before whitespace; cannot close after whitespace. */ + if(tmp >= line->end || ISUNICODEWHITESPACE(tmp)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* A potential strikethrough/subscript start/end. */ + if(ch == _T('~')) { + OFF tmp = off + 1; + + while(tmp < line->end && CH(tmp) == _T('~')) + tmp++; + + if(tmp - off == 1 && (ctx->parser.flags & MD_FLAG_SUBSCRIPTS)) { + /* Subscript: can open after any non-whitespace, cannot open + * before whitespace; cannot close after whitespace. */ + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + if(off + 1 >= line->end || ISUNICODEWHITESPACE(off + 1)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, off + 1, flags); + } else if(tmp - off <= 2 && (ctx->parser.flags & MD_FLAG_STRIKETHROUGH)) { + /* Strikethrough: standard GFM left/right-flanking rules. */ + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off) && !ISUNICODEPUNCTBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(tmp < line->end && !ISUNICODEWHITESPACE(tmp) && !ISUNICODEPUNCT(tmp)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* A potential equation start/end. */ + if(ch == _T('$')) { + OFF tmp = off + 1; + + while(tmp < line->end && CH(tmp) == _T('$')) + tmp++; + + if(tmp - off <= 2) { + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off) && !ISUNICODEPUNCTBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(tmp < line->end && !ISUNICODEWHITESPACE(tmp) && !ISUNICODEPUNCT(tmp)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* Turn non-trivial whitespace into single space. */ + if(ISWHITESPACE_(ch)) { + OFF tmp = off+1; + + while(tmp < line->end && ISWHITESPACE(tmp)) + tmp++; + + if(tmp - off > 1 || ch != _T(' ')) + ADD_MARK(ch, off, tmp, MD_MARK_RESOLVED); + + off = tmp; + continue; + } + + /* NULL character. */ + if(ch == _T('\0')) { + ADD_MARK(ch, off, off+1, MD_MARK_RESOLVED); + off++; + continue; + } + + off++; + } + } + + /* Add a dummy mark at the end of the mark vector to simplify + * process_inlines(). */ + ADD_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); + +abort: + return ret; +} + +static void +md_analyze_bracket(MD_CTX* ctx, int mark_index) +{ + /* We cannot really resolve links here as for that we would need + * more context. E.g. a following pair of brackets (reference link), + * or enclosing pair of brackets (if the inner is the link, the outer + * one cannot be.) + * + * Therefore we here only construct a list of '[' ']' pairs ordered by + * position of the closer. This allows us to analyze what is or is not + * link in the right order, from inside to outside in case of nested + * brackets. + * + * The resolving itself is deferred to md_resolve_brackets(). + */ + + MD_MARK* mark = &ctx->marks[mark_index]; + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) { + if(BRACKET_OPENERS.top >= 0) + ctx->marks[BRACKET_OPENERS.top].flags |= MD_MARK_BRACKET_HASNESTED; + + md_mark_stack_push(ctx, &BRACKET_OPENERS, mark_index); + return; + } + + if(BRACKET_OPENERS.top >= 0) { + int opener_index = md_mark_stack_pop(ctx, &BRACKET_OPENERS); + MD_MARK* opener = &ctx->marks[opener_index]; + + /* Interconnect the opener and closer. */ + opener->next = mark_index; + mark->prev = opener_index; + + /* Add the pair into a list of potential brackets for md_resolve_brackets(). + * Note we misuse opener->prev for this as opener->next points to its + * closer. */ + if(ctx->unresolved_link_tail >= 0) + ctx->marks[ctx->unresolved_link_tail].prev = opener_index; + else + ctx->unresolved_link_head = opener_index; + ctx->unresolved_link_tail = opener_index; + opener->prev = -1; + } +} + +/* Forward declaration. */ +static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end); + +/* Try to resolve a bracket pair as a wiki link '[[destination]]' or + * '[[destination|label]]'. + * Returns true if resolved, false if not a wiki link, -1 on error. */ +static int +md_resolve_bracket_wikilink(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int opener_index, int closer_index, + MD_MARK* opener, MD_MARK* closer, + MD_MARK* next_opener, MD_MARK* next_closer, + OFF* last_link_beg, OFF* last_link_end, + int* p_opener_index) +{ + MD_MARK* delim = NULL; + int delim_index; + OFF dest_beg, dest_end; + OFF off; + + if(!(ctx->parser.flags & MD_FLAG_WIKILINKS)) + return false; + + if(opener->ch != _T('[') || opener->end - opener->beg != 1 || + next_opener == NULL || next_opener->ch != _T('[') || next_opener->end - next_opener->beg != 1 || + next_closer == NULL || next_closer->ch != _T(']') || next_closer->end - next_closer->beg != 1) + return false; + + /* Check that the next_opener and next_closer are nested properly. */ + if(next_opener->beg != opener->beg - 1 || next_closer->beg != closer->beg + 1) + return false; + + /* We don't allow destination to be longer than 100 characters. + * Lets scan to see whether there is '|'. (If not then the whole + * wiki-link has to be below the 100 characters.) */ + delim_index = opener_index + 1; + while(delim_index < closer_index) { + MD_MARK* m = &ctx->marks[delim_index]; + if(m->ch == _T('|') && m->end - m->beg == 1 && !(m->flags & MD_MARK_RESOLVED)) { + delim = m; + break; + } + if(m->ch != _T('D')) { + if(m->beg - opener->end > 100) + break; + if(m->ch != _T('D') && (m->flags & MD_MARK_OPENER)) + delim_index = m->next; + } + delim_index++; + } + + dest_beg = opener->end; + dest_end = (delim != NULL) ? delim->beg : closer->beg; + if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) + return false; + + /* There may not be any new line in the destination. */ + for(off = dest_beg; off < dest_end; off++) { + if(ISNEWLINE(off)) + return false; + } + + md_pop_openers(ctx, opener_index); + + if(delim != NULL) { + if(delim->end < closer->beg) { + md_disable_marks(ctx, opener_index+1, delim_index); + delim->flags |= MD_MARK_RESOLVED; + opener->end = delim->beg; + } else { + /* The pipe is just before the closer: [[foo|]] */ + md_disable_marks(ctx, opener_index+1, closer_index); + closer->beg = delim->beg; + } + } + + opener->beg = next_opener->beg; + closer->end = next_closer->end; + md_resolve_range(ctx, opener_index, closer_index); + + *last_link_beg = opener->beg; + *last_link_end = closer->end; + + if(delim != NULL) + md_analyze_link_contents(ctx, lines, n_lines, delim_index+1, closer_index); + + *p_opener_index = next_opener->prev; + return true; +} + +/* Resolve footnote references [^label] in the current block. */ +static int +md_resolve_bracket_footnote(MD_CTX* ctx, MD_MARK* opener, MD_MARK* closer, + OFF* last_link_beg, OFF* last_link_end, + int* p_opener_index) +{ + MD_MARK* index_mark; + MD_FOOTNOTE_DEF* def; + OFF label_beg, label_end; + + if(!(ctx->parser.flags & MD_FLAG_FOOTNOTES)) + return false; + if(opener->ch != _T('[') || opener->end >= ctx->size || CH(opener->end) != _T('^')) + return false; + + /* Expand the opener to eat the '^' */ + opener->end++; + closer = &ctx->marks[opener->next]; + + /* Verify the label satisfies the label rules. */ + label_beg = opener->end; + if(!md_is_footnote_label(ctx, label_beg, &label_end) || label_end != closer->beg) + return false; + + if(label_beg >= label_end) + return false; /* empty label */ + + def = md_lookup_footnote_def(ctx, STR(label_beg), label_end - label_beg); + if(def == NULL) + return false; + + /* Assign index on first reference. */ + if(def->index == 0) + def->index = ++ctx->next_footnote_index; + def->ref_count++; + + /* Store the public callback details in the dummy mark after the opener. */ + index_mark = opener + 1; + MD_ASSERT(index_mark->ch == _T('D')); + index_mark->beg = def->index; + index_mark->end = def->ref_count; + + /* Mark as resolved. */ + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED | MD_MARK_BRACKET_FOOTNOTEREF; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED | MD_MARK_BRACKET_FOOTNOTEREF; + *last_link_beg = opener->beg; + *last_link_end = closer->end; + + *p_opener_index = opener->prev; + return true; +} + +/* Try to resolve a bracket pair as a CommonMark link or image. + * Returns -1 on error, 0 otherwise. */ +static int +md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int opener_index, int closer_index, + MD_MARK* opener, MD_MARK* closer, + MD_MARK* next_opener, MD_MARK* next_closer, + int* p_next_index, + OFF* last_link_beg, OFF* last_link_end, + OFF* last_img_beg, OFF* last_img_end) +{ + MD_LINK_ATTR attr; + int is_link = false; + + if(next_opener != NULL && next_opener->beg == closer->end) { + if(next_closer->beg > closer->end + 1) { + /* Might be full reference link. */ + if(!(next_opener->flags & MD_MARK_BRACKET_HASNESTED)) + is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr); + } else { + /* Might be shortcut reference link. */ + if(!(opener->flags & MD_MARK_BRACKET_HASNESTED)) + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + } + + if(is_link < 0) + return -1; + + if(is_link) { + /* Eat the 2nd "[...]". */ + closer->end = next_closer->end; + + /* Do not analyze the label as a standalone link in the next + * iteration. */ + *p_next_index = ctx->marks[*p_next_index].prev; + } + } else { + if(closer->end < ctx->size && CH(closer->end) == _T('(')) { + /* Might be inline link. */ + OFF inline_link_end = UINT_MAX; + int following_mark_index = closer_index + 1; + + is_link = md_is_inline_link_spec(ctx, lines, n_lines, closer->end, &inline_link_end, &attr); + if(is_link < 0) + return -1; + + /* Check the closing ')' is not inside an already resolved range + * (i.e. a range with a higher priority), e.g. a code span. */ + if(is_link) { + while(following_mark_index < ctx->n_marks) { + MD_MARK* mark = &ctx->marks[following_mark_index]; + + if(mark->beg >= inline_link_end) + break; + if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { + if(ctx->marks[mark->next].beg >= inline_link_end) { + /* Cancel the link status. */ + if(attr.title_needs_free) + free(attr.title); + is_link = false; + break; + } + + following_mark_index = mark->next + 1; + } else { + following_mark_index++; + } + } + } + + if(is_link) { + /* Eat the "(...)" */ + closer->end = inline_link_end; + md_disable_marks(ctx, closer_index+1, following_mark_index); + } + } + + if(!is_link) { + /* Might be collapsed reference link. */ + if(!(opener->flags & MD_MARK_BRACKET_HASNESTED)) + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + if(is_link < 0) + return -1; + } + } + + if(is_link) { + /* Resolve the brackets as a link. */ + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + /* If it is a link, we store the destination and title in the two + * dummy marks after the opener. */ + MD_ASSERT(ctx->marks[opener_index+1].ch == _T('D')); + ctx->marks[opener_index+1].beg = attr.dest_beg; + ctx->marks[opener_index+1].end = attr.dest_end; + + MD_ASSERT(ctx->marks[opener_index+2].ch == _T('D')); + md_mark_store_ptr(ctx, opener_index+2, attr.title); + /* The title might or might not have been allocated for us. */ + if(attr.title_needs_free) + md_mark_stack_push(ctx, &ctx->ptr_stack, opener_index+2); + ctx->marks[opener_index+2].prev = attr.title_size; + + if(opener->ch == _T('[')) { + *last_link_beg = opener->beg; + *last_link_end = closer->end; + } else { + *last_img_beg = opener->beg; + *last_img_end = closer->end; + } + + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + + /* If the link text is formed by nothing but permissive autolink, + * suppress the autolink. + * See https://github.com/mity/md4c/issues/152 for more info. */ + if(ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) { + MD_MARK* first_nested; + MD_MARK* last_nested; + + first_nested = opener + 1; + while(first_nested->ch == _T('D') && first_nested < closer) + first_nested++; + + last_nested = closer - 1; + while(first_nested->ch == _T('D') && last_nested > opener) + last_nested--; + + if((first_nested->flags & MD_MARK_RESOLVED) && + first_nested->beg == opener->end && + ISANYOF_(first_nested->ch, _T("@:.")) && + first_nested->next == (last_nested - ctx->marks) && + last_nested->end == closer->beg) + { + first_nested->ch = _T('D'); + first_nested->flags &= ~MD_MARK_RESOLVED; + last_nested->ch = _T('D'); + last_nested->flags &= ~MD_MARK_RESOLVED; + } + } + } + + return 0; +} + +/* Resolve bracket pairs as links, wiki links, or (in a 2nd pass) footnotes. */ +static int +md_resolve_brackets(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + int opener_index = ctx->unresolved_link_head; + OFF last_link_beg = 0; + OFF last_link_end = 0; + OFF last_img_beg = 0; + OFF last_img_end = 0; + int ret; + + /* Note we here analyze from inner to outer as the marks are ordered + * by closer->beg. */ + while(opener_index >= 0) { + MD_MARK* opener = &ctx->marks[opener_index]; + int closer_index = opener->next; + MD_MARK* closer = &ctx->marks[closer_index]; + int next_index = opener->prev; + MD_MARK* next_opener; + MD_MARK* next_closer; + + if(opener->ch == _T('D')) { + /* We could have this disabled in previous iterations, and + * processing would be just burning CPU cycles. */ + opener_index = next_index; + continue; + } + + if(next_index >= 0) { + next_opener = &ctx->marks[next_index]; + next_closer = &ctx->marks[next_opener->next]; + } else { + next_opener = NULL; + next_closer = NULL; + } + + /* We can perhaps be an image? */ + if(opener->flags & MD_MARK_BRACKET_CANBEIMAGE) { + opener->ch = _T('!'); + opener->beg--; + } + + /* If nested ("[ [ ] ]"), we need to make sure that: + * - The outer does not end inside of (...) belonging to the inner. + * - The outer cannot be link if the inner is link (but this does not apply to images). */ + if((opener->beg < last_link_beg && closer->end < last_link_end) || + (opener->beg < last_img_beg && closer->end < last_img_end) || + (opener->beg < last_link_end && opener->ch != _T('!'))) + { + opener_index = next_index; + continue; + } + + ret = md_resolve_bracket_footnote(ctx, opener, closer, + &last_link_beg, &last_link_end, &opener_index); + if(ret < 0) + return -1; + if(ret > 0) + continue; + + ret = md_resolve_bracket_wikilink(ctx, lines, n_lines, opener_index, closer_index, + opener, closer, next_opener, next_closer, + &last_link_beg, &last_link_end, &opener_index); + if(ret < 0) + return -1; + if(ret > 0) + continue; + + ret = md_resolve_bracket_link(ctx, lines, n_lines, opener_index, closer_index, + opener, closer, next_opener, next_closer, &next_index, + &last_link_beg, &last_link_end, &last_img_beg, &last_img_end); + if(ret < 0) + return -1; + + opener_index = next_index; + } + + return 0; +} + +/* Analyze whether the mark '&' starts a HTML entity. + * If so, update its flags as well as flags of corresponding closer ';'. */ +static void +md_analyze_entity(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + MD_MARK* closer; + OFF off; + + /* Cannot be entity if there is no closer as the next mark. + * (Any other mark between would mean strange character which cannot be + * part of the entity. + * + * So we can do all the work on '&' and do not call this later for the + * closing mark ';'. + */ + if(mark_index + 1 >= ctx->n_marks) + return; + closer = &ctx->marks[mark_index+1]; + if(closer->ch != ';') + return; + + if(md_is_entity(ctx, opener->beg, closer->end, &off)) { + MD_ASSERT(off == closer->end); + + md_resolve_range(ctx, mark_index, mark_index+1); + opener->end = closer->end; + } +} + +static void +md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* FIXME: With MD_FLAG_SPOILERS, we reserve double "||" for spoiler marks + * (potentially inside the table). But is it worth it the incompatibility + * with GFM? Perhaps it would be better to disallow spoilers in a table? */ + if((ctx->parser.flags & MD_FLAG_SPOILERS) && mark->end - mark->beg == 2) + return; + + mark->flags |= MD_MARK_RESOLVED; + mark->next = -1; + + if(ctx->table_cell_boundaries_head < 0) + ctx->table_cell_boundaries_head = mark_index; + else + ctx->marks[ctx->table_cell_boundaries_tail].next = mark_index; + ctx->table_cell_boundaries_tail = mark_index; + ctx->n_table_cell_boundaries += mark->end - mark->beg; +} + +/* Split a longer mark into two. The new mark takes the given count of + * characters. May only be called if an adequate number of dummy 'D' marks + * follows. + */ +static int +md_split_emph_mark(MD_CTX* ctx, int mark_index, SZ n) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + int new_mark_index = mark_index + (mark->end - mark->beg - n); + MD_MARK* dummy = &ctx->marks[new_mark_index]; + + MD_ASSERT(mark->end - mark->beg > n); + MD_ASSERT(dummy->ch == 'D'); + + memcpy(dummy, mark, sizeof(MD_MARK)); + mark->end -= n; + dummy->beg = mark->end; + + return new_mark_index; +} + +static void +md_analyze_emph(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* If we can be a closer, try to resolve with the preceding opener. */ + if(mark->flags & MD_MARK_POTENTIAL_CLOSER) { + MD_MARK* opener = NULL; + int opener_index = 0; + MD_MARKSTACK* opener_stacks[6]; + int i, n_opener_stacks; + unsigned flags = mark->flags; + + n_opener_stacks = 0; + + /* Apply the rule of 3 */ + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0 | MD_MARK_EMPH_OC); + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1 | MD_MARK_EMPH_OC); + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2 | MD_MARK_EMPH_OC); + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0); + if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1); + if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2); + + /* Opener is the most recent mark from the allowed stacks. */ + for(i = 0; i < n_opener_stacks; i++) { + if(opener_stacks[i]->top >= 0) { + int m_index = opener_stacks[i]->top; + MD_MARK* m = &ctx->marks[m_index]; + + if(opener == NULL || m->end > opener->end) { + opener_index = m_index; + opener = m; + } + } + } + + /* Resolve, if we have found matching opener. */ + if(opener != NULL) { + SZ opener_size = opener->end - opener->beg; + SZ closer_size = mark->end - mark->beg; + MD_MARKSTACK* stack = md_opener_stack(ctx, opener_index); + + if(opener_size > closer_size) { + opener_index = md_split_emph_mark(ctx, opener_index, closer_size); + md_mark_stack_push(ctx, stack, opener_index); + } else if(opener_size < closer_size) { + md_split_emph_mark(ctx, mark_index, closer_size - opener_size); + } + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + } + + /* If we could not resolve as closer, we may be yet be an opener. */ + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, md_emph_stack(ctx, mark->ch, mark->flags), mark_index); +} + +static void +md_analyze_tilde(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKSTACK* stack = md_opener_stack(ctx, mark_index); + + /* We attempt to be Github Flavored Markdown compatible here. GFM accepts + * only tildes sequences of length 1 and 2, and the length of the opener + * and closer has to match. */ + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && stack->top >= 0) { + int opener_index = stack->top; + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, stack, mark_index); +} + +static void +md_analyze_caret(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && CARET_OPENERS.top >= 0) { + int opener_index = CARET_OPENERS.top; + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &CARET_OPENERS, mark_index); +} + +static void +md_analyze_dollar(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && DOLLAR_OPENERS.top >= 0) { + /* If the potential closer has a non-matching number of $, discard */ + MD_MARK* opener = &ctx->marks[DOLLAR_OPENERS.top]; + int opener_index = DOLLAR_OPENERS.top; + MD_MARK* closer = mark; + int closer_index = mark_index; + + if(opener->end - opener->beg == closer->end - closer->beg) { + /* We are the matching closer */ + md_pop_openers(ctx, opener_index); + md_disable_marks(ctx, opener_index+1, closer_index); + md_resolve_range(ctx, opener_index, closer_index); + + /* Discard all pending openers: Latex math span do not allow + * nesting. */ + DOLLAR_OPENERS.top = -1; + return; + } + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &DOLLAR_OPENERS, mark_index); +} + +static void +md_analyze_spoiler(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* Only double "||" are recognized as spoiler marks. */ + if((mark->flags & MD_MARK_RESOLVED) || mark->end - mark->beg != 2) + return; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && PIPE_OPENERS.top >= 0) { + int opener_index = PIPE_OPENERS.top; + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &PIPE_OPENERS, mark_index); +} + +static void +md_analyze_highlight(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* Only "==" is recognized as a highlight mark. */ + if(mark->end - mark->beg != 2) + return; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && EQUAL_OPENERS.top >= 0) { + int opener_index = EQUAL_OPENERS.top; + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &EQUAL_OPENERS, mark_index); +} + +static void +md_analyze_insert(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* Only "++" is recognized as a insert mark. */ + if(mark->end - mark->beg != 2) + return; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && PLUS_OPENERS.top >= 0) { + int opener_index = PLUS_OPENERS.top; + + md_pop_openers(ctx, opener_index); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &PLUS_OPENERS, mark_index); +} + +static MD_MARK* +md_scan_left_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor) +{ + MD_MARK* mark; + + for(mark = mark_from; mark >= ctx->marks; mark--) { + if(mark->ch == 'D' || mark->beg > off) + continue; + if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) { + if(p_cursor != NULL) + *p_cursor = mark; + return mark; + } + if(mark->end <= off) + break; + } + + if(p_cursor != NULL) + *p_cursor = mark; + return NULL; +} + +static MD_MARK* +md_scan_right_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor) +{ + MD_MARK* mark; + + for(mark = mark_from; mark < ctx->marks + ctx->n_marks; mark++) { + if(mark->ch == 'D' || mark->end <= off) + continue; + if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) { + if(p_cursor != NULL) + *p_cursor = mark; + return mark; + } + if(mark->beg > off) + break; + } + + if(p_cursor != NULL) + *p_cursor = mark; + return NULL; +} + +static int +md_analyze_permissive_autolink_segment(MD_CTX* ctx, OFF off, OFF end, OFF* p_end, + int scan_backwards, MD_CHAR component_delim, const MD_CHAR* word_extra, + const MD_CHAR* word_delims, MD_MARK** p_cursor) +{ + int n_components = 0; + int n_open_brackets = 0; + int seen_word_delim = true; + int seen_component_delim = true; + OFF component_beg = off; + + if(word_extra == NULL) + word_extra = _T(""); + if(word_delims == NULL) + word_delims = _T(""); + + while(off != end) { + if(scan_backwards) + off--; + + /* Only accept extra and delimiter characters if they're not part of a + * resolved mark. */ + if(!ISALNUM(off) && !ISWHITESPACE(off)) { + if((!scan_backwards && md_scan_right_for_resolved_mark(ctx, *p_cursor, off, p_cursor) != NULL) || + (scan_backwards && md_scan_left_for_resolved_mark(ctx, *p_cursor, off, p_cursor) != NULL)) { + if(scan_backwards) + off++; + break; + } + } + + /* The autolink can be _inside_ brackets so we disallow unbalanced bracket pairs in the URL. + * (Note the brackets are not allowed in e-mail username, so we happily skip this in that case.) */ + if(!scan_backwards) { + if(CH(off) == _T('(')) { + n_open_brackets++; + } else if(CH(off) == _T(')')) { + if(n_open_brackets <= 0) + break; + n_open_brackets--; + } + } + + if(ISALNUM(off) || ISANYOF(off, word_extra)) { + seen_word_delim = false; + seen_component_delim = false; + } else { + if(seen_word_delim) + break; + + if(ISANYOF(off, word_delims)) { + seen_word_delim = true; + } else if(component_delim != _T('\0') && CH(off) == component_delim) { + if(seen_component_delim) + break; + seen_component_delim = true; + component_beg = off; + n_components++; + } else { + if(scan_backwards) + off++; + break; + } + } + + if(!scan_backwards) + off++; + } + + /* Rollback falsely consumed delimiter. */ + if(seen_word_delim || seen_component_delim) + off = (scan_backwards ? off+1 : off-1); + + if(off != component_beg) + n_components++; + + if(n_open_brackets != 0) + return -1; + + *p_end = off; + return n_components; +} + +static void +md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + MD_MARK* closer = &ctx->marks[mark_index + 1]; /* The dummy. */ + OFF line_beg = closer->beg; /* md_collect_mark() sets this for us */ + OFF line_end = closer->end; /* ditto */ + OFF beg = opener->beg; + OFF end = opener->end; + MD_MARK* left_cursor = opener; + MD_MARK* right_cursor = opener; + + MD_ASSERT(closer->ch == 'D'); + + /* E-mail requires the user name (before '@', i.e. scanning backwards). */ + if(opener->ch == '@') { + MD_ASSERT(CH(opener->beg) == _T('@')); + if(md_analyze_permissive_autolink_segment(ctx, beg, line_beg, &beg, true, + _T('\0'), NULL, _T(".-_+"), &left_cursor) < 1) + return; + + /* Swallow optional "mailto:" or "xmpp:" before it. */ + if(beg >= 7 && md_ascii_eq(_T("mailto:"), STR(beg-7), 7)) + beg -= 7; + else if(beg >= 5 && md_ascii_eq(_T("xmpp:"), STR(beg-5), 5)) + beg -= 5; + else + opener->flags |= MD_MARK_AUTOLINK_MISSING_MAILTO; + } + + /* Verify there's line boundary, whitespace, allowed punctuation or + * resolved opener mark just before the suspected autolink. */ + if(beg > line_beg && !ISUNICODEWHITESPACEBEFORE(beg) && !ISANYOF(beg-1, _T("({["))) { + MD_MARK* mark; + + mark = md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor); + if(mark == NULL || !(mark->flags & MD_MARK_OPENER)) + return; + } + + /* Scan for hostname segment. Hostname is mandatory and requires at least two + * components delimited with a dot. */ + if(md_analyze_permissive_autolink_segment(ctx, end, line_end, &end, false, + _T('.'), NULL, _T("-_"), &right_cursor) < 2) + return; + + if(opener->ch != '@') { + /* Scan for path segment. */ + if(end < line_end && CH(end) == _T('/')) { + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + _T('/'), _T(".+-_~%"), NULL, &right_cursor) < 0) + return; + + /* Path can also end with additional '/' if its a directory. */ + if(end < line_end && CH(end) == _T('/')) + end++; + } + + /* Scan for query segment. */ + if(end < line_end && CH(end) == _T('?')) { + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + _T('&'), _T("._=()"), _T("+-"), &right_cursor) < 0) + return; + } + + /* Scan for fragment segment. */ + if(end < line_end && CH(end) == _T('#')) { + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + _T('\0'), NULL, _T(".-+_"), &right_cursor) < 0) + return; + } + } + + /* Verify there's line boundary, whitespace, allowed punctuation or + * resolved closer mark just after the suspected autolink. */ + if(end < line_end && !ISUNICODEWHITESPACE(end) && !ISANYOF(end, _T(")}].!?,;"))) { + MD_MARK* mark; + + mark = md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor); + if(mark == NULL || !(mark->flags & MD_MARK_CLOSER)) + return; + } + + /* Success, we are an autolink. */ + opener->beg = beg; + opener->end = beg; + closer->beg = end; + closer->end = end; + closer->ch = opener->ch; + md_resolve_range(ctx, mark_index, mark_index + 1); +} + +#define MD_ANALYZE_NOSKIP_EMPH 0x01 + +static inline void +md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end, const CHAR* mark_chars, const CHAR* noskip_mark_chars) +{ + int i = mark_beg; + OFF last_end = lines[0].beg; + + MD_UNUSED(lines); + MD_UNUSED(n_lines); + + while(i < mark_end) { + MD_MARK* mark = &ctx->marks[i]; + + /* Skip resolved spans. */ + if(mark->flags & MD_MARK_RESOLVED) { + if((mark->flags & MD_MARK_OPENER) && + (noskip_mark_chars == NULL || !(ISANYOF_(mark->ch, noskip_mark_chars)))) + { + MD_ASSERT(i < mark->next); + i = mark->next + 1; + } else { + i++; + } + continue; + } + + /* Skip marks we do not want to deal with. */ + if(!ISANYOF_(mark->ch, mark_chars)) { + i++; + continue; + } + + /* The resolving in previous step could have expanded a mark. */ + if(mark->beg < last_end) { + i++; + continue; + } + + /* Analyze the mark. */ + switch(mark->ch) { + case '[': MD_FALLTHROUGH(); + case '!': MD_FALLTHROUGH(); + case ']': md_analyze_bracket(ctx, i); break; + case '&': md_analyze_entity(ctx, i); break; + case '_': MD_FALLTHROUGH(); + case '*': md_analyze_emph(ctx, i); break; + case '~': md_analyze_tilde(ctx, i); break; + case '^': md_analyze_caret(ctx, i); break; + case '$': md_analyze_dollar(ctx, i); break; + case '.': MD_FALLTHROUGH(); + case ':': MD_FALLTHROUGH(); + case '@': md_analyze_permissive_autolink(ctx, i); break; + case '|': md_analyze_spoiler(ctx, i); break; + case '=': md_analyze_highlight(ctx, i); break; + case '+': md_analyze_insert(ctx, i); break; + } + + if(mark->flags & MD_MARK_RESOLVED) { + if(mark->flags & MD_MARK_OPENER) + last_end = ctx->marks[mark->next].end; + else + last_end = mark->end; + } + + i++; + } +} + +/* Analyze marks (build ctx->marks). */ +static int +md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) +{ + int i; + int ret; + + /* Reset the previously collected stack of marks. */ + ctx->n_marks = 0; + + /* Collect all marks. */ + MD_CHECK(md_collect_marks(ctx, lines, n_lines, table_mode)); + + /* (1) Bracket spans: links, wiki links, footnotes. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!"), NULL); + MD_CHECK(md_resolve_brackets(ctx, lines, n_lines)); + BRACKET_OPENERS.top = -1; + ctx->unresolved_link_head = -1; + ctx->unresolved_link_tail = -1; + + if(table_mode) { + /* (2) Analyze table cell boundaries. */ + MD_ASSERT(n_lines == 1); + ctx->n_table_cell_boundaries = 0; + for(i = 0; i < ctx->n_marks; i++) { + if(!(ctx->marks[i].flags & MD_MARK_RESOLVED) && ctx->marks[i].ch == '|') + md_analyze_table_cell_boundary(ctx, i); + } + return ret; + } + + /* (3) Emphasis and strong emphasis; permissive autolinks. */ + md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks); + +abort: + return ret; +} + +static void +md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end) +{ + int i; + CHAR emph_mark_types[16]; + SZ n_emph_mark_types = 0; + + emph_mark_types[n_emph_mark_types++] = _T('&'); + emph_mark_types[n_emph_mark_types++] = _T('*'); + emph_mark_types[n_emph_mark_types++] = _T('_'); + if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS) + emph_mark_types[n_emph_mark_types++] = _T('$'); + if(ctx->parser.flags & MD_FLAG_HIGHLIGHT) + emph_mark_types[n_emph_mark_types++] = _T('='); + if(ctx->parser.flags & MD_FLAG_INSERT) + emph_mark_types[n_emph_mark_types++] = _T('+'); + if(ctx->parser.flags & MD_FLAG_SPOILERS) + emph_mark_types[n_emph_mark_types++] = _T('|'); + if(ctx->parser.flags & MD_FLAG_SUPERSCRIPTS) + emph_mark_types[n_emph_mark_types++] = _T('^'); + if((ctx->parser.flags & MD_FLAG_STRIKETHROUGH) || (ctx->parser.flags & MD_FLAG_SUBSCRIPTS)) + emph_mark_types[n_emph_mark_types++] = _T('~'); + emph_mark_types[n_emph_mark_types] = _T('\0'); + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, emph_mark_types, NULL); + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) { + /* These have to be processed last, as they may be greedy and expand + * from their original mark. Also their implementation must be careful + * not to cross any (previously) resolved marks when doing so. */ + CHAR autolink_mark_types[16]; + SZ n_autolink_mark_types = 0; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS) + autolink_mark_types[n_autolink_mark_types++] = _T('@'); + if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS) + autolink_mark_types[n_autolink_mark_types++] = _T(':'); + if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) + autolink_mark_types[n_autolink_mark_types++] = _T('.'); + autolink_mark_types[n_autolink_mark_types] = _T('\0'); + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, autolink_mark_types, emph_mark_types); + } + + for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) + ctx->opener_stacks[i].top = -1; +} + +static int +md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type, + const CHAR* dest, SZ dest_size, int is_autolink, + const CHAR* title, SZ title_size) +{ + MD_ATTRIBUTE_BUILD href_build = { 0 }; + MD_ATTRIBUTE_BUILD title_build = { 0 }; + MD_SPAN_A_DETAIL det; + int ret = 0; + + /* Note we here rely on fact that MD_SPAN_A_DETAIL and + * MD_SPAN_IMG_DETAIL are binary-compatible. */ + memset(&det, 0, sizeof(MD_SPAN_A_DETAIL)); + MD_CHECK(md_build_attribute(ctx, dest, dest_size, + (is_autolink ? MD_BUILD_ATTR_NO_ESCAPES : 0), + &det.href, &href_build)); + MD_CHECK(md_build_attribute(ctx, title, title_size, 0, &det.title, &title_build)); + det.is_autolink = is_autolink; + if(enter) + MD_ENTER_SPAN(type, &det); + else + MD_LEAVE_SPAN(type, &det); + +abort: + md_free_attribute(ctx, &href_build); + md_free_attribute(ctx, &title_build); + return ret; +} + +static int +md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size) +{ + MD_ATTRIBUTE_BUILD target_build = { 0 }; + MD_SPAN_WIKILINK_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL)); + MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build)); + + if (enter) + MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det); + else + MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det); + +abort: + md_free_attribute(ctx, &target_build); + return ret; +} + +static int +md_enter_leave_span_footnote_ref(MD_CTX* ctx, unsigned int id, + unsigned int ref_id, const CHAR* label, SZ label_size) +{ + MD_ATTRIBUTE_BUILD label_build = { 0 }; + MD_SPAN_FOOTNOTE_REF_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_FOOTNOTE_REF_DETAIL)); + det.id = id; + det.ref_id = ref_id; + MD_CHECK(md_build_attribute(ctx, label, label_size, 0, + &det.label, &label_build)); + + MD_ENTER_SPAN(MD_SPAN_FOOTNOTE_REF, &det); + MD_LEAVE_SPAN(MD_SPAN_FOOTNOTE_REF, &det); + +abort: + md_free_attribute(ctx, &label_build); + return ret; +} + + +/* Render the output, accordingly to the analyzed ctx->marks. */ +static int +md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + MD_TEXTTYPE text_type; + const MD_LINE* line = lines; + MD_MARK* prev_mark = NULL; + MD_MARK* mark; + OFF off = lines[0].beg; + OFF end = lines[n_lines-1].end; + OFF tmp; + int enforce_hardbreak = 0; + int ret = 0; + + /* Find first resolved mark. Note there is always at least one resolved + * mark, the dummy last one after the end of the latest line we actually + * never really reach. This saves us of a lot of special checks and cases + * in this function. */ + mark = ctx->marks; + while(!(mark->flags & MD_MARK_RESOLVED)) + mark++; + + text_type = MD_TEXT_NORMAL; + + while(1) { + /* Process the text up to the next mark or end-of-line. */ + tmp = (line->end < mark->beg ? line->end : mark->beg); + if(tmp > off) { + MD_TEXT(text_type, STR(off), tmp - off); + off = tmp; + } + + /* If reached the mark, process it and move to next one. */ + if(off >= mark->beg) { + switch(mark->ch) { + case '\\': /* Backslash escape. */ + if(ISNEWLINE(mark->beg+1)) + enforce_hardbreak = 1; + else + MD_TEXT(text_type, STR(mark->beg+1), 1); + break; + + case ' ': /* Non-trivial space. */ + MD_TEXT(text_type, _T(" "), 1); + break; + + case '`': /* Code span. */ + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_CODE; + } else { + MD_LEAVE_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '_': /* Underline (or emphasis if we fall through). */ + if(ctx->parser.flags & MD_FLAG_UNDERLINE) { + if(mark->flags & MD_MARK_OPENER) { + while(off < mark->end) { + MD_ENTER_SPAN(MD_SPAN_U, NULL); + off++; + } + } else { + while(off < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_U, NULL); + off++; + } + } + break; + } + MD_FALLTHROUGH(); + + case '*': /* Emphasis, strong emphasis. */ + if(mark->flags & MD_MARK_OPENER) { + if((mark->end - off) % 2) { + MD_ENTER_SPAN(MD_SPAN_EM, NULL); + off++; + } + while(off + 1 < mark->end) { + MD_ENTER_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + } else { + while(off + 1 < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + if((mark->end - off) % 2) { + MD_LEAVE_SPAN(MD_SPAN_EM, NULL); + off++; + } + } + break; + + case '~': + if(mark->end - mark->beg == 1 && (ctx->parser.flags & MD_FLAG_SUBSCRIPTS)) { + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_SUBSCRIPT, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_SUBSCRIPT, NULL); + } else { + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_DEL, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_DEL, NULL); + } + break; + + case '^': + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_SUPERSCRIPT, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_SUPERSCRIPT, NULL); + break; + + case '|': + if(mark->end - mark->beg == 2) { + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_SPOILER, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_SPOILER, NULL); + } + break; + + case '=': + if(mark->end - mark->beg == 2) { + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_MARK, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_MARK, NULL); + } + break; + + case '+': + if(mark->end - mark->beg == 2) { + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_INS, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_INS, NULL); + } + break; + + case '$': + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_LATEXMATH; + } else { + MD_LEAVE_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '[': /* Footnote reference, link, wiki link, or image. */ + case '!': + case ']': + { + const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]); + const MD_MARK* closer = &ctx->marks[opener->next]; + const MD_MARK* dest_mark; + const MD_MARK* title_mark; + + /* Footnote reference: self-contained span, no text emitted. + * Only the opener is ever processed here; the closer mark + * is guaranteed to be skipped by the off-advance below. */ + if(opener->flags & MD_MARK_BRACKET_FOOTNOTEREF) { + MD_MARK* index_mark = (MD_MARK*) opener + 1; + MD_ASSERT(mark->ch != ']'); + MD_ASSERT(index_mark->ch == 'D'); + MD_CHECK(md_enter_leave_span_footnote_ref(ctx, + (unsigned int) index_mark->beg, + (unsigned int) index_mark->end, + STR(opener->end), closer->beg - opener->end)); + /* Redirect the opener's end past the whole [^label] + * so that the post-switch "off = mark->end" skips + * the label text and the closing ]. */ + ((MD_MARK*) mark)->end = closer->end; + break; + } + + if ((opener->ch == '[' && closer->ch == ']') && + opener->end - opener->beg >= 2 && + closer->end - closer->beg >= 2) + { + int has_label = (opener->end - opener->beg > 2); + SZ target_sz; + + if(has_label) + target_sz = opener->end - (opener->beg+2); + else + target_sz = closer->beg - opener->end; + + MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'), + has_label ? STR(opener->beg+2) : STR(opener->end), + target_sz)); + + break; + } + + dest_mark = opener+1; + MD_ASSERT(dest_mark->ch == 'D'); + title_mark = opener+2; + MD_ASSERT(title_mark->ch == 'D'); + + MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), + (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A), + STR(dest_mark->beg), dest_mark->end - dest_mark->beg, false, + md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), + title_mark->prev)); + + /* link/image closer may span multiple lines. */ + if(mark->ch == ']') { + while(mark->end > line->end) + line++; + } + + break; + } + + case '<': + case '>': /* Autolink or raw HTML. */ + if(!(mark->flags & MD_MARK_AUTOLINK)) { + /* Raw HTML. */ + if(mark->flags & MD_MARK_OPENER) + text_type = MD_TEXT_HTML; + else + text_type = MD_TEXT_NORMAL; + break; + } + /* Pass through, if auto-link. */ + MD_FALLTHROUGH(); + + case '@': /* Permissive e-mail autolink. */ + case ':': /* Permissive URL autolink. */ + case '.': /* Permissive WWW autolink. */ + { + MD_MARK* opener = ((mark->flags & MD_MARK_OPENER) ? mark : &ctx->marks[mark->prev]); + MD_MARK* closer = &ctx->marks[opener->next]; + const CHAR* dest = STR(opener->end); + SZ dest_size = closer->beg - opener->end; + + /* For permissive auto-links we do not know closer mark + * position at the time of md_collect_marks(), therefore + * it can be out-of-order in ctx->marks[]. + * + * With this flag, we make sure that we output the closer + * only if we processed the opener. */ + if(mark->flags & MD_MARK_OPENER) + closer->flags |= MD_MARK_VALIDPERMISSIVEAUTOLINK; + + if(opener->ch == '.' || + (ISANYOF2_(opener->ch, _T('@'), _T('<')) && (opener->flags & MD_MARK_AUTOLINK_MISSING_MAILTO))) + { + dest_size += 7; + MD_TEMP_BUFFER(dest_size * sizeof(CHAR)); + memcpy(ctx->buffer, + (opener->ch == '.' ? _T("http://") : _T("mailto:")), + 7 * sizeof(CHAR)); + memcpy(ctx->buffer + 7, dest, (dest_size-7) * sizeof(CHAR)); + dest = ctx->buffer; + } + + if(closer->flags & MD_MARK_VALIDPERMISSIVEAUTOLINK) + MD_CHECK(md_enter_leave_span_a(ctx, (mark->flags & MD_MARK_OPENER), + MD_SPAN_A, dest, dest_size, true, NULL, 0)); + break; + } + + case '&': /* Entity. */ + MD_TEXT(MD_TEXT_ENTITY, STR(mark->beg), mark->end - mark->beg); + break; + + case '\0': + MD_TEXT(MD_TEXT_NULLCHAR, _T(""), 1); + break; + + case 127: + goto abort; + } + + off = mark->end; + + /* Move to next resolved mark. */ + prev_mark = mark; + mark++; + while(!(mark->flags & MD_MARK_RESOLVED) || mark->beg < off) + mark++; + } + + /* If reached end of line, move to next one. */ + if(off >= line->end) { + /* If it is the last line, we are done. */ + if(off >= end) + break; + + if(text_type == MD_TEXT_CODE || text_type == MD_TEXT_LATEXMATH) { + MD_ASSERT(prev_mark != NULL); + MD_ASSERT(ISANYOF2_(prev_mark->ch, '`', '$') && (prev_mark->flags & MD_MARK_OPENER)); + MD_ASSERT(ISANYOF2_(mark->ch, '`', '$') && (mark->flags & MD_MARK_CLOSER)); + + /* Inside a code span, trailing line whitespace has to be + * outputted. */ + tmp = off; + while(off < ctx->size && ISBLANK(off)) + off++; + if(off > tmp) + MD_TEXT(text_type, STR(tmp), off-tmp); + + /* and new lines are transformed into single spaces. Emit the + * space when off rests on an interior newline still preceding + * the closer. Testing off == line->end here instead drops the + * space when the line ends in whitespace, because the loop + * above advances off past line->end over the trailing blanks + * (CommonMark code-span examples 335, 337, 640). */ + if(off < mark->beg && ISNEWLINE(off)) + MD_TEXT(text_type, _T(" "), 1); + } else if(text_type == MD_TEXT_HTML) { + /* Inside raw HTML, we output the new line verbatim, including + * any trailing spaces. */ + tmp = off; + while(tmp < end && ISBLANK(tmp)) + tmp++; + if(tmp > off) + MD_TEXT(MD_TEXT_HTML, STR(off), tmp - off); + MD_TEXT(MD_TEXT_HTML, _T("\n"), 1); + } else { + /* Output soft or hard line break. */ + MD_TEXTTYPE break_type = MD_TEXT_SOFTBR; + + if(text_type == MD_TEXT_NORMAL) { + if(enforce_hardbreak || (ctx->parser.flags & MD_FLAG_HARD_SOFT_BREAKS)) { + break_type = MD_TEXT_BR; + } else { + while(off < ctx->size && ISBLANK(off)) + off++; + if(off >= line->end + 2 && CH(off-2) == _T(' ') && CH(off-1) == _T(' ') && ISNEWLINE(off)) + break_type = MD_TEXT_BR; + } + } + + MD_TEXT(break_type, _T("\n"), 1); + } + + /* Move to the next line. */ + line++; + off = MAX(off, line->beg); + + enforce_hardbreak = 0; + } + } + +abort: + return ret; +} + + +/*************************** + *** Processing Tables *** + ***************************/ + +static void +md_analyze_table_alignment(MD_CTX* ctx, OFF beg, OFF end, MD_ALIGN* align, int n_align) +{ + static const MD_ALIGN align_map[] = { MD_ALIGN_DEFAULT, MD_ALIGN_LEFT, MD_ALIGN_RIGHT, MD_ALIGN_CENTER }; + OFF off = beg; + + while(n_align > 0) { + int index = 0; /* index into align_map[] */ + + while(off < end && CH(off) != _T('-')) + off++; + if(off > beg && CH(off-1) == _T(':')) + index |= 1; + while(off < end && CH(off) == _T('-')) + off++; + if(off < end && CH(off) == _T(':')) + index |= 2; + + *align = align_map[index]; + align++; + n_align--; + } + +} + +/* Forward declaration. */ +static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines); + +static int +md_process_table_cell(MD_CTX* ctx, MD_BLOCKTYPE cell_type, MD_ALIGN align, OFF beg, OFF end) +{ + MD_LINE line; + MD_BLOCK_TD_DETAIL det; + int ret = 0; + + while(beg < end && ISWHITESPACE(beg)) + beg++; + while(end > beg && ISWHITESPACE(end-1)) + end--; + + det.align = align; + line.beg = beg; + line.end = end; + + MD_ENTER_BLOCK(cell_type, &det); + MD_CHECK(md_process_normal_block_contents(ctx, &line, 1)); + MD_LEAVE_BLOCK(cell_type, &det); + +abort: + return ret; +} + +static int +md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, + const MD_ALIGN* align, int col_count) +{ + MD_LINE line; + OFF* cell_begs = NULL; + int i, j, k, n; + int ret = 0; + MD_MARK* mark = NULL; + + line.beg = beg; + line.end = end; + + /* Break the line into table cells by identifying pipe characters who + * form the cell boundary. */ + MD_CHECK(md_analyze_inlines(ctx, &line, 1, true)); + + /* We have to remember the cell boundaries in local buffer because + * ctx->marks[] shall be reused during cell contents processing. */ + n = ctx->n_table_cell_boundaries + 2; + cell_begs = (OFF*) malloc(n * sizeof(OFF)); + if(cell_begs == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + j = 0; + + /* First cell of the row may or may not be started with '|'. */ + if(ctx->table_cell_boundaries_head < 0 || + ctx->marks[ctx->table_cell_boundaries_head].beg > beg) + cell_begs[j++] = beg; + for(i = ctx->table_cell_boundaries_head; i >= 0; i = ctx->marks[i].next) { + mark = &ctx->marks[i]; + for(k = 0; k < (int)(mark->end - mark->beg); k++) + cell_begs[j++] = mark->beg + k + 1; + } + if(mark == NULL || mark->end < end) + cell_begs[j++] = end+1; + + /* Process cells. */ + MD_ENTER_BLOCK(MD_BLOCK_TR, NULL); + for(i = 0; i < j-1 && i < col_count; i++) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[i], cell_begs[i], cell_begs[i+1]-1)); + /* Make sure we report enough table cells even if the current table contains + * too few of them. */ + while(i < col_count) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[i++], 0, 0)); + MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL); + +abort: + free(cell_begs); + + ctx->table_cell_boundaries_head = -1; + ctx->table_cell_boundaries_tail = -1; + + return ret; +} + +static int +md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, MD_SIZE n_lines) +{ + MD_ALIGN* align; + MD_SIZE line_index; + int ret = 0; + + /* At least two lines have to be present: The column headers and the line + * with the underlines. */ + MD_ASSERT(n_lines >= 2); + + align = malloc(col_count * sizeof(MD_ALIGN)); + if(align == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + + md_analyze_table_alignment(ctx, lines[1].beg, lines[1].end, align, col_count); + + MD_ENTER_BLOCK(MD_BLOCK_THEAD, NULL); + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TH, + lines[0].beg, lines[0].end, align, col_count)); + MD_LEAVE_BLOCK(MD_BLOCK_THEAD, NULL); + + if(n_lines > 2) { + MD_ENTER_BLOCK(MD_BLOCK_TBODY, NULL); + for(line_index = 2; line_index < n_lines; line_index++) { + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TD, + lines[line_index].beg, lines[line_index].end, align, col_count)); + } + MD_LEAVE_BLOCK(MD_BLOCK_TBODY, NULL); + } + +abort: + free(align); + return ret; +} + + +/************************** + *** Processing Block *** + **************************/ + +#define MD_BLOCK_CONTAINER_OPENER 0x01 +#define MD_BLOCK_CONTAINER_CLOSER 0x02 +#define MD_BLOCK_CONTAINER (MD_BLOCK_CONTAINER_OPENER | MD_BLOCK_CONTAINER_CLOSER) +#define MD_BLOCK_LOOSE_LIST 0x04 +#define MD_BLOCK_SETEXT_HEADER 0x08 + +struct MD_BLOCK_tag { + MD_BLOCKTYPE type : 8; + unsigned flags : 8; + + /* MD_BLOCK_H: Header level (1 - 6) + * MD_BLOCK_CODE: Non-zero if fenced, zero if indented. + * MD_BLOCK_LI: Task mark character (0 if not task list item, 'x', 'X' or ' '). + * MD_BLOCK_TABLE: Column count (as determined by the table underline). + * MD_BLOCK_ADMONITION: Admonition type. + */ + unsigned data : 16; + + /* Leaf blocks: Count of lines (MD_LINE or MD_VERBATIMLINE) on the block. + * MD_BLOCK_LI: Task mark offset in the input doc. + * MD_BLOCK_OL: Start item number. + */ + MD_SIZE n_lines; +}; + +struct MD_CONTAINER_tag { + CHAR ch; + unsigned is_loose : 1; + unsigned is_task : 1; + unsigned is_admonition : 1; + unsigned admonition_type : 3; + unsigned start; + unsigned mark_indent; + unsigned contents_indent; + OFF block_byte_off; + OFF task_mark_off; +}; + + +static int +md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + int i; + int ret; + + MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, false)); + MD_CHECK(md_process_inlines(ctx, lines, n_lines)); + +abort: + /* Free any temporary memory blocks stored within some dummy marks. */ + for(i = ctx->ptr_stack.top; i >= 0; i = ctx->marks[i].next) + free(md_mark_get_ptr(ctx, i)); + ctx->ptr_stack.top = -1; + + return ret; +} + +static int +md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, MD_SIZE n_lines) +{ + static const CHAR indent_chunk_str[] = _T(" "); + static const SZ indent_chunk_size = SIZEOF_ARRAY(indent_chunk_str) - 1; + + MD_SIZE line_index; + int ret = 0; + + for(line_index = 0; line_index < n_lines; line_index++) { + const MD_VERBATIMLINE* line = &lines[line_index]; + int indent = line->indent; + + MD_ASSERT(indent >= 0); + + /* Output code indentation. */ + while(indent > (int) indent_chunk_size) { + MD_TEXT(text_type, indent_chunk_str, indent_chunk_size); + indent -= indent_chunk_size; + } + if(indent > 0) + MD_TEXT(text_type, indent_chunk_str, indent); + + /* Output the code line itself. */ + MD_TEXT_INSECURE(text_type, STR(line->beg), line->end - line->beg); + + /* Enforce end-of-line. */ + MD_TEXT(text_type, _T("\n"), 1); + } + +abort: + return ret; +} + +static int +md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, MD_SIZE n_lines) +{ + if(is_fenced) { + /* Skip the first line in case of fenced code: It is the fence. + * (Only the starting fence is present due to logic in md_analyze_line().) */ + lines++; + n_lines--; + } else { + /* Ignore blank lines at start/end of indented code block. */ + while(n_lines > 0 && lines[0].beg == lines[0].end) { + lines++; + n_lines--; + } + while(n_lines > 0 && lines[n_lines-1].beg == lines[n_lines-1].end) { + n_lines--; + } + } + + if(n_lines == 0) + return 0; + + return md_process_verbatim_block_contents(ctx, MD_TEXT_CODE, lines, n_lines); +} + +static int +md_setup_fenced_code_detail(MD_CTX* ctx, const MD_BLOCK* block, MD_BLOCK_CODE_DETAIL* det, + MD_ATTRIBUTE_BUILD* info_build, MD_ATTRIBUTE_BUILD* lang_build) +{ + const MD_VERBATIMLINE* fence_line = (const MD_VERBATIMLINE*)(block + 1); + OFF beg = fence_line->beg; + OFF end = fence_line->end; + OFF lang_end; + CHAR fence_ch = CH(fence_line->beg); + int ret = 0; + + /* Skip the fence itself. */ + while(beg < ctx->size && CH(beg) == fence_ch) + beg++; + /* Trim initial spaces. */ + while(beg < ctx->size && CH(beg) == _T(' ')) + beg++; + + /* Trim trailing spaces. */ + while(end > beg && CH(end-1) == _T(' ')) + end--; + + /* Build info string attribute. */ + MD_CHECK(md_build_attribute(ctx, STR(beg), end - beg, 0, &det->info, info_build)); + + /* Build info string attribute. */ + lang_end = beg; + while(lang_end < end && !ISWHITESPACE(lang_end)) + lang_end++; + MD_CHECK(md_build_attribute(ctx, STR(beg), lang_end - beg, 0, &det->lang, lang_build)); + + det->fence_char = fence_ch; + +abort: + return ret; +} + +static int +md_process_leaf_block(MD_CTX* ctx, MD_BLOCK* block) +{ + union { + MD_BLOCK_H_DETAIL header; + MD_BLOCK_CODE_DETAIL code; + MD_BLOCK_TABLE_DETAIL table; + MD_BLOCK_BLANK_DETAIL blank; + } det; + MD_ATTRIBUTE_BUILD info_build = { 0 }; + MD_ATTRIBUTE_BUILD lang_build = { 0 }; + int is_in_tight_list; + int clean_fence_code_detail = false; + int ret = 0; + + /* For large tables check the table density: If it's too low, lets suppress + * its interpretation as a table, as a safety measure against quadratic + * output size explosion. See https://github.com/mity/md4c/issues/345 */ + if(block->type == MD_BLOCK_TABLE) { + unsigned n_cols = block->data; + unsigned n_rows = block->n_lines; + + if(n_cols > 32 && n_rows > 4096 / n_cols) { + const MD_LINE* lines = (const MD_LINE*)(block + 1); + SZ table_input_size = n_rows; + unsigned i; + + for(i = 0; i < n_rows; i++) + table_input_size += lines[i].end - lines[i].beg; + + if(table_input_size / n_cols < n_rows / 4) { + /* Number of characters encoding the table in the input is + * lower then 25% of all cells to be generated? */ + MD_LOG("Suppressing too sparse table " + "(see https://github.com/mity/md4c/issues/345)"); + block->type = MD_BLOCK_P; + } + } + } + + memset(&det, 0, sizeof(det)); + + if(ctx->n_containers == 0) + is_in_tight_list = false; + else + is_in_tight_list = !ctx->containers[ctx->n_containers-1].is_loose; + + switch(block->type) { + case MD_BLOCK_H: + det.header.level = block->data; + break; + + case MD_BLOCK_CODE: + /* For fenced code block, we may need to set the info string. */ + if(block->data != 0) { + memset(&det.code, 0, sizeof(MD_BLOCK_CODE_DETAIL)); + clean_fence_code_detail = true; + MD_CHECK(md_setup_fenced_code_detail(ctx, block, &det.code, &info_build, &lang_build)); + } + break; + + case MD_BLOCK_TABLE: + det.table.col_count = block->data; + det.table.head_row_count = 1; + det.table.body_row_count = block->n_lines - 2; + break; + + case MD_BLOCK_BLANK: + det.blank.line_count = block->data; + break; + + default: + /* Noop. */ + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_ENTER_BLOCK(block->type, (void*) &det); + + /* Process the block contents accordingly to is type. */ + switch(block->type) { + case MD_BLOCK_HR: + case MD_BLOCK_BLANK: + /* noop (no contents) */ + break; + + case MD_BLOCK_CODE: + MD_CHECK(md_process_code_block_contents(ctx, (block->data != 0), + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_HTML: + MD_CHECK(md_process_verbatim_block_contents(ctx, MD_TEXT_HTML, + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_TABLE: + MD_CHECK(md_process_table_block_contents(ctx, block->data, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + + default: + MD_CHECK(md_process_normal_block_contents(ctx, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_LEAVE_BLOCK(block->type, (void*) &det); + +abort: + if(clean_fence_code_detail) { + md_free_attribute(ctx, &info_build); + md_free_attribute(ctx, &lang_build); + } + return ret; +} + +static const MD_CHAR* MD_ADMONITION_TAGS[] = { _T("note"), _T("tip"), _T("important"), _T("warning"), _T("caution") }; + +static int +md_process_all_blocks(MD_CTX* ctx) +{ + MD_TEXTTYPE adm_substr_types[1] = { MD_TEXT_NORMAL }; + MD_OFFSET adm_substr_offsets[2]; + int byte_off = 0; + int ret = 0; + + /* ctx->containers now is not needed for detection of lists and list items + * so we reuse it for tracking what lists are loose or tight. We rely + * on the fact the vector is large enough to hold the deepest nesting + * level of lists. */ + ctx->n_containers = 0; + + while(byte_off < ctx->n_block_bytes) { + MD_BLOCK* block = (MD_BLOCK*)((char*)ctx->block_bytes + byte_off); + union { + MD_BLOCK_UL_DETAIL ul; + MD_BLOCK_OL_DETAIL ol; + MD_BLOCK_LI_DETAIL li; + MD_BLOCK_ADMONITION_DETAIL adm; + } det; + + switch(block->type) { + case MD_BLOCK_UL: + det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? false : true; + det.ul.mark = (CHAR) block->data; + break; + + case MD_BLOCK_OL: + det.ol.start = block->n_lines; + det.ol.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? false : true; + det.ol.mark_delimiter = (CHAR) block->data; + break; + + case MD_BLOCK_LI: + det.li.is_task = (block->data != 0); + det.li.task_mark = (CHAR) block->data; + det.li.task_mark_offset = (OFF) block->n_lines; + break; + + case MD_BLOCK_ADMONITION: + adm_substr_offsets[0] = 0; + adm_substr_offsets[1] = (unsigned) md_strlen(MD_ADMONITION_TAGS[block->data]); + + det.adm.type.text = MD_ADMONITION_TAGS[block->data]; + det.adm.type.size = adm_substr_offsets[1]; + det.adm.type.substr_types = adm_substr_types; + det.adm.type.substr_offsets = adm_substr_offsets; + break; + + default: + /* noop */ + break; + } + + if(block->flags & MD_BLOCK_CONTAINER) { + if(block->flags & MD_BLOCK_CONTAINER_CLOSER) { + MD_LEAVE_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL || + block->type == MD_BLOCK_QUOTE || block->type == MD_BLOCK_ADMONITION) + ctx->n_containers--; + } + + if(block->flags & MD_BLOCK_CONTAINER_OPENER) { + MD_ENTER_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) { + ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST) ? true : false; + ctx->n_containers++; + } else if(block->type == MD_BLOCK_QUOTE || block->type == MD_BLOCK_ADMONITION) { + /* This causes that any text in a block quote, even if + * nested inside a tight list item, is wrapped with + *

...

. */ + ctx->containers[ctx->n_containers].is_loose = true; + ctx->n_containers++; + } + } + } else { + MD_CHECK(md_process_leaf_block(ctx, block)); + + if(block->type == MD_BLOCK_CODE || block->type == MD_BLOCK_HTML) + byte_off += block->n_lines * sizeof(MD_VERBATIMLINE); + else + byte_off += block->n_lines * sizeof(MD_LINE); + } + + byte_off += sizeof(MD_BLOCK); + } + + ctx->n_block_bytes = 0; + +abort: + return ret; +} + + +/************************************ + *** Grouping Lines into Blocks *** + ************************************/ + +static void* +md_push_block_bytes(MD_CTX* ctx, int n_bytes) +{ + void* ptr; + + if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { + void* new_block_bytes; + + ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 + ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 + : 512); + new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); + if(new_block_bytes == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + /* Fix the ->current_block after the reallocation. */ + if(ctx->current_block != NULL) { + OFF off_current_block = (OFF) ((char*) ctx->current_block - (char*) ctx->block_bytes); + ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block); + } + + ctx->block_bytes = new_block_bytes; + } + + ptr = (char*)ctx->block_bytes + ctx->n_block_bytes; + ctx->n_block_bytes += n_bytes; + return ptr; +} + +static int +md_start_new_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* line) +{ + MD_BLOCK* block; + + MD_ASSERT(ctx->current_block == NULL); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + switch(line->type) { + case MD_LINE_HR: + block->type = MD_BLOCK_HR; + break; + + case MD_LINE_ATXHEADER: + case MD_LINE_SETEXTHEADER: + block->type = MD_BLOCK_H; + break; + + case MD_LINE_FENCEDCODE: + case MD_LINE_INDENTEDCODE: + block->type = MD_BLOCK_CODE; + break; + + case MD_LINE_TEXT: + block->type = MD_BLOCK_P; + break; + + case MD_LINE_HTML: + block->type = MD_BLOCK_HTML; + break; + + case MD_LINE_BLANK: + case MD_LINE_SETEXTUNDERLINE: + case MD_LINE_TABLEUNDERLINE: + default: + MD_UNREACHABLE(); + break; + } + + block->flags = 0; + block->data = line->data; + block->n_lines = 0; + + ctx->current_block = block; + return 0; +} + +/* Forward declarations */ +static int md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer); +static void* md_push_block_bytes(MD_CTX* ctx, int n_bytes); + +/* Eat from start of current (textual) block any reference definitions and/or + * footnote definitions, and remember them. + * + * (Such definitions can only be at start of it as they cannot break a + * paragraph.) + */ +static int +md_consume_link_reference_definitions(MD_CTX* ctx) +{ + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + MD_SIZE n_lines = ctx->current_block->n_lines; + MD_SIZE n = 0; + bool inject_hr = false; + OFF ignored; + + while(n < n_lines) { + int n_consumed = 0; + + /* When footnotes are enabled, try footnote definition first for lines + * starting with [^, so they are not accidentally consumed as link ref + * definitions (which would also match [^label]: url). */ + if((ctx->parser.flags & MD_FLAG_FOOTNOTES) && + lines[n].beg + 1 < ctx->size && + CH(lines[n].beg) == _T('[') && CH(lines[n].beg + 1) == _T('^')) + { + n_consumed = md_is_footnote_definition(ctx, lines + n, n_lines - n); + if(n_consumed < 0) + return -1; + } + + if(n_consumed == 0) { + n_consumed = md_is_link_reference_definition(ctx, lines + n, n_lines - n); + if(n_consumed < 0) + return -1; + } + + if(n_consumed == 0) + break; + + n += n_consumed; + } + + /* If no link ref. def. was detected, leave the block intact. */ + if(n == 0) + return 0; + + /* We may need to turn the first line after the link ref. def(s) into HR. + * (https://github.com/mity/md4c/issues/414) */ + if(n < n_lines && md_is_hr_line(ctx, lines[n].beg, &ignored, &ignored)) { + inject_hr = true; + n++; /* Remove one more line below. */ + } + + if(n == n_lines) { + /* Undo the whole block. */ + ctx->n_block_bytes -= n_lines * sizeof(MD_LINE); + ctx->n_block_bytes -= sizeof(MD_BLOCK); + ctx->current_block = NULL; + } else { + /* Remove some initial lines from the block. */ + memmove(lines, lines + n, (n_lines - n) * sizeof(MD_LINE)); + ctx->current_block->n_lines -= n; + ctx->n_block_bytes -= n * sizeof(MD_LINE); + } + + if(inject_hr) { + MD_BLOCK* hr_block; + + hr_block = md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(hr_block == NULL) + return -1; + + if(ctx->current_block != NULL) { + memmove(ctx->current_block + 1, ctx->current_block, + (sizeof(MD_BLOCK) + ctx->current_block->n_lines * sizeof(MD_LINE))); + hr_block = ctx->current_block; + ctx->current_block++; + } + + memset(hr_block, 0, sizeof(MD_BLOCK)); + hr_block->type = MD_BLOCK_HR; + } + + return 0; +} + +static int +md_end_current_block(MD_CTX* ctx) +{ + int ret = 0; + + if(ctx->current_block == NULL) + return ret; + + /* Check whether there is a reference definition. (We do this here instead + * of in md_analyze_line() because reference definition can take multiple + * lines.) */ + if(ctx->current_block->type == MD_BLOCK_P || + (ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER))) + { + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + if(lines[0].beg < ctx->size && CH(lines[0].beg) == _T('[')) { + MD_CHECK(md_consume_link_reference_definitions(ctx)); + if(ctx->current_block == NULL) + return ret; + } + } + + if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) { + MD_SIZE n_lines = ctx->current_block->n_lines; + + if(n_lines > 1) { + /* Get rid of the underline. */ + ctx->current_block->n_lines--; + ctx->n_block_bytes -= sizeof(MD_LINE); + } else { + /* Only the underline has left after eating the ref. defs. + * Keep the line as beginning of a new ordinary paragraph. */ + ctx->current_block->type = MD_BLOCK_P; + return 0; + } + } + + /* Mark we are not building any block anymore. */ + ctx->current_block = NULL; + +abort: + return ret; +} + +static int +md_add_line_into_current_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* analysis) +{ + MD_ASSERT(ctx->current_block != NULL); + + if(ctx->current_block->type == MD_BLOCK_CODE || ctx->current_block->type == MD_BLOCK_HTML) { + MD_VERBATIMLINE* line; + + line = (MD_VERBATIMLINE*) md_push_block_bytes(ctx, sizeof(MD_VERBATIMLINE)); + if(line == NULL) + return -1; + + line->indent = analysis->indent; + line->beg = analysis->beg; + line->end = analysis->end; + } else { + MD_LINE* line; + + line = (MD_LINE*) md_push_block_bytes(ctx, sizeof(MD_LINE)); + if(line == NULL) + return -1; + + line->beg = analysis->beg; + line->end = analysis->end; + } + ctx->current_block->n_lines++; + + return 0; +} + +/* Part of the MD_FLAG_PRESERVEBLANKLINES implementation. */ +static int +md_flush_blank_lines(MD_CTX* ctx) +{ + MD_BLOCK* block; + + if(ctx->n_blank_lines == 0) + return 0; + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + block->type = MD_BLOCK_BLANK; + block->flags = 0; + block->data = ctx->n_blank_lines; + block->n_lines = 0; + + ctx->n_blank_lines = 0; + return 0; +} + +static int +md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, + unsigned data, unsigned flags) +{ + MD_BLOCK* block; + int ret = 0; + + MD_CHECK(md_flush_blank_lines(ctx)); + MD_CHECK(md_end_current_block(ctx)); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + block->type = type; + block->flags = flags; + block->data = data; + block->n_lines = start; + +abort: + return ret; +} + + + +/*********************** + *** Line Analysis *** + ***********************/ + +static int +md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) +{ + OFF off = beg + 1; + int n = 1; + + if(!ISANYOF(beg, _T("-_*"))) + return false; + + while(off < ctx->size && (CH(off) == CH(beg) || CH(off) == _T(' ') || CH(off) == _T('\t'))) { + if(CH(off) == CH(beg)) + n++; + off++; + } + + if(n < 3) { + *p_killer = off; + return false; + } + + /* Nothing else can be present on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) { + *p_killer = off; + return false; + } + + *p_end = off; + return true; +} + +static int +md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end, unsigned* p_level) +{ + int n; + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == _T('#') && off - beg < 7) + off++; + n = off - beg; + + if(n > 6) + return false; + *p_level = n; + + if(!(ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS) && off < ctx->size && + !ISBLANK(off) && !ISNEWLINE(off)) + return false; + + while(off < ctx->size && ISBLANK(off)) + off++; + *p_beg = off; + *p_end = off; + return true; +} + +static int +md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) +{ + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Optionally, space(s) or tabs can follow. */ + while(off < ctx->size && ISBLANK(off)) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + return false; + + *p_level = (CH(beg) == _T('=') ? 1 : 2); + *p_end = off; + return true; +} + +static int +md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) +{ + OFF off = beg; + int found_pipe = false; + unsigned col_count = 0; + + if(off < ctx->size && CH(off) == _T('|')) { + found_pipe = true; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + while(1) { + int delimited = false; + + /* Cell underline ("-----", ":----", "----:" or ":----:") */ + if(off < ctx->size && CH(off) == _T(':')) + off++; + if(off >= ctx->size || CH(off) != _T('-')) + return false; + while(off < ctx->size && CH(off) == _T('-')) + off++; + if(off < ctx->size && CH(off) == _T(':')) + off++; + + col_count++; + + /* Pipe delimiter (optional at the end of line). */ + while(off < ctx->size && ISWHITESPACE(off)) + off++; + if(off < ctx->size && CH(off) == _T('|')) { + delimited = true; + found_pipe = true; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + /* Success, if we reach end of line. */ + if(off >= ctx->size || ISNEWLINE(off)) + break; + + if(!delimited) + return false; + } + + if(!found_pipe) + return false; + + *p_end = off; + *p_col_count = col_count; + return true; +} + +static int +md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + OFF off = beg; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Fence must have at least three characters. */ + if(off - beg < 3) + return false; + + ctx->code_fence_length = off - beg; + + /* Optionally, space(s) can follow. */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* Optionally, an info string can follow. */ + while(off < ctx->size && !ISNEWLINE(off)) { + /* Backtick-based fence must not contain '`' in the info string. */ + if(CH(beg) == _T('`') && CH(off) == _T('`')) + return false; + off++; + } + + *p_end = off; + return true; +} + +static int +md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) +{ + OFF off = beg; + int ret = false; + + /* Closing fence must have at least the same length and use same char as + * opening one. */ + while(off < ctx->size && CH(off) == ch) + off++; + if(off - beg < ctx->code_fence_length) + goto out; + + /* Optionally, space(s) can follow */ + while(off < ctx->size && ISANYOF2(off, _T(' '), _T('\t'))) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + goto out; + + ret = true; + +out: + /* Note we set *p_end even on failure: If we are not closing fence, caller + * would eat the line anyway without any parsing. */ + *p_end = off; + return ret; +} + + +/* Helper data for md_is_html_block_start_condition() and + * md_is_html_block_end_condition() */ +typedef struct TAG_tag TAG; +struct TAG_tag { + const CHAR* name; + unsigned len : 8; +}; + +#ifdef X + #undef X +#endif +#define X(name) { _T(name), (sizeof(_T(name))-1) / sizeof(CHAR) } +#define Xend { NULL, 0 } + +static const TAG t1[] = { X("pre"), X("script"), X("style"), X("textarea"), Xend }; + +static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend }; +static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend }; +static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend }; +static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"), + X("div"), X("dl"), X("dt"), Xend }; +static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"), + X("form"), X("frame"), X("frameset"), Xend }; +static const TAG h6[] = { X("h1"), X("h2"), X("h3"), X("h4"), X("h5"), X("h6"), + X("head"), X("header"), X("hr"), X("html"), Xend }; +static const TAG i6[] = { X("iframe"), Xend }; +static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend }; +static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend }; +static const TAG n6[] = { X("nav"), X("noframes"), Xend }; +static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend }; +static const TAG p6[] = { X("p"), X("param"), Xend }; +static const TAG s6[] = { X("search"), X("section"), X("summary"), Xend }; +static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"), + X("thead"), X("title"), X("tr"), X("track"), Xend }; +static const TAG u6[] = { X("ul"), Xend }; +static const TAG v6[] = { X("video"), Xend }; +static const TAG xx[] = { Xend }; + +#undef X +#undef Xend + +/* Returns type of the raw HTML block, or false if it is not HTML block. + * (Refer to CommonMark specification for details about the types.) + */ +static int +md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) +{ + /* Type 6 is started by a long list of allowed tags. We use two-level + * tree to speed-up the search. */ + static const TAG* map6[26] = { + a6, b6, c6, d6, xx, f6, xx, h6, i6, xx, xx, l6, m6, + n6, o6, p6, xx, xx, s6, t6, u6, v6, xx, xx, xx, xx + }; + OFF off = beg + 1; + int i; + + /* Check for type 1: size) { + if(md_ascii_case_eq(STR(off), t1[i].name, t1[i].len)) + return 1; + } + } + + /* Check for type 2: "), 3, p_end) ? 2 : false); + + case 3: + return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : false); + + case 4: + return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : false); + + case 5: + return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : false); + + case 6: MD_FALLTHROUGH(); + case 7: + if(beg >= ctx->size || ISNEWLINE(beg)) { + /* Blank line ends types 6 and 7. */ + *p_end = beg; + return ctx->html_block_type; + } + return false; + + default: + MD_UNREACHABLE(); + } + return false; +} + + +static int +md_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* container) +{ + /* Block quote has no "items" like lists. */ + if(container->ch == _T('>')) + return false; + + if(container->ch != pivot->ch) + return false; + if(container->mark_indent > pivot->contents_indent) + return false; + + return true; +} + +static int +md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) +{ + if(ctx->n_containers >= ctx->alloc_containers) { + MD_CONTAINER* new_containers; + + ctx->alloc_containers = (ctx->alloc_containers > 0 + ? ctx->alloc_containers + ctx->alloc_containers / 2 + : 16); + new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); + if(new_containers == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + + ctx->containers = new_containers; + } + + memcpy(&ctx->containers[ctx->n_containers++], container, sizeof(MD_CONTAINER)); + return 0; +} + +static int +md_enter_child_containers(MD_CTX* ctx, int n_children) +{ + int i; + int ret = 0; + + for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) { + MD_CONTAINER* c = &ctx->containers[i]; + int is_ordered_list = false; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = true; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + /* Remember offset in ctx->block_bytes so we can revisit the + * block if we detect it is a loose list. */ + MD_CHECK(md_end_current_block(ctx)); + c->block_byte_off = ctx->n_block_bytes; + + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), + c->start, c->ch, MD_BLOCK_CONTAINER_OPENER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, + (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, + (c->is_admonition ? MD_BLOCK_ADMONITION : MD_BLOCK_QUOTE), + 0, c->admonition_type, MD_BLOCK_CONTAINER_OPENER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + } + +abort: + return ret; +} + +static int +md_leave_child_containers(MD_CTX* ctx, int n_keep) +{ + int ret = 0; + + while(ctx->n_containers > n_keep) { + MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1]; + int is_ordered_list = false; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = true; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0, + c->ch, MD_BLOCK_CONTAINER_CLOSER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, + (c->is_admonition ? MD_BLOCK_ADMONITION : MD_BLOCK_QUOTE), + 0, c->admonition_type, MD_BLOCK_CONTAINER_CLOSER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + + ctx->n_containers--; + } + +abort: + return ret; +} + +static int +md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTAINER* p_container) +{ + OFF off = beg; + OFF max_end; + + if(off >= ctx->size || indent >= ctx->code_indent_offset) + return false; + + /* Check for block quote mark. */ + if(CH(off) == _T('>')) { + off++; + p_container->ch = _T('>'); + p_container->is_loose = false; + p_container->is_task = false; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off; + return true; + } + + /* Check for list item bullet mark. */ + if(ISANYOF(off, _T("-+*")) && (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { + p_container->ch = CH(off); + p_container->is_loose = false; + p_container->is_task = false; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off+1; + return true; + } + + /* Check for ordered list item marks. */ + max_end = off + 9; + if(max_end > ctx->size) + max_end = ctx->size; + p_container->start = 0; + while(off < max_end && ISDIGIT(off)) { + p_container->start = p_container->start * 10 + CH(off) - _T('0'); + off++; + } + if(off > beg && + off < ctx->size && + (CH(off) == _T('.') || CH(off) == _T(')')) && + (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) + { + p_container->ch = CH(off); + p_container->is_loose = false; + p_container->is_task = false; + p_container->mark_indent = indent; + p_container->contents_indent = indent + off - beg + 1; + *p_end = off+1; + return true; + } + + return false; +} + +static unsigned +md_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end) +{ + OFF off = beg; + unsigned indent = total_indent; + + while(off < ctx->size && ISBLANK(off)) { + if(CH(off) == _T('\t')) + indent = (indent + 4) & ~3; + else + indent++; + off++; + } + + *p_end = off; + return indent - total_indent; +} + +static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0, 0 }; + +/* Analyze type of the line and find some its properties. This serves as a + * main input for determining type and boundaries of a block. */ +static int +md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, + const MD_LINE_ANALYSIS* pivot_line, MD_LINE_ANALYSIS* line) +{ + unsigned total_indent = 0; + int n_parents = 0; + int n_brothers = 0; + int n_children = 0; + MD_CONTAINER container = { 0 }; + int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect; + OFF off = beg; + OFF hr_killer = 0; + int ret = 0; + + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + line->enforce_new_block = false; + + /* Given the indentation and block quote marks '>', determine how many of + * the current containers are our parents. */ + while(n_parents < ctx->n_containers) { + MD_CONTAINER* c = &ctx->containers[n_parents]; + + if(c->ch == _T('>') && line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('>')) + { + /* Block quote mark. */ + off++; + total_indent++; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + /* The optional 1st space after '>' is part of the block quote mark. */ + if(line->indent > 0) + line->indent--; + + line->beg = off; + + } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { + /* List. */ + line->indent -= c->contents_indent; + } else { + break; + } + + n_parents++; + } + + if(off >= ctx->size || ISNEWLINE(off)) { + /* Blank line does not need any real indentation to be nested inside + * a list. */ + if(n_brothers + n_children == 0) { + while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) + n_parents++; + } + } + + while(true) { + /* Check whether we are fenced code continuation. */ + if(pivot_line->type == MD_LINE_FENCEDCODE) { + line->beg = off; + + /* We are another MD_LINE_FENCEDCODE unless we are closing fence + * which we transform into MD_LINE_BLANK. */ + if(line->indent < ctx->code_indent_offset) { + if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = false; + break; + } + } + + /* Change indentation accordingly to the initial code fence. */ + if(n_parents == ctx->n_containers) { + if(line->indent > pivot_line->indent) + line->indent -= pivot_line->indent; + else + line->indent = 0; + + line->type = MD_LINE_FENCEDCODE; + break; + } + } + + /* Check whether we are HTML block continuation. */ + if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { + if(n_parents < ctx->n_containers) { + /* HTML block is implicitly ended if the enclosing container + * block ends. */ + ctx->html_block_type = 0; + } else { + int html_block_type; + + html_block_type = md_is_html_block_end_condition(ctx, off, &off); + if(html_block_type > 0) { + MD_ASSERT(html_block_type == ctx->html_block_type); + + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + + /* Some end conditions serve as blank lines at the same time. */ + if(html_block_type == 6 || html_block_type == 7) { + line->type = MD_LINE_BLANK; + line->indent = 0; + break; + } + } + + line->type = MD_LINE_HTML; + n_parents = ctx->n_containers; + break; + } + } + + /* Check for blank line. */ + if(off >= ctx->size || ISNEWLINE(off)) { + if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { + line->type = MD_LINE_INDENTEDCODE; + if(line->indent > ctx->code_indent_offset) + line->indent -= ctx->code_indent_offset; + else + line->indent = 0; + ctx->last_line_has_list_loosening_effect = false; + } else { + line->type = MD_LINE_BLANK; + ctx->consecutive_blank_lines++; + ctx->last_line_has_list_loosening_effect = (n_parents > 0 && + n_brothers + n_children == 0 && + ctx->containers[n_parents-1].ch != _T('>')); + } + break; + } else { + /* CommonMark requires a list item cannot begin with two (or more) + * blank lines so we may need to forcefully end the list. + * (See https://github.com/mity/md4c/issues/6) */ + if(ctx->consecutive_blank_lines >= 2) { + if(n_parents > 0 && n_parents == ctx->n_containers && + ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) { + n_parents--; + + line->indent = total_indent; + if(n_parents > 0) + line->indent -= MIN(line->indent, ctx->containers[n_parents-1].contents_indent); + } + } + } + ctx->consecutive_blank_lines = 0; + + ctx->last_line_has_list_loosening_effect = false; + } + + /* Check whether we are Setext underline. */ + if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF2(off, _T('='), _T('-')) + && (n_parents == ctx->n_containers)) + { + unsigned level; + + if(md_is_setext_underline(ctx, off, &off, &level)) { + line->type = MD_LINE_SETEXTUNDERLINE; + line->data = level; + break; + } + } + + /* Check for thematic break line. */ + if(line->indent < ctx->code_indent_offset + && off < ctx->size && off >= hr_killer) + { + if(md_is_hr_line(ctx, off, &off, &hr_killer)) { + line->type = MD_LINE_HR; + break; + } + } + + /* Check for "brother" container. I.e. whether we are another list item + * in already started list. */ + if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { + OFF tmp; + + if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && + md_is_container_compatible(&ctx->containers[n_parents], &container)) + { + pivot_line = &md_dummy_blank_line; + + off = tmp; + + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + ctx->containers[n_parents].mark_indent = container.mark_indent; + ctx->containers[n_parents].contents_indent = container.contents_indent; + + n_brothers++; + continue; + } + } + + /* Check for indented code. + * Note indented code block cannot interrupt a paragraph. */ + if(line->indent >= ctx->code_indent_offset && (pivot_line->type != MD_LINE_TEXT)) { + line->type = MD_LINE_INDENTEDCODE; + line->indent -= ctx->code_indent_offset; + line->data = 0; + break; + } + + /* Check for start of a new container block. */ + if(line->indent < ctx->code_indent_offset && + md_is_container_mark(ctx, line->indent, off, &off, &container)) + { + if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + (off >= ctx->size || ISNEWLINE(off)) && container.ch != _T('>')) + { + /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ + } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + ISANYOF2_(container.ch, _T('.'), _T(')')) && container.start != 1) + { + /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ + } else { + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + line->beg = off; + line->data = container.ch; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + if(n_brothers + n_children == 0) + pivot_line = &md_dummy_blank_line; + + if(n_children == 0) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + n_children++; + MD_CHECK(md_push_container(ctx, &container)); + continue; + } + } + + /* Check whether we are table continuation. */ + if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { + line->type = MD_LINE_TABLE; + break; + } + + /* Check for ATX header. */ + if(line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('#')) + { + unsigned level; + + if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { + line->type = MD_LINE_ATXHEADER; + line->data = level; + break; + } + } + + /* Check whether we are starting code fence. */ + if(line->indent < ctx->code_indent_offset && + off < ctx->size && ISANYOF2(off, _T('`'), _T('~'))) + { + if(md_is_opening_code_fence(ctx, off, &off)) { + line->type = MD_LINE_FENCEDCODE; + line->data = 1; + line->enforce_new_block = true; + break; + } + } + + /* Check for start of raw HTML block. */ + if(off < ctx->size && CH(off) == _T('<') + && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) + { + ctx->html_block_type = md_is_html_block_start_condition(ctx, off); + + /* HTML block type 7 cannot interrupt paragraph. */ + if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) + ctx->html_block_type = 0; + + if(ctx->html_block_type > 0) { + /* The line itself also may immediately close the block. */ + if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + } + + line->enforce_new_block = true; + line->type = MD_LINE_HTML; + break; + } + } + + /* Check for table underline. */ + if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF3(off, _T('|'), _T('-'), _T(':')) + && n_parents == ctx->n_containers) + { + unsigned col_count; + + if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && + md_is_table_underline(ctx, off, &off, &col_count)) + { + line->data = col_count; + line->type = MD_LINE_TABLEUNDERLINE; + break; + } + } + + /* By default, we are normal text line. */ + line->type = MD_LINE_TEXT; + if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { + /* Lazy continuation. */ + n_parents = ctx->n_containers; + } + + /* Check for task mark. */ + if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && + ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) + { + OFF tmp = off; + + while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) + tmp++; + if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && + ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && + (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) + { + MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); + task_container->is_task = true; + task_container->task_mark_off = tmp + 1; + off = tmp + 3; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + line->beg = off; + } + } + + break; + } + + /* Scan for end of the line. */ + /* Optimization: Use some loop unrolling. */ + while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) + && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) + off += 4; + while(off < ctx->size && !ISNEWLINE(off)) + off++; + + /* Set end of the line. */ + line->end = off; + + /* But for ATX header, we should exclude the optional trailing mark. */ + if(line->type == MD_LINE_ATXHEADER) { + OFF tmp = line->end; + while(tmp > line->beg && ISBLANK(tmp-1)) + tmp--; + while(tmp > line->beg && CH(tmp-1) == _T('#')) + tmp--; + if(tmp == line->beg || ISBLANK(tmp-1) || (ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS)) + line->end = tmp; + } + + /* Trim trailing spaces. */ + if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE && line->type != MD_LINE_HTML) { + while(line->end > line->beg && ISBLANK(line->end-1)) + line->end--; + } + + /* Eat also the new line. */ + if(off < ctx->size && CH(off) == _T('\r')) + off++; + if(off < ctx->size && CH(off) == _T('\n')) + off++; + + *p_end = off; + + /* If we belong to a list after seeing a blank line, the list is loose. */ + if(prev_line_has_list_loosening_effect && line->type != MD_LINE_BLANK && n_parents + n_brothers > 0) { + MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1]; + if(c->ch != _T('>')) { + MD_BLOCK* block = (MD_BLOCK*) (((char*)ctx->block_bytes) + c->block_byte_off); + block->flags |= MD_BLOCK_LOOSE_LIST; + } + } + + /* Leave any containers we are not part of anymore. */ + if(n_children == 0 && n_parents + n_brothers < ctx->n_containers) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + /* Enter any container we found a mark for. */ + if(n_brothers > 0) { + MD_ASSERT(n_brothers == 1); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + ctx->containers[n_parents].task_mark_off, + (ctx->containers[n_parents].is_task ? CH(ctx->containers[n_parents].task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + container.task_mark_off, + (container.is_task ? CH(container.task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + ctx->containers[n_parents].is_task = container.is_task; + ctx->containers[n_parents].task_mark_off = container.task_mark_off; + } + + if(n_children > 0) { + /* Check for admonition tag. */ + if((ctx->parser.flags & MD_FLAG_ADMONITIONS) && n_children > 0 && + ctx->containers[ctx->n_containers-1].ch == _T('>') && line->type == MD_LINE_TEXT && + 3 < line->end - line->beg && line->end - line->beg < 16 && + CH(line->beg) == _T('[') && CH(line->beg+1) == _T('!') && CH(line->end-1) == _T(']')) + { + unsigned i; + + for(i = 0; i < SIZEOF_ARRAY(MD_ADMONITION_TAGS); i++) { + if(line->end - line->beg == md_strlen(MD_ADMONITION_TAGS[i]) + 3 && + md_ascii_case_eq(STR(line->beg+2), MD_ADMONITION_TAGS[i], line->end - line->beg - 3)) + { + ctx->containers[ctx->n_containers-1].is_admonition = true; + ctx->containers[ctx->n_containers-1].admonition_type = i; + line->type = MD_LINE_BLANK; + break; + } + } + } + + /* Enter all the child container blocks. */ + MD_CHECK(md_enter_child_containers(ctx, n_children)); + } + +abort: + return ret; +} + +static int +md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line) +{ + const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line; + int ret = 0; + + /* Blank line ends current leaf block. */ + if(line->type == MD_LINE_BLANK) { + MD_CHECK(md_end_current_block(ctx)); + /* Count only genuinely empty lines: some non-blank lines (e.g. a closing + * code fence) are internally retyped as MD_LINE_BLANK but still hold + * their text (beg < end), and must not be counted. */ + if((ctx->parser.flags & MD_FLAG_PRESERVEBLANKLINES) && line->beg >= line->end) + ctx->n_blank_lines++; + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + /* The blank lines preceding this block (if any) form a block separation + * which we report before the block itself. */ + MD_CHECK(md_flush_blank_lines(ctx)); + + if(line->enforce_new_block) + MD_CHECK(md_end_current_block(ctx)); + + /* Some line types form block on their own. */ + if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) { + MD_CHECK(md_end_current_block(ctx)); + + /* Add our single-line block. */ + MD_CHECK(md_start_new_block(ctx, line)); + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + /* MD_LINE_SETEXTUNDERLINE changes meaning of the current block and ends it. */ + if(line->type == MD_LINE_SETEXTUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + ctx->current_block->type = MD_BLOCK_H; + ctx->current_block->data = line->data; + ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + if(ctx->current_block == NULL) { + *p_pivot_line = &md_dummy_blank_line; + } else { + /* This happens if we have consumed all the body as link ref. defs. + * and downgraded the underline into start of a new paragraph block. */ + line->type = MD_LINE_TEXT; + *p_pivot_line = line; + } + return 0; + } + + /* MD_LINE_TABLEUNDERLINE changes meaning of the current block. */ + if(line->type == MD_LINE_TABLEUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + MD_ASSERT(ctx->current_block->n_lines == 1); + ctx->current_block->type = MD_BLOCK_TABLE; + ctx->current_block->data = line->data; + MD_ASSERT(pivot_line != &md_dummy_blank_line); + ((MD_LINE_ANALYSIS*)pivot_line)->type = MD_LINE_TABLE; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + return 0; + } + + /* The current block also ends if the line has different type. */ + if(line->type != pivot_line->type) + MD_CHECK(md_end_current_block(ctx)); + + /* The current line may start a new block. */ + if(ctx->current_block == NULL) { + MD_CHECK(md_start_new_block(ctx, line)); + *p_pivot_line = line; + } + + /* In all other cases the line is just a continuation of the current block. */ + MD_CHECK(md_add_line_into_current_block(ctx, line)); + +abort: + return ret; +} + +static int +md_footnote_def_cmp_index(const void* a, const void* b) +{ + const MD_FOOTNOTE_DEF* da = (const MD_FOOTNOTE_DEF*) a; + const MD_FOOTNOTE_DEF* db = (const MD_FOOTNOTE_DEF*) b; + + /* Unreferenced defs (index == 0) always sort after referenced ones. */ + if(da->index == 0 && db->index == 0) return 0; + if(da->index == 0) return +1; + if(db->index == 0) return -1; + if(da->index < db->index) return -1; + if(da->index > db->index) return +1; + return 0; +} + +static int +md_process_footnote_def(MD_CTX* ctx, MD_FOOTNOTE_DEF* def) +{ + MD_BLOCK_FOOTNOTE_DEF_DETAIL det; + MD_ATTRIBUTE_BUILD label_build = { 0 }; + int ret = 0; + + memset(&det, 0, sizeof(MD_BLOCK_FOOTNOTE_DEF_DETAIL)); + det.id = def->index; + det.ref_count = def->ref_count; + MD_CHECK(md_build_attribute(ctx, def->entry.label, def->entry.label_size, 0, + &det.label, &label_build)); + + MD_ENTER_BLOCK(MD_BLOCK_FOOTNOTE_DEF, &det); + MD_CHECK(md_process_normal_block_contents(ctx, def->content_lines, + def->n_content_lines)); + MD_LEAVE_BLOCK(MD_BLOCK_FOOTNOTE_DEF, &det); + +abort: + md_free_attribute(ctx, &label_build); + return ret; +} + +/* Render footnote definitions that were actually referenced, in reference order. + * Called from md_process_doc() after md_process_all_blocks(). */ +static int +md_process_footnote_defs(MD_CTX* ctx) +{ + unsigned i; + int ret = 0; + + if(ctx->footnote_hashtable.n_defs == 0 || ctx->next_footnote_index == 0) + return 0; + + /* Sort defs by index so we emit in reference order. */ + qsort(ctx->footnote_hashtable.defs, ctx->footnote_hashtable.n_defs, + sizeof(MD_FOOTNOTE_DEF), md_footnote_def_cmp_index); + + MD_ENTER_BLOCK(MD_BLOCK_FOOTNOTE_DEF_SECTION, NULL); + + for(i = 0; i < ctx->footnote_hashtable.n_defs; i++) { + MD_FOOTNOTE_DEF* def = &ctx->footnote_hashtable.footnote_defs[i]; + if(def->index == 0) + break; + MD_CHECK(md_process_footnote_def(ctx, def)); + } + + MD_LEAVE_BLOCK(MD_BLOCK_FOOTNOTE_DEF_SECTION, NULL); + +abort: + return ret; +} + +static int +md_process_doc(MD_CTX *ctx) +{ + const MD_LINE_ANALYSIS* pivot_line = &md_dummy_blank_line; + MD_LINE_ANALYSIS line_buf[2]; + MD_LINE_ANALYSIS* line = &line_buf[0]; + OFF off = 0; + int ret = 0; + + MD_ENTER_BLOCK(MD_BLOCK_DOC, NULL); + + while(off < ctx->size) { + if(line == pivot_line) + line = (line == &line_buf[0] ? &line_buf[1] : &line_buf[0]); + + MD_CHECK(md_analyze_line(ctx, off, &off, pivot_line, line)); + MD_CHECK(md_process_line(ctx, &pivot_line, line)); + } + + MD_CHECK(md_end_current_block(ctx)); + + MD_CHECK(md_build_ref_def_hashtable(ctx)); + if(ctx->parser.flags & MD_FLAG_FOOTNOTES) + MD_CHECK(md_build_footnote_def_hashtable(ctx)); + + /* Process all blocks. */ + MD_CHECK(md_leave_child_containers(ctx, 0)); + /* Report any blank lines trailing the document. */ + MD_CHECK(md_flush_blank_lines(ctx)); + MD_CHECK(md_process_all_blocks(ctx)); + + /* Emit footnote definitions that were referenced, in reference order. */ + if(ctx->parser.flags & MD_FLAG_FOOTNOTES) + MD_CHECK(md_process_footnote_defs(ctx)); + + MD_LEAVE_BLOCK(MD_BLOCK_DOC, NULL); + +abort: + +#if 0 + /* Output some memory consumption statistics. */ + { + char buffer[256]; + sprintf(buffer, "Alloced %u bytes for block buffer.", + (unsigned)(ctx->alloc_block_bytes)); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for containers buffer.", + (unsigned)(ctx->alloc_containers * sizeof(MD_CONTAINER))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for marks buffer.", + (unsigned)(ctx->alloc_marks * sizeof(MD_MARK))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for aux. buffer.", + (unsigned)(ctx->alloc_buffer * sizeof(MD_CHAR))); + MD_LOG(buffer); + } +#endif + + return ret; +} + + +/******************** + *** Public API *** + ********************/ + +int +md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata) +{ + MD_CTX ctx; + int i; + int ret; + + if(parser->abi_version != 0) { + if(parser->debug_log != NULL) + parser->debug_log("Unsupported abi_version.", userdata); + return -1; + } + + /* Setup context structure. */ + memset(&ctx, 0, sizeof(MD_CTX)); + ctx.text = text; + ctx.size = size; + memcpy(&ctx.parser, parser, sizeof(MD_PARSER)); + ctx.userdata = userdata; + ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4; + md_build_mark_char_map(&ctx); + ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1])); + ctx.ref_def_hashtable.def_size = sizeof(MD_REF_DEF); + ctx.max_ref_def_output = 16 * MIN(size, (MD_SIZE)(1024 * 1024 / 16)); + ctx.footnote_hashtable.def_size = sizeof(MD_FOOTNOTE_DEF); + + /* Reset all mark stacks and lists. */ + for(i = 0; i < (int) SIZEOF_ARRAY(ctx.opener_stacks); i++) + ctx.opener_stacks[i].top = -1; + ctx.ptr_stack.top = -1; + ctx.unresolved_link_head = -1; + ctx.unresolved_link_tail = -1; + ctx.table_cell_boundaries_head = -1; + ctx.table_cell_boundaries_tail = -1; + + /* All the work. */ + ret = md_process_doc(&ctx); + + /* Clean-up. */ + md_free_ref_defs(&ctx); + md_free_footnote_defs(&ctx); + free(ctx.buffer); + free(ctx.marks); + free(ctx.block_bytes); + free(ctx.containers); + + return ret; +} diff --git a/external/md4c.h b/external/md4c.h new file mode 100644 index 000000000..7a6896a3c --- /dev/null +++ b/external/md4c.h @@ -0,0 +1,495 @@ +/* + * MD4C: Markdown parser for C + * (https://github.com/mity/md4c) + * + * Copyright (c) 2016-2026 Martin Mitáš + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef MD4C_H +#define MD4C_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined MD4C_USE_UTF16 + /* Magic to support UTF-16. Note that in order to use it, you have to define + * the macro MD4C_USE_UTF16 both when building MD4C as well as when + * including this header in your code. */ + #ifdef _WIN32 + #include + typedef WCHAR MD_CHAR; + #else + #error MD4C_USE_UTF16 is only supported on Windows. + #endif +#else + typedef char MD_CHAR; +#endif + +typedef unsigned MD_SIZE; +typedef unsigned MD_OFFSET; + + +/* Block represents a part of document hierarchy structure like a paragraph + * or list item. + */ +typedef enum MD_BLOCKTYPE { + /* ... */ + MD_BLOCK_DOC = 0, + + /*
...
*/ + MD_BLOCK_QUOTE, + + /*
    ...
+ * Detail: Structure MD_BLOCK_UL_DETAIL. */ + MD_BLOCK_UL, + + /*
    ...
+ * Detail: Structure MD_BLOCK_OL_DETAIL. */ + MD_BLOCK_OL, + + /*
  • ...
  • + * Detail: Structure MD_BLOCK_LI_DETAIL. */ + MD_BLOCK_LI, + + /*
    */ + MD_BLOCK_HR, + + /*

    ...

    (for levels up to 6) + * Detail: Structure MD_BLOCK_H_DETAIL. */ + MD_BLOCK_H, + + /*
    ...
    + * Note the text lines within code blocks are terminated with '\n' + * instead of explicit MD_TEXT_BR. */ + MD_BLOCK_CODE, + + /* Raw HTML block. This itself does not correspond to any particular HTML + * tag. The contents of it _is_ raw HTML source intended to be put + * in verbatim form to the HTML output. */ + MD_BLOCK_HTML, + + /*

    ...

    */ + MD_BLOCK_P, + + /* ...
    and its contents. + * Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE), + * structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD) + * Note all of these are used only if extension MD_FLAG_TABLES is enabled. */ + MD_BLOCK_TABLE, + MD_BLOCK_THEAD, + MD_BLOCK_TBODY, + MD_BLOCK_TR, + MD_BLOCK_TH, + MD_BLOCK_TD, + + /* Container for all referenced footnote definitions, rendered at the end + * of the document. + * Detail: NULL. + * Note: Used only if extension MD_FLAG_FOOTNOTES is enabled, and only when + * at least one footnote definition is referenced. */ + MD_BLOCK_FOOTNOTE_DEF_SECTION, + + /* A single footnote definition, rendered at the end of the document. + * Detail: Structure MD_BLOCK_FOOTNOTE_DEF_DETAIL. + * Note: Used only if extension MD_FLAG_FOOTNOTES is enabled. + * Only definitions that are actually referenced in the document are + * emitted, in order of first reference. */ + MD_BLOCK_FOOTNOTE_DEF, + + /* Adminition extension. + * Detail MD_BLOCK_ADMONITION_DETAIL. + * Note: Recognized only when MD_FLAG_ADMONITIONS is enabled. */ + MD_BLOCK_ADMONITION, + + /* A run of blank lines separating two blocks. Has no contents. + * Detail: Structure MD_BLOCK_BLANK_DETAIL. + * Note: Emitted only when MD_FLAG_PRESERVEBLANKLINES is enabled. */ + MD_BLOCK_BLANK +} MD_BLOCKTYPE; + +/* Span represents an in-line piece of a document which should be rendered with + * the same font, color and other attributes. A sequence of spans forms a block + * like paragraph or list item. */ +typedef enum MD_SPANTYPE { + /* ... */ + MD_SPAN_EM, + + /* ... */ + MD_SPAN_STRONG, + + /* ... + * Detail: Structure MD_SPAN_A_DETAIL. */ + MD_SPAN_A, + + /* ... + * Detail: Structure MD_SPAN_IMG_DETAIL. + * Note: Image text can contain nested spans and even nested images. + * If rendered into ALT attribute of HTML tag, it's responsibility + * of the parser to deal with it. + */ + MD_SPAN_IMG, + + /* ... */ + MD_SPAN_CODE, + + /* ... + * Syntax: ++insert++ + * Note: Recognized only when MD_FLAG_INSERT is enabled. */ + MD_SPAN_INS, + + /* ... + * Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled. + */ + MD_SPAN_DEL, + + /* For recognizing inline ($) and display ($$) equations + * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. + */ + MD_SPAN_LATEXMATH, + MD_SPAN_LATEXMATH_DISPLAY, + + /* Wiki links + * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. + */ + MD_SPAN_WIKILINK, + + /* ... + * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ + MD_SPAN_U, + + /* Spoiler (hidden content revealed on interaction). + * Syntax: ||hidden text|| + * Note: Recognized only when MD_FLAG_SPOILERS is enabled. */ + MD_SPAN_SPOILER, + + /* ... + * Syntax: ^superscript^ + * Note: Recognized only when MD_FLAG_SUPERSCRIPTS is enabled. */ + MD_SPAN_SUPERSCRIPT, + + /* ... + * Syntax: ~subscript~ + * Note: Recognized only when MD_FLAG_SUBSCRIPTS is enabled. */ + MD_SPAN_SUBSCRIPT, + + /* Footnote reference, e.g. [^1] or [^note]. + * Syntax: [^label] + * Note: Recognized only when MD_FLAG_FOOTNOTES is enabled. + * The span is self-contained: no MD_TEXT callbacks fire between enter and + * leave. All needed information is in MD_SPAN_FOOTNOTE_REF_DETAIL. */ + MD_SPAN_FOOTNOTE_REF, + + /* ... + * Syntax: ==highlight== + * Note: Recognized only when MD_FLAG_HIGHLIGHT is enabled. */ + MD_SPAN_MARK +} MD_SPANTYPE; + +/* Text is the actual textual contents of span. */ +typedef enum MD_TEXTTYPE { + /* Normal text. */ + MD_TEXT_NORMAL = 0, + + /* NULL character. CommonMark requires replacing NULL character with + * the replacement char U+FFFD, so this allows caller to do that easily. */ + MD_TEXT_NULLCHAR, + + /* Line breaks. + * Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE + * or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */ + MD_TEXT_BR, /*
    (hard break) */ + MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */ + + /* Entity. + * (a) Named entity, e.g.   + * (Note MD4C does not have a list of known entities. + * Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is + * treated as a named entity.) + * (b) Numerical entity, e.g. Ӓ + * (c) Hexadecimal entity, e.g. ካ + * + * As MD4C is mostly encoding agnostic, application gets the verbatim + * entity text into the MD_PARSER::text_callback(). */ + MD_TEXT_ENTITY, + + /* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`). + * If it is inside MD_BLOCK_CODE, it includes spaces for indentation and + * '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this + * kind of text. */ + MD_TEXT_CODE, + + /* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not + * an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used. + * The text contains verbatim '\n' for the new lines. */ + MD_TEXT_HTML, + + /* Text is inside an equation. This is processed the same way as inlined code + * spans (`code`). */ + MD_TEXT_LATEXMATH +} MD_TEXTTYPE; + + +/* Alignment enumeration. */ +typedef enum MD_ALIGN { + MD_ALIGN_DEFAULT = 0, /* When unspecified. */ + MD_ALIGN_LEFT, + MD_ALIGN_CENTER, + MD_ALIGN_RIGHT +} MD_ALIGN; + + +/* String attribute. + * + * This wraps strings which are outside of a normal text flow and which are + * propagated within various detailed structures, but which still may contain + * string portions of different types like e.g. entities. + * + * So, for example, lets consider this image: + * + * ![image alt text](http://example.org/image.png 'foo " bar') + * + * The image alt text is propagated as a normal text via the MD_PARSER::text() + * callback. However, the image title ('foo " bar') is propagated as + * MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title. + * + * Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following: + * -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0) + * -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4) + * -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10) + * -- [3]: (n/a) (n/a ; substr_offsets[3] == 14) + * + * Note that these invariants are always guaranteed: + * -- substr_offsets[0] == 0 + * -- substr_offsets[LAST+1] == size + * -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR + * substrings can appear. This could change only of the specification + * changes. + */ +typedef struct MD_ATTRIBUTE { + const MD_CHAR* text; + MD_SIZE size; + const MD_TEXTTYPE* substr_types; + const MD_OFFSET* substr_offsets; +} MD_ATTRIBUTE; + + +/* Detailed info for MD_BLOCK_UL. */ +typedef struct MD_BLOCK_UL_DETAIL { + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */ +} MD_BLOCK_UL_DETAIL; + +/* Detailed info for MD_BLOCK_OL. */ +typedef struct MD_BLOCK_OL_DETAIL { + unsigned start; /* Start index of the ordered list. */ + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */ +} MD_BLOCK_OL_DETAIL; + +/* Detailed info for MD_BLOCK_LI. */ +typedef struct MD_BLOCK_LI_DETAIL { + int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */ + MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */ + MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */ +} MD_BLOCK_LI_DETAIL; + +/* Detailed info for MD_BLOCK_H. */ +typedef struct MD_BLOCK_H_DETAIL { + unsigned level; /* Header level (1 - 6) */ +} MD_BLOCK_H_DETAIL; + +/* Detailed info for MD_BLOCK_CODE. */ +typedef struct MD_BLOCK_CODE_DETAIL { + MD_ATTRIBUTE info; + MD_ATTRIBUTE lang; + MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */ +} MD_BLOCK_CODE_DETAIL; + +/* Detailed info for MD_BLOCK_TABLE. */ +typedef struct MD_BLOCK_TABLE_DETAIL { + unsigned col_count; /* Count of columns in the table. */ + unsigned head_row_count; /* Count of rows in the table header (currently always 1) */ + unsigned body_row_count; /* Count of rows in the table body */ +} MD_BLOCK_TABLE_DETAIL; + +/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */ +typedef struct MD_BLOCK_TD_DETAIL { + MD_ALIGN align; +} MD_BLOCK_TD_DETAIL; + +/* Detailed info for MD_BLOCK_ADMONITION. */ +typedef struct MD_BLOCK_ADMONITION_DETAIL { + MD_ATTRIBUTE type; /* One of "note", "tip", "important", "warning", "caution" */ +} MD_BLOCK_ADMONITION_DETAIL; + +/* Detailed info for MD_SPAN_A. */ +typedef struct MD_SPAN_A_DETAIL { + MD_ATTRIBUTE href; + MD_ATTRIBUTE title; + int is_autolink; /* nonzero if this is an autolink */ +} MD_SPAN_A_DETAIL; + +/* Detailed info for MD_SPAN_IMG. */ +typedef struct MD_SPAN_IMG_DETAIL { + MD_ATTRIBUTE src; + MD_ATTRIBUTE title; +} MD_SPAN_IMG_DETAIL; + +/* Detailed info for MD_SPAN_WIKILINK. */ +typedef struct MD_SPAN_WIKILINK { + MD_ATTRIBUTE target; +} MD_SPAN_WIKILINK_DETAIL; + +/* Detailed info for MD_SPAN_FOOTNOTE_REF. */ +typedef struct MD_SPAN_FOOTNOTE_REF_DETAIL { + unsigned int id; /* 1-based identifier of the referenced footnote */ + unsigned int ref_id; /* 1-based identifier of this reference among references to the same footnote */ + MD_ATTRIBUTE label; /* Raw label text, e.g. "1" or "note" */ +} MD_SPAN_FOOTNOTE_REF_DETAIL; + +/* Detailed info for MD_BLOCK_FOOTNOTE_DEF. */ +typedef struct MD_BLOCK_FOOTNOTE_DEF_DETAIL { + unsigned int id; /* 1-based identifier of this footnote */ + unsigned int ref_count; /* Number of references to this footnote */ + MD_ATTRIBUTE label; /* Raw label text */ +} MD_BLOCK_FOOTNOTE_DEF_DETAIL; + +/* Detailed info for MD_BLOCK_BLANK. */ +typedef struct MD_BLOCK_BLANK_DETAIL { + unsigned line_count; /* Count of blank lines forming the block separation */ +} MD_BLOCK_BLANK_DETAIL; + +/* Flags specifying extensions/deviations from CommonMark specification. + * + * By default (when MD_PARSER::flags == 0), we follow CommonMark specification. + * The following flags may allow some extensions or deviations from it. + */ +#define MD_FLAG_COLLAPSEWHITESPACE 0x1 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */ +#define MD_FLAG_PERMISSIVEATXHEADERS 0x2 /* Do not require space in ATX headers ( ###header ) */ +#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x4 /* Recognize URLs as autolinks even without '<', '>' */ +#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x8 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */ +#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x10 /* Disable indented code blocks. (Only fenced code works.) */ +#define MD_FLAG_NOHTMLBLOCKS 0x20 /* Disable raw HTML blocks. */ +#define MD_FLAG_NOHTMLSPANS 0x40 /* Disable raw HTML (inline). */ +#define MD_FLAG_TABLES 0x100 /* Enable tables extension. */ +#define MD_FLAG_STRIKETHROUGH 0x200 /* Enable strikethrough extension. */ +#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ +#define MD_FLAG_TASKLISTS 0x800 /* Enable task list extension. */ +#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ +#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ +#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ +#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */ +#define MD_FLAG_SPOILERS 0x10000 /* Enable ||hidden text|| spoiler spans. */ +#define MD_FLAG_SUPERSCRIPTS 0x20000 /* Enable ^superscript^ spans. */ +#define MD_FLAG_SUBSCRIPTS 0x40000 /* Enable ~subscript~ spans. */ +#define MD_FLAG_ADMONITIONS 0x80000 /* Enable admonitions extension. */ +#define MD_FLAG_FOOTNOTES 0x100000 /* Enable [^label] footnote references. */ +#define MD_FLAG_HIGHLIGHT 0x200000 /* Enable ==highlight== spans. */ +#define MD_FLAG_PRESERVEBLANKLINES 0x400000 /* Report blank line runs as MD_BLOCK_BLANK. */ +#define MD_FLAG_INSERT 0x800000 /* Enable insert extension. */ + +#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) +#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) + +/* Convenient sets of flags corresponding to well-known Markdown dialects. + * + * Note we may only support subset of features of the referred dialect. + * The constant just enables those extensions which bring us as close as + * possible given what features we implement. + * + * ABI compatibility note: Meaning of these can change in time as new + * extensions, bringing the dialect closer to the original, are implemented. + */ +#define MD_DIALECT_COMMONMARK 0 +#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS | MD_FLAG_ADMONITIONS | MD_FLAG_FOOTNOTES) + +/* Parser structure. + */ +typedef struct MD_PARSER { + /* Reserved. Set to zero. + */ + unsigned abi_version; + + /* Dialect options. Bitmask of MD_FLAG_xxxx values. + */ + unsigned flags; + + /* Caller-provided rendering callbacks. + * + * For some block/span types, more detailed information is provided in a + * type-specific structure pointed by the argument 'detail'. + * + * The last argument of all callbacks, 'userdata', is just propagated from + * md_parse() and is available for any use by the application. + * + * Note any strings provided to the callbacks as their arguments or as + * members of any detail structure are generally not zero-terminated. + * Application has to take the respective size information into account. + * + * Any rendering callback may abort further parsing of the document by + * returning non-zero. + */ + int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/); + + /* Debug callback. Optional (may be NULL). + * + * If provided and something goes wrong, this function gets called. + * This is intended for debugging and problem diagnosis for developers; + * it is not intended to provide any errors suitable for displaying to an + * end user. + */ + void (*debug_log)(const char* /*msg*/, void* /*userdata*/); + + /* Reserved. Set to NULL. + */ + void (*syntax)(void); +} MD_PARSER; + + +/* For backward compatibility. Do not use in new code. + */ +typedef MD_PARSER MD_RENDERER; + + +/* Parse the Markdown document stored in the string 'text' of size 'size'. + * The parser provides callbacks to be called during the parsing so the + * caller can render the document on the screen or convert the Markdown + * to another format. + * + * Zero is returned on success. If a runtime error occurs (e.g. a memory + * fails), -1 is returned. If the processing is aborted due any callback + * returning non-zero, the return value of the callback is returned. + */ +int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata); + + +#ifdef __cplusplus + } /* extern "C" { */ +#endif + +#endif /* MD4C_H */ diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index abdc073d3..6d35d5445 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index d820ea470..71b8f5fbe 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -58,6 +58,7 @@ #define MwNminute "Iminute" #define MwNsecond "Isecond" #define MwNtype "Itype" +#define MwNautoResize "IautoResize" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/include/Mw/Widget/Document.h b/include/Mw/Widget/Document.h new file mode 100644 index 000000000..5b38af418 --- /dev/null +++ b/include/Mw/Widget/Document.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Document.h + * @brief Document widget + */ +#ifndef __MW_WIDGET_DOCUMENT_H__ +#define __MW_WIDGET_DOCUMENT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Clock widget class + */ +MWDECL MwClass MwDocumentClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/milsko.xml b/milsko.xml index 084f82594..ec30e8237 100644 --- a/milsko.xml +++ b/milsko.xml @@ -111,6 +111,7 @@ + diff --git a/pl/rules.pl b/pl/rules.pl index 9d2081c87..ad62d6c24 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -155,6 +155,7 @@ new_object("src/widget/checkbox.c"); new_object("src/widget/chart.c"); new_object("src/widget/clock.c"); new_object("src/widget/combobox.c"); +new_object("src/widget/document.c"); new_object("src/widget/entry.c"); new_object("src/widget/frame.c"); new_object("src/widget/image.c"); @@ -212,6 +213,7 @@ new_example("examples/basic/filechooser"); new_example("examples/basic/periodic"); new_example("examples/basic/subwindow"); new_example("examples/basic/tab"); +new_example("examples/basic/document"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); diff --git a/src/widget/document.c b/src/widget/document.c new file mode 100644 index 000000000..4c5414a6e --- /dev/null +++ b/src/widget/document.c @@ -0,0 +1,54 @@ +#include + +#include "../../external/md4c.h" + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + return 0; +} + +static void draw(MwWidget handle) { + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwRect r; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNautoResize) == 0 || strcmp(key, MwNtext) == 0) MwForceRender(handle); + + if(strcmp(key, MwNtext) == 0) { + MD_PARSER parser; + memset(&parser, 0, sizeof(parser)); + } +} + +MwClassRec MwDocumentClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwDocumentClass = &MwDocumentClassRec; diff --git a/tools/genmk.pl b/tools/genmk.pl index 689e09ef7..26a7ebbbd 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -230,6 +230,6 @@ scan_examples("examples/gldemos"); @examples = sort(@examples); -generate("BorMakefile", "Borland"); +#generate("BorMakefile", "Borland"); generate("NTMakefile", "MSVC"); generate("WatMakefile", "Watcom"); From c1ab3af1c1e94c4ec7c914419fed2052b609752c Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:19:37 +0900 Subject: [PATCH 60/90] ok --- external/md4c.c | 3 +-- src/backend/gdi.c | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/external/md4c.c b/external/md4c.c index 22ab420d1..73c7b5d55 100644 --- a/external/md4c.c +++ b/external/md4c.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include @@ -5840,7 +5839,7 @@ md_consume_link_reference_definitions(MD_CTX* ctx) MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); MD_SIZE n_lines = ctx->current_block->n_lines; MD_SIZE n = 0; - bool inject_hr = false; + int inject_hr = 0; OFF ignored; while(n < n_lines) { diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 660a0fc32..2013b9a11 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -178,13 +178,14 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { for(i = 0; i < count; i++) { wchar_t wpath[MAX_PATH]; - char path[MAX_PATH]; + char* path; wsymtbl.DragQueryFileW(hDrop, i, wpath, MAX_PATH); - memset(path, 0, sizeof(path)); - WideCharToMultiByte(CP_UTF8, 0, wpath, -1, path, sizeof(path) - 1, NULL, NULL); + path = MwUTF16TextToUTF8Text(wpath); MwLLDispatch(u->ll, drag_and_drop, path); + + free(path); } wsymtbl.DragFinish(hDrop); break; From cbcf3c5ef185d38fca51bf6a6aba6261db9667ce Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:21:38 +0900 Subject: [PATCH 61/90] ok --- NTMakefile | 12 ++++++++++-- WatMakefile | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index d0fc4638a..26723bc12 100644 --- a/NTMakefile +++ b/NTMakefile @@ -6,9 +6,9 @@ MW_LDFLAGS = /DLL EXE_CFLAGS = /Iinclude EXE_LDFLAGS = .SUFFIXES: .obj .c -all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe lib: src\Mw.dll -examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe clean: del /f /q external\libz\src\adler32.obj del /f /q external\libz\src\compress.obj @@ -112,6 +112,7 @@ clean: del /f /q examples\basic\clipboard.obj del /f /q examples\basic\colorpicker.obj del /f /q examples\basic\combobox.obj + del /f /q examples\basic\document.obj del /f /q examples\basic\example.obj del /f /q examples\basic\filechooser.obj del /f /q examples\basic\image.obj @@ -139,6 +140,7 @@ clean: del /f /q examples\basic\clipboard.exe del /f /q examples\basic\colorpicker.exe del /f /q examples\basic\combobox.exe + del /f /q examples\basic\document.exe del /f /q examples\basic\example.exe del /f /q examples\basic\filechooser.exe del /f /q examples\basic\image.exe @@ -197,6 +199,12 @@ examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll examples\basic\combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c +examples\basic\document.exe: examples\basic\document.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\document.obj src\Mw.lib + +examples\basic\document.obj: examples/basic/document.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/document.c + examples\basic\example.exe: examples\basic\example.obj src\Mw.dll $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\example.obj src\Mw.lib diff --git a/WatMakefile b/WatMakefile index ce6792bfa..7924e17b6 100644 --- a/WatMakefile +++ b/WatMakefile @@ -5,9 +5,9 @@ MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -d MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include EXE_LDFLAGS = system nt -all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe lib: src/Mw.dll -examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe clean: .SYMBOLIC %erase external/libz/src/adler32.obj %erase external/libz/src/compress.obj @@ -111,6 +111,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.obj %erase examples/basic/colorpicker.obj %erase examples/basic/combobox.obj + %erase examples/basic/document.obj %erase examples/basic/example.obj %erase examples/basic/filechooser.obj %erase examples/basic/image.obj @@ -138,6 +139,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.exe %erase examples/basic/colorpicker.exe %erase examples/basic/combobox.exe + %erase examples/basic/document.exe %erase examples/basic/example.exe %erase examples/basic/filechooser.exe %erase examples/basic/image.exe @@ -196,6 +198,12 @@ examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll examples/basic/combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c +examples/basic/document.exe: examples/basic/document.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/document.obj library clib3r.lib library src/Mw.lib + +examples/basic/document.obj: examples/basic/document.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/document.c + examples/basic/example.exe: examples/basic/example.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/example.obj library clib3r.lib library src/Mw.lib From 1d39b6584db19de6ef0d29ee99a4be1213d05f0f Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:22:23 +0900 Subject: [PATCH 62/90] ok --- external/md4c.c | 444 ++++++++++++++++++++++++------------------------ 1 file changed, 222 insertions(+), 222 deletions(-) diff --git a/external/md4c.c b/external/md4c.c index 73c7b5d55..8665a1481 100644 --- a/external/md4c.c +++ b/external/md4c.c @@ -176,7 +176,7 @@ struct MD_CTX_tag { MD_PARSER parser; void* userdata; - /* When this is true, it allows some optimizations. */ + /* When this is 1, it allows some optimizations. */ int doc_ends_with_newline; /* Helper temporary growing buffer. */ @@ -384,9 +384,9 @@ md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) if(ISLOWER_(ch2)) ch2 += ('A'-'a'); if(ch1 != ch2) - return false; + return 0; } - return true; + return 1; } static inline int @@ -1107,7 +1107,7 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF MD_ASSERT(CH(beg) == _T('<')); if(off + 1 >= line_end) - return false; + return 0; off++; /* For parsing attributes, we need a little state automaton below. @@ -1130,7 +1130,7 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF /* Tag name */ if(off >= line_end || !ISALPHA(off)) - return false; + return 0; off++; while(off < line_end && (ISALNUM(off) || CH(off) == _T('-'))) off++; @@ -1179,22 +1179,22 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF else if(!ISANYOF(off, _T("\"'=<>`")) && !ISNEWLINE(off)) attr_state = 41; else - return false; + return 0; off++; } else { /* Anything unexpected. */ - return false; + return 0; } } /* We have to be on a single line. See definition of start condition * of HTML block, type 7. */ if(n_lines == 0) - return false; + return 0; line_index++; if(line_index >= n_lines) - return false; + return 0; off = lines[line_index].beg; line_end = lines[line_index].end; @@ -1203,15 +1203,15 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF attr_state = 1; if(off >= max_end) - return false; + return 0; } done: if(off >= max_end) - return false; + return 0; *p_end = off+1; - return true; + return 1; } static int @@ -1226,15 +1226,15 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) { /* We have already scanned the range up to the max_end so we know * there is nothing to see. */ - return false; + return 0; } - while(true) { + while(1) { while(off + len <= lines[line_index].end && off + len <= max_end) { if(md_ascii_eq(STR(off), str, len)) { /* Success. */ *p_end = off + len; - return true; + return 1; } off++; } @@ -1243,7 +1243,7 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, if(off >= max_end || line_index >= n_lines) { /* Failure. */ *p_scan_horizon = off; - return false; + return 0; } off = lines[line_index].beg; @@ -1258,9 +1258,9 @@ md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, MD_ASSERT(CH(beg) == _T('<')); if(off + 4 >= lines[0].end) - return false; + return 0; if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) - return false; + return 0; /* Skip only "" or "" */ off += 2; @@ -1276,9 +1276,9 @@ md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_l OFF off = beg; if(off + 2 >= lines[0].end) - return false; + return 0; if(CH(off+1) != _T('?')) - return false; + return 0; off += 2; return md_scan_for_html_closer(ctx, _T("?>"), 2, @@ -1291,14 +1291,14 @@ md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF b OFF off = beg; if(off + 2 >= lines[0].end) - return false; + return 0; if(CH(off+1) != _T('!')) - return false; + return 0; off += 2; /* Declaration name. */ if(off >= lines[0].end || !ISALPHA(off)) - return false; + return 0; off++; while(off < lines[0].end && ISALPHA(off)) off++; @@ -1316,9 +1316,9 @@ md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OF OFF off = beg; if(off + open_size >= lines[0].end) - return false; + return 0; if(memcmp(STR(off), open_str, open_size * sizeof(CHAR)) != 0) - return false; + return 0; off += open_size; return md_scan_for_html_closer(ctx, _T("]]>"), 3, @@ -1352,9 +1352,9 @@ md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, O if(1 <= off - beg && off - beg <= 6) { *p_end = off; - return true; + return 1; } else { - return false; + return 0; } } @@ -1369,9 +1369,9 @@ md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, O if(1 <= off - beg && off - beg <= 7) { *p_end = off; - return true; + return 1; } else { - return false; + return 0; } } @@ -1384,16 +1384,16 @@ md_is_named_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, if(off < max_end && ISALPHA_(text[off])) off++; else - return false; + return 0; while(off < max_end && ISALNUM_(text[off]) && off - beg <= 48) off++; if(2 <= off - beg && off - beg <= 48) { *p_end = off; - return true; + return 1; } else { - return false; + return 0; } } @@ -1415,9 +1415,9 @@ md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end if(is_contents && off < max_end && text[off] == _T(';')) { *p_end = off+1; - return true; + return 1; } else { - return false; + return 0; } } @@ -1517,10 +1517,10 @@ md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size, /* If there is no backslash and no ampersand, build trivial attribute * without any malloc(). */ - is_trivial = true; + is_trivial = 1; for(raw_off = 0; raw_off < raw_size; raw_off++) { if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) { - is_trivial = false; + is_trivial = 0; break; } } @@ -1623,7 +1623,7 @@ md_label_hash(const CHAR* label, SZ size) unsigned hash = MD_FNV1A_BASE; OFF off; unsigned codepoint; - int is_whitespace = false; + int is_whitespace = 0; off = md_skip_unicode_whitespace(label, 0, size); while(off < size) { @@ -1761,7 +1761,7 @@ static int md_is_complex_label_bucket(MD_LABEL_HASH_TABLE* table, void* bucket) { if(bucket == NULL) - return false; + return 0; return (MD_LABEL_HASH_ENTRY*) bucket < (MD_LABEL_HASH_ENTRY*) table->defs || (MD_LABEL_HASH_ENTRY*) bucket >= (MD_LABEL_HASH_ENTRY*)((char*)table->defs + table->n_defs * table->def_size); @@ -2031,9 +2031,9 @@ md_is_footnote_label(MD_CTX* ctx, OFF beg, OFF* p_end) if(end - beg > 0 && end < ctx->size && CH(end) == _T(']')) { if(p_end != NULL) *p_end = end; - return true; + return 1; } else { - return false; + return 0; } } @@ -2061,17 +2061,17 @@ md_is_footnote_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) label_beg = off; if(!md_is_footnote_label(ctx, label_beg, &off)) - return false; + return 0; label_end = off; /* Closing bracket. */ if(off >= lines[0].end || CH(off) != _T(']')) - return false; + return 0; off++; /* Colon. */ if(off >= lines[0].end || CH(off) != _T(':')) - return false; + return 0; off++; /* Skip optional whitespace after colon on the first line. */ @@ -2199,7 +2199,7 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, *p_beg_line_index = 0; if(CH(off) != _T('[')) - return false; + return 0; off++; while(1) { @@ -2214,7 +2214,7 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, contents_end = off + 2; off += 2; } else if(CH(off) == _T('[')) { - return false; + return 0; } else if(CH(off) == _T(']')) { if(contents_beg < contents_end) { /* Success. */ @@ -2222,10 +2222,10 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, *p_contents_end = contents_end; *p_end = off+1; *p_end_line_index = line_index; - return true; + return 1; } else { /* Link label must have some non-whitespace contents. */ - return false; + return 0; } } else { unsigned codepoint; @@ -2245,7 +2245,7 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, len++; if(len > 999) - return false; + return 0; } line_index++; @@ -2256,7 +2256,7 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, break; } - return false; + return 0; } static int @@ -2266,7 +2266,7 @@ md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, OFF off = beg; if(off >= max_end || CH(off) != _T('<')) - return false; + return 0; off++; while(off < max_end) { @@ -2276,20 +2276,20 @@ md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, } if(ISNEWLINE(off) || CH(off) == _T('<')) - return false; + return 0; if(CH(off) == _T('>')) { /* Success. */ *p_contents_beg = beg+1; *p_contents_end = off; *p_end = off+1; - return true; + return 1; } off++; } - return false; + return 0; } static int @@ -2314,7 +2314,7 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, if(CH(off) == _T('(')) { parenthesis_level++; if(parenthesis_level > 32) - return false; + return 0; } else if(CH(off) == _T(')')) { if(parenthesis_level == 0) break; @@ -2325,13 +2325,13 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, } if(parenthesis_level != 0 || off == beg) - return false; + return 0; /* Success. */ *p_contents_beg = beg; *p_contents_end = off; *p_end = off; - return true; + return 1; } static inline int @@ -2359,11 +2359,11 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, if(off >= lines[line_index].end) { line_index++; if(line_index >= n_lines) - return false; + return 0; off = lines[line_index].beg; } if(off == beg) - return false; + return 0; *p_beg_line_index = line_index; @@ -2372,7 +2372,7 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, case _T('"'): closer_char = _T('"'); break; case _T('\''): closer_char = _T('\''); break; case _T('('): closer_char = _T(')'); break; - default: return false; + default: return 0; } off++; @@ -2389,10 +2389,10 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, *p_contents_end = off; *p_end = off+1; *p_end_line_index = line_index; - return true; + return 1; } else if(closer_char == _T(')') && CH(off) == _T('(')) { /* ()-style title cannot contain (unescaped '(')) */ - return false; + return 0; } off++; @@ -2401,7 +2401,7 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, line_index++; } - return false; + return 0; } /* Returns 0 if it is not a reference definition. @@ -2418,13 +2418,13 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin OFF label_contents_beg; OFF label_contents_end; MD_SIZE label_contents_line_index; - int label_is_multiline = false; + int label_is_multiline = 0; OFF dest_contents_beg; OFF dest_contents_end; OFF title_contents_beg; OFF title_contents_end; MD_SIZE title_contents_line_index; - int title_is_multiline = false; + int title_is_multiline = 0; OFF off; MD_SIZE line_index = 0; MD_SIZE tmp_line_index; @@ -2435,12 +2435,12 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg, &off, &label_contents_line_index, &line_index, &label_contents_beg, &label_contents_end)) - return false; + return 0; label_is_multiline = (label_contents_line_index != line_index); /* Colon. */ if(off >= lines[line_index].end || CH(off) != _T(':')) - return false; + return 0; off++; /* Optional white space with up to one line break. */ @@ -2449,14 +2449,14 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin if(off >= lines[line_index].end) { line_index++; if(line_index >= n_lines) - return false; + return 0; off = lines[line_index].beg; } /* Link destination. */ if(!md_is_link_destination(ctx, off, lines[line_index].end, &off, &dest_contents_beg, &dest_contents_end)) - return false; + return 0; /* (Optional) title. Note we interpret it as an title only if nothing * more follows on its last line. */ @@ -2470,7 +2470,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin line_index += tmp_line_index; } else { /* Not a title. */ - title_is_multiline = false; + title_is_multiline = 0; title_contents_beg = off; title_contents_end = off; title_contents_line_index = 0; @@ -2478,7 +2478,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin /* Nothing more can follow on the last line. */ if(off < lines[line_index].end) - return false; + return 0; if(label_is_multiline) { CHAR* label; @@ -2493,7 +2493,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin free(label); goto abort; } - def->label_needs_free = true; + def->label_needs_free = 1; } else { def = (MD_REF_DEF*) md_add_label_def(ctx, &ctx->ref_def_hashtable, STR(label_contents_beg), label_contents_end - label_contents_beg); @@ -2507,7 +2507,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, lines + title_contents_line_index, n_lines - title_contents_line_index, _T('\n'), &def->title, &def->title_size)); - def->title_needs_free = true; + def->title_needs_free = 1; } else { def->title = (CHAR*) STR(title_contents_beg); def->title_size = title_contents_end - title_contents_beg; @@ -2535,13 +2535,13 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int is_multiline; CHAR* label; SZ label_size; - int ret = false; + int ret = 0; MD_ASSERT(CH(beg) == _T('[') || CH(beg) == _T('!')); MD_ASSERT(CH(end-1) == _T(']')); if(ctx->max_ref_def_output == 0) - return false; + return 0; beg += (CH(beg) == _T('!') ? 2 : 1); end--; @@ -2564,7 +2564,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, attr->dest_end = def->dest_end; attr->title = def->title; attr->title_size = def->title_size; - attr->title_needs_free = false; + attr->title_needs_free = 0; } if(is_multiline) @@ -2575,7 +2575,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE output_size_estimation = def->entry.label_size + def->title_size + def->dest_end - def->dest_beg; if(output_size_estimation < ctx->max_ref_def_output) { ctx->max_ref_def_output -= output_size_estimation; - ret = true; + ret = 1; } else { MD_LOG("Too many link reference definition instantiations."); ctx->max_ref_def_output = 0; @@ -2597,7 +2597,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE title_contents_line_index; int title_is_multiline; OFF off = beg; - int ret = false; + int ret = 0; md_lookup_line(off, lines, n_lines, &line_index); @@ -2610,7 +2610,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, if(off >= lines[line_index].end && (off >= ctx->size || ISNEWLINE(off))) { line_index++; if(line_index >= n_lines) - return false; + return 0; off = lines[line_index].beg; } @@ -2620,16 +2620,16 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, attr->dest_end = off; attr->title = NULL; attr->title_size = 0; - attr->title_needs_free = false; + attr->title_needs_free = 0; off++; *p_end = off; - return true; + return 1; } /* Link destination. */ if(!md_is_link_destination(ctx, off, lines[line_index].end, &off, &attr->dest_beg, &attr->dest_end)) - return false; + return 0; /* (Optional) title. */ if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, @@ -2641,7 +2641,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, line_index += tmp_line_index; } else { /* Not a title. */ - title_is_multiline = false; + title_is_multiline = 0; title_contents_beg = off; title_contents_end = off; title_contents_line_index = 0; @@ -2653,7 +2653,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, if(off >= lines[line_index].end) { line_index++; if(line_index >= n_lines) - return false; + return 0; off = lines[line_index].beg; } if(CH(off) != _T(')')) @@ -2663,20 +2663,20 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, if(title_contents_beg >= title_contents_end) { attr->title = NULL; attr->title_size = 0; - attr->title_needs_free = false; + attr->title_needs_free = 0; } else if(!title_is_multiline) { attr->title = (CHAR*) STR(title_contents_beg); attr->title_size = title_contents_end - title_contents_beg; - attr->title_needs_free = false; + attr->title_needs_free = 0; } else { MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, lines + title_contents_line_index, n_lines - title_contents_line_index, _T('\n'), &attr->title, &attr->title_size)); - attr->title_needs_free = true; + attr->title_needs_free = 1; } *p_end = off; - ret = true; + ret = 1; abort: return ret; @@ -3036,11 +3036,11 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF closer_end; SZ mark_len; OFF line_end; - int has_space_after_opener = false; - int has_eol_after_opener = false; - int has_space_before_closer = false; - int has_eol_before_closer = false; - int has_only_space = true; + int has_space_after_opener = 0; + int has_eol_after_opener = 0; + int has_space_before_closer = 0; + int has_eol_before_closer = 0; + int has_only_space = 1; MD_SIZE line_index = 0; line_end = lines[0].end; @@ -3055,22 +3055,22 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, mark_len = opener_end - opener_beg; if(mark_len > CODESPAN_MARK_MAXLEN) - return false; + return 0; /* Check whether we already know there is no closer of this length. * If so, re-scan does no sense. This fixes issue #59. */ if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end || (*p_reached_paragraph_end && last_potential_closers[mark_len-1] < opener_end)) - return false; + return 0; closer_beg = opener_end; closer_end = opener_end; /* Find closer mark. */ - while(true) { + while(1) { while(closer_beg < line_end && CH(closer_beg) != _T('`')) { if(CH(closer_beg) != _T(' ')) - has_only_space = false; + has_only_space = 0; closer_beg++; } closer_end = closer_beg; @@ -3086,7 +3086,7 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, if(closer_end - closer_beg > 0) { /* We have found a back-tick which is not part of the closer. */ - has_only_space = false; + has_only_space = 0; /* But if we eventually fail, remember it as a potential closer * of its own length for future attempts. This mitigates needs for @@ -3101,8 +3101,8 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, line_index++; if(line_index >= n_lines) { /* Reached end of the paragraph and still nothing. */ - *p_reached_paragraph_end = true; - return false; + *p_reached_paragraph_end = 1; + return 0; } /* Try on the next line. */ line_end = lines[line_index].end; @@ -3143,7 +3143,7 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, closer->beg = closer_beg; closer->end = closer_end; closer->flags = MD_MARK_POTENTIAL_CLOSER; - return true; + return 1; } static int @@ -3155,33 +3155,33 @@ md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) /* Check for scheme. */ if(off >= max_end || !ISALNUM(off)) - return false; + return 0; off++; while(1) { if(off >= max_end) - return false; + return 0; if(off - beg > 32) - return false; + return 0; if(CH(off) == _T(':') && off - beg >= 3) break; if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) - return false; + return 0; off++; } /* Check the path after the scheme. */ while(off < max_end && CH(off) != _T('>')) { if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<')) - return false; + return 0; off++; } if(off >= max_end) - return false; + return 0; MD_ASSERT(CH(off) == _T('>')); *p_end = off+1; - return true; + return 1; } static int @@ -3202,11 +3202,11 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) while(off < max_end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) off++; if(off <= beg+1) - return false; + return 0; /* '@' */ if(off >= max_end || CH(off) != _T('@')) - return false; + return 0; off++; /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum @@ -3223,32 +3223,32 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) break; if(label_len > 63) - return false; + return 0; off++; } if(label_len <= 0 || off >= max_end || CH(off) != _T('>') || CH(off-1) == _T('-')) - return false; + return 0; *p_end = off+1; - return true; + return 1; } static int md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto) { if(md_is_autolink_uri(ctx, beg, max_end, p_end)) { - *p_missing_mailto = false; - return true; + *p_missing_mailto = 0; + return 1; } if(md_is_autolink_email(ctx, beg, max_end, p_end)) { - *p_missing_mailto = true; - return true; + *p_missing_mailto = 1; + return 1; } - return false; + return 0; } static int @@ -3258,13 +3258,13 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_m int ret = 0; MD_MARK* mark; OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 }; - int codespan_scanned_till_paragraph_end = false; + int codespan_scanned_till_paragraph_end = 0; for(line_index = 0; line_index < n_lines; line_index++) { const MD_LINE* line = &lines[line_index]; OFF off = line->beg; - while(true) { + while(1) { CHAR ch; #ifdef MD4C_USE_UTF16 @@ -3776,7 +3776,7 @@ static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE /* Try to resolve a bracket pair as a wiki link '[[destination]]' or * '[[destination|label]]'. - * Returns true if resolved, false if not a wiki link, -1 on error. */ + * Returns 1 if resolved, 0 if not a wiki link, -1 on error. */ static int md_resolve_bracket_wikilink(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int opener_index, int closer_index, @@ -3791,16 +3791,16 @@ md_resolve_bracket_wikilink(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF off; if(!(ctx->parser.flags & MD_FLAG_WIKILINKS)) - return false; + return 0; if(opener->ch != _T('[') || opener->end - opener->beg != 1 || next_opener == NULL || next_opener->ch != _T('[') || next_opener->end - next_opener->beg != 1 || next_closer == NULL || next_closer->ch != _T(']') || next_closer->end - next_closer->beg != 1) - return false; + return 0; /* Check that the next_opener and next_closer are nested properly. */ if(next_opener->beg != opener->beg - 1 || next_closer->beg != closer->beg + 1) - return false; + return 0; /* We don't allow destination to be longer than 100 characters. * Lets scan to see whether there is '|'. (If not then the whole @@ -3824,12 +3824,12 @@ md_resolve_bracket_wikilink(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, dest_beg = opener->end; dest_end = (delim != NULL) ? delim->beg : closer->beg; if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) - return false; + return 0; /* There may not be any new line in the destination. */ for(off = dest_beg; off < dest_end; off++) { if(ISNEWLINE(off)) - return false; + return 0; } md_pop_openers(ctx, opener_index); @@ -3857,7 +3857,7 @@ md_resolve_bracket_wikilink(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, md_analyze_link_contents(ctx, lines, n_lines, delim_index+1, closer_index); *p_opener_index = next_opener->prev; - return true; + return 1; } /* Resolve footnote references [^label] in the current block. */ @@ -3871,9 +3871,9 @@ md_resolve_bracket_footnote(MD_CTX* ctx, MD_MARK* opener, MD_MARK* closer, OFF label_beg, label_end; if(!(ctx->parser.flags & MD_FLAG_FOOTNOTES)) - return false; + return 0; if(opener->ch != _T('[') || opener->end >= ctx->size || CH(opener->end) != _T('^')) - return false; + return 0; /* Expand the opener to eat the '^' */ opener->end++; @@ -3882,14 +3882,14 @@ md_resolve_bracket_footnote(MD_CTX* ctx, MD_MARK* opener, MD_MARK* closer, /* Verify the label satisfies the label rules. */ label_beg = opener->end; if(!md_is_footnote_label(ctx, label_beg, &label_end) || label_end != closer->beg) - return false; + return 0; if(label_beg >= label_end) - return false; /* empty label */ + return 0; /* empty label */ def = md_lookup_footnote_def(ctx, STR(label_beg), label_end - label_beg); if(def == NULL) - return false; + return 0; /* Assign index on first reference. */ if(def->index == 0) @@ -3909,7 +3909,7 @@ md_resolve_bracket_footnote(MD_CTX* ctx, MD_MARK* opener, MD_MARK* closer, *last_link_end = closer->end; *p_opener_index = opener->prev; - return true; + return 1; } /* Try to resolve a bracket pair as a CommonMark link or image. @@ -3924,7 +3924,7 @@ md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF* last_img_beg, OFF* last_img_end) { MD_LINK_ATTR attr; - int is_link = false; + int is_link = 0; if(next_opener != NULL && next_opener->beg == closer->end) { if(next_closer->beg > closer->end + 1) { @@ -3971,7 +3971,7 @@ md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, /* Cancel the link status. */ if(attr.title_needs_free) free(attr.title); - is_link = false; + is_link = 0; break; } @@ -4457,8 +4457,8 @@ md_analyze_permissive_autolink_segment(MD_CTX* ctx, OFF off, OFF end, OFF* p_end { int n_components = 0; int n_open_brackets = 0; - int seen_word_delim = true; - int seen_component_delim = true; + int seen_word_delim = 1; + int seen_component_delim = 1; OFF component_beg = off; if(word_extra == NULL) @@ -4494,18 +4494,18 @@ md_analyze_permissive_autolink_segment(MD_CTX* ctx, OFF off, OFF end, OFF* p_end } if(ISALNUM(off) || ISANYOF(off, word_extra)) { - seen_word_delim = false; - seen_component_delim = false; + seen_word_delim = 0; + seen_component_delim = 0; } else { if(seen_word_delim) break; if(ISANYOF(off, word_delims)) { - seen_word_delim = true; + seen_word_delim = 1; } else if(component_delim != _T('\0') && CH(off) == component_delim) { if(seen_component_delim) break; - seen_component_delim = true; + seen_component_delim = 1; component_beg = off; n_components++; } else { @@ -4519,7 +4519,7 @@ md_analyze_permissive_autolink_segment(MD_CTX* ctx, OFF off, OFF end, OFF* p_end off++; } - /* Rollback falsely consumed delimiter. */ + /* Rollback 0ly consumed delimiter. */ if(seen_word_delim || seen_component_delim) off = (scan_backwards ? off+1 : off-1); @@ -4550,7 +4550,7 @@ md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) /* E-mail requires the user name (before '@', i.e. scanning backwards). */ if(opener->ch == '@') { MD_ASSERT(CH(opener->beg) == _T('@')); - if(md_analyze_permissive_autolink_segment(ctx, beg, line_beg, &beg, true, + if(md_analyze_permissive_autolink_segment(ctx, beg, line_beg, &beg, 1, _T('\0'), NULL, _T(".-_+"), &left_cursor) < 1) return; @@ -4575,14 +4575,14 @@ md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) /* Scan for hostname segment. Hostname is mandatory and requires at least two * components delimited with a dot. */ - if(md_analyze_permissive_autolink_segment(ctx, end, line_end, &end, false, + if(md_analyze_permissive_autolink_segment(ctx, end, line_end, &end, 0, _T('.'), NULL, _T("-_"), &right_cursor) < 2) return; if(opener->ch != '@') { /* Scan for path segment. */ if(end < line_end && CH(end) == _T('/')) { - if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, 0, _T('/'), _T(".+-_~%"), NULL, &right_cursor) < 0) return; @@ -4593,14 +4593,14 @@ md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) /* Scan for query segment. */ if(end < line_end && CH(end) == _T('?')) { - if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, 0, _T('&'), _T("._=()"), _T("+-"), &right_cursor) < 0) return; } /* Scan for fragment segment. */ if(end < line_end && CH(end) == _T('#')) { - if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, false, + if(md_analyze_permissive_autolink_segment(ctx, end+1, line_end, &end, 0, _T('\0'), NULL, _T(".-+_"), &right_cursor) < 0) return; } @@ -5058,7 +5058,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A), - STR(dest_mark->beg), dest_mark->end - dest_mark->beg, false, + STR(dest_mark->beg), dest_mark->end - dest_mark->beg, 0, md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), title_mark->prev)); @@ -5116,7 +5116,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) if(closer->flags & MD_MARK_VALIDPERMISSIVEAUTOLINK) MD_CHECK(md_enter_leave_span_a(ctx, (mark->flags & MD_MARK_OPENER), - MD_SPAN_A, dest, dest_size, true, NULL, 0)); + MD_SPAN_A, dest, dest_size, 1, NULL, 0)); break; } @@ -5279,7 +5279,7 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, /* Break the line into table cells by identifying pipe characters who * form the cell boundary. */ - MD_CHECK(md_analyze_inlines(ctx, &line, 1, true)); + MD_CHECK(md_analyze_inlines(ctx, &line, 1, 1)); /* We have to remember the cell boundaries in local buffer because * ctx->marks[] shall be reused during cell contents processing. */ @@ -5412,7 +5412,7 @@ md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_li int i; int ret; - MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, false)); + MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, 0)); MD_CHECK(md_process_inlines(ctx, lines, n_lines)); abort: @@ -5532,7 +5532,7 @@ md_process_leaf_block(MD_CTX* ctx, MD_BLOCK* block) MD_ATTRIBUTE_BUILD info_build = { 0 }; MD_ATTRIBUTE_BUILD lang_build = { 0 }; int is_in_tight_list; - int clean_fence_code_detail = false; + int clean_fence_code_detail = 0; int ret = 0; /* For large tables check the table density: If it's too low, lets suppress @@ -5563,7 +5563,7 @@ md_process_leaf_block(MD_CTX* ctx, MD_BLOCK* block) memset(&det, 0, sizeof(det)); if(ctx->n_containers == 0) - is_in_tight_list = false; + is_in_tight_list = 0; else is_in_tight_list = !ctx->containers[ctx->n_containers-1].is_loose; @@ -5576,7 +5576,7 @@ md_process_leaf_block(MD_CTX* ctx, MD_BLOCK* block) /* For fenced code block, we may need to set the info string. */ if(block->data != 0) { memset(&det.code, 0, sizeof(MD_BLOCK_CODE_DETAIL)); - clean_fence_code_detail = true; + clean_fence_code_detail = 1; MD_CHECK(md_setup_fenced_code_detail(ctx, block, &det.code, &info_build, &lang_build)); } break; @@ -5665,13 +5665,13 @@ md_process_all_blocks(MD_CTX* ctx) switch(block->type) { case MD_BLOCK_UL: - det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? false : true; + det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? 0 : 1; det.ul.mark = (CHAR) block->data; break; case MD_BLOCK_OL: det.ol.start = block->n_lines; - det.ol.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? false : true; + det.ol.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? 0 : 1; det.ol.mark_delimiter = (CHAR) block->data; break; @@ -5709,13 +5709,13 @@ md_process_all_blocks(MD_CTX* ctx) MD_ENTER_BLOCK(block->type, &det); if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) { - ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST) ? true : false; + ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST) ? 1 : 0; ctx->n_containers++; } else if(block->type == MD_BLOCK_QUOTE || block->type == MD_BLOCK_ADMONITION) { /* This causes that any text in a block quote, even if * nested inside a tight list item, is wrapped with *

    ...

    . */ - ctx->containers[ctx->n_containers].is_loose = true; + ctx->containers[ctx->n_containers].is_loose = 1; ctx->n_containers++; } } @@ -5876,7 +5876,7 @@ md_consume_link_reference_definitions(MD_CTX* ctx) /* We may need to turn the first line after the link ref. def(s) into HR. * (https://github.com/mity/md4c/issues/414) */ if(n < n_lines && md_is_hr_line(ctx, lines[n].beg, &ignored, &ignored)) { - inject_hr = true; + inject_hr = 1; n++; /* Remove one more line below. */ } @@ -6045,7 +6045,7 @@ md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) int n = 1; if(!ISANYOF(beg, _T("-_*"))) - return false; + return 0; while(off < ctx->size && (CH(off) == CH(beg) || CH(off) == _T(' ') || CH(off) == _T('\t'))) { if(CH(off) == CH(beg)) @@ -6055,17 +6055,17 @@ md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) if(n < 3) { *p_killer = off; - return false; + return 0; } /* Nothing else can be present on the line. */ if(off < ctx->size && !ISNEWLINE(off)) { *p_killer = off; - return false; + return 0; } *p_end = off; - return true; + return 1; } static int @@ -6079,18 +6079,18 @@ md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end, unsigned* p_l n = off - beg; if(n > 6) - return false; + return 0; *p_level = n; if(!(ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS) && off < ctx->size && !ISBLANK(off) && !ISNEWLINE(off)) - return false; + return 0; while(off < ctx->size && ISBLANK(off)) off++; *p_beg = off; *p_end = off; - return true; + return 1; } static int @@ -6107,35 +6107,35 @@ md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) /* But nothing more is allowed on the line. */ if(off < ctx->size && !ISNEWLINE(off)) - return false; + return 0; *p_level = (CH(beg) == _T('=') ? 1 : 2); *p_end = off; - return true; + return 1; } static int md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) { OFF off = beg; - int found_pipe = false; + int found_pipe = 0; unsigned col_count = 0; if(off < ctx->size && CH(off) == _T('|')) { - found_pipe = true; + found_pipe = 1; off++; while(off < ctx->size && ISWHITESPACE(off)) off++; } while(1) { - int delimited = false; + int delimited = 0; /* Cell underline ("-----", ":----", "----:" or ":----:") */ if(off < ctx->size && CH(off) == _T(':')) off++; if(off >= ctx->size || CH(off) != _T('-')) - return false; + return 0; while(off < ctx->size && CH(off) == _T('-')) off++; if(off < ctx->size && CH(off) == _T(':')) @@ -6147,8 +6147,8 @@ md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) while(off < ctx->size && ISWHITESPACE(off)) off++; if(off < ctx->size && CH(off) == _T('|')) { - delimited = true; - found_pipe = true; + delimited = 1; + found_pipe = 1; off++; while(off < ctx->size && ISWHITESPACE(off)) off++; @@ -6159,15 +6159,15 @@ md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) break; if(!delimited) - return false; + return 0; } if(!found_pipe) - return false; + return 0; *p_end = off; *p_col_count = col_count; - return true; + return 1; } static int @@ -6180,7 +6180,7 @@ md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) /* Fence must have at least three characters. */ if(off - beg < 3) - return false; + return 0; ctx->code_fence_length = off - beg; @@ -6192,19 +6192,19 @@ md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) while(off < ctx->size && !ISNEWLINE(off)) { /* Backtick-based fence must not contain '`' in the info string. */ if(CH(beg) == _T('`') && CH(off) == _T('`')) - return false; + return 0; off++; } *p_end = off; - return true; + return 1; } static int md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) { OFF off = beg; - int ret = false; + int ret = 0; /* Closing fence must have at least the same length and use same char as * opening one. */ @@ -6221,7 +6221,7 @@ md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) if(off < ctx->size && !ISNEWLINE(off)) goto out; - ret = true; + ret = 1; out: /* Note we set *p_end even on failure: If we are not closing fence, caller @@ -6272,7 +6272,7 @@ static const TAG xx[] = { Xend }; #undef X #undef Xend -/* Returns type of the raw HTML block, or false if it is not HTML block. +/* Returns type of the raw HTML block, or 0 if it is not HTML block. * (Refer to CommonMark specification for details about the types.) */ static int @@ -6356,7 +6356,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) } } - return false; + return 0; } /* Case sensitive check whether there is a substring 'what' between 'beg' @@ -6370,15 +6370,15 @@ md_line_contains(MD_CTX* ctx, OFF beg, const CHAR* what, SZ what_len, OFF* p_end break; if(memcmp(STR(i), what, what_len * sizeof(CHAR)) == 0) { *p_end = i + what_len; - return true; + return 1; } } *p_end = i; - return false; + return 0; } -/* Returns type of HTML block end condition or false if not an end condition. +/* Returns type of HTML block end condition or 0 if not an end condition. * * Note it fills p_end even when it is not end condition as the caller * does not need to analyze contents of a raw HTML block. @@ -6400,7 +6400,7 @@ md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end) CH(off+2+t1[i].len) == _T('>')) { *p_end = off+2+t1[i].len+1; - return true; + return 1; } } } @@ -6408,20 +6408,20 @@ md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end) off++; } *p_end = off; - return false; + return 0; } case 2: - return (md_line_contains(ctx, beg, _T("-->"), 3, p_end) ? 2 : false); + return (md_line_contains(ctx, beg, _T("-->"), 3, p_end) ? 2 : 0); case 3: - return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : false); + return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : 0); case 4: - return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : false); + return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : 0); case 5: - return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : false); + return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : 0); case 6: MD_FALLTHROUGH(); case 7: @@ -6430,12 +6430,12 @@ md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end) *p_end = beg; return ctx->html_block_type; } - return false; + return 0; default: MD_UNREACHABLE(); } - return false; + return 0; } @@ -6444,14 +6444,14 @@ md_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* contai { /* Block quote has no "items" like lists. */ if(container->ch == _T('>')) - return false; + return 0; if(container->ch != pivot->ch) - return false; + return 0; if(container->mark_indent > pivot->contents_indent) - return false; + return 0; - return true; + return 1; } static int @@ -6484,12 +6484,12 @@ md_enter_child_containers(MD_CTX* ctx, int n_children) for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) { MD_CONTAINER* c = &ctx->containers[i]; - int is_ordered_list = false; + int is_ordered_list = 0; switch(c->ch) { case _T(')'): case _T('.'): - is_ordered_list = true; + is_ordered_list = 1; MD_FALLTHROUGH(); case _T('-'): @@ -6532,12 +6532,12 @@ md_leave_child_containers(MD_CTX* ctx, int n_keep) while(ctx->n_containers > n_keep) { MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1]; - int is_ordered_list = false; + int is_ordered_list = 0; switch(c->ch) { case _T(')'): case _T('.'): - is_ordered_list = true; + is_ordered_list = 1; MD_FALLTHROUGH(); case _T('-'): @@ -6576,29 +6576,29 @@ md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTA OFF max_end; if(off >= ctx->size || indent >= ctx->code_indent_offset) - return false; + return 0; /* Check for block quote mark. */ if(CH(off) == _T('>')) { off++; p_container->ch = _T('>'); - p_container->is_loose = false; - p_container->is_task = false; + p_container->is_loose = 0; + p_container->is_task = 0; p_container->mark_indent = indent; p_container->contents_indent = indent + 1; *p_end = off; - return true; + return 1; } /* Check for list item bullet mark. */ if(ISANYOF(off, _T("-+*")) && (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { p_container->ch = CH(off); - p_container->is_loose = false; - p_container->is_task = false; + p_container->is_loose = 0; + p_container->is_task = 0; p_container->mark_indent = indent; p_container->contents_indent = indent + 1; *p_end = off+1; - return true; + return 1; } /* Check for ordered list item marks. */ @@ -6616,15 +6616,15 @@ md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTA (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { p_container->ch = CH(off); - p_container->is_loose = false; - p_container->is_task = false; + p_container->is_loose = 0; + p_container->is_task = 0; p_container->mark_indent = indent; p_container->contents_indent = indent + off - beg + 1; *p_end = off+1; - return true; + return 1; } - return false; + return 0; } static unsigned @@ -6666,7 +6666,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, line->indent = md_line_indentation(ctx, total_indent, off, &off); total_indent += line->indent; line->beg = off; - line->enforce_new_block = false; + line->enforce_new_block = 0; /* Given the indentation and block quote marks '>', determine how many of * the current containers are our parents. */ @@ -6707,7 +6707,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, } } - while(true) { + while(1) { /* Check whether we are fenced code continuation. */ if(pivot_line->type == MD_LINE_FENCEDCODE) { line->beg = off; @@ -6717,7 +6717,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, if(line->indent < ctx->code_indent_offset) { if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { line->type = MD_LINE_BLANK; - ctx->last_line_has_list_loosening_effect = false; + ctx->last_line_has_list_loosening_effect = 0; break; } } @@ -6772,7 +6772,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, line->indent -= ctx->code_indent_offset; else line->indent = 0; - ctx->last_line_has_list_loosening_effect = false; + ctx->last_line_has_list_loosening_effect = 0; } else { line->type = MD_LINE_BLANK; ctx->consecutive_blank_lines++; @@ -6803,7 +6803,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, } ctx->consecutive_blank_lines = 0; - ctx->last_line_has_list_loosening_effect = false; + ctx->last_line_has_list_loosening_effect = 0; } /* Check whether we are Setext underline. */ @@ -6944,7 +6944,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, if(md_is_opening_code_fence(ctx, off, &off)) { line->type = MD_LINE_FENCEDCODE; line->data = 1; - line->enforce_new_block = true; + line->enforce_new_block = 1; break; } } @@ -6966,7 +6966,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, ctx->html_block_type = 0; } - line->enforce_new_block = true; + line->enforce_new_block = 1; line->type = MD_LINE_HTML; break; } @@ -7008,7 +7008,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) { MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); - task_container->is_task = true; + task_container->is_task = 1; task_container->task_mark_off = tmp + 1; off = tmp + 3; while(off < ctx->size && ISWHITESPACE(off)) @@ -7097,7 +7097,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, if(line->end - line->beg == md_strlen(MD_ADMONITION_TAGS[i]) + 3 && md_ascii_case_eq(STR(line->beg+2), MD_ADMONITION_TAGS[i], line->end - line->beg - 3)) { - ctx->containers[ctx->n_containers-1].is_admonition = true; + ctx->containers[ctx->n_containers-1].is_admonition = 1; ctx->containers[ctx->n_containers-1].admonition_type = i; line->type = MD_LINE_BLANK; break; From 0f60df489dd176f891776bda7ca14b17507418fe Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:26:02 +0900 Subject: [PATCH 63/90] huh --- external/md4c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/external/md4c.c b/external/md4c.c index 8665a1481..1c23cd113 100644 --- a/external/md4c.c +++ b/external/md4c.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include From 01356a07666b56d4462138bd73606e514d602d05 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:29:31 +0900 Subject: [PATCH 64/90] i love msvc --- external/md4c.c | 72 +++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/external/md4c.c b/external/md4c.c index 1c23cd113..c582ef92a 100644 --- a/external/md4c.c +++ b/external/md4c.c @@ -157,7 +157,7 @@ struct MD_LABEL_HASH_TABLE_tag { }; -/* During analyzes of inline marks, we need to manage stacks of unresolved +/* During analyzes of __inline marks, we need to manage stacks of unresolved * openers of the given type. * The stack connects the marks via MD_MARK::next; */ @@ -190,7 +190,7 @@ struct MD_CTX_tag { MD_LABEL_HASH_TABLE footnote_hashtable; unsigned next_footnote_index; /* 1-based counter for sequential numbering */ - /* Stack of inline/span markers. + /* Stack of __inline/span markers. * This is only used for parsing a single block contents but by storing it * here we may reuse the stack for subsequent blocks; i.e. we have fewer * (re)allocations. */ @@ -204,7 +204,7 @@ struct MD_CTX_tag { char mark_char_map[256]; #endif - /* For resolving of inline spans. */ + /* For resolving of __inline spans. */ MD_MARKSTACK opener_stacks[20]; #define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0]) /* Opener-only */ #define ASTERISK_OPENERS_oo_mod3_1 (ctx->opener_stacks[1]) @@ -228,7 +228,7 @@ struct MD_CTX_tag { #define PLUS_OPENERS (ctx->opener_stacks[19]) /* Stack of dummies which need to call free() for pointers stored in them. - * These are constructed during inline parsing and freed after all the block + * These are constructed during __inline parsing and freed after all the block * is processed (i.e. all callbacks referring those strings are called). */ MD_MARKSTACK ptr_stack; @@ -370,7 +370,7 @@ struct MD_VERBATIMLINE_tag { /* Case insensitive check of string equality. */ -static inline int +static __inline int md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) { OFF i; @@ -388,7 +388,7 @@ md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) return 1; } -static inline int +static __inline int md_ascii_eq(const CHAR* s1, const CHAR* s2, SZ n) { return memcmp(s1, s2, n * sizeof(CHAR)) == 0; @@ -887,7 +887,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf16le__(STR(off), ctx->size - (off), NULL)) #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf16le_before__(ctx, off)) - static inline int + static __inline int md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) { return md_decode_utf16le__(str+off, str_size-off, p_char_size); @@ -968,7 +968,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf8_before__(ctx, off)) - static inline unsigned + static __inline unsigned md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) { return md_decode_utf8__(str+off, str_size-off, p_char_size); @@ -981,7 +981,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define ISUNICODEPUNCT(off) ISPUNCT(off) #define ISUNICODEPUNCTBEFORE(off) ISPUNCT((off)-1) - static inline void + static __inline void md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) { info->codepoints[0] = codepoint; @@ -990,7 +990,7 @@ struct MD_UNICODE_FOLD_INFO_tag { info->n_codepoints = 1; } - static inline unsigned + static __inline unsigned md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size) { MD_UNUSED(str_size); @@ -1088,7 +1088,7 @@ md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size) *** Recognizing raw HTML *** ******************************/ -/* md_is_html_tag() may be called when processing inlines (inline raw HTML) +/* md_is_html_tag() may be called when processing __inlines (__inline raw HTML) * or when breaking document to blocks (checking for start of HTML block type 7). * * When breaking document to blocks, we do not yet know line boundaries, but @@ -1420,7 +1420,7 @@ md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end } } -static inline int +static __inline int md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) { return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end); @@ -1597,7 +1597,7 @@ abort: #define MD_FNV1A_BASE 2166136261U #define MD_FNV1A_PRIME 16777619U -static inline unsigned +static __inline unsigned md_fnv1a(unsigned base, const void* data, size_t n) { const unsigned char* buf = (const unsigned char*) data; @@ -2169,7 +2169,7 @@ md_free_footnote_defs(MD_CTX* ctx) *** Recognizing Links *** ***************************/ -/* Note this code is partially shared between processing inlines and blocks +/* Note this code is partially shared between processing __inlines and blocks * as reference definitions and links share some helper parser functions. */ @@ -2333,7 +2333,7 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, return 1; } -static inline int +static __inline int md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, OFF* p_contents_beg, OFF* p_contents_end) { @@ -2586,7 +2586,7 @@ abort: } static int -md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, +md_is___inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF* p_end, MD_LINK_ATTR* attr) { MD_SIZE line_index = 0; @@ -2705,7 +2705,7 @@ md_free_ref_defs(MD_CTX* ctx) *** Processing Inlines (a.k.a Spans) *** ******************************************/ -/* We process inlines in few phases: +/* We process __inlines in few phases: * * (1) We go through the block text and collect all significant characters * which may start/end a span or some other significant position into @@ -2850,6 +2850,8 @@ md_opener_stack(MD_CTX* ctx, int mark_index) default: MD_UNREACHABLE(); } + + return NULL; } static MD_MARK* @@ -2894,14 +2896,14 @@ md_add_mark(MD_CTX* ctx) } while(0) -static inline void +static __inline void md_mark_stack_push(MD_CTX* ctx, MD_MARKSTACK* stack, int mark_index) { ctx->marks[mark_index].next = stack->top; stack->top = mark_index; } -static inline int +static __inline int md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) { int top = stack->top; @@ -2912,21 +2914,21 @@ md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) /* Sometimes, we need to store a pointer into the mark. It can only happen * for dummy marks. */ -static inline void +static __inline void md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) { MD_ASSERT(ctx->marks[mark_index].ch == 'D'); ctx->marks[mark_index].pointer = ptr; } -static inline void* +static __inline void* md_mark_get_ptr(MD_CTX* ctx, int mark_index) { MD_ASSERT(ctx->marks[mark_index].ch == 'D'); return ctx->marks[mark_index].pointer; } -static inline void +static __inline void md_resolve_range(MD_CTX* ctx, int opener_index, int closer_index) { MD_MARK* opener = &ctx->marks[opener_index]; @@ -3716,7 +3718,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_m } /* Add a dummy mark at the end of the mark vector to simplify - * process_inlines(). */ + * process___inlines(). */ ADD_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); abort: @@ -3949,11 +3951,11 @@ md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, } } else { if(closer->end < ctx->size && CH(closer->end) == _T('(')) { - /* Might be inline link. */ - OFF inline_link_end = UINT_MAX; + /* Might be __inline link. */ + OFF __inline_link_end = UINT_MAX; int following_mark_index = closer_index + 1; - is_link = md_is_inline_link_spec(ctx, lines, n_lines, closer->end, &inline_link_end, &attr); + is_link = md_is___inline_link_spec(ctx, lines, n_lines, closer->end, &__inline_link_end, &attr); if(is_link < 0) return -1; @@ -3963,10 +3965,10 @@ md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, while(following_mark_index < ctx->n_marks) { MD_MARK* mark = &ctx->marks[following_mark_index]; - if(mark->beg >= inline_link_end) + if(mark->beg >= __inline_link_end) break; if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { - if(ctx->marks[mark->next].beg >= inline_link_end) { + if(ctx->marks[mark->next].beg >= __inline_link_end) { /* Cancel the link status. */ if(attr.title_needs_free) free(attr.title); @@ -3983,7 +3985,7 @@ md_resolve_bracket_link(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, if(is_link) { /* Eat the "(...)" */ - closer->end = inline_link_end; + closer->end = __inline_link_end; md_disable_marks(ctx, closer_index+1, following_mark_index); } } @@ -4626,7 +4628,7 @@ md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) #define MD_ANALYZE_NOSKIP_EMPH 0x01 -static inline void +static __inline void md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int mark_beg, int mark_end, const CHAR* mark_chars, const CHAR* noskip_mark_chars) { @@ -4696,7 +4698,7 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, /* Analyze marks (build ctx->marks). */ static int -md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) +md_analyze___inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) { int i; int ret; @@ -4853,7 +4855,7 @@ abort: /* Render the output, accordingly to the analyzed ctx->marks. */ static int -md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +md_process___inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) { MD_TEXTTYPE text_type; const MD_LINE* line = lines; @@ -5278,7 +5280,7 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, /* Break the line into table cells by identifying pipe characters who * form the cell boundary. */ - MD_CHECK(md_analyze_inlines(ctx, &line, 1, 1)); + MD_CHECK(md_analyze___inlines(ctx, &line, 1, 1)); /* We have to remember the cell boundaries in local buffer because * ctx->marks[] shall be reused during cell contents processing. */ @@ -5411,8 +5413,8 @@ md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_li int i; int ret; - MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, 0)); - MD_CHECK(md_process_inlines(ctx, lines, n_lines)); + MD_CHECK(md_analyze___inlines(ctx, lines, n_lines, 0)); + MD_CHECK(md_process___inlines(ctx, lines, n_lines)); abort: /* Free any temporary memory blocks stored within some dummy marks. */ From 09f2d6c565a8458468162408a811a21b9a439fc0 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:53:56 +0900 Subject: [PATCH 65/90] testing ci --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6c1637e8c..0a8b712a0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,7 +26,7 @@ pipeline { parallel { stage("Build for Linux 64-bit") { agent { - label "built-in" + label "untrusted" } steps { sh("git clean -dfx") From 0747cf2ec3d9ae68d74a9d1f7dae6b61064a9018 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 05:54:19 +0900 Subject: [PATCH 66/90] testing ci --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0a8b712a0..4f0b2027a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -38,7 +38,7 @@ pipeline { } stage("Build for Windows 32-bit") { agent { - label "built-in" + label "untrusted" } steps { sh("git clean -dfx") @@ -51,7 +51,7 @@ pipeline { } stage("Build for Windows 64-bit") { agent { - label "built-in" + label "untrusted" } steps { sh("git clean -dfx") @@ -76,7 +76,7 @@ pipeline { } stage("Build for Windows 32-bit (Watcom)") { agent { - label "built-in" + label "untrusted" } environment { WATCOM = "/usr/watcom" From 2f224ac912b957cd6baf0fd6ac3c5133c2716b00 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:06:07 +0900 Subject: [PATCH 67/90] fixing ci --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 4f0b2027a..76e3093af 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,6 +29,7 @@ pipeline { label "untrusted" } steps { + sh("apt-get install build-essential libx11-dev wayland-protocols libwayland-dev") sh("git clean -dfx") sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") sh("make -j4") From ffae70cbe78e2f7905f0a2a8148914f3a5e2d7b8 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:08:45 +0900 Subject: [PATCH 68/90] fixing ci --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 76e3093af..428176303 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,6 +29,7 @@ pipeline { label "untrusted" } steps { + sh("apt-get update") sh("apt-get install build-essential libx11-dev wayland-protocols libwayland-dev") sh("git clean -dfx") sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") From 289338a23c5ced89a4c746b62e2e655d269d60db Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:13:07 +0900 Subject: [PATCH 69/90] fixing ci --- Jenkinsfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 428176303..8f0033d93 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -30,7 +30,7 @@ pipeline { } steps { sh("apt-get update") - sh("apt-get install build-essential libx11-dev wayland-protocols libwayland-dev") + sh("apt-get install -y build-essential libx11-dev wayland-protocols libwayland-dev") sh("git clean -dfx") sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") sh("make -j4") @@ -43,6 +43,8 @@ pipeline { label "untrusted" } steps { + sh("apt-get update") + sh("apt-get install -y build-essential mingw-w64-i686-dev") sh("git clean -dfx") sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") sh("make -j4") @@ -57,6 +59,7 @@ pipeline { } steps { sh("git clean -dfx") + sh("apt-get install -y build-essential mingw-w64-x86-64-dev") sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") sh("make -j4") sh("mv src/Mw.dll Mw64.dll") @@ -86,6 +89,11 @@ pipeline { PATH = "/usr/watcom/binl64:${env.PATH}" } steps { + sh("git clean -dfx") + sh("apt-get install -y wget") + sh("wget https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz") + sh("mkdir -p /usr/watcom") + sh("tar xvf ow-snapshot.tar.xz -C /usr/watcom") sh("git clean -dfx") sh("wmake -f WatMakefile") sh("mv src/Mw.dll MwWat32.dll") From ac7373ebfc15ac891e24f13a4e103b829ab42bd5 Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:19:49 +0900 Subject: [PATCH 70/90] fix --- Jenkinsfile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8f0033d93..40cd9798d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -44,9 +44,9 @@ pipeline { } steps { sh("apt-get update") - sh("apt-get install -y build-essential mingw-w64-i686-dev") + sh("apt-get install -y make mingw-w64") sh("git clean -dfx") - sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") + sh("./configure --enable-opengl --cross --target=Windows --host=i686-w64-mingw32") sh("make -j4") sh("mv src/Mw.dll Mw32.dll") sh("mv src/libMw.dll.a libMw32.dll.a") @@ -58,9 +58,10 @@ pipeline { label "untrusted" } steps { + sh("apt-get update") + sh("apt-get install -y make mingw-w64") sh("git clean -dfx") - sh("apt-get install -y build-essential mingw-w64-x86-64-dev") - sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") + sh("./configure --enable-opengl --cross --target=Windows --host=x86_64-w64-mingw32") sh("make -j4") sh("mv src/Mw.dll Mw64.dll") sh("mv src/libMw.dll.a libMw64.dll.a") @@ -89,8 +90,9 @@ pipeline { PATH = "/usr/watcom/binl64:${env.PATH}" } steps { - sh("git clean -dfx") + sh("apt-get update") sh("apt-get install -y wget") + sh("git clean -dfx") sh("wget https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz") sh("mkdir -p /usr/watcom") sh("tar xvf ow-snapshot.tar.xz -C /usr/watcom") From 61cf15f562e5d0f8f470180514fb095b8ee3a6fb Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:52:34 +0900 Subject: [PATCH 71/90] ahh --- Dockerfile | 15 +++++++++++++++ Jenkinsfile | 17 ----------------- 2 files changed, 15 insertions(+), 17 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..02a430a58 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM jenkins/inbound-agent:latest + +USER root + +RUN apt-get update && apt-get install -y build-essential cmake pkg-config mingw-w64 xz-utils wget \ + libx11-dev libxrender-dev libfreetype-dev libwayland-dev wayland-protocols libxkbcommon-dev libcairo-dev libdbus-1-dev libgl-dev libvulkan-dev + +RUN mkdir -p /usr/watcom && wget -q -O /tmp/ow-snapshot.tar.xz https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz +RUN tar xJf /tmp/ow-snapshot.tar.xz -C /usr/watcom && rm -f /tmp/ow-snapshot.tar.xz + +ENV PATH=/usr/watcom/binl64:$PATH +ENV WATCOM=/usr/watcom +ENV INCLUDE=/usr/watcom/h + +USER jenkins diff --git a/Jenkinsfile b/Jenkinsfile index 40cd9798d..4e17a0776 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,8 +29,6 @@ pipeline { label "untrusted" } steps { - sh("apt-get update") - sh("apt-get install -y build-essential libx11-dev wayland-protocols libwayland-dev") sh("git clean -dfx") sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") sh("make -j4") @@ -43,8 +41,6 @@ pipeline { label "untrusted" } steps { - sh("apt-get update") - sh("apt-get install -y make mingw-w64") sh("git clean -dfx") sh("./configure --enable-opengl --cross --target=Windows --host=i686-w64-mingw32") sh("make -j4") @@ -58,8 +54,6 @@ pipeline { label "untrusted" } steps { - sh("apt-get update") - sh("apt-get install -y make mingw-w64") sh("git clean -dfx") sh("./configure --enable-opengl --cross --target=Windows --host=x86_64-w64-mingw32") sh("make -j4") @@ -84,18 +78,7 @@ pipeline { agent { label "untrusted" } - environment { - WATCOM = "/usr/watcom" - INCLUDE = "/usr/watcom/h:/usr/watcom/h/nt" - PATH = "/usr/watcom/binl64:${env.PATH}" - } steps { - sh("apt-get update") - sh("apt-get install -y wget") - sh("git clean -dfx") - sh("wget https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz") - sh("mkdir -p /usr/watcom") - sh("tar xvf ow-snapshot.tar.xz -C /usr/watcom") sh("git clean -dfx") sh("wmake -f WatMakefile") sh("mv src/Mw.dll MwWat32.dll") From 1f8b4074a9a167df9cea3903b118dc8003e2770a Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 06:58:36 +0900 Subject: [PATCH 72/90] ok --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02a430a58..10c8ea7aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,12 +4,13 @@ USER root RUN apt-get update && apt-get install -y build-essential cmake pkg-config mingw-w64 xz-utils wget \ libx11-dev libxrender-dev libfreetype-dev libwayland-dev wayland-protocols libxkbcommon-dev libcairo-dev libdbus-1-dev libgl-dev libvulkan-dev +RUN apt-get install -y libglu-dev libegl-dev RUN mkdir -p /usr/watcom && wget -q -O /tmp/ow-snapshot.tar.xz https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz RUN tar xJf /tmp/ow-snapshot.tar.xz -C /usr/watcom && rm -f /tmp/ow-snapshot.tar.xz ENV PATH=/usr/watcom/binl64:$PATH ENV WATCOM=/usr/watcom -ENV INCLUDE=/usr/watcom/h +ENV INCLUDE=/usr/watcom/h:/usr/watcom/h/nt USER jenkins From cb0d7b8583eafd77166219564f500793910bc170 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 14 Sep 2026 15:09:14 -0700 Subject: [PATCH 73/90] wayland drag and drop --- NTMakefile | 12 +++- WatMakefile | 12 +++- examples/basic/dnd.c | 59 ++++++++++++++++ include/Mw/LowLevel/Wayland.h | 3 + pl/rules.pl | 1 + src/backend/wayland/interfaces.c | 115 +++++++++++++++++++++++++++---- 6 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 examples/basic/dnd.c diff --git a/NTMakefile b/NTMakefile index 26723bc12..213800d0c 100644 --- a/NTMakefile +++ b/NTMakefile @@ -6,9 +6,9 @@ MW_LDFLAGS = /DLL EXE_CFLAGS = /Iinclude EXE_LDFLAGS = .SUFFIXES: .obj .c -all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\dnd.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe lib: src\Mw.dll -examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\dnd.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe clean: del /f /q external\libz\src\adler32.obj del /f /q external\libz\src\compress.obj @@ -112,6 +112,7 @@ clean: del /f /q examples\basic\clipboard.obj del /f /q examples\basic\colorpicker.obj del /f /q examples\basic\combobox.obj + del /f /q examples\basic\dnd.obj del /f /q examples\basic\document.obj del /f /q examples\basic\example.obj del /f /q examples\basic\filechooser.obj @@ -140,6 +141,7 @@ clean: del /f /q examples\basic\clipboard.exe del /f /q examples\basic\colorpicker.exe del /f /q examples\basic\combobox.exe + del /f /q examples\basic\dnd.exe del /f /q examples\basic\document.exe del /f /q examples\basic\example.exe del /f /q examples\basic\filechooser.exe @@ -199,6 +201,12 @@ examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll examples\basic\combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c +examples\basic\dnd.exe: examples\basic\dnd.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\dnd.obj src\Mw.lib + +examples\basic\dnd.obj: examples/basic/dnd.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/dnd.c + examples\basic\document.exe: examples\basic\document.obj src\Mw.dll $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\document.obj src\Mw.lib diff --git a/WatMakefile b/WatMakefile index 7924e17b6..0b846d13a 100644 --- a/WatMakefile +++ b/WatMakefile @@ -5,9 +5,9 @@ MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -d MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include EXE_LDFLAGS = system nt -all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/dnd.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe lib: src/Mw.dll -examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/dnd.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe clean: .SYMBOLIC %erase external/libz/src/adler32.obj %erase external/libz/src/compress.obj @@ -111,6 +111,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.obj %erase examples/basic/colorpicker.obj %erase examples/basic/combobox.obj + %erase examples/basic/dnd.obj %erase examples/basic/document.obj %erase examples/basic/example.obj %erase examples/basic/filechooser.obj @@ -139,6 +140,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.exe %erase examples/basic/colorpicker.exe %erase examples/basic/combobox.exe + %erase examples/basic/dnd.exe %erase examples/basic/document.exe %erase examples/basic/example.exe %erase examples/basic/filechooser.exe @@ -198,6 +200,12 @@ examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll examples/basic/combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c +examples/basic/dnd.exe: examples/basic/dnd.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/dnd.obj library clib3r.lib library src/Mw.lib + +examples/basic/dnd.obj: examples/basic/dnd.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/dnd.c + examples/basic/document.exe: examples/basic/document.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/document.obj library clib3r.lib library src/Mw.lib diff --git a/examples/basic/dnd.c b/examples/basic/dnd.c new file mode 100644 index 000000000..f88a650f3 --- /dev/null +++ b/examples/basic/dnd.c @@ -0,0 +1,59 @@ +#include + +MwWidget window, instructions, text1, cur_text; + +static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + MwVaApply(instructions, + MwNy, 50, + MwNwidth, w - 50 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(text1, + MwNy, 150, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); +} +static void MWAPI dnd(MwWidget handle, void* user_data, void* call_data) { + char* filename = call_data; + + (void)handle; + (void)user_data; + + if(filename != NULL) { + MwVaApply(cur_text, MwNtext, filename, NULL); + MwForceRender(cur_text); + } +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "dnd", + NULL); + instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, + MwNtext, "drag a file and its name will show up below.", + NULL); + text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, + MwNtext, "", + NULL); + + cur_text = text1; + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNdragAndDropHandler, dnd, NULL); + + resize(window, NULL, NULL); + + MwLoop(window); +} diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index fd9717802..44a39837b 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -292,6 +292,9 @@ typedef struct wl_clipboard_device_context { struct zwp_primary_selection_offer_v1* zwp; } offer; + const char* accepted_types[6]; + char selected_mime_type[4096]; + MwLL ll; // struct wl_seat* seat; } wl_clipboard_device_context_t; diff --git a/pl/rules.pl b/pl/rules.pl index ad62d6c24..551d39103 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -207,6 +207,7 @@ new_example("examples/basic/combobox"); new_example("examples/basic/treeview"); new_example("examples/basic/box"); new_example("examples/basic/clipboard"); +new_example("examples/basic/dnd"); new_example("examples/basic/sevensegment"); new_example("examples/basic/calculator"); new_example("examples/basic/filechooser"); diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index cbab2ad06..eaabf1657 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -100,11 +100,32 @@ static void wl_offer(void* data, struct wl_data_offer* wl_data_offer, const char* mime_type) { wl_clipboard_device_context_t* self = data; - wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); + int i; + for(i = 0; i < sizeof(self->accepted_types) / sizeof(self->accepted_types[0]); i++) { + if(strcmp(self->accepted_types[i], mime_type) == 0) { + wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); + memset(self->selected_mime_type, 0, 4096); + snprintf(self->selected_mime_type, sizeof(self->selected_mime_type), "%s", mime_type); + break; + } + } }; +static void wl_source_actions(void* data, + struct wl_data_offer* wl_data_offer, + uint32_t source_actions) { + + // printf("%d\n", source_actions); +}; + +static void wl_action(void* data, + struct wl_data_offer* wl_data_offer, + uint32_t dnd_action) {}; + struct wl_data_offer_listener offer_listener = { - .offer = wl_offer, + .offer = wl_offer, + .source_actions = wl_source_actions, + .action = wl_action, }; static void wl_data_device_data_offer(void* data, @@ -125,7 +146,7 @@ static void wl_data_device_enter(void* data, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer* id) { - MwLL self = data; + wl_clipboard_device_context_t* self = data; (void)wl_data_device; (void)surface; (void)x; @@ -134,33 +155,86 @@ static void wl_data_device_enter(void* data, WAYLAND_EVENT_OP_START(self); - self->wayland.clipboard_serial = serial; + self->ll->wayland.clipboard_serial = serial; WAYLAND_EVENT_OP_END(self); }; static void wl_data_device_leave(void* data, struct wl_data_device* wl_data_device) { - MwLL self = data; + wl_clipboard_device_context_t* self = data; - WAYLAND_EVENT_OP_START(self); - wl_data_device_destroy(wl_data_device); - WAYLAND_EVENT_OP_END(self); + if(self->offer.wl) { + wl_data_offer_destroy(self->offer.wl); + self->offer.wl = NULL; + } }; static void wl_data_device_motion(void* data, struct wl_data_device* wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y) { - (void)data; (void)wl_data_device; (void)time; (void)x; (void)y; + wl_clipboard_device_context_t* self = data; + + if(self->selected_mime_type[0] != '\0' && self->offer.wl) { + wl_data_offer_set_actions(self->offer.wl, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + } }; static void wl_data_device_drop(void* data, struct wl_data_device* wl_data_device) { - (void)data; - (void)wl_data_device; + wl_clipboard_device_context_t* self = data; + int fds[2]; + fd_set set; + char* buf = NULL; + struct timeval timeout; + int rc = 0; + + if(pipe(fds) != 0) { + + return; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + timeout.tv_sec = 0; + timeout.tv_usec = 1000; + + wl_data_offer_receive(self->offer.wl, self->selected_mime_type, fds[1]); + close(fds[1]); + + MwLLWaylandFlush(self->ll); + wl_display_roundtrip(self->ll->wayland.display); + + while(MwTRUE) { + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + char b; + ssize_t n = read(fds[0], &b, sizeof(b)); + if(n <= 0) { + break; + } + arrpush(buf, b); + } + } + arrpush(buf, 0); + close(fds[0]); + + setup_clipboard(self->ll, self->ll->wayland.pointer_seat); + + if(strstr(buf, "file://")) { + MwLLDispatch(self->ll, drag_and_drop, buf + sizeof("file://") - 1); + } else { + MwLLDispatch(self->ll, drag_and_drop, buf); + } + + arrfree(buf); + + self->selected_mime_type[0] = '\0'; }; static void wl_data_device_selection(void* data, @@ -256,6 +330,7 @@ static void wl_data_source_listener_target(void* data, (void)data; (void)wl_data_source; (void)mime_type; + printf("test\n"); }; static void wl_data_source_listener_send(void* data, struct wl_data_source* wl_data_source, @@ -297,6 +372,7 @@ static void wl_data_source_listener_cancelled(void* data, wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/uri-list"); wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); @@ -348,7 +424,7 @@ struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_ /* wl_data_device_manager setup function */ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { (void)version; - wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); + wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 3); wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); @@ -357,6 +433,7 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); + wl_data_source_offer(wayland->clipboard_source.wl, "text/uri-list"); wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); @@ -1040,6 +1117,13 @@ static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat) { device_ctx_zwp->ll = self; zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); + + device_ctx_zwp->accepted_types[0] = "text/plain"; + device_ctx_zwp->accepted_types[1] = "text/plain;charset=utf-8"; + device_ctx_zwp->accepted_types[2] = "TEXT"; + device_ctx_zwp->accepted_types[3] = "STRING"; + device_ctx_zwp->accepted_types[4] = "UTF8_STRING"; + device_ctx_zwp->accepted_types[5] = "text/uri-list"; } static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); @@ -1050,6 +1134,13 @@ static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); + + device_ctx_wl->accepted_types[0] = "text/plain"; + device_ctx_wl->accepted_types[1] = "text/plain;charset=utf-8"; + device_ctx_wl->accepted_types[2] = "TEXT"; + device_ctx_wl->accepted_types[3] = "STRING"; + device_ctx_wl->accepted_types[4] = "UTF8_STRING"; + device_ctx_wl->accepted_types[5] = "text/uri-list"; }; static void keyboard_repeat_info(void* data, From 36e647fcef5c854727aadbeb8fcbe7db8db9bd7d Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 07:16:53 +0900 Subject: [PATCH 74/90] ok --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 10c8ea7aa..0cb38a7ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,9 +2,7 @@ FROM jenkins/inbound-agent:latest USER root -RUN apt-get update && apt-get install -y build-essential cmake pkg-config mingw-w64 xz-utils wget \ - libx11-dev libxrender-dev libfreetype-dev libwayland-dev wayland-protocols libxkbcommon-dev libcairo-dev libdbus-1-dev libgl-dev libvulkan-dev -RUN apt-get install -y libglu-dev libegl-dev +RUN apt-get update && apt-get install -y build-essential cmake pkg-config mingw-w64 xz-utils wget libx11-dev libxrender-dev libfreetype-dev libwayland-dev wayland-protocols libxkbcommon-dev libcairo-dev libdbus-1-dev libgl-dev libvulkan-dev libglu-dev libegl-dev libgbm-dev RUN mkdir -p /usr/watcom && wget -q -O /tmp/ow-snapshot.tar.xz https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz RUN tar xJf /tmp/ow-snapshot.tar.xz -C /usr/watcom && rm -f /tmp/ow-snapshot.tar.xz From 2835b917a9e2eb6881be5ce4c41c26123102c73b Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 07:24:41 +0900 Subject: [PATCH 75/90] ok --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4e17a0776..8e4228586 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,7 +26,7 @@ pipeline { parallel { stage("Build for Linux 64-bit") { agent { - label "untrusted" + label "built-in" } steps { sh("git clean -dfx") @@ -38,7 +38,7 @@ pipeline { } stage("Build for Windows 32-bit") { agent { - label "untrusted" + label "built-in" } steps { sh("git clean -dfx") @@ -51,7 +51,7 @@ pipeline { } stage("Build for Windows 64-bit") { agent { - label "untrusted" + label "built-in" } steps { sh("git clean -dfx") @@ -76,7 +76,7 @@ pipeline { } stage("Build for Windows 32-bit (Watcom)") { agent { - label "untrusted" + label "built-in" } steps { sh("git clean -dfx") From 979e5e056de063d58c0f52bf062114f6db3cd0cd Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 07:30:04 +0900 Subject: [PATCH 76/90] ok --- Jenkinsfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8e4228586..9b7d63979 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -78,6 +78,11 @@ pipeline { agent { label "built-in" } + environment { + WATCOM = "/usr/watcom" + INCLUDE = "/usr/watcom/h:/usr/watcom/h/nt" + PATH = "/usr/watcom/binl64:${env.PATH}" + } steps { sh("git clean -dfx") sh("wmake -f WatMakefile") From e5255bcbfa01cc69df47094fdab8da9d7f6ec06d Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 07:39:29 +0900 Subject: [PATCH 77/90] fix dnd --- examples/basic/dnd.c | 1 + milsko.xml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/examples/basic/dnd.c b/examples/basic/dnd.c index f88a650f3..0a2495e0b 100644 --- a/examples/basic/dnd.c +++ b/examples/basic/dnd.c @@ -40,6 +40,7 @@ int main() { window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, MwNtitle, "dnd", + MwNacceptsDnD, 1, NULL); instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, MwNtext, "drag a file and its name will show up below.", diff --git a/milsko.xml b/milsko.xml index ec30e8237..7ac33f181 100644 --- a/milsko.xml +++ b/milsko.xml @@ -107,6 +107,7 @@ + @@ -197,6 +198,9 @@ + + + From fdbdc83527a6bb2a77f60d00451b5130942b5df8 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 15 Sep 2026 09:45:38 +0900 Subject: [PATCH 78/90] better wayland clipboard, initial xdnd support --- examples/basic/dnd.c | 44 +++---- include/Mw/LowLevel/Wayland.h | 2 + include/Mw/LowLevel/X11.h | 44 ++++--- src/backend/wayland/interfaces.c | 80 +++++++++++- src/backend/wayland/wayland.c | 2 +- src/backend/x11.c | 208 +++++++++++++++++++++++++++++-- 6 files changed, 322 insertions(+), 58 deletions(-) diff --git a/examples/basic/dnd.c b/examples/basic/dnd.c index 0a2495e0b..8d0f47d03 100644 --- a/examples/basic/dnd.c +++ b/examples/basic/dnd.c @@ -1,6 +1,6 @@ #include -MwWidget window, instructions, text1, cur_text; +MwWidget window, box, instructions, cur_text, text_listbox; static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h; @@ -11,17 +11,7 @@ static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { w = MwGetInteger(handle, MwNwidth); h = MwGetInteger(handle, MwNheight); - MwVaApply(instructions, - MwNy, 50, - MwNwidth, w - 50 * 2, - MwNheight, h - 125 - 50 * 3, - NULL); - - MwVaApply(text1, - MwNy, 150, - MwNwidth, w - 25 * 2, - MwNheight, h - 125 - 50 * 3, - NULL); + MwVaApply(box, MwNwidth, w, MwNheight, h, NULL); } static void MWAPI dnd(MwWidget handle, void* user_data, void* call_data) { char* filename = call_data; @@ -30,29 +20,35 @@ static void MWAPI dnd(MwWidget handle, void* user_data, void* call_data) { (void)user_data; if(filename != NULL) { - MwVaApply(cur_text, MwNtext, filename, NULL); - MwForceRender(cur_text); + MwListBoxSet(text_listbox, -1, -1, filename); + MwForceRender(text_listbox); } } int main() { - MwLibraryInit(); + MwSizeHints hints; - window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, - MwNtitle, "dnd", + MwLibraryInit(); + hints.min_width = hints.min_height = 600; + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 600, 600, + MwNtitle, "dnd", + MwNsizeHints, &hints, + NULL); + + box = MwVaCreateWidget(MwBoxClass, NULL, window, 0, 0, 800, 800, MwNorientation, MwVERTICAL, MwNpadding, 25, NULL); + + instructions = MwVaCreateWidget(MwLabelClass, "button", box, 50, 50, 750, 50, + MwNtext, "drag files onto this text box, and their names will show up below.", MwNacceptsDnD, 1, NULL); - instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, - MwNtext, "drag a file and its name will show up below.", - NULL); - text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, + text_listbox = MwVaCreateWidget(MwListBoxClass, "label", box, 25, 150, 750, 700, MwNtext, "", + MwNacceptsDnD, 1, NULL); - cur_text = text1; - MwAddUserHandler(window, MwNresizeHandler, resize, NULL); - MwAddUserHandler(window, MwNdragAndDropHandler, dnd, NULL); + MwAddUserHandler(instructions, MwNdragAndDropHandler, dnd, NULL); resize(window, NULL, NULL); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 44a39837b..7a2c25c23 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -456,6 +456,8 @@ struct _MwLLWayland { MwU64 next_elapsed; long start_time; long end_time; + + MwBool accepts_dnd; }; struct _MwLLWaylandColor { diff --git a/include/Mw/LowLevel/X11.h b/include/Mw/LowLevel/X11.h index e1b74169c..9663097cb 100644 --- a/include/Mw/LowLevel/X11.h +++ b/include/Mw/LowLevel/X11.h @@ -27,20 +27,36 @@ struct _MwLLX11 { unsigned int width; unsigned int height; - Display* display; - Window window; - Pixmap pixmap; - GC gc; - Colormap colormap; - Atom wm_delete; - Atom wm_protocols; - Atom utf8_string; - Atom compound_text; - Atom text; - Atom clipboard; - Atom selection; - XIM xim; - XIC xic; + Display* display; + Window window; + Pixmap pixmap; + GC gc; + Colormap colormap; + Atom wm_delete; + Atom wm_protocols; + Atom utf8_string; + Atom compound_text; + Atom text; + Atom clipboard; + Atom selection; + Atom xdnd_type_list; + Atom xdnd_selection; + Atom xdnd_enter; + Atom xdnd_position; + Atom xdnd_status; + Atom xdnd_leave; + Atom xdnd_drop; + Atom xdnd_finished; + Atom xdnd_action_copy; + Atom xdnd_text_uri_list; + Atom xdnd_text_plain; + Atom xdnd_aware; + int xdnd_source; + unsigned char xdnd_version; + int xdnd_format; + + XIM xim; + XIC xic; long clipboard_time; int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUND_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index eaabf1657..dd58f9aa9 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -19,6 +19,7 @@ static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); +static bool hit_detect(MwLL child, MwLL* _topmost_parent, MwPoint* _point, MwPoint* _relative_mouse_pos, MwPoint* _absolute_pos); /* Recursively dispatch a key event to a widget and its children */ static void recursive_dispatch_key(MwLL handle, int* k) { @@ -168,6 +169,57 @@ static void wl_data_device_leave(void* data, self->offer.wl = NULL; } }; + +static MwBool motion_cursor_change(MwLL self, wl_clipboard_device_context_t* ctx) { + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.accepts_dnd) { + return MwTRUE; + } else if(self->common.user) { + MwWidget w = self->common.user; + int i, n; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + MwLL topmost_parent = child; + MwPoint point; + MwPoint relative_mouse_pos; + MwPoint absolute_pos; + + if(hit_detect(child, &topmost_parent, &point, &relative_mouse_pos, &absolute_pos)) { + return MwTRUE; + } else { + return motion_cursor_change(child, ctx); + } + } + } + } + return MwFALSE; +} + +static void clipboard_dispatch(MwLL self, char* buf) { + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.accepts_dnd) { + MwLLDispatch(self, drag_and_drop, buf); + } else if(self->common.user) { + MwWidget w = self->common.user; + int i, n; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + MwLL topmost_parent = child; + MwPoint point; + MwPoint relative_mouse_pos; + MwPoint absolute_pos; + + if(hit_detect(child, &topmost_parent, &point, &relative_mouse_pos, &absolute_pos) && child->wayland.accepts_dnd) { + MwLLDispatch(child, drag_and_drop, buf); + return; + } else { + clipboard_dispatch(child, buf); + } + } + } + } +} + static void wl_data_device_motion(void* data, struct wl_data_device* wl_data_device, uint32_t time, @@ -179,8 +231,15 @@ static void wl_data_device_motion(void* data, (void)y; wl_clipboard_device_context_t* self = data; + self->ll->wayland.cur_mouse_pos.x = wl_fixed_to_int(x); + self->ll->wayland.cur_mouse_pos.y = wl_fixed_to_int(y); + if(self->selected_mime_type[0] != '\0' && self->offer.wl) { - wl_data_offer_set_actions(self->offer.wl, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + if(motion_cursor_change(self->ll, self)) { + wl_data_offer_set_actions(self->offer.wl, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + } else { + wl_data_offer_set_actions(self->offer.wl, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); + }; } }; static void wl_data_device_drop(void* data, @@ -193,7 +252,6 @@ static void wl_data_device_drop(void* data, int rc = 0; if(pipe(fds) != 0) { - return; } @@ -226,10 +284,20 @@ static void wl_data_device_drop(void* data, setup_clipboard(self->ll, self->ll->wayland.pointer_seat); - if(strstr(buf, "file://")) { - MwLLDispatch(self->ll, drag_and_drop, buf + sizeof("file://") - 1); - } else { - MwLLDispatch(self->ll, drag_and_drop, buf); + char* buf_ptr = buf; + while(buf_ptr) { + char* next = strstr(buf_ptr, "\n"); + if(next) { + *next = '\0'; + if(strstr(buf_ptr, "file://")) { + clipboard_dispatch(self->ll, buf_ptr + sizeof("file://") - 1); + } else { + clipboard_dispatch(self->ll, buf_ptr); + } + buf_ptr = next + 1; + } else { + buf_ptr = NULL; + } } arrfree(buf); diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 61546646c..bd17f848c 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1794,7 +1794,6 @@ static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - rect->x = 0; rect->y = 0; rect->width = handle->wayland.mw; @@ -1803,6 +1802,7 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { static void MwLLSetupDragAndDropImpl(MwLL handle) { (void)handle; + handle->wayland.accepts_dnd = MwTRUE; } static void MwLLBeginStateChangeImpl(MwLL handle) { diff --git a/src/backend/x11.c b/src/backend/x11.c index 8b908e474..eaa64e0f6 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -82,6 +82,8 @@ static struct symtbl { void (*XSetICFocus)(XIC); XImage* (*XGetImage)(Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int); int (*XRaiseWindow)(Display*, Window); + int (*XFlush)(Display*); + char* (*XGetAtomName)(Display*, Atom); XSizeHints* (*XAllocSizeHints)(void); XVisualInfo* (*XGetVisualInfo)(Display*, long, XVisualInfo*, int*); @@ -186,6 +188,8 @@ static struct symtbl { #define XChangeWindowAttributes xsymtbl.XChangeWindowAttributes #define XGetImage xsymtbl.XGetImage #define XRaiseWindow xsymtbl.XRaiseWindow +#define XFlush xsymtbl.XFlush +#define XGetAtomName xsymtbl.XGetAtomName #if USE_XRENDER #define XRenderFindStandardFormat xsymtbl.XRenderFindStandardFormat @@ -425,6 +429,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); r->x11.wm_protocols = XInternAtom(r->x11.display, "WM_PROTOCOLS", False); + XSetWMProtocols(r->x11.display, r->x11.window, &r->x11.wm_delete, 1); r->x11.utf8_string = XInternAtom(r->x11.display, "UTF8_STRING", False); @@ -433,6 +438,21 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.clipboard = XInternAtom(r->x11.display, "CLIPBOARD", False); r->x11.selection = XInternAtom(r->x11.display, "_MILSKO_SELECTION_", False); + r->x11.xdnd_type_list = XInternAtom(r->x11.display, "XdndTypeList", False); + r->x11.xdnd_selection = XInternAtom(r->x11.display, "XdndSelection", False); + r->x11.xdnd_enter = XInternAtom(r->x11.display, "XdndEnter", False); + r->x11.xdnd_position = XInternAtom(r->x11.display, "XdndPosition", False); + r->x11.xdnd_status = XInternAtom(r->x11.display, "XdndStatus", False); + r->x11.xdnd_leave = XInternAtom(r->x11.display, "XdndLeave", False); + r->x11.xdnd_drop = XInternAtom(r->x11.display, "XdndDrop", False); + r->x11.xdnd_finished = XInternAtom(r->x11.display, "XdndFinished", False); + r->x11.xdnd_action_copy = XInternAtom(r->x11.display, "XdndActionCopy", False); + r->x11.xdnd_text_uri_list = XInternAtom(r->x11.display, "text/uri-list", False); + r->x11.xdnd_text_plain = XInternAtom(r->x11.display, "text/plain", False); + r->x11.xdnd_aware = XInternAtom(r->x11.display, "XdndAware", False); + r->x11.xdnd_version = 5; + r->x11.xdnd_format = None; + r->x11.clipboard_pending = 0; r->x11.gc = XCreateGC(r->x11.display, r->x11.window, 0, NULL); @@ -704,10 +724,15 @@ static void MwLLNextEventImpl(MwLL handle) { while(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, SelectionNotify, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { int render = 0; - if(ev.type == Expose) { + switch(ev.type) { + case Expose: + { handle->x11.force_render = 0; render = 1; - } else if(ev.type == ButtonPress) { + break; + }; + case ButtonPress: + { MwMouse p; p.point.x = ev.xbutton.x; p.point.y = ev.xbutton.y; @@ -728,7 +753,10 @@ static void MwLLNextEventImpl(MwLL handle) { #endif MwLLDispatch(handle, down, &p); - } else if(ev.type == ButtonRelease) { + break; + }; + case ButtonRelease: + { MwMouse p; p.point.x = ev.xbutton.x; p.point.y = ev.xbutton.y; @@ -745,24 +773,122 @@ static void MwLLNextEventImpl(MwLL handle) { } MwLLDispatch(handle, up, &p); - } else if(ev.type == ConfigureNotify) { + break; + }; + case ConfigureNotify: + { if(handle->x11.width != (unsigned int)ev.xconfigure.width || handle->x11.height != (unsigned int)ev.xconfigure.height) { MwLLDispatch(handle, resize, NULL); destroy_pixmap(handle); create_pixmap(handle); render = 1; + break; } handle->x11.width = ev.xconfigure.width; handle->x11.height = ev.xconfigure.height; - } else if(ev.type == ClientMessage) { + }; + case ClientMessage: + { + if(ev.xclient.message_type == handle->x11.wm_protocols && ev.xclient.data.l[0] == (long)handle->x11.wm_delete) { MwLLDispatch(handle, close, NULL); } - } else if(ev.type == FocusIn) { + + if( + ev.xclient.message_type == handle->x11.xdnd_enter || + ev.xclient.message_type == handle->x11.xdnd_position || + ev.xclient.message_type == handle->x11.xdnd_drop) { + char* name = XGetAtomName(handle->x11.display, ev.xclient.message_type); + + if(ev.xclient.message_type == handle->x11.xdnd_enter) { + Bool list = ev.xclient.data.l[1] & 1; + int version = ev.xclient.data.l[1] >> 24; + unsigned long count = 0; + unsigned char* formats = NULL; + unsigned long i; + handle->x11.xdnd_source = ev.xclient.data.l[0]; + if(list) { + Atom actualType; + int32_t actualFormat; + unsigned long bytesAfter; + + XGetWindowProperty((Display*)handle->x11.display, + handle->x11.xdnd_source, + handle->x11.xdnd_type_list, + 0, + LONG_MAX, + False, + 4, + &actualType, + &actualFormat, + &count, + &bytesAfter, + (unsigned char**)&formats); + } else { + count = 0; + + if(ev.xclient.data.l[2] != None) + formats[count++] = ev.xclient.data.l[2]; + if(ev.xclient.data.l[3] != None) + formats[count++] = ev.xclient.data.l[3]; + if(ev.xclient.data.l[4] != None) + formats[count++] = ev.xclient.data.l[4]; + } + + for(i = 0; i < count; i++) { + if(formats[i] == handle->x11.xdnd_text_uri_list || formats[i] == handle->x11.xdnd_text_plain) { + handle->x11.xdnd_format = formats[i]; + printf("format %d\n", handle->x11.xdnd_format); + break; + } + } + + if(list) { + XFree(formats); + } + } + if(ev.xclient.message_type == handle->x11.xdnd_position && handle->x11.xdnd_version >= 5) { + XEvent reply; + reply.xclient.message_type = handle->x11.xdnd_status; + + if(handle->x11.xdnd_format) { + reply.xclient.data.l[1] = 1; + if(handle->x11.xdnd_version >= 2) reply.xclient.data.l[4] = handle->x11.xdnd_action_copy; + } + XSendEvent(handle->x11.display, handle->x11.xdnd_source, False, NoEventMask, &reply); + XFlush(handle->x11.display); + } + if(ev.xclient.message_type == handle->x11.xdnd_drop && handle->x11.xdnd_version >= 5) { + Time time = CurrentTime; + if(handle->x11.xdnd_version >= 1) + time = ev.xclient.data.l[2]; + + if(handle->x11.xdnd_format) { + XConvertSelection((Display*)handle->x11.display, + handle->x11.xdnd_selection, + handle->x11.xdnd_format, + handle->x11.xdnd_selection, + (Window)handle->x11.window, + time); + } + } + + XFree(name); + } + break; + }; + case FocusIn: + { MwLLDispatch(handle, focus_in, NULL); - } else if(ev.type == FocusOut) { + break; + }; + case FocusOut: + { MwLLDispatch(handle, focus_out, NULL); - } else if(ev.type == MotionNotify) { + break; + }; + case MotionNotify: + { MwPoint p; XWindowAttributes attr; @@ -780,7 +906,11 @@ static void MwLLNextEventImpl(MwLL handle) { if(handle->x11.grabbed && (p.x != 0 || p.y != 0)) { XWarpPointer(handle->x11.display, None, handle->x11.window, 0, 0, 0, 0, attr.width / 2, attr.height / 2); } - } else if(ev.type == KeyPress || ev.type == KeyRelease) { + break; + }; + case KeyPress: + case KeyRelease: + { int n = -1; char str[512]; KeySym sym; @@ -844,10 +974,60 @@ static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, key_released, &n); } } - } else if(ev.type == SelectionNotify) { + break; + }; + case SelectionNotify: + { handle->x11.clipboard_pending = 0; - if(ev.xselection.property != None) { + if(ev.xselection.property == handle->x11.xdnd_selection) { + XEvent reply; + char* data; + unsigned long result; + Atom actualType; + int32_t actualFormat; + unsigned long bytesAfter; + + XGetWindowProperty(handle->x11.display, + ev.xselection.requestor, ev.xselection.property, + 0, LONG_MAX, False, ev.xselection.target, + &actualType, &actualFormat, &result, &bytesAfter, + (unsigned char**)&data); + + if(result == 0) + break; + + /* !! untested lmao !! */ + printf("File(s) dropped: %s\n", data); + char* data_ptr = data; + while(data_ptr) { + char* next = strstr(data, "\n"); + if(next) *next = '\0'; + + printf("%s\n", data_ptr); + + if(strstr(data_ptr, "file://")) { + MwLLDispatch(handle, drag_and_drop, data_ptr + sizeof("file://") - 1); + } else { + MwLLDispatch(handle, drag_and_drop, data_ptr); + } + if(next) data_ptr = next + 1; + else + data_ptr = NULL; + } + + if(data) + XFree(data); + + if(handle->x11.xdnd_version >= 2) { + reply.xclient.message_type = handle->x11.xdnd_finished; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = handle->x11.xdnd_action_copy; + + XSendEvent((Display*)handle->x11.display, handle->x11.xdnd_source, False, NoEventMask, &reply); + XFlush((Display*)handle->x11.display); + } + } else if(ev.xselection.property != None) { Atom type; int format; unsigned long nitems, after, size; @@ -884,9 +1064,9 @@ static void MwLLNextEventImpl(MwLL handle) { free(buf); } } - XDeleteProperty(handle->x11.display, handle->x11.window, handle->x11.selection); } + } break; } if(render) { int x, y; @@ -1365,7 +1545,7 @@ static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { } static void MwLLSetupDragAndDropImpl(MwLL handle) { - (void)handle; + XChangeProperty(handle->x11.display, handle->x11.window, handle->x11.xdnd_aware, 4, 32, PropModeReplace, &handle->x11.xdnd_version, 1); } static void MwLLBeginStateChangeImpl(MwLL handle) { @@ -1512,6 +1692,8 @@ static int MwLLX11CallInitImpl(void) { X11_FUNC_LOAD(XSetICFocus); X11_FUNC_LOAD(XGetImage); X11_FUNC_LOAD(XRaiseWindow); + X11_FUNC_LOAD(XFlush); + X11_FUNC_LOAD(XGetAtomName); X11_FUNC_LOAD(XAllocSizeHints); X11_FUNC_LOAD(XGetVisualInfo); From 097e11244ccffd618c8d05a28555c50f5cd88baf Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 11:58:16 +0900 Subject: [PATCH 79/90] somewhat functional --- examples/basic/document.c | 27 ++- include/Mw/Constants.h | 10 + include/Mw/StringDefs.h | 2 +- include/Mw/TypeDefs.h | 19 ++ milsko.xml | 12 +- src/widget/document.c | 437 +++++++++++++++++++++++++++++++++++++- 6 files changed, 490 insertions(+), 17 deletions(-) diff --git a/examples/basic/document.c b/examples/basic/document.c index e53339c78..a9482a8c6 100644 --- a/examples/basic/document.c +++ b/examples/basic/document.c @@ -12,10 +12,22 @@ static void MWAPI resize_window(MwWidget handle, void* user, void* call) { MwNwidth, width - 20, MwNheight, height - 20, NULL); + + width = MwGetInteger(MwGetParent(MwViewportGetViewport(viewport)), MwNwidth); + height = MwGetInteger(MwGetParent(MwViewportGetViewport(viewport)), MwNheight); + + MwVaApply(document, + MwNwidth, width, + NULL); } -static void MWAPI resize_document(MwWidget handle, void* user, void* call) { - MwViewportSetSize(viewport, MwGetInteger(document, MwNwidth), MwGetInteger(document, MwNheight)); +static void MWAPI layout_document(MwWidget handle, void* user, void* call) { + int height = *(int*)call; + + MwViewportSetSize(viewport, MwGetInteger(document, MwNwidth), height); + MwVaApply(document, + MwNheight, height, + NULL); } int main() { @@ -27,17 +39,14 @@ int main() { viewport = MwCreateWidget(MwViewportClass, "viewport", window, 0, 0, 0, 0); - MwVaApply(MwGetParent(MwViewportGetViewport(viewport)), - MwNbackground, "#fff", - MwNforeground, "#000", - NULL); - document = MwVaCreateWidget(MwDocumentClass, "document", MwViewportGetViewport(viewport), 0, 0, 0, 0, - MwNtext, "# Hello world!\nThis is a test text...", + MwNtext, "# Hello world!\nThis is a __test__ text...\n\n`Some monospace here`\n\n~~Removed~~\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + MwNbackground, "#fff", + MwNforeground, "#000", NULL); MwAddUserHandler(window, MwNresizeHandler, resize_window, NULL); - MwAddUserHandler(document, MwNresizeHandler, resize_document, NULL); + MwAddUserHandler(document, MwNlayoutHandler, layout_document, NULL); resize_window(window, NULL, NULL); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index acd6b0539..bbef56c18 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -121,6 +121,16 @@ enum MwCHART { MwCHART_LINE }; +enum MwDOCUMENT_LAYOUT { + MwDOCUMENT_TEXT = 0, + MwDOCUMENT_NEWLINE, + MwDOCUMENT_HEADER, + MwDOCUMENT_BOLD, + MwDOCUMENT_MONOSPACE, + MwDOCUMENT_STRIKETHROUGH, + MwDOCUMENT_UNDERLINE, +}; + enum MwMOUSE { MwMOUSE_LEFT = 1, MwMOUSE_MIDDLE, diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 71b8f5fbe..b3f527bdf 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -58,7 +58,6 @@ #define MwNminute "Iminute" #define MwNsecond "Isecond" #define MwNtype "Itype" -#define MwNautoResize "IautoResize" #define MwNtitle "Stitle" #define MwNtext "Stext" @@ -105,5 +104,6 @@ #define MwNclipboardHandler "Cclipboard" #define MwNdarkThemeHandler "CdarkTheme" #define MwNdragAndDropHandler "CdragAndDrop" +#define MwNlayoutHandler "Clayout" #endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 0be60e855..2a11d36c3 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -32,6 +32,8 @@ typedef struct _MwTab* MwTab; typedef struct _MwTable* MwTable; typedef struct _MwChartEntry MwChartEntry; typedef struct _MwChart* MwChart; +typedef struct _MwDocumentLayout MwDocumentLayout; +typedef struct _MwDocument* MwDocument; typedef struct _MwMouse MwMouse; typedef struct _MwTTFInfo* MwTTFInfo; #ifdef _MILSKO @@ -264,6 +266,23 @@ struct _MwMouse { int button; }; +struct _MwDocumentLayout { + int type; + + int x; + int y; + + char* text; + int integer; + + MwFLFont font; +}; + +struct _MwDocument { + MwDocumentLayout* layouts; + MwFLFont headers[6]; +}; + struct _MwTTFInfo { char* family; int weight; diff --git a/milsko.xml b/milsko.xml index 7ac33f181..b864efc9a 100644 --- a/milsko.xml +++ b/milsko.xml @@ -112,7 +112,6 @@ - @@ -201,6 +200,9 @@ + + + @@ -702,6 +704,14 @@
    + + + + + + + + diff --git a/src/widget/document.c b/src/widget/document.c index 4c5414a6e..3f8364601 100644 --- a/src/widget/document.c +++ b/src/widget/document.c @@ -1,16 +1,62 @@ #include #include "../../external/md4c.h" +#include "../../external/stb_ds.h" + +#define IsFontChange(x) ((x) == MwDOCUMENT_HEADER || (x) == MwDOCUMENT_BOLD || (x) == MwDOCUMENT_MONOSPACE || (x) == MwDOCUMENT_STRIKETHROUGH) + +static void reset(MwWidget handle) { + MwDocument d = handle->internal; + int i; + + for(i = 0; i < arrlen(d->layouts); i++) { + if(d->layouts[i].text != NULL) free(d->layouts[i].text); + } + arrfree(d->layouts); +} static int wcreate(MwWidget handle) { + MwDocument d = malloc(sizeof(*d)); + int i; + + memset(d, 0, sizeof(*d)); + + for(i = 0; i < 6; i++) { + d->headers[i] = MwFLFontLoad == NULL ? NULL : MwFLFontLoad(MwBoldTTFData, MwBoldTTFDataSize, 13 + 2 * (6 - i)); + } + + handle->internal = d; + MwSetDefault(handle); return 0; } +static void destroy(MwWidget handle) { + MwDocument d = handle->internal; + int i; + + reset(handle); + + for(i = 0; i < 6; i++) { + if(d->headers[i] != NULL) MwFLFontFree(d->headers[i]); + } + + free(handle->internal); +} + static void draw(MwWidget handle) { - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwRect r; + MwDocument d = handle->internal; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r; + int i; + MwFLFont font = NULL; + MwPoint u_p, s_p; + int u = 0, s = 0; + + u_p.x = u_p.y = 0; + s_p.x = s_p.y = 0; r.x = 0; r.y = 0; @@ -18,21 +64,400 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); + for(i = 0; i < arrlen(d->layouts); i++) { + MwDocumentLayout* l = &d->layouts[i]; + + switch(l->type) { + case MwDOCUMENT_TEXT: + { + MwPoint p; + + p.x = l->x; + p.y = l->y + MwTextHeight(handle, font, l->text) / 2; + + MwDrawText(handle, font, &p, l->text, MwALIGNMENT_BEGINNING, text); + + if(u || s) { + MwPoint line[2]; + int j; + + if(u_p.y != l->y) { + u_p.x = 0; + u_p.y = l->y; + } + + line[0] = u_p; + line[1] = u_p; + + line[1].x = p.x + MwTextWidth(handle, font, l->text); + u_p.x = line[1].x; + + for(j = 0; j < 2; j++) { + line[0].y += MwTextHeight(handle, font, l->text) / 2; + line[1].y += MwTextHeight(handle, font, l->text) / 2; + if((j == 0 && s) || (j == 1 && u)) MwLLLine(handle->lowlevel, line, text); + } + } + break; + } + case MwDOCUMENT_UNDERLINE: + case MwDOCUMENT_STRIKETHROUGH: + { + if(l->type == MwDOCUMENT_UNDERLINE) { + u = l->integer; + } else { + s = l->integer; + } + + if(l->type == MwDOCUMENT_UNDERLINE ? u : s) { + int j; + + for(j = i + 1; j < arrlen(d->layouts) && d->layouts[j].type != l->type; j++) { + if(d->layouts[j].type == MwDOCUMENT_TEXT) { + MwPoint p; + + p.x = d->layouts[j].x; + p.y = d->layouts[j].y; + + if(l->type == MwDOCUMENT_UNDERLINE) { + u_p = p; + } else { + s_p = p; + } + break; + } + } + } + break; + } + default: + break; + } + + if(IsFontChange(l->type)) font = l->font; + } + + MwLLFreeColor(text); MwLLFreeColor(base); } +static int enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) { + MwDocument d = userdata; + MwDocumentLayout l; + + memset(&l, 0, sizeof(l)); + + switch(type) { + case MD_BLOCK_H: + { + l.type = MwDOCUMENT_HEADER; + l.integer = ((MD_BLOCK_H_DETAIL*)detail)->level; + + arrput(d->layouts, l); + break; + } + default: + break; + } + + return 0; +} + +static int leave_block(MD_BLOCKTYPE type, void* detail, void* userdata) { + MwDocument d = userdata; + MwDocumentLayout l; + + (void)detail; + + memset(&l, 0, sizeof(l)); + + switch(type) { + case MD_BLOCK_H: + { + l.type = MwDOCUMENT_HEADER; + l.integer = 0; + + arrput(d->layouts, l); + break; + } + case MD_BLOCK_P: + { + l.type = MwDOCUMENT_NEWLINE; + + arrput(d->layouts, l); + break; + } + default: + break; + } + + return 0; +} + +static int enter_span(MD_SPANTYPE type, void* detail, void* userdata) { + MwDocument d = userdata; + MwDocumentLayout l; + + (void)detail; + + memset(&l, 0, sizeof(l)); + + switch(type) { + case MD_SPAN_STRONG: + { + l.type = MwDOCUMENT_BOLD; + l.integer = 1; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_U: + { + l.type = MwDOCUMENT_UNDERLINE; + l.integer = 1; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_CODE: + { + l.type = MwDOCUMENT_MONOSPACE; + l.integer = 1; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_DEL: + { + l.type = MwDOCUMENT_STRIKETHROUGH; + l.integer = 1; + + arrput(d->layouts, l); + break; + } + default: + break; + } + + return 0; +} + +static int leave_span(MD_SPANTYPE type, void* detail, void* userdata) { + MwDocument d = userdata; + MwDocumentLayout l; + + (void)detail; + + memset(&l, 0, sizeof(l)); + + switch(type) { + case MD_SPAN_STRONG: + { + l.type = MwDOCUMENT_BOLD; + l.integer = 0; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_U: + { + l.type = MwDOCUMENT_UNDERLINE; + l.integer = 0; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_CODE: + { + l.type = MwDOCUMENT_MONOSPACE; + l.integer = 0; + + arrput(d->layouts, l); + break; + } + case MD_SPAN_DEL: + { + l.type = MwDOCUMENT_STRIKETHROUGH; + l.integer = 0; + + arrput(d->layouts, l); + break; + } + default: + break; + } + + return 0; +} + +static int text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) { + MwDocument d = userdata; + MwDocumentLayout l; + + memset(&l, 0, sizeof(l)); + + switch(type) { + case MD_TEXT_NORMAL: + case MD_TEXT_CODE: + { + char* str = malloc(size + 1); + char* begin = str; + char* next; + + memcpy(str, text, size); + str[size] = 0; + + do { + next = strchr(str, ' '); + if(next != NULL) next[0] = 0; + + if(strlen(str) > 0) { + memset(&l, 0, sizeof(l)); + + l.type = MwDOCUMENT_TEXT; + l.text = MwStringDuplicate(str); + + arrput(d->layouts, l); + } + + str = next + 1; + } while(next != NULL); + + free(begin); + break; + } + case MD_TEXT_BR: + { + l.type = MwDOCUMENT_NEWLINE; + + arrput(d->layouts, l); + break; + } + default: + break; + } + + return 0; +} + +#define TOPFONT fontstack[arrlen(fontstack) - 1] +#define POP arrdel(fontstack, arrlen(fontstack) - 1); + +static void layout(MwWidget handle) { + MwDocument d = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int i; + int x = 0; + int y = 0; + MwFLFont* fontstack = NULL; + + arrput(fontstack, NULL); + + for(i = 0; i < arrlen(d->layouts); i++) { + MwDocumentLayout* l = &d->layouts[i]; + + switch(l->type) { + case MwDOCUMENT_TEXT: + { + int t = MwTextWidth(handle, TOPFONT, l->text); + + if(x > 0) x += MwTextWidth(handle, TOPFONT, " "); + + if((x + t) >= w) { + x = 0; + y += MwTextHeight(handle, TOPFONT, "M"); + } + + l->x = x; + l->y = y; + + x += t; + break; + } + case MwDOCUMENT_NEWLINE: + { + x = 0; + y += MwTextHeight(handle, TOPFONT, "M"); + break; + } + case MwDOCUMENT_BOLD: + { + if(l->integer) { + MwFLFont f = (void*)((size_t)(TOPFONT) | MwFLFlagBold); + + arrput(fontstack, f); + } else { + POP; + } + break; + } + case MwDOCUMENT_MONOSPACE: + { + if(l->integer) { + MwFLFont f = (void*)((size_t)(TOPFONT) | MwFLFlagMonospace); + + arrput(fontstack, f); + } else { + POP; + } + break; + } + case MwDOCUMENT_HEADER: + { + if(l->integer) { + arrput(fontstack, d->headers[l->integer - 1]); + } else { + x = 0; + y += MwTextHeight(handle, TOPFONT, "M"); + + POP; + } + break; + } + } + + l->font = TOPFONT; + } + + y += MwTextHeight(handle, TOPFONT, "M"); + MwDispatchUserHandler(handle, MwNlayoutHandler, &y); + + arrfree(fontstack); + + MwForceRender(handle); +} + static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNautoResize) == 0 || strcmp(key, MwNtext) == 0) MwForceRender(handle); + if(strcmp(key, MwNtext) == 0) MwForceRender(handle); if(strcmp(key, MwNtext) == 0) { - MD_PARSER parser; + MD_PARSER parser; + const char* str = MwGetText(handle, MwNtext); + memset(&parser, 0, sizeof(parser)); + + parser.flags = MD_FLAG_UNDERLINE | MD_FLAG_STRIKETHROUGH; + parser.enter_block = enter_block; + parser.leave_block = leave_block; + parser.enter_span = enter_span; + parser.leave_span = leave_span; + parser.text = text; + + reset(handle); + + md_parse(str, strlen(str), &parser, handle->internal); + + layout(handle); } } +static void resize(MwWidget handle) { + layout(handle); +} + MwClassRec MwDocumentClassRec = { wcreate, /* create */ - NULL, /* destroy */ + destroy, /* destroy */ draw, /* draw */ NULL, /* click */ NULL, /* parent_resize */ @@ -43,7 +468,7 @@ MwClassRec MwDocumentClassRec = { NULL, /* key */ NULL, /* execute */ NULL, /* tick */ - NULL, /* resize */ + resize, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ NULL, /* clipboard */ From 3922213bebb21ec39bf70e6fa3ac5a8686f47c2e Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 12:01:53 +0900 Subject: [PATCH 80/90] fix --- examples/basic/periodic.c | 4 ++-- include/Mw/Constants.h | 4 ++-- milsko.xml | 4 ++-- src/widget/chart.c | 20 ++++++++++---------- src/widget/combobox.c | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index f7148daf2..fb2fbd9d0 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -269,7 +269,7 @@ int main() { wclock = child(f); f = frame("3D Bar Chart", -PaddingContent, -PaddingContent, MwChartClass, - MwNtype, MwCHART_3D_BAR, + MwNtype, MwCHART_BAR_3D, NULL); w = child(f); MwChartAdd(w, -1, "A", -800, NULL); @@ -282,7 +282,7 @@ int main() { MwChartAdd(w, -1, "H", 800, NULL); f = frame("3D Pie Chart", -PaddingContent, -PaddingContent, MwChartClass, - MwNtype, MwCHART_3D_PIE, + MwNtype, MwCHART_PIE_3D, NULL); w = child(f); MwChartAdd(w, -1, "A", 10, NULL); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index bbef56c18..ed77ab5c5 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -115,9 +115,9 @@ enum MwCLIPBOARD { enum MwCHART { MwCHART_BAR = 0, - MwCHART_3D_BAR, + MwCHART_BAR_3D, MwCHART_PIE, - MwCHART_3D_PIE, + MwCHART_PIE_3D, MwCHART_LINE }; diff --git a/milsko.xml b/milsko.xml index b864efc9a..1bb19fd31 100644 --- a/milsko.xml +++ b/milsko.xml @@ -239,9 +239,9 @@
    0 - + - + 1 diff --git a/src/widget/chart.c b/src/widget/chart.c index 67753c998..40e760da2 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -44,7 +44,7 @@ static void draw_line(MwWidget handle, const char* text, double x, double y, dou p[1].y = p[0].y; MwDrawText(handle, NULL, p, text, MwALIGNMENT_END, color); - if(type == MwCHART_3D_BAR) { + if(type == MwCHART_BAR_3D) { MwPoint p2[2]; p2[0] = p[0]; @@ -150,7 +150,7 @@ static void bar_chart(MwWidget handle, MwRect* _r, double vmin, double vmax, int MwDrawRect(handle, &node, color); - if(type == MwCHART_3D_BAR) { + if(type == MwCHART_BAR_3D) { MwRect node2 = node; MwFixRect(&node2); @@ -195,7 +195,7 @@ static void bar_chart(MwWidget handle, MwRect* _r, double vmin, double vmax, int if(!modern) { MwDrawRectLine(handle, &node, border); - if(type == MwCHART_3D_BAR) { + if(type == MwCHART_BAR_3D) { MwLLLine(handle->lowlevel, &persp_top[0], border); MwLLLine(handle->lowlevel, &persp_top[1], border); MwLLLine(handle->lowlevel, &persp_top[2], border); @@ -231,7 +231,7 @@ static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, M int k; int type = MwGetInteger(handle, MwNtype); int modern = MwGetInteger(handle, MwNmodernLook); - double vsquish = type == MwCHART_3D_PIE ? 2 : 1; + double vsquish = type == MwCHART_PIE_3D ? 2 : 1; int i; MwPoint p[2]; MwPoint p2[360 + 1 + 1]; @@ -266,7 +266,7 @@ static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, M count = j + 1; - if((k == 0 || k == 1) && type == MwCHART_3D_PIE) { + if((k == 0 || k == 1) && type == MwCHART_PIE_3D) { int j; MwPoint p3[360 + 1 + 1]; int d = 0; @@ -296,7 +296,7 @@ static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, M } if(k == 2) { - MwLLPolygon(handle->lowlevel, p2, count, type == MwCHART_3D_PIE ? colorl : color); + MwLLPolygon(handle->lowlevel, p2, count, type == MwCHART_PIE_3D ? colorl : color); } else if(k == 3) { int j; @@ -308,7 +308,7 @@ static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, M p2[0].x += cos((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4; p2[0].y += sin((cangle + angle / 2 - 90) / 180 * M_PI) * radius / 4 / vsquish; - handle->bgcolor = type == MwCHART_3D_PIE ? colorl : color; + handle->bgcolor = type == MwCHART_PIE_3D ? colorl : color; MwDrawText(handle, NULL, p2, c->entries[i].name, MwALIGNMENT_CENTER, border); } @@ -320,7 +320,7 @@ static void pie_chart(MwWidget handle, MwRect* _r, const char** colors, int n, M } } - if(!modern && type == MwCHART_3D_PIE) { + if(!modern && type == MwCHART_PIE_3D) { p[0].x = r.width / 2 - radius / 2; p[0].y = r.height / 2; p[1] = p[0]; @@ -425,11 +425,11 @@ static void draw(MwWidget handle) { switch(type) { case MwCHART_BAR: - case MwCHART_3D_BAR: + case MwCHART_BAR_3D: bar_chart(handle, &r, vmin, vmax, space, colors, n, border); break; case MwCHART_PIE: - case MwCHART_3D_PIE: + case MwCHART_PIE_3D: pie_chart(handle, &r, colors, n, border); break; case MwCHART_LINE: diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 5502a0702..a6cb87695 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -19,8 +19,6 @@ static int wcreate(MwWidget handle) { } static void destroy(MwWidget handle) { - MwComboBox cb = handle->internal; - MwComboBoxReset(handle); free(handle->internal); } From a87f7813120ec5bf288aa7637eccbf048c9edb1a Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 12:05:02 +0900 Subject: [PATCH 81/90] i love msvc --- examples/basic/document.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/basic/document.c b/examples/basic/document.c index a9482a8c6..8ae77f480 100644 --- a/examples/basic/document.c +++ b/examples/basic/document.c @@ -31,6 +31,14 @@ static void MWAPI layout_document(MwWidget handle, void* user, void* call) { } int main() { + char* text = malloc(64 * 1024); + int i; + + strcpy(text, "# Hello world!\nThis is a __test__ text...\n\n`Some monospace here`\n\n~~Removed~~"); + for(i = 0; i < 10; i++) { + strcat(text, "\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); + } + MwLibraryInit(); window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, @@ -40,7 +48,7 @@ int main() { viewport = MwCreateWidget(MwViewportClass, "viewport", window, 0, 0, 0, 0); document = MwVaCreateWidget(MwDocumentClass, "document", MwViewportGetViewport(viewport), 0, 0, 0, 0, - MwNtext, "# Hello world!\nThis is a __test__ text...\n\n`Some monospace here`\n\n~~Removed~~\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + MwNtext, text, MwNbackground, "#fff", MwNforeground, "#000", NULL); @@ -50,5 +58,7 @@ int main() { resize_window(window, NULL, NULL); + free(text); + MwLoop(window); } From 5d14444de0cb6b1ec77bdcc83262ae603fe4473b Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 15 Sep 2026 12:07:02 +0900 Subject: [PATCH 82/90] looks better --- examples/basic/document.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/basic/document.c b/examples/basic/document.c index 8ae77f480..9bce54832 100644 --- a/examples/basic/document.c +++ b/examples/basic/document.c @@ -49,8 +49,6 @@ int main() { document = MwVaCreateWidget(MwDocumentClass, "document", MwViewportGetViewport(viewport), 0, 0, 0, 0, MwNtext, text, - MwNbackground, "#fff", - MwNforeground, "#000", NULL); MwAddUserHandler(window, MwNresizeHandler, resize_window, NULL); From fe371ad89c881416c054e87ce205184fe0dc785b Mon Sep 17 00:00:00 2001 From: Nishi Date: Wed, 16 Sep 2026 03:29:42 +0900 Subject: [PATCH 83/90] add codeblock --- examples/basic/document.c | 1 + include/Mw/Constants.h | 1 + src/widget/document.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/examples/basic/document.c b/examples/basic/document.c index 9bce54832..1051a6b9e 100644 --- a/examples/basic/document.c +++ b/examples/basic/document.c @@ -35,6 +35,7 @@ int main() { int i; strcpy(text, "# Hello world!\nThis is a __test__ text...\n\n`Some monospace here`\n\n~~Removed~~"); + strcat(text, "\n```\nint main(){\n printf(\"Hello, world!\\n\");\n}\n```"); for(i = 0; i < 10; i++) { strcat(text, "\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); } diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index ed77ab5c5..0a79ae606 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -124,6 +124,7 @@ enum MwCHART { enum MwDOCUMENT_LAYOUT { MwDOCUMENT_TEXT = 0, MwDOCUMENT_NEWLINE, + MwDOCUMENT_SPACE, MwDOCUMENT_HEADER, MwDOCUMENT_BOLD, MwDOCUMENT_MONOSPACE, diff --git a/src/widget/document.c b/src/widget/document.c index 3f8364601..2dc7ec96d 100644 --- a/src/widget/document.c +++ b/src/widget/document.c @@ -156,6 +156,14 @@ static int enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) { arrput(d->layouts, l); break; } + case MD_BLOCK_CODE: + { + l.type = MwDOCUMENT_MONOSPACE; + l.integer = 1; + + arrput(d->layouts, l); + break; + } default: break; } @@ -187,6 +195,14 @@ static int leave_block(MD_BLOCKTYPE type, void* detail, void* userdata) { arrput(d->layouts, l); break; } + case MD_BLOCK_CODE: + { + l.type = MwDOCUMENT_MONOSPACE; + l.integer = 0; + + arrput(d->layouts, l); + break; + } default: break; } @@ -311,12 +327,24 @@ static int text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userd next = strchr(str, ' '); if(next != NULL) next[0] = 0; - if(strlen(str) > 0) { + if(strcmp(str, "\n") == 0) { + memset(&l, 0, sizeof(l)); + + l.type = MwDOCUMENT_NEWLINE; + + arrput(d->layouts, l); + } else if(strlen(str) > 0) { memset(&l, 0, sizeof(l)); l.type = MwDOCUMENT_TEXT; l.text = MwStringDuplicate(str); + arrput(d->layouts, l); + } else { + memset(&l, 0, sizeof(l)); + + l.type = MwDOCUMENT_SPACE; + arrput(d->layouts, l); } @@ -374,6 +402,11 @@ static void layout(MwWidget handle) { x += t; break; } + case MwDOCUMENT_SPACE: + { + x += MwTextWidth(handle, TOPFONT, " "); + break; + } case MwDOCUMENT_NEWLINE: { x = 0; From 8d48075f50780c03715c56e65616da4006e484e3 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 02:03:09 +0900 Subject: [PATCH 84/90] MwNdocumentActivateHandler --- examples/basic/document.c | 18 +++- include/Mw/Constants.h | 1 + include/Mw/Resource/Cursor.h | 20 ++++ include/Mw/StringDefs.h | 1 + include/Mw/TypeDefs.h | 13 ++- milsko.xml | 4 + src/cursor/center.c | 43 ++++++++ src/cursor/hand.c | 46 ++++++++ src/widget/document.c | 202 +++++++++++++++++++++++++++++++---- 9 files changed, 322 insertions(+), 26 deletions(-) create mode 100644 src/cursor/center.c create mode 100644 src/cursor/hand.c diff --git a/examples/basic/document.c b/examples/basic/document.c index 1051a6b9e..f9529fe04 100644 --- a/examples/basic/document.c +++ b/examples/basic/document.c @@ -30,14 +30,25 @@ static void MWAPI layout_document(MwWidget handle, void* user, void* call) { NULL); } +static void MWAPI activate_document(MwWidget handle, void* user, void* call) { + if(strcmp((const char*)call, "you_clicked") == 0) { + MwVaApply(document, + MwNtext, "# You clicked the thing!", + NULL); + } +} + int main() { char* text = malloc(64 * 1024); int i; - strcpy(text, "# Hello world!\nThis is a __test__ text...\n\n`Some monospace here`\n\n~~Removed~~"); - strcat(text, "\n```\nint main(){\n printf(\"Hello, world!\\n\");\n}\n```"); + strcpy(text, "# Hello world!\nThis is a __test__ text...\n\n"); + strcat(text, "`Some monospace here`\n\n"); + strcat(text, "~~Removed~~\n"); + strcat(text, "```\nint main(){\n printf(\"Hello, world!\\n\");\n}\n```\n"); + strcat(text, "[Click me!](you_clicked)\n\n"); for(i = 0; i < 10; i++) { - strcat(text, "\n\n**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); + strcat(text, "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n"); } MwLibraryInit(); @@ -54,6 +65,7 @@ int main() { MwAddUserHandler(window, MwNresizeHandler, resize_window, NULL); MwAddUserHandler(document, MwNlayoutHandler, layout_document, NULL); + MwAddUserHandler(document, MwNdocumentActivateHandler, activate_document, NULL); resize_window(window, NULL, NULL); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 0a79ae606..a0eec8beb 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -130,6 +130,7 @@ enum MwDOCUMENT_LAYOUT { MwDOCUMENT_MONOSPACE, MwDOCUMENT_STRIKETHROUGH, MwDOCUMENT_UNDERLINE, + MwDOCUMENT_CLICKABLE }; enum MwMOUSE { diff --git a/include/Mw/Resource/Cursor.h b/include/Mw/Resource/Cursor.h index 9a4780286..c9347b97a 100644 --- a/include/Mw/Resource/Cursor.h +++ b/include/Mw/Resource/Cursor.h @@ -63,6 +63,26 @@ MWDECL MwCursor MwCursorHidden; */ MWDECL MwCursor MwCursorHiddenMask; +/*! + * @brief Hand cursor + */ +MWDECL MwCursor MwCursorHand; + +/*! + * @brief Hand cursor mask + */ +MWDECL MwCursor MwCursorHandMask; + +/*! + * @brief Center cursor + */ +MWDECL MwCursor MwCursorCenter; + +/*! + * @brief Center cursor mask + */ +MWDECL MwCursor MwCursorCenterMask; + #ifdef __cplusplus } #endif diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index b3f527bdf..cf0a7233a 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -84,6 +84,7 @@ #define MwNactivateHandler "Cactivate" #define MwNlistBoxActivateHandler "ClistBoxActivate" #define MwNtreeViewActivateHandler "CtreeViewActivate" +#define MwNdocumentActivateHandler "CdocumentActivate" #define MwNresizeHandler "Cresize" #define MwNtickHandler "Ctick" #define MwNmenuHandler "Cmenu" diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 2a11d36c3..3463b37b8 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -33,6 +33,7 @@ typedef struct _MwTable* MwTable; typedef struct _MwChartEntry MwChartEntry; typedef struct _MwChart* MwChart; typedef struct _MwDocumentLayout MwDocumentLayout; +typedef struct _MwDocumentClickable MwDocumentClickable; typedef struct _MwDocument* MwDocument; typedef struct _MwMouse MwMouse; typedef struct _MwTTFInfo* MwTTFInfo; @@ -278,9 +279,17 @@ struct _MwDocumentLayout { MwFLFont font; }; +struct _MwDocumentClickable { + MwRect hitbox; + char* event; +}; + struct _MwDocument { - MwDocumentLayout* layouts; - MwFLFont headers[6]; + MwDocumentLayout* layouts; + MwDocumentClickable* clickables; + MwFLFont headers[6]; + + int center_cursor; }; struct _MwTTFInfo { diff --git a/milsko.xml b/milsko.xml index 1bb19fd31..5b9041000 100644 --- a/milsko.xml +++ b/milsko.xml @@ -154,6 +154,9 @@ + + + @@ -710,6 +713,7 @@ +
    diff --git a/src/cursor/center.c b/src/cursor/center.c new file mode 100644 index 000000000..2340f57d5 --- /dev/null +++ b/src/cursor/center.c @@ -0,0 +1,43 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ +MwCursor MwCursorCenter = { + 10, 14, -4, -14, {48, /* ....##.... */ + 48, /* ....##.... */ + 120, /* ...####... */ + 120, /* ...####... */ + 252, /* ..######.. */ + 252, /* ..######.. */ + 510, /* .########. */ + 510, /* .########. */ + 819, /* ##..##..## */ + 561, /* #...##...# */ + 48, /* ....##.... */ + 48, /* ....##.... */ + 48, /* ....##.... */ + 48, /* ....##.... */ + 0, 0}}; +MwCursor MwCursorCenterMask = { + 12, 16, -5, -15, { + 240, /* ....####.... */ + 240, /* ....####.... */ + 504, /* ...######... */ + 504, /* ...######... */ + 1020, /* ..########.. */ + 1020, /* ..########.. */ + 2046, /* .##########. */ + 2046, /* .##########. */ + 4095, /* ############ */ + 4095, /* ############ */ + 4095, /* ############ */ + 3831, /* ###.####.### */ + 240, /* ....####.... */ + 240, /* ....####.... */ + 240, /* ....####.... */ + 240 /* ....####.... */ + }}; diff --git a/src/cursor/hand.c b/src/cursor/hand.c new file mode 100644 index 000000000..07b015d6d --- /dev/null +++ b/src/cursor/hand.c @@ -0,0 +1,46 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ +MwCursor MwCursorHand = { + 13, 16, -12, -16, { + 3, /* ...........## */ + 15, /* .........#### */ + 60, /* .......####.. */ + 120, /* ......####... */ + 240, /* .....####.... */ + 504, /* ....######... */ + 1020, /* ...########.. */ + 3064, /* .#.#######... */ + 8188, /* ###########.. */ + 6140, /* #.#########.. */ + 504, /* ....######... */ + 496, /* ....#####.... */ + 4736, /* #..#.#....... */ + 6272, /* ##...#....... */ + 3328, /* .##.#........ */ + 1536 /* ..##......... */ + }}; +MwCursor MwCursorHandMask = { + 13, 16, -12, -16, { + 7, /* ..........### */ + 31, /* ........##### */ + 126, /* ......######. */ + 252, /* .....######.. */ + 504, /* ....######... */ + 1020, /* ...########.. */ + 4094, /* .###########. */ + 8190, /* ############. */ + 8190, /* ############. */ + 8190, /* ############. */ + 8188, /* ###########.. */ + 8184, /* ##########... */ + 8176, /* #########.... */ + 8128, /* #######...... */ + 8064, /* ######....... */ + 3840 /* .####........ */ + }}; diff --git a/src/widget/document.c b/src/widget/document.c index 2dc7ec96d..7611c62ac 100644 --- a/src/widget/document.c +++ b/src/widget/document.c @@ -3,7 +3,7 @@ #include "../../external/md4c.h" #include "../../external/stb_ds.h" -#define IsFontChange(x) ((x) == MwDOCUMENT_HEADER || (x) == MwDOCUMENT_BOLD || (x) == MwDOCUMENT_MONOSPACE || (x) == MwDOCUMENT_STRIKETHROUGH) +#define IsFontChange(x) ((x) == MwDOCUMENT_HEADER || (x) == MwDOCUMENT_BOLD || (x) == MwDOCUMENT_MONOSPACE) static void reset(MwWidget handle) { MwDocument d = handle->internal; @@ -13,6 +13,11 @@ static void reset(MwWidget handle) { if(d->layouts[i].text != NULL) free(d->layouts[i].text); } arrfree(d->layouts); + + for(i = 0; i < arrlen(d->clickables); i++) { + if(d->clickables[i].event != NULL) free(d->clickables[i].event); + } + arrfree(d->clickables); } static int wcreate(MwWidget handle) { @@ -52,11 +57,11 @@ static void draw(MwWidget handle) { MwRect r; int i; MwFLFont font = NULL; - MwPoint u_p, s_p; - int u = 0, s = 0; + MwPoint u_p, s_p, c_p; + int u = 0, s = 0, c = 0; - u_p.x = u_p.y = 0; - s_p.x = s_p.y = 0; + u_p.x = s_p.x = c_p.x = 0; + u_p.y = s_p.y = c_p.y = 0; r.x = 0; r.y = 0; @@ -75,9 +80,7 @@ static void draw(MwWidget handle) { p.x = l->x; p.y = l->y + MwTextHeight(handle, font, l->text) / 2; - MwDrawText(handle, font, &p, l->text, MwALIGNMENT_BEGINNING, text); - - if(u || s) { + if(u || s || c) { MwPoint line[2]; int j; @@ -85,31 +88,74 @@ static void draw(MwWidget handle) { u_p.x = 0; u_p.y = l->y; } + if(s_p.y != l->y) { + s_p.x = 0; + s_p.y = l->y; + } + if(c_p.y != l->y) { + c_p.x = 0; + c_p.y = l->y; + } - line[0] = u_p; - line[1] = u_p; + for(j = 0; j < 3; j++) { + if(j == 0) { + if(!u) continue; + line[0] = u_p; + line[1] = u_p; + } else if(j == 1) { + if(!s) continue; + line[0] = s_p; + line[1] = s_p; + } else if(j == 2) { + if(!c) continue; + line[0] = c_p; + line[1] = c_p; + } - line[1].x = p.x + MwTextWidth(handle, font, l->text); - u_p.x = line[1].x; + line[1].x = p.x + MwTextWidth(handle, font, l->text); - for(j = 0; j < 2; j++) { - line[0].y += MwTextHeight(handle, font, l->text) / 2; - line[1].y += MwTextHeight(handle, font, l->text) / 2; - if((j == 0 && s) || (j == 1 && u)) MwLLLine(handle->lowlevel, line, text); + if(j == 0) u_p.x = line[1].x; + if(j == 1) s_p.x = line[1].x; + if(j == 2) c_p.x = line[1].x; + + if(j == 2) { + MwRect c_r; + + c_r.x = line[0].x; + c_r.y = line[0].y; + c_r.width = line[1].x - line[0].x; + c_r.height = MwTextHeight(handle, font, l->text); + + MwDrawRect(handle, &c_r, text); + } + + if(j == 0 || j == 1) { + line[0].y += MwTextHeight(handle, font, l->text) / 2 * (2 - j); + line[1].y += MwTextHeight(handle, font, l->text) / 2 * (2 - j); + MwLLLine(handle->lowlevel, line, c ? base : text); + } } } + + handle->bgcolor = c ? text : NULL; + MwDrawText(handle, font, &p, l->text, MwALIGNMENT_BEGINNING, c ? base : text); + handle->bgcolor = NULL; break; } case MwDOCUMENT_UNDERLINE: case MwDOCUMENT_STRIKETHROUGH: + case MwDOCUMENT_CLICKABLE: { if(l->type == MwDOCUMENT_UNDERLINE) { u = l->integer; - } else { + } else if(l->type == MwDOCUMENT_STRIKETHROUGH) { s = l->integer; + } else { + c = l->integer; } - if(l->type == MwDOCUMENT_UNDERLINE ? u : s) { + if(l->type == MwDOCUMENT_UNDERLINE ? u : l->type == MwDOCUMENT_STRIKETHROUGH ? s + : c) { int j; for(j = i + 1; j < arrlen(d->layouts) && d->layouts[j].type != l->type; j++) { @@ -121,8 +167,10 @@ static void draw(MwWidget handle) { if(l->type == MwDOCUMENT_UNDERLINE) { u_p = p; - } else { + } else if(l->type == MwDOCUMENT_STRIKETHROUGH) { s_p = p; + } else { + c_p = p; } break; } @@ -141,6 +189,29 @@ static void draw(MwWidget handle) { MwLLFreeColor(base); } +static char* in_hitbox(MwWidget handle, MwPoint* p) { + int i; + MwDocument d = handle->internal; + + for(i = 0; i < arrlen(d->clickables); i++) { + MwRect hitbox = d->clickables[i].hitbox; + + if(hitbox.x <= p->x && p->x <= (hitbox.x + hitbox.width) && hitbox.y <= p->y && p->y <= (hitbox.y + hitbox.height)) { + return d->clickables[i].event; + } + } + + return NULL; +} + +static void click(MwWidget handle) { + char* event; + + if((event = in_hitbox(handle, &handle->mouse_point)) != NULL) { + MwDispatchUserHandler(handle, MwNdocumentActivateHandler, event); + } +} + static int enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) { MwDocument d = userdata; MwDocumentLayout l; @@ -251,6 +322,21 @@ static int enter_span(MD_SPANTYPE type, void* detail, void* userdata) { arrput(d->layouts, l); break; } + case MD_SPAN_A: + { + MD_ATTRIBUTE* href = &((MD_SPAN_A_DETAIL*)detail)->href; + char* text = malloc(href->size + 1); + + memcpy(text, href->text, href->size); + text[href->size] = 0; + + l.type = MwDOCUMENT_CLICKABLE; + l.text = text; + l.integer = 1; + + arrput(d->layouts, l); + break; + } default: break; } @@ -299,6 +385,14 @@ static int leave_span(MD_SPANTYPE type, void* detail, void* userdata) { arrput(d->layouts, l); break; } + case MD_SPAN_A: + { + l.type = MwDOCUMENT_CLICKABLE; + l.integer = 0; + + arrput(d->layouts, l); + break; + } default: break; } @@ -371,6 +465,15 @@ static int text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userd #define TOPFONT fontstack[arrlen(fontstack) - 1] #define POP arrdel(fontstack, arrlen(fontstack) - 1); +static void add_clickable(MwDocument d, char* c_title, MwRect* clickable) { + MwDocumentClickable c; + + c.hitbox = *clickable; + c.event = MwStringDuplicate(c_title); + + arrput(d->clickables, c); +} + static void layout(MwWidget handle) { MwDocument d = handle->internal; int w = MwGetInteger(handle, MwNwidth); @@ -378,9 +481,16 @@ static void layout(MwWidget handle) { int x = 0; int y = 0; MwFLFont* fontstack = NULL; + MwRect clickable; + char* c_title = NULL; arrput(fontstack, NULL); + for(i = 0; i < arrlen(d->clickables); i++) { + if(d->clickables[i].event != NULL) free(d->clickables[i].event); + } + arrfree(d->clickables); + for(i = 0; i < arrlen(d->layouts); i++) { MwDocumentLayout* l = &d->layouts[i]; @@ -399,7 +509,21 @@ static void layout(MwWidget handle) { l->x = x; l->y = y; + if(c_title != NULL) { + if(clickable.y < y) { + if(clickable.y >= 0 && clickable.width > 0) add_clickable(d, c_title, &clickable); + + clickable.x = x; + clickable.y = y; + } + } + x += t; + + if(c_title != NULL) { + clickable.width = x - clickable.x; + } + break; } case MwDOCUMENT_SPACE: @@ -411,6 +535,11 @@ static void layout(MwWidget handle) { { x = 0; y += MwTextHeight(handle, TOPFONT, "M"); + + if(c_title != NULL) { + add_clickable(d, c_title, &clickable); + } + break; } case MwDOCUMENT_BOLD: @@ -447,6 +576,22 @@ static void layout(MwWidget handle) { } break; } + case MwDOCUMENT_CLICKABLE: + { + if(l->integer) { + clickable.y = -100; + clickable.width = 0; + clickable.height = MwTextHeight(handle, TOPFONT, "M"); + + c_title = MwStringDuplicate(l->text); + } else { + if(clickable.y >= 0 && clickable.width > 0) add_clickable(d, c_title, &clickable); + + free(c_title); + c_title = NULL; + } + break; + } } l->font = TOPFONT; @@ -484,6 +629,21 @@ static void prop_change(MwWidget handle, const char* key) { } } +static void mouse_move(MwWidget handle) { + char* event = in_hitbox(handle, &handle->mouse_point); + MwDocument d = handle->internal; + + if(d->center_cursor && event == NULL) { + MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); + + d->center_cursor = 0; + } else if(!d->center_cursor && event != NULL) { + MwLLSetCursor(handle->lowlevel, &MwCursorCenter, &MwCursorCenterMask); + + d->center_cursor = 1; + } +} + static void resize(MwWidget handle) { layout(handle); } @@ -492,10 +652,10 @@ MwClassRec MwDocumentClassRec = { wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ - NULL, /* click */ + click, /* click */ NULL, /* parent_resize */ prop_change, /* prop_change */ - NULL, /* mouse_move */ + mouse_move, /* mouse_move */ NULL, /* mouse_up */ NULL, /* mouse_down */ NULL, /* key */ From ae2d859e63fbc3d1c357034d9236e8124b7b29ec Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 02:06:39 +0900 Subject: [PATCH 85/90] move --- src/widget/document.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/widget/document.c b/src/widget/document.c index 7611c62ac..55dd1f0c1 100644 --- a/src/widget/document.c +++ b/src/widget/document.c @@ -474,6 +474,21 @@ static void add_clickable(MwDocument d, char* c_title, MwRect* clickable) { arrput(d->clickables, c); } +static void mouse_move(MwWidget handle) { + char* event = in_hitbox(handle, &handle->mouse_point); + MwDocument d = handle->internal; + + if(d->center_cursor && event == NULL) { + MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); + + d->center_cursor = 0; + } else if(!d->center_cursor && event != NULL) { + MwLLSetCursor(handle->lowlevel, &MwCursorCenter, &MwCursorCenterMask); + + d->center_cursor = 1; + } +} + static void layout(MwWidget handle) { MwDocument d = handle->internal; int w = MwGetInteger(handle, MwNwidth); @@ -602,6 +617,7 @@ static void layout(MwWidget handle) { arrfree(fontstack); + mouse_move(handle); MwForceRender(handle); } @@ -629,21 +645,6 @@ static void prop_change(MwWidget handle, const char* key) { } } -static void mouse_move(MwWidget handle) { - char* event = in_hitbox(handle, &handle->mouse_point); - MwDocument d = handle->internal; - - if(d->center_cursor && event == NULL) { - MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); - - d->center_cursor = 0; - } else if(!d->center_cursor && event != NULL) { - MwLLSetCursor(handle->lowlevel, &MwCursorCenter, &MwCursorCenterMask); - - d->center_cursor = 1; - } -} - static void resize(MwWidget handle) { layout(handle); } From d0c79575059d23cb9966a1b742fcd10b3a2e173f Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 02:07:06 +0900 Subject: [PATCH 86/90] update --- NTMakefile | 6 ++++-- WatMakefile | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index 213800d0c..b07f798ad 100644 --- a/NTMakefile +++ b/NTMakefile @@ -37,8 +37,10 @@ clean: del /f /q src\color.obj del /f /q src\core.obj del /f /q src\cursor\arrow.obj + del /f /q src\cursor\center.obj del /f /q src\cursor\cross.obj del /f /q src\cursor\default.obj + del /f /q src\cursor\hand.obj del /f /q src\cursor\hidden.obj del /f /q src\cursor\text.obj del /f /q src\default.obj @@ -340,8 +342,8 @@ examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c -src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib +src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\center.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hand.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\md4c.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\center.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hand.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\chart.obj src\widget\checkbox.obj src\widget\clock.obj src\widget\combobox.obj src\widget\document.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib ole32.lib uuid.lib user32.lib advapi32.lib .c.obj: diff --git a/WatMakefile b/WatMakefile index 0b846d13a..fd9807901 100644 --- a/WatMakefile +++ b/WatMakefile @@ -36,8 +36,10 @@ clean: .SYMBOLIC %erase src/color.obj %erase src/core.obj %erase src/cursor/arrow.obj + %erase src/cursor/center.obj %erase src/cursor/cross.obj %erase src/cursor/default.obj + %erase src/cursor/hand.obj %erase src/cursor/hidden.obj %erase src/cursor/text.obj %erase src/default.obj @@ -339,8 +341,8 @@ examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c -src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/md4c.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/chart.obj src/widget/checkbox.obj src/widget/clock.obj src/widget/combobox.obj src/widget/document.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/md4c.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/chart.obj file src/widget/checkbox.obj file src/widget/clock.obj file src/widget/combobox.obj file src/widget/document.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib +src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/md4c.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/center.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hand.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/chart.obj src/widget/checkbox.obj src/widget/clock.obj src/widget/combobox.obj src/widget/document.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/md4c.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/center.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hand.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/chart.obj file src/widget/checkbox.obj file src/widget/clock.obj file src/widget/combobox.obj file src/widget/document.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library ole32.lib library uuid.lib library user32.lib library advapi32.lib @@ -398,10 +400,14 @@ src/core.obj: src/core.c $(CC) $(MW_CFLAGS) -fo=$@ src/core.c src/cursor/arrow.obj: src/cursor/arrow.c $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/arrow.c +src/cursor/center.obj: src/cursor/center.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/center.c src/cursor/cross.obj: src/cursor/cross.c $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/cross.c src/cursor/default.obj: src/cursor/default.c $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/default.c +src/cursor/hand.obj: src/cursor/hand.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/hand.c src/cursor/hidden.obj: src/cursor/hidden.c $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/hidden.c src/cursor/text.obj: src/cursor/text.c From de5e26b1282971b1631a7a6f3722056a9a48a4cf Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 03:21:27 +0900 Subject: [PATCH 87/90] fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 534614f04..07f7bb9cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,7 +497,7 @@ configure_file( install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc - DESTINATION $ENV{MINGW_PREFIX}/${CMAKE_INSTALL_DATADIR}/pkgconfig + DESTINATION $ENV{MINGW_PREFIX}/${CMAKE_INSTALL_FULL_DATADIR}/pkgconfig ) if(MW_INSTALL_HEADERS) From 74054fba4b1590758d8afde29d0beff9742fd1e3 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 03:36:00 +0900 Subject: [PATCH 88/90] fix --- src/draw.c | 3 +++ src/widget/document.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/draw.c b/src/draw.c index eb15c76ba..be82fb4fd 100644 --- a/src/draw.c +++ b/src/draw.c @@ -138,6 +138,9 @@ void MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color) { MwFixRect(&r); + r.width--; + r.height--; + p[0].x = r.x; p[0].y = r.y; diff --git a/src/widget/document.c b/src/widget/document.c index 55dd1f0c1..1f48cec66 100644 --- a/src/widget/document.c +++ b/src/widget/document.c @@ -514,7 +514,7 @@ static void layout(MwWidget handle) { { int t = MwTextWidth(handle, TOPFONT, l->text); - if(x > 0) x += MwTextWidth(handle, TOPFONT, " "); + if(x > 0) x += MwTextWidth(handle, TOPFONT, "."); if((x + t) >= w) { x = 0; @@ -543,7 +543,7 @@ static void layout(MwWidget handle) { } case MwDOCUMENT_SPACE: { - x += MwTextWidth(handle, TOPFONT, " "); + x += MwTextWidth(handle, TOPFONT, "."); break; } case MwDOCUMENT_NEWLINE: From 7398604b7ca6bb56d4129b02448e40a488182d02 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 17 Sep 2026 03:38:11 +0900 Subject: [PATCH 89/90] unfix --- src/draw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/draw.c b/src/draw.c index be82fb4fd..eb15c76ba 100644 --- a/src/draw.c +++ b/src/draw.c @@ -138,9 +138,6 @@ void MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color) { MwFixRect(&r); - r.width--; - r.height--; - p[0].x = r.x; p[0].y = r.y; From f9bbba8af9506952ed9317e1bdfea95babf0864a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 16 Sep 2026 12:48:51 -0700 Subject: [PATCH 90/90] minor improvements on wayland --- .gitignore | 2 ++ include/Mw/LowLevel/Wayland.h | 13 ------------- src/backend/wayland/buffer.c | 13 +++++++++++++ src/backend/wayland/wayland.c | 33 +++++++-------------------------- 4 files changed, 22 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 58b172ada..3faccd358 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ compile_flags.txt *.finf *.gdb +flamegraph.svg +perf.* diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7a2c25c23..3b7918426 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -426,13 +426,9 @@ struct _MwLLWayland { MwBool force_render; MwBool did_event_loop_early; - MwBool do_cascading_draw; - int cascading_child_num; MwBool dispatching_resize; - MwBool is_toplevel_menu; - struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; @@ -440,15 +436,6 @@ struct _MwLLWayland { MwLLPixmap icon_pixmap; - pthread_mutex_t eventsMutex; - - int cancelEvent; - int numCallbacksRunning; - - uint32_t last_time; - - MwBool moving; - MwI64 keyboard_rate; MwI32 keyboard_delay; int last_pressed_key; diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c index cb1eca5f0..48071ec95 100644 --- a/src/backend/wayland/buffer.c +++ b/src/backend/wayland/buffer.c @@ -113,3 +113,16 @@ void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer) { close(buffer->fd_back); buffer->setup = MwFALSE; } + +void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { + if(self->wayland.configured) { + memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); + if(buffer->surface) { + // Yes this is needed every time, it's how we fix weston. + if(self->wayland.configured) + wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); + + wl_surface_commit(buffer->surface); + } + } +} diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index bd17f848c..9d8d634ab 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -218,19 +218,6 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } -void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { - if(self->wayland.configured) { - memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); - if(buffer->surface) { - // Yes this is needed every time, it's how we fix weston. - if(self->wayland.configured) - wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - - wl_surface_commit(buffer->surface); - } - } -} - /* Toplevel setup function */ static void setup_toplevel(MwLL r, int x, int y) { char* mw_force_csd = getenv("MW_FORCE_CSD"); @@ -986,7 +973,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); - pthread_mutex_init(&r->wayland.eventsMutex, NULL); + // pthread_mutex_init(&r->wayland.eventsMutex, NULL); MwLLCreateCommon(r); r->wayland.is_toplevel = parent == NULL; @@ -1015,8 +1002,6 @@ static void MwLLDestroyImpl(MwLL handle) { MwLLWaylandFlush(handle); - handle->wayland.cancelEvent = MwTRUE; - MwLLDestroyCommon(handle); tv.tv_sec = 0; @@ -1050,7 +1035,7 @@ static void MwLLDestroyImpl(MwLL handle) { printf("widget invalid\n"); } - pthread_mutex_destroy(&handle->wayland.eventsMutex); + // pthread_mutex_destroy(&handle->wayland.eventsMutex); free(handle); } @@ -1321,10 +1306,6 @@ static void MwLLEndDrawImpl(MwLL handle) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - - if(handle->wayland.type != MwLL_WAYLAND_SUBLEVEL) { - handle->wayland.do_cascading_draw = 1; - } } } @@ -1382,16 +1363,16 @@ static int MwLLPendingImpl(MwLL handle) { handle->wayland.resizing = 0; + if(handle->wayland.type != MwLL_WAYLAND_SUBLEVEL) { + draw_children(handle); + frontbuffer_draw(handle); + } + if(handle->wayland.setting_wh) { actually_set_wh(handle); handle->wayland.setting_wh = 0; } - if(handle->wayland.do_cascading_draw) { - draw_children(handle); - frontbuffer_draw(handle); - } - handle->wayland.end_time = MwTimeGetTick(); if(handle->wayland.holding_key) {