From 336019b94d3007068377dd73014299dfb7111a1f Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 9 Aug 2026 14:06:19 -0700 Subject: [PATCH 01/95] experimental changes to get it compiling on win16 --- .gitignore | 3 +- WatMakefile | 27 +- examples/basic/colorpicker.c | 17 +- external/stb_ds.h | 2445 ++++--- external/stb_image.h | 11649 +++++++++++++++--------------- include/Mw/BaseTypes.h | 14 + include/Mw/Constants.h | 4 + include/Mw/Dialog/ColorPicker.h | 4 + include/Mw/Draw.h | 2 + include/Mw/LowLevel.h | 2 + include/Mw/LowLevel/GDI.h | 1 + include/Mw/MachDep.h | 18 +- include/Mw/Milsko.h | 4 + include/Mw/Resource/Cursor.h | 3 + include/Mw/Widget/OpenGL.h | 2 +- src/abstract/directory.c | 50 +- src/abstract/dynamic.c | 2 +- src/abstract/time.c | 2 +- src/backend/gdi.c | 183 +- src/color.c | 1299 ++-- src/core.c | 14 +- src/dialog/colorpicker.c | 4 + src/dialog/filechooser.c | 33 +- src/dialog/messagebox.c | 9 +- src/draw.c | 20 +- src/text/text.c | 6 +- src/widget/combobox.c | 6 + src/widget/entry.c | 2 + src/widget/label.c | 9 + src/widget/numberentry.c | 2 + 30 files changed, 7988 insertions(+), 7848 deletions(-) diff --git a/.gitignore b/.gitignore index 4e56495..0b4efb8 100644 --- a/.gitignore +++ b/.gitignore @@ -22,10 +22,11 @@ compile_flags.txt /vms /BorMakefile +*.err + *.pef *.dsk *.bin *.rsrc *.finf *.gdb - diff --git a/WatMakefile b/WatMakefile index bd32d9b..eca4ed8 100644 --- a/WatMakefile +++ b/WatMakefile @@ -1,10 +1,22 @@ +!ifndef %mw16 CC = wcc386 -bt=nt -q +!else +CC = wcc -bt=windows -q +!endif + LD = wlink option quiet -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD -MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include +!ifndef %mw16 +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dMW_OPENGL +MW_LDFLAGS = system nt_dll EXE_LDFLAGS = system nt +!else +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE -os -oh +MW_LDFLAGS = system windows_dll +EXE_LDFLAGS = system windows +!endif + 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 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 @@ -280,6 +292,7 @@ examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll examples/basic/viewport.obj: examples/basic/viewport.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c +!ifndef %mw16 examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib @@ -315,11 +328,15 @@ examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c +!endif - +!ifndef %mw16 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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 user32.lib library advapi32.lib - +!else +src/Mw.dll: external/stb_ds.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/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/lowlevel.obj src/string.obj src/text/text.obj src/text/font/font.obj src/text/font/boldfont.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/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/stb_ds.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/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/lowlevel.obj file src/string.obj file src/text/text.obj file src/text/font/font.obj file src/text/font/boldfont.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/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 clibs.lib +!endif external/libz/src/adler32.obj: external/libz/src/adler32.c @@ -474,8 +491,10 @@ src/widget/menu.obj: src/widget/menu.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c src/widget/numberentry.obj: src/widget/numberentry.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c +!ifndef %mw16 src/widget/opengl.obj: src/widget/opengl.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c +!endif src/widget/progressbar.obj: src/widget/progressbar.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c src/widget/radiobox.obj: src/widget/radiobox.c diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index dbce7fe..65f507e 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -2,8 +2,16 @@ MwWidget fpicker; MwWidget window; -MwWidget button; +/* This example does nothing on Win16 because we don't support the color picker on it (yet?) */ +#ifdef __WINDOWS__ +MwWidget missing_text; +#else +MwWidget button; +#endif + +/* don't bother with color picker on win16 */ +#ifndef __WINDOWS__ void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { char hexColor[8]; MwRGB* rgb = call_data; @@ -29,6 +37,7 @@ void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); } +#endif int main() { MwLibraryInit(); @@ -37,12 +46,18 @@ int main() { MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); +#ifndef __WINDOWS__ button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); +#else + missing_text = MwVaCreateWidget(MwLabelClass, NULL, window, 160, 180, 320, 120, + MwNtext, "Color picker doesn't yet exist on 16-bit Windows", + NULL); +#endif MwLoop(window); } diff --git a/external/stb_ds.h b/external/stb_ds.h index e84c82d..41c1343 100644 --- a/external/stb_ds.h +++ b/external/stb_ds.h @@ -71,80 +71,80 @@ DOCUMENTATION Non-function interface: Declare an empty dynamic array of type T - T* foo = NULL; + T* foo = NULL; Access the i'th item of a dynamic array 'foo' of type T, T* foo: - foo[i] + foo[i] Functions (actually macros) arrfree: - void arrfree(T*); - Frees the array. + void arrfree(T*); + Frees the array. arrlen: - ptrdiff_t arrlen(T*); - Returns the number of elements in the array. + ptrdiff_t arrlen(T*); + Returns the number of elements in the array. arrlenu: - size_t arrlenu(T*); - Returns the number of elements in the array as an unsigned type. + size_t arrlenu(T*); + Returns the number of elements in the array as an unsigned type. arrpop: - T arrpop(T* a) - Removes the final element of the array and returns it. + T arrpop(T* a) + Removes the final element of the array and returns it. arrput: - T arrput(T* a, T b); - Appends the item b to the end of array a. Returns b. + T arrput(T* a, T b); + Appends the item b to the end of array a. Returns b. arrins: - T arrins(T* a, int p, T b); - Inserts the item b into the middle of array a, into a[p], - moving the rest of the array over. Returns b. + T arrins(T* a, int p, T b); + Inserts the item b into the middle of array a, into a[p], + moving the rest of the array over. Returns b. arrinsn: - void arrinsn(T* a, int p, int n); - Inserts n uninitialized items into array a starting at a[p], - moving the rest of the array over. + void arrinsn(T* a, int p, int n); + Inserts n uninitialized items into array a starting at a[p], + moving the rest of the array over. arraddnptr: - T* arraddnptr(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns a pointer to the first uninitialized item added. + T* arraddnptr(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns a pointer to the first uninitialized item added. arraddnindex: - size_t arraddnindex(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns the index of the first uninitialized item added. + size_t arraddnindex(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns the index of the first uninitialized item added. arrdel: - void arrdel(T* a, int p); - Deletes the element at a[p], moving the rest of the array over. + void arrdel(T* a, int p); + Deletes the element at a[p], moving the rest of the array over. arrdeln: - void arrdeln(T* a, int p, int n); - Deletes n elements starting at a[p], moving the rest of the array over. + void arrdeln(T* a, int p, int n); + Deletes n elements starting at a[p], moving the rest of the array over. arrdelswap: - void arrdelswap(T* a, int p); - Deletes the element at a[p], replacing it with the element from - the end of the array. O(1) performance. + void arrdelswap(T* a, int p); + Deletes the element at a[p], replacing it with the element from + the end of the array. O(1) performance. arrsetlen: - void arrsetlen(T* a, int n); - Changes the length of the array to n. Allocates uninitialized - slots at the end if necessary. + void arrsetlen(T* a, int n); + Changes the length of the array to n. Allocates uninitialized + slots at the end if necessary. arrsetcap: - size_t arrsetcap(T* a, int n); - Sets the length of allocated storage to at least n. It will not - change the length of the array. + size_t arrsetcap(T* a, int n); + Sets the length of allocated storage to at least n. It will not + change the length of the array. arrcap: - size_t arrcap(T* a); - Returns the number of total elements the array can contain without - needing to be reallocated. + size_t arrcap(T* a); + Returns the number of total elements the array can contain without + needing to be reallocated. Hash maps & String hash maps @@ -155,140 +155,140 @@ DOCUMENTATION Special interface: stbds_rand_seed: - void stbds_rand_seed(size_t seed); - For security against adversarially chosen data, you should seed the - library with a strong random number. Or at least seed it with time(). + void stbds_rand_seed(size_t seed); + For security against adversarially chosen data, you should seed the + library with a strong random number. Or at least seed it with time(). stbds_hash_string: - size_t stbds_hash_string(char *str, size_t seed); - Returns a hash value for a string. + size_t stbds_hash_string(char *str, size_t seed); + Returns a hash value for a string. stbds_hash_bytes: - size_t stbds_hash_bytes(void *p, size_t len, size_t seed); - These functions hash an arbitrary number of bytes. The function - uses a custom hash for 4- and 8-byte data, and a weakened version - of SipHash for everything else. On 64-bit platforms you can get - specification-compliant SipHash-2-4 on all data by defining - STBDS_SIPHASH_2_4, at a significant cost in speed. + size_t stbds_hash_bytes(void *p, size_t len, size_t seed); + These functions hash an arbitrary number of bytes. The function + uses a custom hash for 4- and 8-byte data, and a weakened version + of SipHash for everything else. On 64-bit platforms you can get + specification-compliant SipHash-2-4 on all data by defining + STBDS_SIPHASH_2_4, at a significant cost in speed. Non-function interface: Declare an empty hash map of type T - T* foo = NULL; + T* foo = NULL; Access the i'th entry in a hash table T* foo: - foo[i] + foo[i] Function interface (actually macros): hmfree shfree - void hmfree(T*); - void shfree(T*); - Frees the hashmap and sets the pointer to NULL. + void hmfree(T*); + void shfree(T*); + Frees the hashmap and sets the pointer to NULL. hmlen shlen - ptrdiff_t hmlen(T*) - ptrdiff_t shlen(T*) - Returns the number of elements in the hashmap. + ptrdiff_t hmlen(T*) + ptrdiff_t shlen(T*) + Returns the number of elements in the hashmap. hmlenu shlenu - size_t hmlenu(T*) - size_t shlenu(T*) - Returns the number of elements in the hashmap. + size_t hmlenu(T*) + size_t shlenu(T*) + Returns the number of elements in the hashmap. hmgeti shgeti hmgeti_ts - ptrdiff_t hmgeti(T*, TK key) - ptrdiff_t shgeti(T*, char* key) - ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) - Returns the index in the hashmap which has the key 'key', or -1 - if the key is not present. + ptrdiff_t hmgeti(T*, TK key) + ptrdiff_t shgeti(T*, char* key) + ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) + Returns the index in the hashmap which has the key 'key', or -1 + if the key is not present. hmget hmget_ts shget - TV hmget(T*, TK key) - TV shget(T*, char* key) - TV hmget_ts(T*, TK key, ptrdiff_t tempvar) - Returns the value corresponding to 'key' in the hashmap. - The structure must have a 'value' field + TV hmget(T*, TK key) + TV shget(T*, char* key) + TV hmget_ts(T*, TK key, ptrdiff_t tempvar) + Returns the value corresponding to 'key' in the hashmap. + The structure must have a 'value' field hmgets shgets - T hmgets(T*, TK key) - T shgets(T*, char* key) - Returns the structure corresponding to 'key' in the hashmap. + T hmgets(T*, TK key) + T shgets(T*, char* key) + Returns the structure corresponding to 'key' in the hashmap. hmgetp shgetp hmgetp_ts hmgetp_null shgetp_null - T* hmgetp(T*, TK key) - T* shgetp(T*, char* key) - T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) - T* hmgetp_null(T*, TK key) - T* shgetp_null(T*, char *key) - Returns a pointer to the structure corresponding to 'key' in - the hashmap. Functions ending in "_null" return NULL if the key - is not present in the hashmap; the others return a pointer to a - structure holding the default value (but not the searched-for key). + T* hmgetp(T*, TK key) + T* shgetp(T*, char* key) + T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) + T* hmgetp_null(T*, TK key) + T* shgetp_null(T*, char *key) + Returns a pointer to the structure corresponding to 'key' in + the hashmap. Functions ending in "_null" return NULL if the key + is not present in the hashmap; the others return a pointer to a + structure holding the default value (but not the searched-for key). hmdefault shdefault - TV hmdefault(T*, TV value) - TV shdefault(T*, TV value) - Sets the default value for the hashmap, the value which will be - returned by hmget/shget if the key is not present. + TV hmdefault(T*, TV value) + TV shdefault(T*, TV value) + Sets the default value for the hashmap, the value which will be + returned by hmget/shget if the key is not present. hmdefaults shdefaults - TV hmdefaults(T*, T item) - TV shdefaults(T*, T item) - Sets the default struct for the hashmap, the contents which will be - returned by hmgets/shgets if the key is not present. + TV hmdefaults(T*, T item) + TV shdefaults(T*, T item) + Sets the default struct for the hashmap, the contents which will be + returned by hmgets/shgets if the key is not present. hmput shput - TV hmput(T*, TK key, TV value) - TV shput(T*, char* key, TV value) - Inserts a pair into the hashmap. If the key is already - present in the hashmap, updates its value. + TV hmput(T*, TK key, TV value) + TV shput(T*, char* key, TV value) + Inserts a pair into the hashmap. If the key is already + present in the hashmap, updates its value. hmputs shputs - T hmputs(T*, T item) - T shputs(T*, T item) - Inserts a struct with T.key into the hashmap. If the struct is already - present in the hashmap, updates it. + T hmputs(T*, T item) + T shputs(T*, T item) + Inserts a struct with T.key into the hashmap. If the struct is already + present in the hashmap, updates it. hmdel shdel - int hmdel(T*, TK key) - int shdel(T*, char* key) - If 'key' is in the hashmap, deletes its entry and returns 1. - Otherwise returns 0. + int hmdel(T*, TK key) + int shdel(T*, char* key) + If 'key' is in the hashmap, deletes its entry and returns 1. + Otherwise returns 0. Function interface (actually macros) for strings only: sh_new_strdup - void sh_new_strdup(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate and free - each string key using realloc/free + void sh_new_strdup(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate and free + each string key using realloc/free sh_new_arena - void sh_new_arena(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate each string - key to a string arena. Every string key ever used by this - hash table remains in the arena until the arena is freed. - Additionally, any key which is deleted and reinserted will - be allocated multiple times in the string arena. + void sh_new_arena(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate each string + key to a string arena. Every string key ever used by this + hash table remains in the arena until the arena is freed. + Additionally, any key which is deleted and reinserted will + be allocated multiple times in the string arena. NOTES @@ -303,17 +303,17 @@ NOTES * The following are the only functions that are thread-safe on a single data structure, i.e. can be run in multiple threads simultaneously on the same data structure - hmlen shlen - hmlenu shlenu - hmget_ts shget_ts - hmgeti_ts shgeti_ts - hmgets_ts shgets_ts + hmlen shlen + hmlenu shlenu + hmget_ts shget_ts + hmgeti_ts shgeti_ts + hmgets_ts shgets_ts * You iterate over the contents of a dynamic array and a hashmap in exactly the same way, using arrlen/hmlen/shlen: for (i=0; i < arrlen(foo); ++i) - ... foo[i] ... + ... foo[i] ... * All operations except arrins/arrdel are O(1) amortized, but individual operations can be slow, so these data structures may not be suitable @@ -395,61 +395,61 @@ CREDITS #include #ifndef STBDS_NO_SHORT_NAMES -#define arrlen stbds_arrlen -#define arrlenu stbds_arrlenu -#define arrput stbds_arrput -#define arrpush stbds_arrput -#define arrpop stbds_arrpop -#define arrfree stbds_arrfree -#define arraddn stbds_arraddn // deprecated, use one of the following instead: -#define arraddnptr stbds_arraddnptr +#define arrlen stbds_arrlen +#define arrlenu stbds_arrlenu +#define arrput stbds_arrput +#define arrpush stbds_arrput +#define arrpop stbds_arrpop +#define arrfree stbds_arrfree +#define arraddn stbds_arraddn // deprecated, use one of the following instead: +#define arraddnptr stbds_arraddnptr #define arraddnindex stbds_arraddnindex -#define arrsetlen stbds_arrsetlen -#define arrlast stbds_arrlast -#define arrins stbds_arrins -#define arrinsn stbds_arrinsn -#define arrdel stbds_arrdel -#define arrdeln stbds_arrdeln -#define arrdelswap stbds_arrdelswap -#define arrcap stbds_arrcap -#define arrsetcap stbds_arrsetcap +#define arrsetlen stbds_arrsetlen +#define arrlast stbds_arrlast +#define arrins stbds_arrins +#define arrinsn stbds_arrinsn +#define arrdel stbds_arrdel +#define arrdeln stbds_arrdeln +#define arrdelswap stbds_arrdelswap +#define arrcap stbds_arrcap +#define arrsetcap stbds_arrsetcap -#define hmput stbds_hmput -#define hmputs stbds_hmputs -#define hmget stbds_hmget -#define hmget_ts stbds_hmget_ts -#define hmgets stbds_hmgets -#define hmgetp stbds_hmgetp -#define hmgetp_ts stbds_hmgetp_ts +#define hmput stbds_hmput +#define hmputs stbds_hmputs +#define hmget stbds_hmget +#define hmget_ts stbds_hmget_ts +#define hmgets stbds_hmgets +#define hmgetp stbds_hmgetp +#define hmgetp_ts stbds_hmgetp_ts #define hmgetp_null stbds_hmgetp_null -#define hmgeti stbds_hmgeti -#define hmgeti_ts stbds_hmgeti_ts -#define hmdel stbds_hmdel -#define hmlen stbds_hmlen -#define hmlenu stbds_hmlenu -#define hmfree stbds_hmfree -#define hmdefault stbds_hmdefault -#define hmdefaults stbds_hmdefaults +#define hmgeti stbds_hmgeti +#define hmgeti_ts stbds_hmgeti_ts +#define hmdel stbds_hmdel +#define hmlen stbds_hmlen +#define hmlenu stbds_hmlenu +#define hmfree stbds_hmfree +#define hmdefault stbds_hmdefault +#define hmdefaults stbds_hmdefaults -#define shput stbds_shput -#define shputi stbds_shputi -#define shputs stbds_shputs -#define shget stbds_shget -#define shgeti stbds_shgeti -#define shgets stbds_shgets -#define shgetp stbds_shgetp +#define shput stbds_shput +#define shputi stbds_shputi +#define shputs stbds_shputs +#define shget stbds_shget +#define shgeti stbds_shgeti +#define shgets stbds_shgets +#define shgetp stbds_shgetp #define shgetp_null stbds_shgetp_null -#define shdel stbds_shdel -#define shlen stbds_shlen -#define shlenu stbds_shlenu -#define shfree stbds_shfree -#define shdefault stbds_shdefault -#define shdefaults stbds_shdefaults -#define sh_new_arena stbds_sh_new_arena +#define shdel stbds_shdel +#define shlen stbds_shlen +#define shlenu stbds_shlenu +#define shfree stbds_shfree +#define shdefault stbds_shdefault +#define shdefaults stbds_shdefaults +#define sh_new_arena stbds_sh_new_arena #define sh_new_strdup stbds_sh_new_strdup -#define stralloc stbds_stralloc -#define strreset stbds_strreset +#define stralloc stbds_stralloc +#define strreset stbds_strreset #endif #if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) @@ -457,14 +457,14 @@ CREDITS #endif #if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) #include -#define STBDS_REALLOC(c,p,s) realloc(p,s) -#define STBDS_FREE(c,p) free(p) +#define STBDS_REALLOC(c, p, s) realloc(p, s) +#define STBDS_FREE(c, p) free(p) #endif #ifdef _MSC_VER -#define STBDS_NOTUSED(v) (void)(v) +#define STBDS_NOTUSED(v) (void)(v) #else -#define STBDS_NOTUSED(v) (void)sizeof(v) +#define STBDS_NOTUSED(v) (void)sizeof(v) #endif #ifdef __cplusplus @@ -475,13 +475,13 @@ extern "C" { extern void stbds_rand_seed(size_t seed); // these are the hash functions used internally if you want to test them or use them for other purposes -extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); -extern size_t stbds_hash_string(char *str, size_t seed); +extern size_t stbds_hash_bytes(void* p, size_t len, size_t seed); +extern size_t stbds_hash_string(char* str, size_t seed); // this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. typedef struct stbds_string_arena stbds_string_arena; -extern char * stbds_stralloc(stbds_string_arena *a, char *str); -extern void stbds_strreset(stbds_string_arena *a); +extern char* stbds_stralloc(stbds_string_arena* a, char* str); +extern void stbds_strreset(stbds_string_arena* a); // have to #define STBDS_UNIT_TESTS to call this extern void stbds_unit_tests(void); @@ -491,15 +491,15 @@ extern void stbds_unit_tests(void); // Everything below here is implementation details // -extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); -extern void stbds_arrfreef(void *a); -extern void stbds_hmfree_func(void *p, size_t elemsize); -extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); -extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode); -extern void * stbds_hmput_default(void *a, size_t elemsize); -extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); -extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); -extern void * stbds_shmode_func(size_t elemsize, int mode); +extern void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap); +extern void stbds_arrfreef(void* a); +extern void stbds_hmfree_func(void* p, size_t elemsize); +extern void* stbds_hmget_key(void* a, size_t elemsize, void* key, size_t keysize, int mode); +extern void* stbds_hmget_key_ts(void* a, size_t elemsize, void* key, size_t keysize, ptrdiff_t* temp, int mode); +extern void* stbds_hmput_default(void* a, size_t elemsize); +extern void* stbds_hmput_key(void* a, size_t elemsize, void* key, size_t keysize, int mode); +extern void* stbds_hmdel_key(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode); +extern void* stbds_shmode_func(size_t elemsize, int mode); #ifdef __cplusplus } @@ -508,7 +508,7 @@ extern void * stbds_shmode_func(size_t elemsize, int mode); #if defined(__GNUC__) || defined(__clang__) #define STBDS_HAS_TYPEOF #ifdef __cplusplus -//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang +// #define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang #endif #endif @@ -520,210 +520,214 @@ extern void * stbds_shmode_func(size_t elemsize, int mode); // this macro takes the address of the argument, but on gcc/clang can accept rvalues #if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) - #if __clang__ - #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value - #else - #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value - #endif +#if __clang__ +#define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value #else -#define STBDS_ADDRESSOF(typevar, value) &(value) +#define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value +#endif +#else +#define STBDS_ADDRESSOF(typevar, value) &(value) #endif -#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) +#define STBDS_OFFSETOF(var, field) ((char*)&(var)->field - (char*)(var)) -#define stbds_header(t) ((stbds_array_header *) (t) - 1) -#define stbds_temp(t) stbds_header(t)->temp -#define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) +#define stbds_header(t) ((stbds_array_header*)(t) - 1) +#define stbds_temp(t) stbds_header(t)->temp +#define stbds_temp_key(t) (*(char**)stbds_header(t)->hash_table) -#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) -#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0) -#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) -#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) -#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) -#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) -#define stbds_arrpush stbds_arrput // synonym -#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) -#define stbds_arraddn(a,n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: -#define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) -#define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) -#define stbds_arraddnoff stbds_arraddnindex -#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) -#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) -#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) -#define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) -#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) -#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) -#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) +#define stbds_arrsetcap(a, n) (stbds_arrgrow(a, 0, n)) +#define stbds_arrsetlen(a, n) ((stbds_arrcap(a) < (size_t)(n) ? stbds_arrsetcap((a), (size_t)(n)), 0 : 0), (a) ? stbds_header(a)->length = (size_t)(n) : 0) +#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) +#define stbds_arrlen(a) ((a) ? (ptrdiff_t)stbds_header(a)->length : 0) +#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) +#define stbds_arrput(a, v) (stbds_arrmaybegrow(a, 1), (a)[stbds_header(a)->length++] = (v)) +#define stbds_arrpush stbds_arrput // synonym +#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) +#define stbds_arraddn(a, n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: +#define stbds_arraddnptr(a, n) (stbds_arrmaybegrow(a, n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length - (n)]) : (a)) +#define stbds_arraddnindex(a, n) (stbds_arrmaybegrow(a, n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length - (n)) : stbds_arrlen(a)) +#define stbds_arraddnoff stbds_arraddnindex +#define stbds_arrlast(a) ((a)[stbds_header(a)->length - 1]) +#define stbds_arrfree(a) ((void)((a) ? STBDS_FREE(NULL, stbds_header(a)) : (void)0), (a) = NULL) +#define stbds_arrdel(a, i) stbds_arrdeln(a, i, 1) +#define stbds_arrdeln(a, i, n) (memmove(&(a)[i], &(a)[(i) + (n)], sizeof *(a) * (stbds_header(a)->length - (n) - (i))), stbds_header(a)->length -= (n)) +#define stbds_arrdelswap(a, i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) +#define stbds_arrinsn(a, i, n) (stbds_arraddn((a), (n)), memmove(&(a)[(i) + (n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length - (n) - (i)))) +#define stbds_arrins(a, i, v) (stbds_arrinsn((a), (i), 1), (a)[i] = (v)) -#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ - ? (stbds_arrgrow(a,n,0),0) : 0) +#define stbds_arrmaybegrow(a, n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ + ? (stbds_arrgrow(a, n, 0), 0) \ + : 0) -#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) +#define stbds_arrgrow(a, b, c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) #define stbds_hmput(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ - (t)[stbds_temp((t)-1)].key = (k), \ - (t)[stbds_temp((t)-1)].value = (v)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)STBDS_ADDRESSOF((t)->key, (k)), sizeof(t)->key, 0), \ + (t)[stbds_temp((t) - 1)].key = (k), \ + (t)[stbds_temp((t) - 1)].value = (v)) #define stbds_hmputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ - (t)[stbds_temp((t)-1)] = (s)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof(s).key, STBDS_HM_BINARY), \ + (t)[stbds_temp((t) - 1)] = (s)) -#define stbds_hmgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ - stbds_temp((t)-1)) +#define stbds_hmgeti(t, k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*)STBDS_ADDRESSOF((t)->key, (k)), sizeof(t)->key, STBDS_HM_BINARY), \ + stbds_temp((t) - 1)) -#define stbds_hmgeti_ts(t,k,temp) \ - ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \ - (temp)) +#define stbds_hmgeti_ts(t, k, temp) \ + ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*)STBDS_ADDRESSOF((t)->key, (k)), sizeof(t)->key, &(temp), STBDS_HM_BINARY), \ + (temp)) #define stbds_hmgetp(t, k) \ - ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) + ((void)stbds_hmgeti(t, k), &(t)[stbds_temp((t) - 1)]) #define stbds_hmgetp_ts(t, k, temp) \ - ((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp]) + ((void)stbds_hmgeti_ts(t, k, temp), &(t)[temp]) -#define stbds_hmdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0) +#define stbds_hmdel(t, k) \ + (((t) = stbds_hmdel_key_wrapper((t), sizeof *(t), (void*)STBDS_ADDRESSOF((t)->key, (k)), sizeof(t)->key, STBDS_OFFSETOF((t), key), STBDS_HM_BINARY)), (t) ? stbds_temp((t) - 1) : 0) #define stbds_hmdefault(t, v) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) #define stbds_hmdefaults(t, s) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) -#define stbds_hmfree(p) \ - ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL) +#define stbds_hmfree(p) \ + ((void)((p) != NULL ? stbds_hmfree_func((p) - 1, sizeof *(p)), 0 : 0), (p) = NULL) -#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) -#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) -#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value) -#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) -#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) -#define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) +#define stbds_hmgets(t, k) (*stbds_hmgetp(t, k)) +#define stbds_hmget(t, k) (stbds_hmgetp(t, k)->value) +#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t, k, temp)->value) +#define stbds_hmlen(t) ((t) ? (ptrdiff_t)stbds_header((t) - 1)->length - 1 : 0) +#define stbds_hmlenu(t) ((t) ? stbds_header((t) - 1)->length - 1 : 0) +#define stbds_hmgetp_null(t, k) (stbds_hmgeti(t, k) == -1 ? NULL : &(t)[stbds_temp((t) - 1)]) #define stbds_shput(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)].value = (v)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t) - 1)].value = (v)) #define stbds_shputi(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t) - 1)].value = (v), stbds_temp((t) - 1)) #define stbds_shputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)] = (s), \ - (t)[stbds_temp((t)-1)].key = stbds_temp_key((t)-1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)(s).key, sizeof(s).key, STBDS_HM_STRING), \ + (t)[stbds_temp((t) - 1)] = (s), \ + (t)[stbds_temp((t) - 1)].key = stbds_temp_key((t) - 1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally #define stbds_pshput(t, p) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ - (t)[stbds_temp((t)-1)] = (p)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)(p)->key, sizeof(p)->key, STBDS_HM_PTR_TO_STRING), \ + (t)[stbds_temp((t) - 1)] = (p)) -#define stbds_shgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - stbds_temp((t)-1)) +#define stbds_shgeti(t, k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(t)->key, STBDS_HM_STRING), \ + stbds_temp((t) - 1)) -#define stbds_pshgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ - stbds_temp((t)-1)) +#define stbds_pshgeti(t, k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(*(t))->key, STBDS_HM_PTR_TO_STRING), \ + stbds_temp((t) - 1)) #define stbds_shgetp(t, k) \ - ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) + ((void)stbds_shgeti(t, k), &(t)[stbds_temp((t) - 1)]) #define stbds_pshget(t, k) \ - ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) + ((void)stbds_pshgeti(t, k), (t)[stbds_temp((t) - 1)]) -#define stbds_shdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0) -#define stbds_pshdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0) +#define stbds_shdel(t, k) \ + (((t) = stbds_hmdel_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(t)->key, STBDS_OFFSETOF((t), key), STBDS_HM_STRING)), (t) ? stbds_temp((t) - 1) : 0) +#define stbds_pshdel(t, k) \ + (((t) = stbds_hmdel_key_wrapper((t), sizeof *(t), (void*)(k), sizeof(*(t))->key, STBDS_OFFSETOF(*(t), key), STBDS_HM_PTR_TO_STRING)), (t) ? stbds_temp((t) - 1) : 0) -#define stbds_sh_new_arena(t) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) +#define stbds_sh_new_arena(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) #define stbds_sh_new_strdup(t) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) -#define stbds_shdefault(t, v) stbds_hmdefault(t,v) -#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) +#define stbds_shdefault(t, v) stbds_hmdefault(t, v) +#define stbds_shdefaults(t, s) stbds_hmdefaults(t, s) -#define stbds_shfree stbds_hmfree -#define stbds_shlenu stbds_hmlenu +#define stbds_shfree stbds_hmfree +#define stbds_shlenu stbds_hmlenu -#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) -#define stbds_shget(t, k) (stbds_shgetp(t,k)->value) -#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) -#define stbds_shlen stbds_hmlen +#define stbds_shgets(t, k) (*stbds_shgetp(t, k)) +#define stbds_shget(t, k) (stbds_shgetp(t, k)->value) +#define stbds_shgetp_null(t, k) (stbds_shgeti(t, k) == -1 ? NULL : &(t)[stbds_temp((t) - 1)]) +#define stbds_shlen stbds_hmlen typedef struct { - size_t length; - size_t capacity; - void * hash_table; - ptrdiff_t temp; + size_t length; + size_t capacity; + void* hash_table; + ptrdiff_t temp; } stbds_array_header; -typedef struct stbds_string_block -{ - struct stbds_string_block *next; - char storage[8]; +typedef struct stbds_string_block { + struct stbds_string_block* next; + char storage[8]; } stbds_string_block; -struct stbds_string_arena -{ - stbds_string_block *storage; - size_t remaining; - unsigned char block; - unsigned char mode; // this isn't used by the string arena itself +struct stbds_string_arena { + stbds_string_block* storage; + size_t remaining; + unsigned char block; + unsigned char mode; // this isn't used by the string arena itself }; -#define STBDS_HM_BINARY 0 -#define STBDS_HM_STRING 1 +#define STBDS_HM_BINARY 0 +#define STBDS_HM_STRING 1 -enum -{ - STBDS_SH_NONE, - STBDS_SH_DEFAULT, - STBDS_SH_STRDUP, - STBDS_SH_ARENA +enum { + STBDS_SH_NONE, + STBDS_SH_DEFAULT, + STBDS_SH_STRDUP, + STBDS_SH_ARENA }; #ifdef __cplusplus // in C we use implicit assignment from these void*-returning functions to T*. // in C++ these templates make the same code work -template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { - return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); +template +static T* stbds_arrgrowf_wrapper(T* a, size_t elemsize, size_t addlen, size_t min_cap) { + return (T*)stbds_arrgrowf((void*)a, elemsize, addlen, min_cap); } -template static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { - return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); +template +static T* stbds_hmget_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, int mode) { + return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); } -template static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) { - return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); +template +static T* stbds_hmget_key_ts_wrapper(T* a, size_t elemsize, void* key, size_t keysize, ptrdiff_t* temp, int mode) { + return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); } -template static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { - return (T*)stbds_hmput_default((void *)a, elemsize); +template +static T* stbds_hmput_default_wrapper(T* a, size_t elemsize) { + return (T*)stbds_hmput_default((void*)a, elemsize); } -template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { - return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); +template +static T* stbds_hmput_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, int mode) { + return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); } -template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ - return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); +template +static T* stbds_hmdel_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) { + return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); } -template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { - return (T*)stbds_shmode_func(elemsize, mode); +template +static T* stbds_shmode_func_wrapper(T*, size_t elemsize, int mode) { + return (T*)stbds_shmode_func(elemsize, mode); } #else -#define stbds_arrgrowf_wrapper stbds_arrgrowf -#define stbds_hmget_key_wrapper stbds_hmget_key -#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts -#define stbds_hmput_default_wrapper stbds_hmput_default -#define stbds_hmput_key_wrapper stbds_hmput_key -#define stbds_hmdel_key_wrapper stbds_hmdel_key -#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) +#define stbds_arrgrowf_wrapper stbds_arrgrowf +#define stbds_hmget_key_wrapper stbds_hmget_key +#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts +#define stbds_hmput_default_wrapper stbds_hmput_default +#define stbds_hmput_key_wrapper stbds_hmput_key +#define stbds_hmdel_key_wrapper stbds_hmdel_key +#define stbds_shmode_func_wrapper(t, e, m) stbds_shmode_func(e, m) #endif #endif // INCLUDE_STB_DS_H - ////////////////////////////////////////////////////////////////////////////// // // IMPLEMENTATION @@ -735,11 +739,11 @@ template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int #ifndef STBDS_ASSERT #define STBDS_ASSERT_WAS_UNDEFINED -#define STBDS_ASSERT(x) ((void) 0) +#define STBDS_ASSERT(x) ((void)0) #endif #ifdef STBDS_STATISTICS -#define STBDS_STATS(x) x +#define STBDS_STATS(x) x size_t stbds_array_grow; size_t stbds_hash_grow; size_t stbds_hash_shrink; @@ -756,50 +760,48 @@ size_t stbds_rehash_items; // stbds_arr implementation // -//int *prev_allocs[65536]; -//int num_prev; +// int *prev_allocs[65536]; +// int num_prev; -void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) -{ - stbds_array_header temp={0}; // force debugging - void *b; - size_t min_len = stbds_arrlen(a) + addlen; - (void) sizeof(temp); +void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap) { + stbds_array_header temp = {0}; // force debugging + void* b; + size_t min_len = stbds_arrlen(a) + addlen; + (void)sizeof(temp); - // compute the minimum capacity needed - if (min_len > min_cap) - min_cap = min_len; + // compute the minimum capacity needed + if(min_len > min_cap) + min_cap = min_len; - if (min_cap <= stbds_arrcap(a)) - return a; + if(min_cap <= stbds_arrcap(a)) + return a; - // increase needed capacity to guarantee O(1) amortized - if (min_cap < 2 * stbds_arrcap(a)) - min_cap = 2 * stbds_arrcap(a); - else if (min_cap < 4) - min_cap = 4; + // increase needed capacity to guarantee O(1) amortized + if(min_cap < 2 * stbds_arrcap(a)) + min_cap = 2 * stbds_arrcap(a); + else if(min_cap < 4) + min_cap = 4; - //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); - //if (num_prev == 2201) - // num_prev = num_prev; - b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); - //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; - b = (char *) b + sizeof(stbds_array_header); - if (a == NULL) { - stbds_header(b)->length = 0; - stbds_header(b)->hash_table = 0; - stbds_header(b)->temp = 0; - } else { - STBDS_STATS(++stbds_array_grow); - } - stbds_header(b)->capacity = min_cap; + // if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); + // if (num_prev == 2201) + // num_prev = num_prev; + b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); + // if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; + b = (char*)b + sizeof(stbds_array_header); + if(a == NULL) { + stbds_header(b)->length = 0; + stbds_header(b)->hash_table = 0; + stbds_header(b)->temp = 0; + } else { + STBDS_STATS(++stbds_array_grow); + } + stbds_header(b)->capacity = min_cap; - return b; + return b; } -void stbds_arrfreef(void *a) -{ - STBDS_FREE(NULL, stbds_header(a)); +void stbds_arrfreef(void* a) { + STBDS_FREE(NULL, stbds_header(a)); } // @@ -807,227 +809,221 @@ void stbds_arrfreef(void *a) // #ifdef STBDS_INTERNAL_SMALL_BUCKET -#define STBDS_BUCKET_LENGTH 4 +#define STBDS_BUCKET_LENGTH 4 #else -#define STBDS_BUCKET_LENGTH 8 +#define STBDS_BUCKET_LENGTH 8 #endif -#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) -#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) -#define STBDS_CACHE_LINE_SIZE 64 +#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) +#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH - 1) +#define STBDS_CACHE_LINE_SIZE 64 -#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) +#define STBDS_ALIGN_FWD(n, a) (((n) + (a) - 1) & ~((a) - 1)) typedef struct { - size_t hash [STBDS_BUCKET_LENGTH]; - ptrdiff_t index[STBDS_BUCKET_LENGTH]; + size_t hash[STBDS_BUCKET_LENGTH]; + ptrdiff_t index[STBDS_BUCKET_LENGTH]; } stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line typedef struct { - char * temp_key; // this MUST be the first field of the hash table - size_t slot_count; - size_t used_count; - size_t used_count_threshold; - size_t used_count_shrink_threshold; - size_t tombstone_count; - size_t tombstone_count_threshold; - size_t seed; - size_t slot_count_log2; - stbds_string_arena string; - stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct + char* temp_key; // this MUST be the first field of the hash table + size_t slot_count; + size_t used_count; + size_t used_count_threshold; + size_t used_count_shrink_threshold; + size_t tombstone_count; + size_t tombstone_count_threshold; + size_t seed; + size_t slot_count_log2; + stbds_string_arena string; + stbds_hash_bucket* storage; // not a separate allocation, just 64-byte aligned storage after this struct } stbds_hash_index; -#define STBDS_INDEX_EMPTY -1 -#define STBDS_INDEX_DELETED -2 -#define STBDS_INDEX_IN_USE(x) ((x) >= 0) +#define STBDS_INDEX_EMPTY -1 +#define STBDS_INDEX_DELETED -2 +#define STBDS_INDEX_IN_USE(x) ((x) >= 0) -#define STBDS_HASH_EMPTY 0 -#define STBDS_HASH_DELETED 1 +#define STBDS_HASH_EMPTY 0 +#define STBDS_HASH_DELETED 1 -static size_t stbds_hash_seed=0x31415926; +static size_t stbds_hash_seed = 0x31415926; -void stbds_rand_seed(size_t seed) -{ - stbds_hash_seed = seed; +void stbds_rand_seed(size_t seed) { + stbds_hash_seed = seed; } -#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ - temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ - var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ - var ^= temp ^ v32 +#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ + temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ + var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ + var ^= temp ^ v32 -#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) +#define STBDS_SIZE_T_BITS ((sizeof(size_t)) * 8) -static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) -{ - size_t pos; - STBDS_NOTUSED(slot_log2); - pos = hash & (slot_count-1); - #ifdef STBDS_INTERNAL_BUCKET_START - pos &= ~STBDS_BUCKET_MASK; - #endif - return pos; +static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) { + size_t pos; + STBDS_NOTUSED(slot_log2); + pos = hash & (slot_count - 1); +#ifdef STBDS_INTERNAL_BUCKET_START + pos &= ~STBDS_BUCKET_MASK; +#endif + return pos; } -static size_t stbds_log2(size_t slot_count) -{ - size_t n=0; - while (slot_count > 1) { - slot_count >>= 1; - ++n; - } - return n; +static size_t stbds_log2(size_t slot_count) { + size_t n = 0; + while(slot_count > 1) { + slot_count >>= 1; + ++n; + } + return n; } -static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) -{ - stbds_hash_index *t; - t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); - t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); - t->slot_count = slot_count; - t->slot_count_log2 = stbds_log2(slot_count); - t->tombstone_count = 0; - t->used_count = 0; +static stbds_hash_index* stbds_make_hash_index(size_t slot_count, stbds_hash_index* ot) { + stbds_hash_index* t; + t = (stbds_hash_index*)STBDS_REALLOC(NULL, 0, (slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE - 1); + t->storage = (stbds_hash_bucket*)STBDS_ALIGN_FWD((size_t)(t + 1), STBDS_CACHE_LINE_SIZE); + t->slot_count = slot_count; + t->slot_count_log2 = stbds_log2(slot_count); + t->tombstone_count = 0; + t->used_count = 0; - #if 0 // A1 +#if 0 // A1 t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - #elif 1 // A2 - //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild - //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink +#elif 1 // A2 + // t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + // t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild + // t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - // compute without overflowing - t->used_count_threshold = slot_count - (slot_count>>2); - t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); - t->used_count_shrink_threshold = slot_count >> 2; + // compute without overflowing + t->used_count_threshold = slot_count - (slot_count >> 2); + t->tombstone_count_threshold = (slot_count >> 3) + (slot_count >> 4); + t->used_count_shrink_threshold = slot_count >> 2; - #elif 0 // B1 - t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink - #else // C1 - t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // A1 A2 B1 C1 - // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table - // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table - // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table - // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table - // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table - // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table - // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table - // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table - // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table - // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table - // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table +#elif 0 // B1 + t->used_count_threshold = slot_count * 13 / 16; // if 13/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count * 2 / 16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count * 5 / 16; // if table is only 5/16th full, shrink +#else // C1 + t->used_count_threshold = slot_count * 14 / 16; // if 14/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count * 2 / 16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count * 6 / 16; // if table is only 6/16th full, shrink +#endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // A1 A2 B1 C1 + // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table + // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table + // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table + // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table + // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table + // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table + // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table + // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table + // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table + // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table + // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table - if (slot_count <= STBDS_BUCKET_LENGTH) - t->used_count_shrink_threshold = 0; - // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes - STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); - STBDS_STATS(++stbds_hash_alloc); - if (ot) { - t->string = ot->string; - // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing - t->seed = ot->seed; - } else { - size_t a,b,temp; - memset(&t->string, 0, sizeof(t->string)); - t->seed = stbds_hash_seed; - // LCG - // in 32-bit, a = 2147001325 b = 715136305 - // in 64-bit, a = 2862933555777941757 b = 3037000493 - stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); - stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); - stbds_hash_seed = stbds_hash_seed * a + b; - } + if(slot_count <= STBDS_BUCKET_LENGTH) + t->used_count_shrink_threshold = 0; + // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes + STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); + STBDS_STATS(++stbds_hash_alloc); + if(ot) { + t->string = ot->string; + // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing + t->seed = ot->seed; + } else { + size_t a, b, temp; + memset(&t->string, 0, sizeof(t->string)); + t->seed = stbds_hash_seed; + // LCG + // in 32-bit, a = 2147001325 b = 715136305 + // in 64-bit, a = 2862933555777941757 b = 3037000493 + stbds_load_32_or_64(a, temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); + stbds_load_32_or_64(b, temp, 715136305, 0, 0xb504f32d); + stbds_hash_seed = stbds_hash_seed * a + b; + } - { - size_t i,j; - for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *b = &t->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->hash[j] = STBDS_HASH_EMPTY; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->index[j] = STBDS_INDEX_EMPTY; - } - } + { + size_t i, j; + for(i = 0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket* b = &t->storage[i]; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) + b->hash[j] = STBDS_HASH_EMPTY; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) + b->index[j] = STBDS_INDEX_EMPTY; + } + } - // copy out the old data, if any - if (ot) { - size_t i,j; - t->used_count = ot->used_count; - for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *ob = &ot->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { - if (STBDS_INDEX_IN_USE(ob->index[j])) { - size_t hash = ob->hash[j]; - size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); - size_t step = STBDS_BUCKET_LENGTH; - STBDS_STATS(++stbds_rehash_items); - for (;;) { - size_t limit,z; - stbds_hash_bucket *bucket; - bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; - STBDS_STATS(++stbds_rehash_probes); + // copy out the old data, if any + if(ot) { + size_t i, j; + t->used_count = ot->used_count; + for(i = 0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket* ob = &ot->storage[i]; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) { + if(STBDS_INDEX_IN_USE(ob->index[j])) { + size_t hash = ob->hash[j]; + size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); + size_t step = STBDS_BUCKET_LENGTH; + STBDS_STATS(++stbds_rehash_items); + for(;;) { + size_t limit, z; + stbds_hash_bucket* bucket; + bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; + STBDS_STATS(++stbds_rehash_probes); - for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } + for(z = pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { + if(bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } - limit = pos & STBDS_BUCKET_MASK; - for (z = 0; z < limit; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } + limit = pos & STBDS_BUCKET_MASK; + for(z = 0; z < limit; ++z) { + if(bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } - pos += step; // quadratic probing - step += STBDS_BUCKET_LENGTH; - pos &= (t->slot_count-1); - } - } - done: - ; - } - } - } + pos += step; // quadratic probing + step += STBDS_BUCKET_LENGTH; + pos &= (t->slot_count - 1); + } + } + done:; + } + } + } - return t; + return t; } -#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) -#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) -size_t stbds_hash_string(char *str, size_t seed) -{ - size_t hash = seed; - while (*str) - hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; +size_t stbds_hash_string(char* str, size_t seed) { + size_t hash = seed; + while(*str) + hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char)*str++; - // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits - hash ^= seed; - hash = (~hash) + (hash << 18); - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); - hash = hash * 21; - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); - hash += (hash << 6); - hash ^= STBDS_ROTATE_RIGHT(hash,22); - return hash+seed; + // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits + hash ^= seed; + hash = (~hash) + (hash << 18); + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash, 31); + hash = hash * 21; + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash, 11); + hash += (hash << 6); + hash ^= STBDS_ROTATE_RIGHT(hash, 22); + return hash + seed; } #ifdef STBDS_SIPHASH_2_4 @@ -1045,84 +1041,100 @@ typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) = #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== +#pragma warning(disable : 4127) // conditional expression is constant, for do..while(0) and sizeof()== #endif -static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) -{ - unsigned char *d = (unsigned char *) p; - size_t i,j; - size_t v0,v1,v2,v3, data; +static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) { + unsigned char* d = (unsigned char*)p; + size_t i, j; + size_t v0, v1, v2, v3, data; - // hash that works on 32- or 64-bit registers without knowing which we have - // (computes different results on 32-bit and 64-bit platform) - // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit - v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; - v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; - v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; - v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; + // hash that works on 32- or 64-bit registers without knowing which we have + // (computes different results on 32-bit and 64-bit platform) + // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit + v0 = ((((size_t)0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; + v1 = ((((size_t)0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; + v2 = ((((size_t)0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; + v3 = ((((size_t)0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; - #ifdef STBDS_TEST_SIPHASH_2_4 - // hardcoded with key material in the siphash test vectors - v0 ^= 0x0706050403020100ull ^ seed; - v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - v2 ^= 0x0706050403020100ull ^ seed; - v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - #endif +#ifdef STBDS_TEST_SIPHASH_2_4 + // hardcoded with key material in the siphash test vectors + v0 ^= 0x0706050403020100ull ^ seed; + v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + v2 ^= 0x0706050403020100ull ^ seed; + v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; +#endif - #define STBDS_SIPROUND() \ - do { \ - v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ - v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ - v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ - v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ - } while (0) +#define STBDS_SIPROUND() \ + do { \ + v0 += v1; \ + v1 = STBDS_ROTATE_LEFT(v1, 13); \ + v1 ^= v0; \ + v0 = STBDS_ROTATE_LEFT(v0, STBDS_SIZE_T_BITS / 2); \ + v2 += v3; \ + v3 = STBDS_ROTATE_LEFT(v3, 16); \ + v3 ^= v2; \ + v2 += v1; \ + v1 = STBDS_ROTATE_LEFT(v1, 17); \ + v1 ^= v2; \ + v2 = STBDS_ROTATE_LEFT(v2, STBDS_SIZE_T_BITS / 2); \ + v0 += v3; \ + v3 = STBDS_ROTATE_LEFT(v3, 21); \ + v3 ^= v0; \ + } while(0) - for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { - data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 + for(i = 0; i + sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { + data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + data |= (size_t)(d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - } - data = len << (STBDS_SIZE_T_BITS-8); - switch (len - i) { - case 7: data |= ((size_t) d[6] << 24) << 24; // fall through - case 6: data |= ((size_t) d[5] << 20) << 20; // fall through - case 5: data |= ((size_t) d[4] << 16) << 16; // fall through - case 4: data |= (d[3] << 24); // fall through - case 3: data |= (d[2] << 16); // fall through - case 2: data |= (d[1] << 8); // fall through - case 1: data |= d[0]; // fall through - case 0: break; - } - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - v2 ^= 0xff; - for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) - STBDS_SIPROUND(); + v3 ^= data; + for(j = 0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + } + data = len << (STBDS_SIZE_T_BITS - 8); + switch(len - i) { + case 7: + data |= ((size_t)d[6] << 24) << 24; // fall through + case 6: + data |= ((size_t)d[5] << 20) << 20; // fall through + case 5: + data |= ((size_t)d[4] << 16) << 16; // fall through + case 4: + data |= (d[3] << 24); // fall through + case 3: + data |= (d[2] << 16); // fall through + case 2: + data |= (d[1] << 8); // fall through + case 1: + data |= d[0]; // fall through + case 0: + break; + } + v3 ^= data; + for(j = 0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + v2 ^= 0xff; + for(j = 0; j < STBDS_SIPHASH_D_ROUNDS; ++j) + STBDS_SIPROUND(); #ifdef STBDS_SIPHASH_2_4 - return v0^v1^v2^v3; + return v0 ^ v1 ^ v2 ^ v3; #else - return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply + return v1 ^ v2 ^ v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply #endif } -size_t stbds_hash_bytes(void *p, size_t len, size_t seed) -{ +size_t stbds_hash_bytes(void* p, size_t len, size_t seed) { #ifdef STBDS_SIPHASH_2_4 - return stbds_siphash_bytes(p,len,seed); + return stbds_siphash_bytes(p, len, seed); #else - unsigned char *d = (unsigned char *) p; + unsigned char* d = (unsigned char*)p; - if (len == 4) { - unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - #if 0 + if(len == 4) { + unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); +#if 0 // HASH32-A Bob Jenkin's hash function w/o large constants hash ^= seed; hash -= (hash<<6); @@ -1133,485 +1145,480 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed) hash -= (hash<<3); hash ^= (hash<<10); hash ^= (hash>>15); - #elif 1 - // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. - // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm - // not really sure what's going on. - hash ^= seed; - hash = (hash ^ 61) ^ (hash >> 16); - hash = hash + (hash << 3); - hash = hash ^ (hash >> 4); - hash = hash * 0x27d4eb2d; - hash ^= seed; - hash = hash ^ (hash >> 15); - #else // HASH32-C - Murmur3 - hash ^= seed; - hash *= 0xcc9e2d51; - hash = (hash << 17) | (hash >> 15); - hash *= 0x1b873593; - hash ^= seed; - hash = (hash << 19) | (hash >> 13); - hash = hash*5 + 0xe6546b64; - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= seed; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // HASH32-A // HASH32-BB // HASH32-C - // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table - // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table - // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table - // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table - // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table - // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table - // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table - // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table - // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table - // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table - // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table - // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing +#elif 1 + // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. + // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm + // not really sure what's going on. + hash ^= seed; + hash = (hash ^ 61) ^ (hash >> 16); + hash = hash + (hash << 3); + hash = hash ^ (hash >> 4); + hash = hash * 0x27d4eb2d; + hash ^= seed; + hash = hash ^ (hash >> 15); +#else // HASH32-C - Murmur3 + hash ^= seed; + hash *= 0xcc9e2d51; + hash = (hash << 17) | (hash >> 15); + hash *= 0x1b873593; + hash ^= seed; + hash = (hash << 19) | (hash >> 13); + hash = hash * 5 + 0xe6546b64; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= seed; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; +#endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // HASH32-A // HASH32-BB // HASH32-C + // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table + // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table + // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table + // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table + // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table + // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table + // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table + // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table + // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table + // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table + // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table + // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing - return (((size_t) hash << 16 << 16) | hash) ^ seed; - } else if (len == 8 && sizeof(size_t) == 8) { - size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 - hash ^= seed; - hash = (~hash) + (hash << 21); - hash ^= STBDS_ROTATE_RIGHT(hash,24); - hash *= 265; - hash ^= STBDS_ROTATE_RIGHT(hash,14); - hash ^= seed; - hash *= 21; - hash ^= STBDS_ROTATE_RIGHT(hash,28); - hash += (hash << 31); - hash = (~hash) + (hash << 18); - return hash; - } else { - return stbds_siphash_bytes(p,len,seed); - } + return (((size_t)hash << 16 << 16) | hash) ^ seed; + } else if(len == 8 && sizeof(size_t) == 8) { + size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + hash |= (size_t)(d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 + hash ^= seed; + hash = (~hash) + (hash << 21); + hash ^= STBDS_ROTATE_RIGHT(hash, 24); + hash *= 265; + hash ^= STBDS_ROTATE_RIGHT(hash, 14); + hash ^= seed; + hash *= 21; + hash ^= STBDS_ROTATE_RIGHT(hash, 28); + hash += (hash << 31); + hash = (~hash) + (hash << 18); + return hash; + } else { + return stbds_siphash_bytes(p, len, seed); + } #endif } #ifdef _MSC_VER #pragma warning(pop) #endif - -static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i) -{ - if (mode >= STBDS_HM_STRING) - return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); - else - return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); +static int stbds_is_key_equal(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode, size_t i) { + if(mode >= STBDS_HM_STRING) + return 0 == strcmp((char*)key, *(char**)((char*)a + elemsize * i + keyoffset)); + else + return 0 == memcmp(key, (char*)a + elemsize * i + keyoffset, keysize); } -#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) -#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) +#define STBDS_HASH_TO_ARR(x, elemsize) ((char*)(x) - (elemsize)) +#define STBDS_ARR_TO_HASH(x, elemsize) ((char*)(x) + (elemsize)) -#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) +#define stbds_hash_table(a) ((stbds_hash_index*)stbds_header(a)->hash_table) -void stbds_hmfree_func(void *a, size_t elemsize) -{ - if (a == NULL) return; - if (stbds_hash_table(a) != NULL) { - if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { - size_t i; - // skip 0th element, which is default - for (i=1; i < stbds_header(a)->length; ++i) - STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); - } - stbds_strreset(&stbds_hash_table(a)->string); - } - STBDS_FREE(NULL, stbds_header(a)->hash_table); - STBDS_FREE(NULL, stbds_header(a)); +void stbds_hmfree_func(void* a, size_t elemsize) { + if(a == NULL) return; + if(stbds_hash_table(a) != NULL) { + if(stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { + size_t i; + // skip 0th element, which is default + for(i = 1; i < stbds_header(a)->length; ++i) + STBDS_FREE(NULL, *(char**)((char*)a + elemsize * i)); + } + stbds_strreset(&stbds_hash_table(a)->string); + } + STBDS_FREE(NULL, stbds_header(a)->hash_table); + STBDS_FREE(NULL, stbds_header(a)); } -static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) -{ - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - stbds_hash_index *table = stbds_hash_table(raw_a); - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t limit,i; - size_t pos; - stbds_hash_bucket *bucket; +static ptrdiff_t stbds_hm_find_slot(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) { + void* raw_a = STBDS_HASH_TO_ARR(a, elemsize); + stbds_hash_index* table = stbds_hash_table(raw_a); + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key, table->seed) : stbds_hash_bytes(key, keysize, table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit, i; + size_t pos; + stbds_hash_bucket* bucket; - if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots + if(hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - for (;;) { - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + for(;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } + // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache + for(i = pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if(bucket->hash[i] == hash) { + if(stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK) + i; + } + } else if(bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for(i = 0; i < limit; ++i) { + if(bucket->hash[i] == hash) { + if(stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK) + i; + } + } else if(bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - /* NOTREACHED */ + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count - 1); + } + /* NOTREACHED */ } -void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) -{ - size_t keyoffset = 0; - if (a == NULL) { - // make it non-empty so we can return a temp - a = stbds_arrgrowf(0, elemsize, 0, 1); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - *temp = STBDS_INDEX_EMPTY; - // adjust a to point after the default element - return STBDS_ARR_TO_HASH(a,elemsize); - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - // adjust a to point to the default element - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - if (table == 0) { - *temp = -1; - } else { - ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) { - *temp = STBDS_INDEX_EMPTY; - } else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - *temp = b->index[slot & STBDS_BUCKET_MASK]; - } - } - return a; - } +void* stbds_hmget_key_ts(void* a, size_t elemsize, void* key, size_t keysize, ptrdiff_t* temp, int mode) { + size_t keyoffset = 0; + if(a == NULL) { + // make it non-empty so we can return a temp + a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + *temp = STBDS_INDEX_EMPTY; + // adjust a to point after the default element + return STBDS_ARR_TO_HASH(a, elemsize); + } else { + stbds_hash_index* table; + void* raw_a = STBDS_HASH_TO_ARR(a, elemsize); + // adjust a to point to the default element + table = (stbds_hash_index*)stbds_header(raw_a)->hash_table; + if(table == 0) { + *temp = -1; + } else { + ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if(slot < 0) { + *temp = STBDS_INDEX_EMPTY; + } else { + stbds_hash_bucket* b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + *temp = b->index[slot & STBDS_BUCKET_MASK]; + } + } + return a; + } } -void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) -{ - ptrdiff_t temp; - void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); - stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; - return p; +void* stbds_hmget_key(void* a, size_t elemsize, void* key, size_t keysize, int mode) { + ptrdiff_t temp; + void* p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); + stbds_temp(STBDS_HASH_TO_ARR(p, elemsize)) = temp; + return p; } -void * stbds_hmput_default(void *a, size_t elemsize) -{ - // three cases: - // a is NULL <- allocate - // a has a hash table but no entries, because of shmode <- grow - // a has entries <- do nothing - if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { - a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - a=STBDS_ARR_TO_HASH(a,elemsize); - } - return a; +void* stbds_hmput_default(void* a, size_t elemsize) { + // three cases: + // a is NULL <- allocate + // a has a hash table but no entries, because of shmode <- grow + // a has entries <- do nothing + if(a == NULL || stbds_header(STBDS_HASH_TO_ARR(a, elemsize))->length == 0) { + a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a, elemsize) : NULL, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + a = STBDS_ARR_TO_HASH(a, elemsize); + } + return a; } -static char *stbds_strdup(char *str); +static char* stbds_strdup(char* str); -void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) -{ - size_t keyoffset=0; - void *raw_a; - stbds_hash_index *table; +void* stbds_hmput_key(void* a, size_t elemsize, void* key, size_t keysize, int mode) { + size_t keyoffset = 0; + void* raw_a; + stbds_hash_index* table; - if (a == NULL) { - a = stbds_arrgrowf(0, elemsize, 0, 1); - memset(a, 0, elemsize); - stbds_header(a)->length += 1; - // adjust a to point AFTER the default element - a = STBDS_ARR_TO_HASH(a,elemsize); - } + if(a == NULL) { + a = stbds_arrgrowf(0, elemsize, 0, 1); + memset(a, 0, elemsize); + stbds_header(a)->length += 1; + // adjust a to point AFTER the default element + a = STBDS_ARR_TO_HASH(a, elemsize); + } - // adjust a to point to the default element - raw_a = a; - a = STBDS_HASH_TO_ARR(a,elemsize); + // adjust a to point to the default element + raw_a = a; + a = STBDS_HASH_TO_ARR(a, elemsize); - table = (stbds_hash_index *) stbds_header(a)->hash_table; + table = (stbds_hash_index*)stbds_header(a)->hash_table; - if (table == NULL || table->used_count >= table->used_count_threshold) { - stbds_hash_index *nt; - size_t slot_count; + if(table == NULL || table->used_count >= table->used_count_threshold) { + stbds_hash_index* nt; + size_t slot_count; - slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; - nt = stbds_make_hash_index(slot_count, table); - if (table) - STBDS_FREE(NULL, table); - else - nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; - stbds_header(a)->hash_table = table = nt; - STBDS_STATS(++stbds_hash_grow); - } + slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count * 2; + nt = stbds_make_hash_index(slot_count, table); + if(table) + STBDS_FREE(NULL, table); + else + nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; + stbds_header(a)->hash_table = table = nt; + STBDS_STATS(++stbds_hash_grow); + } - // we iterate hash table explicitly because we want to track if we saw a tombstone - { - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t pos; - ptrdiff_t tombstone = -1; - stbds_hash_bucket *bucket; + // we iterate hash table explicitly because we want to track if we saw a tombstone + { + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key, table->seed) : stbds_hash_bytes(key, keysize, table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t pos; + ptrdiff_t tombstone = -1; + stbds_hash_bucket* bucket; - // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly - if (hash < 2) hash += 2; + // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly + if(hash < 2) hash += 2; - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - for (;;) { - size_t limit, i; - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + for(;;) { + size_t limit, i; + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - // start searching from pos to end of bucket - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - if (mode >= STBDS_HM_STRING) - stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } + // start searching from pos to end of bucket + for(i = pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if(bucket->hash[i] == hash) { + if(stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + if(mode >= STBDS_HM_STRING) + stbds_temp_key(a) = *(char**)((char*)raw_a + elemsize * bucket->index[i] + keyoffset); + return STBDS_ARR_TO_HASH(a, elemsize); + } + } else if(bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if(tombstone < 0) { + if(bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t)((pos & ~STBDS_BUCKET_MASK) + i); + } + } - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for(i = 0; i < limit; ++i) { + if(bucket->hash[i] == hash) { + if(stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a, elemsize); + } + } else if(bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if(tombstone < 0) { + if(bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t)((pos & ~STBDS_BUCKET_MASK) + i); + } + } - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - found_empty_slot: - if (tombstone >= 0) { - pos = tombstone; - --table->tombstone_count; - } - ++table->used_count; + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count - 1); + } + found_empty_slot: + if(tombstone >= 0) { + pos = tombstone; + --table->tombstone_count; + } + ++table->used_count; - { - ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); - // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type - if ((size_t) i+1 > stbds_arrcap(a)) - *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); - raw_a = STBDS_ARR_TO_HASH(a,elemsize); + { + ptrdiff_t i = (ptrdiff_t)stbds_arrlen(a); + // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type + if((size_t)i + 1 > stbds_arrcap(a)) + *(void**)&a = stbds_arrgrowf(a, elemsize, 1, 0); + raw_a = STBDS_ARR_TO_HASH(a, elemsize); - STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); - stbds_header(a)->length = i+1; - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - bucket->hash[pos & STBDS_BUCKET_MASK] = hash; - bucket->index[pos & STBDS_BUCKET_MASK] = i-1; - stbds_temp(a) = i-1; + STBDS_ASSERT((size_t)i + 1 <= stbds_arrcap(a)); + stbds_header(a)->length = i + 1; + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + bucket->hash[pos & STBDS_BUCKET_MASK] = hash; + bucket->index[pos & STBDS_BUCKET_MASK] = i - 1; + stbds_temp(a) = i - 1; - switch (table->string.mode) { - case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; - case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; - case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; - default: memcpy((char *) a + elemsize*i, key, keysize); break; - } - } - return STBDS_ARR_TO_HASH(a,elemsize); - } + switch(table->string.mode) { + case STBDS_SH_STRDUP: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_strdup((char*)key); + break; + case STBDS_SH_ARENA: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_stralloc(&table->string, (char*)key); + break; + case STBDS_SH_DEFAULT: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = (char*)key; + break; + default: + memcpy((char*)a + elemsize * i, key, keysize); + break; + } + } + return STBDS_ARR_TO_HASH(a, elemsize); + } } -void * stbds_shmode_func(size_t elemsize, int mode) -{ - void *a = stbds_arrgrowf(0, elemsize, 0, 1); - stbds_hash_index *h; - memset(a, 0, elemsize); - stbds_header(a)->length = 1; - stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); - h->string.mode = (unsigned char) mode; - return STBDS_ARR_TO_HASH(a,elemsize); +void* stbds_shmode_func(size_t elemsize, int mode) { + void* a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_hash_index* h; + memset(a, 0, elemsize); + stbds_header(a)->length = 1; + stbds_header(a)->hash_table = h = (stbds_hash_index*)stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); + h->string.mode = (unsigned char)mode; + return STBDS_ARR_TO_HASH(a, elemsize); } -void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) -{ - if (a == NULL) { - return 0; - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - stbds_temp(raw_a) = 0; - if (table == 0) { - return a; - } else { - ptrdiff_t slot; - slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) - return a; - else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - int i = slot & STBDS_BUCKET_MASK; - ptrdiff_t old_index = b->index[i]; - ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' - STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); - --table->used_count; - ++table->tombstone_count; - stbds_temp(raw_a) = 1; - STBDS_ASSERT(table->used_count >= 0); - //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); - b->hash[i] = STBDS_HASH_DELETED; - b->index[i] = STBDS_INDEX_DELETED; +void* stbds_hmdel_key(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) { + if(a == NULL) { + return 0; + } else { + stbds_hash_index* table; + void* raw_a = STBDS_HASH_TO_ARR(a, elemsize); + table = (stbds_hash_index*)stbds_header(raw_a)->hash_table; + stbds_temp(raw_a) = 0; + if(table == 0) { + return a; + } else { + ptrdiff_t slot; + slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if(slot < 0) + return a; + else { + stbds_hash_bucket* b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + int i = slot & STBDS_BUCKET_MASK; + ptrdiff_t old_index = b->index[i]; + ptrdiff_t final_index = (ptrdiff_t)stbds_arrlen(raw_a) - 1 - 1; // minus one for the raw_a vs a, and minus one for 'last' + STBDS_ASSERT(slot < (ptrdiff_t)table->slot_count); + --table->used_count; + ++table->tombstone_count; + stbds_temp(raw_a) = 1; + STBDS_ASSERT(table->used_count >= 0); + // STBDS_ASSERT(table->tombstone_count < table->slot_count/4); + b->hash[i] = STBDS_HASH_DELETED; + b->index[i] = STBDS_INDEX_DELETED; - if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) - STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); + if(mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) + STBDS_FREE(NULL, *(char**)((char*)a + elemsize * old_index)); - // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip - if (old_index != final_index) { - // swap delete - memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); + // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip + if(old_index != final_index) { + // swap delete + memmove((char*)a + elemsize * old_index, (char*)a + elemsize * final_index, elemsize); - // now find the slot for the last element - if (mode == STBDS_HM_STRING) - slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode); - else - slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode); - STBDS_ASSERT(slot >= 0); - b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - i = slot & STBDS_BUCKET_MASK; - STBDS_ASSERT(b->index[i] == final_index); - b->index[i] = old_index; - } - stbds_header(raw_a)->length -= 1; + // now find the slot for the last element + if(mode == STBDS_HM_STRING) + slot = stbds_hm_find_slot(a, elemsize, *(char**)((char*)a + elemsize * old_index + keyoffset), keysize, keyoffset, mode); + else + slot = stbds_hm_find_slot(a, elemsize, (char*)a + elemsize * old_index + keyoffset, keysize, keyoffset, mode); + STBDS_ASSERT(slot >= 0); + b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + i = slot & STBDS_BUCKET_MASK; + STBDS_ASSERT(b->index[i] == final_index); + b->index[i] = old_index; + } + stbds_header(raw_a)->length -= 1; - if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_shrink); - } else if (table->tombstone_count > table->tombstone_count_threshold) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_rebuild); - } + if(table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count >> 1, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_shrink); + } else if(table->tombstone_count > table->tombstone_count_threshold) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_rebuild); + } - return a; - } - } - } - /* NOTREACHED */ + return a; + } + } + } + /* NOTREACHED */ } -static char *stbds_strdup(char *str) -{ - // to keep replaceable allocator simple, we don't want to use strdup. - // rolling our own also avoids problem of strdup vs _strdup - size_t len = strlen(str)+1; - char *p = (char*) STBDS_REALLOC(NULL, 0, len); - memmove(p, str, len); - return p; +static char* stbds_strdup(char* str) { + // to keep replaceable allocator simple, we don't want to use strdup. + // rolling our own also avoids problem of strdup vs _strdup + size_t len = strlen(str) + 1; + char* p = (char*)STBDS_REALLOC(NULL, 0, len); + memmove(p, str, len); + return p; } #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN -#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u +#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u #endif #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX -#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) +#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u << 20) #endif -char *stbds_stralloc(stbds_string_arena *a, char *str) -{ - char *p; - size_t len = strlen(str)+1; - if (len > a->remaining) { - // compute the next blocksize - size_t blocksize = a->block; +char* stbds_stralloc(stbds_string_arena* a, char* str) { + char* p; + size_t len = strlen(str) + 1; + if(len > a->remaining) { + // compute the next blocksize + size_t blocksize = a->block; - // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that - // there are log(SIZE) allocations to free when we destroy the table - blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); + // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that + // there are log(SIZE) allocations to free when we destroy the table + blocksize = (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize >> 1); - // if size is under 1M, advance to next blocktype - if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) - ++a->block; + // if size is under 1M, advance to next blocktype + if(blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) + ++a->block; - if (len > blocksize) { - // if string is larger than blocksize, then just allocate the full size. - // note that we still advance string_block so block size will continue - // increasing, so e.g. if somebody only calls this with 1000-long strings, - // eventually the arena will start doubling and handling those as well - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); - memmove(sb->storage, str, len); - if (a->storage) { - // insert it after the first element, so that we don't waste the space there - sb->next = a->storage->next; - a->storage->next = sb; - } else { - sb->next = 0; - a->storage = sb; - a->remaining = 0; // this is redundant, but good for clarity - } - return sb->storage; - } else { - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); - sb->next = a->storage; - a->storage = sb; - a->remaining = blocksize; - } - } + if(len > blocksize) { + // if string is larger than blocksize, then just allocate the full size. + // note that we still advance string_block so block size will continue + // increasing, so e.g. if somebody only calls this with 1000-long strings, + // eventually the arena will start doubling and handling those as well + stbds_string_block* sb = (stbds_string_block*)STBDS_REALLOC(NULL, 0, sizeof(*sb) - 8 + len); + memmove(sb->storage, str, len); + if(a->storage) { + // insert it after the first element, so that we don't waste the space there + sb->next = a->storage->next; + a->storage->next = sb; + } else { + sb->next = 0; + a->storage = sb; + a->remaining = 0; // this is redundant, but good for clarity + } + return sb->storage; + } else { + stbds_string_block* sb = (stbds_string_block*)STBDS_REALLOC(NULL, 0, sizeof(*sb) - 8 + blocksize); + sb->next = a->storage; + a->storage = sb; + a->remaining = blocksize; + } + } - STBDS_ASSERT(len <= a->remaining); - p = a->storage->storage + a->remaining - len; - a->remaining -= len; - memmove(p, str, len); - return p; + STBDS_ASSERT(len <= a->remaining); + p = a->storage->storage + a->remaining - len; + a->remaining -= len; + memmove(p, str, len); + return p; } -void stbds_strreset(stbds_string_arena *a) -{ - stbds_string_block *x,*y; - x = a->storage; - while (x) { - y = x->next; - STBDS_FREE(NULL, x); - x = y; - } - memset(a, 0, sizeof(*a)); +void stbds_strreset(stbds_string_arena* a) { + stbds_string_block *x, *y; + x = a->storage; + while(x) { + y = x->next; + STBDS_FREE(NULL, x); + x = y; + } + memset(a, 0, sizeof(*a)); } #endif @@ -1631,227 +1638,259 @@ void stbds_strreset(stbds_string_arena *a) #include #endif -typedef struct { int key,b,c,d; } stbds_struct; -typedef struct { int key[2],b,c,d; } stbds_struct2; +typedef struct { + int key, b, c, d; +} stbds_struct; +typedef struct { + int key[2], b, c, d; +} stbds_struct2; static char buffer[256]; -char *strkey(int n) -{ -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - sprintf_s(buffer, sizeof(buffer), "test_%d", n); +char* strkey(int n) { +#if defined(_WIN32) || defined(__WINDOWS__) && defined(__STDC_WANT_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "test_%d", n); #else - sprintf(buffer, "test_%d", n); + sprintf(buffer, "test_%d", n); #endif - return buffer; + return buffer; } -void stbds_unit_tests(void) -{ +void stbds_unit_tests(void) { #if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) - // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! - STBDS_ASSERT(0); + // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! + STBDS_ASSERT(0); #else - const int testsize = 100000; - const int testsize2 = testsize/20; - int *arr=NULL; - struct { int key; int value; } *intmap = NULL; - struct { char *key; int value; } *strmap = NULL, s; - struct { stbds_struct key; int value; } *map = NULL; - stbds_struct *map2 = NULL; - stbds_struct2 *map3 = NULL; - stbds_string_arena sa = { 0 }; - int key3[2] = { 1,2 }; - ptrdiff_t temp; + const int testsize = 100000; + const int testsize2 = testsize / 20; + int* arr = NULL; + struct { + int key; + int value; + }* intmap = NULL; + struct { + char* key; + int value; + } *strmap = NULL, s; + struct { + stbds_struct key; + int value; + }* map = NULL; + stbds_struct* map2 = NULL; + stbds_struct2* map3 = NULL; + stbds_string_arena sa = {0}; + int key3[2] = {1, 2}; + ptrdiff_t temp; - int i,j; + int i, j; - STBDS_ASSERT(arrlen(arr)==0); - for (i=0; i < 20000; i += 50) { - for (j=0; j < i; ++j) - arrpush(arr,j); - arrfree(arr); - } + STBDS_ASSERT(arrlen(arr) == 0); + for(i = 0; i < 20000; i += 50) { + for(j = 0; j < i; ++j) + arrpush(arr, j); + arrfree(arr); + } - for (i=0; i < 4; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdel(arr,i); - arrfree(arr); - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdelswap(arr,i); - arrfree(arr); - } + for(i = 0; i < 4; ++i) { + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + arrdel(arr, i); + arrfree(arr); + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + arrdelswap(arr, i); + arrfree(arr); + } - for (i=0; i < 5; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - stbds_arrins(arr,i,5); - STBDS_ASSERT(arr[i] == 5); - if (i < 4) - STBDS_ASSERT(arr[4] == 4); - arrfree(arr); - } + for(i = 0; i < 5; ++i) { + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + stbds_arrins(arr, i, 5); + STBDS_ASSERT(arr[i] == 5); + if(i < 4) + STBDS_ASSERT(arr[4] == 4); + arrfree(arr); + } - i = 1; - STBDS_ASSERT(hmgeti(intmap,i) == -1); - hmdefault(intmap, -2); - STBDS_ASSERT(hmgeti(intmap, i) == -1); - STBDS_ASSERT(hmget (intmap, i) == -2); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*5); - for (i=0; i < testsize; i+=1) { - if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 ); - else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5); - } - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=2; i < testsize; i+=4) - hmdel(intmap, i); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=0; i < testsize; i+=1) - hmdel(intmap, i); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(hmget(intmap, i) == -2 ); - hmfree(intmap); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3); - hmfree(intmap); + i = 1; + STBDS_ASSERT(hmgeti(intmap, i) == -1); + hmdefault(intmap, -2); + STBDS_ASSERT(hmgeti(intmap, i) == -1); + STBDS_ASSERT(hmget(intmap, i) == -2); + for(i = 0; i < testsize; i += 2) + hmput(intmap, i, i * 5); + for(i = 0; i < testsize; i += 1) { + if(i & 1) STBDS_ASSERT(hmget(intmap, i) == -2); + else + STBDS_ASSERT(hmget(intmap, i) == i * 5); + if(i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2); + else + STBDS_ASSERT(hmget_ts(intmap, i, temp) == i * 5); + } + for(i = 0; i < testsize; i += 2) + hmput(intmap, i, i * 3); + for(i = 0; i < testsize; i += 1) + if(i & 1) STBDS_ASSERT(hmget(intmap, i) == -2); + else + STBDS_ASSERT(hmget(intmap, i) == i * 3); + for(i = 2; i < testsize; i += 4) + hmdel(intmap, i); // delete half the entries + for(i = 0; i < testsize; i += 1) + if(i & 3) STBDS_ASSERT(hmget(intmap, i) == -2); + else + STBDS_ASSERT(hmget(intmap, i) == i * 3); + for(i = 0; i < testsize; i += 1) + hmdel(intmap, i); // delete the rest of the entries + for(i = 0; i < testsize; i += 1) + STBDS_ASSERT(hmget(intmap, i) == -2); + hmfree(intmap); + for(i = 0; i < testsize; i += 2) + hmput(intmap, i, i * 3); + hmfree(intmap); - #if defined(__clang__) || defined(__GNUC__) - #ifndef __cplusplus - intmap = NULL; - hmput(intmap, 15, 7); - hmput(intmap, 11, 3); - hmput(intmap, 9, 5); - STBDS_ASSERT(hmget(intmap, 9) == 5); - STBDS_ASSERT(hmget(intmap, 11) == 3); - STBDS_ASSERT(hmget(intmap, 15) == 7); - #endif - #endif +#if defined(__clang__) || defined(__GNUC__) +#ifndef __cplusplus + intmap = NULL; + hmput(intmap, 15, 7); + hmput(intmap, 11, 3); + hmput(intmap, 9, 5); + STBDS_ASSERT(hmget(intmap, 9) == 5); + STBDS_ASSERT(hmget(intmap, 11) == 3); + STBDS_ASSERT(hmget(intmap, 15) == 7); +#endif +#endif - for (i=0; i < testsize; ++i) - stralloc(&sa, strkey(i)); - strreset(&sa); + for(i = 0; i < testsize; ++i) + stralloc(&sa, strkey(i)); + strreset(&sa); - { - s.key = "a", s.value = 1; - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key == s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key == s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - { - s.key = "a", s.value = 1; - sh_new_strdup(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + sh_new_strdup(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - { - s.key = "a", s.value = 1; - sh_new_arena(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + sh_new_arena(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - for (j=0; j < 2; ++j) { - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - if (j == 0) - sh_new_strdup(strmap); - else - sh_new_arena(strmap); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - shdefault(strmap, -2); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - for (i=0; i < testsize; i+=2) - shput(strmap, strkey(i), i*3); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=2; i < testsize; i+=4) - shdel(strmap, strkey(i)); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=0; i < testsize; i+=1) - shdel(strmap, strkey(i)); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - shfree(strmap); - } + for(j = 0; j < 2; ++j) { + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + if(j == 0) + sh_new_strdup(strmap); + else + sh_new_arena(strmap); + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + shdefault(strmap, -2); + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + for(i = 0; i < testsize; i += 2) + shput(strmap, strkey(i), i * 3); + for(i = 0; i < testsize; i += 1) + if(i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + else + STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3); + for(i = 2; i < testsize; i += 4) + shdel(strmap, strkey(i)); // delete half the entries + for(i = 0; i < testsize; i += 1) + if(i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + else + STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3); + for(i = 0; i < testsize; i += 1) + shdel(strmap, strkey(i)); // delete the rest of the entries + for(i = 0; i < testsize; i += 1) + STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + shfree(strmap); + } - { - struct { char *key; char value; } *hash = NULL; - char name[4] = "jen"; - shput(hash, "bob" , 'h'); - shput(hash, "sally" , 'e'); - shput(hash, "fred" , 'l'); - shput(hash, "jen" , 'x'); - shput(hash, "doug" , 'o'); + { + struct { + char* key; + char value; + }* hash = NULL; + char name[4] = "jen"; + shput(hash, "bob", 'h'); + shput(hash, "sally", 'e'); + shput(hash, "fred", 'l'); + shput(hash, "jen", 'x'); + shput(hash, "doug", 'o'); - shput(hash, name , 'l'); - shfree(hash); - } + shput(hash, name, 'l'); + shfree(hash); + } - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmput(map, s, i*5); - } + for(i = 0; i < testsize; i += 2) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + hmput(map, s, i * 5); + } - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3 ,i*4 }; - stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmget(map, s) == 0); - else STBDS_ASSERT(hmget(map, s) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0); - else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5); - //STBDS_ASSERT(hmget(map, t.key) == 0); - } + for(i = 0; i < testsize; i += 1) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + stbds_struct t = {i, i * 2, i * 3 + 1, i * 4}; + if(i & 1) STBDS_ASSERT(hmget(map, s) == 0); + else + STBDS_ASSERT(hmget(map, s) == i * 5); + if(i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0); + else + STBDS_ASSERT(hmget_ts(map, s, temp) == i * 5); + // STBDS_ASSERT(hmget(map, t.key) == 0); + } - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmputs(map2, s); - } - hmfree(map); + for(i = 0; i < testsize; i += 2) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + hmputs(map2, s); + } + hmfree(map); - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3,i*4 }; - stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); - else STBDS_ASSERT(hmgets(map2, s.key).d == i*4); - //STBDS_ASSERT(hmgetp(map2, t.key) == 0); - } - hmfree(map2); + for(i = 0; i < testsize; i += 1) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + stbds_struct t = {i, i * 2, i * 3 + 1, i * 4}; + if(i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); + else + STBDS_ASSERT(hmgets(map2, s.key).d == i * 4); + // STBDS_ASSERT(hmgetp(map2, t.key) == 0); + } + hmfree(map2); - for (i=0; i < testsize; i += 2) { - stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; - hmputs(map3, s); - } - for (i=0; i < testsize; i += 1) { - stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; - stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; - if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0); - else STBDS_ASSERT(hmgets(map3, s.key).d == i*5); - //STBDS_ASSERT(hmgetp(map3, t.key) == 0); - } + for(i = 0; i < testsize; i += 2) { + stbds_struct2 s = {{i, i * 2}, i * 3, i * 4, i * 5}; + hmputs(map3, s); + } + for(i = 0; i < testsize; i += 1) { + stbds_struct2 s = {{i, i * 2}, i * 3, i * 4, i * 5}; + stbds_struct2 t = {{i, i * 2}, i * 3 + 1, i * 4, i * 5}; + if(i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0); + else + STBDS_ASSERT(hmgets(map3, s.key).d == i * 5); + // STBDS_ASSERT(hmgetp(map3, t.key) == 0); + } #endif } #endif - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/external/stb_image.h b/external/stb_image.h index 6eac58c..d4fe98f 100644 --- a/external/stb_image.h +++ b/external/stb_image.h @@ -1,5 +1,5 @@ /* stb_image - v2.30 - public domain image loader - http://nothings.org/stb - no warranty implied; use at your own risk + no warranty implied; use at your own risk Do this: #define STB_IMAGE_IMPLEMENTATION @@ -18,7 +18,7 @@ QUICK NOTES: Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface + avoid problematic images and only need the trivial interface JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) PNG 1/2/4/8/16-bit-per-channel @@ -33,7 +33,7 @@ PNM (PPM and PGM binary only) Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 + http://gist.github.com/urraka/685d9a6340b26b830d49 - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - decode from arbitrary I/O callbacks @@ -68,9 +68,9 @@ RECENT REVISION HISTORY: 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP 2.10 (2016-01-22) avoid warning introduced in 2.09 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED @@ -89,8 +89,8 @@ RECENT REVISION HISTORY: Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) github:urraka (animated gif) Junggon Kim (PNM comments) Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine Simon Breuss (16-bit PNM) @@ -114,12 +114,12 @@ RECENT REVISION HISTORY: Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko github:mosra + Brad Weinberger Matvey Cherevko github:mosra Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] - DO NOT ADD YOUR NAME HERE + DO NOT ADD YOUR NAME HERE - Jacko Dirks + Jacko Dirks To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end @@ -373,18 +373,17 @@ RECENT REVISION HISTORY: #define STBI_VERSION 1 -enum -{ - STBI_default = 0, // only used for desired_channels +enum { + STBI_default = 0, // only used for desired_channels - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 }; #include -typedef unsigned char stbi_uc; +typedef unsigned char stbi_uc; typedef unsigned short stbi_us; #ifdef __cplusplus @@ -410,9 +409,9 @@ extern "C" { typedef struct { - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data + int (*read)(void* user, char* data, int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip)(void* user, int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof)(void* user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; //////////////////////////////////// @@ -420,21 +419,21 @@ typedef struct // 8-bits-per-channel interface // -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc* stbi_load_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF stbi_uc* stbi_load_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc* stbi_load(char const* filename, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF stbi_uc* stbi_load_from_file(FILE* f, int* x, int* y, int* channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +STBIDEF stbi_uc* stbi_load_gif_from_memory(stbi_uc const* buffer, int len, int** delays, int* x, int* y, int* z, int* comp, int req_comp); #endif #ifdef STBI_WINDOWS_UTF8 -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +STBIDEF int stbi_convert_wchar_to_utf8(char* buffer, size_t bufferlen, const wchar_t* input); #endif //////////////////////////////////// @@ -442,12 +441,12 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch // 16-bits-per-channel interface // -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us* stbi_load_16_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF stbi_us* stbi_load_16_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us* stbi_load_16(char const* filename, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF stbi_us* stbi_load_from_file_16(FILE* f, int* x, int* y, int* channels_in_file, int desired_channels); #endif //////////////////////////////////// @@ -455,56 +454,53 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i // float-per-channel interface // #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float* stbi_loadf_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF float* stbi_loadf_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif +#ifndef STBI_NO_STDIO +STBIDEF float* stbi_loadf(char const* filename, int* x, int* y, int* channels_in_file, int desired_channels); +STBIDEF float* stbi_loadf_from_file(FILE* f, int* x, int* y, int* channels_in_file, int desired_channels); +#endif #endif #ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); +STBIDEF void stbi_hdr_to_ldr_scale(float scale); #endif // STBI_NO_HDR #ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); +STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_LINEAR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const* clbk, void* user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const* buffer, int len); #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); +STBIDEF int stbi_is_hdr(char const* filename); +STBIDEF int stbi_is_hdr_from_file(FILE* f); #endif // STBI_NO_STDIO - // get a VERY brief reason for failure // on most compilers (and ALL modern mainstream compilers) this is threadsafe -STBIDEF const char *stbi_failure_reason (void); +STBIDEF const char* stbi_failure_reason(void); // free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); +STBIDEF void stbi_image_free(void* retval_from_stbi_load); // get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_info_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const* buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const* clbk, void* user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); +STBIDEF int stbi_info(char const* filename, int* x, int* y, int* comp); +STBIDEF int stbi_info_from_file(FILE* f, int* x, int* y, int* comp); +STBIDEF int stbi_is_16_bit(char const* filename); +STBIDEF int stbi_is_16_bit_from_file(FILE* f); #endif - - // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. @@ -526,14 +522,13 @@ STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_fli // ZLIB client - used by PNG, available for other purposes -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); +STBIDEF char* stbi_zlib_decode_malloc_guesssize(const char* buffer, int len, int initial_size, int* outlen); +STBIDEF char* stbi_zlib_decode_malloc_guesssize_headerflag(const char* buffer, int len, int initial_size, int* outlen, int parse_header); +STBIDEF char* stbi_zlib_decode_malloc(const char* buffer, int len, int* outlen); +STBIDEF int stbi_zlib_decode_buffer(char* obuffer, int olen, const char* ibuffer, int ilen); +STBIDEF char* stbi_zlib_decode_noheader_malloc(const char* buffer, int len, int* outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char* obuffer, int olen, const char* ibuffer, int ilen); #ifdef __cplusplus } @@ -546,44 +541,40 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #ifdef STB_IMAGE_IMPLEMENTATION -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) || defined(STBI_ONLY_ZLIB) +#ifndef STBI_ONLY_JPEG +#define STBI_NO_JPEG +#endif +#ifndef STBI_ONLY_PNG +#define STBI_NO_PNG +#endif +#ifndef STBI_ONLY_BMP +#define STBI_NO_BMP +#endif +#ifndef STBI_ONLY_PSD +#define STBI_NO_PSD +#endif +#ifndef STBI_ONLY_TGA +#define STBI_NO_TGA +#endif +#ifndef STBI_ONLY_GIF +#define STBI_NO_GIF +#endif +#ifndef STBI_ONLY_HDR +#define STBI_NO_HDR +#endif +#ifndef STBI_ONLY_PIC +#define STBI_NO_PIC +#endif +#ifndef STBI_ONLY_PNM +#define STBI_NO_PNM +#endif #endif #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) #define STBI_NO_ZLIB #endif - #include #include // ptrdiff_t on osx #include @@ -591,7 +582,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp, pow +#include // ldexp, pow #endif #ifndef STBI_NO_STDIO @@ -609,55 +600,54 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_EXTERN extern #endif - #ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif +#ifdef __cplusplus +#define stbi_inline inline #else - #define stbi_inline __forceinline +#define stbi_inline +#endif +#else +#define stbi_inline __forceinline #endif #ifndef STBI_NO_THREAD_LOCALS - #if defined(__cplusplus) && __cplusplus >= 201103L - #define STBI_THREAD_LOCAL thread_local - #elif defined(__GNUC__) && __GNUC__ < 5 - #define STBI_THREAD_LOCAL __thread - #elif defined(_MSC_VER) - #define STBI_THREAD_LOCAL __declspec(thread) - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) - #define STBI_THREAD_LOCAL _Thread_local - #endif +#if defined(__cplusplus) && __cplusplus >= 201103L +#define STBI_THREAD_LOCAL thread_local +#elif defined(__GNUC__) && __GNUC__ < 5 +#define STBI_THREAD_LOCAL __thread +#elif defined(_MSC_VER) +#define STBI_THREAD_LOCAL __declspec(thread) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) +#define STBI_THREAD_LOCAL _Thread_local +#endif - #ifndef STBI_THREAD_LOCAL - #if defined(__GNUC__) - #define STBI_THREAD_LOCAL __thread - #endif - #endif +#ifndef STBI_THREAD_LOCAL +#if defined(__GNUC__) +#define STBI_THREAD_LOCAL __thread +#endif +#endif #endif #if defined(_MSC_VER) || defined(__SYMBIAN32__) || defined(__BORLANDC__) typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; +typedef signed short stbi__int16; typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; +typedef signed int stbi__int32; #else #include typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; +typedef int16_t stbi__int16; typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef int32_t stbi__int32; #endif // should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; +typedef unsigned char validate_uint32[sizeof(stbi__uint32) == 4 ? 1 : -1]; #ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) +#define STBI_NOTUSED(v) (void)(v) #else -#define STBI_NOTUSED(v) (void)sizeof(v) +#define STBI_NOTUSED(v) (void)sizeof(v) #endif #ifdef _MSC_VER @@ -665,9 +655,9 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) +#define stbi_lrot(x, y) _lrotl(x, y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#define stbi_lrot(x, y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -679,13 +669,13 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p, newsz) realloc(p, newsz) +#define STBI_FREE(p) free(p) #endif #ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#define STBI_REALLOC_SIZED(p, oldsz, newsz) STBI_REALLOC(p, newsz) #endif // x86/x64 detection @@ -727,34 +717,31 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef _MSC_VER -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) { + int info[4]; + __cpuid(info, 1); + return info[3]; } #else -static int stbi__cpuid3(void) -{ - int res; - __asm { +static int stbi__cpuid3(void) { + int res; + __asm { mov eax,1 cpuid mov res,edx - } - return res; + } + return res; } #endif #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; +static int stbi__sse2_available(void) { + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; } #endif @@ -762,12 +749,11 @@ static int stbi__sse2_available(void) #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; +static int stbi__sse2_available(void) { + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } #endif @@ -804,187 +790,175 @@ static int stbi__sse2_available(void) // contains all the IO context, plus some basic image information typedef struct { - stbi__uint32 img_x, img_y; - int img_n, img_out_n; + stbi__uint32 img_x, img_y; + int img_n, img_out_n; - stbi_io_callbacks io; - void *io_user_data; + stbi_io_callbacks io; + void* io_user_data; - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - int callback_already_read; + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; } stbi__context; - -static void stbi__refill_buffer(stbi__context *s); +static void stbi__refill_buffer(stbi__context* s); // initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +static void stbi__start_mem(stbi__context* s, stbi_uc const* buffer, int len) { + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc*)buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc*)buffer + len; } // initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; +static void stbi__start_callbacks(stbi__context* s, stbi_io_callbacks* c, void* user) { + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; } #ifndef STBI_NO_STDIO -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); +static int stbi__stdio_read(void* user, char* data, int size) { + return (int)fread(data, 1, size, (FILE*)user); } -static void stbi__stdio_skip(void *user, int n) -{ - int ch; - fseek((FILE*) user, n, SEEK_CUR); - ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ - if (ch != EOF) { - ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ - } +static void stbi__stdio_skip(void* user, int n) { + int ch; + fseek((FILE*)user, n, SEEK_CUR); + ch = fgetc((FILE*)user); /* have to read a byte to reset feof()'s flag */ + if(ch != EOF) { + ungetc(ch, (FILE*)user); /* push byte back onto stream if valid. */ + } } -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user) || ferror((FILE *) user); +static int stbi__stdio_eof(void* user) { + return feof((FILE*)user) || ferror((FILE*)user); } static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, + { + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, }; -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +static void stbi__start_file(stbi__context* s, FILE* f) { + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void*)f); } -//static void stop_file(stbi__context *s) { } +// static void stop_file(stbi__context *s) { } #endif // !STBI_NO_STDIO -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; +static void stbi__rewind(stbi__context* s) { + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; } -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR +enum { + STBI_ORDER_RGB, + STBI_ORDER_BGR }; typedef struct { - int bits_per_channel; - int num_channels; - int channel_order; + int bits_per_channel; + int num_channels; + int channel_order; } stbi__result_info; #ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__jpeg_test(stbi__context* s); +static void* stbi__jpeg_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__jpeg_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); +static int stbi__png_test(stbi__context* s); +static void* stbi__png_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__png_info(stbi__context* s, int* x, int* y, int* comp); +static int stbi__png_is16(stbi__context* s); #endif #ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__bmp_test(stbi__context* s); +static void* stbi__bmp_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__bmp_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__tga_test(stbi__context* s); +static void* stbi__tga_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__tga_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); +static int stbi__psd_test(stbi__context* s); +static void* stbi__psd_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri, int bpc); +static int stbi__psd_info(stbi__context* s, int* x, int* y, int* comp); +static int stbi__psd_is16(stbi__context* s); #endif #ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__hdr_test(stbi__context* s); +static float* stbi__hdr_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__hdr_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pic_test(stbi__context* s); +static void* stbi__pic_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__pic_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__gif_test(stbi__context* s); +static void* stbi__gif_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static void* stbi__load_gif_main(stbi__context* s, int** delays, int* x, int* y, int* z, int* comp, int req_comp); +static int stbi__gif_info(stbi__context* s, int* x, int* y, int* comp); #endif #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__pnm_is16(stbi__context *s); +static int stbi__pnm_test(stbi__context* s); +static void* stbi__pnm_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri); +static int stbi__pnm_info(stbi__context* s, int* x, int* y, int* comp); +static int stbi__pnm_is16(stbi__context* s); #endif static #ifdef STBI_THREAD_LOCAL -STBI_THREAD_LOCAL + STBI_THREAD_LOCAL #endif -const char *stbi__g_failure_reason; + const char* stbi__g_failure_reason; -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; +STBIDEF const char* stbi_failure_reason(void) { + return stbi__g_failure_reason; } #ifndef STBI_NO_FAILURE_STRINGS -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; +static int stbi__err(const char* str) { + stbi__g_failure_reason = str; + return 0; } #endif -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); +static void* stbi__malloc(size_t size) { + return STBI_MALLOC(size); } // stb_image uses ints pervasively, including for offset calculations. @@ -999,88 +973,78 @@ static void *stbi__malloc(size_t size) // return 1 if the sum is valid, 0 on overflow. // negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; +static int stbi__addsizes_valid(int a, int b) { + if(b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; } // returns 1 if the product is valid, 0 on overflow. // negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; +static int stbi__mul2sizes_valid(int a, int b) { + if(a < 0 || b < 0) return 0; + if(b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX / b; } #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +static int stbi__mad2sizes_valid(int a, int b, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a * b, add); } #endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); +static int stbi__mad3sizes_valid(int a, int b, int c, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && + stbi__addsizes_valid(a * b * c, add); } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && + stbi__mul2sizes_valid(a * b * c, d) && stbi__addsizes_valid(a * b * c * d, add); } #endif #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); +static void* stbi__malloc_mad2(int a, int b, int add) { + if(!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a * b + add); } #endif -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); +static void* stbi__malloc_mad3(int a, int b, int c, int add) { + if(!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a * b * c + add); } #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); +static void* stbi__malloc_mad4(int a, int b, int c, int d, int add) { + if(!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a * b * c * d + add); } #endif // returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. -static int stbi__addints_valid(int a, int b) -{ - if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow - if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. - return a <= INT_MAX - b; +static int stbi__addints_valid(int a, int b) { + if((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if(a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; } // returns 1 if the product of two ints fits in a signed short, 0 on overflow. -static int stbi__mul2shorts_valid(int a, int b) -{ - if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow - if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid - if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN - return a >= SHRT_MIN / b; +static int stbi__mul2shorts_valid(int a, int b) { + if(b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if((a >= 0) == (b >= 0)) return a <= SHRT_MAX / b; // product is positive, so similar to mul2sizes_valid + if(b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; } // stbi__err - error @@ -1088,423 +1052,394 @@ static int stbi__mul2shorts_valid(int a, int b) // stbi__errpuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 +#define stbi__err(x, y) 0 #elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) +#define stbi__err(x, y) stbi__err(y) #else - #define stbi__err(x,y) stbi__err(x) +#define stbi__err(x, y) stbi__err(x) #endif -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpf(x, y) ((float*)(size_t)(stbi__err(x, y) ? NULL : NULL)) +#define stbi__errpuc(x, y) ((unsigned char*)(size_t)(stbi__err(x, y) ? NULL : NULL)) -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); +STBIDEF void stbi_image_free(void* retval_from_stbi_load) { + STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static float* stbi__ldr_to_hdr(stbi_uc* data, int x, int y, int comp); #endif #ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +static stbi_uc* stbi__hdr_to_ldr(float* data, int x, int y, int comp); #endif static int stbi__vertically_flip_on_load_global = 0; -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } #ifndef STBI_THREAD_LOCAL -#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global #else static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_local = flag_true_if_should_flip; - stbi__vertically_flip_on_load_set = 1; +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; } -#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ - ? stbi__vertically_flip_on_load_local \ - : stbi__vertically_flip_on_load_global) +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) #endif // STBI_THREAD_LOCAL -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; +static void* stbi__load_main(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri, int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; - // test the formats with a very explicit header first (at least a FOURCC - // or distinctive magic number first) - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #else - STBI_NOTUSED(bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif +// test the formats with a very explicit header first (at least a FOURCC +// or distinctive magic number first) +#ifndef STBI_NO_PNG + if(stbi__png_test(s)) return stbi__png_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_BMP + if(stbi__bmp_test(s)) return stbi__bmp_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_GIF + if(stbi__gif_test(s)) return stbi__gif_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PSD + if(stbi__psd_test(s)) return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc); +#else + STBI_NOTUSED(bpc); +#endif +#ifndef STBI_NO_PIC + if(stbi__pic_test(s)) return stbi__pic_load(s, x, y, comp, req_comp, ri); +#endif - // then the formats that can end up attempting to load with just 1 or 2 - // bytes matching expectations; these are prone to false positives, so - // try them later - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif +// then the formats that can end up attempting to load with just 1 or 2 +// bytes matching expectations; these are prone to false positives, so +// try them later +#ifndef STBI_NO_JPEG + if(stbi__jpeg_test(s)) return stbi__jpeg_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNM + if(stbi__pnm_test(s)) return stbi__pnm_load(s, x, y, comp, req_comp, ri); +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif +#ifndef STBI_NO_HDR + if(stbi__hdr_test(s)) { + float* hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } +#endif - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif +#ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if(stbi__tga_test(s)) + return stbi__tga_load(s, x, y, comp, req_comp, ri); +#endif - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; +static stbi_uc* stbi__convert_16_to_8(stbi__uint16* orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi_uc* reduced; - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + reduced = (stbi_uc*)stbi__malloc(img_len); + if(reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + for(i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - STBI_FREE(orig); - return reduced; + STBI_FREE(orig); + return reduced; } -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; +static stbi__uint16* stbi__convert_8_to_16(stbi_uc* orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi__uint16* enlarged; - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + enlarged = (stbi__uint16*)stbi__malloc(img_len * 2); + if(enlarged == NULL) return (stbi__uint16*)stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + for(i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff - STBI_FREE(orig); - return enlarged; + STBI_FREE(orig); + return enlarged; } -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; +static void stbi__vertical_flip(void* image, int w, int h, int bytes_per_pixel) { + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc* bytes = (stbi_uc*)image; - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } + for(row = 0; row < (h >> 1); row++) { + stbi_uc* row0 = bytes + row * bytes_per_row; + stbi_uc* row1 = bytes + (h - row - 1) * bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while(bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } } #ifndef STBI_NO_GIF -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; +static void stbi__vertical_flip_slices(void* image, int w, int h, int z, int bytes_per_pixel) { + int slice; + int slice_size = w * h * bytes_per_pixel; - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } + stbi_uc* bytes = (stbi_uc*)image; + for(slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } } #endif -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); +static unsigned char* stbi__load_and_postprocess_8bit(stbi__context* s, int* x, int* y, int* comp, int req_comp) { + stbi__result_info ri; + void* result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - if (result == NULL) - return NULL; + if(result == NULL) + return NULL; - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - if (ri.bits_per_channel != 8) { - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } + if(ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16*)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } - // @TODO: move stbi__convert_format to here + // @TODO: move stbi__convert_format to here - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } + if(stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } - return (unsigned char *) result; + return (unsigned char*)result; } -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); +static stbi__uint16* stbi__load_and_postprocess_16bit(stbi__context* s, int* x, int* y, int* comp, int req_comp) { + stbi__result_info ri; + void* result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - if (result == NULL) - return NULL; + if(result == NULL) + return NULL; - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - if (ri.bits_per_channel != 16) { - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } + if(ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc*)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } + if(stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } - return (stbi__uint16 *) result; + return (stbi__uint16*)result; } #if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } +static void stbi__float_postprocess(float* result, int* x, int* y, int* comp, int req_comp) { + if(stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } } #endif #ifndef STBI_NO_STDIO -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char* str, int cbmb, wchar_t* widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t* widestr, int cchwide, char* str, int cbmb, const char* defchar, int* used_default); #endif -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char* buffer, size_t bufferlen, const wchar_t* input) { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int)bufferlen, NULL, NULL); } #endif -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) - return 0; +static FILE* stbi__fopen(char const* filename, char const* mode) { + FILE* f; +#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if(0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename) / sizeof(*wFilename))) + return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) - return 0; + if(0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode) / sizeof(*wMode))) + return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) + if(0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else - f = _wfopen(wFilename, wMode); + f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if(0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_uc* stbi_load(char const* filename, int* x, int* y, int* comp, int req_comp) { + FILE* f = stbi__fopen(filename, "rb"); + unsigned char* result; + if(!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi_uc* stbi_load_from_file(FILE* f, int* x, int* y, int* comp, int req_comp) { + unsigned char* result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); + if(result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi__uint16* stbi_load_from_file_16(FILE* f, int* x, int* y, int* comp, int req_comp) { + stbi__uint16* result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_16bit(&s, x, y, comp, req_comp); + if(result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_us* stbi_load_16(char const* filename, int* x, int* y, int* comp, int req_comp) { + FILE* f = stbi__fopen(filename, "rb"); + stbi__uint16* result; + if(!f) return (stbi_us*)stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f, x, y, comp, req_comp); + fclose(f); + return result; } +#endif //! STBI_NO_STDIO -#endif //!STBI_NO_STDIO - -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us* stbi_load_16_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us* stbi_load_16_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)clbk, user); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc* stbi_load_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc* stbi_load_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* comp, int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)clbk, user); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); +STBIDEF stbi_uc* stbi_load_gif_from_memory(stbi_uc const* buffer, int len, int** delays, int* x, int* y, int* z, int* comp, int req_comp) { + unsigned char* result; + stbi__context s; + stbi__start_mem(&s, buffer, len); - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } + result = (unsigned char*)stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if(stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices(result, *x, *y, *z, *comp); + } - return result; + return result; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +static float* stbi__loadf_main(stbi__context* s, int* x, int* y, int* comp, int req_comp) { + unsigned char* data; +#ifndef STBI_NO_HDR + if(stbi__hdr_test(s)) { + stbi__result_info ri; + float* hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri); + if(hdr_data) + stbi__float_postprocess(hdr_data, x, y, comp, req_comp); + return hdr_data; + } +#endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if(data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); } -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float* stbi_loadf_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__loadf_main(&s, x, y, comp, req_comp); } -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float* stbi_loadf_from_callbacks(stbi_io_callbacks const* clbk, void* user, int* x, int* y, int* comp, int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)clbk, user); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF float* stbi_loadf(char const* filename, int* x, int* y, int* comp, int req_comp) { + float* result; + FILE* f = stbi__fopen(filename, "rb"); + if(!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float* stbi_loadf_from_file(FILE* f, int* x, int* y, int* comp, int req_comp) { + stbi__context s; + stbi__start_file(&s, f); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #endif // !STBI_NO_STDIO @@ -1514,220 +1449,213 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_ // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always // reports false! -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const* buffer, int len) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; +#endif } #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; +STBIDEF int stbi_is_hdr(char const* filename) { + FILE* f = stbi__fopen(filename, "rb"); + int result = 0; + if(f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; - stbi__context s; - stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; - #else - STBI_NOTUSED(f); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_file(FILE* f) { +#ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s, f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; +#else + STBI_NOTUSED(f); + return 0; +#endif } #endif // !STBI_NO_STDIO -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const* clbk, void* user) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)clbk, user); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; +#endif } #ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; +static float stbi__l2h_gamma = 2.2f, stbi__l2h_scale = 1.0f; -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { + stbi__l2h_gamma = gamma; +} +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { + stbi__l2h_scale = scale; +} #endif -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +static float stbi__h2l_gamma_i = 1.0f / 2.2f, stbi__h2l_scale_i = 1.0f; +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { + stbi__h2l_gamma_i = 1 / gamma; +} +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { + stbi__h2l_scale_i = 1 / scale; +} ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header +enum { + STBI__SCAN_load = 0, + STBI__SCAN_type, + STBI__SCAN_header }; -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } +static void stbi__refill_buffer(stbi__context* s) { + int n = (s->io.read)(s->io_user_data, (char*)s->buffer_start, s->buflen); + s->callback_already_read += (int)(s->img_buffer - s->img_buffer_original); + if(n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + 1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } } -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; +stbi_inline static stbi_uc stbi__get8(stbi__context* s) { + if(s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if(s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; } #if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } +stbi_inline static int stbi__at_eof(stbi__context* s) { + if(s->io.read) { + if(!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if(s->read_from_callbacks == 0) return 1; + } - return s->img_buffer >= s->img_buffer_end; + return s->img_buffer >= s->img_buffer_end; } #endif #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) // nothing #else -static void stbi__skip(stbi__context *s, int n) -{ - if (n == 0) return; // already there! - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; +static void stbi__skip(stbi__context* s, int n) { + if(n == 0) return; // already there! + if(n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if(s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if(blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) // nothing #else -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; +static int stbi__getn(stbi__context* s, stbi_uc* buffer, int n) { + if(s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if(blen < n) { + int res, count; - memcpy(buffer, s->img_buffer, blen); + memcpy(buffer, s->img_buffer, blen); - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } + count = (s->io.read)(s->io_user_data, (char*)buffer + blen, n - blen); + res = (count == (n - blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; + if(s->img_buffer + n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; } #endif #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) // nothing #else -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); +static int stbi__get16be(stbi__context* s) { + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) // nothing #else -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); +static stbi__uint32 stbi__get32be(stbi__context* s) { + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); } #endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing #else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); +static int stbi__get16le(stbi__context* s) { + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); } #endif #ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - z += (stbi__uint32)stbi__get16le(s) << 16; - return z; +static stbi__uint32 stbi__get32le(stbi__context* s) { + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings +#define STBI__BYTECAST(x) ((stbi_uc)((x) & 255)) // truncate int to byte without warnings #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing @@ -1743,169 +1671,277 @@ static stbi__uint32 stbi__get32le(stbi__context *s) // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +static stbi_uc stbi__compute_y(int r, int g, int b) { + return (stbi_uc)(((r * 77) + (g * 150) + (29 * b)) >> 8); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; +static unsigned char* stbi__convert_format(unsigned char* data, int img_n, int req_comp, unsigned int x, unsigned int y) { + int i, j; + unsigned char* good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if(req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } + good = (unsigned char*)stbi__malloc_mad3(req_comp, x, y, 0); + if(good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; + for(j = 0; j < (int)y; ++j) { + unsigned char* src = data + j * x * img_n; + unsigned char* dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); - } - #undef STBI__CASE - } +#define STBI__COMBO(a, b) ((a) * 8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for(i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch(STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { + dest[0] = src[0]; + dest[1] = 255; + } + break; + STBI__CASE(1, 3) { + dest[0] = dest[1] = dest[2] = src[0]; + } + break; + STBI__CASE(1, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = 255; + } + break; + STBI__CASE(2, 1) { + dest[0] = src[0]; + } + break; + STBI__CASE(2, 3) { + dest[0] = dest[1] = dest[2] = src[0]; + } + break; + STBI__CASE(2, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = src[1]; + } + break; + STBI__CASE(3, 4) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 255; + } + break; + STBI__CASE(3, 1) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + } + break; + STBI__CASE(3, 2) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + dest[1] = 255; + } + break; + STBI__CASE(4, 1) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + } + break; + STBI__CASE(4, 2) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + dest[1] = src[3]; + } + break; + STBI__CASE(4, 3) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + } + break; + default: + STBI_ASSERT(0); + STBI_FREE(data); + STBI_FREE(good); + return stbi__errpuc("unsupported", "Unsupported format conversion"); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { + return (stbi__uint16)(((r * 77) + (g * 150) + (29 * b)) >> 8); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; +static stbi__uint16* stbi__convert_format16(stbi__uint16* data, int img_n, int req_comp, unsigned int x, unsigned int y) { + int i, j; + stbi__uint16* good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if(req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } + good = (stbi__uint16*)stbi__malloc(req_comp * x * y * 2); + if(good == NULL) { + STBI_FREE(data); + return (stbi__uint16*)stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; + for(j = 0; j < (int)y; ++j) { + stbi__uint16* src = data + j * x * img_n; + stbi__uint16* dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); - } - #undef STBI__CASE - } +#define STBI__COMBO(a, b) ((a) * 8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for(i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch(STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { + dest[0] = src[0]; + dest[1] = 0xffff; + } + break; + STBI__CASE(1, 3) { + dest[0] = dest[1] = dest[2] = src[0]; + } + break; + STBI__CASE(1, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = 0xffff; + } + break; + STBI__CASE(2, 1) { + dest[0] = src[0]; + } + break; + STBI__CASE(2, 3) { + dest[0] = dest[1] = dest[2] = src[0]; + } + break; + STBI__CASE(2, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = src[1]; + } + break; + STBI__CASE(3, 4) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 0xffff; + } + break; + STBI__CASE(3, 1) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + } + break; + STBI__CASE(3, 2) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + dest[1] = 0xffff; + } + break; + STBI__CASE(4, 1) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + } + break; + STBI__CASE(4, 2) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + dest[1] = src[3]; + } + break; + STBI__CASE(4, 3) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + } + break; + default: + STBI_ASSERT(0); + STBI_FREE(data); + STBI_FREE(good); + return (stbi__uint16*)stbi__errpuc("unsupported", "Unsupported format conversion"); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - } - if (n < comp) { - for (i=0; i < x*y; ++i) { - output[i*comp + n] = data[i*comp + n]/255.0f; - } - } - STBI_FREE(data); - return output; +static float* stbi__ldr_to_hdr(stbi_uc* data, int x, int y, int comp) { + int i, k, n; + float* output; + if(!data) return NULL; + output = (float*)stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if(output == NULL) { + STBI_FREE(data); + return stbi__errpf("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if(comp & 1) n = comp; + else + n = comp - 1; + for(i = 0; i < x * y; ++i) { + for(k = 0; k < n; ++k) { + output[i * comp + k] = (float)(pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if(n < comp) { + for(i = 0; i < x * y; ++i) { + output[i * comp + n] = data[i * comp + n] / 255.0f; + } + } + STBI_FREE(data); + return output; } #endif #ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; +#define stbi__float2int(x) ((int)(x)) +static stbi_uc* stbi__hdr_to_ldr(float* data, int x, int y, int comp) { + int i, k, n; + stbi_uc* output; + if(!data) return NULL; + output = (stbi_uc*)stbi__malloc_mad3(x, y, comp, 0); + if(output == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if(comp & 1) n = comp; + else + n = comp - 1; + for(i = 0; i < x * y; ++i) { + for(k = 0; k < n; ++k) { + float z = (float)pow(data[i * comp + k] * stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if(z < 0) z = 0; + if(z > 255) z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + if(k < comp) { + float z = data[i * comp + k] * 255 + 0.5f; + if(z < 0) z = 0; + if(z > 255) z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + } + STBI_FREE(data); + return output; } #endif @@ -1933,763 +1969,758 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) #ifndef STBI_NO_JPEG // huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache typedef struct { - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; typedef struct { - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; + stbi__context* s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; + // sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; + // definition of jpeg image component + struct + { + int id; + int h, v; + int tq; + int hd, ha; + int dc_pred; - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; + int x, y, w2, h2; + stbi_uc* data; + void * raw_data, *raw_coeff; + stbi_uc* linebuf; + short* coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; - int scan_n, order[4]; - int restart_interval, todo; + int scan_n, order[4]; + int restart_interval, todo; -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); + // kernels + void (*idct_block_kernel)(stbi_uc* out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc* out, const stbi_uc* y, const stbi_uc* pcb, const stbi_uc* pcr, int count, int step); + stbi_uc* (*resample_row_hv_2_kernel)(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs); } stbi__jpeg; -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0; - unsigned int code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) { - for (j=0; j < count[i]; ++j) { - h->size[k++] = (stbi_uc) (i+1); - if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); - } - } - h->size[k] = 0; +static int stbi__build_huffman(stbi__huffman* h, int* count) { + int i, j, k = 0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for(i = 0; i < 16; ++i) { + for(j = 0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc)(i + 1); + if(k >= 257) return stbi__err("bad size list", "Corrupt JPEG"); + } + } + h->size[k] = 0; - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j = 1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if(h->size[k] == j) { + while(h->size[k] == j) + h->code[k++] = (stbi__uint16)(code++); + if(code - 1 >= (1u << j)) return stbi__err("bad code lengths", "Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16 - j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for(i = 0; i < k; ++i) { + int s = h->size[i]; + if(s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS - s); + int m = 1 << (FAST_BITS - s); + for(j = 0; j < m; ++j) { + h->fast[c + j] = (stbi_uc)i; + } + } + } + return 1; } // build a table that decodes both magnitude and value of small ACs in // one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; +static void stbi__build_fast_ac(stbi__int16* fast_ac, stbi__huffman* h) { + int i; + for(i = 0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if(fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); - } - } - } + if(magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if(k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if(k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16)((k * 256) + (run * 16) + (len + magbits)); + } + } + } } -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); +static void stbi__grow_buffer_unsafe(stbi__jpeg* j) { + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if(b == 0xff) { + int c = stbi__get8(j->s); + while(c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if(c != 0) { + j->marker = (unsigned char)c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while(j->code_bits <= 24); } // (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static const stbi__uint32 stbi__bmask[17] = {0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535}; // decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg* j, stbi__huffman* h) { + unsigned int temp; + int c, k; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if(j->code_bits < 16) stbi__grow_buffer_unsafe(j); - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + k = h->fast[c]; + if(k < 255) { + int s = h->size[k]; + if(s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for(k = FAST_BITS + 1;; ++k) + if(temp < h->maxcode[k]) + break; + if(k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } - if (k > j->code_bits) - return -1; + if(k > j->code_bits) + return -1; - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - if(c < 0 || c >= 256) // symbol id out of bounds! - return -1; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; } // bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing +stbi_inline static int stbi__extend_receive(stbi__jpeg* j, int n) { + unsigned int k; + int sgn; + if(j->code_bits < n) stbi__grow_buffer_unsafe(j); + if(j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & (sgn - 1)); + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg* j, int n) { + unsigned int k; + if(j->code_bits < n) stbi__grow_buffer_unsafe(j); + if(j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; } -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg* j) { + unsigned int k; + if(j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if(j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? -static const stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; +static const stbi_uc stbi__jpeg_dezigzag[64 + 15] = + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63}; // decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; +static int stbi__jpeg_decode_block(stbi__jpeg* j, short data[64], stbi__huffman* hdc, stbi__huffman* hac, stbi__int16* fac, int b, stbi__uint16* dequant) { + int diff, dc, k; + int t; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + if(j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if(t < 0 || t > 15) return stbi__err("bad huffman code", "Corrupt JPEG"); - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); + // 0 all the ac values now so we can do it 32-bits at a time + memset(data, 0, 64 * sizeof(data[0])); - diff = t ? stbi__extend_receive(j, t) : 0; - if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - data[0] = (short) (dc * dequant[0]); + diff = t ? stbi__extend_receive(j, t) : 0; + if(!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if(!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short)(dc * dequant[0]); - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c, r, s; + if(j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if(r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if(s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if(rs < 0) return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if(s == 0) { + if(rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * dequant[zig]); + } + } + } while(k < 64); + return 1; } -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg* j, short data[64], stbi__huffman* hdc, int b) { + int diff, dc; + int t; + if(j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if(j->code_bits < 16) stbi__grow_buffer_unsafe(j); - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - diff = t ? stbi__extend_receive(j, t) : 0; + if(j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data, 0, 64 * sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if(t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; - if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - data[0] = (short) (dc * (1 << j->succ_low)); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; + if(!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if(!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short)(dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if(stbi__jpeg_get_bit(j)) + data[0] += (short)(1 << j->succ_low); + } + return 1; } // @OPTIMIZE: store non-zigzagged during the decode passes, // and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg* j, short data[64], stbi__huffman* hac, stbi__int16* fac) { + int k; + if(j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->succ_high == 0) { - int shift = j->succ_low; + if(j->succ_high == 0) { + int shift = j->succ_low; - if (j->eob_run) { - --j->eob_run; - return 1; - } + if(j->eob_run) { + --j->eob_run; + return 1; + } - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * (1 << shift)); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients + k = j->spec_start; + do { + unsigned int zig; + int c, r, s; + if(j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if(r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if(s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if(rs < 0) return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if(s == 0) { + if(r < 15) { + j->eob_run = (1 << r); + if(r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * (1 << shift)); + } + } + } while(k <= j->spec_end); + } else { + // refinement scan for these AC coefficients - short bit = (short) (1 << j->succ_low); + short bit = (short)(1 << j->succ_low); - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } + if(j->eob_run) { + --j->eob_run; + for(k = j->spec_start; k <= j->spec_end; ++k) { + short* p = &data[stbi__jpeg_dezigzag[k]]; + if(*p != 0) + if(stbi__jpeg_get_bit(j)) + if((*p & bit) == 0) { + if(*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r, s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if(rs < 0) return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if(s == 0) { + if(r < 15) { + j->eob_run = (1 << r) - 1; + if(r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if(s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if(stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; + // advance by r + while(k <= j->spec_end) { + short* p = &data[stbi__jpeg_dezigzag[k++]]; + if(*p != 0) { + if(stbi__jpeg_get_bit(j)) + if((*p & bit) == 0) { + if(*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if(r == 0) { + *p = (short)s; + break; + } + --r; + } + } + } while(k <= j->spec_end); + } + } + return 1; } // take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; +stbi_inline static stbi_uc stbi__clamp(int x) { + // trick to use a single test to catch both cases + if((unsigned int)x > 255) { + if(x < 0) return 0; + if(x > 255) return 255; + } + return (stbi_uc)x; } -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) * 4096) +#define stbi__f2f(x) ((int)(((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) // derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; +#define STBI__IDCT_1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int t0, t1, t2, t3, p1, p2, p3, p4, p5, x0, x1, x2, x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2 + p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3 * stbi__f2f(-1.847759065f); \ + t3 = p1 + p2 * stbi__f2f(0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2 + p3); \ + t1 = stbi__fsh(p2 - p3); \ + x0 = t0 + t3; \ + x3 = t0 - t3; \ + x1 = t1 + t2; \ + x2 = t1 - t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0 + t2; \ + p4 = t1 + t3; \ + p1 = t0 + t3; \ + p2 = t1 + t2; \ + p5 = (p3 + p4) * stbi__f2f(1.175875602f); \ + t0 = t0 * stbi__f2f(0.298631336f); \ + t1 = t1 * stbi__f2f(2.053119869f); \ + t2 = t2 * stbi__f2f(3.072711026f); \ + t3 = t3 * stbi__f2f(1.501321110f); \ + p1 = p5 + p1 * stbi__f2f(-0.899976223f); \ + p2 = p5 + p2 * stbi__f2f(-2.562915447f); \ + p3 = p3 * stbi__f2f(-1.961570560f); \ + p4 = p4 * stbi__f2f(-0.390180644f); \ + t3 += p1 + p4; \ + t2 += p2 + p3; \ + t1 += p2 + p4; \ + t0 += p1 + p3; -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; +static void stbi__idct_block(stbi_uc* out, int out_stride, short data[64]) { + int i, val[64], *v = val; + stbi_uc* o; + short* d = data; - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0]*4; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } + // columns + for(i = 0; i < 8; ++i, ++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if(d[8] == 0 && d[16] == 0 && d[24] == 0 && d[32] == 0 && d[40] == 0 && d[48] == 0 && d[56] == 0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * 4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[0], d[8], d[16], d[24], d[32], d[40], d[48], d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; + x1 += 512; + x2 += 512; + x3 += 512; + v[0] = (x0 + t3) >> 10; + v[56] = (x0 - t3) >> 10; + v[8] = (x1 + t2) >> 10; + v[48] = (x1 - t2) >> 10; + v[16] = (x2 + t1) >> 10; + v[40] = (x2 - t1) >> 10; + v[24] = (x3 + t0) >> 10; + v[32] = (x3 - t0) >> 10; + } + } - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } + for(i = 0, v = val, o = out; i < 8; ++i, v += 8, o += out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128 << 17); + x1 += 65536 + (128 << 17); + x2 += 65536 + (128 << 17); + x3 += 65536 + (128 << 17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0 + t3) >> 17); + o[7] = stbi__clamp((x0 - t3) >> 17); + o[1] = stbi__clamp((x1 + t2) >> 17); + o[6] = stbi__clamp((x1 - t2) >> 17); + o[2] = stbi__clamp((x2 + t1) >> 17); + o[5] = stbi__clamp((x2 - t1) >> 17); + o[3] = stbi__clamp((x3 + t0) >> 17); + o[4] = stbi__clamp((x3 - t0) >> 17); + } } #ifdef STBI_SSE2 // sse2 integer IDCT. not the fastest possible implementation but it // produces bit-identical results to the generic C version so it's // fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; +static void stbi__idct_simd(stbi_uc* out, int out_stride, short data[64]) { + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) +// dot product constant: even elems=x, odd elems=y +#define dct_const(x, y) _mm_setr_epi16((x), (y), (x), (y), (x), (y), (x), (y)) - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) +// out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) +// out(1) = c1[even]*x + c1[odd]*y +#define dct_rot(out0, out1, x, y, c0, c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x), (y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x), (y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) +// out = in << 12 (in 16-bit, out 32-bit) +#define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) +// wide add +#define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) +// wide sub +#define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } +// butterfly a/b, add bias, then shift by "s" and pack +#define dct_bfly32o(out0, out1, a, b, bias, s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) +// 8-bit interleave step (for transposes) +#define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) +// 16-bit interleave step (for transposes) +#define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } +#define dct_pass(bias, shift) \ + { \ + /* even part */ \ + dct_rot(t2e, t3e, row2, row6, rot0_0, rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o, y2o, row7, row3, rot2_0, rot2_1); \ + dct_rot(y1o, y3o, row5, row1, rot3_0, rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o, y5o, sum17, sum35, rot1_0, rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0, row7, x0, x7, bias, shift); \ + dct_bfly32o(row1, row6, x1, x6, bias, shift); \ + dct_bfly32o(row2, row5, x2, x5, bias, shift); \ + dct_bfly32o(row3, row4, x3, x4, bias, shift); \ + } - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f(0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f(0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f(3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f(2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f(1.501321110f)); - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128 << 17)); - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + // load + row0 = _mm_load_si128((const __m128i*)(data + 0 * 8)); + row1 = _mm_load_si128((const __m128i*)(data + 1 * 8)); + row2 = _mm_load_si128((const __m128i*)(data + 2 * 8)); + row3 = _mm_load_si128((const __m128i*)(data + 3 * 8)); + row4 = _mm_load_si128((const __m128i*)(data + 4 * 8)); + row5 = _mm_load_si128((const __m128i*)(data + 5 * 8)); + row6 = _mm_load_si128((const __m128i*)(data + 6 * 8)); + row7 = _mm_load_si128((const __m128i*)(data + 7 * 8)); - // column pass - dct_pass(bias_0, 10); + // column pass + dct_pass(bias_0, 10); - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } - // row pass - dct_pass(bias_1, 17); + // row pass + dct_pass(bias_1, 17); - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } + // store + _mm_storel_epi64((__m128i*)out, p0); + out += out_stride; + _mm_storel_epi64((__m128i*)out, _mm_shuffle_epi32(p0, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i*)out, p2); + out += out_stride; + _mm_storel_epi64((__m128i*)out, _mm_shuffle_epi32(p2, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i*)out, p1); + out += out_stride; + _mm_storel_epi64((__m128i*)out, _mm_shuffle_epi32(p1, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i*)out, p3); + out += out_stride; + _mm_storel_epi64((__m128i*)out, _mm_shuffle_epi32(p3, 0x4e)); + } #undef dct_const #undef dct_rot @@ -2708,198 +2739,235 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) // NEON integer IDCT. should produce bit-identical // results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; +static void stbi__idct_simd(stbi_uc* out, int out_stride, short data[64]) { + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f(0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f(1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f(0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f(2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f(3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f(1.501321110f)); #define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) #define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) #define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) // wide add #define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) // wide sub #define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) // butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } +#define dct_bfly32o(out0, out1, a, b, shiftop, s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } #define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0, row7, x0, x7, shiftop, shift); \ + dct_bfly32o(row1, row6, x1, x6, shiftop, shift); \ + dct_bfly32o(row2, row5, x2, x5, shiftop, shift); \ + dct_bfly32o(row3, row4, x3, x4, shiftop, shift); \ + } - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); + // load + row0 = vld1q_s16(data + 0 * 8); + row1 = vld1q_s16(data + 1 * 8); + row2 = vld1q_s16(data + 2 * 8); + row3 = vld1q_s16(data + 3 * 8); + row4 = vld1q_s16(data + 4 * 8); + row5 = vld1q_s16(data + 5 * 8); + row6 = vld1q_s16(data + 6 * 8); + row7 = vld1q_s16(data + 7 * 8); - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - // column pass - dct_pass(vrshrn_n_s32, 10); + // column pass + dct_pass(vrshrn_n_s32, 10); - // 16bit 8x8 transpose - { + // 16bit 8x8 transpose + { // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. // whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } +#define dct_trn16(x, y) \ + { \ + int16x8x2_t t = vtrnq_s16(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn32(x, y) \ + { \ + int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); \ + x = vreinterpretq_s16_s32(t.val[0]); \ + y = vreinterpretq_s16_s32(t.val[1]); \ + } +#define dct_trn64(x, y) \ + { \ + int16x8_t x0 = x; \ + int16x8_t y0 = y; \ + x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); \ + y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); \ + } - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); #undef dct_trn16 #undef dct_trn32 #undef dct_trn64 - } + } - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) \ + { \ + uint8x8x2_t t = vtrn_u8(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn8_16(x, y) \ + { \ + uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); \ + x = vreinterpret_u8_u16(t.val[0]); \ + y = vreinterpret_u8_u16(t.val[1]); \ + } +#define dct_trn8_32(x, y) \ + { \ + uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); \ + x = vreinterpret_u8_u32(t.val[0]); \ + y = vreinterpret_u8_u32(t.val[1]); \ + } - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); + // store + vst1_u8(out, p0); + out += out_stride; + vst1_u8(out, p1); + out += out_stride; + vst1_u8(out, p2); + out += out_stride; + vst1_u8(out, p3); + out += out_stride; + vst1_u8(out, p4); + out += out_stride; + vst1_u8(out, p5); + out += out_stride; + vst1_u8(out, p6); + out += out_stride; + vst1_u8(out, p7); #undef dct_trn8_8 #undef dct_trn8_16 #undef dct_trn8_32 - } + } #undef dct_long_mul #undef dct_long_mac @@ -2912,1169 +2980,1198 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) #endif // STBI_NEON -#define STBI__MARKER_none 0xff +#define STBI__MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; +static stbi_uc stbi__get_marker(stbi__jpeg* j) { + stbi_uc x; + if(j->marker != STBI__MARKER_none) { + x = j->marker; + j->marker = STBI__MARKER_none; + return x; + } + x = stbi__get8(j->s); + if(x != 0xff) return STBI__MARKER_none; + while(x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, stbi__jpeg_reset the entropy decoder and // the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels +static void stbi__jpeg_reset(stbi__jpeg* j) { + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels } -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } +static int stbi__parse_entropy_coded_data(stbi__jpeg* z) { + stbi__jpeg_reset(z); + if(!z->progressive) { + if(z->scan_n == 1) { + int i, j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for(j = 0; j < h; ++j) { + for(i = 0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if(!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if(--z->todo <= 0) { + if(z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if(!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + STBI_SIMD_ALIGN(short, data[64]); + for(j = 0; j < z->img_mcu_y; ++j) { + for(i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for(k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for(y = 0; y < z->img_comp[n].v; ++y) { + for(x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x) * 8; + int y2 = (j * z->img_comp[n].v + y) * 8; + int ha = z->img_comp[n].ha; + if(!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * y2 + x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if(--z->todo <= 0) { + if(z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if(!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if(z->scan_n == 1) { + int i, j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for(j = 0; j < h; ++j) { + for(i = 0; i < w; ++i) { + short* data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if(z->spec_start == 0) { + if(!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if(!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if(--z->todo <= 0) { + if(z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if(!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + for(j = 0; j < z->img_mcu_y; ++j) { + for(i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for(k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for(y = 0; y < z->img_comp[n].v; ++y) { + for(x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x); + int y2 = (j * z->img_comp[n].v + y); + short* data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if(!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if(--z->todo <= 0) { + if(z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if(!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } } -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; +static void stbi__jpeg_dequantize(short* data, stbi__uint16* dequant) { + int i; + for(i = 0; i < 64; ++i) + data[i] *= dequant[i]; } -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } +static void stbi__jpeg_finish(stbi__jpeg* z) { + if(z->progressive) { + // dequantize and idct the data + int i, j, n; + for(n = 0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for(j = 0; j < h; ++j) { + for(i = 0; i < w; ++i) { + short* data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, data); + } + } + } + } } -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); +static int stbi__process_marker(stbi__jpeg* z, int m) { + int L; + switch(m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker", "Corrupt JPEG"); - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; + case 0xDD: // DRI - specify restart interval + if(stbi__get16be(z->s) != 4) return stbi__err("bad DRI len", "Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s) - 2; + while(L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15, i; + if(p != 0 && p != 1) return stbi__err("bad DQT type", "Corrupt JPEG"); + if(t > 3) return stbi__err("bad DQT table", "Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; + for(i = 0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L == 0; - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s) - 2; + while(L > 0) { + stbi_uc* v; + int sizes[16], i, n = 0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if(tc > 1 || th > 3) return stbi__err("bad DHT header", "Corrupt JPEG"); + for(i = 0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header", "Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if(tc == 0) { + if(!stbi__build_huffman(z->huff_dc + th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if(!stbi__build_huffman(z->huff_ac + th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for(i = 0; i < n; ++i) + v[i] = stbi__get8(z->s); + if(tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L == 0; + } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; + // check for comment block or APP blocks + if((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if(L < 2) { + if(m == 0xFE) + return stbi__err("bad COM len", "Corrupt JPEG"); + else + return stbi__err("bad APP len", "Corrupt JPEG"); + } + L -= 2; - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } + if(m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J', 'F', 'I', 'F', '\0'}; + int ok = 1; + int i; + for(i = 0; i < 5; ++i) + if(stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if(ok) + z->jfif = 1; + } else if(m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A', 'd', 'o', 'b', 'e', '\0'}; + int ok = 1; + int i; + for(i = 0; i < 6; ++i) + if(stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if(ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } - stbi__skip(z->s, L); - return 1; - } + stbi__skip(z->s, L); + return 1; + } - return stbi__err("unknown marker","Corrupt JPEG"); + return stbi__err("unknown marker", "Corrupt JPEG"); } // after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } +static int stbi__process_scan_header(stbi__jpeg* z) { + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if(z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int)z->s->img_n) return stbi__err("bad SOS component count", "Corrupt JPEG"); + if(Ls != 6 + 2 * z->scan_n) return stbi__err("bad SOS len", "Corrupt JPEG"); + for(i = 0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for(which = 0; which < z->s->img_n; ++which) + if(z->img_comp[which].id == id) + break; + if(which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; + if(z->img_comp[which].hd > 3) return stbi__err("bad DC huff", "Corrupt JPEG"); + z->img_comp[which].ha = q & 15; + if(z->img_comp[which].ha > 3) return stbi__err("bad AC huff", "Corrupt JPEG"); + z->order[i] = which; + } - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if(z->progressive) { + if(z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if(z->spec_start != 0) return stbi__err("bad SOS", "Corrupt JPEG"); + if(z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS", "Corrupt JPEG"); + z->spec_end = 63; + } + } - return 1; + return 1; } -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; +static int stbi__free_jpeg_components(stbi__jpeg* z, int ncomp, int why) { + int i; + for(i = 0; i < ncomp; ++i) { + if(z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if(z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if(z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; } -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } +static int stbi__process_frame_header(stbi__jpeg* z, int scan) { + stbi__context* s = z->s; + int Lf, p, i, q, h_max = 1, v_max = 1, c; + Lf = stbi__get16be(s); + if(Lf < 11) return stbi__err("bad SOF len", "Corrupt JPEG"); // JPEG + p = stbi__get8(s); + if(p != 8) return stbi__err("only 8-bit", "JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); + if(s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); + if(s->img_x == 0) return stbi__err("0 width", "Corrupt JPEG"); // JPEG requires + if(s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); + if(s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); + c = stbi__get8(s); + if(c != 3 && c != 1 && c != 4) return stbi__err("bad component count", "Corrupt JPEG"); + s->img_n = c; + for(i = 0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + if(Lf != 8 + 3 * s->img_n) return stbi__err("bad SOF len", "Corrupt JPEG"); - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } + z->rgb = 0; + for(i = 0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = {'R', 'G', 'B'}; + z->img_comp[i].id = stbi__get8(s); + if(s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); + if(!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H", "Corrupt JPEG"); + z->img_comp[i].v = q & 15; + if(!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V", "Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); + if(z->img_comp[i].tq > 3) return stbi__err("bad TQ", "Corrupt JPEG"); + } - if (scan != STBI__SCAN_load) return 1; + if(scan != STBI__SCAN_load) return 1; - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + if(!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } + for(i = 0; i < s->img_n; ++i) { + if(z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if(z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } - // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios - // and I've never seen a non-corrupted JPEG file actually use them - for (i=0; i < s->img_n; ++i) { - if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); - if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); - } + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for(i = 0; i < s->img_n; ++i) { + if(h_max % z->img_comp[i].h != 0) return stbi__err("bad H", "Corrupt JPEG"); + if(v_max % z->img_comp[i].v != 0) return stbi__err("bad V", "Corrupt JPEG"); + } - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w - 1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h - 1) / z->img_mcu_h; - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } + for(i = 0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max - 1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max - 1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if(z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*)(((size_t)z->img_comp[i].raw_data + 15) & ~15); + if(z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if(z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*)(((size_t)z->img_comp[i].raw_coeff + 15) & ~15); + } + } - return 1; + return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) -#define stbi__SOF_progressive(x) ((x) == 0xc2) +#define stbi__SOF_progressive(x) ((x) == 0xc2) -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; +static int stbi__decode_jpeg_header(stbi__jpeg* z, int scan) { + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if(!stbi__SOI(m)) return stbi__err("no SOI", "Corrupt JPEG"); + if(scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while(!stbi__SOF(m)) { + if(!stbi__process_marker(z, m)) return 0; + m = stbi__get_marker(z); + while(m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if(stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if(!stbi__process_frame_header(z, scan)) return 0; + return 1; } -static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) -{ - // some JPEGs have junk at end, skip over it but if we find what looks - // like a valid marker, resume there - while (!stbi__at_eof(j->s)) { - stbi_uc x = stbi__get8(j->s); - while (x == 0xff) { // might be a marker - if (stbi__at_eof(j->s)) return STBI__MARKER_none; - x = stbi__get8(j->s); - if (x != 0x00 && x != 0xff) { - // not a stuffed zero or lead-in to another marker, looks - // like an actual marker, return it - return x; - } - // stuffed zero has x=0 now which ends the loop, meaning we go - // back to regular scan loop. - // repeated 0xff keeps trying to read the next byte of the marker. - } - } - return STBI__MARKER_none; +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg* j) { + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while(!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while(x == 0xff) { // might be a marker + if(stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if(x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; } // decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - j->marker = stbi__skip_jpeg_junk_at_end(j); - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - m = stbi__get_marker(j); - if (STBI__RESTART(m)) - m = stbi__get_marker(j); - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - m = stbi__get_marker(j); - } else { - if (!stbi__process_marker(j, m)) return 1; - m = stbi__get_marker(j); - } - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; +static int stbi__decode_jpeg_image(stbi__jpeg* j) { + int m; + for(m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if(!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while(!stbi__EOI(m)) { + if(stbi__SOS(m)) { + if(!stbi__process_scan_header(j)) return 0; + if(!stbi__parse_entropy_coded_data(j)) return 0; + if(j->marker == STBI__MARKER_none) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if(STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if(stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if(Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if(NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if(!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if(j->progressive) + stbi__jpeg_finish(j); + return 1; } // static jfif-centered resampling (across block boundaries) -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); +typedef stbi_uc* (*resample_row_func)(stbi_uc* out, stbi_uc* in0, stbi_uc* in1, + int w, int hs); -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) +#define stbi__div4(x) ((stbi_uc)((x) >> 2)) -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; +static stbi_uc* resample_row_1(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; } -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; +static stbi_uc* stbi__resample_row_v_2(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for(i = 0; i < w; ++i) + out[i] = stbi__div4(3 * in_near[i] + in_far[i] + 2); + return out; } -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; +static stbi_uc* stbi__resample_row_h_2(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + // need to generate two samples horizontally for every one in input + int i; + stbi_uc* input = in_near; - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } + if(w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; + out[0] = input[0]; + out[1] = stbi__div4(input[0] * 3 + input[1] + 2); + for(i = 1; i < w - 1; ++i) { + int n = 3 * input[i] + 2; + out[i * 2 + 0] = stbi__div4(n + input[i - 1]); + out[i * 2 + 1] = stbi__div4(n + input[i + 1]); + } + out[i * 2 + 0] = stbi__div4(input[w - 2] * 3 + input[w - 1] + 2); + out[i * 2 + 1] = input[w - 1]; - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); - return out; + return out; } -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) +#define stbi__div16(x) ((stbi_uc)((x) >> 4)) -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } +static stbi_uc* stbi__resample_row_hv_2(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i, t0, t1; + if(w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + t1 = 3 * in_near[0] + in_far[0]; + out[0] = stbi__div4(t1 + 2); + for(i = 1; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; +static stbi_uc* stbi__resample_row_hv_2_simd(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i = 0, t0, t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } + if(w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { + t1 = 3 * in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for(; i < ((w - 1) & ~7); i += 8) { #if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i*)(in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i*)(in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3 * in_near[i + 8] + in_far[i + 8], 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i*)(out + i * 2), outv); #elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3 * in_near[i + 8] + in_far[i + 8], nxt0, 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i * 2, o); #endif - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } + // "previous" value for next iter + t1 = 3 * in_near[i + 7] + in_far[i + 7]; + } - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + for(++i; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #endif -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; +static stbi_uc* stbi__resample_row_generic(stbi_uc* out, stbi_uc* in_near, stbi_uc* in_far, int w, int hs) { + // resample with nearest-neighbor + int i, j; + STBI_NOTUSED(in_far); + for(i = 0; i < w; ++i) + for(j = 0; j < hs; ++j) + out[i * hs + j] = in_near[i]; + return out; } // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } +#define stbi__float2fixed(x) (((int)((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc* out, const stbi_uc* y, const stbi_uc* pcb, const stbi_uc* pcr, int count, int step) { + int i; + for(i = 0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + (cr * -stbi__float2fixed(0.71414f)) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if((unsigned)r > 255) { + if(r < 0) r = 0; + else + r = 255; + } + if((unsigned)g > 255) { + if(g < 0) g = 0; + else + g = 255; + } + if((unsigned)b > 255) { + if(b < 0) b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; +static void stbi__YCbCr_to_RGB_simd(stbi_uc* out, stbi_uc const* y, stbi_uc const* pcb, stbi_uc const* pcr, int count, int step) { + int i = 0; #ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if(step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16((short)(1.40200f * 4096.0f + 0.5f)); + __m128i cr_const1 = _mm_set1_epi16(-(short)(0.71414f * 4096.0f + 0.5f)); + __m128i cb_const0 = _mm_set1_epi16(-(short)(0.34414f * 4096.0f + 0.5f)); + __m128i cb_const1 = _mm_set1_epi16((short)(1.77200f * 4096.0f + 0.5f)); + __m128i y_bias = _mm_set1_epi8((char)(unsigned char)128); + __m128i xw = _mm_set1_epi16(255); // alpha channel - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + for(; i + 7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i*)(y + i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i*)(pcr + i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i*)(pcb + i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } + // store + _mm_storeu_si128((__m128i*)(out + 0), o0); + _mm_storeu_si128((__m128i*)(out + 16), o1); + out += 32; + } + } #endif #ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + // in this version, step=3 support would be easy to add. but is there demand? + if(step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16((short)(1.40200f * 4096.0f + 0.5f)); + int16x8_t cr_const1 = vdupq_n_s16(-(short)(0.71414f * 4096.0f + 0.5f)); + int16x8_t cb_const0 = vdupq_n_s16(-(short)(0.34414f * 4096.0f + 0.5f)); + int16x8_t cb_const1 = vdupq_n_s16((short)(1.77200f * 4096.0f + 0.5f)); - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + for(; i + 7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8 * 4; + } + } #endif - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } + for(; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + cr * -stbi__float2fixed(0.71414f) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if((unsigned)r > 255) { + if(r < 0) r = 0; + else + r = 255; + } + if((unsigned)g > 255) { + if(g < 0) g = 0; + else + g = 255; + } + if((unsigned)b > 255) { + if(b < 0) b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #endif // set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; +static void stbi__setup_jpeg(stbi__jpeg* j) { + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; #ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } + if(stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } #endif #ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } // clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); +static void stbi__cleanup_jpeg(stbi__jpeg* j) { + stbi__free_jpeg_components(j, j->s->img_n, 0); } typedef struct { - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on + resample_row_func resample; + stbi_uc * line0, *line1; + int hs, vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on } stbi__resample; // fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { + unsigned int t = x * y + 128; + return (stbi_uc)((t + (t >> 8)) >> 8); } -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe +static stbi_uc* load_jpeg_image(stbi__jpeg* z, int* out_x, int* out_y, int* comp, int req_comp) { + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + // validate req_comp + if(req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + // load a jpeg image from whichever source, but leave in YCbCr format + if(!stbi__decode_jpeg_image(z)) { + stbi__cleanup_jpeg(z); + return NULL; + } - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 + : 1; - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; + if(z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; - // nothing to do if no components requested; check this now to avoid - // accessing uninitialized coutput[0] later - if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if(decode_n <= 0) { + stbi__cleanup_jpeg(z); + return NULL; + } - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + // resample and color-convert + { + int k; + unsigned int i, j; + stbi_uc* output; + stbi_uc* coutput[4] = {NULL, NULL, NULL, NULL}; - stbi__resample res_comp[4]; + stbi__resample res_comp[4]; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; + for(k = 0; k < decode_n; ++k) { + stbi__resample* r = &res_comp[k]; - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc*)stbi__malloc(z->s->img_x + 3); + if(!z->img_comp[k].linebuf) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs - 1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } + if(r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if(r->hs == 1 && r->vs == 2) + r->resample = stbi__resample_row_v_2; + else if(r->hs == 2 && r->vs == 1) + r->resample = stbi__resample_row_h_2; + else if(r->hs == 2 && r->vs == 2) + r->resample = z->resample_row_hv_2_kernel; + else + r->resample = stbi__resample_row_generic; + } - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + // can't error after this so, this is safe + output = (stbi_uc*)stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if(!output) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } - } - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } + // now go ahead and resample + for(j = 0; j < z->s->img_y; ++j) { + stbi_uc* out = output + n * z->s->img_x * j; + for(k = 0; k < decode_n; ++k) { + stbi__resample* r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if(++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if(++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if(n >= 3) { + stbi_uc* y = coutput[0]; + if(z->s->img_n == 3) { + if(is_rgb) { + for(i = 0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if(z->s->img_n == 4) { + if(z->app14_color_transform == 0) { // CMYK + for(i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if(z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for(i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for(i = 0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if(is_rgb) { + if(n == 1) + for(i = 0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for(i = 0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if(z->s->img_n == 4 && z->app14_color_transform == 0) { + for(i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if(z->s->img_n == 4 && z->app14_color_transform == 2) { + for(i = 0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc* y = coutput[0]; + if(n == 1) + for(i = 0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for(i = 0; i < z->s->img_x; ++i) { + *out++ = y[i]; + *out++ = 255; + } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if(comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } } -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__errpuc("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; +static void* stbi__jpeg_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if(!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x, y, comp, req_comp); + STBI_FREE(j); + return result; } -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__err("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; +static int stbi__jpeg_test(stbi__context* s) { + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if(!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; } -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; +static int stbi__jpeg_info_raw(stbi__jpeg* j, int* x, int* y, int* comp) { + if(!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind(j->s); + return 0; + } + if(x) *x = j->s->img_x; + if(y) *y = j->s->img_y; + if(comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; } -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - if (!j) return stbi__err("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; +static int stbi__jpeg_info(stbi__context* s, int* x, int* y, int* comp) { + int result; + stbi__jpeg* j = (stbi__jpeg*)(stbi__malloc(sizeof(stbi__jpeg))); + if(!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; } #endif @@ -4088,84 +4185,81 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_ZLIB // fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) #define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) typedef struct { - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[STBI__ZNSYMS]; - stbi__uint16 value[STBI__ZNSYMS]; + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; +stbi_inline static int stbi__bitreverse16(int n) { + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; } -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); +stbi_inline static int stbi__bit_reverse(int v, int bits) { + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16 - bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; +static int stbi__zbuild_huffman(stbi__zhuffman* z, const stbi_uc* sizelist, int num) { + int i, k = 0; + int code, next_code[16], sizes[17]; - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for(i = 0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for(i = 1; i < 16; ++i) + if(sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for(i = 1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16)code; + z->firstsymbol[i] = (stbi__uint16)k; + code = (code + sizes[i]); + if(sizes[i]) + if(code - 1 >= (1 << i)) return stbi__err("bad codelengths", "Corrupt PNG"); + z->maxcode[i] = code << (16 - i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for(i = 0; i < num; ++i) { + int s = sizelist[i]; + if(s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16)((s << 9) | i); + z->size[c] = (stbi_uc)s; + z->value[c] = (stbi__uint16)i; + if(s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s], s); + while(j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; } // zlib-from-memory implementation for PNG reading @@ -4176,295 +4270,289 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int typedef struct { - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - int hit_zeof_once; - stbi__uint32 code_buffer; + stbi_uc * zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; + char* zout; + char* zout_start; + char* zout_end; + int z_expandable; - stbi__zhuffman z_length, z_distance; + stbi__zhuffman z_length, z_distance; } stbi__zbuf; -stbi_inline static int stbi__zeof(stbi__zbuf *z) -{ - return (z->zbuffer >= z->zbuffer_end); +stbi_inline static int stbi__zeof(stbi__zbuf* z) { + return (z->zbuffer >= z->zbuffer_end); } -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - return stbi__zeof(z) ? 0 : *z->zbuffer++; +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf* z) { + return stbi__zeof(z) ? 0 : *z->zbuffer++; } -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - if (z->code_buffer >= (1U << z->num_bits)) { - z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ - return; - } - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); +static void stbi__fill_bits(stbi__zbuf* z) { + do { + if(z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int)stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while(z->num_bits <= 24); } -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf* z, int n) { + unsigned int k; + if(z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; } -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s >= 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! - if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; +static int stbi__zhuffman_decode_slowpath(stbi__zbuf* a, stbi__zhuffman* z) { + int b, s, k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for(s = STBI__ZFAST_BITS + 1;; ++s) + if(k < z->maxcode[s]) + break; + if(s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s]; + if(b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if(z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; } -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) { - if (stbi__zeof(a)) { - if (!a->hit_zeof_once) { - // This is the first time we hit eof, insert 16 extra padding btis - // to allow us to keep going; if we actually consume any of them - // though, that is invalid data. This is caught later. - a->hit_zeof_once = 1; - a->num_bits += 16; // add 16 implicit zero bits - } else { - // We already inserted our extra 16 padding bits and are again - // out, this stream is actually prematurely terminated. - return -1; - } - } else { - stbi__fill_bits(a); - } - } - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf* a, stbi__zhuffman* z) { + int b, s; + if(a->num_bits < 16) { + if(stbi__zeof(a)) { + if(!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if(b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); } -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +static int stbi__zexpand(stbi__zbuf* z, char* zout, int n) // need to make room for n bytes { - char *q; - unsigned int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (unsigned int) (z->zout - z->zout_start); - limit = old_limit = (unsigned) (z->zout_end - z->zout_start); - if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); - while (cur + n > limit) { - if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); - limit *= 2; - } - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; + char* q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if(!z->z_expandable) return stbi__err("output buffer limit", "Corrupt PNG"); + cur = (unsigned int)(z->zout - z->zout_start); + limit = old_limit = (unsigned)(z->zout_end - z->zout_start); + if(UINT_MAX - cur < (unsigned)n) return stbi__err("outofmem", "Out of memory"); + while(cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char*)STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if(q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; } static const int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; -static const int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; +static const int stbi__zlength_extra[31] = + {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; +static const int stbi__zdist_base[32] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - if (a->hit_zeof_once && a->num_bits < 16) { - // The first time we hit zeof, we inserted 16 extra zero bits into our bit - // buffer so the decoder can just do its speculative decoding. But if we - // actually consumed any of those bits (which is the case when num_bits < 16), - // the stream actually read past the end so it is malformed. - return stbi__err("unexpected end","Corrupt PNG"); - } - return 1; - } - if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (len > a->zout_end - zout) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } +static int stbi__parse_huffman_block(stbi__zbuf* a) { + char* zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if(z < 256) { + if(z < 0) return stbi__err("bad huffman code", "Corrupt PNG"); // error in huffman codes + if(zout >= a->zout_end) { + if(!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char)z; + } else { + stbi_uc* p; + int len, dist; + if(z == 256) { + a->zout = zout; + if(a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end", "Corrupt PNG"); + } + return 1; + } + if(z >= 286) return stbi__err("bad huffman code", "Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if(stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if(z < 0 || z >= 30) return stbi__err("bad huffman code", "Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if(stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if(zout - a->zout_start < dist) return stbi__err("bad dist", "Corrupt PNG"); + if(len > a->zout_end - zout) { + if(!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc*)(zout - dist); + if(dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if(len) { + do *zout++ = v; + while(--len); + } + } else { + if(len) { + do *zout++ = *p++; + while(--len); + } + } + } + } } -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; +static int stbi__compute_huffman_codes(stbi__zbuf* a) { + static const stbi_uc length_dezigzag[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286 + 32 + 137]; // padding for maximum single op + stbi_uc codelength_sizes[19]; + int i, n; - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; + int hlit = stbi__zreceive(a, 5) + 257; + int hdist = stbi__zreceive(a, 5) + 1; + int hclen = stbi__zreceive(a, 4) + 4; + int ntot = hlit + hdist; - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for(i = 0; i < hclen; ++i) { + int s = stbi__zreceive(a, 3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc)s; + } + if(!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - } else if (c == 18) { - c = stbi__zreceive(a,7)+11; - } else { - return stbi__err("bad codelengths", "Corrupt PNG"); - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; + n = 0; + while(n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if(c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if(c < 16) + lencodes[n++] = (stbi_uc)c; + else { + stbi_uc fill = 0; + if(c == 16) { + c = stbi__zreceive(a, 2) + 3; + if(n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n - 1]; + } else if(c == 17) { + c = stbi__zreceive(a, 3) + 3; + } else if(c == 18) { + c = stbi__zreceive(a, 7) + 11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if(ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes + n, fill, c); + n += c; + } + } + if(n != ntot) return stbi__err("bad codelengths", "Corrupt PNG"); + if(!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if(!stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist)) return 0; + return 1; } -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; +static int stbi__parse_uncompressed_block(stbi__zbuf* a) { + stbi_uc header[4]; + int len, nlen, k; + if(a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while(a->num_bits > 0) { + header[k++] = (stbi_uc)(a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if(a->num_bits < 0) return stbi__err("zlib corrupt", "Corrupt PNG"); + // now fill header the normal way + while(k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if(nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt", "Corrupt PNG"); + if(a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer", "Corrupt PNG"); + if(a->zout + len > a->zout_end) + if(!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; } -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; +static int stbi__parse_zlib_header(stbi__zbuf* a) { + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if(stbi__zeof(a)) return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if((cmf * 256 + flg) % 31 != 0) return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if(flg & 32) return stbi__err("no preset dict", "Corrupt PNG"); // preset dictionary not allowed in png + if(cm != 8) return stbi__err("bad compression", "Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; } static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; + { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}; static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; + { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; /* Init algorithm: { @@ -4478,118 +4566,110 @@ Init algorithm: } */ -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - a->hit_zeof_once = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; +static int stbi__parse_zlib(stbi__zbuf* a, int parse_header) { + int final, type; + if(parse_header) + if(!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a, 1); + type = stbi__zreceive(a, 2); + if(type == 0) { + if(!stbi__parse_uncompressed_block(a)) return 0; + } else if(type == 3) { + return 0; + } else { + if(type == 1) { + // use fixed code lengths + if(!stbi__zbuild_huffman(&a->z_length, stbi__zdefault_length, STBI__ZNSYMS)) return 0; + if(!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if(!stbi__compute_huffman_codes(a)) return 0; + } + if(!stbi__parse_huffman_block(a)) return 0; + } + } while(!final); + return 1; } -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; +static int stbi__do_zlib(stbi__zbuf* a, char* obuf, int olen, int exp, int parse_header) { + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; - return stbi__parse_zlib(a, parse_header); + return stbi__parse_zlib(a, parse_header); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char* stbi_zlib_decode_malloc_guesssize(const char* buffer, int len, int initial_size, int* outlen) { + stbi__zbuf a; + char* p = (char*)stbi__malloc(initial_size); + if(p == NULL) return NULL; + a.zbuffer = (stbi_uc*)buffer; + a.zbuffer_end = (stbi_uc*)buffer + len; + if(stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if(outlen) *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +STBIDEF char* stbi_zlib_decode_malloc(char const* buffer, int len, int* outlen) { + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char* stbi_zlib_decode_malloc_guesssize_headerflag(const char* buffer, int len, int initial_size, int* outlen, int parse_header) { + stbi__zbuf a; + char* p = (char*)stbi__malloc(initial_size); + if(p == NULL) return NULL; + a.zbuffer = (stbi_uc*)buffer; + a.zbuffer_end = (stbi_uc*)buffer + len; + if(stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if(outlen) *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_buffer(char* obuffer, int olen, char const* ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc*)ibuffer; + a.zbuffer_end = (stbi_uc*)ibuffer + ilen; + if(stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int)(a.zout - a.zout_start); + else + return -1; } -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char* stbi_zlib_decode_noheader_malloc(char const* buffer, int len, int* outlen) { + stbi__zbuf a; + char* p = (char*)stbi__malloc(16384); + if(p == NULL) return NULL; + a.zbuffer = (stbi_uc*)buffer; + a.zbuffer_end = (stbi_uc*)buffer + len; + if(stbi__do_zlib(&a, p, 16384, 1, 0)) { + if(outlen) *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_noheader_buffer(char* obuffer, int olen, const char* ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc*)ibuffer; + a.zbuffer_end = (stbi_uc*)ibuffer + ilen; + if(stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int)(a.zout - a.zout_start); + else + return -1; } #endif @@ -4606,1129 +4686,1171 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char #ifndef STBI_NO_PNG typedef struct { - stbi__uint32 length; - stbi__uint32 type; + stbi__uint32 length; + stbi__uint32 type; } stbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; +static stbi__pngchunk stbi__get_chunk_header(stbi__context* s) { + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; } -static int stbi__check_png_header(stbi__context *s) -{ - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; +static int stbi__check_png_header(stbi__context* s) { + static const stbi_uc png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + int i; + for(i = 0; i < 8; ++i) + if(stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig", "Not a PNG"); + return 1; } typedef struct { - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; + stbi__context* s; + stbi_uc * idata, *expanded, *out; + int depth; } stbi__png; - enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filter used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first + STBI__F_none = 0, + STBI__F_sub = 1, + STBI__F_up = 2, + STBI__F_avg = 3, + STBI__F_paeth = 4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first }; static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub + { + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub }; -static int stbi__paeth(int a, int b, int c) -{ - // This formulation looks very different from the reference in the PNG spec, but is - // actually equivalent and has favorable data dependencies and admits straightforward - // generation of branch-free code, which helps performance significantly. - int thresh = c*3 - (a + b); - int lo = a < b ? a : b; - int hi = a < b ? b : a; - int t0 = (hi <= thresh) ? lo : c; - int t1 = (thresh <= lo) ? hi : t0; - return t1; +static int stbi__paeth(int a, int b, int c) { + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c * 3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; } -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const stbi_uc stbi__depth_scale_table[9] = {0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01}; // adds an extra all-255 alpha channel // dest == src is legal // img_n must be 1 or 3 -static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) -{ - int i; - // must process data backwards since we allow dest==src - if (img_n == 1) { - for (i=x-1; i >= 0; --i) { - dest[i*2+1] = 255; - dest[i*2+0] = src[i]; - } - } else { - STBI_ASSERT(img_n == 3); - for (i=x-1; i >= 0; --i) { - dest[i*4+3] = 255; - dest[i*4+2] = src[i*3+2]; - dest[i*4+1] = src[i*3+1]; - dest[i*4+0] = src[i*3+0]; - } - } +static void stbi__create_png_alpha_expand8(stbi_uc* dest, stbi_uc* src, stbi__uint32 x, int img_n) { + int i; + // must process data backwards since we allow dest==src + if(img_n == 1) { + for(i = x - 1; i >= 0; --i) { + dest[i * 2 + 1] = 255; + dest[i * 2 + 0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for(i = x - 1; i >= 0; --i) { + dest[i * 4 + 3] = 255; + dest[i * 4 + 2] = src[i * 3 + 2]; + dest[i * 4 + 1] = src[i * 3 + 1]; + dest[i * 4 + 0] = src[i * 3 + 0]; + } + } } // create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16 ? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - stbi_uc *filter_buf; - int all_ok = 1; - int k; - int img_n = s->img_n; // copy it into a local for later +static int stbi__create_png_image_raw(stbi__png* a, stbi_uc* raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { + int bytes = (depth == 16 ? 2 : 1); + stbi__context* s = a->s; + stbi__uint32 i, j, stride = x * out_n * bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc* filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; + int output_bytes = out_n * bytes; + int filter_bytes = img_n * bytes; + int width = x; - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n + 1); + a->out = (stbi_uc*)stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if(!a->out) return stbi__err("outofmem", "Out of memory"); - // note: error exits here don't need to clean up a->out individually, - // stbi__do_png always does on error. - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); - img_len = (img_width_bytes + 1) * y; + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if(!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if(!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if(raw_len < img_len) return stbi__err("not enough pixels", "Corrupt PNG"); - // Allocate two scan lines worth of filter workspace buffer. - filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); - if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc*)stbi__malloc_mad2(img_width_bytes, 2, 0); + if(!filter_buf) return stbi__err("outofmem", "Out of memory"); - // Filtering for low-bit-depth images - if (depth < 8) { - filter_bytes = 1; - width = img_width_bytes; - } + // Filtering for low-bit-depth images + if(depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } - for (j=0; j < y; ++j) { - // cur/prior filter buffers alternate - stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; - stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; - stbi_uc *dest = a->out + stride*j; - int nk = width * filter_bytes; - int filter = *raw++; + for(j = 0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc* cur = filter_buf + (j & 1) * img_width_bytes; + stbi_uc* prior = filter_buf + (~j & 1) * img_width_bytes; + stbi_uc* dest = a->out + stride * j; + int nk = width * filter_bytes; + int filter = *raw++; - // check filter type - if (filter > 4) { - all_ok = stbi__err("invalid filter","Corrupt PNG"); - break; - } + // check filter type + if(filter > 4) { + all_ok = stbi__err("invalid filter", "Corrupt PNG"); + break; + } - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; + // if first row, use special filter that doesn't sample previous row + if(j == 0) filter = first_row_filter[filter]; - // perform actual filtering - switch (filter) { - case STBI__F_none: - memcpy(cur, raw, nk); - break; - case STBI__F_sub: - memcpy(cur, raw, filter_bytes); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); - break; - case STBI__F_up: - for (k = 0; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + prior[k]); - break; - case STBI__F_avg: - for (k = 0; k < filter_bytes; ++k) - cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); - break; - case STBI__F_paeth: - for (k = 0; k < filter_bytes; ++k) - cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); - break; - case STBI__F_avg_first: - memcpy(cur, raw, filter_bytes); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); - break; - } + // perform actual filtering + switch(filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for(k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k - filter_bytes]); + break; + case STBI__F_up: + for(k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for(k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k] >> 1)); + for(k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)); + break; + case STBI__F_paeth: + for(k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for(k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k], prior[k - filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for(k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k - filter_bytes] >> 1)); + break; + } - raw += nk; + raw += nk; - // expand decoded bits in cur to dest, also adding an extra alpha channel if desired - if (depth < 8) { - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - stbi_uc *in = cur; - stbi_uc *out = dest; - stbi_uc inb = 0; - stbi__uint32 nsmp = x*img_n; + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if(depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc* in = cur; + stbi_uc* out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x * img_n; - // expand bits to bytes first - if (depth == 4) { - for (i=0; i < nsmp; ++i) { - if ((i & 1) == 0) inb = *in++; - *out++ = scale * (inb >> 4); - inb <<= 4; - } - } else if (depth == 2) { - for (i=0; i < nsmp; ++i) { - if ((i & 3) == 0) inb = *in++; - *out++ = scale * (inb >> 6); - inb <<= 2; - } - } else { - STBI_ASSERT(depth == 1); - for (i=0; i < nsmp; ++i) { - if ((i & 7) == 0) inb = *in++; - *out++ = scale * (inb >> 7); - inb <<= 1; - } - } + // expand bits to bytes first + if(depth == 4) { + for(i = 0; i < nsmp; ++i) { + if((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if(depth == 2) { + for(i = 0; i < nsmp; ++i) { + if((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for(i = 0; i < nsmp; ++i) { + if((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } - // insert alpha=255 values if desired - if (img_n != out_n) - stbi__create_png_alpha_expand8(dest, dest, x, img_n); - } else if (depth == 8) { - if (img_n == out_n) - memcpy(dest, cur, x*img_n); - else - stbi__create_png_alpha_expand8(dest, cur, x, img_n); - } else if (depth == 16) { - // convert the image data from big-endian to platform-native - stbi__uint16 *dest16 = (stbi__uint16*)dest; - stbi__uint32 nsmp = x*img_n; + // insert alpha=255 values if desired + if(img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if(depth == 8) { + if(img_n == out_n) + memcpy(dest, cur, x * img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if(depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16* dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x * img_n; - if (img_n == out_n) { - for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) - *dest16 = (cur[0] << 8) | cur[1]; - } else { - STBI_ASSERT(img_n+1 == out_n); - if (img_n == 1) { - for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { - dest16[0] = (cur[0] << 8) | cur[1]; - dest16[1] = 0xffff; - } - } else { - STBI_ASSERT(img_n == 3); - for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { - dest16[0] = (cur[0] << 8) | cur[1]; - dest16[1] = (cur[2] << 8) | cur[3]; - dest16[2] = (cur[4] << 8) | cur[5]; - dest16[3] = 0xffff; - } - } - } - } - } + if(img_n == out_n) { + for(i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n + 1 == out_n); + if(img_n == 1) { + for(i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for(i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } - STBI_FREE(filter_buf); - if (!all_ok) return 0; + STBI_FREE(filter_buf); + if(!all_ok) return 0; - return 1; + return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); +static int stbi__create_png_image(stbi__png* a, stbi_uc* image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc* final; + int p; + if(!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - if (!final) return stbi__err("outofmem", "Out of memory"); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; + // de-interlacing + final = (stbi_uc*)stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if(!final) return stbi__err("outofmem", "Out of memory"); + for(p = 0; p < 7; ++p) { + int xorig[] = {0, 4, 0, 2, 0, 1, 0}; + int yorig[] = {0, 0, 4, 0, 2, 0, 1}; + int xspc[] = {8, 8, 4, 4, 2, 2, 1}; + int yspc[] = {8, 8, 8, 4, 4, 2, 2}; + int i, j, x, y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p] - 1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p] - 1) / yspc[p]; + if(x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if(!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for(j = 0; j < y; ++j) { + for(i = 0; i < x; ++i) { + int out_y = j * yspc[p] + yorig[p]; + int out_x = i * xspc[p] + xorig[p]; + memcpy(final + out_y * a->s->img_x * out_bytes + out_x * out_bytes, + a->out + (j * x + i) * out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; - return 1; + return 1; } -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static int stbi__compute_transparency(stbi__png* z, stbi_uc tc[3], int out_n) { + stbi__context* s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc* p = z->out; - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if(out_n == 2) { + for(i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for(i = 0; i < pixel_count; ++i) { + if(p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; +static int stbi__compute_transparency16(stbi__png* z, stbi__uint16 tc[3], int out_n) { + stbi__context* s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16* p = (stbi__uint16*)z->out; - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if(out_n == 2) { + for(i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for(i = 0; i < pixel_count; ++i) { + if(p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; +static int stbi__expand_png_palette(stbi__png* a, stbi_uc* palette, int len, int pal_img_n) { + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc * p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (stbi_uc*)stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if(p == NULL) return stbi__err("outofmem", "Out of memory"); - // between here and free(out) below, exitting would leak - temp_out = p; + // between here and free(out) below, exitting would leak + temp_out = p; - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; + if(pal_img_n == 3) { + for(i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p += 3; + } + } else { + for(i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p[3] = palette[n + 3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; - STBI_NOTUSED(len); + STBI_NOTUSED(len); - return 1; + return 1; } static int stbi__unpremultiply_on_load_global = 0; -static int stbi__de_iphone_flag_global = 0; +static int stbi__de_iphone_flag_global = 0; -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_global = flag_true_if_should_convert; +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { + stbi__de_iphone_flag_global = flag_true_if_should_convert; } #ifndef STBI_THREAD_LOCAL -#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global -#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global #else static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; -STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; - stbi__unpremultiply_on_load_set = 1; +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; } -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_local = flag_true_if_should_convert; - stbi__de_iphone_flag_set = 1; +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) { + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; } -#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ - ? stbi__unpremultiply_on_load_local \ - : stbi__unpremultiply_on_load_global) -#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ - ? stbi__de_iphone_flag_local \ - : stbi__de_iphone_flag_global) +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) #endif // STBI_THREAD_LOCAL -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static void stbi__de_iphone(stbi__png* z) { + stbi__context* s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc* p = z->out; - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } + if(s->img_out_n == 3) { // convert bgr to rgb + for(i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if(stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for(i = 0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if(a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = (t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for(i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } } -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) +#define STBI__PNG_TYPE(a, b, c, d) (((unsigned)(a) << 24) + ((unsigned)(b) << 16) + ((unsigned)(c) << 8) + (unsigned)(d)) -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]={0}; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; +static int stbi__parse_png_file(stbi__png* z, int scan, int req_comp) { + stbi_uc palette[1024], pal_img_n = 0; + stbi_uc has_trans = 0, tc[3] = {0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff = 0, idata_limit = 0, i, pal_len = 0; + int first = 1, k, interlace = 0, color = 0, is_iphone = 0; + stbi__context* s = z->s; - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; - if (!stbi__check_png_header(s)) return 0; + if(!stbi__check_png_header(s)) return 0; - if (scan == STBI__SCAN_type) return 1; + if(scan == STBI__SCAN_type) return 1; - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); - s->img_y = stbi__get32be(s); - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - } - // even with SCAN_header, have to scan to see if we have a tRNS - break; - } + for(;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch(c.type) { + case STBI__PNG_TYPE('C', 'g', 'B', 'I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I', 'H', 'D', 'R'): + { + int comp, filter; + if(!first) return stbi__err("multiple IHDR", "Corrupt PNG"); + first = 0; + if(c.length != 13) return stbi__err("bad IHDR len", "Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if(s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); + if(s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); + z->depth = stbi__get8(s); + if(z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only", "PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); + if(color > 6) return stbi__err("bad ctype", "Corrupt PNG"); + if(color == 3 && z->depth == 16) return stbi__err("bad ctype", "Corrupt PNG"); + if(color == 3) pal_img_n = 3; + else if(color & 1) + return stbi__err("bad ctype", "Corrupt PNG"); + comp = stbi__get8(s); + if(comp) return stbi__err("bad comp method", "Corrupt PNG"); + filter = stbi__get8(s); + if(filter) return stbi__err("bad filter method", "Corrupt PNG"); + interlace = stbi__get8(s); + if(interlace > 1) return stbi__err("bad interlace method", "Corrupt PNG"); + if(!s->img_x || !s->img_y) return stbi__err("0-pixel image", "Corrupt PNG"); + if(!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large", "Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } + case STBI__PNG_TYPE('P', 'L', 'T', 'E'): + { + if(first) return stbi__err("first not IHDR", "Corrupt PNG"); + if(c.length > 256 * 3) return stbi__err("invalid PLTE", "Corrupt PNG"); + pal_len = c.length / 3; + if(pal_len * 3 != c.length) return stbi__err("invalid PLTE", "Corrupt PNG"); + for(i = 0; i < pal_len; ++i) { + palette[i * 4 + 0] = stbi__get8(s); + palette[i * 4 + 1] = stbi__get8(s); + palette[i * 4 + 2] = stbi__get8(s); + palette[i * 4 + 3] = 255; + } + break; + } - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. - if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } - if (z->depth == 16) { - for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning - tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n && k < 3; ++k) - tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } + case STBI__PNG_TYPE('t', 'R', 'N', 'S'): + { + if(first) return stbi__err("first not IHDR", "Corrupt PNG"); + if(z->idata) return stbi__err("tRNS after IDAT", "Corrupt PNG"); + if(pal_img_n) { + if(scan == STBI__SCAN_header) { + s->img_n = 4; + return 1; + } + if(pal_len == 0) return stbi__err("tRNS before PLTE", "Corrupt PNG"); + if(c.length > pal_len) return stbi__err("bad tRNS len", "Corrupt PNG"); + pal_img_n = 4; + for(i = 0; i < c.length; ++i) + palette[i * 4 + 3] = stbi__get8(s); + } else { + if(!(s->img_n & 1)) return stbi__err("tRNS with alpha", "Corrupt PNG"); + if(c.length != (stbi__uint32)s->img_n * 2) return stbi__err("bad tRNS len", "Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if(scan == STBI__SCAN_header) { + ++s->img_n; + return 1; + } + if(z->depth == 16) { + for(k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for(k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { - // header scan definitely stops at first IDAT - if (pal_img_n) - s->img_n = pal_img_n; - return 1; - } - if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } + case STBI__PNG_TYPE('I', 'D', 'A', 'T'): + { + if(first) return stbi__err("first not IHDR", "Corrupt PNG"); + if(pal_img_n && !pal_len) return stbi__err("no PLTE", "Corrupt PNG"); + if(scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if(pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if(c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if((int)(ioff + c.length) < (int)ioff) return 0; + if(ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc* p; + if(idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while(ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc*)STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); + if(p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if(!stbi__getn(s, z->idata + ioff, c.length)) return stbi__err("outofdata", "Corrupt PNG"); + ioff += c.length; + break; + } - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - return 1; - } + case STBI__PNG_TYPE('I', 'E', 'N', 'D'): + { + stbi__uint32 raw_len, bpl; + if(first) return stbi__err("first not IHDR", "Corrupt PNG"); + if(scan != STBI__SCAN_load) return 1; + if(z->idata == NULL) return stbi__err("no IDAT", "Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc*)stbi_zlib_decode_malloc_guesssize_headerflag((char*)z->idata, ioff, raw_len, (int*)&raw_len, !is_iphone); + if(z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); + z->idata = NULL; + if((req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n + 1; + else + s->img_out_n = s->img_n; + if(!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if(has_trans) { + if(z->depth == 16) { + if(!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if(!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if(is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if(pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if(req_comp >= 3) s->img_out_n = req_comp; + if(!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if(has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); + z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } + default: + // if critical, fail + if(first) return stbi__err("first not IHDR", "Corrupt PNG"); + if((c.type & (1 << 29)) == 0) { +#ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); +#endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth <= 8) - ri->bits_per_channel = 8; - else if (p->depth == 16) - ri->bits_per_channel = 16; - else - return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; +static void* stbi__do_png(stbi__png* p, int* x, int* y, int* n, int req_comp, stbi__result_info* ri) { + void* result = NULL; + if(req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if(stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if(p->depth <= 8) + ri->bits_per_channel = 8; + else if(p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if(req_comp && req_comp != p->s->img_out_n) { + if(ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char*)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16*)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if(result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if(n) *n = p->s->img_n; + } + STBI_FREE(p->out); + p->out = NULL; + STBI_FREE(p->expanded); + p->expanded = NULL; + STBI_FREE(p->idata); + p->idata = NULL; - return result; + return result; } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); +static void* stbi__png_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + stbi__png p; + p.s = s; + return stbi__do_png(&p, x, y, comp, req_comp, ri); } -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; +static int stbi__png_test(stbi__context* s) { + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; } -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; +static int stbi__png_info_raw(stbi__png* p, int* x, int* y, int* comp) { + if(!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind(p->s); + return 0; + } + if(x) *x = p->s->img_x; + if(y) *y = p->s->img_y; + if(comp) *comp = p->s->img_n; + return 1; } -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); +static int stbi__png_info(stbi__context* s, int* x, int* y, int* comp) { + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); } -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; +static int stbi__png_is16(stbi__context* s) { + stbi__png p; + p.s = s; + if(!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if(p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; } #endif // Microsoft/Windows BMP image #ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; +static int stbi__bmp_test_raw(stbi__context* s) { + int r; + int sz; + if(stbi__get8(s) != 'B') return 0; + if(stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; } -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__bmp_test(stbi__context* s) { + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; } - // returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) { n += 16; z >>= 16; } - if (z >= 0x00100) { n += 8; z >>= 8; } - if (z >= 0x00010) { n += 4; z >>= 4; } - if (z >= 0x00004) { n += 2; z >>= 2; } - if (z >= 0x00002) { n += 1;/* >>= 1;*/ } - return n; +static int stbi__high_bit(unsigned int z) { + int n = 0; + if(z == 0) return -1; + if(z >= 0x10000) { + n += 16; + z >>= 16; + } + if(z >= 0x00100) { + n += 8; + z >>= 8; + } + if(z >= 0x00010) { + n += 4; + z >>= 4; + } + if(z >= 0x00004) { + n += 2; + z >>= 2; + } + if(z >= 0x00002) { + n += 1; /* >>= 1;*/ + } + return n; } -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; +static int stbi__bitcount(unsigned int a) { + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; } // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(unsigned int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { - 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +static int stbi__shiftsigned(unsigned int v, int shift, int bits) { + static unsigned int mul_table[9] = { + 0, + 0xff /*0b11111111*/, + 0x55 /*0b01010101*/, + 0x49 /*0b01001001*/, + 0x11 /*0b00010001*/, + 0x21 /*0b00100001*/, + 0x41 /*0b01000001*/, + 0x81 /*0b10000001*/, + 0x01 /*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, + 0, + 0, + 1, + 0, + 2, + 4, + 6, + 0, + }; + if(shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8 - bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int)((unsigned)v * mul_table[bits]) >> shift_table[bits]; } typedef struct { - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; - int extra_read; + int bpp, offset, hsz; + unsigned int mr, mg, mb, ma, all_a; + int extra_read; } stbi__bmp_data; -static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) -{ - // BI_BITFIELDS specifies masks explicitly, don't override - if (compress == 3) - return 1; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data* info, int compress) { + // BI_BITFIELDS specifies masks explicitly, don't override + if(compress == 3) + return 1; - if (compress == 0) { - if (info->bpp == 16) { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } else if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - // otherwise, use defaults, which is all-0 - info->mr = info->mg = info->mb = info->ma = 0; - } - return 1; - } - return 0; // error + if(compress == 0) { + if(info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if(info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error } -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - info->extra_read = 14; +static void* stbi__bmp_parse_header(stbi__context* s, stbi__bmp_data* info) { + int hsz; + if(stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; - if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + if(info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes - if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - stbi__bmp_set_mask_defaults(info, compress); - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->extra_read += 12; - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - // V4/V5 header - int i; - if (hsz != 108 && hsz != 124) - return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs - stbi__bmp_set_mask_defaults(info, compress); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - } - return (void *) 1; + if(hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if(hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if(stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if(hsz != 12) { + int compress = stbi__get32le(s); + if(compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if(compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if(compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if(hsz == 40 || hsz == 56) { + if(hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if(info->bpp == 16 || info->bpp == 32) { + if(compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if(compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if(info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if(hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if(compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for(i = 0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if(hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void*)1; } +static void* stbi__bmp_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + stbi_uc* out; + unsigned int mr = 0, mg = 0, mb = 0, ma = 0, all_a; + stbi_uc pal[256][4]; + int psize = 0, i, j, width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); + info.all_a = 255; + if(stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set + flip_vertically = ((int)s->img_y) > 0; + s->img_y = abs((int)s->img_y); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); + if(s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); + if(s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; + if(info.hsz == 12) { + if(info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if(info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if(psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256 * 4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if(bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if(info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - info.extra_read - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - info.extra_read - info.hsz) >> 2; - } - if (psize == 0) { - // accept some number of extra bytes after the header, but if the offset points either to before - // the header ends or implies a large amount of extra data, reject the file as malformed - int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); - int header_limit = 1024; // max we actually read is below 256 bytes currently. - int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. - if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { - return stbi__errpuc("bad header", "Corrupt BMP"); - } - // we established that bytes_read_so_far is positive and sensible. - // the first half of this test rejects offsets that are either too small positives, or - // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn - // ensures the number computed in the second half of the test can't overflow. - if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { - return stbi__errpuc("bad offset", "Corrupt BMP"); - } else { - stbi__skip(s, info.offset - bytes_read_so_far); - } - } + if(info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if(req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert - if (info.bpp == 24 && ma == 0xff000000) - s->img_n = 3; - else - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert + // sanity-check size + if(!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); + out = (stbi_uc*)stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if(!out) return stbi__errpuc("outofmem", "Out of memory"); + if(info.bpp < 16) { + int z = 0; + if(psize == 0 || psize > 256) { + STBI_FREE(out); + return stbi__errpuc("invalid", "Corrupt BMP"); + } + for(i = 0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if(info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if(info.bpp == 1) width = (s->img_x + 7) >> 3; + else if(info.bpp == 4) + width = (s->img_x + 1) >> 1; + else if(info.bpp == 8) + width = s->img_x; + else { + STBI_FREE(out); + return stbi__errpuc("bad bpp", "Corrupt BMP"); + } + pad = (-width) & 3; + if(info.bpp == 1) { + for(j = 0; j < (int)s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for(i = 0; i < (int)s->img_x; ++i) { + int color = (v >> bit_offset) & 0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if(target == 4) out[z++] = 255; + if(i + 1 == (int)s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for(j = 0; j < (int)s->img_y; ++j) { + for(i = 0; i < (int)s->img_x; i += 2) { + int v = stbi__get8(s), v2 = 0; + if(info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if(target == 4) out[z++] = 255; + if(i + 1 == (int)s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if(target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift = 0, gshift = 0, bshift = 0, ashift = 0, rcount = 0, gcount = 0, bcount = 0, acount = 0; + int z = 0; + int easy = 0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if(info.bpp == 24) width = 3 * s->img_x; + else if(info.bpp == 16) + width = 2 * s->img_x; + else /* bpp = 32 and pad = 0 */ + width = 0; + pad = (-width) & 3; + if(info.bpp == 24) { + easy = 1; + } else if(info.bpp == 32) { + if(mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if(!easy) { + if(!mr || !mg || !mb) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr) - 7; + rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg) - 7; + gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb) - 7; + bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma) - 7; + acount = stbi__bitcount(ma); + if(rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + } + for(j = 0; j < (int)s->img_y; ++j) { + if(easy) { + for(i = 0; i < (int)s->img_x; ++i) { + unsigned char a; + out[z + 2] = stbi__get8(s); + out[z + 1] = stbi__get8(s); + out[z + 0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if(target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for(i = 0; i < (int)s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32)stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if(target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } - } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - info.extra_read - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } + // if alpha channel is all 0s, replace with all 255s + if(target == 4 && all_a == 0) + for(i = 4 * s->img_x * s->img_y - 1; i >= 0; i -= 4) + out[i] = 255; - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; + if(flip_vertically) { + stbi_uc t; + for(j = 0; j < (int)s->img_y >> 1; ++j) { + stbi_uc* p1 = out + j * s->img_x * target; + stbi_uc* p2 = out + (s->img_y - 1 - j) * s->img_x * target; + for(i = 0; i < (int)s->img_x * target; ++i) { + t = p1[i]; + p1[i] = p2[i]; + p2[i] = t; + } + } + } - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i]; p1[i] = p2[i]; p2[i] = t; - } - } - } + if(req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if(out == NULL) return out; // stbi__convert_format frees input on failure + } - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; + *x = s->img_x; + *y = s->img_y; + if(comp) *comp = s->img_n; + return out; } #endif @@ -5736,341 +5858,327 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough - case 32: return bits_per_pixel/8; - default: return 0; - } +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { + // only RGB or RGBA (incl. 16bit) or grey allowed + if(is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: + return STBI_grey; + case 16: + if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: + if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: + return bits_per_pixel / 8; + default: + return 0; + } } -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { - stbi__rewind(s); - return 0; - } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything +static int stbi__tga_info(stbi__context* s, int* x, int* y, int* comp) { + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if(tga_colormap_type > 1) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if(tga_colormap_type == 1) { // colormapped (paletted) image + if(tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if((tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11)) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s, 9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if(tga_w < 1) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if(tga_h < 1) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if(tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if(x) *x = tga_w; + if(y) *y = tga_h; + if(comp) *comp = tga_comp; + return 1; // seems to have passed everything } -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; +static int stbi__tga_test(stbi__context* s) { + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if(tga_color_type > 1) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if(tga_color_type == 1) { // colormapped (paletted) image + if(sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) goto errorEnd; + stbi__skip(s, 4); // skip image x and y origin + } else { // "normal" image w/o colormap + if((sz != 2) && (sz != 3) && (sz != 10) && (sz != 11)) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s, 9); // skip colormap specification and image x/y origin + } + if(stbi__get16le(s) < 1) goto errorEnd; // test width + if(stbi__get16le(s) < 1) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if((tga_color_type == 1) && (sz != 8) && (sz != 16)) goto errorEnd; // for colormapped images, bpp is size of an index + if((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) goto errorEnd; - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 errorEnd: - stbi__rewind(s); - return res; + stbi__rewind(s); + return res; } // read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); +static void stbi__tga_read_rgb16(stbi__context* s, stbi_uc* out) { + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255) / 31); + out[1] = (stbi_uc)((g * 255) / 31); + out[2] = (stbi_uc)((b * 255) / 31); - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); - STBI_NOTUSED(tga_x_origin); // @TODO - STBI_NOTUSED(tga_y_origin); // @TODO +static void* stbi__tga_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16 = 0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char* tga_data; + unsigned char* tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO - if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if(tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); + if(tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); + // do a tiny bit of precessing + if(tga_image_type >= 8) { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + // If I'm paletted, then I'll use the number of bits from the palette + if(tga_indexed) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; + // tga info + *x = tga_width; + *y = tga_height; + if(comp) *comp = tga_comp; - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); + if(!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if(!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset); - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - if (tga_palette_len == 0) { /* you have to have at least one entry! */ - STBI_FREE(tga_data); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } + if(!tga_indexed && !tga_is_RLE && !tga_rgb16) { + for(i = 0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height - i - 1 : i; + stbi_uc* tga_row = tga_data + row * tga_width * tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if(tga_indexed) { + if(tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if(!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if(tga_rgb16) { + stbi_uc* pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for(i = 0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if(!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for(i = 0; i < tga_width * tga_height; ++i) { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if(tga_is_RLE) { + if(RLE_count == 0) { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if(!RLE_repeating) { + read_next_pixel = 1; + } + } else { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if(read_next_pixel) { + // load however much data we did have + if(tga_indexed) { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if(pal_idx >= tga_palette_len) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for(j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx + j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for(j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; + // copy data + for(j = 0; j < tga_comp; ++j) + tga_data[i * tga_comp + j] = raw_data[j]; - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if(tga_inverted) { + for(j = 0; j * 2 < tga_height; ++j) { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for(i = tga_width * tga_comp; i > 0; --i) { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if(tga_palette != NULL) { + STBI_FREE(tga_palette); + } + } - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } + // swap RGB - if the source data was RGB16, it already is in the right order + if(tga_comp >= 3 && !tga_rgb16) { + unsigned char* tga_pixel = tga_data; + for(i = 0; i < tga_width * tga_height; ++i) { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + // convert to target component count + if(req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - STBI_NOTUSED(tga_palette_start); - // OK, done - return tga_data; + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; } #endif @@ -6078,250 +6186,247 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; +static int stbi__psd_test(stbi__context* s) { + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; } -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; +static int stbi__psd_decode_rle(stbi__context* s, stbi_uc* p, int pixelCount) { + int count, nleft, len; - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } + count = 0; + while((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if(len == 128) { + // No-op. + } else if(len < 128) { + // Copy next len+1 bytes literally. + len++; + if(len > nleft) return 0; // corrupt data + count += len; + while(len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if(len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if(len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while(len) { + *p = val; + p += 4; + len--; + } + } + } - return 1; + return 1; } -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); +static void* stbi__psd_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri, int bpc) { + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w, h; + stbi_uc* out; + STBI_NOTUSED(ri); - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); + // Check identifier + if(stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + // Check file type version. + if(stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); + // Skip 6 reserved bytes. + stbi__skip(s, 6); - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if(channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); - if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if(h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); + if(w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if(bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if(stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s, stbi__get32be(s)); - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s)); - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s)); - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if(compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); + // Check size + if(!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); - // Create the destination image. + // Create the destination image. - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); + if(!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc*)stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc*)stbi__malloc(4 * w * h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; + if(!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w * h; - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); + // Initialize the data to zero. + // memset( out, 0, pixelCount * 4 ); - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop + // Finally, the image data. + if(compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop - // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2); - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; + // Read the RLE data by channel. + for(channel = 0; channel < 4; channel++) { + stbi_uc* p; - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } + p = out + channel; + if(channel >= channelCount) { + // Fill this channel with default data. + for(i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if(!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } + // Read the data by channel. + for(channel = 0; channel < 4; channel++) { + if(channel >= channelCount) { + // Fill this channel with default data. + if(bitdepth == 16 && bpc == 16) { + stbi__uint16* q = ((stbi__uint16*)out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for(i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc* p = out + channel; + stbi_uc val = channel == 3 ? 255 : 0; + for(i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if(ri->bits_per_channel == 16) { // output bpc + stbi__uint16* q = ((stbi__uint16*)out) + channel; + for(i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16)stbi__get16be(s); + } else { + stbi_uc* p = out + channel; + if(bitdepth == 16) { // input bpc + for(i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc)(stbi__get16be(s) >> 8); + } else { + for(i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } - } - } + // remove weird white matte from PSD + if(channelCount >= 4) { + if(ri->bits_per_channel == 16) { + for(i = 0; i < w * h; ++i) { + stbi__uint16* pixel = (stbi__uint16*)out + 4 * i; + if(pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16)(pixel[0] * ra + inv_a); + pixel[1] = (stbi__uint16)(pixel[1] * ra + inv_a); + pixel[2] = (stbi__uint16)(pixel[2] * ra + inv_a); + } + } + } else { + for(i = 0; i < w * h; ++i) { + unsigned char* pixel = out + 4 * i; + if(pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char)(pixel[0] * ra + inv_a); + pixel[1] = (unsigned char)(pixel[1] * ra + inv_a); + pixel[2] = (unsigned char)(pixel[2] * ra + inv_a); + } + } + } + } - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } + // convert to desired output format + if(req_comp && req_comp != 4) { + if(ri->bits_per_channel == 16) + out = (stbi_uc*)stbi__convert_format16((stbi__uint16*)out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if(out == NULL) return out; // stbi__convert_format frees input on failure + } - if (comp) *comp = 4; - *y = h; - *x = w; + if(comp) *comp = 4; + *y = h; + *x = w; - return out; + return out; } #endif @@ -6333,216 +6438,210 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ #ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; +static int stbi__pic_is4(stbi__context* s, const char* str) { + int i; + for(i = 0; i < 4; ++i) + if(stbi__get8(s) != (stbi_uc)str[i]) + return 0; - return 1; + return 1; } -static int stbi__pic_test_core(stbi__context *s) -{ - int i; +static int stbi__pic_test_core(stbi__context* s) { + int i; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; + if(!stbi__pic_is4(s, "\x53\x80\xF6\x34")) + return 0; - for(i=0;i<84;++i) - stbi__get8(s); + for(i = 0; i < 84; ++i) + stbi__get8(s); - if (!stbi__pic_is4(s,"PICT")) - return 0; + if(!stbi__pic_is4(s, "PICT")) + return 0; - return 1; + return 1; } typedef struct { - stbi_uc size,type,channel; + stbi_uc size, type, channel; } stbi__pic_packet; -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; +static stbi_uc* stbi__readval(stbi__context* s, int channel, stbi_uc* dest) { + int mask = 0x80, i; - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } + for(i = 0; i < 4; ++i, mask >>= 1) { + if(channel & mask) { + if(stbi__at_eof(s)) return stbi__errpuc("bad file", "PIC file too short"); + dest[i] = stbi__get8(s); + } + } - return dest; + return dest; } -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; +static void stbi__copyval(int channel, stbi_uc* dest, const stbi_uc* src) { + int mask = 0x80, i; - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; + for(i = 0; i < 4; ++i, mask >>= 1) + if(channel & mask) + dest[i] = src[i]; } -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; +static stbi_uc* stbi__pic_load_core(stbi__context* s, int width, int height, int* comp, stbi_uc* result) { + int act_comp = 0, num_packets = 0, y, chained; + stbi__pic_packet packets[10]; - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet* packet; - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); + if(num_packets == sizeof(packets) / sizeof(packets[0])) + return stbi__errpuc("bad format", "too many packets"); - packet = &packets[num_packets++]; + packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); - act_comp |= packet->channel; + act_comp |= packet->channel; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); + if(stbi__at_eof(s)) return stbi__errpuc("bad file", "file too short (reading packets)"); + if(packet->size != 8) return stbi__errpuc("bad format", "packet isn't 8bpp"); + } while(chained); - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); + switch(packet->type) { + default: + return stbi__errpuc("bad format", "packet has bad compression type"); - case 0: {//uncompressed - int x; + case 0: + { // uncompressed + int x; - for(x=0;xchannel,dest)) - return 0; - break; - } + for(x = 0; x < width; ++x, dest += 4) + if(!stbi__readval(s, packet->channel, dest)) + return 0; + break; + } - case 1://Pure RLE - { - int left=width, i; + case 1: // Pure RLE + { + int left = width, i; - while (left>0) { - stbi_uc count,value[4]; + while(left > 0) { + stbi_uc count, value[4]; - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + count = stbi__get8(s); + if(stbi__at_eof(s)) return stbi__errpuc("bad file", "file too short (pure read count)"); - if (count > left) - count = (stbi_uc) left; + if(count > left) + count = (stbi_uc)left; - if (!stbi__readval(s,packet->channel,value)) return 0; + if(!stbi__readval(s, packet->channel, value)) return 0; - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; + for(i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + left -= count; + } + } break; - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + case 2: + { // Mixed RLE + int left = width; + while(left > 0) { + int count = stbi__get8(s), i; + if(stbi__at_eof(s)) return stbi__errpuc("bad file", "file too short (mixed read count)"); - if (count >= 128) { // Repeated - stbi_uc value[4]; + if(count >= 128) { // Repeated + stbi_uc value[4]; - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); + if(count == 128) + count = stbi__get16be(s); + else + count -= 127; + if(count > left) + return stbi__errpuc("bad file", "scanline overrun"); - if (!stbi__readval(s,packet->channel,value)) - return 0; + if(!stbi__readval(s, packet->channel, value)) + return 0; - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); + for(i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + } else { // Raw + ++count; + if(count > left) return stbi__errpuc("bad file", "scanline overrun"); - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } + for(i = 0; i < count; ++i, dest += 4) + if(!stbi__readval(s, packet->channel, dest)) + return 0; + } + left -= count; + } + break; + } + } + } + } - return result; + return result; } -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); +static void* stbi__pic_load(stbi__context* s, int* px, int* py, int* comp, int req_comp, stbi__result_info* ri) { + stbi_uc* result; + int i, x, y, internal_comp; + STBI_NOTUSED(ri); - if (!comp) comp = &internal_comp; + if(!comp) comp = &internal_comp; - for (i=0; i<92; ++i) - stbi__get8(s); + for(i = 0; i < 92; ++i) + stbi__get8(s); - x = stbi__get16be(s); - y = stbi__get16be(s); + x = stbi__get16be(s); + y = stbi__get16be(s); - if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if(y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); + if(x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + if(stbi__at_eof(s)) return stbi__errpuc("bad file", "file too short (pic header)"); + if(!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' + stbi__get32be(s); // skip `ratio' + stbi__get16be(s); // skip `fields' + stbi__get16be(s); // skip `pad' - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - if (!result) return stbi__errpuc("outofmem", "Out of memory"); - memset(result, 0xff, x*y*4); + // intermediate buffer is RGBA + result = (stbi_uc*)stbi__malloc_mad3(x, y, 4, 0); + if(!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x * y * 4); - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); + if(!stbi__pic_load_core(s, x, y, comp, result)) { + STBI_FREE(result); + result = 0; + } + *px = x; + *py = y; + if(req_comp == 0) req_comp = *comp; + result = stbi__convert_format(result, 4, req_comp, x, y); - return result; + return result; } -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; +static int stbi__pic_test(stbi__context* s) { + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; } #endif @@ -6552,531 +6651,519 @@ static int stbi__pic_test(stbi__context *s) #ifndef STBI_NO_GIF typedef struct { - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; } stbi__gif_lzw; typedef struct { - int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; - int delay; + int w, h; + stbi_uc* out; // output buffer (always 4 components) + stbi_uc* background; // The current "background" as far as a gif is concerned + stbi_uc* history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc* color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; } stbi__gif; -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; +static int stbi__gif_test_raw(stbi__context* s) { + int sz; + if(stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if(sz != '9' && sz != '7') return 0; + if(stbi__get8(s) != 'a') return 0; + return 1; } -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__gif_test(stbi__context* s) { + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; } -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } +static void stbi__gif_parse_colortable(stbi__context* s, stbi_uc pal[256][4], int num_entries, int transp) { + int i; + for(i = 0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } } -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); +static int stbi__gif_header(stbi__context* s, stbi__gif* g, int* comp, int is_info) { + stbi_uc version; + if(stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + version = stbi__get8(s); + if(version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if(stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; - if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if(g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); + if(g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large", "Very large image (corrupt?)"); - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + if(comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - if (is_info) return 1; + if(is_info) return 1; - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + if(g->flags & 0x80) + stbi__gif_parse_colortable(s, g->pal, 2 << (g->flags & 7), -1); - return 1; + return 1; } -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!g) return stbi__err("outofmem", "Out of memory"); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; +static int stbi__gif_info_raw(stbi__context* s, int* x, int* y, int* comp) { + stbi__gif* g = (stbi__gif*)stbi__malloc(sizeof(stbi__gif)); + if(!g) return stbi__err("outofmem", "Out of memory"); + if(!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind(s); + return 0; + } + if(x) *x = g->w; + if(y) *y = g->h; + STBI_FREE(g); + return 1; } -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - int idx; +static void stbi__out_gif_code(stbi__gif* g, stbi__uint16 code) { + stbi_uc *p, *c; + int idx; - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if(g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); - if (g->cur_y >= g->max_y) return; + if(g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; + c = &g->color_table[g->codes[code].suffix * 4]; + if(c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; + if(g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } + while(g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } } -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; +static stbi_uc* stbi__process_gif_raster(stbi__context* s, stbi__gif* g) { + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw* p; - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } + lzw_cs = stbi__get8(s); + if(lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for(init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc)init_code; + g->codes[init_code].suffix = (stbi_uc)init_code; + } - // support no starting clear code - avail = clear+2; - oldcode = -1; + // support no starting clear code + avail = clear + 2; + oldcode = -1; - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } + len = 0; + for(;;) { + if(valid_bits < codesize) { + if(len == 0) { + len = stbi__get8(s); // start new block + if(len == 0) + return g->out; + } + --len; + bits |= (stbi__int32)stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if(code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if(code == clear + 1) { // end of stream code + stbi__skip(s, len); + while((len = stbi__get8(s)) > 0) + stbi__skip(s, len); + return g->out; + } else if(code <= avail) { + if(first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } + if(oldcode >= 0) { + p = &g->codes[avail++]; + if(avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + p->prefix = (stbi__int16)oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if(code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - stbi__out_gif_code(g, (stbi__uint16) code); + stbi__out_gif_code(g, (stbi__uint16)code); - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } + if((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } } // this function is designed to support animated gifs, although stb_image doesn't support it // two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) -{ - int dispose; - int first_frame; - int pi; - int pcount; - STBI_NOTUSED(req_comp); +static stbi_uc* stbi__gif_load_next(stbi__context* s, stbi__gif* g, int* comp, int req_comp, stbi_uc* two_back) { + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) - return stbi__errpuc("too large", "GIF image is too large"); - pcount = g->w * g->h; - g->out = (stbi_uc *) stbi__malloc(4 * pcount); - g->background = (stbi_uc *) stbi__malloc(4 * pcount); - g->history = (stbi_uc *) stbi__malloc(pcount); - if (!g->out || !g->background || !g->history) - return stbi__errpuc("outofmem", "Out of memory"); + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if(g->out == 0) { + if(!stbi__gif_header(s, g, comp, 0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if(!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc*)stbi__malloc(4 * pcount); + g->background = (stbi_uc*)stbi__malloc(4 * pcount); + g->history = (stbi_uc*)stbi__malloc(pcount); + if(!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. - memset(g->out, 0x00, 4 * pcount); - memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) - memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispose of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background - } + if((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); - } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } - } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. - } + if(dispose == 3) { // use previous graphic + for(pi = 0; pi < pcount; ++pi) { + if(g->history[pi]) { + memcpy(&g->out[pi * 4], &two_back[pi * 4], 4); + } + } + } else if(dispose == 2) { + // restore what was changed last frame to background before that frame; + for(pi = 0; pi < pcount; ++pi) { + if(g->history[pi]) { + memcpy(&g->out[pi * 4], &g->background[pi * 4], 4); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); - } + // background is what out is after the undoing of the previou frame; + memcpy(g->background, g->out, 4 * g->w * g->h); + } - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + // clear my history; + memset(g->history, 0x00, g->w * g->h); // pixels that were affected previous frame - for (;;) { - int tag = stbi__get8(s); - switch (tag) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; + for(;;) { + int tag = stbi__get8(s); + switch(tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc* o; - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if(((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; - // if the width of the specified rectangle is 0, that means - // we may not see *any* pixels or the image is malformed; - // to make sure this is caught, move the current y down to - // max_y (which is what out_gif_code checks). - if (w == 0) - g->cur_y = g->max_y; + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if(w == 0) + g->cur_y = g->max_y; - g->lflags = stbi__get8(s); + g->lflags = stbi__get8(s); - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } + if(g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); + if(g->lflags & 0x80) { + stbi__gif_parse_colortable(s, g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc*)g->lpal; + } else if(g->flags & 0x80) { + g->color_table = (stbi_uc*)g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); - o = stbi__process_gif_raster(s, g); - if (!o) return NULL; + o = stbi__process_gif_raster(s, g); + if(!o) return NULL; - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } + // if this was the first frame, + pcount = g->w * g->h; + if(first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for(pi = 0; pi < pcount; ++pi) { + if(g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy(&g->out[pi * 4], &g->pal[g->bgindex], 4); + } + } + } - return o; - } + return o; + } - case 0x21: // Comment Extension. - { - int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if(ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if(len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) { - stbi__skip(s, len); - } - break; - } + // unset old transparent + if(g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if(g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if(g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers + case 0x3B: // gif stream termination code + return (stbi_uc*)s; // using '1' causes warning on some compilers - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } } -static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) -{ - STBI_FREE(g->out); - STBI_FREE(g->history); - STBI_FREE(g->background); +static void* stbi__load_gif_main_outofmem(stbi__gif* g, stbi_uc* out, int** delays) { + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); - if (out) STBI_FREE(out); - if (delays && *delays) STBI_FREE(*delays); - return stbi__errpuc("outofmem", "Out of memory"); + if(out) STBI_FREE(out); + if(delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); } -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - int out_size = 0; - int delays_size = 0; +static void* stbi__load_gif_main(stbi__context* s, int** delays, int* x, int* y, int* z, int* comp, int req_comp) { + if(stbi__gif_test(s)) { + int layers = 0; + stbi_uc* u = 0; + stbi_uc* out = 0; + stbi_uc* two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; - STBI_NOTUSED(out_size); - STBI_NOTUSED(delays_size); + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; - } + memset(&g, 0, sizeof(g)); + if(delays) { + *delays = 0; + } - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if(u == (stbi_uc*)s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; + if(u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; - if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (!tmp) - return stbi__load_gif_main_outofmem(&g, out, delays); - else { - out = (stbi_uc*) tmp; - out_size = layers * stride; - } + if(out) { + void* tmp = (stbi_uc*)STBI_REALLOC_SIZED(out, out_size, layers * stride); + if(!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*)tmp; + out_size = layers * stride; + } - if (delays) { - int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); - if (!new_delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - *delays = new_delays; - delays_size = layers * sizeof(int); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (!out) - return stbi__load_gif_main_outofmem(&g, out, delays); - out_size = layers * stride; - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - if (!*delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - delays_size = layers * sizeof(int); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } + if(delays) { + int* new_delays = (int*)STBI_REALLOC_SIZED(*delays, delays_size, sizeof(int) * layers); + if(!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc(layers * stride); + if(!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if(delays) { + *delays = (int*)stbi__malloc(layers * sizeof(int)); + if(!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy(out + ((layers - 1) * stride), u, stride); + if(layers >= 2) { + two_back = out - 2 * stride; + } - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); + if(delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while(u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + // do the final conversion after loading everything; + if(req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } } -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - STBI_NOTUSED(ri); +static void* stbi__gif_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + stbi_uc* u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if(u == (stbi_uc*)s) u = 0; // end of animated gif marker + if(u) { + *x = g.w; + *y = g.h; - // moved conversion to after successful load so that the same - // can be done for multiple frames. - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } else if (g.out) { - // if there was an error and we allocated an image buffer, free it! - STBI_FREE(g.out); - } + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if(req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if(g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); - return u; + return u; } -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); +static int stbi__gif_info(stbi__context* s, int* x, int* y, int* comp) { + return stbi__gif_info_raw(s, x, y, comp); } #endif @@ -7084,397 +7171,402 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; +static int stbi__hdr_test_core(stbi__context* s, const char* signature) { + int i; + for(i = 0; signature[i]; ++i) + if(stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; } -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; +static int stbi__hdr_test(stbi__context* s) { + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; } -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; +#define STBI__HDR_BUFLEN 1024 +static char* stbi__hdr_gettoken(stbi__context* z, char* buffer) { + int len = 0; + char c = '\0'; - c = (char) stbi__get8(z); + c = (char)stbi__get8(z); - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } + while(!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if(len == STBI__HDR_BUFLEN - 1) { + // flush to end of line + while(!stbi__at_eof(z) && stbi__get8(z) != '\n'); + break; + } + c = (char)stbi__get8(z); + } - buffer[len] = 0; - return buffer; + buffer[len] = 0; + return buffer; } -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } +static void stbi__hdr_convert(float* output, stbi_uc* input, int req_comp) { + if(input[3] != 0) { + float f1; + // Exponent + f1 = (float)ldexp(1.0f, input[3] - (int)(128 + 8)); + if(req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if(req_comp == 2) output[1] = 1; + if(req_comp == 4) output[3] = 1; + } else { + switch(req_comp) { + case 4: + output[3] = 1; /* fallthrough */ + case 3: + output[0] = output[1] = output[2] = 0; + break; + case 2: + output[1] = 1; /* fallthrough */ + case 1: + output[0] = 0; + break; + } + } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); +static float* stbi__hdr_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + char buffer[STBI__HDR_BUFLEN]; + char* token; + int valid = 0; + int width, height; + stbi_uc* scanline; + float* hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1, c2, z; + const char* headerToken; + STBI_NOTUSED(ri); - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); + // Check identifier + headerToken = stbi__hdr_gettoken(s, buffer); + if(strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s, buffer); + if(token[0] == 0) break; + if(strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + if(!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s, buffer); + if(strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int)strtol(token, &token, 10); + while(*token == ' ') ++token; + if(strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int)strtol(token, NULL, 10); - if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); - if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if(height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large", "Very large image (corrupt?)"); + if(width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large", "Very large image (corrupt?)"); - *x = width; - *y = height; + *x = width; + *y = height; - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; + if(comp) *comp = 3; + if(req_comp == 0) req_comp = 3; - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); + if(!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); + // Read data + hdr_data = (float*)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if(!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; + // Load image data + // image data is stored as some number of sca + if(width < 8 || width >= 32768) { + // Read flat data + for(j = 0; j < height; ++j) { + for(i = 0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } + for(j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if(c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc)c1; + rgbe[1] = (stbi_uc)c2; + rgbe[2] = (stbi_uc)len; + rgbe[3] = (stbi_uc)stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if(len != width) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); + } + if(scanline == NULL) { + scanline = (stbi_uc*)stbi__malloc_mad2(width, 4, 0); + if(!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - if (scanline) - STBI_FREE(scanline); - } + for(k = 0; k < 4; ++k) { + int nleft; + i = 0; + while((nleft = width - i) > 0) { + count = stbi__get8(s); + if(count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if((count == 0) || (count > nleft)) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for(z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if((count == 0) || (count > nleft)) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for(z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for(i = 0; i < width; ++i) + stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, scanline + i * 4, req_comp); + } + if(scanline) + STBI_FREE(scanline); + } - return hdr_data; + return hdr_data; } -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; +static int stbi__hdr_info(stbi__context* s, int* x, int* y, int* comp) { + char buffer[STBI__HDR_BUFLEN]; + char* token; + int valid = 0; + int dummy; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if(!x) x = &dummy; + if(!y) y = &dummy; + if(!comp) comp = &dummy; - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } + if(stbi__hdr_test(s) == 0) { + stbi__rewind(s); + return 0; + } - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + for(;;) { + token = stbi__hdr_gettoken(s, buffer); + if(token[0] == 0) break; + if(strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; + if(!valid) { + stbi__rewind(s); + return 0; + } + token = stbi__hdr_gettoken(s, buffer); + if(strncmp(token, "-Y ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *y = (int)strtol(token, &token, 10); + while(*token == ' ') ++token; + if(strncmp(token, "+X ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *x = (int)strtol(token, NULL, 10); + *comp = 3; + return 1; } #endif // STBI_NO_HDR #ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; +static int stbi__bmp_info(stbi__context* s, int* x, int* y, int* comp) { + void* p; + stbi__bmp_data info; - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - if (p == NULL) { - stbi__rewind( s ); - return 0; - } - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) { - if (info.bpp == 24 && info.ma == 0xff000000) - *comp = 3; - else - *comp = info.ma ? 4 : 3; - } - return 1; + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if(p == NULL) { + stbi__rewind(s); + return 0; + } + if(x) *x = s->img_x; + if(y) *y = s->img_y; + if(comp) { + if(info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; } #endif #ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; +static int stbi__psd_info(stbi__context* s, int* x, int* y, int* comp) { + int channelCount, dummy, depth; + if(!x) x = &dummy; + if(!y) y = &dummy; + if(!comp) comp = &dummy; + if(stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if(stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if(channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if(depth != 8 && depth != 16) { + stbi__rewind(s); + return 0; + } + if(stbi__get16be(s) != 3) { + stbi__rewind(s); + return 0; + } + *comp = 4; + return 1; } -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - STBI_NOTUSED(stbi__get32be(s)); - STBI_NOTUSED(stbi__get32be(s)); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__psd_is16(stbi__context* s) { + int channelCount, depth; + if(stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if(stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if(channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if(depth != 16) { + stbi__rewind(s); + return 0; + } + return 1; } #endif #ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; +static int stbi__pic_info(stbi__context* s, int* x, int* y, int* comp) { + int act_comp = 0, num_packets = 0, chained, dummy; + stbi__pic_packet packets[10]; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if(!x) x = &dummy; + if(!y) y = &dummy; + if(!comp) comp = &dummy; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } + if(!stbi__pic_is4(s, "\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } - stbi__skip(s, 88); + stbi__skip(s, 88); - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if(stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if((*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind(s); + return 0; + } - stbi__skip(s, 8); + stbi__skip(s, 8); - do { - stbi__pic_packet *packet; + do { + stbi__pic_packet* packet; - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; + if(num_packets == sizeof(packets) / sizeof(packets[0])) + return 0; - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); + if(stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if(packet->size != 8) { + stbi__rewind(s); + return 0; + } + } while(chained); - *comp = (act_comp & 0x10 ? 4 : 3); + *comp = (act_comp & 0x10 ? 4 : 3); - return 1; + return 1; } #endif @@ -7491,272 +7583,254 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__pnm_test(stbi__context* s) { + char p, t; + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if(p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + return 1; } -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); +static void* stbi__pnm_load(stbi__context* s, int* x, int* y, int* comp, int req_comp, stbi__result_info* ri) { + stbi_uc* out; + STBI_NOTUSED(ri); - ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); - if (ri->bits_per_channel == 0) - return 0; + ri->bits_per_channel = stbi__pnm_info(s, (int*)&s->img_x, (int*)&s->img_y, (int*)&s->img_n); + if(ri->bits_per_channel == 0) + return 0; - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if(s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); + if(s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large", "Very large image (corrupt?)"); - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; + *x = s->img_x; + *y = s->img_y; + if(comp) *comp = s->img_n; - if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) - return stbi__errpuc("too large", "PNM too large"); + if(!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { - STBI_FREE(out); - return stbi__errpuc("bad PNM", "PNM file truncated"); - } + out = (stbi_uc*)stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if(!out) return stbi__errpuc("outofmem", "Out of memory"); + if(!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } - if (req_comp && req_comp != s->img_n) { - if (ri->bits_per_channel == 16) { - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); - } else { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - } - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; + if(req_comp && req_comp != s->img_n) { + if(ri->bits_per_channel == 16) { + out = (stbi_uc*)stbi__convert_format16((stbi__uint16*)out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if(out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; } -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +static int stbi__pnm_isspace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); +static void stbi__pnm_skip_whitespace(stbi__context* s, char* c) { + for(;;) { + while(!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char)stbi__get8(s); - if (stbi__at_eof(s) || *c != '#') - break; + if(stbi__at_eof(s) || *c != '#') + break; - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } + while(!stbi__at_eof(s) && *c != '\n' && *c != '\r') + *c = (char)stbi__get8(s); + } } -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; +static int stbi__pnm_isdigit(char c) { + return c >= '0' && c <= '9'; } -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; +static int stbi__pnm_getinteger(stbi__context* s, char* c) { + int value = 0; - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - if((value > 214748364) || (value == 214748364 && *c > '7')) - return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); - } + while(!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value * 10 + (*c - '0'); + *c = (char)stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } - return value; + return value; } -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; +static int stbi__pnm_info(stbi__context* s, int* x, int* y, int* comp) { + int maxv, dummy; + char c, p, t; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if(!x) x = &dummy; + if(!y) y = &dummy; + if(!comp) comp = &dummy; - stbi__rewind(s); + stbi__rewind(s); - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } + // Get identifier + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if(p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); + c = (char)stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); - *x = stbi__pnm_getinteger(s, &c); // read width - if(*x == 0) - return stbi__err("invalid width", "PPM image header had zero or overflowing width"); - stbi__pnm_skip_whitespace(s, &c); + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); - *y = stbi__pnm_getinteger(s, &c); // read height - if (*y == 0) - return stbi__err("invalid width", "PPM image header had zero or overflowing width"); - stbi__pnm_skip_whitespace(s, &c); + *y = stbi__pnm_getinteger(s, &c); // read height + if(*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); - maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 65535) - return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); - else if (maxv > 255) - return 16; - else - return 8; + maxv = stbi__pnm_getinteger(s, &c); // read max value + if(maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if(maxv > 255) + return 16; + else + return 8; } -static int stbi__pnm_is16(stbi__context *s) -{ - if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) - return 1; - return 0; +static int stbi__pnm_is16(stbi__context* s) { + if(stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif +static int stbi__info_main(stbi__context* s, int* x, int* y, int* comp) { +#ifndef STBI_NO_JPEG + if(stbi__jpeg_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNG + if(stbi__png_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_GIF + if(stbi__gif_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_BMP + if(stbi__bmp_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PSD + if(stbi__psd_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PIC + if(stbi__pic_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNM + if(stbi__pnm_info(s, x, y, comp)) return 1; +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_HDR + if(stbi__hdr_info(s, x, y, comp)) return 1; +#endif - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +// test tga last because it's a crappy test! +#ifndef STBI_NO_TGA + if(stbi__tga_info(s, x, y, comp)) + return 1; +#endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif +static int stbi__is_16_main(stbi__context* s) { +#ifndef STBI_NO_PNG + if(stbi__png_is16(s)) return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif +#ifndef STBI_NO_PSD + if(stbi__psd_is16(s)) return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_is16(s)) return 1; - #endif - return 0; +#ifndef STBI_NO_PNM + if(stbi__pnm_is16(s)) return 1; +#endif + return 0; } #ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; +STBIDEF int stbi_info(char const* filename, int* x, int* y, int* comp) { + FILE* f = stbi__fopen(filename, "rb"); + int result; + if(!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; } -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_info_from_file(FILE* f, int* x, int* y, int* comp) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s, x, y, comp); + fseek(f, pos, SEEK_SET); + return r; } -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; +STBIDEF int stbi_is_16_bit(char const* filename) { + FILE* f = stbi__fopen(filename, "rb"); + int result; + if(!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; } -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_is_16_bit_from_file(FILE* f) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f, pos, SEEK_SET); + return r; } #endif // !STBI_NO_STDIO -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_memory(stbi_uc const* buffer, int len, int* x, int* y, int* comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const* c, void* user, int* x, int* y, int* comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)c, user); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const* buffer, int len) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__is_16_main(&s); } -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const* c, void* user) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks*)c, user); + return stbi__is_16_main(&s); } #endif // STB_IMAGE_IMPLEMENTATION @@ -7767,146 +7841,146 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug - 1-bit BMP - *_is_16_bit api - avoid warnings + 1-bit BMP + *_is_16_bit api + avoid warnings 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED 2.09 (2016-01-16) allow comments in PNM files - 16-bit-per-pixel TGA (not bit-per-component) - info() for TGA could break due to .hdr handling - info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bpc PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support 2.02 (2015-01-19) fix incorrect assert, fix warning 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc + fix MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier + various warning fixes from Ronny Chevalier 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 + fix MSVC-only compiler problem in code changed in 1.42 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages + fix search&replace from 1.36 that messed up comments/error messages 1.40 (2014-06-22) - fix gcc struct-initialization warning + fix gcc struct-initialization warning 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O 1.37 (2014-06-04) - remove duplicate typedef + remove duplicate typedef 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) + support for "info" function for all supported filetypes (SpartanJ) 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) + a few more leak fixes, bug in PNG handling (SpartanJ) 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville + various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) + fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings + cast-to-stbi_uc to fix warnings 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ + fix bug in file buffering for PNG reported by SpartanJ 1.25 (2010-07-17) - refix trans_data warning (Won Chun) + refix trans_data warning (Won Chun) 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) 1.23 fixed bug in iPhone support 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) 1.21 fix use of 'stbi_uc' in header (reported by jon blow) 1.20 added support for Softimage PIC, by Tom Seddon 1.19 bug in interlaced PNG corruption check (found by ryg) 1.18 (2008-08-02) - fix a threading bug (local mutable static) + fix a threading bug (local mutable static) 1.17 support interlaced PNG 1.16 major bugfix - stbi__convert_format converted one too many pixels 1.15 initialize some fields for thread safety 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 1.13 threadsafe 1.12 const qualifiers in the API 1.11 Support installable IDCT, colorspace conversion routines 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen + optimized upsampling by Fabian "ryg" Giesen 1.09 Fix format-conversion for PSD code (bad global variables!) 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 1.07 attempt to fix C++ warning/errors again @@ -7916,7 +7990,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR 1.02 support for (subset of) HDR files, float interface for preferred access to them 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all 1.00 interface to zlib that skips zlib header 0.99 correct handling of alpha in palette 0.98 TGA loader by lonesock; dynamically add loaders (untested) @@ -7939,12 +8013,11 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 0.53 fix bug in png 3->4; speedup png decoding 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant + on 'test' only check type, not whether we support this variant 0.50 (2006-11-19) - first released version + first released version */ - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/include/Mw/BaseTypes.h b/include/Mw/BaseTypes.h index 313215e..527dcde 100644 --- a/include/Mw/BaseTypes.h +++ b/include/Mw/BaseTypes.h @@ -49,6 +49,9 @@ typedef __int8 MwI8; typedef unsigned __int8 MwU8; #define MW_OTHER_TYPES_DEFINED +#elif defined(__WINDOWS__) +typedef long long MwI64; +typedef unsigned long long MwU64; #else /* out of hope */ typedef long MwI64; @@ -58,6 +61,16 @@ typedef unsigned long MwU64; #ifdef MW_OTHER_TYPES_DEFINED #undef MW_OTHER_TYPES_DEFINED #else +#ifdef __WINDOWS__ +typedef long MwI32; +typedef unsigned long MwU32; + +typedef int MwI16; +typedef unsigned int MwU16; + +typedef signed char MwI8; +typedef unsigned char MwU8; +#else typedef int MwI32; typedef unsigned int MwU32; @@ -67,6 +80,7 @@ typedef unsigned short MwU16; typedef signed char MwI8; typedef unsigned char MwU8; #endif +#endif typedef MwI64 MwOffset; diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 15853ff..8a9db9e 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -35,7 +35,11 @@ enum MwALIGNMENT { /*! * @brief Default */ +#ifdef __WINDOWS__ +#define MwDEFAULT 0x0ffff +#else #define MwDEFAULT 0x0fffffff +#endif /*! * @brief Directory entry type diff --git a/include/Mw/Dialog/ColorPicker.h b/include/Mw/Dialog/ColorPicker.h index b143fdf..1a574b2 100644 --- a/include/Mw/Dialog/ColorPicker.h +++ b/include/Mw/Dialog/ColorPicker.h @@ -12,6 +12,9 @@ extern "C" { #endif +#ifdef __WINDOWS__ +#error Color Picker Widget is not avaliable on Win16 +#else /*! * @brief Creates a color picker * @param handle Widget @@ -19,6 +22,7 @@ extern "C" { * @return Widget */ MWDECL MwWidget MWAPI MwColorPicker(MwWidget handle, const char* title); +#endif #ifdef __cplusplus } diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index deefe0f..a88ae59 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -162,6 +162,7 @@ MWDECL unsigned char* MWAPI MwPixmapGetRaw(MwLLPixmap pixmap); */ MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); +#ifndef __WINDOWS__ /*! * @brief Creates a pixmap from XPM data * @param handle Widget @@ -169,6 +170,7 @@ MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); * @return Pixmap */ MWDECL MwLLPixmap MWAPI MwLoadXPM(MwWidget handle, char** data); +#endif /*! * @brief Creates a pixmap from icon data diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 2ba2265..67f96fe 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -334,6 +334,7 @@ MWDECL void (*MwLLRaise)(MwLL handle); MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); /* font renderer */ +#ifndef __WINDOWS__ MWDECL void MwFLSetup(void); #ifdef USE_FREETYPE2 @@ -348,6 +349,7 @@ MWDECL int (*MwFLTextWidth)(MwFLFont ttf, const char* text); MWDECL int (*MwFLTextHeight)(MwFLFont ttf, int count); MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px); MWDECL void (*MwFLFontFree)(void* handle); +#endif #ifdef __cplusplus } diff --git a/include/Mw/LowLevel/GDI.h b/include/Mw/LowLevel/GDI.h index d2e2473..568e555 100644 --- a/include/Mw/LowLevel/GDI.h +++ b/include/Mw/LowLevel/GDI.h @@ -42,6 +42,7 @@ struct _MwLLGDIPixmap { RGBQUAD* quad; HBITMAP hBitmap; + HDC hBitmapMem; HBITMAP hMask; HBITMAP hMask2; }; diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 0415b4c..c344283 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -20,11 +20,18 @@ #include #define MW_HAS_WCHAR #endif -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) #include #ifdef _MILSKO #include +#if defined(__WINDOWS__) +#include +#define GetSysColorBrush(x) CreateSolidBrush(GetSysColor(x)) +#endif +#ifndef HALFTONE +#define HALFTONE 4 +#endif #ifndef GWLP_USERDATA #define GWLP_USERDATA GWL_USERDATA #define GWLP_WNDPROC GWL_WNDPROC @@ -35,6 +42,9 @@ #define SetClassLongPtr SetClassLong #define GetClassLongPtr GetClassLong #endif +#ifndef GWL_USERDATA +#define GWL_USERDATA (-21) +#endif #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020a #define GET_WHEEL_DELTA_WPARAM(x) ((short)HIWORD(x)) @@ -89,9 +99,9 @@ #endif /* Windows */ -#if defined(_MILSKO) && defined(_MILSKO_BUILD) && defined(_WIN32) +#if defined(_MILSKO) && defined(_MILSKO_BUILD) && defined(_WIN32) || defined(__WINDOWS__) #define MWDECL extern __declspec(dllexport) -#elif defined(_WIN32) +#elif defined(_WIN32) || defined(__WINDOWS__) #define MWDECL extern __declspec(dllimport) /* GCC/Clang */ /* First check if we have __has_attribute and can check for the existence of visibility */ @@ -111,7 +121,7 @@ #define MWDECL extern #endif -#if defined(_WIN32) +#if defined(_WIN32) || defined(__WINDOWS__) #define MWAPI __cdecl #else #define MWAPI diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index f7b4b49..7bb0f64 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -23,14 +23,18 @@ #include #include +#ifndef __WINDOWS__ #include +#endif #include #include #include #include #include +#ifndef __WINDOWS__ #include +#endif #include #include diff --git a/include/Mw/Resource/Cursor.h b/include/Mw/Resource/Cursor.h index 9a47802..fc75979 100644 --- a/include/Mw/Resource/Cursor.h +++ b/include/Mw/Resource/Cursor.h @@ -13,6 +13,7 @@ extern "C" { #endif +#ifndef __WINDOWS__ /*! * @brief Default cursor */ @@ -63,6 +64,8 @@ MWDECL MwCursor MwCursorHidden; */ MWDECL MwCursor MwCursorHiddenMask; +#endif + #ifdef __cplusplus } #endif diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index 3f7a0c4..5594505 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -10,7 +10,7 @@ #include #if !defined(MW_OPENGL_NO_INCLUDE) && !defined(__gl_h_) -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) #include #elif defined(__APPLE__) #else diff --git a/src/abstract/directory.c b/src/abstract/directory.c index ac5a382..89fbeb7 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -1,11 +1,16 @@ #include -#ifdef _WIN32 +#if defined(_WIN32) typedef struct dir { HANDLE hFind; WIN32_FIND_DATA ffd; int next; } dir_t; +#elif defined(__WINDOWS__) +typedef struct dir { + struct find_t result; + int next; +} dir_t; #elif defined(CLASSIC_MAC_OS) typedef struct dir { int dummy; @@ -19,7 +24,7 @@ typedef struct dir { void* MwDirectoryOpen(const char* path) { dir_t* dir = malloc(sizeof(*dir)); -#ifdef _WIN32 +#if defined(_WIN32) char* p = malloc(strlen(path) + 2 + 1); strcpy(p, path); if(strchr(path, '/') != NULL) { @@ -35,6 +40,22 @@ void* MwDirectoryOpen(const char* path) { } free(p); dir->next = 1; +#elif defined(__WINDOWS__) + char* p = malloc(strlen(path) + 2 + 1); + strcpy(p, path); + if(strchr(path, '/') != NULL) { + strcat(p, "/"); + } else { + strcat(p, "\\"); + } + strcat(p, "*.*"); + if(_dos_findfirst(p, _A_NORMAL, &dir->result) != 0) { + free(p); + free(dir); + return NULL; + } + free(p); + dir->next = 1; #elif defined(CLASSIC_MAC_OS) /* todo */ #else @@ -51,8 +72,10 @@ void* MwDirectoryOpen(const char* path) { void MwDirectoryClose(void* handle) { dir_t* dir = handle; -#ifdef _WIN32 +#if defined(_WIN32) FindClose(dir->hFind); +#elif defined(__WINDOWS__) + /* nothing? */ #elif defined(CLASSIC_MAC_OS) /* todo */ #else @@ -65,7 +88,7 @@ void MwDirectoryClose(void* handle) { MwDirectoryEntry* MwDirectoryRead(void* handle) { dir_t* dir = handle; MwDirectoryEntry* entry = malloc(sizeof(*entry)); -#ifdef _WIN32 +#if defined(_WIN32) ULARGE_INTEGER* l; if(!dir->next) return NULL; @@ -88,6 +111,21 @@ MwDirectoryEntry* MwDirectoryRead(void* handle) { entry->mtime = l->QuadPart / 10000000 - 11644473600; dir->next = FindNextFile(dir->hFind, &dir->ffd); +#elif defined(__WINDOWS__) + if(!dir->next) return NULL; + + entry->name = MwStringDuplicate(dir->result.name); + if(dir->result.attrib & _A_SUBDIR) { + entry->type = MwDIRECTORY_DIRECTORY; + } else { + entry->type = MwDIRECTORY_FILE; + } + + entry->size = dir->result.size; + + entry->mtime = MwDosDateTimeToUnix(dir->result.wr_date, dir->result.wr_time); + + dir->next = (_dos_findnext(&dir->result) == 0); #elif defined(CLASSIC_MAC_OS) /* todo */ #else @@ -126,7 +164,7 @@ void MwDirectoryFreeEntry(MwDirectoryEntry* entry) { } char* MwDirectoryCurrent(void) { -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) int len = GetCurrentDirectory(0, NULL); char* out = malloc(len); @@ -140,7 +178,7 @@ char* MwDirectoryCurrent(void) { #endif } -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) #define DIRSEP '\\' #else #define DIRSEP '/' diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index 58bc831..e1cd393 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -1,6 +1,6 @@ #include -#if defined(_WIN32) +#if defined(_WIN32) || defined(__WINDOWS__) void* MwDynamicOpen(const char* path) { return LoadLibrary(path); } diff --git a/src/abstract/time.c b/src/abstract/time.c index d1ddb83..214248a 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -1,6 +1,6 @@ #include -#if defined(_WIN32) +#if defined(_WIN32) || defined(__WINDOWS__) long MwTimeGetTick(void) { return GetTickCount(); } diff --git a/src/backend/gdi.c b/src/backend/gdi.c index bbab256..c770c59 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -8,14 +8,13 @@ typedef struct userdata { int max_set; } userdata_t; +#ifndef __WINDOWS__ static struct symtbl { void* lib_dwmapi; HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); } wsymtbl; -static int is_plgblt_reliable = 0; - #define DwmSetWindowAttribute wsymtbl.DwmSetWindowAttribute /* Dark theme detection for classic Windows: check if the user has set their theme to be dark. */ @@ -62,6 +61,15 @@ static void detect_darktheme(MwLL handle) { MwLLDispatch(handle, dark_theme, &t); } +#endif + +/* There isn't any plgblt on Win16 at all */ +#ifdef __WINDOWS__ +#define is_plgblt_reliable 0 +#else +static int is_plgblt_reliable = 0; +#endif + static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { userdata_t* u = (userdata_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -125,7 +133,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { p.button = MwMOUSE_RIGHT; } - SetCapture(NULL); + SetCapture(0); MwLLDispatch(u->ll, up, &p); } else if(msg == WM_MOUSEWHEEL) { int d = GET_WHEEL_DELTA_WPARAM(wp); @@ -182,12 +190,18 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } else if(msg == WM_CLOSE) { MwLLDispatch(u->ll, close, NULL); } else if(msg == WM_CHAR || msg == WM_SYSCHAR) { - int n = wp; +#ifndef __WINDOWS__ + int n = wp; +#else + unsigned long n = wp; +#endif const int base = 'A' - 1; if(n != 0x1b && n <= 0x1f) { n = (n + base) | MwKEY_CONTROL_FLAG; +#ifndef __WINDOWS__ if(!(GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT))) n += 0x20; +#endif } if(HIBYTE(VkKeyScan(wp)) & 2) n |= MwKEY_CONTROL_FLAG; if(msg == WM_SYSCHAR) n |= MwKEY_ALT_FLAG; @@ -198,7 +212,11 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } else if(msg == WM_KILLFOCUS) { MwLLDispatch(u->ll, focus_out, NULL); } else if(msg == WM_KEYDOWN || msg == WM_KEYUP || msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) { +#ifndef __WINDOWS__ int n = -1; +#else + unsigned long n = -1; +#endif if(wp == VK_MENU && msg == WM_KEYUP) return 0; if(wp == VK_LEFT) n = MwKEY_LEFT; if(wp == VK_RIGHT) n = MwKEY_RIGHT; @@ -207,8 +225,10 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { if(wp == VK_RETURN) n = MwKEY_ENTER; if(wp == VK_BACK) n = MwKEY_BACKSPACE; if(wp == VK_ESCAPE) n = MwKEY_ESCAPE; +#ifndef __WINDOWS__ if(wp == VK_LSHIFT) n = MwKEY_LEFTSHIFT; if(wp == VK_RSHIFT) n = MwKEY_RIGHTSHIFT; +#endif if(wp == VK_MENU) n = MwKEY_ALT; if(wp == VK_CONTROL) n = MwKEY_CONTROL; @@ -255,7 +275,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } } else if(msg == WM_SETCURSOR) { if(LOWORD(lp) != HTCLIENT) return DefWindowProc(hWnd, msg, wp, lp); - if(u->ll->gdi.cursor != NULL) SetCursor(u->ll->gdi.cursor); + if(u->ll->gdi.cursor != 0) SetCursor(u->ll->gdi.cursor); } else if(msg == WM_USER) { InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); @@ -263,9 +283,11 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { char* s = (char*)lp; LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); +#ifndef __WINDOWS__ if(!(style & WS_CHILD)) { if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); } +#endif } else { return DefWindowProc(hWnd, msg, wp, lp); } @@ -275,10 +297,16 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r = malloc(sizeof(*r)); userdata_t* u = malloc(sizeof(*u)); - WNDCLASSEX wc; +#ifdef __WINDOWS__ + WNDCLASS wc; +#else + WNDCLASSEX wc; +#endif memset(&wc, 0, sizeof(wc)); - wc.cbSize = sizeof(WNDCLASSEX); +#ifndef __WINDOWS__ + wc.cbSize = sizeof(WNDCLASSEX); +#endif wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = wndproc; wc.cbClsExtra = 0; @@ -286,14 +314,22 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { wc.hInstance = (HINSTANCE)GetModuleHandle(NULL); wc.lpszClassName = "milsko"; wc.lpszMenuName = NULL; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = GetSysColorBrush(COLOR_MENU); - wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); - wc.hIconSm = NULL; +#ifndef __WINDOWS__ + wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); + wc.hIconSm = NULL; +#else + wc.hIcon = LoadIcon(0, IDI_APPLICATION); +#endif MwLLCreateCommon(r); +#ifdef __WINDOWS__ + RegisterClass(&wc); +#else RegisterClassEx(&wc); +#endif r->common.copy_buffer = 1; r->common.type = MwLLBackendGDI; @@ -302,12 +338,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(parent == NULL) r->gdi.get_darktheme = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; - r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); + r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? 0 : parent->gdi.hWnd, 0, wc.hInstance, NULL); r->gdi.hInstance = wc.hInstance; - r->gdi.cursor = NULL; - r->gdi.icon = NULL; + r->gdi.cursor = 0; + r->gdi.icon = 0; - r->gdi.clip = NULL; + r->gdi.clip = 0; u->ll = r; u->min_set = 0; @@ -322,7 +358,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { rc.right = width; rc.bottom = height; AdjustWindowRect(&rc, GetWindowLongPtr(r->gdi.hWnd, GWL_STYLE), FALSE); - SetWindowPos(r->gdi.hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE); + SetWindowPos(r->gdi.hWnd, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE); ShowWindow(r->gdi.hWnd, SW_NORMAL); UpdateWindow(r->gdi.hWnd); @@ -330,7 +366,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { InvalidateRect(r->gdi.hWnd, NULL, FALSE); } - SetWindowPos(r->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(r->gdi.hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); return r; } @@ -342,9 +378,9 @@ static void MwLLDestroyImpl(MwLL handle) { SetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA, (LPARAM)NULL); DestroyWindow(handle->gdi.hWnd); - if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + if(handle->gdi.clip) DeleteObject(handle->gdi.clip); - if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); + if(handle->gdi.cursor) DestroyCursor(handle->gdi.cursor); free(handle); } @@ -396,7 +432,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { MwLLColor c = malloc(sizeof(*c)); - c->gdi.brush = NULL; + c->gdi.brush = 0; MwLLColorUpdate(handle, c, r, g, b); @@ -413,7 +449,7 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { if(g < 0) g = 0; if(b < 0) b = 0; - if(c->gdi.brush != NULL) DeleteObject(c->gdi.brush); + if(c->gdi.brush != 0) DeleteObject(c->gdi.brush); c->gdi.brush = CreateSolidBrush(GetNearestColor(dc, RGB(r, g, b))); c->common.red = r; c->common.green = g; @@ -441,12 +477,12 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - SetWindowPos(handle->gdi.hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetWindowPos(handle->gdi.hWnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER); - InvalidateRect(handle->gdi.hWnd, NULL, FALSE); + SetWindowPos(handle->gdi.hWnd, 0, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER); + InvalidateRect(handle->gdi.hWnd, 0, FALSE); } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -467,11 +503,12 @@ static void MwLLNextEventImpl(MwLL handle) { (void)handle; +#ifndef __WINDOWS__ if(handle->gdi.get_clipboard) { HGLOBAL hg; - if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) { - char* txt = malloc(GlobalSize(hg)); + if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != 0) { char* clp = GlobalLock(hg); + char* txt = malloc(GlobalSize(hg)); strcpy(txt, clp); @@ -485,11 +522,15 @@ static void MwLLNextEventImpl(MwLL handle) { handle->gdi.get_clipboard = 0; } +#endif + +#ifndef __WINDOWS__ if(handle->gdi.get_darktheme) { detect_darktheme(handle); handle->gdi.get_darktheme = 0; } +#endif while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { GetMessage(&msg, handle->gdi.hWnd, 0, 0); TranslateMessage(&msg); @@ -498,9 +539,13 @@ static void MwLLNextEventImpl(MwLL handle) { } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { - MwLLPixmap r = malloc(sizeof(*r)); - HDC dc = GetDC(handle->gdi.hWnd); + MwLLPixmap r = malloc(sizeof(*r)); + HDC dc = GetDC(handle->gdi.hWnd); +#ifndef __WINDOWS__ BITMAPINFOHEADER bmih; +#else + BITMAPINFO bmi; +#endif r->common.raw = malloc(width * height * 4); memcpy(r->common.raw, data, 4 * width * height); @@ -508,6 +553,7 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid r->common.width = width; r->common.height = height; +#ifndef __WINDOWS__ bmih.biSize = sizeof(bmih); bmih.biWidth = width; bmih.biHeight = -(LONG)height; @@ -521,9 +567,15 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid bmih.biClrImportant = 0; r->gdi.hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&r->gdi.quad, NULL, (DWORD)0); +#else + r->gdi.hBitmap = CreateCompatibleBitmap(dc, width, height); + r->gdi.hBitmapMem = CreateCompatibleDC(dc); + SelectObject(r->gdi.hBitmapMem, r->gdi.hBitmap); + SetDIBits(r->gdi.hBitmapMem, r->gdi.hBitmap, 0, height, r->common.raw, &bmi, DIB_RGB_COLORS); +#endif - r->gdi.hMask = NULL; - r->gdi.hMask2 = NULL; + r->gdi.hMask = 0; + r->gdi.hMask2 = 0; ReleaseDC(handle->gdi.hWnd, dc); @@ -563,8 +615,8 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap r) { } } - if(r->gdi.hMask != NULL) DeleteObject(r->gdi.hMask); - if(r->gdi.hMask2 != NULL) DeleteObject(r->gdi.hMask2); + if(r->gdi.hMask != 0) DeleteObject(r->gdi.hMask); + if(r->gdi.hMask2 != 0) DeleteObject(r->gdi.hMask2); r->gdi.hMask = CreateBitmap(r->common.width, r->common.height, 1, 1, words); r->gdi.hMask2 = CreateBitmap(r->common.width, r->common.height, 1, 1, words2); @@ -598,18 +650,27 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { SelectObject(hmdc, pixmap->gdi.hBitmap); +#ifndef __WINDOWS__ if(!is_plgblt_reliable || PlgBlt(handle->gdi.hDC, p, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, pixmap->gdi.hMask, 0, 0) == 0) { +#endif SelectObject(hmdc, pixmap->gdi.hMask2); StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCAND); SelectObject(hmdc, pixmap->gdi.hBitmap); StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCPAINT); +#ifndef __WINDOWS__ } +#endif DeleteDC(hmdc); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + /* it's probably (presumably) not possible to set the icon on 16-bit windows */ +#ifdef __WINDOWS__ + (void)handle; + (void)pixmap; +#else ICONINFO ii; memset(&ii, 0, sizeof(ii)); @@ -623,6 +684,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { handle->gdi.icon = CreateIconIndirect(&ii); SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)handle->gdi.icon); SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_BIG, (LPARAM)handle->gdi.icon); +#endif } static void MwLLForceRenderImpl(MwLL handle) { @@ -683,11 +745,19 @@ HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) { } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - HCURSOR cursor = MwLLGDICreateCursor(image, mask); + if(image && mask) { + HCURSOR cursor = MwLLGDICreateCursor(image, mask); - if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); - if(handle->gdi.icon != NULL) DestroyIcon(handle->gdi.icon); - handle->gdi.cursor = cursor; + if(handle->gdi.cursor != 0) DestroyCursor(handle->gdi.cursor); + if(handle->gdi.icon != 0) DestroyIcon(handle->gdi.icon); + handle->gdi.cursor = cursor; + } + /* Only on Win16: hide the cursor outright if image/mask are null */ +#ifndef __WINDOWS__ + else if(!image && !mask) { + ShowCursor(FALSE); + } +#endif } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { @@ -701,12 +771,16 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { GetClientRect(handle->gdi.hWnd, &rc2); +#ifdef __WINDOWS__ + if(lp2 & WS_POPUP) { +#else if(lp2 & WS_EX_TOOLWINDOW) { +#endif SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp); } else { SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)WS_OVERLAPPEDWINDOW | lp); } - SetParent(handle->gdi.hWnd, NULL); + SetParent(handle->gdi.hWnd, 0); rc.left += point->x; rc.top += point->y; @@ -752,7 +826,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, lp); - SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); + SetWindowPos(handle->gdi.hWnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); } static void MwLLFocusImpl(MwLL handle) { @@ -789,6 +863,11 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { +#ifdef __WINDOWS__ + (void)handle; + (void)text; + (void)clipboard_type; +#else HGLOBAL hg; (void)clipboard_type; if(OpenClipboard(handle->gdi.hWnd) != 0) { @@ -805,6 +884,7 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty CloseClipboard(); } +#endif } static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { @@ -818,14 +898,17 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { int w, h; SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp); +#ifdef __WINDOWS__ + SetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE, (LPARAM)WS_POPUP); +#else SetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE, (LPARAM)WS_EX_TOOLWINDOW); - +#endif GetClientRect(handle->gdi.hWnd, &rc); w = rc.right - rc.left; h = rc.bottom - rc.top; - SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + SetWindowPos(handle->gdi.hWnd, 0, 0, 0, w, h, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { @@ -860,13 +943,21 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { +#ifdef __WINDOWS__ + (void)handle; + (void)toggle; +#else BOOL v = toggle ? TRUE : FALSE; if(DwmSetWindowAttribute) DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); +#endif } static MwBool MwLLDoModernImpl(MwLL handle) { +#ifdef __WINDOWS__ + return MwFALSE; +#else OSVERSIONINFO osvi; (void)handle; @@ -880,34 +971,35 @@ static MwBool MwLLDoModernImpl(MwLL handle) { } return MwTRUE; +#endif } static void MwLLRaiseImpl(MwLL handle) { - SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(handle->gdi.hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } static void MwLLClipImpl(MwLL handle, MwRect* rect) { if(rect == NULL) { - SelectClipRgn(handle->gdi.hDC, NULL); + SelectClipRgn(handle->gdi.hDC, 0); - if(handle->gdi.clip != NULL) { + if(handle->gdi.clip) { DeleteObject(handle->gdi.clip); - handle->gdi.clip = NULL; + handle->gdi.clip = 0; } } else { HRGN clip = CreateRectRgn(rect->x, rect->y, rect->x + rect->width, rect->y + rect->height); SelectClipRgn(handle->gdi.hDC, clip); - if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + if(handle->gdi.clip != 0) DeleteObject(handle->gdi.clip); handle->gdi.clip = clip; } } static int MwLLGDICallInitImpl(void) { +#ifndef __WINDOWS__ void* ntdll; - memset(&wsymtbl, 0, sizeof(wsymtbl)); wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); @@ -919,6 +1011,7 @@ static int MwLLGDICallInitImpl(void) { } else { is_plgblt_reliable = 1; } +#endif /* TODO: check properly */ return 0; diff --git a/src/color.c b/src/color.c index ae3667e..e74518d 100644 --- a/src/color.c +++ b/src/color.c @@ -2,6 +2,491 @@ #include "../external/stb_ds.h" +struct color_table_entry { + char* key; + MwU8 red; + MwU8 blue; + MwU8 green; +}; + +static struct color_table_entry color_entries[] = { + {"snow", 255, 250, 250}, + {"ghost white", 248, 248, 255}, + {"white smoke", 245, 245, 245}, + {"gainsboro", 220, 220, 220}, + {"floral white", 255, 250, 240}, + {"old lace", 253, 245, 230}, + {"linen", 250, 240, 230}, + {"antique white", 250, 235, 215}, + {"papaya whip", 255, 239, 213}, + {"blanched almond", 255, 235, 205}, + {"bisque", 255, 228, 196}, + {"peach puff", 255, 218, 185}, + {"navajo white", 255, 222, 173}, + {"moccasin", 255, 228, 181}, + {"cornsilk", 255, 248, 220}, + {"ivory", 255, 255, 240}, + {"lemon chiffon", 255, 250, 205}, + {"seashell", 255, 245, 238}, + {"honeydew", 240, 255, 240}, + {"mint cream", 245, 255, 250}, + {"azure", 240, 255, 255}, + {"alice blue", 240, 248, 255}, + {"lavender", 230, 230, 250}, + {"lavender blush", 255, 240, 245}, + {"misty rose", 255, 228, 225}, + {"white", 255, 255, 255}, + {"black", 0, 0, 0}, + {"dark slate gray", 47, 79, 79}, + {"dark slate grey", 47, 79, 79}, + {"dim gray", 105, 105, 105}, + {"dim grey", 105, 105, 105}, + {"slate gray", 112, 128, 144}, + {"slate grey", 112, 128, 144}, + {"light slate gray", 119, 136, 153}, + {"light slate grey", 119, 136, 153}, + {"gray", 190, 190, 190}, + {"grey", 190, 190, 190}, + {"x11 gray", 190, 190, 190}, + {"x11 grey", 190, 190, 190}, + {"web gray", 128, 128, 128}, + {"web grey", 128, 128, 128}, + {"light grey", 211, 211, 211}, + {"light gray", 211, 211, 211}, + {"midnight blue", 25, 25, 112}, + {"navy", 0, 0, 128}, + {"navy blue", 0, 0, 128}, + {"cornflower blue", 100, 149, 237}, + {"dark slate blue", 72, 61, 139}, + {"slate blue", 106, 90, 205}, + {"medium slate blue", 123, 104, 238}, + {"light slate blue", 132, 112, 255}, + {"medium blue", 0, 0, 205}, + {"royal blue", 65, 105, 225}, + {"blue", 0, 0, 255}, + {"dodger blue", 30, 144, 255}, + {"deep sky blue", 0, 191, 255}, + {"sky blue", 135, 206, 235}, + {"light sky blue", 135, 206, 250}, + {"steel blue", 70, 130, 180}, + {"light steel blue", 176, 196, 222}, + {"light blue", 173, 216, 230}, + {"powder blue", 176, 224, 230}, + {"pale turquoise", 175, 238, 238}, + {"dark turquoise", 0, 206, 209}, + {"medium turquoise", 72, 209, 204}, + {"turquoise", 64, 224, 208}, + {"cyan", 0, 255, 255}, + {"aqua", 0, 255, 255}, + {"light cyan", 224, 255, 255}, + {"cadet blue", 95, 158, 160}, + {"medium aquamarine", 102, 205, 170}, + {"aquamarine", 127, 255, 212}, + {"dark green", 0, 100, 0}, + {"dark olive green", 85, 107, 47}, + {"dark sea green", 143, 188, 143}, + {"sea green", 46, 139, 87}, + {"medium sea green", 60, 179, 113}, + {"light sea green", 32, 178, 170}, + {"pale green", 152, 251, 152}, + {"spring green", 0, 255, 127}, + {"lawn green", 124, 252, 0}, + {"green", 0, 255, 0}, + {"lime", 0, 255, 0}, + {"x11 green", 0, 255, 0}, + {"web green", 0, 128, 0}, + {"chartreuse", 127, 255, 0}, + {"medium spring green", 0, 250, 154}, + {"green yellow", 173, 255, 47}, + {"lime green", 50, 205, 50}, + {"yellow green", 154, 205, 50}, + {"forest green", 34, 139, 34}, + {"olive drab", 107, 142, 35}, + {"dark khaki", 189, 183, 107}, + {"khaki", 240, 230, 140}, + {"pale goldenrod", 238, 232, 170}, + {"light goldenrod yellow", 250, 250, 210}, + {"light yellow", 255, 255, 224}, + {"yellow", 255, 255, 0}, + {"gold", 255, 215, 0}, + {"light goldenrod", 238, 221, 130}, + {"goldenrod", 218, 165, 32}, + {"dark goldenrod", 184, 134, 11}, + {"rosy brown", 188, 143, 143}, + {"indian red", 205, 92, 92}, + {"saddle brown", 139, 69, 19}, + {"sienna", 160, 82, 45}, + {"peru", 205, 133, 63}, + {"burlywood", 222, 184, 135}, + {"beige", 245, 245, 220}, + {"wheat", 245, 222, 179}, + {"sandy brown", 244, 164, 96}, + {"tan", 210, 180, 140}, + {"chocolate", 210, 105, 30}, + {"firebrick", 178, 34, 34}, + {"brown", 165, 42, 42}, + {"dark salmon", 233, 150, 122}, + {"salmon", 250, 128, 114}, + {"light salmon", 255, 160, 122}, + {"orange", 255, 165, 0}, + {"dark orange", 255, 140, 0}, + {"coral", 255, 127, 80}, + {"light coral", 240, 128, 128}, + {"tomato", 255, 99, 71}, + {"orange red", 255, 69, 0}, + {"red", 255, 0, 0}, + {"hot pink", 255, 105, 180}, + {"deep pink", 255, 20, 147}, + {"pink", 255, 192, 203}, + {"light pink", 255, 182, 193}, + {"pale violet red", 219, 112, 147}, + {"maroon", 176, 48, 96}, + {"x11 maroon", 176, 48, 96}, + {"web maroon", 128, 0, 0}, + {"medium violet red", 199, 21, 133}, + {"violet red", 208, 32, 144}, + {"magenta", 255, 0, 255}, + {"fuchsia", 255, 0, 255}, + {"violet", 238, 130, 238}, + {"plum", 221, 160, 221}, + {"orchid", 218, 112, 214}, + {"medium orchid", 186, 85, 211}, + {"dark orchid", 153, 50, 204}, + {"dark violet", 148, 0, 211}, + {"blue violet", 138, 43, 226}, + {"purple", 160, 32, 240}, + {"x11 purple", 160, 32, 240}, + {"web purple", 128, 0, 128}, + {"medium purple", 147, 112, 219}, + {"thistle", 216, 191, 216}, + {"snow1", 255, 250, 250}, + {"snow2", 238, 233, 233}, + {"snow3", 205, 201, 201}, + {"snow4", 139, 137, 137}, + {"seashell1", 255, 245, 238}, + {"seashell2", 238, 229, 222}, + {"seashell3", 205, 197, 191}, + {"seashell4", 139, 134, 130}, + {"AntiqueWhite1", 255, 239, 219}, + {"AntiqueWhite2", 238, 223, 204}, + {"AntiqueWhite3", 205, 192, 176}, + {"AntiqueWhite4", 139, 131, 120}, + {"bisque1", 255, 228, 196}, + {"bisque2", 238, 213, 183}, + {"bisque3", 205, 183, 158}, + {"bisque4", 139, 125, 107}, + {"PeachPuff1", 255, 218, 185}, + {"PeachPuff2", 238, 203, 173}, + {"PeachPuff3", 205, 175, 149}, + {"PeachPuff4", 139, 119, 101}, + {"NavajoWhite1", 255, 222, 173}, + {"NavajoWhite2", 238, 207, 161}, + {"NavajoWhite3", 205, 179, 139}, + {"NavajoWhite4", 139, 121, 94}, + {"LemonChiffon1", 255, 250, 205}, + {"LemonChiffon2", 238, 233, 191}, + {"LemonChiffon3", 205, 201, 165}, + {"LemonChiffon4", 139, 137, 112}, + {"cornsilk1", 255, 248, 220}, + {"cornsilk2", 238, 232, 205}, + {"cornsilk3", 205, 200, 177}, + {"cornsilk4", 139, 136, 120}, + {"ivory1", 255, 255, 240}, + {"ivory2", 238, 238, 224}, + {"ivory3", 205, 205, 193}, + {"ivory4", 139, 139, 131}, + {"honeydew1", 240, 255, 240}, + {"honeydew2", 224, 238, 224}, + {"honeydew3", 193, 205, 193}, + {"honeydew4", 131, 139, 131}, + {"LavenderBlush1", 255, 240, 245}, + {"LavenderBlush2", 238, 224, 229}, + {"LavenderBlush3", 205, 193, 197}, + {"LavenderBlush4", 139, 131, 134}, + {"MistyRose1", 255, 228, 225}, + {"MistyRose2", 238, 213, 210}, + {"MistyRose3", 205, 183, 181}, + {"MistyRose4", 139, 125, 123}, + {"azure1", 240, 255, 255}, + {"azure2", 224, 238, 238}, + {"azure3", 193, 205, 205}, + {"azure4", 131, 139, 139}, + {"SlateBlue1", 131, 111, 255}, + {"SlateBlue2", 122, 103, 238}, + {"SlateBlue3", 105, 89, 205}, + {"SlateBlue4", 71, 60, 139}, + {"RoyalBlue1", 72, 118, 255}, + {"RoyalBlue2", 67, 110, 238}, + {"RoyalBlue3", 58, 95, 205}, + {"RoyalBlue4", 39, 64, 139}, + {"blue1", 0, 0, 255}, + {"blue2", 0, 0, 238}, + {"blue3", 0, 0, 205}, + {"blue4", 0, 0, 139}, + {"DodgerBlue1", 30, 144, 255}, + {"DodgerBlue2", 28, 134, 238}, + {"DodgerBlue3", 24, 116, 205}, + {"DodgerBlue4", 16, 78, 139}, + {"SteelBlue1", 99, 184, 255}, + {"SteelBlue2", 92, 172, 238}, + {"SteelBlue3", 79, 148, 205}, + {"SteelBlue4", 54, 100, 139}, + {"DeepSkyBlue1", 0, 191, 255}, + {"DeepSkyBlue2", 0, 178, 238}, + {"DeepSkyBlue3", 0, 154, 205}, + {"DeepSkyBlue4", 0, 104, 139}, + {"SkyBlue1", 135, 206, 255}, + {"SkyBlue2", 126, 192, 238}, + {"SkyBlue3", 108, 166, 205}, + {"SkyBlue4", 74, 112, 139}, + {"LightSkyBlue1", 176, 226, 255}, + {"LightSkyBlue2", 164, 211, 238}, + {"LightSkyBlue3", 141, 182, 205}, + {"LightSkyBlue4", 96, 123, 139}, + {"SlateGray1", 198, 226, 255}, + {"SlateGray2", 185, 211, 238}, + {"SlateGray3", 159, 182, 205}, + {"SlateGray4", 108, 123, 139}, + {"LightSteelBlue1", 202, 225, 255}, + {"LightSteelBlue2", 188, 210, 238}, + {"LightSteelBlue3", 162, 181, 205}, + {"LightSteelBlue4", 110, 123, 139}, + {"LightBlue1", 191, 239, 255}, + {"LightBlue2", 178, 223, 238}, + {"LightBlue3", 154, 192, 205}, + {"LightBlue4", 104, 131, 139}, + {"LightCyan1", 224, 255, 255}, + {"LightCyan2", 209, 238, 238}, + {"LightCyan3", 180, 205, 205}, + {"LightCyan4", 122, 139, 139}, + {"PaleTurquoise1", 187, 255, 255}, + {"PaleTurquoise2", 174, 238, 238}, + {"PaleTurquoise3", 150, 205, 205}, + {"PaleTurquoise4", 102, 139, 139}, + {"CadetBlue1", 152, 245, 255}, + {"CadetBlue2", 142, 229, 238}, + {"CadetBlue3", 122, 197, 205}, + {"CadetBlue4", 83, 134, 139}, + {"turquoise1", 0, 245, 255}, + {"turquoise2", 0, 229, 238}, + {"turquoise3", 0, 197, 205}, + {"turquoise4", 0, 134, 139}, + {"cyan1", 0, 255, 255}, + {"cyan2", 0, 238, 238}, + {"cyan3", 0, 205, 205}, + {"cyan4", 0, 139, 139}, + {"DarkSlateGray1", 151, 255, 255}, + {"DarkSlateGray2", 141, 238, 238}, + {"DarkSlateGray3", 121, 205, 205}, + {"DarkSlateGray4", 82, 139, 139}, + {"aquamarine1", 127, 255, 212}, + {"aquamarine2", 118, 238, 198}, + {"aquamarine3", 102, 205, 170}, + {"aquamarine4", 69, 139, 116}, + {"DarkSeaGreen1", 193, 255, 193}, + {"DarkSeaGreen2", 180, 238, 180}, + {"DarkSeaGreen3", 155, 205, 155}, + {"DarkSeaGreen4", 105, 139, 105}, + {"SeaGreen1", 84, 255, 159}, + {"SeaGreen2", 78, 238, 148}, + {"SeaGreen3", 67, 205, 128}, + {"SeaGreen4", 46, 139, 87}, + {"PaleGreen1", 154, 255, 154}, + {"PaleGreen2", 144, 238, 144}, + {"PaleGreen3", 124, 205, 124}, + {"PaleGreen4", 84, 139, 84}, + {"SpringGreen1", 0, 255, 127}, + {"SpringGreen2", 0, 238, 118}, + {"SpringGreen3", 0, 205, 102}, + {"SpringGreen4", 0, 139, 69}, + {"green1", 0, 255, 0}, + {"green2", 0, 238, 0}, + {"green3", 0, 205, 0}, + {"green4", 0, 139, 0}, + {"chartreuse1", 127, 255, 0}, + {"chartreuse2", 118, 238, 0}, + {"chartreuse3", 102, 205, 0}, + {"chartreuse4", 69, 139, 0}, + {"OliveDrab1", 192, 255, 62}, + {"OliveDrab2", 179, 238, 58}, + {"OliveDrab3", 154, 205, 50}, + {"OliveDrab4", 105, 139, 34}, + {"DarkOliveGreen1", 202, 255, 112}, + {"DarkOliveGreen2", 188, 238, 104}, + {"DarkOliveGreen3", 162, 205, 90}, + {"DarkOliveGreen4", 110, 139, 61}, + {"khaki1", 255, 246, 143}, + {"khaki2", 238, 230, 133}, + {"khaki3", 205, 198, 115}, + {"khaki4", 139, 134, 78}, + {"LightGoldenrod1", 255, 236, 139}, + {"LightGoldenrod2", 238, 220, 130}, + {"LightGoldenrod3", 205, 190, 112}, + {"LightGoldenrod4", 139, 129, 76}, + {"LightYellow1", 255, 255, 224}, + {"LightYellow2", 238, 238, 209}, + {"LightYellow3", 205, 205, 180}, + {"LightYellow4", 139, 139, 122}, + {"yellow1", 255, 255, 0}, + {"yellow2", 238, 238, 0}, + {"yellow3", 205, 205, 0}, + {"yellow4", 139, 139, 0}, + {"gold1", 255, 215, 0}, + {"gold2", 238, 201, 0}, + {"gold3", 205, 173, 0}, + {"gold4", 139, 117, 0}, + {"goldenrod1", 255, 193, 37}, + {"goldenrod2", 238, 180, 34}, + {"goldenrod3", 205, 155, 29}, + {"goldenrod4", 139, 105, 20}, + {"DarkGoldenrod1", 255, 185, 15}, + {"DarkGoldenrod2", 238, 173, 14}, + {"DarkGoldenrod3", 205, 149, 12}, + {"DarkGoldenrod4", 139, 101, 8}, + {"RosyBrown1", 255, 193, 193}, + {"RosyBrown2", 238, 180, 180}, + {"RosyBrown3", 205, 155, 155}, + {"RosyBrown4", 139, 105, 105}, + {"IndianRed1", 255, 106, 106}, + {"IndianRed2", 238, 99, 99}, + {"IndianRed3", 205, 85, 85}, + {"IndianRed4", 139, 58, 58}, + {"sienna1", 255, 130, 71}, + {"sienna2", 238, 121, 66}, + {"sienna3", 205, 104, 57}, + {"sienna4", 139, 71, 38}, + {"burlywood1", 255, 211, 155}, + {"burlywood2", 238, 197, 145}, + {"burlywood3", 205, 170, 125}, + {"burlywood4", 139, 115, 85}, + {"wheat1", 255, 231, 186}, + {"wheat2", 238, 216, 174}, + {"wheat3", 205, 186, 150}, + {"wheat4", 139, 126, 102}, + {"tan1", 255, 165, 79}, + {"tan2", 238, 154, 73}, + {"tan3", 205, 133, 63}, + {"tan4", 139, 90, 43}, + {"chocolate1", 255, 127, 36}, + {"chocolate2", 238, 118, 33}, + {"chocolate3", 205, 102, 29}, + {"chocolate4", 139, 69, 19}, + {"firebrick1", 255, 48, 48}, + {"firebrick2", 238, 44, 44}, + {"firebrick3", 205, 38, 38}, + {"firebrick4", 139, 26, 26}, + {"brown1", 255, 64, 64}, + {"brown2", 238, 59, 59}, + {"brown3", 205, 51, 51}, + {"brown4", 139, 35, 35}, + {"salmon1", 255, 140, 105}, + {"salmon2", 238, 130, 98}, + {"salmon3", 205, 112, 84}, + {"salmon4", 139, 76, 57}, + {"LightSalmon1", 255, 160, 122}, + {"LightSalmon2", 238, 149, 114}, + {"LightSalmon3", 205, 129, 98}, + {"LightSalmon4", 139, 87, 66}, + {"orange1", 255, 165, 0}, + {"orange2", 238, 154, 0}, + {"orange3", 205, 133, 0}, + {"orange4", 139, 90, 0}, + {"DarkOrange1", 255, 127, 0}, + {"DarkOrange2", 238, 118, 0}, + {"DarkOrange3", 205, 102, 0}, + {"DarkOrange4", 139, 69, 0}, + {"coral1", 255, 114, 86}, + {"coral2", 238, 106, 80}, + {"coral3", 205, 91, 69}, + {"coral4", 139, 62, 47}, + {"tomato1", 255, 99, 71}, + {"tomato2", 238, 92, 66}, + {"tomato3", 205, 79, 57}, + {"tomato4", 139, 54, 38}, + {"OrangeRed1", 255, 69, 0}, + {"OrangeRed2", 238, 64, 0}, + {"OrangeRed3", 205, 55, 0}, + {"OrangeRed4", 139, 37, 0}, + {"red1", 255, 0, 0}, + {"red2", 238, 0, 0}, + {"red3", 205, 0, 0}, + {"red4", 139, 0, 0}, + {"DeepPink1", 255, 20, 147}, + {"DeepPink2", 238, 18, 137}, + {"DeepPink3", 205, 16, 118}, + {"DeepPink4", 139, 10, 80}, + {"HotPink1", 255, 110, 180}, + {"HotPink2", 238, 106, 167}, + {"HotPink3", 205, 96, 144}, + {"HotPink4", 139, 58, 98}, + {"pink1", 255, 181, 197}, + {"pink2", 238, 169, 184}, + {"pink3", 205, 145, 158}, + {"pink4", 139, 99, 108}, + {"LightPink1", 255, 174, 185}, + {"LightPink2", 238, 162, 173}, + {"LightPink3", 205, 140, 149}, + {"LightPink4", 139, 95, 101}, + {"PaleVioletRed1", 255, 130, 171}, + {"PaleVioletRed2", 238, 121, 159}, + {"PaleVioletRed3", 205, 104, 137}, + {"PaleVioletRed4", 139, 71, 93}, + {"maroon1", 255, 52, 179}, + {"maroon2", 238, 48, 167}, + {"maroon3", 205, 41, 144}, + {"maroon4", 139, 28, 98}, + {"VioletRed1", 255, 62, 150}, + {"VioletRed2", 238, 58, 140}, + {"VioletRed3", 205, 50, 120}, + {"VioletRed4", 139, 34, 82}, + {"magenta1", 255, 0, 255}, + {"magenta2", 238, 0, 238}, + {"magenta3", 205, 0, 205}, + {"magenta4", 139, 0, 139}, + {"orchid1", 255, 131, 250}, + {"orchid2", 238, 122, 233}, + {"orchid3", 205, 105, 201}, + {"orchid4", 139, 71, 137}, + {"plum1", 255, 187, 255}, + {"plum2", 238, 174, 238}, + {"plum3", 205, 150, 205}, + {"plum4", 139, 102, 139}, + {"MediumOrchid1", 224, 102, 255}, + {"MediumOrchid2", 209, 95, 238}, + {"MediumOrchid3", 180, 82, 205}, + {"MediumOrchid4", 122, 55, 139}, + {"DarkOrchid1", 191, 62, 255}, + {"DarkOrchid2", 178, 58, 238}, + {"DarkOrchid3", 154, 50, 205}, + {"DarkOrchid4", 104, 34, 139}, + {"purple1", 155, 48, 255}, + {"purple2", 145, 44, 238}, + {"purple3", 125, 38, 205}, + {"purple4", 85, 26, 139}, + {"MediumPurple1", 171, 130, 255}, + {"MediumPurple2", 159, 121, 238}, + {"MediumPurple3", 137, 104, 205}, + {"MediumPurple4", 93, 71, 139}, + {"thistle1", 255, 225, 255}, + {"thistle2", 238, 210, 238}, + {"thistle3", 205, 181, 205}, + {"thistle4", 139, 123, 139}, + + {"dark grey", 169, 169, 169}, + {"dark gray", 169, 169, 169}, + {"dark blue", 0, 0, 139}, + {"dark cyan", 0, 139, 139}, + {"dark magenta", 139, 0, 139}, + {"dark red", 139, 0, 0}, + {"light green", 144, 238, 144}, + {"crimson", 220, 20, 60}, + {"indigo", 75, 0, 130}, + {"olive", 128, 128, 0}, + {"rebecca purple", 102, 51, 153}, + {"silver", 192, 192, 192}, + {"teal", 0, 128, 128}, +}; + struct color { char* key; MwU32 value; @@ -23,793 +508,41 @@ void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb) { } static void add_color(const char* name, int red, int green, int blue) { - MwU32 v = (red << 16) | (green << 8) | (blue << 0); + const char* p; + MwU32 v = (red << 16) | (green << 8) | (blue << 0); + char camel[64]; + size_t out = 0; + int capitalize_next = 1; + shput(colors, name, v); + for(p = name; *p != '\0' && out < sizeof(camel) - 1; p++) { + if(*p == ' ') { + capitalize_next = 1; + } else { + camel[out++] = capitalize_next ? (char)toupper((unsigned char)*p) : *p; + capitalize_next = 0; + } + } + camel[out] = '\0'; + + shput(colors, camel, v); } void MwColorTableInit(void) { + int i = 0, gray = 0, grayID = 0; sh_new_strdup(colors); shdefault(colors, 0); - add_color("snow", 255, 250, 250); - add_color("ghost white", 248, 248, 255); - add_color("GhostWhite", 248, 248, 255); - add_color("white smoke", 245, 245, 245); - add_color("WhiteSmoke", 245, 245, 245); - add_color("gainsboro", 220, 220, 220); - add_color("floral white", 255, 250, 240); - add_color("FloralWhite", 255, 250, 240); - add_color("old lace", 253, 245, 230); - add_color("OldLace", 253, 245, 230); - add_color("linen", 250, 240, 230); - add_color("antique white", 250, 235, 215); - add_color("AntiqueWhite", 250, 235, 215); - add_color("papaya whip", 255, 239, 213); - add_color("PapayaWhip", 255, 239, 213); - add_color("blanched almond", 255, 235, 205); - add_color("BlanchedAlmond", 255, 235, 205); - add_color("bisque", 255, 228, 196); - add_color("peach puff", 255, 218, 185); - add_color("PeachPuff", 255, 218, 185); - add_color("navajo white", 255, 222, 173); - add_color("NavajoWhite", 255, 222, 173); - add_color("moccasin", 255, 228, 181); - add_color("cornsilk", 255, 248, 220); - add_color("ivory", 255, 255, 240); - add_color("lemon chiffon", 255, 250, 205); - add_color("LemonChiffon", 255, 250, 205); - add_color("seashell", 255, 245, 238); - add_color("honeydew", 240, 255, 240); - add_color("mint cream", 245, 255, 250); - add_color("MintCream", 245, 255, 250); - add_color("azure", 240, 255, 255); - add_color("alice blue", 240, 248, 255); - add_color("AliceBlue", 240, 248, 255); - add_color("lavender", 230, 230, 250); - add_color("lavender blush", 255, 240, 245); - add_color("LavenderBlush", 255, 240, 245); - add_color("misty rose", 255, 228, 225); - add_color("MistyRose", 255, 228, 225); - add_color("white", 255, 255, 255); - add_color("black", 0, 0, 0); - add_color("dark slate gray", 47, 79, 79); - add_color("DarkSlateGray", 47, 79, 79); - add_color("dark slate grey", 47, 79, 79); - add_color("DarkSlateGrey", 47, 79, 79); - add_color("dim gray", 105, 105, 105); - add_color("DimGray", 105, 105, 105); - add_color("dim grey", 105, 105, 105); - add_color("DimGrey", 105, 105, 105); - add_color("slate gray", 112, 128, 144); - add_color("SlateGray", 112, 128, 144); - add_color("slate grey", 112, 128, 144); - add_color("SlateGrey", 112, 128, 144); - add_color("light slate gray", 119, 136, 153); - add_color("LightSlateGray", 119, 136, 153); - add_color("light slate grey", 119, 136, 153); - add_color("LightSlateGrey", 119, 136, 153); - add_color("gray", 190, 190, 190); - add_color("grey", 190, 190, 190); - add_color("x11 gray", 190, 190, 190); - add_color("X11Gray", 190, 190, 190); - add_color("x11 grey", 190, 190, 190); - add_color("X11Grey", 190, 190, 190); - add_color("web gray", 128, 128, 128); - add_color("WebGray", 128, 128, 128); - add_color("web grey", 128, 128, 128); - add_color("WebGrey", 128, 128, 128); - add_color("light grey", 211, 211, 211); - add_color("LightGrey", 211, 211, 211); - add_color("light gray", 211, 211, 211); - add_color("LightGray", 211, 211, 211); - add_color("midnight blue", 25, 25, 112); - add_color("MidnightBlue", 25, 25, 112); - add_color("navy", 0, 0, 128); - add_color("navy blue", 0, 0, 128); - add_color("NavyBlue", 0, 0, 128); - add_color("cornflower blue", 100, 149, 237); - add_color("CornflowerBlue", 100, 149, 237); - add_color("dark slate blue", 72, 61, 139); - add_color("DarkSlateBlue", 72, 61, 139); - add_color("slate blue", 106, 90, 205); - add_color("SlateBlue", 106, 90, 205); - add_color("medium slate blue", 123, 104, 238); - add_color("MediumSlateBlue", 123, 104, 238); - add_color("light slate blue", 132, 112, 255); - add_color("LightSlateBlue", 132, 112, 255); - add_color("medium blue", 0, 0, 205); - add_color("MediumBlue", 0, 0, 205); - add_color("royal blue", 65, 105, 225); - add_color("RoyalBlue", 65, 105, 225); - add_color("blue", 0, 0, 255); - add_color("dodger blue", 30, 144, 255); - add_color("DodgerBlue", 30, 144, 255); - add_color("deep sky blue", 0, 191, 255); - add_color("DeepSkyBlue", 0, 191, 255); - add_color("sky blue", 135, 206, 235); - add_color("SkyBlue", 135, 206, 235); - add_color("light sky blue", 135, 206, 250); - add_color("LightSkyBlue", 135, 206, 250); - add_color("steel blue", 70, 130, 180); - add_color("SteelBlue", 70, 130, 180); - add_color("light steel blue", 176, 196, 222); - add_color("LightSteelBlue", 176, 196, 222); - add_color("light blue", 173, 216, 230); - add_color("LightBlue", 173, 216, 230); - add_color("powder blue", 176, 224, 230); - add_color("PowderBlue", 176, 224, 230); - add_color("pale turquoise", 175, 238, 238); - add_color("PaleTurquoise", 175, 238, 238); - add_color("dark turquoise", 0, 206, 209); - add_color("DarkTurquoise", 0, 206, 209); - add_color("medium turquoise", 72, 209, 204); - add_color("MediumTurquoise", 72, 209, 204); - add_color("turquoise", 64, 224, 208); - add_color("cyan", 0, 255, 255); - add_color("aqua", 0, 255, 255); - add_color("light cyan", 224, 255, 255); - add_color("LightCyan", 224, 255, 255); - add_color("cadet blue", 95, 158, 160); - add_color("CadetBlue", 95, 158, 160); - add_color("medium aquamarine", 102, 205, 170); - add_color("MediumAquamarine", 102, 205, 170); - add_color("aquamarine", 127, 255, 212); - add_color("dark green", 0, 100, 0); - add_color("DarkGreen", 0, 100, 0); - add_color("dark olive green", 85, 107, 47); - add_color("DarkOliveGreen", 85, 107, 47); - add_color("dark sea green", 143, 188, 143); - add_color("DarkSeaGreen", 143, 188, 143); - add_color("sea green", 46, 139, 87); - add_color("SeaGreen", 46, 139, 87); - add_color("medium sea green", 60, 179, 113); - add_color("MediumSeaGreen", 60, 179, 113); - add_color("light sea green", 32, 178, 170); - add_color("LightSeaGreen", 32, 178, 170); - add_color("pale green", 152, 251, 152); - add_color("PaleGreen", 152, 251, 152); - add_color("spring green", 0, 255, 127); - add_color("SpringGreen", 0, 255, 127); - add_color("lawn green", 124, 252, 0); - add_color("LawnGreen", 124, 252, 0); - add_color("green", 0, 255, 0); - add_color("lime", 0, 255, 0); - add_color("x11 green", 0, 255, 0); - add_color("X11Green", 0, 255, 0); - add_color("web green", 0, 128, 0); - add_color("WebGreen", 0, 128, 0); - add_color("chartreuse", 127, 255, 0); - add_color("medium spring green", 0, 250, 154); - add_color("MediumSpringGreen", 0, 250, 154); - add_color("green yellow", 173, 255, 47); - add_color("GreenYellow", 173, 255, 47); - add_color("lime green", 50, 205, 50); - add_color("LimeGreen", 50, 205, 50); - add_color("yellow green", 154, 205, 50); - add_color("YellowGreen", 154, 205, 50); - add_color("forest green", 34, 139, 34); - add_color("ForestGreen", 34, 139, 34); - add_color("olive drab", 107, 142, 35); - add_color("OliveDrab", 107, 142, 35); - add_color("dark khaki", 189, 183, 107); - add_color("DarkKhaki", 189, 183, 107); - add_color("khaki", 240, 230, 140); - add_color("pale goldenrod", 238, 232, 170); - add_color("PaleGoldenrod", 238, 232, 170); - add_color("light goldenrod yellow", 250, 250, 210); - add_color("LightGoldenrodYellow", 250, 250, 210); - add_color("light yellow", 255, 255, 224); - add_color("LightYellow", 255, 255, 224); - add_color("yellow", 255, 255, 0); - add_color("gold", 255, 215, 0); - add_color("light goldenrod", 238, 221, 130); - add_color("LightGoldenrod", 238, 221, 130); - add_color("goldenrod", 218, 165, 32); - add_color("dark goldenrod", 184, 134, 11); - add_color("DarkGoldenrod", 184, 134, 11); - add_color("rosy brown", 188, 143, 143); - add_color("RosyBrown", 188, 143, 143); - add_color("indian red", 205, 92, 92); - add_color("IndianRed", 205, 92, 92); - add_color("saddle brown", 139, 69, 19); - add_color("SaddleBrown", 139, 69, 19); - add_color("sienna", 160, 82, 45); - add_color("peru", 205, 133, 63); - add_color("burlywood", 222, 184, 135); - add_color("beige", 245, 245, 220); - add_color("wheat", 245, 222, 179); - add_color("sandy brown", 244, 164, 96); - add_color("SandyBrown", 244, 164, 96); - add_color("tan", 210, 180, 140); - add_color("chocolate", 210, 105, 30); - add_color("firebrick", 178, 34, 34); - add_color("brown", 165, 42, 42); - add_color("dark salmon", 233, 150, 122); - add_color("DarkSalmon", 233, 150, 122); - add_color("salmon", 250, 128, 114); - add_color("light salmon", 255, 160, 122); - add_color("LightSalmon", 255, 160, 122); - add_color("orange", 255, 165, 0); - add_color("dark orange", 255, 140, 0); - add_color("DarkOrange", 255, 140, 0); - add_color("coral", 255, 127, 80); - add_color("light coral", 240, 128, 128); - add_color("LightCoral", 240, 128, 128); - add_color("tomato", 255, 99, 71); - add_color("orange red", 255, 69, 0); - add_color("OrangeRed", 255, 69, 0); - add_color("red", 255, 0, 0); - add_color("hot pink", 255, 105, 180); - add_color("HotPink", 255, 105, 180); - add_color("deep pink", 255, 20, 147); - add_color("DeepPink", 255, 20, 147); - add_color("pink", 255, 192, 203); - add_color("light pink", 255, 182, 193); - add_color("LightPink", 255, 182, 193); - add_color("pale violet red", 219, 112, 147); - add_color("PaleVioletRed", 219, 112, 147); - add_color("maroon", 176, 48, 96); - add_color("x11 maroon", 176, 48, 96); - add_color("X11Maroon", 176, 48, 96); - add_color("web maroon", 128, 0, 0); - add_color("WebMaroon", 128, 0, 0); - add_color("medium violet red", 199, 21, 133); - add_color("MediumVioletRed", 199, 21, 133); - add_color("violet red", 208, 32, 144); - add_color("VioletRed", 208, 32, 144); - add_color("magenta", 255, 0, 255); - add_color("fuchsia", 255, 0, 255); - add_color("violet", 238, 130, 238); - add_color("plum", 221, 160, 221); - add_color("orchid", 218, 112, 214); - add_color("medium orchid", 186, 85, 211); - add_color("MediumOrchid", 186, 85, 211); - add_color("dark orchid", 153, 50, 204); - add_color("DarkOrchid", 153, 50, 204); - add_color("dark violet", 148, 0, 211); - add_color("DarkViolet", 148, 0, 211); - add_color("blue violet", 138, 43, 226); - add_color("BlueViolet", 138, 43, 226); - add_color("purple", 160, 32, 240); - add_color("x11 purple", 160, 32, 240); - add_color("X11Purple", 160, 32, 240); - add_color("web purple", 128, 0, 128); - add_color("WebPurple", 128, 0, 128); - add_color("medium purple", 147, 112, 219); - add_color("MediumPurple", 147, 112, 219); - add_color("thistle", 216, 191, 216); - add_color("snow1", 255, 250, 250); - add_color("snow2", 238, 233, 233); - add_color("snow3", 205, 201, 201); - add_color("snow4", 139, 137, 137); - add_color("seashell1", 255, 245, 238); - add_color("seashell2", 238, 229, 222); - add_color("seashell3", 205, 197, 191); - add_color("seashell4", 139, 134, 130); - add_color("AntiqueWhite1", 255, 239, 219); - add_color("AntiqueWhite2", 238, 223, 204); - add_color("AntiqueWhite3", 205, 192, 176); - add_color("AntiqueWhite4", 139, 131, 120); - add_color("bisque1", 255, 228, 196); - add_color("bisque2", 238, 213, 183); - add_color("bisque3", 205, 183, 158); - add_color("bisque4", 139, 125, 107); - add_color("PeachPuff1", 255, 218, 185); - add_color("PeachPuff2", 238, 203, 173); - add_color("PeachPuff3", 205, 175, 149); - add_color("PeachPuff4", 139, 119, 101); - add_color("NavajoWhite1", 255, 222, 173); - add_color("NavajoWhite2", 238, 207, 161); - add_color("NavajoWhite3", 205, 179, 139); - add_color("NavajoWhite4", 139, 121, 94); - add_color("LemonChiffon1", 255, 250, 205); - add_color("LemonChiffon2", 238, 233, 191); - add_color("LemonChiffon3", 205, 201, 165); - add_color("LemonChiffon4", 139, 137, 112); - add_color("cornsilk1", 255, 248, 220); - add_color("cornsilk2", 238, 232, 205); - add_color("cornsilk3", 205, 200, 177); - add_color("cornsilk4", 139, 136, 120); - add_color("ivory1", 255, 255, 240); - add_color("ivory2", 238, 238, 224); - add_color("ivory3", 205, 205, 193); - add_color("ivory4", 139, 139, 131); - add_color("honeydew1", 240, 255, 240); - add_color("honeydew2", 224, 238, 224); - add_color("honeydew3", 193, 205, 193); - add_color("honeydew4", 131, 139, 131); - add_color("LavenderBlush1", 255, 240, 245); - add_color("LavenderBlush2", 238, 224, 229); - add_color("LavenderBlush3", 205, 193, 197); - add_color("LavenderBlush4", 139, 131, 134); - add_color("MistyRose1", 255, 228, 225); - add_color("MistyRose2", 238, 213, 210); - add_color("MistyRose3", 205, 183, 181); - add_color("MistyRose4", 139, 125, 123); - add_color("azure1", 240, 255, 255); - add_color("azure2", 224, 238, 238); - add_color("azure3", 193, 205, 205); - add_color("azure4", 131, 139, 139); - add_color("SlateBlue1", 131, 111, 255); - add_color("SlateBlue2", 122, 103, 238); - add_color("SlateBlue3", 105, 89, 205); - add_color("SlateBlue4", 71, 60, 139); - add_color("RoyalBlue1", 72, 118, 255); - add_color("RoyalBlue2", 67, 110, 238); - add_color("RoyalBlue3", 58, 95, 205); - add_color("RoyalBlue4", 39, 64, 139); - add_color("blue1", 0, 0, 255); - add_color("blue2", 0, 0, 238); - add_color("blue3", 0, 0, 205); - add_color("blue4", 0, 0, 139); - add_color("DodgerBlue1", 30, 144, 255); - add_color("DodgerBlue2", 28, 134, 238); - add_color("DodgerBlue3", 24, 116, 205); - add_color("DodgerBlue4", 16, 78, 139); - add_color("SteelBlue1", 99, 184, 255); - add_color("SteelBlue2", 92, 172, 238); - add_color("SteelBlue3", 79, 148, 205); - add_color("SteelBlue4", 54, 100, 139); - add_color("DeepSkyBlue1", 0, 191, 255); - add_color("DeepSkyBlue2", 0, 178, 238); - add_color("DeepSkyBlue3", 0, 154, 205); - add_color("DeepSkyBlue4", 0, 104, 139); - add_color("SkyBlue1", 135, 206, 255); - add_color("SkyBlue2", 126, 192, 238); - add_color("SkyBlue3", 108, 166, 205); - add_color("SkyBlue4", 74, 112, 139); - add_color("LightSkyBlue1", 176, 226, 255); - add_color("LightSkyBlue2", 164, 211, 238); - add_color("LightSkyBlue3", 141, 182, 205); - add_color("LightSkyBlue4", 96, 123, 139); - add_color("SlateGray1", 198, 226, 255); - add_color("SlateGray2", 185, 211, 238); - add_color("SlateGray3", 159, 182, 205); - add_color("SlateGray4", 108, 123, 139); - add_color("LightSteelBlue1", 202, 225, 255); - add_color("LightSteelBlue2", 188, 210, 238); - add_color("LightSteelBlue3", 162, 181, 205); - add_color("LightSteelBlue4", 110, 123, 139); - add_color("LightBlue1", 191, 239, 255); - add_color("LightBlue2", 178, 223, 238); - add_color("LightBlue3", 154, 192, 205); - add_color("LightBlue4", 104, 131, 139); - add_color("LightCyan1", 224, 255, 255); - add_color("LightCyan2", 209, 238, 238); - add_color("LightCyan3", 180, 205, 205); - add_color("LightCyan4", 122, 139, 139); - add_color("PaleTurquoise1", 187, 255, 255); - add_color("PaleTurquoise2", 174, 238, 238); - add_color("PaleTurquoise3", 150, 205, 205); - add_color("PaleTurquoise4", 102, 139, 139); - add_color("CadetBlue1", 152, 245, 255); - add_color("CadetBlue2", 142, 229, 238); - add_color("CadetBlue3", 122, 197, 205); - add_color("CadetBlue4", 83, 134, 139); - add_color("turquoise1", 0, 245, 255); - add_color("turquoise2", 0, 229, 238); - add_color("turquoise3", 0, 197, 205); - add_color("turquoise4", 0, 134, 139); - add_color("cyan1", 0, 255, 255); - add_color("cyan2", 0, 238, 238); - add_color("cyan3", 0, 205, 205); - add_color("cyan4", 0, 139, 139); - add_color("DarkSlateGray1", 151, 255, 255); - add_color("DarkSlateGray2", 141, 238, 238); - add_color("DarkSlateGray3", 121, 205, 205); - add_color("DarkSlateGray4", 82, 139, 139); - add_color("aquamarine1", 127, 255, 212); - add_color("aquamarine2", 118, 238, 198); - add_color("aquamarine3", 102, 205, 170); - add_color("aquamarine4", 69, 139, 116); - add_color("DarkSeaGreen1", 193, 255, 193); - add_color("DarkSeaGreen2", 180, 238, 180); - add_color("DarkSeaGreen3", 155, 205, 155); - add_color("DarkSeaGreen4", 105, 139, 105); - add_color("SeaGreen1", 84, 255, 159); - add_color("SeaGreen2", 78, 238, 148); - add_color("SeaGreen3", 67, 205, 128); - add_color("SeaGreen4", 46, 139, 87); - add_color("PaleGreen1", 154, 255, 154); - add_color("PaleGreen2", 144, 238, 144); - add_color("PaleGreen3", 124, 205, 124); - add_color("PaleGreen4", 84, 139, 84); - add_color("SpringGreen1", 0, 255, 127); - add_color("SpringGreen2", 0, 238, 118); - add_color("SpringGreen3", 0, 205, 102); - add_color("SpringGreen4", 0, 139, 69); - add_color("green1", 0, 255, 0); - add_color("green2", 0, 238, 0); - add_color("green3", 0, 205, 0); - add_color("green4", 0, 139, 0); - add_color("chartreuse1", 127, 255, 0); - add_color("chartreuse2", 118, 238, 0); - add_color("chartreuse3", 102, 205, 0); - add_color("chartreuse4", 69, 139, 0); - add_color("OliveDrab1", 192, 255, 62); - add_color("OliveDrab2", 179, 238, 58); - add_color("OliveDrab3", 154, 205, 50); - add_color("OliveDrab4", 105, 139, 34); - add_color("DarkOliveGreen1", 202, 255, 112); - add_color("DarkOliveGreen2", 188, 238, 104); - add_color("DarkOliveGreen3", 162, 205, 90); - add_color("DarkOliveGreen4", 110, 139, 61); - add_color("khaki1", 255, 246, 143); - add_color("khaki2", 238, 230, 133); - add_color("khaki3", 205, 198, 115); - add_color("khaki4", 139, 134, 78); - add_color("LightGoldenrod1", 255, 236, 139); - add_color("LightGoldenrod2", 238, 220, 130); - add_color("LightGoldenrod3", 205, 190, 112); - add_color("LightGoldenrod4", 139, 129, 76); - add_color("LightYellow1", 255, 255, 224); - add_color("LightYellow2", 238, 238, 209); - add_color("LightYellow3", 205, 205, 180); - add_color("LightYellow4", 139, 139, 122); - add_color("yellow1", 255, 255, 0); - add_color("yellow2", 238, 238, 0); - add_color("yellow3", 205, 205, 0); - add_color("yellow4", 139, 139, 0); - add_color("gold1", 255, 215, 0); - add_color("gold2", 238, 201, 0); - add_color("gold3", 205, 173, 0); - add_color("gold4", 139, 117, 0); - add_color("goldenrod1", 255, 193, 37); - add_color("goldenrod2", 238, 180, 34); - add_color("goldenrod3", 205, 155, 29); - add_color("goldenrod4", 139, 105, 20); - add_color("DarkGoldenrod1", 255, 185, 15); - add_color("DarkGoldenrod2", 238, 173, 14); - add_color("DarkGoldenrod3", 205, 149, 12); - add_color("DarkGoldenrod4", 139, 101, 8); - add_color("RosyBrown1", 255, 193, 193); - add_color("RosyBrown2", 238, 180, 180); - add_color("RosyBrown3", 205, 155, 155); - add_color("RosyBrown4", 139, 105, 105); - add_color("IndianRed1", 255, 106, 106); - add_color("IndianRed2", 238, 99, 99); - add_color("IndianRed3", 205, 85, 85); - add_color("IndianRed4", 139, 58, 58); - add_color("sienna1", 255, 130, 71); - add_color("sienna2", 238, 121, 66); - add_color("sienna3", 205, 104, 57); - add_color("sienna4", 139, 71, 38); - add_color("burlywood1", 255, 211, 155); - add_color("burlywood2", 238, 197, 145); - add_color("burlywood3", 205, 170, 125); - add_color("burlywood4", 139, 115, 85); - add_color("wheat1", 255, 231, 186); - add_color("wheat2", 238, 216, 174); - add_color("wheat3", 205, 186, 150); - add_color("wheat4", 139, 126, 102); - add_color("tan1", 255, 165, 79); - add_color("tan2", 238, 154, 73); - add_color("tan3", 205, 133, 63); - add_color("tan4", 139, 90, 43); - add_color("chocolate1", 255, 127, 36); - add_color("chocolate2", 238, 118, 33); - add_color("chocolate3", 205, 102, 29); - add_color("chocolate4", 139, 69, 19); - add_color("firebrick1", 255, 48, 48); - add_color("firebrick2", 238, 44, 44); - add_color("firebrick3", 205, 38, 38); - add_color("firebrick4", 139, 26, 26); - add_color("brown1", 255, 64, 64); - add_color("brown2", 238, 59, 59); - add_color("brown3", 205, 51, 51); - add_color("brown4", 139, 35, 35); - add_color("salmon1", 255, 140, 105); - add_color("salmon2", 238, 130, 98); - add_color("salmon3", 205, 112, 84); - add_color("salmon4", 139, 76, 57); - add_color("LightSalmon1", 255, 160, 122); - add_color("LightSalmon2", 238, 149, 114); - add_color("LightSalmon3", 205, 129, 98); - add_color("LightSalmon4", 139, 87, 66); - add_color("orange1", 255, 165, 0); - add_color("orange2", 238, 154, 0); - add_color("orange3", 205, 133, 0); - add_color("orange4", 139, 90, 0); - add_color("DarkOrange1", 255, 127, 0); - add_color("DarkOrange2", 238, 118, 0); - add_color("DarkOrange3", 205, 102, 0); - add_color("DarkOrange4", 139, 69, 0); - add_color("coral1", 255, 114, 86); - add_color("coral2", 238, 106, 80); - add_color("coral3", 205, 91, 69); - add_color("coral4", 139, 62, 47); - add_color("tomato1", 255, 99, 71); - add_color("tomato2", 238, 92, 66); - add_color("tomato3", 205, 79, 57); - add_color("tomato4", 139, 54, 38); - add_color("OrangeRed1", 255, 69, 0); - add_color("OrangeRed2", 238, 64, 0); - add_color("OrangeRed3", 205, 55, 0); - add_color("OrangeRed4", 139, 37, 0); - add_color("red1", 255, 0, 0); - add_color("red2", 238, 0, 0); - add_color("red3", 205, 0, 0); - add_color("red4", 139, 0, 0); - add_color("DeepPink1", 255, 20, 147); - add_color("DeepPink2", 238, 18, 137); - add_color("DeepPink3", 205, 16, 118); - add_color("DeepPink4", 139, 10, 80); - add_color("HotPink1", 255, 110, 180); - add_color("HotPink2", 238, 106, 167); - add_color("HotPink3", 205, 96, 144); - add_color("HotPink4", 139, 58, 98); - add_color("pink1", 255, 181, 197); - add_color("pink2", 238, 169, 184); - add_color("pink3", 205, 145, 158); - add_color("pink4", 139, 99, 108); - add_color("LightPink1", 255, 174, 185); - add_color("LightPink2", 238, 162, 173); - add_color("LightPink3", 205, 140, 149); - add_color("LightPink4", 139, 95, 101); - add_color("PaleVioletRed1", 255, 130, 171); - add_color("PaleVioletRed2", 238, 121, 159); - add_color("PaleVioletRed3", 205, 104, 137); - add_color("PaleVioletRed4", 139, 71, 93); - add_color("maroon1", 255, 52, 179); - add_color("maroon2", 238, 48, 167); - add_color("maroon3", 205, 41, 144); - add_color("maroon4", 139, 28, 98); - add_color("VioletRed1", 255, 62, 150); - add_color("VioletRed2", 238, 58, 140); - add_color("VioletRed3", 205, 50, 120); - add_color("VioletRed4", 139, 34, 82); - add_color("magenta1", 255, 0, 255); - add_color("magenta2", 238, 0, 238); - add_color("magenta3", 205, 0, 205); - add_color("magenta4", 139, 0, 139); - add_color("orchid1", 255, 131, 250); - add_color("orchid2", 238, 122, 233); - add_color("orchid3", 205, 105, 201); - add_color("orchid4", 139, 71, 137); - add_color("plum1", 255, 187, 255); - add_color("plum2", 238, 174, 238); - add_color("plum3", 205, 150, 205); - add_color("plum4", 139, 102, 139); - add_color("MediumOrchid1", 224, 102, 255); - add_color("MediumOrchid2", 209, 95, 238); - add_color("MediumOrchid3", 180, 82, 205); - add_color("MediumOrchid4", 122, 55, 139); - add_color("DarkOrchid1", 191, 62, 255); - add_color("DarkOrchid2", 178, 58, 238); - add_color("DarkOrchid3", 154, 50, 205); - add_color("DarkOrchid4", 104, 34, 139); - add_color("purple1", 155, 48, 255); - add_color("purple2", 145, 44, 238); - add_color("purple3", 125, 38, 205); - add_color("purple4", 85, 26, 139); - add_color("MediumPurple1", 171, 130, 255); - add_color("MediumPurple2", 159, 121, 238); - add_color("MediumPurple3", 137, 104, 205); - add_color("MediumPurple4", 93, 71, 139); - add_color("thistle1", 255, 225, 255); - add_color("thistle2", 238, 210, 238); - add_color("thistle3", 205, 181, 205); - add_color("thistle4", 139, 123, 139); - add_color("gray0", 0, 0, 0); - add_color("grey0", 0, 0, 0); - add_color("gray1", 3, 3, 3); - add_color("grey1", 3, 3, 3); - add_color("gray2", 5, 5, 5); - add_color("grey2", 5, 5, 5); - add_color("gray3", 8, 8, 8); - add_color("grey3", 8, 8, 8); - add_color("gray4", 10, 10, 10); - add_color("grey4", 10, 10, 10); - add_color("gray5", 13, 13, 13); - add_color("grey5", 13, 13, 13); - add_color("gray6", 15, 15, 15); - add_color("grey6", 15, 15, 15); - add_color("gray7", 18, 18, 18); - add_color("grey7", 18, 18, 18); - add_color("gray8", 20, 20, 20); - add_color("grey8", 20, 20, 20); - add_color("gray9", 23, 23, 23); - add_color("grey9", 23, 23, 23); - add_color("gray10", 26, 26, 26); - add_color("grey10", 26, 26, 26); - add_color("gray11", 28, 28, 28); - add_color("grey11", 28, 28, 28); - add_color("gray12", 31, 31, 31); - add_color("grey12", 31, 31, 31); - add_color("gray13", 33, 33, 33); - add_color("grey13", 33, 33, 33); - add_color("gray14", 36, 36, 36); - add_color("grey14", 36, 36, 36); - add_color("gray15", 38, 38, 38); - add_color("grey15", 38, 38, 38); - add_color("gray16", 41, 41, 41); - add_color("grey16", 41, 41, 41); - add_color("gray17", 43, 43, 43); - add_color("grey17", 43, 43, 43); - add_color("gray18", 46, 46, 46); - add_color("grey18", 46, 46, 46); - add_color("gray19", 48, 48, 48); - add_color("grey19", 48, 48, 48); - add_color("gray20", 51, 51, 51); - add_color("grey20", 51, 51, 51); - add_color("gray21", 54, 54, 54); - add_color("grey21", 54, 54, 54); - add_color("gray22", 56, 56, 56); - add_color("grey22", 56, 56, 56); - add_color("gray23", 59, 59, 59); - add_color("grey23", 59, 59, 59); - add_color("gray24", 61, 61, 61); - add_color("grey24", 61, 61, 61); - add_color("gray25", 64, 64, 64); - add_color("grey25", 64, 64, 64); - add_color("gray26", 66, 66, 66); - add_color("grey26", 66, 66, 66); - add_color("gray27", 69, 69, 69); - add_color("grey27", 69, 69, 69); - add_color("gray28", 71, 71, 71); - add_color("grey28", 71, 71, 71); - add_color("gray29", 74, 74, 74); - add_color("grey29", 74, 74, 74); - add_color("gray30", 77, 77, 77); - add_color("grey30", 77, 77, 77); - add_color("gray31", 79, 79, 79); - add_color("grey31", 79, 79, 79); - add_color("gray32", 82, 82, 82); - add_color("grey32", 82, 82, 82); - add_color("gray33", 84, 84, 84); - add_color("grey33", 84, 84, 84); - add_color("gray34", 87, 87, 87); - add_color("grey34", 87, 87, 87); - add_color("gray35", 89, 89, 89); - add_color("grey35", 89, 89, 89); - add_color("gray36", 92, 92, 92); - add_color("grey36", 92, 92, 92); - add_color("gray37", 94, 94, 94); - add_color("grey37", 94, 94, 94); - add_color("gray38", 97, 97, 97); - add_color("grey38", 97, 97, 97); - add_color("gray39", 99, 99, 99); - add_color("grey39", 99, 99, 99); - add_color("gray40", 102, 102, 102); - add_color("grey40", 102, 102, 102); - add_color("gray41", 105, 105, 105); - add_color("grey41", 105, 105, 105); - add_color("gray42", 107, 107, 107); - add_color("grey42", 107, 107, 107); - add_color("gray43", 110, 110, 110); - add_color("grey43", 110, 110, 110); - add_color("gray44", 112, 112, 112); - add_color("grey44", 112, 112, 112); - add_color("gray45", 115, 115, 115); - add_color("grey45", 115, 115, 115); - add_color("gray46", 117, 117, 117); - add_color("grey46", 117, 117, 117); - add_color("gray47", 120, 120, 120); - add_color("grey47", 120, 120, 120); - add_color("gray48", 122, 122, 122); - add_color("grey48", 122, 122, 122); - add_color("gray49", 125, 125, 125); - add_color("grey49", 125, 125, 125); - add_color("gray50", 127, 127, 127); - add_color("grey50", 127, 127, 127); - add_color("gray51", 130, 130, 130); - add_color("grey51", 130, 130, 130); - add_color("gray52", 133, 133, 133); - add_color("grey52", 133, 133, 133); - add_color("gray53", 135, 135, 135); - add_color("grey53", 135, 135, 135); - add_color("gray54", 138, 138, 138); - add_color("grey54", 138, 138, 138); - add_color("gray55", 140, 140, 140); - add_color("grey55", 140, 140, 140); - add_color("gray56", 143, 143, 143); - add_color("grey56", 143, 143, 143); - add_color("gray57", 145, 145, 145); - add_color("grey57", 145, 145, 145); - add_color("gray58", 148, 148, 148); - add_color("grey58", 148, 148, 148); - add_color("gray59", 150, 150, 150); - add_color("grey59", 150, 150, 150); - add_color("gray60", 153, 153, 153); - add_color("grey60", 153, 153, 153); - add_color("gray61", 156, 156, 156); - add_color("grey61", 156, 156, 156); - add_color("gray62", 158, 158, 158); - add_color("grey62", 158, 158, 158); - add_color("gray63", 161, 161, 161); - add_color("grey63", 161, 161, 161); - add_color("gray64", 163, 163, 163); - add_color("grey64", 163, 163, 163); - add_color("gray65", 166, 166, 166); - add_color("grey65", 166, 166, 166); - add_color("gray66", 168, 168, 168); - add_color("grey66", 168, 168, 168); - add_color("gray67", 171, 171, 171); - add_color("grey67", 171, 171, 171); - add_color("gray68", 173, 173, 173); - add_color("grey68", 173, 173, 173); - add_color("gray69", 176, 176, 176); - add_color("grey69", 176, 176, 176); - add_color("gray70", 179, 179, 179); - add_color("grey70", 179, 179, 179); - add_color("gray71", 181, 181, 181); - add_color("grey71", 181, 181, 181); - add_color("gray72", 184, 184, 184); - add_color("grey72", 184, 184, 184); - add_color("gray73", 186, 186, 186); - add_color("grey73", 186, 186, 186); - add_color("gray74", 189, 189, 189); - add_color("grey74", 189, 189, 189); - add_color("gray75", 191, 191, 191); - add_color("grey75", 191, 191, 191); - add_color("gray76", 194, 194, 194); - add_color("grey76", 194, 194, 194); - add_color("gray77", 196, 196, 196); - add_color("grey77", 196, 196, 196); - add_color("gray78", 199, 199, 199); - add_color("grey78", 199, 199, 199); - add_color("gray79", 201, 201, 201); - add_color("grey79", 201, 201, 201); - add_color("gray80", 204, 204, 204); - add_color("grey80", 204, 204, 204); - add_color("gray81", 207, 207, 207); - add_color("grey81", 207, 207, 207); - add_color("gray82", 209, 209, 209); - add_color("grey82", 209, 209, 209); - add_color("gray83", 212, 212, 212); - add_color("grey83", 212, 212, 212); - add_color("gray84", 214, 214, 214); - add_color("grey84", 214, 214, 214); - add_color("gray85", 217, 217, 217); - add_color("grey85", 217, 217, 217); - add_color("gray86", 219, 219, 219); - add_color("grey86", 219, 219, 219); - add_color("gray87", 222, 222, 222); - add_color("grey87", 222, 222, 222); - add_color("gray88", 224, 224, 224); - add_color("grey88", 224, 224, 224); - add_color("gray89", 227, 227, 227); - add_color("grey89", 227, 227, 227); - add_color("gray90", 229, 229, 229); - add_color("grey90", 229, 229, 229); - add_color("gray91", 232, 232, 232); - add_color("grey91", 232, 232, 232); - add_color("gray92", 235, 235, 235); - add_color("grey92", 235, 235, 235); - add_color("gray93", 237, 237, 237); - add_color("grey93", 237, 237, 237); - add_color("gray94", 240, 240, 240); - add_color("grey94", 240, 240, 240); - add_color("gray95", 242, 242, 242); - add_color("grey95", 242, 242, 242); - add_color("gray96", 245, 245, 245); - add_color("grey96", 245, 245, 245); - add_color("gray97", 247, 247, 247); - add_color("grey97", 247, 247, 247); - add_color("gray98", 250, 250, 250); - add_color("grey98", 250, 250, 250); - add_color("gray99", 252, 252, 252); - add_color("grey99", 252, 252, 252); - add_color("gray100", 255, 255, 255); - add_color("grey100", 255, 255, 255); - add_color("dark grey", 169, 169, 169); - add_color("DarkGrey", 169, 169, 169); - add_color("dark gray", 169, 169, 169); - add_color("DarkGray", 169, 169, 169); - add_color("dark blue", 0, 0, 139); - add_color("DarkBlue", 0, 0, 139); - add_color("dark cyan", 0, 139, 139); - add_color("DarkCyan", 0, 139, 139); - add_color("dark magenta", 139, 0, 139); - add_color("DarkMagenta", 139, 0, 139); - add_color("dark red", 139, 0, 0); - add_color("DarkRed", 139, 0, 0); - add_color("light green", 144, 238, 144); - add_color("LightGreen", 144, 238, 144); - add_color("crimson", 220, 20, 60); - add_color("indigo", 75, 0, 130); - add_color("olive", 128, 128, 0); - add_color("rebecca purple", 102, 51, 153); - add_color("RebeccaPurple", 102, 51, 153); - add_color("silver", 192, 192, 192); - add_color("teal", 0, 128, 128); + + for(i = 0; i < sizeof(color_entries) / sizeof(struct color_table_entry); i++) { + add_color(color_entries[i].key, color_entries[i].red, color_entries[i].green, color_entries[i].blue); + } + + for(grayID = 0; grayID < 100; grayID++) { + char grayName[255]; + MwStringPrintIntoBuffer(grayName, 255, "gray%d", grayID); + add_color(grayName, gray, gray, gray); + MwStringPrintIntoBuffer(grayName, 255, "grey%d", grayID); + add_color(grayName, gray, gray, gray); + gray += 3; + } } diff --git a/src/core.c b/src/core.c index 59984a5..eb240d6 100644 --- a/src/core.c +++ b/src/core.c @@ -881,11 +881,17 @@ void MwVaListApply(MwWidget handle, va_list va) { } void MwSetDefault(MwWidget handle) { +#ifndef __WINDOWS__ if(handle->lowlevel != NULL) MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); +#endif } void MwHideCursor(MwWidget handle) { +#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorHidden, &MwCursorHiddenMask); +#else + MwLLSetCursor(handle->lowlevel, NULL, NULL); +#endif } void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data) { @@ -934,10 +940,14 @@ void MwDispatchError(int code, const char* message) { if(error_handler != NULL) { error_handler(code, message, error_user_data); } else { -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) char buffer[1024]; MwStringPrintIntoBuffer(buffer, 1024, "Error: %s\r\nCode : %d\r\n\r\nMilsko is exiting.", message, code); +#if defined(__WINDOWS__) + MessageBox(NULL, buffer, "Error", MB_ICONHAND | MB_OK); +#else MessageBox(NULL, buffer, "Error", MB_ICONERROR | MB_OK); +#endif #else fprintf(stderr, "Error: %s\nCode : %d\n\nMilsko is exiting.", message, code); #endif @@ -1019,7 +1029,9 @@ int MwLibraryInit(void) { MwColorTableInit(); +#ifndef __WINDOWS__ MwFLSetup(); +#endif for(i = 0; calls[i] != NULL; i++) { if(calls[i]() == 0) return 0; diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 926fddc..d36b0f5 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -1,5 +1,7 @@ #include +#ifndef __WINDOWS__ + #define WIN_SIZE 464 #define PICKER_SIZE 364 #define IMG_POS_X(w) ((w - PICKER_SIZE) / 2) @@ -378,3 +380,5 @@ MwWidget MwColorPicker(MwWidget handle, const char* title) { return window; } + +#endif diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index 138fc6c..415b550 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -1,5 +1,7 @@ #include +#ifndef __WINDOWS__ + #include "../external/stb_ds.h" typedef struct filechooser { @@ -505,8 +507,9 @@ static void scan(MwWidget handle, const char* path, int record) { } static void setup_fallback_filechooser(MwWidget window, int dir) { - char* path; - MwLLPixmap icon; + char* path; + MwLLPixmap icon; + filechooser_t* fc = malloc(sizeof(*fc)); memset(fc, 0, sizeof(*fc)); @@ -568,6 +571,32 @@ MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { return window; } +#else +MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { + MwWidget window; + int w, h; + int wx; + int wy; + + w = 700; + h = w * 2 / 3; + + if(handle == NULL) { + wx = wy = MwDEFAULT; + } else { + wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; + wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; + } + + window = MwVaCreateWidget(MwWindowClass, "filechooser", NULL, wx, wy, w, h, + MwNtitle, title, + NULL); + if(handle != NULL) MwReparent(window, handle); + + return window; +} +#endif + MwWidget MwFileChooser(MwWidget handle, const char* title) { return MwFileChooserEx(handle, title, 0); } diff --git a/src/dialog/messagebox.c b/src/dialog/messagebox.c index f7084ab..4606dae 100644 --- a/src/dialog/messagebox.c +++ b/src/dialog/messagebox.c @@ -68,9 +68,11 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi if(flag & MwMB_BUTTONYES) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONYES, "Yes"); if((flag & MwMB_ICONMASK) != 0) { - MwWidget icon; - MwLLPixmap px; - unsigned int* data = NULL; + MwWidget icon; + MwLLPixmap px; + MwU32* data = NULL; + +#ifndef __WINDOWS__ icon = MwCreateWidget(MwImageClass, "image", window, 8, (h - 48) / 2, 48, 48); @@ -110,6 +112,7 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi px = MwLoadIcon(icon, data); MwSetVoid(icon, MwNpixmap, px); +#endif left = 8 + 48 + 8; } diff --git a/src/draw.c b/src/draw.c index d8cadad..12d5440 100644 --- a/src/draw.c +++ b/src/draw.c @@ -115,6 +115,7 @@ void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPolygon(handle->lowlevel, p, 4, color); } +#ifndef __WINDOWS__ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; int y; @@ -153,6 +154,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { free(data); } +#endif void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwDrawFrameWithBorder(handle, rect, color, invert, MwDefaultBorderWidth(handle)); @@ -220,12 +222,17 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; color_set_disabled_if_disabled(handle, col); +#ifndef __WINDOWS__ if(MwGetInteger(handle, MwNmodernLook)) { MwDrawRectFading(handle, rect, col); - } else { + } else +#else + { MwDrawRect(handle, rect, col); } - if(col != color) MwLLFreeColor(col); +#endif + if(col != color) + MwLLFreeColor(col); } void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -352,6 +359,7 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, rect->height -= border * 2; } +#ifndef __WINDOWS__ static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { MwPoint p[7]; @@ -423,13 +431,17 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color rect->width -= border * 2; rect->height -= border * 2; } +#endif void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { border = translate_border(handle, border); +#ifndef __WINDOWS__ if(MwGetInteger(handle, MwNmodernLook)) { MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same); - } else { + } else +#endif + { MwDrawFrameEx_simple(handle, rect, color, invert, border, diff, same); } } @@ -894,6 +906,7 @@ typedef struct color { int a; } color_t; +#ifndef __WINDOWS__ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { int col, row, colors, cpp; unsigned char* rgb; @@ -966,3 +979,4 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { return px; } +#endif diff --git a/src/text/text.c b/src/text/text.c index b6297e3..955be5f 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1,12 +1,14 @@ #include +#ifndef __WINDOWS int (*MwFLDrawText)(MwWidget handle, MwFLFont font, MwPoint* point, const char* text, MwLLColor color) = NULL; int (*MwFLTextWidth)(MwFLFont font, const char* text) = NULL; int (*MwFLTextHeight)(MwFLFont font, int count) = NULL; void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px) = NULL; void (*MwFLFontFree)(void* handle) = NULL; +#endif -#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) +#if (defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE)) && !defined(__WINDOWS__) #define TTF #endif @@ -292,6 +294,7 @@ static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, free(px); } +#ifndef __INWDOWS__ typedef int (*call_t)(void); void MwFLSetup(void) { call_t calls[] = { @@ -308,3 +311,4 @@ void MwFLSetup(void) { if(calls[i]() == 0) return; } } +#endif diff --git a/src/widget/combobox.c b/src/widget/combobox.c index e53647d..6bfc1e8 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -102,7 +102,9 @@ static void click(MwWidget handle) { if(ent > arrlen(cb->list)) ent = arrlen(cb->list); +#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorArrow, &MwCursorArrowMask); +#endif for(i = 0; i < arrlen(cb->list); i++) { int l = MwTextWidth(handle, NULL, cb->list[i]) + MwDefaultBorderWidth(handle) * 2; @@ -113,7 +115,9 @@ static void click(MwWidget handle) { MwNsingleClickSelectable, 1, NULL); +#ifndef __WINDOWS__ MwLLSetCursor(((MwListBox)cb->listbox->internal)->frame->lowlevel, &MwCursorArrow, &MwCursorArrowMask); +#endif for(i = 0; i < arrlen(cb->list); i++) { MwListBoxSet(cb->listbox, -1, 0, cb->list[i]); @@ -128,7 +132,9 @@ static void click(MwWidget handle) { MwLLMakeToolWindow(cb->listbox->lowlevel); MwLLEndStateChange(cb->listbox->lowlevel); } else { +#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); +#endif if(cb->listbox != NULL) { MwDestroyWidget(cb->listbox); diff --git a/src/widget/entry.c b/src/widget/entry.c index 8580768..0323ef6 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -10,7 +10,9 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); +#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); +#endif return 0; } diff --git a/src/widget/label.c b/src/widget/label.c index 5a165e7..d346219 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -4,6 +4,11 @@ #define Spacing 1 +/* 16 bit windows */ +#ifdef __WINDOWS__ +#define HAVE_SEVEN_SEGMENT 0 +#endif + static int wcreate(MwWidget handle) { MwLabel lab = malloc(sizeof(*lab)); memset(lab, 0, sizeof(*lab)); @@ -122,6 +127,7 @@ static void draw_h(MwWidget handle, unsigned char* raw, int x, int y, int stride } } +#ifndef HAVE_SEVEN_SEGMENT static void draw_seven_segment(MwWidget handle) { MwRect r; MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); @@ -311,6 +317,7 @@ static void draw_seven_segment(MwWidget handle) { MwLLDestroyPixmap(px); } +#endif static void draw_normal(MwWidget handle) { MwRect r; @@ -377,9 +384,11 @@ static void prop_change(MwWidget handle, const char* key) { if(strcmp(key, MwNsevenSegment) == 0) { MwLabel lab = handle->internal; +#ifndef HAVE_SEVEN_SEGMENT if(MwGetInteger(handle, MwNsevenSegment)) lab->draw = draw_seven_segment; else +#endif lab->draw = draw_normal; } } diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index f3a80e9..63c4259 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -85,11 +85,13 @@ static void key(MwWidget handle, int code) { static void mouse_move(MwWidget handle) { MwEntry e = handle->internal; int w = MwGetInteger(handle, MwNwidth); +#ifndef __WINDOWS__ if(handle->mouse_point.x >= (w - e->right)) { MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); } else { MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); } +#endif } static void mouse_up(MwWidget handle, void* ptr) { From 1272c613c03196698d17ab7f89ee965b23ee1750 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 9 Aug 2026 14:45:07 -0700 Subject: [PATCH 02/95] revert some removals --- WatMakefile | 6 +++--- src/dialog/filechooser.c | 28 ---------------------------- src/dialog/messagebox.c | 3 --- src/draw.c | 2 -- src/widget/combobox.c | 6 ------ src/widget/entry.c | 2 -- src/widget/label.c | 5 ----- src/widget/numberentry.c | 2 -- 8 files changed, 3 insertions(+), 51 deletions(-) diff --git a/WatMakefile b/WatMakefile index eca4ed8..522c300 100644 --- a/WatMakefile +++ b/WatMakefile @@ -12,7 +12,7 @@ MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -d MW_LDFLAGS = system nt_dll EXE_LDFLAGS = system nt !else -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE -os -oh +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE -ml -zm -zW MW_LDFLAGS = system windows_dll EXE_LDFLAGS = system windows !endif @@ -334,8 +334,8 @@ examples/gldemos/tripaint.obj: 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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 user32.lib library advapi32.lib !else -src/Mw.dll: external/stb_ds.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/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/lowlevel.obj src/string.obj src/text/text.obj src/text/font/font.obj src/text/font/boldfont.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/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/stb_ds.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/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/lowlevel.obj file src/string.obj file src/text/text.obj file src/text/font/font.obj file src/text/font/boldfont.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/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 clibs.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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 clibs.lib !endif diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index 415b550..8b03e4e 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -1,7 +1,5 @@ #include -#ifndef __WINDOWS__ - #include "../external/stb_ds.h" typedef struct filechooser { @@ -571,32 +569,6 @@ MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { return window; } -#else -MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { - MwWidget window; - int w, h; - int wx; - int wy; - - w = 700; - h = w * 2 / 3; - - if(handle == NULL) { - wx = wy = MwDEFAULT; - } else { - wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; - wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; - } - - window = MwVaCreateWidget(MwWindowClass, "filechooser", NULL, wx, wy, w, h, - MwNtitle, title, - NULL); - if(handle != NULL) MwReparent(window, handle); - - return window; -} -#endif - MwWidget MwFileChooser(MwWidget handle, const char* title) { return MwFileChooserEx(handle, title, 0); } diff --git a/src/dialog/messagebox.c b/src/dialog/messagebox.c index 4606dae..ff72bc8 100644 --- a/src/dialog/messagebox.c +++ b/src/dialog/messagebox.c @@ -72,8 +72,6 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi MwLLPixmap px; MwU32* data = NULL; -#ifndef __WINDOWS__ - icon = MwCreateWidget(MwImageClass, "image", window, 8, (h - 48) / 2, 48, 48); switch(flag & MwMB_ICONMASK) { @@ -112,7 +110,6 @@ MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsi px = MwLoadIcon(icon, data); MwSetVoid(icon, MwNpixmap, px); -#endif left = 8 + 48 + 8; } diff --git a/src/draw.c b/src/draw.c index 12d5440..5e593bd 100644 --- a/src/draw.c +++ b/src/draw.c @@ -906,7 +906,6 @@ typedef struct color { int a; } color_t; -#ifndef __WINDOWS__ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { int col, row, colors, cpp; unsigned char* rgb; @@ -979,4 +978,3 @@ MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { return px; } -#endif diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 6bfc1e8..e53647d 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -102,9 +102,7 @@ static void click(MwWidget handle) { if(ent > arrlen(cb->list)) ent = arrlen(cb->list); -#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorArrow, &MwCursorArrowMask); -#endif for(i = 0; i < arrlen(cb->list); i++) { int l = MwTextWidth(handle, NULL, cb->list[i]) + MwDefaultBorderWidth(handle) * 2; @@ -115,9 +113,7 @@ static void click(MwWidget handle) { MwNsingleClickSelectable, 1, NULL); -#ifndef __WINDOWS__ MwLLSetCursor(((MwListBox)cb->listbox->internal)->frame->lowlevel, &MwCursorArrow, &MwCursorArrowMask); -#endif for(i = 0; i < arrlen(cb->list); i++) { MwListBoxSet(cb->listbox, -1, 0, cb->list[i]); @@ -132,9 +128,7 @@ static void click(MwWidget handle) { MwLLMakeToolWindow(cb->listbox->lowlevel); MwLLEndStateChange(cb->listbox->lowlevel); } else { -#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); -#endif if(cb->listbox != NULL) { MwDestroyWidget(cb->listbox); diff --git a/src/widget/entry.c b/src/widget/entry.c index 0323ef6..8580768 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -10,9 +10,7 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); -#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); -#endif return 0; } diff --git a/src/widget/label.c b/src/widget/label.c index d346219..6e55816 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -4,11 +4,6 @@ #define Spacing 1 -/* 16 bit windows */ -#ifdef __WINDOWS__ -#define HAVE_SEVEN_SEGMENT 0 -#endif - static int wcreate(MwWidget handle) { MwLabel lab = malloc(sizeof(*lab)); memset(lab, 0, sizeof(*lab)); diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 63c4259..f3a80e9 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -85,13 +85,11 @@ static void key(MwWidget handle, int code) { static void mouse_move(MwWidget handle) { MwEntry e = handle->internal; int w = MwGetInteger(handle, MwNwidth); -#ifndef __WINDOWS__ if(handle->mouse_point.x >= (w - e->right)) { MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); } else { MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); } -#endif } static void mouse_up(MwWidget handle, void* ptr) { From 4990a5e8f0118f41c849a7c9b4b15c5d60f410a9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 9 Aug 2026 15:13:41 -0700 Subject: [PATCH 03/95] back to error state --- WatMakefile | 37 +++++++++++++------- include/Mw/LowLevel.h | 6 ++-- include/Mw/Milsko.h | 2 -- include/Mw/Resource/Cursor.h | 3 -- src/abstract/directory.c | 2 +- src/backend/gdi.c | 65 ++++++++++++++++++++++++++++-------- src/core.c | 17 +++++----- src/dialog/filechooser.c | 2 +- src/draw.c | 18 ++-------- src/lowlevel.c | 8 ++--- 10 files changed, 96 insertions(+), 64 deletions(-) diff --git a/WatMakefile b/WatMakefile index 4533f3c..480f38f 100644 --- a/WatMakefile +++ b/WatMakefile @@ -1,10 +1,22 @@ +!ifndef %mw16 CC = wcc386 -bt=nt -q +!else +CC = wcc -bt=windows -q +!endif + LD = wlink option quiet -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dUSE_GDI_TEXT -dMW_OPENGL -MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include +!ifndef %mw16 +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dMW_OPENGL +MW_LDFLAGS = system nt_dll EXE_LDFLAGS = system nt +!else +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE +MW_LDFLAGS = system windows_dll +EXE_LDFLAGS = system windows +!endif + 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 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 @@ -70,10 +82,8 @@ clean: .SYMBOLIC %erase src/text/font/monottf.obj %erase src/text/font/ttf.obj %erase src/text/ft2.obj - %erase src/text/gdi.obj %erase src/text/stbtt.obj %erase src/text/text.obj - %erase src/truetype.obj %erase src/unicode.obj %erase src/widget/box.obj %erase src/widget/button.obj @@ -282,6 +292,7 @@ examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll examples/basic/viewport.obj: examples/basic/viewport.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c +!ifndef %mw16 examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib @@ -317,11 +328,15 @@ examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c +!endif - -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 - +!ifndef %mw16 +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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 user32.lib library advapi32.lib +!else +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/stbtt.obj src/text/text.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/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/stbtt.obj file src/text/text.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/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 clibs.lib +!endif external/libz/src/adler32.obj: external/libz/src/adler32.c @@ -446,14 +461,10 @@ src/text/font/ttf.obj: src/text/font/ttf.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c src/text/ft2.obj: src/text/ft2.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/ft2.c -src/text/gdi.obj: src/text/gdi.c - $(CC) $(MW_CFLAGS) -fo=$@ src/text/gdi.c src/text/stbtt.obj: src/text/stbtt.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c src/text/text.obj: src/text/text.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/text.c -src/truetype.obj: src/truetype.c - $(CC) $(MW_CFLAGS) -fo=$@ src/truetype.c src/unicode.obj: src/unicode.c $(CC) $(MW_CFLAGS) -fo=$@ src/unicode.c src/widget/box.obj: src/widget/box.c @@ -480,8 +491,10 @@ src/widget/menu.obj: src/widget/menu.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c src/widget/numberentry.obj: src/widget/numberentry.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c +!ifndef %mw16 src/widget/opengl.obj: src/widget/opengl.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c +!endif src/widget/progressbar.obj: src/widget/progressbar.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c src/widget/radiobox.obj: src/widget/radiobox.c diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index b635a4c..95adad0 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -365,10 +365,10 @@ MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px); MWDECL void (*MwFLFontFree)(void* handle); #endif -#ifdef _WIN32 +#if defined(_WIN32) || defined(__WINDOWS__) MWDECL void* MwLL_winmmLib; -MWDECL long(__stdcall* MwLL_PFN_timeGetTime)(void); -MWDECL unsigned int(__stdcall* MwLL_PFN_timeBeginPeriod)(unsigned int period); +MWDECL long(WINAPI* MwLL_PFN_timeGetTime)(void); +MWDECL unsigned int(WINAPI* MwLL_PFN_timeBeginPeriod)(unsigned int period); #endif #ifdef __cplusplus diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index d39f93a..4f80700 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -24,9 +24,7 @@ #include #include -#ifndef __WINDOWS__ #include -#endif #include #include diff --git a/include/Mw/Resource/Cursor.h b/include/Mw/Resource/Cursor.h index fc75979..9a47802 100644 --- a/include/Mw/Resource/Cursor.h +++ b/include/Mw/Resource/Cursor.h @@ -13,7 +13,6 @@ extern "C" { #endif -#ifndef __WINDOWS__ /*! * @brief Default cursor */ @@ -64,8 +63,6 @@ MWDECL MwCursor MwCursorHidden; */ MWDECL MwCursor MwCursorHiddenMask; -#endif - #ifdef __cplusplus } #endif diff --git a/src/abstract/directory.c b/src/abstract/directory.c index c890732..122f423 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -45,7 +45,7 @@ void* MwDirectoryOpen(const char* path) { free(p); dir->next = 1; #elif defined(__WINDOWS__) - char* p = malloc(strlen(path) + 2 + 1); + p = malloc(strlen(path) + 2 + 1); strcpy(p, path); if(strchr(path, '/') != NULL) { strcat(p, "/"); diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 2ae4de6..bc0990d 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -176,6 +176,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { MwLLDispatch(u->ll, up, &p); break; } +#ifndef __WINDOWS__ case WM_DROPFILES: { HDROP hDrop = (HDROP)wp; @@ -197,6 +198,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { wsymtbl.DragFinish(hDrop); break; } +#endif case WM_MOUSEMOVE: { MwPoint p; @@ -252,6 +254,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { case WM_CLOSE: { MwLLDispatch(u->ll, close, NULL); + break; } case WM_CHAR: case WM_SYSCHAR: @@ -283,6 +286,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { case WM_KILLFOCUS: { MwLLDispatch(u->ll, focus_out, NULL); + break; } case WM_KEYDOWN: case WM_KEYUP: @@ -294,20 +298,43 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { #else unsigned long n = -1; #endif - if(wp == VK_MENU && msg == WM_KEYUP) return 0; - if(wp == VK_LEFT) n = MwKEY_LEFT; - if(wp == VK_RIGHT) n = MwKEY_RIGHT; - if(wp == VK_UP) n = MwKEY_UP; - if(wp == VK_DOWN) n = MwKEY_DOWN; - if(wp == VK_RETURN) n = MwKEY_ENTER; - if(wp == VK_BACK) n = MwKEY_BACKSPACE; - if(wp == VK_ESCAPE) n = MwKEY_ESCAPE; + switch(wp) { + case VK_LEFT: + n = MwKEY_LEFT; + break; + case VK_RIGHT: + n = MwKEY_RIGHT; + break; + case VK_UP: + n = MwKEY_UP; + break; + case VK_DOWN: + n = MwKEY_DOWN; + break; + case VK_RETURN: + n = MwKEY_ENTER; + break; + case VK_BACK: + n = MwKEY_BACKSPACE; + break; + case VK_ESCAPE: + n = MwKEY_ESCAPE; + break; #ifndef __WINDOWS__ - if(wp == VK_LSHIFT) n = MwKEY_LEFTSHIFT; - if(wp == VK_RSHIFT) n = MwKEY_RIGHTSHIFT; + case VK_LSHIFT: + n = MwKEY_LEFTSHIFT; + break; + case VK_RSHIFT: + n = MwKEY_RIGHTSHIFT; + break; #endif - if(wp == VK_MENU) n = MwKEY_ALT; - if(wp == VK_CONTROL) n = MwKEY_CONTROL; + case VK_MENU: + n = MwKEY_ALT; + break; + case VK_CONTROL: + n = MwKEY_CONTROL; + break; + } if((msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) && n != -1 && wp != VK_MENU) { n |= MwKEY_ALT_FLAG; @@ -376,6 +403,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); } #endif + break; } default: { @@ -533,6 +561,11 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { MwLLColor c = malloc(sizeof(*c)); + if(!c) { + printf("Out Of Memory\n"); + return NULL; + } + c->gdi.brush = 0; MwLLColorUpdate(handle, c, r, g, b); @@ -551,8 +584,10 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { if(g < 0) g = 0; if(b < 0) b = 0; + color = GetNearestColor(dc, RGB(r, g, b)); + if(c->gdi.brush != 0) DeleteObject(c->gdi.brush); - c->gdi.brush = CreateSolidBrush(GetNearestColor(dc, RGB(r, g, b))); + c->gdi.brush = CreateSolidBrush(color); c->common.red = r; c->common.green = g; c->common.blue = b; @@ -1143,7 +1178,9 @@ static void MwLLClipImpl(MwLL handle, MwRect* rect) { } static void MwLLSetupDragAndDropImpl(MwLL handle) { +#ifndef __WINDOWS__ wsymtbl.DragAcceptFiles(handle->gdi.hWnd, TRUE); +#endif } static int MwLLGDICallInitImpl(void) { @@ -1160,7 +1197,6 @@ static int MwLLGDICallInitImpl(void) { } else { is_plgblt_reliable = 1; } -#endif wsymtbl.has_drag_and_drop = MwFALSE; @@ -1183,6 +1219,7 @@ static int MwLLGDICallInitImpl(void) { wsymtbl.has_drag_and_drop = MwTRUE; } dnd_error: +#endif /* TODO: check properly */ return 0; diff --git a/src/core.c b/src/core.c index a25d736..85cf12f 100644 --- a/src/core.c +++ b/src/core.c @@ -953,9 +953,7 @@ void MwVaListApply(MwWidget handle, va_list va) { } void MwSetDefault(MwWidget handle) { -#ifndef __WINDOWS__ if(handle->lowlevel != NULL) MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); -#endif } void MwHideCursor(MwWidget handle) { @@ -1099,15 +1097,16 @@ int MwLibraryInit(void) { NULL}; int i; -#ifdef _WIN32 - /* +#if defined(_WIN32) || defined(__WINDOWS__) + /* 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. + This could maybe be removed? */ - 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"); + assert(MwLL_PFN_timeGetTime); + assert(MwLL_PFN_timeBeginPeriod); MwLL_PFN_timeBeginPeriod(10); #endif diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index 8b03e4e..b3bd49a 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -146,7 +146,7 @@ static void MWAPI nav_activate(MwWidget handle, void* user, void* call) { (void)user; if(strcmp(e, "Home") == 0) { -#if defined(_WIN32) || defined(CLASSIC_MAC_OS) +#if defined(_WIN32) || defined(CLASSIC_MAC_OS) || defined(__WINDOWS__) #else struct passwd* p = getpwuid(getuid()); diff --git a/src/draw.c b/src/draw.c index b5c60fe..c6de78f 100644 --- a/src/draw.c +++ b/src/draw.c @@ -117,7 +117,6 @@ void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPolygon(handle->lowlevel, p, 4, color); } -#ifndef __WINDOWS__ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; int y; @@ -159,7 +158,6 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { free(data); } -#endif void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwDrawFrameWithBorder(handle, rect, color, invert, MwDefaultBorderWidth(handle)); @@ -227,17 +225,12 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); color_set_disabled_if_disabled(handle, col); -#ifndef __WINDOWS__ if(MwGetInteger(handle, MwNmodernLook)) { MwDrawRectFading(handle, rect, col); - } else -#else - { + } else { MwDrawRect(handle, rect, col); } -#endif - if(col != color) - MwLLFreeColor(col); + MwLLFreeColor(col); } void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -364,7 +357,6 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, rect->height -= border * 2; } -#ifndef __WINDOWS__ static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { MwPoint p[7]; @@ -436,17 +428,13 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color rect->width -= border * 2; rect->height -= border * 2; } -#endif void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { border = translate_border(handle, border); -#ifndef __WINDOWS__ if(MwGetInteger(handle, MwNmodernLook)) { MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same); - } else -#endif - { + } else { MwDrawFrameEx_simple(handle, rect, color, invert, border, diff, same); } } diff --git a/src/lowlevel.c b/src/lowlevel.c index 2fe1535..d6846ce 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); +#if defined(WIN32) || defined(__WINDOWS__) +void* MwLL_winmmLib; +long(WINAPI* MwLL_PFN_timeGetTime)(void); +unsigned int(WINAPI* MwLL_PFN_timeBeginPeriod)(unsigned int period); #endif MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height) = NULL; From c8cdaecf726ac7e3258fab7b946ba188f9eb5b9a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 9 Aug 2026 15:30:02 -0700 Subject: [PATCH 04/95] properly generate WatMakefile instead of just manually modifiying it Oops --- NTMakefile | 1 + WatMakefile | 26 +++++++++++++++----------- tools/genmk.pl | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/NTMakefile b/NTMakefile index 63a4a2c..c0fc4b0 100644 --- a/NTMakefile +++ b/NTMakefile @@ -5,6 +5,7 @@ MW_CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /D_MILSKO_BUILD /DUSE_G 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 lib: src\Mw.dll diff --git a/WatMakefile b/WatMakefile index 480f38f..46a776b 100644 --- a/WatMakefile +++ b/WatMakefile @@ -3,13 +3,12 @@ CC = wcc386 -bt=nt -q !else CC = wcc -bt=windows -q !endif - LD = wlink option quiet -EXE_CFLAGS = -i=include !ifndef %mw16 -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dMW_OPENGL +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dUSE_GDI_TEXT -dMW_OPENGL MW_LDFLAGS = system nt_dll +EXE_CFLAGS = -i=include EXE_LDFLAGS = system nt !else MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE @@ -82,8 +81,10 @@ clean: .SYMBOLIC %erase src/text/font/monottf.obj %erase src/text/font/ttf.obj %erase src/text/ft2.obj + %erase src/text/gdi.obj %erase src/text/stbtt.obj %erase src/text/text.obj + %erase src/truetype.obj %erase src/unicode.obj %erase src/widget/box.obj %erase src/widget/button.obj @@ -292,7 +293,6 @@ examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll examples/basic/viewport.obj: examples/basic/viewport.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c -!ifndef %mw16 examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib @@ -328,15 +328,17 @@ examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c -!endif + !ifndef %mw16 -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/stbtt.obj src/text/text.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/stbtt.obj file src/text/text.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 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/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 !else -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/stbtt.obj src/text/text.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/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/stbtt.obj file src/text/text.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/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 clibs.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/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 clibs.lib + !endif + external/libz/src/adler32.obj: external/libz/src/adler32.c @@ -461,10 +463,14 @@ src/text/font/ttf.obj: src/text/font/ttf.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c src/text/ft2.obj: src/text/ft2.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/ft2.c +src/text/gdi.obj: src/text/gdi.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/gdi.c src/text/stbtt.obj: src/text/stbtt.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c src/text/text.obj: src/text/text.c $(CC) $(MW_CFLAGS) -fo=$@ src/text/text.c +src/truetype.obj: src/truetype.c + $(CC) $(MW_CFLAGS) -fo=$@ src/truetype.c src/unicode.obj: src/unicode.c $(CC) $(MW_CFLAGS) -fo=$@ src/unicode.c src/widget/box.obj: src/widget/box.c @@ -491,10 +497,8 @@ src/widget/menu.obj: src/widget/menu.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c src/widget/numberentry.obj: src/widget/numberentry.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c -!ifndef %mw16 src/widget/opengl.obj: src/widget/opengl.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c -!endif src/widget/progressbar.obj: src/widget/progressbar.c $(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c src/widget/radiobox.obj: src/widget/radiobox.c diff --git a/tools/genmk.pl b/tools/genmk.pl index 689e09e..247b868 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -112,15 +112,33 @@ sub generate { } open(OUT, ">", $output); - print(OUT "CC = $cc\n"); + if ($type eq "Watcom") { + print(OUT "!ifndef %mw16\n"); + print(OUT "CC = $cc\n"); + print(OUT "!else\n"); + print(OUT "CC = wcc -bt=windows -q\n"); + print(OUT "!endif\n"); + } else { + print(OUT "CC = $cc\n"); + } print(OUT "LD = $link\n"); print(OUT "\n"); + if ($type eq "Watcom") { + print(OUT "!ifndef %mw16\n"); + } print(OUT "MW_CFLAGS = ${cdll} ${inc}include ${inc}external${dir}libz${dir}include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}USE_STB_IMAGE ${def}STBI_NO_SIMD ${def}USE_GDI_TEXT ${def}MW_OPENGL\n" ); print(OUT "MW_LDFLAGS = $dll\n"); print(OUT "EXE_CFLAGS = ${inc}include\n"); - print(OUT "EXE_LDFLAGS = $exe"); + print(OUT "EXE_LDFLAGS = $exe\n"); + if ($type eq "Watcom") { + print(OUT "!else\n"); + print(OUT "MW_CFLAGS = -bd ${inc}include ${inc}external/libz/include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}STBI_NO_SIMD ${def}NO_IMAGE\n"); + print(OUT "MW_LDFLAGS = system windows_dll\n"); + print(OUT "EXE_LDFLAGS = system windows\n"); + print(OUT "!endif\n"); + } print(OUT "\n"); if ($suffix) { @@ -187,11 +205,24 @@ sub generate { print(OUT "\n"); } print(OUT "\n"); + if ($type eq "Watcom") { + print(OUT "!ifndef %mw16\n"); + } print(OUT "src${dir}Mw.dll: " . cobjs($dir) . "\n"); print( OUT " \$(LD) \$(MW_LDFLAGS) $c_dllout $dllout\$@ " . cobjs($dir, $prefobj) . " $needlibs ${lib}opengl32.lib ${lib}gdi32.lib ${lib}ole32.lib ${lib}uuid.lib ${lib}user32.lib ${lib}advapi32.lib\n" ); + if ($type eq "Watcom") { + print(OUT "!else\n"); + print(OUT "src${dir}Mw.dll: " . cobjs($dir) . "\n"); + print( OUT " \$(LD) \$(MW_LDFLAGS) $c_dllout $dllout\$@ " + . cobjs($dir, $prefobj) + . " $needlibs ${lib}clibs.lib\n" + ); + print(OUT "\n"); + print(OUT "!endif\n"); + } print(OUT " $c_dllafter\n"); print(OUT "\n"); From 74f17d71a27a59c4782c64e0ac9739cd1cb38416 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 9 Aug 2026 15:35:48 -0700 Subject: [PATCH 05/95] new MW_16 define for stuff that won't be done on Any 16-bit platform --- WatMakefile | 2 +- examples/basic/colorpicker.c | 8 ++++---- external/stb_ds.h | 2 +- external/stb_image.h | 6 +++--- include/Mw/BaseTypes.h | 4 ++-- include/Mw/Constants.h | 2 +- include/Mw/Dialog/ColorPicker.h | 4 ++-- include/Mw/Draw.h | 2 -- include/Mw/LowLevel.h | 2 +- src/core.c | 9 +++------ src/dialog/colorpicker.c | 2 +- src/text/text.c | 2 +- tools/genmk.pl | 2 +- 13 files changed, 21 insertions(+), 26 deletions(-) diff --git a/WatMakefile b/WatMakefile index 46a776b..504abee 100644 --- a/WatMakefile +++ b/WatMakefile @@ -11,7 +11,7 @@ MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include EXE_LDFLAGS = system nt !else -MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dSTBI_NO_SIMD -dNO_IMAGE -dMW_16 MW_LDFLAGS = system windows_dll EXE_LDFLAGS = system windows !endif diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 65f507e..1a5f423 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -4,14 +4,14 @@ MwWidget fpicker; MwWidget window; /* This example does nothing on Win16 because we don't support the color picker on it (yet?) */ -#ifdef __WINDOWS__ +#ifdef MW_16 MwWidget missing_text; #else MwWidget button; #endif -/* don't bother with color picker on win16 */ -#ifndef __WINDOWS__ +/* don't bother with color picker on 16-bit */ +#ifndef MW_16 void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { char hexColor[8]; MwRGB* rgb = call_data; @@ -46,7 +46,7 @@ int main() { MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); -#ifndef __WINDOWS__ +#ifndef MW_16 button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); diff --git a/external/stb_ds.h b/external/stb_ds.h index 41c1343..c58b00f 100644 --- a/external/stb_ds.h +++ b/external/stb_ds.h @@ -1647,7 +1647,7 @@ typedef struct { static char buffer[256]; char* strkey(int n) { -#if defined(_WIN32) || defined(__WINDOWS__) && defined(__STDC_WANT_SECURE_LIB__) +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) sprintf_s(buffer, sizeof(buffer), "test_%d", n); #else sprintf(buffer, "test_%d", n); diff --git a/external/stb_image.h b/external/stb_image.h index d4fe98f..4f2839c 100644 --- a/external/stb_image.h +++ b/external/stb_image.h @@ -1275,12 +1275,12 @@ static void stbi__float_postprocess(float* result, int* x, int* y, int* comp, in #ifndef STBI_NO_STDIO -#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char* str, int cbmb, wchar_t* widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t* widestr, int cchwide, char* str, int cbmb, const char* defchar, int* used_default); #endif -#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char* buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int)bufferlen, NULL, NULL); } @@ -1288,7 +1288,7 @@ STBIDEF int stbi_convert_wchar_to_utf8(char* buffer, size_t bufferlen, const wch static FILE* stbi__fopen(char const* filename, char const* mode) { FILE* f; -#if defined(_WIN32) || defined(__WINDOWS__) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; if(0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename) / sizeof(*wFilename))) diff --git a/include/Mw/BaseTypes.h b/include/Mw/BaseTypes.h index 527dcde..a89e555 100644 --- a/include/Mw/BaseTypes.h +++ b/include/Mw/BaseTypes.h @@ -49,7 +49,7 @@ typedef __int8 MwI8; typedef unsigned __int8 MwU8; #define MW_OTHER_TYPES_DEFINED -#elif defined(__WINDOWS__) +#elif defined(MW_16) typedef long long MwI64; typedef unsigned long long MwU64; #else @@ -61,7 +61,7 @@ typedef unsigned long MwU64; #ifdef MW_OTHER_TYPES_DEFINED #undef MW_OTHER_TYPES_DEFINED #else -#ifdef __WINDOWS__ +#ifdef MW_16 typedef long MwI32; typedef unsigned long MwU32; diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index 8a9db9e..514ec21 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -35,7 +35,7 @@ enum MwALIGNMENT { /*! * @brief Default */ -#ifdef __WINDOWS__ +#ifdef MW_16 #define MwDEFAULT 0x0ffff #else #define MwDEFAULT 0x0fffffff diff --git a/include/Mw/Dialog/ColorPicker.h b/include/Mw/Dialog/ColorPicker.h index 1a574b2..fdbca92 100644 --- a/include/Mw/Dialog/ColorPicker.h +++ b/include/Mw/Dialog/ColorPicker.h @@ -12,8 +12,8 @@ extern "C" { #endif -#ifdef __WINDOWS__ -#error Color Picker Widget is not avaliable on Win16 +#ifdef MW_16 +#error Color Picker Widget is not avaliable on 16-bit platforms #else /*! * @brief Creates a color picker diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index a88ae59..deefe0f 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -162,7 +162,6 @@ MWDECL unsigned char* MWAPI MwPixmapGetRaw(MwLLPixmap pixmap); */ MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); -#ifndef __WINDOWS__ /*! * @brief Creates a pixmap from XPM data * @param handle Widget @@ -170,7 +169,6 @@ MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); * @return Pixmap */ MWDECL MwLLPixmap MWAPI MwLoadXPM(MwWidget handle, char** data); -#endif /*! * @brief Creates a pixmap from icon data diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 95adad0..07370b5 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -343,7 +343,7 @@ MWDECL void (*MwLLRaise)(MwLL handle); MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); /* font renderer */ -#ifndef __WINDOWS__ +#ifndef MW_16 MWDECL void MwFLSetup(void); #ifdef USE_FREETYPE2 diff --git a/src/core.c b/src/core.c index 85cf12f..dd0f67a 100644 --- a/src/core.c +++ b/src/core.c @@ -957,11 +957,7 @@ void MwSetDefault(MwWidget handle) { } void MwHideCursor(MwWidget handle) { -#ifndef __WINDOWS__ MwLLSetCursor(handle->lowlevel, &MwCursorHidden, &MwCursorHiddenMask); -#else - MwLLSetCursor(handle->lowlevel, NULL, NULL); -#endif } void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data) { @@ -1100,7 +1096,8 @@ int MwLibraryInit(void) { #if defined(_WIN32) || defined(__WINDOWS__) /* There's no Windows configuration that Milsko supports that doesn't have winmm. - This could maybe be removed? + This could maybe be removed? However if we ever get any proof of concept working on Win2.0 + this could be useful. */ MwLL_winmmLib = LoadLibrary("winmm.dll"); MwLL_PFN_timeGetTime = (void*)GetProcAddress(MwLL_winmmLib, "timeGetTime"); @@ -1121,7 +1118,7 @@ int MwLibraryInit(void) { MwColorTableInit(); -#ifndef __WINDOWS__ +#ifndef MW_16 MwFLSetup(); #endif diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 113246e..a409936 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -1,6 +1,6 @@ #include -#ifndef __WINDOWS__ +#ifndef MW_16 #define WIN_SIZE 464 #define PICKER_SIZE 364 diff --git a/src/text/text.c b/src/text/text.c index e445af6..156caa1 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -9,7 +9,7 @@ void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px) void (*MwFLFontFree)(void* handle) = NULL; #endif -#if (defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE)) && !defined(__WINDOWS__) +#if (defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE)) #define TTF #endif diff --git a/tools/genmk.pl b/tools/genmk.pl index 247b868..be913ea 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -134,7 +134,7 @@ sub generate { print(OUT "EXE_LDFLAGS = $exe\n"); if ($type eq "Watcom") { print(OUT "!else\n"); - print(OUT "MW_CFLAGS = -bd ${inc}include ${inc}external/libz/include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}STBI_NO_SIMD ${def}NO_IMAGE\n"); + print(OUT "MW_CFLAGS = -bd ${inc}include ${inc}external/libz/include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}STBI_NO_SIMD ${def}NO_IMAGE ${def}MW_16\n"); print(OUT "MW_LDFLAGS = system windows_dll\n"); print(OUT "EXE_LDFLAGS = system windows\n"); print(OUT "!endif\n"); From 2bea5634b618968593446f3ebf30f8f9a3cfc1b3 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sat, 12 Sep 2026 04:15:02 +0900 Subject: [PATCH 06/95] 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 2637f86..6a86f98 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 07/95] 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 95fc283..378b796 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 08/95] 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 dbce7fe..d02e357 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 6a86f98..6ad5636 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 09/95] 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 839e9ac..087f48b 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 10/95] 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 087f48b..34d2e13 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 11/95] 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 2637f86..6a86f98 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 12/95] 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 95fc283..378b796 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 13/95] 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 dbce7fe..d02e357 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 6a86f98..6ad5636 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 14/95] 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 839e9ac..087f48b 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 15/95] 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 087f48b..34d2e13 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 16/95] 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 0000000..001c301 --- /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 6647672..8822f68 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 34d2e13..6d34e49 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 cc4d22b..8b908e4 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 2fe1535..32070d9 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 17/95] 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 6d34e49..82c053e 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 18/95] 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 ddf10e1..3fbc235 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 c27b1a6..3180922 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 2314c02..c6de78f 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 c894b9a..579c57e 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 f196954..8e65dc0 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 19/95] 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 3fbc235..977f2f5 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 20/95] 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 92dab70..b449f09 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 deefe0f..443835c 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 ad072a3..a9bc3cf 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 2314c02..c7869e0 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 c93e054..1930259 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 21/95] 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 5441692..d072daf 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 ccd1f2f..0f570e3 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 89f13e9..80f930d 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 0000000..e6c8679 --- /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 84ed492..a724591 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 c7869e0..19b4081 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 22/95] 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 a724591..84ed492 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 19b4081..c7869e0 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 23/95] 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 d072daf..534614f 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 0f570e3..c42231c 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 80f930d..986ee98 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 65380fb..d70de1b 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 e6c8679..0000000 --- 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 84ed492..caf62ac 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 82c053e..22c5137 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 24/95] 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 c42231c..0bfe201 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 caf62ac..43703a9 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 22c5137..c8c4b01 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 25/95] 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 0bfe201..f7102ce 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 43703a9..706318a 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 c8c4b01..d032e7d 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 26/95] 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 d032e7d..d3fb201 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 27/95] 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 706318a..0d960c2 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 d3fb201..4f832dc 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 28/95] 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 534614f..1ec1ed8 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 9060a97..6015415 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 f7102ce..5e43c34 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 986ee98..6c4df63 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 df1de79..3ee5e3c 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 0d960c2..9ce4261 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 4f832dc..433001b 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 30a1cee..9e1b91e 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 f4c5340..acffda3 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 29/95] 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 6ad5636..a9a5ec0 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 6015415..9060a97 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 f0a42f7..0d92ec4 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 32edeaa..781fad2 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 6c4df63..0fe264c 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 3bd7625..2c339d5 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 977f2f5..d7b364f 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 d70de1b..65380fb 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 138fc6c..b1fcc9b 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 97e6870..91ccac9 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 f6c7685..979fd31 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 30/95] 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 5e43c34..234e3e8 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 0fe264c..afc9ef9 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 9ce4261..a69ad1b 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 433001b..3c2d9bd 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 31/95] 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 234e3e8..3e9d671 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 a69ad1b..73ac8b1 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 32/95] 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 73ac8b1..e0b962c 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 33/95] 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 e0b962c..b200dd2 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 34/95] 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 b200dd2..0ab3f43 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 3c2d9bd..2b5fce9 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 35/95] 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 b449f09..06a115b 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 dbf9c5e..112d5fc 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 5d06b06..a1aad90 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 443835c..542aac5 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 4c98b24..7313ce2 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 9860990..7997bb6 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 6ad4e46..39730db 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 0000000..a8057fe --- /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 a94c847..573b84d 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 afc9ef9..220e550 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 2c339d5..4b831d5 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 3180922..2982c1e 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 c7869e0..bbd0264 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 0000000..e69de29 diff --git a/src/widget/clock.c b/src/widget/clock.c new file mode 100644 index 0000000..547464a --- /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 36/95] oops --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index 2982c1e..21b16ea 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 37/95] regenerate makefiles --- NTMakefile | 6 ++++-- WatMakefile | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index 63a4a2c..2d41468 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 4533f3c..0b4f73a 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 38/95] 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 06a115b..5b65265 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 7997bb6..abdc073 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 0000000..6ab404b --- /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 eace1d3..660a0fc 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 2b5fce9..3c2d9bd 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 21b16ea..481fa34 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 e69de29..46f248e 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 39/95] 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 5b65265..db833c6 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 15853ff..ad29792 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 542aac5..e3c6991 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 39730db..d820ea4 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 a9bc3cf..0be60e8 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 6ab404b..d0957a2 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 7b2dc2f..fd5c343 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 573b84d..30efce1 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 481fa34..2982c1e 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 bbd0264..5cbfd22 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 46f248e..b014513 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 e53647d..5502a07 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 3fba309..d07d355 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 3d0afe2..9ea16a3 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 40/95] 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 db833c6..e40994d 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 ad29792..6df447d 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 e3c6991..ad13c60 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 30efce1..6bf802b 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 2982c1e..481fa34 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 5cbfd22..eb15c76 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 b014513..34d8f4e 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 41/95] fix --- src/widget/chart.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/widget/chart.c b/src/widget/chart.c index 34d8f4e..cec1c9a 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 42/95] 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 cec1c9a..83e3a5e 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 43/95] 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 e40994d..c17cfd0 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 44/95] 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 6e6c13e..c701341 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 a99d925..ee3828c 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 44e4c4d..baeeb67 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 c63be2c..b021ada 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 e1c5d89..039db26 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 2bb89b6..45e5886 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 45/95] 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 d7b364f..63146b1 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 46/95] ok --- src/default.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/default.c b/src/default.c index baeeb67..2cb1633 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 47/95] limit --- src/widget/clock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/clock.c b/src/widget/clock.c index 547464a..70471c6 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 48/95] 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 3c2d9bd..49b6019 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 49/95] 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 49b6019..958d9ef 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 50/95] =?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 3e9d671..305f8bc 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 0ab3f43..247919c 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 958d9ef..7253c00 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 51/95] 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 305f8bc..b9cbf52 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 52/95] 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 c17cfd0..e53d66b 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 6df447d..42f1471 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 6bf802b..0652a55 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 83e3a5e..4079e8b 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 53/95] 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 e53d66b..adaf35b 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 42f1471..6379fef 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 0652a55..084f825 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 4079e8b..9c87e3f 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 54/95] 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 1ec1ed8..534614f 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 dd2cfa3..680c651 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 b9cbf52..fd97178 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 220e550..9d2081c 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 65380fb..0b74b42 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 3ee5e3c..cb1eca5 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 247919c..cbab2ad 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 7253c00..6154664 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 9e1b91e..c9bb3f4 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 55/95] 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 0b74b42..7f421ac 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 6154664..0c771ab 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 56/95] 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 7f421ac..38345eb 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 57/95] fix --- src/widget/chart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/chart.c b/src/widget/chart.c index 9c87e3f..eaaea55 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 58/95] 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 0c771ab..6154664 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 61/95] 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 38345eb..62fa6ba 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 62/95] 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 adaf35b..f7148da 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 6379fef..acd6b05 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 62fa6ba..3683ca8 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 eaaea55..d66cc61 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 63/95] 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 d66cc61..67753c9 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 64/95] 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 2d41468..d0fc463 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 0b4f73a..ce6792b 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 0000000..e53339c --- /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 0000000..22ab420 --- /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 0000000..7a6896a --- /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 abdc073..6d35d54 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 d820ea4..71b8f5f 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 0000000..5b38af4 --- /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 084f825..ec30e82 100644 --- a/milsko.xml +++ b/milsko.xml @@ -111,6 +111,7 @@ + diff --git a/pl/rules.pl b/pl/rules.pl index 9d2081c..ad62d6c 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 0000000..4c5414a --- /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 689e09e..26a7ebb 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 65/95] 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 22ab420..73c7b5d 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 660a0fc..2013b9a 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 66/95] ok --- NTMakefile | 12 ++++++++++-- WatMakefile | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index d0fc463..26723bc 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 ce6792b..7924e17 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 67/95] ok --- external/md4c.c | 444 ++++++++++++++++++++++++------------------------ 1 file changed, 222 insertions(+), 222 deletions(-) diff --git a/external/md4c.c b/external/md4c.c index 73c7b5d..8665a14 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 68/95] huh --- external/md4c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/external/md4c.c b/external/md4c.c index 8665a14..1c23cd1 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 69/95] 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 1c23cd1..c582ef9 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 70/95] testing ci --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6c1637e..0a8b712 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 71/95] testing ci --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0a8b712..4f0b202 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 72/95] fixing ci --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 4f0b202..76e3093 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 73/95] fixing ci --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 76e3093..4281763 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 74/95] fixing ci --- Jenkinsfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4281763..8f0033d 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 75/95] fix --- Jenkinsfile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8f0033d..40cd979 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 76/95] 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 0000000..02a430a --- /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 40cd979..4e17a07 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 77/95] ok --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02a430a..10c8ea7 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 78/95] 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 26723bc..213800d 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 7924e17..0b846d1 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 0000000..f88a650 --- /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 fd97178..44a3983 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 ad62d6c..551d391 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 cbab2ad..eaabf16 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 79/95] ok --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 10c8ea7..0cb38a7 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 80/95] ok --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4e17a07..8e42285 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 81/95] ok --- Jenkinsfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8e42285..9b7d639 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 82/95] 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 f88a650..0a2495e 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 ec30e82..7ac33f1 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 83/95] 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 0a2495e..8d0f47d 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 44a3983..7a2c25c 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 e1b7416..9663097 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 eaabf16..dd58f9a 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 6154664..bd17f84 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 8b908e4..eaa64e0 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 84/95] 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 e53339c..a9482a8 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 acd6b05..bbef56c 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 71b8f5f..b3f527b 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 0be60e8..2a11d36 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 7ac33f1..b864efc 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 4c5414a..3f83646 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 85/95] 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 f7148da..fb2fbd9 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 bbef56c..ed77ab5 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 b864efc..1bb19fd 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 67753c9..40e760d 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 5502a07..a6cb876 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 86/95] 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 a9482a8..8ae77f4 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 87/95] 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 8ae77f4..9bce548 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 88/95] 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 9bce548..1051a6b 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 ed77ab5..0a79ae6 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 3f83646..2dc7ec9 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 89/95] 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 1051a6b..f9529fe 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 0a79ae6..a0eec8b 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 9a47802..c9347b9 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 b3f527b..cf0a723 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 2a11d36..3463b37 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 1bb19fd..5b90410 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 0000000..2340f57 --- /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 0000000..07b015d --- /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 2dc7ec9..7611c62 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 90/95] 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 7611c62..55dd1f0 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 91/95] update --- NTMakefile | 6 ++++-- WatMakefile | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/NTMakefile b/NTMakefile index 213800d..b07f798 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 0b846d1..fd98079 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 92/95] fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 534614f..07f7bb9 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 93/95] 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 eb15c76..be82fb4 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 55dd1f0..1f48cec 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 94/95] unfix --- src/draw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/draw.c b/src/draw.c index be82fb4..eb15c76 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 95/95] 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 58b172a..3faccd3 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 7a2c25c..3b79184 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 cb1eca5..48071ec 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 bd17f84..9d8d634 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) {