/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Liberally derived from //! This actor manages the configuration flags that the devtools host can apply to the targets. use std::collections::HashMap; use embedder_traits::Theme; use log::warn; use serde::Serialize; use serde_json::{Map, Value}; use crate::actor::{Actor, ActorError, ActorRegistry}; use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::tab::TabDescriptorActor; use crate::protocol::ClientRequest; use crate::{EmptyReplyMsg, RootActor, StreamId}; #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct TargetConfigurationTraits { supported_options: HashMap<&'static str, bool>, } #[derive(Serialize)] pub struct TargetConfigurationActorMsg { actor: String, configuration: HashMap<&'static str, bool>, traits: TargetConfigurationTraits, } pub struct TargetConfigurationActor { name: String, configuration: HashMap<&'static str, bool>, supported_options: HashMap<&'static str, bool>, } impl Actor for TargetConfigurationActor { fn name(&self) -> String { self.name.clone() } /// The target configuration actor can handle the following messages: /// /// - `updateConfiguration`: Receives new configuration flags from the devtools host. fn handle_message( &self, request: ClientRequest, registry: &ActorRegistry, msg_type: &str, msg: &Map, _id: StreamId, ) -> Result<(), ActorError> { match msg_type { "updateConfiguration" => { let config = msg .get("configuration") .ok_or(ActorError::MissingParameter)? .as_object() .ok_or(ActorError::BadParameterType)?; if let Some(scheme) = config.get("colorSchemeSimulation").and_then(|v| v.as_str()) { let theme = match scheme { "dark" => Theme::Dark, "light" => Theme::Light, _ => Theme::Light, }; let root_actor = registry.find::("root"); if let Some(tab_name) = root_actor.active_tab() { let tab_actor = registry.find::(&tab_name); let browsing_context_name = tab_actor.browsing_context(); let browsing_context_actor = registry.find::(&browsing_context_name); browsing_context_actor .simulate_color_scheme(theme) .map_err(|_| ActorError::Internal)?; } else { warn!("No active tab for updateConfiguration"); } } let msg = EmptyReplyMsg { from: self.name() }; request.reply_final(&msg)? }, _ => return Err(ActorError::UnrecognizedPacketType), }; Ok(()) } } impl TargetConfigurationActor { pub fn new(name: String) -> Self { Self { name, configuration: HashMap::new(), supported_options: HashMap::from([ ("cacheDisabled", false), ("colorSchemeSimulation", true), ("customFormatters", false), ("customUserAgent", false), ("javascriptEnabled", false), ("overrideDPPX", false), ("printSimulationEnabled", false), ("rdmPaneMaxTouchPoints", false), ("rdmPaneOrientation", false), ("recordAllocations", false), ("reloadOnTouchSimulationToggle", false), ("restoreFocus", false), ("serviceWorkersTestingEnabled", false), ("setTabOffline", false), ("touchEventsOverride", false), ("tracerOptions", false), ("useSimpleHighlightersForReducedMotion", false), ]), } } pub fn encodable(&self) -> TargetConfigurationActorMsg { TargetConfigurationActorMsg { actor: self.name(), configuration: self.configuration.clone(), traits: TargetConfigurationTraits { supported_options: self.supported_options.clone(), }, } } }