about summary refs log tree commit diff stats
path: root/src/render
Commit message (Expand)AuthorAgeFilesLines
* rendertext: fix tab weirdnessbptato2022-12-251-10/+8
* Add unicode normalization, etcbptato2022-12-191-3/+0
* Display text for img tag, background-imagebptato2022-12-161-0/+12
* Remove obsolete renderPlainText procbptato2022-12-151-42/+0
* Fix console display bugs, add container.locationbptato2022-12-151-1/+6
* rendertext, color: fix escape codesbptato2022-12-141-0/+1
* renderdocument: fix another formatting bugbptato2022-12-121-3/+5
* renderdocument: fix overwriting formatcellsbptato2022-12-121-3/+10
* Fix decoder bugs, move decoder to encoding/bptato2022-12-101-1/+1
* Add support for the encoding standard, fix parseLegacyColorbptato2022-12-101-32/+43
* Add multiple text-decoration, overline emulationbptato2022-12-071-5/+4
* Remove unused twtstr functionsbptato2022-12-051-2/+2
* Do not center error-corrected linesbptato2022-11-301-1/+1
* renderdocument: fix bug negative padwidth bugbptato2022-11-291-1/+8
* Add missing iflush call, add experimental line height error correctionbptato2022-11-291-1/+14
* Add position css property, inline block fixesbptato2022-11-281-2/+3
* Fix some regressions, add loading progress barbptato2022-11-271-21/+31
* Fix some table layout issuesbptato2022-11-251-1/+1
* Add some quirks mode rules + presentational hintsbptato2022-11-251-1/+6
* Buffer improvementsbptato2022-11-251-11/+13
* Table fixes wipbptato2022-11-221-11/+0
* Fix tab renderingbptato2022-11-221-2/+20
* Terminal refactoringsbptato2022-11-201-28/+28
* Rewrite buffer/pager for multi-processingbptato2022-11-192-2/+2
* Very much WIP table implementationbptato2022-11-151-0/+11
* Fix renderdocument setText etc.bptato2022-08-021-81/+117
* Refactor some layout engine types, fix list-itembptato2022-07-201-8/+9
* Clean up vertical line box alignment codebptato2022-07-201-4/+4
* Use StyledNodes instead of passing the entire DOM to the layout enginebptato2022-07-161-7/+9
* Refactor layout enginebptato2022-07-151-2/+2
* specified -> computedbptato2022-06-181-2/+2
* Re-implement list itemsbptato2022-06-171-0/+4
* Re-implement inline-blockbptato2022-06-171-9/+7
* Simplify offset, fix a text node bugbptato2022-06-081-4/+4
* Layout: insignificant changes regarding offsetbptato2022-05-291-2/+2
* Reduce formatting complexitybptato2022-02-192-109/+50
* Background color improvementsbptato2022-02-151-3/+13
* Fix format background unicode problemsbptato2022-02-151-19/+54
* Incomplete background-color implementationbptato2022-02-141-42/+140
* Implement blink tagbptato2022-02-121-0/+2
* Avoid stack overflow in renderBlockContextbptato2022-01-301-8/+13
* Implement list-style-positionbptato2022-01-301-1/+1
* Implement formsbptato2022-01-291-0/+5
* Implement line-height, vertical-alignbptato2022-01-281-6/+7
* Implement paddingbptato2022-01-262-23/+27
* Fix whitespace stylingbptato2022-01-261-0/+50
* Fix node to cell mappingbptato2022-01-241-1/+1
* Fix incorrect canvas width and whitespace bugsbptato2022-01-231-2/+2
* Use pixels as the base unit for the layoutbptato2022-01-231-67/+11
* Fix page navigationbptato2022-01-221-7/+4
/span> ExtendedFrame ExtendedFrame = object # If the debugger is enabled the compiler # provides an extended frame. Of course # only slots that are # needed are allocated and not 10_000, # except for the global data description. f: TFrame slots: array[0..10_000, VarSlot] {.deprecated: [TVarSlot: VarSlot, TExtendedFrame: ExtendedFrame].} var dbgGlobalData: ExtendedFrame # this reserves much space, but # for now it is the most practical way proc dbgRegisterGlobal(name: cstring, address: pointer, typ: PNimType) {.compilerproc.} = let i = dbgGlobalData.f.len if i >= high(dbgGlobalData.slots): #debugOut("[Warning] cannot register global ") return dbgGlobalData.slots[i].name = name dbgGlobalData.slots[i].typ = typ dbgGlobalData.slots[i].address = address inc(dbgGlobalData.f.len) proc getLocal*(frame: PFrame; slot: int): VarSlot {.inline.} = ## retrieves the meta data for the local variable at `slot`. CAUTION: An ## invalid `slot` value causes a corruption! result = cast[PExtendedFrame](frame).slots[slot] proc getGlobalLen*(): int {.inline.} = ## gets the number of registered globals. result = dbgGlobalData.f.len proc getGlobal*(slot: int): VarSlot {.inline.} = ## retrieves the meta data for the global variable at `slot`. CAUTION: An ## invalid `slot` value causes a corruption! result = dbgGlobalData.slots[slot] # ------------------- breakpoint support ------------------------------------ type Breakpoint* = object ## represents a break point low*, high*: int ## range from low to high; if disabled ## both low and high are set to their negative values filename*: cstring ## the filename of the breakpoint var dbgBP: array[0..127, Breakpoint] # breakpoints dbgBPlen: int dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking dbgFilenames*: array[0..300, cstring] ## registered filenames; ## 'nil' terminated dbgFilenameLen: int proc dbgRegisterFilename(filename: cstring) {.compilerproc.} = # XXX we could check for duplicates here for DLL support dbgFilenames[dbgFilenameLen] = filename inc dbgFilenameLen proc dbgRegisterBreakpoint(line: int, filename, name: cstring) {.compilerproc.} = let x = dbgBPlen if x >= high(dbgBP): #debugOut("[Warning] cannot register breakpoint") return inc(dbgBPlen) dbgBP[x].filename = filename dbgBP[x].low = line dbgBP[x].high = line dbgBPbloom = dbgBPbloom or line proc addBreakpoint*(filename: cstring, lo, hi: int): bool = let x = dbgBPlen if x >= high(dbgBP): return false inc(dbgBPlen) result = true dbgBP[x].filename = filename dbgBP[x].low = lo dbgBP[x].high = hi for line in lo..hi: dbgBPbloom = dbgBPbloom or line const FileSystemCaseInsensitive = defined(windows) or defined(dos) or defined(os2) proc fileMatches(c, bp: cstring): bool = # bp = breakpoint filename # c = current filename # we consider it a match if bp is a suffix of c # and the character for the suffix does not exist or # is one of: \ / : # depending on the OS case does not matter! var blen: int = c_strlen(bp) var clen: int = c_strlen(c) if blen > clen: return false # check for \ / : if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}: return false var i = 0 while i < blen: var x = bp[i] var y = c[i+clen-blen] when FileSystemCaseInsensitive: if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a')) if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a')) if x != y: return false inc(i) return true proc canonFilename*(filename: cstring): cstring = ## returns 'nil' if the filename cannot be found. for i in 0 .. <dbgFilenameLen: result = dbgFilenames[i] if fileMatches(result, filename): return result result = nil iterator listBreakpoints*(): ptr Breakpoint = ## lists all breakpoints. for i in 0..dbgBPlen-1: yield addr(dbgBP[i]) proc isActive*(b: ptr Breakpoint): bool = b.low > 0 proc flip*(b: ptr Breakpoint) = ## enables or disables 'b' depending on its current state. b.low = -b.low; b.high = -b.high proc checkBreakpoints*(filename: cstring, line: int): ptr Breakpoint = ## in which breakpoint (if any) we are. if (dbgBPbloom and line) != line: return nil for b in listBreakpoints(): if line >= b.low and line <= b.high and filename == b.filename: return b # ------------------- watchpoint support ------------------------------------ type Hash = int Watchpoint {.pure, final.} = object name: cstring address: pointer typ: PNimType oldValue: Hash {.deprecated: [THash: Hash, TWatchpoint: Watchpoint].} var watchpoints: array [0..99, Watchpoint] watchpointsLen: int proc `!&`(h: Hash, val: int): Hash {.inline.} = result = h +% val result = result +% result shl 10 result = result xor (result shr 6) proc `!$`(h: Hash): Hash {.inline.} = result = h +% h shl 3 result = result xor (result shr 11) result = result +% result shl 15 proc hash(data: pointer, size: int): Hash = var h: Hash = 0 var p = cast[cstring](data) var i = 0 var s = size while s > 0: h = h !& ord(p[i]) inc(i) dec(s) result = !$h proc hashGcHeader(data: pointer): Hash = const headerSize = sizeof(int)*2 result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize) proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, h: Hash): Hash proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool, h: Hash): Hash = var d = cast[ByteAddress](dest) case n.kind of nkSlot: result = genericHashAux(cast[pointer](d +% n.offset), n.typ, shallow, h) of nkList: result = h for i in 0..n.len-1: result = result !& genericHashAux(dest, n.sons[i], shallow, result) of nkCase: result = h !& hash(cast[pointer](d +% n.offset), n.typ.size) var m = selectBranch(dest, n) if m != nil: result = genericHashAux(dest, m, shallow, result) of nkNone: sysAssert(false, "genericHashAux") proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, h: Hash): Hash = sysAssert(mt != nil, "genericHashAux 2") case mt.kind of tyString: var x = cast[PPointer](dest)[] result = h if x != nil: let s = cast[NimString](x) when defined(trackGcHeaders): result = result !& hashGcHeader(x) else: result = result !& hash(x, s.len) of tySequence: var x = cast[PPointer](dest) var dst = cast[ByteAddress](cast[PPointer](dest)[]) result = h if dst != 0: when defined(trackGcHeaders): result = result !& hashGcHeader(cast[PPointer](dest)[]) else: for i in 0..cast[PGenericSeq](dst).len-1: result = result !& genericHashAux( cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), mt.base, shallow, result) of tyObject, tyTuple: # we don't need to copy m_type field for tyObject, as they are equal anyway result = genericHashAux(dest, mt.node, shallow, h) of tyArray, tyArrayConstr: let d = cast[ByteAddress](dest) result = h for i in 0..(mt.size div mt.base.size)-1: result = result !& genericHashAux(cast[pointer](d +% i*% mt.base.size), mt.base, shallow, result) of tyRef: when defined(trackGcHeaders): var s = cast[PPointer](dest)[] if s != nil: result = result !& hashGcHeader(s) else: if shallow: result = h !& hash(dest, mt.size) else: result = h var s = cast[PPointer](dest)[] if s != nil: result = result !& genericHashAux(s, mt.base, shallow, result) else: result = h !& hash(dest, mt.size) # hash raw bits proc genericHash(dest: pointer, mt: PNimType): int = result = genericHashAux(dest, mt, false, 0) proc dbgRegisterWatchpoint(address: pointer, name: cstring, typ: PNimType) {.compilerproc.} = let L = watchPointsLen for i in 0.. <L: if watchPoints[i].name == name: # address may have changed: watchPoints[i].address = address return if L >= watchPoints.high: #debugOut("[Warning] cannot register watchpoint") return watchPoints[L].name = name watchPoints[L].address = address watchPoints[L].typ = typ watchPoints[L].oldValue = genericHash(address, typ) inc watchPointsLen proc dbgUnregisterWatchpoints*() = watchPointsLen = 0 var dbgLineHook*: proc () {.nimcall.} ## set this variable to provide a procedure that should be called before ## each executed instruction. This should only be used by debuggers! ## Only code compiled with the ``debugger:on`` switch calls this hook. dbgWatchpointHook*: proc (watchpointName: cstring) {.nimcall.} proc checkWatchpoints = let L = watchPointsLen for i in 0.. <L: let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ) if newHash != watchPoints[i].oldValue: dbgWatchpointHook(watchPoints[i].name) watchPoints[i].oldValue = newHash proc endb(line: int, file: cstring) {.compilerproc, noinline.} = # This proc is called before every Nim code line! if framePtr == nil: return if dbgWatchpointHook != nil: checkWatchpoints() framePtr.line = line # this is done here for smaller code size! framePtr.filename = file if dbgLineHook != nil: dbgLineHook() include "system/endb"