Webview 4.0 #14

Merged
Leency merged 17 commits from webview-4.0 into main 2026-09-26 13:58:11 +00:00
Contributor

Полная поддержка table
Базовый CSS
Рисуется теперь только видимая область (сильно уменьшает расход памяти)
Параллельная загрузка изображений в 16 потоков
Кэш картинок на /tmp0/1/cache
Выделение и копирование текста
Поиск по странице
ПКМ на картинке -> Можно сохранить

UPD:
Поддержка куки
Поддержка самбита форм по GET и POST: текстовое поле, чекбокс, радиобокс
Можно изменить размер шрифта
Обновлены встроенные страницы
Меню: добавлен пункт "Открыть в NetSurf"
Тулбар: добавлена кнопка открытия папки загрузки

Бинарник 22 КБ => 52 КБ, потому нужно будет освобождать место в IMG.

Полная поддержка table Базовый CSS Рисуется теперь только видимая область (сильно уменьшает расход памяти) Параллельная загрузка изображений в 16 потоков Кэш картинок на /tmp0/1/cache Выделение и копирование текста Поиск по странице ПКМ на картинке -> Можно сохранить UPD: Поддержка куки Поддержка самбита форм по GET и POST: текстовое поле, чекбокс, радиобокс Можно изменить размер шрифта Обновлены встроенные страницы Меню: добавлен пункт "Открыть в NetSurf" Тулбар: добавлена кнопка открытия папки загрузки Бинарник 22 КБ => 52 КБ, потому нужно будет освобождать место в IMG.
Leency added 3 commits 2026-09-21 03:36:20 +00:00
The old TWB renderer is replaced by an engine that builds a DOM, applies
CSS, lays the page out into fragments and paints only what is visible.

Engine (browser/engine):
- DOM builder with scoped closing tags, entity decoding in text and
  attributes, raw text for script/style/textarea, <noscript> shown
- CSS: <style>, style="" and <link rel=stylesheet> (local, cached or
  downloaded), custom properties and var(), @media walking, descendant
  and child selectors, class/id in any case, :link, :visited,
  :first-child, :last-child; colors, fonts, text-align, white-space,
  width, max-width, height (as a minimum), margins with auto and
  negative values, padding, borders, float, display incl. table parts,
  vw units
- Layout: inline lines with baseline images and icons, <pre>, lists,
  <nav> menus in a row, tables with colspan/rowspan and percent columns,
  display:table with or without rows, floats with or without a width,
  float:right, centred blocks, flex rows (flex-grow, basis, wrap, gap,
  justify-content, auto margins, align-items)
- position:absolute / fixed and flex each sit behind a switch in
  style.h (css_abspos off, css_flex on); text parked off-page or in a
  1px clipped box stays hidden either way
- Paint into a viewport canvas, text selection, find on page, hit
  testing, link hover

Browser:
- images load in a separate downloader process ("dl -i"), the image
  cache lives in /tmp0/1/Cache and survives a restart
- Ctrl+A/C stay inside a focused edit box, right click on a selection
  offers Copy, view source works, file:// addresses, history and cache
  keep the real address instead of the proxied one, the built-in error
  page keeps its charset, DuckDuckGo Lite is the default search
- URLs with spaces are escaped, a slash in an unquoted attribute no
  longer closes the tag

dl: filename= without quotes, hidden mode "-i", no double free of the
content buffer.

Test pages for each area are in browser/tests.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
- the updater downloads WebView.com from builds.kolibrios.org/ci/latest
- test page is laid out as a two column table
- Russian error page: a short framed box, tethering over USB as the
  easiest way online, a link to the list of supported network cards
- a line break after the logo on the start page
- build.bat no longer writes into a local floppy image and starts QEMU
- editbox_icons, help_en/help_ru and highlight_c.h are not used by the
  new engine and are removed

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
menu: ignore mouse events until the window exists
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 18s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 20s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 21s
e378665e51
The kernel can deliver a pending mouse event before the first redraw,
while the menu window is not defined and so cannot be the active one.
The active-window check then closed the menu at once whenever the mouse
moved during startup. Mouse events are now skipped until the first
DefineAndDrawWindow.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Leency added 1 commit 2026-09-21 11:40:04 +00:00
webview: ch lengths, implied table rows/cells, <center> tables
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 19s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 22s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 22s
31db9ed160
- ch/ex units: ch in width/max-width follows the element's font glyph width
- parser adds an implied <tr> for cells straight in <table>, and an implied
  <td> for content straight in <tr>/<table>
- <center> and align=center centre child tables
- docs/ROADMAP.md brought up to date

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Leency added 1 commit 2026-09-21 11:52:05 +00:00
homepage upd
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 19s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 22s
178988513b
Burer requested changes 2026-09-21 11:53:23 +00:00
Dismissed
Burer left a comment
Owner

Critical: memory corruption

