docs
Loading...
Searching...
No Matches
JS.h
Go to the documentation of this file.
1///
2/// Copyright (C) 2026 Ultralight, Inc. All rights reserved.
3/// A license is required for commercial use. https://ultralig.ht
4///
5
6///
7/// @namespace ultralight::js
8///
9/// Type-checked JavaScript bridge between C++ and web pages.
10///
11/// `#include <Ultralight/JS.h>`
12///
13/// @note This API is a preview and may still change after 2.0.
14///
15/// The JavaScript API provides two-way communication between your C++ application and the web pages
16/// loaded into a View. You can bind functions and properties under a global object that page
17/// scripts call like any Web API, or reach into a page to run scripts and call JavaScript functions
18/// directly.
19///
20/// Conversions between C++ types and JavaScript values happen automatically. The library checks
21/// types at compile time with static assertions and at runtime during every JavaScript call.
22///
23/// Register a bound function on an API attached to a View, then call into the page once the
24/// document loads:
25///
26/// ```
27/// js::API game_api("app"); // keep the API alive as long as pages use it
28///
29/// void SetupUI(View* view) {
30/// game_api["add"] = [](double a, double b) { return a + b; }; // app.add(2, 3)
31/// if (game_api.AttachTo(view))
32/// view->LoadURL("file:///app.html");
33/// }
34///
35/// void MyApp::OnDOMReady(View* caller, uint64_t frame_id, bool is_main_frame,
36/// const String& url) {
37/// if (!is_main_frame)
38/// return;
39///
40/// js::Context ctx(caller);
41/// ctx["ShowMessage"]("Howdy!"); // calls the page's ShowMessage()
42/// }
43/// ```
44///
45/// ## Where to Start
46///
47/// Common tasks begin with these types:
48///
49/// | Task | Type |
50/// |-----------------------------------------|------------------------|
51/// | Bind functions and properties | js::API |
52/// | Return Promises from async functions | js::Task, js::Resolver |
53/// | Call page functions or evaluate scripts | js::Context |
54/// | Inspect and convert script values | js::Value |
55/// | Work directly with raw JavaScriptCore | View::LockJSContext() |
56///
57/// ## Core Rules
58///
59/// - **Call the API on the Renderer's thread.** API::Emit() works from any thread, and copying,
60/// moving, or destroying a handle is safe from any thread too.
61/// - **A handle never keeps its page alive.** When a page navigates away or its View is destroyed,
62/// the handle's page is gone and operations fail safely (see js::Value for the Valid, Empty, and
63/// Gone states).
64/// - **The API never throws C++ exceptions.** A call that can fail returns a js::Result, which
65/// holds either the value or a js::Error.
66///
67/// \parblock
68/// @note The bridge requires C++20, and every file that uses the API must use the same C++
69/// exception setting.
70/// \endparblock
71///
72/// \parblock
73/// @note DOM elements cross the bridge only with `<Ultralight/dom/JSInterop.h>`, which this header
74/// doesn't include.
75/// \endparblock
76///
77/// @see js::API, js::Context, js::Value, View::LockJSContext()
78///
79#pragma once
80#include <Ultralight/Color.h>
81#include <Ultralight/String.h>
82#include <Ultralight/URL.h>
83#include <Ultralight/js/API.h>
85#include <Ultralight/js/Class.h>
87#include <Ultralight/js/Task.h>
89
90#include <string>
91#include <utility>
92
93namespace ultralight {
94namespace js {
95
96///
97/// ultralight::String as a JavaScript string in UTF-8, the same as std::string.
98///
99/// @note A null character at the very end of a JavaScript string is dropped when it converts
100/// to a String (null characters elsewhere are kept). Use std::string if you need it.
101///
102template <>
104 static bool FromJS(ULJSContext ctx, ULJSValue borrowed, String* out, ULJSValue* exception) {
105 std::string text;
106 if (!TypeTraits<std::string>::FromJS(ctx, borrowed, &text, exception))
107 return false;
108 *out = String(text.data(), text.size());
109 return true;
110 }
111 static ULJSValue ToJS(ULJSContext ctx, const String& value) {
112 const String8& utf8 = value.utf8();
113 return ulCreateJSValueStringUTF8(ctx, utf8.data(), utf8.length());
114 }
115 static constexpr const char* SchemaType() { return "string"; }
116 static bool AcceptsJSType(Type type, bool, bool) { return type == Type::String; }
117};
118
119///
120/// URL as its canonical string (see URL::str()).
121///
122/// From JavaScript, the string must parse as an absolute URL. Anything else (a relative URL or
123/// an empty string) fails with `expected url`. Declare std::optional<URL> to accept `undefined`
124/// or `null` as no URL.
125///
126/// An invalid URL converts to JavaScript as `null`.
127///
128template <>
130 static bool FromJS(ULJSContext ctx, ULJSValue borrowed, URL* out, ULJSValue* exception) {
131 String text;
132 if (!TypeTraits<String>::FromJS(ctx, borrowed, &text, exception))
133 return false;
134 URL parsed(text);
135 if (!parsed.is_valid())
136 return false;
137 *out = std::move(parsed);
138 return true;
139 }
140 static ULJSValue ToJS(ULJSContext ctx, const URL& value) {
141 if (!value.is_valid())
142 return ulCreateJSValueNull(ctx);
143 return TypeTraits<String>::ToJS(ctx, value.str());
144 }
145 static constexpr const char* SchemaType() { return "url"; }
146
147 // SchemaType() is the TypeError noun; the marshaled value is a plain string, or null for an
148 // invalid URL, so the schema expression (and the generated .d.ts) says so.
149 static void WriteSchemaExpr(std::string& out) { out += "{\"union\":[\"string\",\"null\"]}"; }
150 static bool AcceptsJSType(Type type, bool, bool) { return type == Type::String; }
151};
152
153///
154/// Color as CSS color text.
155///
156/// From JavaScript, the text goes through Color::Parse(): named colors, hex, `transparent`, and
157/// the CSS color functions such as rgb(), hsl(), hwb(), lab(), oklch(), and color().
158/// Wide-gamut colors narrow to sRGB. Text that doesn't parse fails with `expected color`, and so
159/// do `currentcolor` and the system color keywords.
160///
161/// To JavaScript, a Color converts as lowercase hex from Color::ToHexString() (`#rrggbb`, or
162/// `#rrggbbaa` when it isn't fully opaque). An unset or invalid Color converts as `null`.
163///
164template <>
166 static bool FromJS(ULJSContext ctx, ULJSValue borrowed, Color* out, ULJSValue* exception) {
167 String text;
168 if (!TypeTraits<String>::FromJS(ctx, borrowed, &text, exception))
169 return false;
170 Color parsed = Color::Parse(text);
171 if (parsed.invalid())
172 return false;
173 *out = parsed;
174 return true;
175 }
176 static ULJSValue ToJS(ULJSContext ctx, const Color& value) {
177 if (!value)
178 return ulCreateJSValueNull(ctx);
179 return TypeTraits<String>::ToJS(ctx, value.ToHexString());
180 }
181 static constexpr const char* SchemaType() { return "color"; }
182
183 // The marshaled value is CSS color text, or null for an unset or invalid Color.
184 static void WriteSchemaExpr(std::string& out) { out += "{\"union\":[\"color\",\"null\"]}"; }
185 static bool AcceptsJSType(Type type, bool, bool) { return type == Type::String; }
186};
187
188} // namespace js
189} // namespace ultralight
struct C_JSContext * ULJSContext
Opaque handle to a JavaScript execution context (one page's script world in one View).
Definition View.h:25
An RGBA color value in a certain color space (with CSS parsing helpers).
Definition Color.h:69
static Color Parse(const String &css)
Parse a CSS color string at runtime: the full CSS color grammar (named colors, hex,...
String ToHexString() const
Serialize this color as CSS hex text: lowercase #rrggbb, or #rrggbbaa when the alpha channel is not f...
constexpr bool invalid() const
Whether or not this color came from a string that failed to parse (Parse() at runtime,...
Definition Color.h:187
A null-terminated UTF-8 string container.
Definition String8.h:17
char * data()
Get raw UTF-8 data.
Definition String8.h:53
size_t length() const
Get length in bytes (not including null terminator).
Definition String8.h:59
Unicode string container with conversions for UTF-8, UTF-16, and UTF-32.
Definition String.h:31
String8 & utf8()
Get native UTF-8 string.
Definition String.h:109
String()
Create empty string.
Parsed web address.
Definition URL.h:104
bool is_valid() const
Whether or not this URL parsed successfully.
String str() const
Get the canonical serialization of the whole URL ("" if invalid).
Type-checked JavaScript bridge between C++ and web pages.
Definition JSInterop.h:141
Type
The type of a JavaScript value.
Definition Value.h:95
@ String
Definition Value.h:101
Root namespace for every public Ultralight type, function, and enumeration.
static bool AcceptsJSType(Type type, bool, bool)
Definition JS.h:185
static bool FromJS(ULJSContext ctx, ULJSValue borrowed, Color *out, ULJSValue *exception)
Definition JS.h:166
static void WriteSchemaExpr(std::string &out)
Definition JS.h:184
static ULJSValue ToJS(ULJSContext ctx, const Color &value)
Definition JS.h:176
static constexpr const char * SchemaType()
Definition JS.h:181
static ULJSValue ToJS(ULJSContext ctx, const String &value)
Definition JS.h:111
static bool AcceptsJSType(Type type, bool, bool)
Definition JS.h:116
static bool FromJS(ULJSContext ctx, ULJSValue borrowed, String *out, ULJSValue *exception)
Definition JS.h:104
static constexpr const char * SchemaType()
Definition JS.h:115
static bool AcceptsJSType(Type type, bool, bool)
Definition JS.h:150
static void WriteSchemaExpr(std::string &out)
Definition JS.h:149
static ULJSValue ToJS(ULJSContext ctx, const URL &value)
Definition JS.h:140
static bool FromJS(ULJSContext ctx, ULJSValue borrowed, URL *out, ULJSValue *exception)
Definition JS.h:130
static constexpr const char * SchemaType()
Definition JS.h:145
Type conversions between C++ and JavaScript across the bridge.
Definition TypeTraits.h:240