Skip to content

Commit a49a81c

Browse files
committed
abstract/refactor JSEngine, add quickjs as a backend, update readme, clang-format all files, add basic js tests, update ci
1 parent b830fae commit a49a81c

33 files changed

Lines changed: 5635 additions & 5270 deletions

.github/workflows/pc-builds.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ jobs:
1414
matrix:
1515
os: [ubuntu]
1616
library: [sdl2]
17+
engine: [quickjs, mujs]
1718
runs-on: ${{ matrix.os }}-latest
1819
steps:
1920
- uses: actions/checkout@main
2021
with:
2122
submodules: recursive
22-
- name: Build ${{ matrix.platform }}
23+
- name: Build ${{ matrix.os }} w/ ${{ matrix.engine }}
2324
shell: bash
24-
run: ./libs/chesto/helpers/build_pc.sh broccolini ${{ matrix.os }} ${{ matrix.library }}
25+
run: JS_ENGINE=${{ matrix.engine }} ./libs/chesto/helpers/build_pc.sh broccolini ${{ matrix.os }} ${{ matrix.library }}
2526
- uses: actions/upload-artifact@v4
2627
with:
27-
name: broccolini_${{ matrix.os }}_${{ matrix.library }}
28-
path: ./broccolini_${{ matrix.os }}_${{ matrix.library }}.zip
28+
name: broccolini_${{ matrix.os }}_${{ matrix.library }}_${{ matrix.engine }}
29+
path: ./broccolini_${{ matrix.os }}_${{ matrix.library }}_${{ matrix.engine }}.zip

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
[submodule "libs/snabbdom"]
1111
path = libs/snabbdom
1212
url = https://github.com/snabbdom/snabbdom
13+
[submodule "libs/quickjs"]
14+
path = libs/quickjs
15+
url = git@github.com:quickjs-ng/quickjs.git

Makefile

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@ BINARY := broccolini
22

33
APP_TITLE := broccolini
44
APP_AUTHOR := vgmoose
5-
APP_VERSION := 0.1
5+
APP_VERSION := 0.2
66

7-
SOURCES += . libs/litehtml/src libs/litehtml/src/gumbo src utils mujs_src
7+
# JavaScript engine selection (override with: make JS_ENGINE=mujs)
8+
JS_ENGINE ?= quickjs
9+
10+
# Base sources and Chesto-related flags
11+
SOURCES += . libs/litehtml/src libs/litehtml/src/gumbo src utils
812
CFLAGS += -g -DUSE_KEYBOARD -DNETWORK
913

1014
CFLAGS += -I$(TOPDIR)/libs/litehtml/include -I$(TOPDIR)/libs/litehtml/include/litehtml
1115
CFLAGS += -I$(TOPDIR)/libs/litehtml/src/gumbo/include -I$(TOPDIR)/libs/litehtml/src/gumbo/include/gumbo
12-
CFLAGS += -I$(TOPDIR)/libs/mujs
16+
17+
# JavaScript engine specific configuration
18+
ifeq ($(JS_ENGINE),quickjs)
19+
SOURCES += libs/quickjs
20+
CFLAGS += -I$(TOPDIR)/libs/quickjs -DUSE_QUICKJS
21+
LDFLAGS += -lm -ldl
22+
else
23+
SOURCES += mujs_src
24+
CFLAGS += -I$(TOPDIR)/libs/mujs -DUSE_MUJS
25+
endif
1326

1427
LDFLAGS += -lcurl
1528

@@ -18,4 +31,20 @@ SOURCES += $(CHESTO_DIR)/libs/wiiu_kbd
1831
VPATH += $(CHESTO_DIR)/libs/wiiu_kbd
1932
endif
2033

