///|
/// BiDi handler for browsingContext.getCssRuleViewportMap
fn BidiProtocol::handle_get_css_rule_viewport_map(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Unit {
match self.resolve_get_css_rule_viewport_map(request_id, params) {
Some(result) => self.send_success(request_id, Some(result))
None => ()
}
}
///|
fn BidiProtocol::resolve_get_css_rule_viewport_map(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Json? {
let params = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let ctx_id = match params.get("context") {
Some(String(id)) => id
_ => {
self.send_error(request_id, "invalid argument", "Missing context")
return None
}
}
let _session = match self.manager.get_session(ctx_id) {
Some(session) => session
None => {
self.send_error(request_id, "no such frame", "Unknown context: " + ctx_id)
return None
}
}
let viewport_widths : Array[Int] = match params.get("viewportWidths") {
Some(Array(items)) => {
let widths : Array[Int] = []
for item in items {
match item {
Number(n, ..) => widths.push(n.to_int())
_ => ()
}
}
widths
}
None => [375, 640, 768, 1024, 1280, 1440]
_ => {
self.send_error(
request_id, "invalid argument", "viewportWidths must be an array of numbers",
)
return None
}
}
let html = responsive_breakpoint_source_html("live-inline")
let map = @responsive.discover_css_rule_viewport_map(html, viewport_widths)
let rules_json : Array[Json] = []
for entry in map.rules {
let item : Map[String, Json] = {}
item["selector"] = Json::string(entry.selector)
item["properties"] = string_array_to_json(entry.properties)
item["mediaCondition"] = Json::string(entry.media_condition)
let active : Array[Json] = []
for w in entry.active_at_widths {
active.push(Json::number(w.to_double()))
}
item["activeAtWidths"] = Json::array(active)
let inactive : Array[Json] = []
for w in entry.inactive_at_widths {
inactive.push(Json::number(w.to_double()))
}
item["inactiveAtWidths"] = Json::array(inactive)
rules_json.push(make_object(item))
}
let result : Map[String, Json] = {}
result["rules"] = Json::array(rules_json)
Some(make_object(result))
}
///|
/// BiDi handler for browsingContext.getCssRuleUsage
fn BidiProtocol::handle_get_css_rule_usage(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Unit {
match self.resolve_get_css_rule_usage(request_id, params) {
Some(result) => self.send_success(request_id, Some(result))
None => ()
}
}
///|
fn BidiProtocol::resolve_get_css_rule_usage(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Json? {
let params = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let ctx_id = match params.get("context") {
Some(String(id)) => id
_ => {
self.send_error(request_id, "invalid argument", "Missing context")
return None
}
}
let _session = match self.manager.get_session(ctx_id) {
Some(session) => session
None => {
self.send_error(request_id, "no such frame", "Unknown context: " + ctx_id)
return None
}
}
let html = responsive_breakpoint_source_html("live-inline")
let usage = @responsive.discover_css_rule_usage(html)
let effective_sources = @responsive.discover_css_effective_property_sources(
html,
)
let rules_json : Array[Json] = []
for entry in usage {
let item : Map[String, Json] = {}
item["selector"] = Json::string(entry.selector)
item["matched"] = Json::boolean(entry.matched)
item["elements"] = Json::number(entry.elements.to_double())
item["overridden"] = Json::boolean(entry.overridden)
match entry.overridden_by {
Some(value) => item["overriddenBy"] = Json::string(value)
None => ()
}
item["noEffect"] = Json::boolean(entry.no_effect)
match entry.no_effect_reason {
Some(value) => item["noEffectReason"] = Json::string(value)
None => ()
}
rules_json.push(make_object(item))
}
let elements_json : Map[String, Json] = {}
effective_sources.each(fn(selector, sources) {
let source_json : Map[String, Json] = {}
sources.each(fn(property, label) {
source_json[property] = Json::string(label)
})
elements_json[selector] = make_object(source_json)
})
Some(
make_object({
"rules": Json::array(rules_json),
"elements": make_object(elements_json),
}),
)
}
///|
/// BiDi handler for browsingContext.getRequiredTestViewports
fn BidiProtocol::handle_get_required_test_viewports(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Unit {
match self.resolve_get_required_test_viewports(request_id, params) {
Some(result) => self.send_success(request_id, Some(result))
None => ()
}
}
///|
fn BidiProtocol::resolve_get_required_test_viewports(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Json? {
let params = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let ctx_id = match params.get("context") {
Some(String(id)) => id
_ => {
self.send_error(request_id, "invalid argument", "Missing context")
return None
}
}
let _session = match self.manager.get_session(ctx_id) {
Some(session) => session
None => {
self.send_error(request_id, "no such frame", "Unknown context: " + ctx_id)
return None
}
}
let html = responsive_breakpoint_source_html("live-inline")
let result = @responsive.discover_required_test_viewports(html)
let viewports_json : Array[Json] = []
for v in result.viewports {
let item : Map[String, Json] = {}
item["width"] = Json::number(v.width.to_double())
item["reason"] = Json::string(v.reason)
viewports_json.push(make_object(item))
}
let out : Map[String, Json] = {}
out["viewports"] = Json::array(viewports_json)
Some(make_object(out))
}
///|
/// BiDi handler for browsingContext.batchRender
fn BidiProtocol::handle_batch_render(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Unit {
match self.resolve_batch_render(request_id, params) {
Some(result) => self.send_success(request_id, Some(result))
None => ()
}
}
///|
fn BidiProtocol::resolve_batch_render(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Json? {
let params = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let ctx_id = match params.get("context") {
Some(String(id)) => id
_ => {
self.send_error(request_id, "invalid argument", "Missing context")
return None
}
}
let _session = match self.manager.get_session(ctx_id) {
Some(session) => session
None => {
self.send_error(request_id, "no such frame", "Unknown context: " + ctx_id)
return None
}
}
let options = match
@rendering.normalize_batch_render_options(
params,
responsive_breakpoint_source_html("live-inline"),
) {
Ok(options) => options
Err(error) => {
self.send_error(request_id, error.name(), error.message())
return None
}
}
let results = @vrt.render_html_batch_variants(
options.base_html,
options.viewport,
options.variants,
)
Some(@rendering.batch_render_results_to_json(results))
}
///|
/// BiDi handler for browsingContext.getComputedStylesWithState
fn BidiProtocol::handle_get_computed_styles_with_state(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Unit {
match self.resolve_get_computed_styles_with_state(request_id, params) {
Some(result) => self.send_success(request_id, Some(result))
None => ()
}
}
///|
fn BidiProtocol::resolve_get_computed_styles_with_state(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Json? {
let params = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let ctx_id = match params.get("context") {
Some(String(id)) => id
_ => {
self.send_error(request_id, "invalid argument", "Missing context")
return None
}
}
let _session = match self.manager.get_session(ctx_id) {
Some(session) => session
None => {
self.send_error(request_id, "no such frame", "Unknown context: " + ctx_id)
return None
}
}
let selector = match params.get("selector") {
Some(String(s)) => s
_ => {
self.send_error(
request_id, "invalid argument", "selector must be a string",
)
return None
}
}
// Parse forced states
let mut hover = false
let mut focus = false
let mut active = false
let mut focus_visible = false
let mut focus_within = false
match params.get("forcedStates") {
Some(Array(states)) =>
for state in states {
match state {
String("hover") => hover = true
String("focus") => focus = true
String("active") => active = true
String("focus-visible") => focus_visible = true
String("focus-within") => focus_within = true
_ => ()
}
}
_ => ()
}
let forced_state_names : Array[String] = []
if hover {
forced_state_names.push("hover")
}
if focus {
forced_state_names.push("focus")
}
if active {
forced_state_names.push("active")
}
if focus_visible {
forced_state_names.push("focus-visible")
}
if focus_within {
forced_state_names.push("focus-within")
}
// Parse properties to check
let properties : Array[String] = []
match params.get("properties") {
Some(Array(props)) =>
for prop in props {
match prop {
String(s) => properties.push(s)
_ => ()
}
}
_ => ()
}
let html = responsive_breakpoint_source_html("live-inline")
let result = @responsive.discover_computed_styles_with_state_names(
html, selector, forced_state_names, properties,
)
// Build JSON response
let normal_json : Map[String, Json] = {}
result.normal.each(fn(prop, val) { normal_json.set(prop, Json::string(val)) })
let forced_json : Map[String, Json] = {}
result.forced.each(fn(prop, val) { forced_json.set(prop, Json::string(val)) })
let diff_json : Array[Json] = []
for d in result.diff {
diff_json.push(
make_object({
"property": Json::string(d.property),
"normal": Json::string(d.normal),
"forced": Json::string(d.forced),
}),
)
}
let out : Map[String, Json] = {}
out["normal"] = make_object(normal_json)
out["forced"] = make_object(forced_json)
out["diff"] = Json::array(diff_json)
Some(make_object(out))
}