From 8027e52cb221c432bed64517015ebf3182e6166d Mon Sep 17 00:00:00 2001 From: bptato Date: Fri, 2 Jun 2023 00:36:54 +0200 Subject: Add support for canvas and multipart Quite incomplete canvas implementation. Crucially, the layout engine can't do much with whatever is drawn because it doesn't support images yet. I've re-introduced multipart as well, with the FormData API. For the append function I've also introduced a hack to the JS binding generator that allows requesting the JSContext pointer in nim procs. Really I should just fix the union generator thing and add support for overloading. In conclusion, for now the only thing canvas can be used for is exporting it as PNG and uploading it somewhere. Also, we now have PNG encoding and decoding too. (Now if only we had sixels as well...) --- lib/endians2.nim | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 lib/endians2.nim (limited to 'lib') diff --git a/lib/endians2.nim b/lib/endians2.nim new file mode 100644 index 00000000..c9a39144 --- /dev/null +++ b/lib/endians2.nim @@ -0,0 +1,186 @@ +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +# Endian conversion operations for unsigned integers, suitable for serializing +# and deserializing data. The operations are only defined for unsigned +# integers - if you wish to encode signed integers, convert / cast them to +# unsigned first! +# +# Although it would be possible to enforce correctness with endians in the type +# (`BigEndian[uin64]`) this seems like overkill. That said, some +# static analysis tools allow you to annotate fields with endianness - perhaps +# an idea for the future, akin to `TaintedString`? +# +# Keeping the above in mind, it's generally safer to use `array[N, byte]` to +# hold values of specific endianness and read them out with `fromBytes` when the +# integer interpretation of the bytes is needed. + +{.push raises: [].} + +type + SomeEndianInt* = uint8|uint16|uint32|uint64 + ## types that we support endian conversions for - uint8 is there for + ## for syntactic / generic convenience. Other candidates: + ## * int/uint - uncertain size, thus less suitable for binary interop + ## * intX - over and underflow protection in nim might easily cause issues - + ## need to consider before adding here + +const + useBuiltins = not defined(noIntrinsicsEndians) + +when (defined(gcc) or defined(llvm_gcc) or defined(clang)) and useBuiltins: + func swapBytesBuiltin(x: uint8): uint8 = x + func swapBytesBuiltin(x: uint16): uint16 {. + importc: "__builtin_bswap16", nodecl.} + + func swapBytesBuiltin(x: uint32): uint32 {. + importc: "__builtin_bswap32", nodecl.} + + func swapBytesBuiltin(x: uint64): uint64 {. + importc: "__builtin_bswap64", nodecl.} + +elif defined(icc) and useBuiltins: + func swapBytesBuiltin(x: uint8): uint8 = x + func swapBytesBuiltin(a: uint16): uint16 {.importc: "_bswap16", nodecl.} + func swapBytesBuiltin(a: uint32): uint32 {.importc: "_bswap", nodec.} + func swapBytesBuiltin(a: uint64): uint64 {.importc: "_bswap64", nodecl.} + +elif defined(vcc) and useBuiltins: + func swapBytesBuiltin(x: uint8): uint8 = x + func swapBytesBuiltin(a: uint16): uint16 {. + importc: "_byteswap_ushort", cdecl, header: "".} + + func swapBytesBuiltin(a: uint32): uint32 {. + importc: "_byteswap_ulong", cdecl, header: "".} + + func swapBytesBuiltin(a: uint64): uint64 {. + importc: "_byteswap_uint64", cdecl, header: "".} + +func swapBytesNim(x: uint8): uint8 = x +func swapBytesNim(x: uint16): uint16 = (x shl 8) or (x shr 8) + +func swapBytesNim(x: uint32): uint32 = + let v = (x shl 16) or (x shr 16) + + ((v shl 8) and 0xff00ff00'u32) or ((v shr 8) and 0x00ff00ff'u32) + +func swapBytesNim(x: uint64): uint64 = + var v = (x shl 32) or (x shr 32) + v = + ((v and 0x0000ffff0000ffff'u64) shl 16) or + ((v and 0xffff0000ffff0000'u64) shr 16) + + ((v and 0x00ff00ff00ff00ff'u64) shl 8) or + ((v and 0xff00ff00ff00ff00'u64) shr 8) + +func swapBytes*[T: SomeEndianInt](x: T): T {.inline.} = + ## Reverse the bytes within an integer, such that the most significant byte + ## changes place with the least significant one, etc + ## + ## Example: + ## doAssert swapBytes(0x01234567'u32) == 0x67452301 + when nimvm: + swapBytesNim(x) + else: + when declared(swapBytesBuiltin): + swapBytesBuiltin(x) + else: + swapBytesNim(x) + +func toBytes*(x: SomeEndianInt, endian: Endianness = system.cpuEndian): + array[sizeof(x), byte] {.noinit, inline.} = + ## Convert integer to its corresponding byte sequence using the chosen + ## endianness. By default, native endianness is used which is not portable! + let v = + if endian == system.cpuEndian: x + else: swapBytes(x) + + when nimvm: # No copyMem in vm + for i in 0..= sizeof(T), "Not enough bytes for endian conversion" + + when nimvm: # No copyMem in vm + for i in 0..