21-
include libs/chesto/Makefile
34+
include libs/chesto/Makefile
35+
36+
# Remove some interpreter-only QuickJS sources
37+
ifeq ($(JS_ENGINE),quickjs)
38+
EXCLUDE_QJS := qjs.c qjsc.c run-test262.c unicode_gen.c api-test.c fuzz.c ctest.c
39+
CFILES := $(filter-out $(EXCLUDE_QJS),$(CFILES))
40+
OFILES := $(filter-out $(EXCLUDE_QJS:.c=.o),$(OFILES))
41+
endif
42+
43+
# Unless building JS engine tests, drop the standalone test suite (has its own main)
44+
ifeq ($(BUILD_JS_TESTS),1)
45+
CPPFILES := $(filter-out main.cpp,$(CPPFILES))
46+
OFILES := $(filter-out main.o,$(OFILES))
47+
else
48+
CPPFILES := $(filter-out test_js_engines.cpp,$(CPPFILES))
49+
OFILES := $(filter-out test_js_engines.o,$(OFILES))
50+
endif

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
## broccolini
22
A lightweight web browser for video game consoles and other low-dependency devices. Written in SDL2 using [Chesto](https://github.com/fortheusers/chesto), it supports viewing simple websites.
33

4-
Broccolini uses [litehtml](https://github.com/litehtml/litehtml) as its rendering engine. litehtml is not intended to be used in a "full-fledged" browser, but it is usable!
4+
Broccolini uses [litehtml](https://github.com/litehtml/litehtml) as its rendering engine. litehtml is not intended to be used in a "full-fledged" browser, but it is usable! "Better than nothing" is the guiding philosophy of this project. It also have very limited JS support through either [quickjs](https://github.com/quickjs-ng/quickjs) or [mujs](https://github.com/ccxvii/mujs) backends (see build instructions for details).
55

66
| URL Webview | Tab Switcher |
77
:-------------------------:|:-------------------------:
88
![Wikipedia demo](https://github.com/user-attachments/assets/060d91ab-3f61-4bd0-9279-10c28ba5f0a5) | ![Tab overview](https://github.com/user-attachments/assets/101fd92f-f5bc-43dc-9a55-069e9e68ec53)
99

10+
Video demo on YT: https://www.youtube.com/watch?v=I9lm6_RgElE
1011

1112
### What Works
1213
- renders HTML and CSS!
1314
- inertia scrolling and touch-based navigation
1415
- async image downloading
1516
- history and bookmarks
1617
- tabs and tab image previews
18+
- very basic javascript support (via mujs or quickjs)
1719
- private browsing mode
1820
- restore previous tabs on re-launch
1921
- full qwerty on-screen keyboard
@@ -25,29 +27,29 @@ Broccolini uses [litehtml](https://github.com/litehtml/litehtml) as its renderin
2527
- add cursor to be controlled with the joystick
2628
- fix images drawing on top of everything
2729
- detailed history and managing bookmarks
28-
- store and use cookies, local storage, etc
30+
- store and use cookies, local storage, etc (has initial support, but not done)
2931
- handle POSTs and other non-GET requests
3032
- handle different error codes
3133
- video and audio embed support
32-
- simple javascript within pages
34+
- better javascript compatibility with more popular sites
3335
- improve HTML/CSS compatibility
3436
- no flexbox support
35-
- form input elements
37+
- form input elements (only button currently supported)
3638
- iframes and frames
37-
- probably many more things
39+
- probably many many more things
3840

3941
### Download
4042
There are no stable releases available yet, however there are in-development builds for each platform under [GH Actions](https://github.com/vgmoose/broccolini/actions).
4143

4244
Nightly links: [Console builds](https://nightly.link/vgmoose/broccolini/workflows/main/main) - [PC builds](https://nightly.link/vgmoose/broccolini/workflows/pc-builds/main)
4345

4446
### Building for PC
45-
**As of this time, building must be done on a case-sensitive filesystem.** Requires SDL2 development libraries for your operating system, and a C++ toolchain.
47+
**As of this time, building must be done on a case-sensitive filesystem.** Requires SDL2 development libraries for your operating system, and a C++ toolchain. (replace `JS_ENGINE` with either `quickjs` or `mujs`)
4648

4749
```
4850
git clone --recursive git@github.com:vgmoose/broccolini.git
4951
cd broccolini
50-
make pc
52+
make pc JS_ENGINE=quickjs
5153
```
5254

5355
After building, `broccolini.bin` will be present in the current directory.

libs/quickjs

Submodule quickjs added at 5299e09

src/Base64Image.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
Base64Image::Base64Image(std::string base64)
55
{
6-
// decode data
7-
std::string decoded = base64_decode(base64);
8-
CST_Surface *surface = IMG_Load_RW(SDL_RWFromMem((void*)decoded.c_str(), decoded.size()), 1);
9-
loadFromSurfaceSaveToCache(base64, surface);
6+
// decode data
7+
std::string decoded = base64_decode(base64);
8+
CST_Surface* surface = IMG_Load_RW(SDL_RWFromMem((void*)decoded.c_str(), decoded.size()), 1);
9+
loadFromSurfaceSaveToCache(base64, surface);
1010

11-
// update size!
12-
this->width = surface->w;
13-
this->height = surface->h;
11+
// update size!
12+
this->width = surface->w;
13+
this->height = surface->h;
1414

15-
CST_FreeSurface(surface);
15+
CST_FreeSurface(surface);
1616
}

src/ClockElement.cpp

Lines changed: 70 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,86 @@
1-
#include <sstream>
2-
#include <iomanip>
31
#include "ClockElement.hpp"
42
#include "../utils/Utils.hpp"
3+
#include <iomanip>
4+
#include <sstream>
55

66
ClockElement::ClockElement(bool useLightText, bool is12Hour)
77
{
8-
this->width = 50;
9-
this->height = 50;
10-
11-
clockFont = CST_CreateFont();
12-
CST_LoadFont(
13-
clockFont,
14-
RootDisplay::renderer,
15-
RAMFS "res/fonts/OpenSans-Regular.ttf",
16-
28,
17-
useLightText ? CST_MakeColor(255, 255, 255, 255) : CST_MakeColor(0,0,0,255),
18-
TTF_STYLE_NORMAL
19-
);
20-
21-
this->touchable = true;
22-
this->is12Hour = is12Hour;
23-
24-
this->action = [this]() {
25-
this->is12Hour = !this->is12Hour;
26-
};
8+
this->width = 50;
9+
this->height = 50;
10+
11+
clockFont = CST_CreateFont();
12+
CST_LoadFont(clockFont, RootDisplay::renderer,
13+
RAMFS "res/fonts/OpenSans-Regular.ttf", 28,
14+
useLightText ? CST_MakeColor(255, 255, 255, 255)
15+
: CST_MakeColor(0, 0, 0, 255),
16+
TTF_STYLE_NORMAL);
17+
18+
this->touchable = true;
19+
this->is12Hour = is12Hour;
20+
21+
this->action = [this]()
22+
{ this->is12Hour = !this->is12Hour; };
2723
}
2824

29-
bool ClockElement::process(InputEvents* event) {
30-
// get the current time
31-
time_t now = time(0);
32-
tm* ltm = localtime(&now);
33-
34-
// get the hour and minute
35-
int hour = ltm->tm_hour;
36-
int minute = ltm->tm_min;
37-
38-
// convert to 12 hour time but only in USA, Austrailia, and English-speaking parts of canada
39-
// std::string locale = std::string(setlocale(LC_ALL, NULL));
40-
// if (locale == "en_US.UTF-8" || locale == "en_AU.UTF-8" || locale == "en_CA.UTF-8") {
41-
// if (hour > 12) {
42-
// hour -= 12;
43-
// }
44-
// }
45-
// printf("Locale: %s\n", locale.c_str());
46-
// TODO: this detection is not working
47-
48-
// convert to 12 hour time if the user has it enabled
49-
if (is12Hour && hour > 12) {
50-
hour -= 12;
51-
}
52-
53-
// if the time has changed, update the values
54-
if (hour != topVal || minute != botVal) {
55-
topVal = hour;
56-
botVal = minute;
57-
return true;
58-
}
59-
60-
// no update
61-
return Element::process(event);
25+
bool ClockElement::process(InputEvents* event)
26+
{
27+
// get the current time
28+
time_t now = time(0);
29+
tm* ltm = localtime(&now);
30+
31+
// get the hour and minute
32+
int hour = ltm->tm_hour;
33+
int minute = ltm->tm_min;
34+
35+
// convert to 12 hour time but only in USA, Austrailia, and English-speaking
36+
// parts of canada std::string locale = std::string(setlocale(LC_ALL, NULL));
37+
// if (locale == "en_US.UTF-8" || locale == "en_AU.UTF-8" || locale ==
38+
// "en_CA.UTF-8") {
39+
// if (hour > 12) {
40+
// hour -= 12;
41+
// }
42+
// }
43+
// printf("Locale: %s\n", locale.c_str());
44+
// TODO: this detection is not working
45+
46+
// convert to 12 hour time if the user has it enabled
47+
if (is12Hour && hour > 12)
48+
{
49+
hour -= 12;
50+
}
51+
52+
// if the time has changed, update the values
53+
if (hour != topVal || minute != botVal)
54+
{
55+
topVal = hour;
56+
botVal = minute;
57+
return true;
58+
}
59+
60+
// no update
61+
return Element::process(event);
6262
}
6363

64-
void ClockElement::render(Element* parent) {
65-
if (hidden) return;
64+
void ClockElement::render(Element* parent)
65+
{
66+
if (hidden)
67+
return;
6668

67-
auto renderer = RootDisplay::renderer;
69+
auto renderer = RootDisplay::renderer;
6870

69-
std::ostringstream str1;
70-
str1 << std::setw(2) << std::setfill('0') << topVal;
71-
std::string topText = str1.str();
71+
std::ostringstream str1;
72+
str1 << std::setw(2) << std::setfill('0') << topVal;
73+
std::string topText = str1.str();
7274

73-
std::ostringstream str2;
74-
str2 << std::setw(2) << std::setfill('0') << botVal;
75-
std::string bottomText = str2.str();
75+
std::ostringstream str2;
76+
str2 << std::setw(2) << std::setfill('0') << botVal;
77+
std::string bottomText = str2.str();
7678

77-
CST_DrawFont(
78-
clockFont, renderer,
79-
this->x + width/2 - 15,
80-
this->y + height/2 - 32,
81-
topText.c_str()
82-
);
79+
CST_DrawFont(clockFont, renderer, this->x + width / 2 - 15,
80+
this->y + height / 2 - 32, topText.c_str());
8381

84-
CST_DrawFont(
85-
clockFont, renderer,
86-
this->x + width/2 - 15,
87-
this->y + height/2 - 6,
88-
bottomText.c_str()
89-
);
82+
CST_DrawFont(clockFont, renderer, this->x + width / 2 - 15,
83+
this->y + height / 2 - 6, bottomText.c_str());
9084

91-
Element::render(parent);
85+
Element::render(parent);
9286
}

src/ClockElement.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class ClockElement : public Element
1010

1111
CST_Font* clockFont = NULL;
1212
int topVal = 12;
13-
int botVal = 0;
13+
int botVal = 0;
1414

1515
bool is12Hour = true;
1616

0 commit comments

Comments
 (0)