1. browser/engine/style.h:310, stack overflow from any page
css_match_compound copies a selector fragment into char part[128] with no length cap, while CSSRULE::add passes selectors of up to ~250 characters. It smashes lc[256], the saved registers and the return address.

2. browser/engine/engine.h:243, Reparse() runs on an unbuilt DOM
The dom.nodes guard present in hit.h:13 and engine_restore_tab is missing here. F12 or Ctrl+Tab on a still loading tab makes dom.n(0) write through a null node and then walk a garbage child index.

3. browser/show_src.h:39, output buffer undersized 5x
malloc(bufsize*5), but one input byte can expand to 26 (" in TAG mode); markup made of short tags expands ~11x. Ctrl+U corrupts the heap. This PR also shrank the allocation by passing WB1.bufsize.

4. browser/engine/layout.h:849, pointer held across a realloc
v = dom.attr(_idx, "src") points into the dpool arena; the next two place_string() calls can reallocate it, and v is then passed to a third call. Every other attribute read in this file copies into a local buffer first.

5. browser/engine/engine.h:359 and image_url, one byte past the end
strncpy in lib/strings.h writes len bytes plus a terminator, but the buffers are declared char path[URL_SIZE]. style_link_sheet (style.h:1125) gets this right with URL_SIZE + 1.

Functional bugs

6. browser/engine/style.h:360, wrong subject in long selectors
np is pinned at 8 but the subject is taken as parts[np-1], so a selector with 9 or more compounds matches its 8th part instead of its last. The rule lands on the wrong nodes.

7. browser/WebView.c:192, text selection navigates away
No break after if (mouse.up) sel_end();, and lib/mouse.h restores key on the up event, so EventClickLink fires. Releasing the button over an <a> after selecting text destroys the selection and loads the link.

8. browser/cache.h:164, two windows wipe each other's cache
remove_orphans() deletes every wv_* file missing from this process's index. Ctrl+N and -new bypass the single instance check and the index is only written on exit, so the second instance deletes files the first one's dl children are still writing.

9. browser/WebView.c:864, image download progress never draws
DrawProgress() returns on !http.transfer, but images are now fetched by an external dl -i after http.hfree() has already cleared it. The http_get_type==IMG branches here and in HandleRedirect are dead code.

10. browser/engine/paint.h:104, clipped icons smear
src += 4 sits after the continue, so a skipped pixel does not consume the source. A <kosicon> near the canvas edge drifts diagonally instead of clipping cleanly.

Resources and performance

11. browser/engine/layout.h:1606, string arena grows without bound
Every layout pass appends fresh copies to dpool; measure_block and flex_measure roll back frags.count but not dpool.used. Resizing a window on a page with a long list doubles the arena until it runs out of memory. This is also what makes finding 4 reachable.

12. browser/engine/layout.h:1494, oversized table allocation
cf_first/cf_end/cf_h are sized R * MAXCOLS (64) although ncols is known at line 1359. A 2000x3 table takes 1.5 MB instead of 72 KB.

13. browser/engine/engine.h:449, style_all() runs twice per tab switch
engine_restore_tab() calls style_all(), and both callers (tabs.h:157, tabs.h:179) immediately follow with Reparse(), which calls it again and re-reads every linked stylesheet.

## Critical: memory corruption **1. `browser/engine/style.h:310`, stack overflow from any page** `css_match_compound` copies a selector fragment into `char part[128]` with no length cap, while `CSSRULE::add` passes selectors of up to ~250 characters. It smashes `lc[256]`, the saved registers and the return address. **2. `browser/engine/engine.h:243`, `Reparse()` runs on an unbuilt DOM** The `dom.nodes` guard present in `hit.h:13` and `engine_restore_tab` is missing here. F12 or Ctrl+Tab on a still loading tab makes `dom.n(0)` write through a null node and then walk a garbage child index. **3. `browser/show_src.h:39`, output buffer undersized 5x** `malloc(bufsize*5)`, but one input byte can expand to 26 (`"` in TAG mode); markup made of short tags expands ~11x. Ctrl+U corrupts the heap. This PR also shrank the allocation by passing `WB1.bufsize`. **4. `browser/engine/layout.h:849`, pointer held across a realloc** `v = dom.attr(_idx, "src")` points into the `dpool` arena; the next two `place_string()` calls can reallocate it, and `v` is then passed to a third call. Every other attribute read in this file copies into a local buffer first. **5. `browser/engine/engine.h:359` and `image_url`, one byte past the end** `strncpy` in `lib/strings.h` writes `len` bytes plus a terminator, but the buffers are declared `char path[URL_SIZE]`. `style_link_sheet` (`style.h:1125`) gets this right with `URL_SIZE + 1`. ## Functional bugs **6. `browser/engine/style.h:360`, wrong subject in long selectors** `np` is pinned at 8 but the subject is taken as `parts[np-1]`, so a selector with 9 or more compounds matches its 8th part instead of its last. The rule lands on the wrong nodes. **7. `browser/WebView.c:192`, text selection navigates away** No `break` after `if (mouse.up) sel_end();`, and `lib/mouse.h` restores `key` on the up event, so `EventClickLink` fires. Releasing the button over an `<a>` after selecting text destroys the selection and loads the link. **8. `browser/cache.h:164`, two windows wipe each other's cache** `remove_orphans()` deletes every `wv_*` file missing from this process's index. Ctrl+N and `-new` bypass the single instance check and the index is only written on exit, so the second instance deletes files the first one's `dl` children are still writing. **9. `browser/WebView.c:864`, image download progress never draws** `DrawProgress()` returns on `!http.transfer`, but images are now fetched by an external `dl -i` after `http.hfree()` has already cleared it. The `http_get_type==IMG` branches here and in `HandleRedirect` are dead code. **10. `browser/engine/paint.h:104`, clipped icons smear** `src += 4` sits after the `continue`, so a skipped pixel does not consume the source. A `<kosicon>` near the canvas edge drifts diagonally instead of clipping cleanly. ## Resources and performance **11. `browser/engine/layout.h:1606`, string arena grows without bound** Every layout pass appends fresh copies to `dpool`; `measure_block` and `flex_measure` roll back `frags.count` but not `dpool.used`. Resizing a window on a page with a long list doubles the arena until it runs out of memory. This is also what makes finding 4 reachable. **12. `browser/engine/layout.h:1494`, oversized table allocation** `cf_first/cf_end/cf_h` are sized `R * MAXCOLS` (64) although `ncols` is known at line 1359. A 2000x3 table takes 1.5 MB instead of 72 KB. **13. `browser/engine/engine.h:449`, `style_all()` runs twice per tab switch** `engine_restore_tab()` calls `style_all()`, and both callers (`tabs.h:157`, `tabs.h:179`) immediately follow with `Reparse()`, which calls it again and re-reads every linked stylesheet.
Leency added 3 commits 2026-09-23 03:27:49 +00:00
Memory safety:
- css_match_compound: cap selector parts at part[] size (stack overflow)
- Reparse(): do nothing while the tab has no document yet
- view-source: grow the output buffer instead of guessing 5x
- iframe/video placeholder: copy src before place_string() may realloc dpool
- GetAbsoluteActiveURL: sized global buffer instead of a returned stack array

Functional:
- selectors with more than 8 parts keep their real last part as the subject
- releasing a text selection over a link no longer follows the link
- a second WebView window no longer deletes the first one's cache files
- image download progress is drawn again; dead IMG branches removed
- clipped <kosicon> icons no longer smear

Resources:
- layout strings are rolled back each layout and measure pass (dpool growth)
- per-cell table arrays sized by the real column count
- tab switch restyles once, not twice

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Features:
- forms: text/password/checkbox/radio/select/submit controls, GET and POST
  submit (http.post, form-urlencoded, cp866 -> page charset)
- cookies: per-host jar sent with requests, Set-Cookie stored
- toolbar button that opens /tmp0/1/Downloads in Eolite
- <link>/<style> media attribute, #rrggbbaa colours, attribute selectors,
  ":link"/":any-link" keep their specificity, "}" inside CSS comments
- hex numeric entities, more named/numeric entities, "?" for unknown ones

Fixes from the code review:
- layout: stale blk_y beside floats, lay_skip_width leaking out of floated
  tables, ln_rw across inline-blocks, glued runs past the right edge, floats
  inside inline-blocks, centering while measuring max-content
- parser: <option> no longer closes <p>+<select>, ">" inside single-quoted
  attributes, "}" in comments
- tabs: keyboard switch/close during a load, stale close button after a close,
  Ctrl+T with every tab taken, selection on a tab without a document
- first page is opened once (a redraw no longer restarts the fetch), Back and
  Forward during a load stop it instead of going one page too far
- form value slots no longer exhausted by radio groups; a form closed inside
  a table cell keeps its own controls only

lib: http.post and extra request headers, proxy site escaping (dl uses it),
box_lib edit box field widths, KEY_MODIFIERS, menu reads Form before use.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
fixed C--.exe
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 24s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 25s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 24s
99cb5e87d8
Burer requested changes 2026-09-24 10:07:48 +00:00
Dismissed
Burer left a comment
Owner

Blocking

1. c--/c--.exe Commit 99cb5e87d re-adds the 1.1 MB binary that a4d502690
deleted on purpose. Unrelated to the browser. Drop the commit.

Memory corruption

2. engine/special.h:111 Scan accepts 9 chars into char special_code[10], then
sprintf(#special_code, "#%i", code) writes the decimal form back. &#xFFFFFFF; =
"#268435455", 11 bytes. Overflows the stack local.

3. engine/engine.h:557 get_absolute_url ends in strncpy(dst, src, URL_SIZE),
which writes URL_SIZE + 1 bytes. Fixed in engine_get_bgimage (529) and
style.h:2569; still URL_SIZE in engine_get_image (572), image_url (585),
WebView.c:1403, 1412, 1442, 1590.

4. engine/hit.h:82 links.active_url holds dpool.buf + offset across events.
CheckImgDownloads -> ImgRedraw -> Relayout -> POOL::addn reallocates buf.
GetAbsoluteActiveURL() (WebView.c:1545) then navigates to freed memory.

5. WebView.c:259 ctx_img_node stores a raw node index. The context menu is a
separate process, so a tab switch or page load can replace dom first. "Save image"
then indexes a smaller arena.

6. engine/style.h:2493 css_abs_urls: k = n * URL_SIZE + strlen(_text),
n = count of url(. 500 occurrences = 2 MB request per sheet per style_all().
malloc result unchecked before strcpy/memmov.

Functional

7. engine/style.h:1896 if (cnt >= 64) break; breaks the scan, not the
collection, so it keeps the first 64 matches, not the most specific. Later rules win
by source order in CSS; on a heavily-classed element they are dropped.

8. WebView.c:386 case TAB_CLOSE_ID calls EventTabClose without
if (http.transfer) StopLoading();. EventCloseActiveTab (tabs.h:192) and middle
click both have it. Arriving page lands in the newly active tab.

9. tabs.h:200 Switch blocked on http.transfer but not img_loading.
img_queue, img_slot_idx, prbar, img_queue_gen still describe the old page, so
CheckImgDownloads relayouts the new tab and mixes the queues. Same in
EventTabClose.

10. WebView.c:861 EventOpenNewTab ignores tab.add() returning false at
TABS_MAX and calls OpenPage on the current tab. EventNewBlankTab (tabs.h:225)
and EventViewSource (WebView.c:1091) check first.

11. engine/layout.h:2118 measure_block restores every line variable except
ln_rw, and inline_block (905) calls it before saving s_rw at 915. line_open()
zeroes ln_rw, so right = blk_x + blk_w - ln_rw (909) ignores a float:right on
the same line.

Performance

12. engine/paint.h:312 memopen("ICONS18", ...) per icon drawn, never closed.
200 <kosicon> = 200 syscalls per repaint, refcount grows for the process lifetime.
Open once at startup.

13. engine/form.h:643 form_submit_url calls form_owner() per node, and
form_owner (111-144) scans backwards over the node list. Repeated by
form_has_secret (247) and form_click (302). Quadratic in page size.

14. engine/style.h:2581 style_all re-reads and re-parses every <link> from
disk (read_file + css_abs_urls copy + css_parse_sheet). Called from ParseHtml,
Reparse (tab switch, F12, zoom), Relayout on @media change (engine.h:257),
ImgRedraw per arriving sheet. Cache the parsed rules per document.

Notes

15. lib/keyboard.h:111 KEY_MODIFIERS defined, no users.

16. Multi-line rationale comments from round 1 remain: style.h:1009, 1120,
layout.h:1725, paint.h:26, WebView.c:14.

## Blocking **1. `c--/c--.exe`** Commit `99cb5e87d` re-adds the 1.1 MB binary that `a4d502690` deleted on purpose. Unrelated to the browser. Drop the commit. ## Memory corruption **2. `engine/special.h:111`** Scan accepts 9 chars into `char special_code[10]`, then `sprintf(#special_code, "#%i", code)` writes the decimal form back. `&#xFFFFFFF;` = "#268435455", 11 bytes. Overflows the stack local. **3. `engine/engine.h:557`** `get_absolute_url` ends in `strncpy(dst, src, URL_SIZE)`, which writes URL_SIZE + 1 bytes. Fixed in `engine_get_bgimage` (529) and `style.h:2569`; still URL_SIZE in `engine_get_image` (572), `image_url` (585), `WebView.c:1403, 1412, 1442, 1590`. **4. `engine/hit.h:82`** `links.active_url` holds `dpool.buf + offset` across events. `CheckImgDownloads` -> `ImgRedraw` -> `Relayout` -> `POOL::addn` reallocates `buf`. `GetAbsoluteActiveURL()` (`WebView.c:1545`) then navigates to freed memory. **5. `WebView.c:259`** `ctx_img_node` stores a raw node index. The context menu is a separate process, so a tab switch or page load can replace `dom` first. "Save image" then indexes a smaller arena. **6. `engine/style.h:2493`** `css_abs_urls`: `k = n * URL_SIZE + strlen(_text)`, `n` = count of `url(`. 500 occurrences = 2 MB request per sheet per `style_all()`. `malloc` result unchecked before `strcpy`/`memmov`. ## Functional **7. `engine/style.h:1896`** `if (cnt >= 64) break;` breaks the scan, not the collection, so it keeps the first 64 matches, not the most specific. Later rules win by source order in CSS; on a heavily-classed element they are dropped. **8. `WebView.c:386`** `case TAB_CLOSE_ID` calls `EventTabClose` without `if (http.transfer) StopLoading();`. `EventCloseActiveTab` (`tabs.h:192`) and middle click both have it. Arriving page lands in the newly active tab. **9. `tabs.h:200`** Switch blocked on `http.transfer` but not `img_loading`. `img_queue`, `img_slot_idx`, `prbar`, `img_queue_gen` still describe the old page, so `CheckImgDownloads` relayouts the new tab and mixes the queues. Same in `EventTabClose`. **10. `WebView.c:861`** `EventOpenNewTab` ignores `tab.add()` returning false at `TABS_MAX` and calls `OpenPage` on the current tab. `EventNewBlankTab` (`tabs.h:225`) and `EventViewSource` (`WebView.c:1091`) check first. **11. `engine/layout.h:2118`** `measure_block` restores every line variable except `ln_rw`, and `inline_block` (905) calls it before saving `s_rw` at 915. `line_open()` zeroes `ln_rw`, so `right = blk_x + blk_w - ln_rw` (909) ignores a `float:right` on the same line. ## Performance **12. `engine/paint.h:312`** `memopen("ICONS18", ...)` per icon drawn, never closed. 200 `<kosicon>` = 200 syscalls per repaint, refcount grows for the process lifetime. Open once at startup. **13. `engine/form.h:643`** `form_submit_url` calls `form_owner()` per node, and `form_owner` (111-144) scans backwards over the node list. Repeated by `form_has_secret` (247) and `form_click` (302). Quadratic in page size. **14. `engine/style.h:2581`** `style_all` re-reads and re-parses every `<link>` from disk (`read_file` + `css_abs_urls` copy + `css_parse_sheet`). Called from `ParseHtml`, `Reparse` (tab switch, F12, zoom), `Relayout` on `@media` change (`engine.h:257`), `ImgRedraw` per arriving sheet. Cache the parsed rules per document. ## Notes **15. `lib/keyboard.h:111`** `KEY_MODIFIERS` defined, no users. **16.** Multi-line rationale comments from round 1 remain: `style.h:1009, 1120`, `layout.h:1725`, `paint.h:26`, `WebView.c:14`.
Leency added 2 commits 2026-09-25 03:45:47 +00:00
Features:
- pictures and stylesheets are fetched by threads of WebView (img_thread.h)
  instead of "dl -i" processes: no 256 byte url limit, cookies are sent,
  stylesheets first and retried, hung threads given up, orphans bounded
- status bar shows the page load: connecting, sending a form, KB received
  (of the total when known), images N/M
- CSS: grid (tracks, spans, template areas), calc(), :is()/:where()/:not(),
  :nth-*, @supports not, media ranges, transform translate, inset,
  min-height/max-height, vw, fractional px/em
- layout: absolute positioning inside blocks and inline boxes, paint order
  sort, float carry between blocks, flex order and item alignment
- <details>/<summary>, checkbox and radio painting, <label> targets,
  <noscript>, webp twin images, image rescaling to fit
- cache: stylesheets outlive pictures, big pictures dropped once laid out,
  evicted sheets are fetched again on a tab switch or font change
- updater downloads straight to /sys/network/WEBVIEW
- tests: calc, checkbox, details, floatcarry, grid, gridareas, iswhere,
  minheight, noscript, webp; sitetest.py site smoke test for the test VM

Fixes:
- stack raised: debian.org crashed with the stack running into globals
- content-type compared in lower case (charset=UTF-8)
- redirect buffer sized for get_absolute_url()

lib: collection::swap, ed_select flag for the rewritten box_lib, local path
check requires a disk number ("/cdn-cgi/...", "/hdimages/" are site paths).

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
webview: SVG/WebP via converter, pseudo-elements, calc() offsets, form fields
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 24s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 24s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 24s
1c05d68938
Features:
- SVG and WebP pictures are fetched through a converter (ini image_converter,
  wsrv.nl by default) at the size the page asks for
- CSS: ::before/::after boxes that give their element a height or clear its
  floats, calc() with percentages in offsets, min()/max()/clamp(),
  background-size in px, aspect-ratio, object-position, max-height in %,
  percent heights of definite boxes, text-indent: -9999px logos,
  clip: rect() of nothing (sr-only)
- small print (10px and less) drawn in the small font when the page is not
  set small all over
- settings: show_css switch
- text fields take their CSS width or size="n" (20 when not given), not 14
  characters; an auto table with percent columns grows so its other columns
  get their content width (Google's search field)

Fixes:
- picture blend never reads past the picture (page fault scrolling habr.com)
- closing a tab stops its stylesheet and picture downloads too; a middle
  click on another tab no longer breaks the load of the active one
- stylesheets and pictures in the cache have their own extensions
- 12 parallel downloads instead of 16

dl: always notifies when a download ends.
lib: CANVAS::DrawBar fills rows with MEMSETD.
Tests: pctheight.htm, slashdot link in showroom.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Burer added 1 commit 2026-09-25 10:49:46 +00:00
webview: italic, and the binary back under 64 KB
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 22s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 24s
e2473a9fcd
Features:
- <i>, <em>, <cite>, <var>, <dfn>, <address> and font-style: italic/oblique
  finally lean. The kernel fonts have no italic, so paint.h shears the run
  after it is drawn (cv_slant): the plain fonts take one 1px step across the
  middle of the line, the doubled pair a step per third. A row is copied from
  k pixels further left rather than k to the right, so the room a step frees
  fills with what lies before the run instead of keeping the ink it moved
  away. SF_ITALIC reached the painter in F_FLAGS all along; nothing read it.

Fixes:
- ImgJobsDump() was the one diagnostic dump not behind #ifdef TESTBUILD, and
  img_job_dump is never set: 180 packed bytes of a release build that could
  not run.

The rest is size, so that the above fits. The 78 branch "if (pid == CP_*)"
chain in css_apply_decl is a switch, and so is the one in css_pseudo_decl;
form_kind() looks its <input type> up in a table; style_compute() copies the
initial style from style_init[] instead of assigning 42 fields one at a time;
ten streq chains are css_kw() lists; six else-if pairs with the same body are
merged.

177170 -> 176042 bytes, 65805 -> 65516 packed with kpack.

Tests: fonts.htm - the four fonts there are, where font-size switches between
them, and every shape of lean.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Leency added 1 commit 2026-09-25 11:13:49 +00:00
webview, dl: detect cut downloads, image fixes, drop History page
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 20s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 23s
062e883b69
- libHTTP: expose http_msg.flags (HTTP_GOT_ALL_DATA) in _http
- dl: a connection lost mid-download is an error, the cut file is not saved
- webview: a cut page shows "Connection lost" and is not cached
- webview images: only complete answers are cached, failed urls are not
  refetched, natural <img> size kept in the node, slot kind fixed at start
- webview: remove the History menu item and WebView:history page
- CSS/form fixes, CANVAS_LEAN to leave unused canvas methods out

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Burer added 1 commit 2026-09-25 11:58:43 +00:00
webview: fix the length of the italic shear copy
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 36s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 38s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 27s
096b427120
c-- evaluates left to right with no operator precedence, so "k + _w * 4" was
compiled as "(k + _w) * 4". k is already in bytes, so cv_slant() copied 3 * k
bytes too many: up to 6 pixels past the run, and past the canvas buffer itself
on the last row.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Burer requested changes 2026-09-25 12:31:06 +00:00
Dismissed
Burer left a comment
Owner

Correctness

1. browser/tabs.h:232, "open in new tab" replaces the current page when the bar is full
Raised in round 2, still open. TAB::add() returns false without doing anything when
count == TABS_MAX (tabs.h:26), and EventOpenNewTab() ignores that:

void EventOpenNewTab(dword _url)
{
	tab.add();
	OpenPage(_url);

The author knows the behaviour: EventViewSource (WebView.c:1101) and
EventNewBlankTab (tabs.h:241) both guard with T_NO_FREE_TAB and carry comments
saying why ("with every tab taken EventOpenNewTab() loads into the current one"). Two
call sites have no guard: WebView.c:869, reached by a middle click on a link and by
"Open in new tab", and WebView.c:380, a URL handed over by another instance.

2. browser/WebView.c:1131, Update browser skips the whole shutdown
The close button does case 1: ImgJobsCancelAll(); cache2_save(); ExitProcess();
(WebView.c:399). EventUpdateBrowser() does EventOpenDownloader(#update_param); ExitProcess(); and nothing else. img_thread.h states that ExitProcess() "ends this
thread only" and that the workers "must not go on", so the fetch threads survive the
window, keep sockets open and keep writing wv_* files, and the session's cache index is
never saved.

3. browser/const.h:44 and :96, Update browser lost its checks and its target
update_param is now "<url>|/sys/network/WEBVIEW". The implementation it replaced
(git show 6713e2858^:browser/WebView.c) downloaded to /tmp0/1/Downloads, compared
get_file_size(#program_path) with the new file, refused a truncated download, said
"already up to date" when the sizes matched, copied over #program_path (the file the
running copy was started from), reported a failed copy, then saved the cache and
restarted itself. All of that is gone: the new build is written to a fixed path that need
not be the running one, with no size check and no message of any kind.

4. browser/engine/form.h:814, an iconv descriptor per form submit, and no way to close it
iconv_open is called on every submit of a non-cp866 page and the result kept in fq_cd.
lib/obj/iconv.h imports only iconv_open and iconv: there is no iconv_close binding
at all, so the descriptor cannot be released without adding the import first.

5. browser/WebView.c:989, view source runs the tail of the load twice
LoadInternalPage() calls ShowSource(), and ShowSource() calls LoadInternalPage()
again (show_src.h:98). The inner call runs the whole tail; control then returns to the
outer one, which runs it again. _http::hfree() has no guard on transfer
(lib/obj/http.h:150-154), so the second pass calls http_free stdcall (0). GetImg()
returns at once because a source page has no pictures or sheets, and the second
PageLoaded() only rewrites the status, so the null free is the whole of it.

6. browser/WebView.c:1390, Save image with no address
EventImageOpen() (1384) and EventImageCopyUrl() (1399) both start with
if (!ctx_img_url[0]) return;. EventImageSave() does not, and runs
RunProgram("/sys/network/dl", "-e ") on an <img> whose address could not be resolved.

7. browser/WebView.c:1322, the find box keeps a stale scroll and selection
EventFindClose() zeroes flags, size and pos but leaves offset, shift and
shift_old. notes/notes.c:200-201 is the same situation done fully:
offset = shift = shift_old = 0; cl_curs_x = cl_curs_y = 0.

Performance

8. browser/WebView.c:1410, the find bar is rebuilt on every hovered link
DrawStatusBar() discards _msg and calls DrawFindBar() whenever find_visible is
set. hit.h:95-101 fires on every change of the hovered link, so crossing a link-dense
page with the find bar open re-runs DefineHiddenButton three times, two raised buttons
and a full edit_box_draw per link, and the hovered URL is never shown.

Notes

9. browser/engine/style.h:5718, read_file(cache2.path.get(cache2.cur), #data, #size)
is the one place that does not follow the file's own rule of hoisting a call out of
another call's arguments. The generated code is correct here (the inner result is pushed
before anything else touches EAX), so this is about keeping the convention, not a defect.

10. browser/settings.h:9, the new search_engine default
https://lite.duckduckgo.com/lite/?q= is never reached on a stock system: the shipped
app.ini sets search_engine=http://wiby.me/?q= and an ini key wins over the code
default. It also disagrees with it, and the https form works only because the same file
sets proxy_address=http://proxy.kolibrios.org/?site= (img_job_url() refuses https
without a proxy). Either update the OS-side app.ini with it or keep the code default on
http.

11. browser/engine/style.h, style_init[100] spans offsets 0..399, the old
NODE_SIZE. This commit grew the node to 408 and put N_IMGW/N_IMGH at 400 and 404,
outside every range style_compute() copies, which is right for structural fields. A
style field added past 399 would silently stop being reset.

12. The multi-line comments carrying implementation rationale are still there
(cache.h:70, WebView.c:10, paint.h:165, engine.h:420, cookies.h:1). That
belongs in the commit message.

## Correctness **1. `browser/tabs.h:232`, "open in new tab" replaces the current page when the bar is full** Raised in round 2, still open. `TAB::add()` returns false without doing anything when `count == TABS_MAX` (`tabs.h:26`), and `EventOpenNewTab()` ignores that: ``` void EventOpenNewTab(dword _url) { tab.add(); OpenPage(_url); ``` The author knows the behaviour: `EventViewSource` (`WebView.c:1101`) and `EventNewBlankTab` (`tabs.h:241`) both guard with `T_NO_FREE_TAB` and carry comments saying why ("with every tab taken EventOpenNewTab() loads into the current one"). Two call sites have no guard: `WebView.c:869`, reached by a middle click on a link and by "Open in new tab", and `WebView.c:380`, a URL handed over by another instance. **2. `browser/WebView.c:1131`, Update browser skips the whole shutdown** The close button does `case 1: ImgJobsCancelAll(); cache2_save(); ExitProcess();` (`WebView.c:399`). `EventUpdateBrowser()` does `EventOpenDownloader(#update_param); ExitProcess();` and nothing else. `img_thread.h` states that `ExitProcess()` "ends this thread only" and that the workers "must not go on", so the fetch threads survive the window, keep sockets open and keep writing `wv_*` files, and the session's cache index is never saved. **3. `browser/const.h:44` and `:96`, Update browser lost its checks and its target** `update_param` is now `"<url>|/sys/network/WEBVIEW"`. The implementation it replaced (`git show 6713e2858^:browser/WebView.c`) downloaded to `/tmp0/1/Downloads`, compared `get_file_size(#program_path)` with the new file, refused a truncated download, said "already up to date" when the sizes matched, copied over `#program_path` (the file the running copy was started from), reported a failed copy, then saved the cache and restarted itself. All of that is gone: the new build is written to a fixed path that need not be the running one, with no size check and no message of any kind. **4. `browser/engine/form.h:814`, an iconv descriptor per form submit, and no way to close it** `iconv_open` is called on every submit of a non-cp866 page and the result kept in `fq_cd`. `lib/obj/iconv.h` imports only `iconv_open` and `iconv`: there is no `iconv_close` binding at all, so the descriptor cannot be released without adding the import first. **5. `browser/WebView.c:989`, view source runs the tail of the load twice** `LoadInternalPage()` calls `ShowSource()`, and `ShowSource()` calls `LoadInternalPage()` again (`show_src.h:98`). The inner call runs the whole tail; control then returns to the outer one, which runs it again. `_http::hfree()` has no guard on `transfer` (`lib/obj/http.h:150-154`), so the second pass calls `http_free stdcall (0)`. `GetImg()` returns at once because a source page has no pictures or sheets, and the second `PageLoaded()` only rewrites the status, so the null free is the whole of it. **6. `browser/WebView.c:1390`, Save image with no address** `EventImageOpen()` (`1384`) and `EventImageCopyUrl()` (`1399`) both start with `if (!ctx_img_url[0]) return;`. `EventImageSave()` does not, and runs `RunProgram("/sys/network/dl", "-e ")` on an `<img>` whose address could not be resolved. **7. `browser/WebView.c:1322`, the find box keeps a stale scroll and selection** `EventFindClose()` zeroes `flags`, `size` and `pos` but leaves `offset`, `shift` and `shift_old`. `notes/notes.c:200-201` is the same situation done fully: `offset = shift = shift_old = 0; cl_curs_x = cl_curs_y = 0`. ## Performance **8. `browser/WebView.c:1410`, the find bar is rebuilt on every hovered link** `DrawStatusBar()` discards `_msg` and calls `DrawFindBar()` whenever `find_visible` is set. `hit.h:95-101` fires on every *change* of the hovered link, so crossing a link-dense page with the find bar open re-runs `DefineHiddenButton` three times, two raised buttons and a full `edit_box_draw` per link, and the hovered URL is never shown. ## Notes **9. `browser/engine/style.h:5718`**, `read_file(cache2.path.get(cache2.cur), #data, #size)` is the one place that does not follow the file's own rule of hoisting a call out of another call's arguments. The generated code is correct here (the inner result is pushed before anything else touches EAX), so this is about keeping the convention, not a defect. **10. `browser/settings.h:9`**, the new `search_engine` default `https://lite.duckduckgo.com/lite/?q=` is never reached on a stock system: the shipped `app.ini` sets `search_engine=http://wiby.me/?q=` and an ini key wins over the code default. It also disagrees with it, and the https form works only because the same file sets `proxy_address=http://proxy.kolibrios.org/?site=` (`img_job_url()` refuses https without a proxy). Either update the OS-side app.ini with it or keep the code default on http. **11. `browser/engine/style.h`**, `style_init[100]` spans offsets 0..399, the old `NODE_SIZE`. This commit grew the node to 408 and put `N_IMGW`/`N_IMGH` at 400 and 404, outside every range `style_compute()` copies, which is right for structural fields. A *style* field added past 399 would silently stop being reset. **12.** The multi-line comments carrying implementation rationale are still there (`cache.h:70`, `WebView.c:10`, `paint.h:165`, `engine.h:420`, `cookies.h:1`). That belongs in the commit message.
Leency added 2 commits 2026-09-25 22:03:04 +00:00
- scrolling (wheel, scroll bar, keys) moves the canvas and paints only the
  band that came into view (paint_scroll)
- form controls take the page's width, height and padding (control_fit);
  value="" shows the placeholder
- vertical-align: super / sub, text sits on an inline-block's baseline
- @media min/max-height against the window height
- margin-right in percent, z-index on flex/grid items, absolute boxes with
  a px height, "width: auto; height: 100%" pictures
- transparent border colours, alpha edges over an empty canvas
- the hovered link no longer overwrites the find bar, ExitBrowser()
  stops the image threads on every exit path
- shorter comments in cache.h, cookies.h, WebView.c

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
WebView :
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 22s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 23s
eae05cefe4
- Short forms C--: IF ELSE WHILE FOR RETURN BREAK CONTINUE SWITCH CASE GOTO instead of lowercase	≈ −1360
- DSDWORD/DSBYTE instead of ESDWORD/ESBYTE (KolibriOS uses flat segments; the es: prefix is unnecessary)	≈ −170
- dom.n/attr/ntype/nfirst/nnext/nparent/ntext became standard functions dom_n(...), without passing 'this'	≈ −150
Leency added 1 commit 2026-09-26 01:55:59 +00:00
WebView: final fixes
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 22s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 22s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 23s
faf95ff552
Burer added 1 commit 2026-09-26 12:02:15 +00:00
webview: update the copy that is running, not a fixed path
Build C-- programs / Build (LANG_ENG) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_SPA) (pull_request) Successful in 21s
Build C-- programs / Build (LANG_RUS) (pull_request) Successful in 22s
7992b74a87
Burer approved these changes 2026-09-26 12:05:49 +00:00
Leency merged commit 2e9e054822 into main 2026-09-26 13:58:11 +00:00
Leency deleted branch webview-4.0 2026-09-26 13:58:11 +00:00
Burer referenced this issue from a commit 2026-09-27 06:47:57 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KolibriOS/cmm_apps#14