///|
fn default_navigation_request(url : String) -> NavigationRequest {
{ url, http_method: "GET", content_type: "", body: "" }
}
///|
fn Browser::load_sync_navigable_html_request(
self : Browser,
request : NavigationRequest,
) -> Bool {
match decode_sync_navigable_html_url(request.url) {
Some(html) => {
self.current_url = request.url
self.last_navigation_request = Some(request)
self.set_html_content(html)
self.set_external_css([])
let script_count = self.execute_scripts()
if script_count > 0 {
println(
"Executed " +
script_count.to_string() +
" script(s) during sync page load",
)
}
true
}
None => false
}
}
///|
fn Browser::navigate_sync_if_supported(
self : Browser,
request : NavigationRequest,
) -> Bool {
let previous_url = self.current_url
let navigated = self.load_sync_navigable_html_request(request)
if navigated {
if previous_url.length() > 0 {
self.back_history.push(previous_url)
}
self.forward_history.clear()
}
navigated
}
///|
/// Navigate to a URL and render (adds to back history, clears forward history)
pub async fn Browser::navigate(
self : Browser,
url : String,
) -> String raise @http.HttpError {
self.navigate_request(default_navigation_request(url))
}
///|
/// Navigate to URL in lightweight mode (for --json, --aom modes)
/// Skips CSS cascade and layout calculation to reduce memory usage
pub async fn Browser::navigate_lightweight(
self : Browser,
url : String,
) -> String raise @http.HttpError {
self.load_url_lightweight(url)
}
///|
/// Load a URL without adding to history (internal use)
async fn Browser::load_url(
self : Browser,
url : String,
) -> String raise @http.HttpError {
self.load_url_request(default_navigation_request(url))
}
///|
async fn Browser::navigate_request(
self : Browser,
request : NavigationRequest,
) -> String raise @http.HttpError {
if self.current_url.length() > 0 {
self.back_history.push(self.current_url)
}
self.forward_history.clear()
self.load_url_request(request)
}
///|
async fn Browser::load_url_request(
self : Browser,
request : NavigationRequest,
) -> String raise @http.HttpError {
let source_url = self.current_url
let request_record = {
url: request.url,
http_method: request.http_method,
content_type: request.content_type,
body: request.body,
}
let url = request_record.url
self.current_url = url
self.last_navigation_request = Some(request_record)
if url == "about:blank" || url.has_prefix("data:") {
let _ = self.load_sync_navigable_html_request(request_record)
return ""
}
let t0 = perf_now()
let response = self.fetch_navigation_document(source_url, request_record)
self.apply_html_source(response.body, false)
let t1 = perf_now()
// Fetch external CSS using lightweight extraction (no full parsing)
self.set_external_css(
fetch_external_css(
self.html_content,
url,
self.request_sandbox,
self.profile.http_cache(),
) catch {
_ => [] // Fallback to no external CSS on error
},
)
let t2 = perf_now()
self.reset_content_view_position()
self.ensure_parsed_content_document()
self.refresh_links_from_render_source()
self.clear_render_cache()
let t3 = perf_now()
// Execute scripts including external (JS execution)
let script_count = self.execute_scripts_async() catch { _ => 0 }
if script_count > 0 {
println(
"Executed " + script_count.to_string() + " script(s) during page load",
)
}
let t4 = perf_now()
// Content height is computed lazily from the layout tree in render_text()
// to avoid a duplicate full layout pass here.
self.reset_content_measurement_state()
// Prefetch images for kitty graphics rendering
self.prefetch_images() catch {
_ => ()
}
let t5 = perf_now()
perf_log(
"[perf] fetch=\{(t1 - t0).to_int()}ms css=\{(t2 - t1).to_int()}ms parse=\{(t3 - t2).to_int()}ms scripts=\{(t4 - t3).to_int()}ms images=\{(t5 - t4).to_int()}ms total=\{(t5 - t0).to_int()}ms",
)
// Render to Sixel
self.render()
}
///|
/// Load a URL in lightweight mode (for --json, --aom modes)
/// Skips CSS cascade and layout calculation to reduce memory usage
async fn Browser::load_url_lightweight(
self : Browser,
url : String,
) -> String raise @http.HttpError {
let source_url = self.current_url
self.current_url = url
let response = self.fetch_lightweight_navigation_document(source_url, url)
self.apply_html_source(response.body, false)
// Skip external CSS fetching in lightweight mode
self.set_external_css([])
// Skip link extraction (not needed for JSON/AOM output)
self.links = []
self.reset_content_view_position()
self.ensure_parsed_content_document()
self.clear_render_cache()
// Skip content height calculation in lightweight mode
self.content_height = 0
// Build lightweight accessibility tree (no CSS cascade, no layout)
self.build_accessibility_tree_lightweight()
// Return empty string (no rendering in lightweight mode)
""
}
///|
/// Go back to previous page in history and load it
pub async fn Browser::go_back(self : Browser) -> String? raise @http.HttpError {
if self.back_history.length() == 0 {
return None
}
// Save current URL to forward history
if self.current_url.length() > 0 {
self.forward_history.push(self.current_url)
}
let url = self.back_history.pop().unwrap()
let _ = self.load_url(url)
Some(url)
}
///|
/// Go forward to next page in history and load it
pub async fn Browser::go_forward(
self : Browser,
) -> String? raise @http.HttpError {
if self.forward_history.length() == 0 {
return None
}
// Save current URL to back history
if self.current_url.length() > 0 {
self.back_history.push(self.current_url)
}
let url = self.forward_history.pop().unwrap()
let _ = self.load_url(url)
Some(url)
}