avm1: Stub out System API (merge #676)

Partially implement System.(capabilities,IME,security)
This commit is contained in:
Mike Welsh 2020-06-09 20:06:04 -07:00 committed by GitHub
commit 2eeba69541
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1268 additions and 2 deletions

View File

@ -30,7 +30,7 @@ jobs:
- name: Install linux depencencies
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get -y install libasound2-dev
run: sudo apt-get -y install libasound2-dev libxcb-shape0-dev libxcb-xfixes0-dev
- name: Run all rust tests
uses: actions-rs/cargo@v1

View File

@ -35,7 +35,7 @@ jobs:
- name: Install linux depencencies
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get -y install libasound2-dev
run: sudo apt-get -y install libasound2-dev libxcb-shape0-dev libxcb-xfixes0-dev
- name: Install wasm-pack
run: cargo install wasm-pack

63
Cargo.lock generated
View File

@ -206,6 +206,26 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clipboard"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clipboard-win 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"x11-clipboard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clipboard-win"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@ -1469,6 +1489,16 @@ dependencies = [
"objc_exception 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
@ -1477,6 +1507,14 @@ dependencies = [
"cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "once_cell"
version = "1.3.1"
@ -1840,6 +1878,7 @@ dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"minimp3 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num_enum 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.16.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"puremp3 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1856,6 +1895,7 @@ dependencies = [
name = "ruffle_desktop"
version = "0.1.0"
dependencies = [
"clipboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cpal 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"embed-resource 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2724,6 +2764,14 @@ dependencies = [
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "x11-clipboard"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"xcb 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "x11-dl"
version = "2.18.5"
@ -2735,6 +2783,15 @@ dependencies = [
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xcb"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xdg"
version = "2.2.0"
@ -2781,6 +2838,8 @@ dependencies = [
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clang-sys 0.29.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clipboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25a904646c0340239dcf7c51677b33928bf24fdf424b79a57909c0109075b2e7"
"checksum clipboard-win 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cocoa 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a4736c86d51bd878b474400d9ec888156f4037015f5d09794fab9f26eab1ad4"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
@ -2917,7 +2976,9 @@ dependencies = [
"checksum num_enum_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4a9f19dafa80d8af21ede328f2c4ed836604a2eb1c309d688f89a7cc40568923"
"checksum number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
"checksum objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
"checksum objc_exception 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
@ -3045,7 +3106,9 @@ dependencies = [
"checksum wio 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum x11 2.18.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773"
"checksum x11-clipboard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
"checksum x11-dl 2.18.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8"
"checksum xcb 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de"
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
"checksum xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
"checksum xz2 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"

View File

@ -27,6 +27,7 @@ quick-xml = "0.18.1"
downcast-rs = "1.1.1"
url = "2.1.0"
weak-table = "0.2.3"
percent-encoding = "2.1.0"
[dependencies.jpeg-decoder]
version = "0.1.19"

View File

@ -28,6 +28,10 @@ mod rectangle;
mod sound;
mod stage;
pub(crate) mod string;
pub(crate) mod system;
pub(crate) mod system_capabilities;
pub(crate) mod system_ime;
pub(crate) mod system_security;
pub(crate) mod text_field;
mod text_format;
mod xml;
@ -271,6 +275,7 @@ pub fn create_globals<'gc>(
let flash = ScriptObject::object(gc_context, Some(object_proto));
let geom = ScriptObject::object(gc_context, Some(object_proto));
let matrix = matrix::create_matrix_object(gc_context, Some(matrix_proto), Some(function_proto));
let point = point::create_point_object(gc_context, Some(point_proto), Some(function_proto));
let rectangle =
rectangle::create_rectangle_object(gc_context, Some(rectangle_proto), Some(function_proto));
@ -310,6 +315,26 @@ pub fn create_globals<'gc>(
globals.define_value(gc_context, "Number", number.into(), EnumSet::empty());
globals.define_value(gc_context, "Boolean", boolean.into(), EnumSet::empty());
let system_security =
system_security::create(gc_context, Some(object_proto), Some(function_proto));
let system_capabilities = system_capabilities::create(gc_context, Some(object_proto));
let system_ime = system_ime::create(
gc_context,
Some(object_proto),
Some(function_proto),
&listeners.ime,
);
let system = system::create(
gc_context,
Some(object_proto),
Some(function_proto),
system_security,
system_capabilities,
system_ime,
);
globals.define_value(gc_context, "System", system.into(), EnumSet::empty());
globals.define_value(
gc_context,
"Math",

View File

@ -0,0 +1,562 @@
use crate::avm1::function::Executable;
use crate::avm1::object::Object;
use crate::avm1::return_value::ReturnValue;
use crate::avm1::{Avm1, Error, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use core::fmt;
use enumset::{EnumSet, EnumSetType};
use gc_arena::MutationContext;
use num_enum::TryFromPrimitive;
use std::convert::TryFrom;
/// Available cpu architectures
pub enum CpuArchitecture {
PowerPC,
X86,
SPARC,
ARM,
}
impl fmt::Display for CpuArchitecture {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
CpuArchitecture::PowerPC => "PowerPC",
CpuArchitecture::X86 => "x86",
CpuArchitecture::SPARC => "SPARC",
CpuArchitecture::ARM => "ARM",
})
}
}
/// Available type of sandbox for a given SWF
pub enum SandboxType {
Remote,
LocalWithFile,
LocalWithNetwork,
LocalTrusted,
}
impl fmt::Display for SandboxType {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(match self {
SandboxType::Remote => "remote",
SandboxType::LocalWithFile => "localWithFile",
SandboxType::LocalWithNetwork => "localWithNetwork",
SandboxType::LocalTrusted => "localTrusted",
})
}
}
/// The available host operating systems
pub enum OperatingSystem {
WindowsXp,
Windows2k,
WindowsNt,
Windows98,
Windows95,
WindowsCE,
WindowsUnknown,
Linux,
MacOS,
}
impl fmt::Display for OperatingSystem {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(match self {
OperatingSystem::WindowsXp => "Windows XP",
OperatingSystem::Windows2k => "Windows 2000",
OperatingSystem::WindowsNt => "Windows NT",
OperatingSystem::Windows98 => "Windows 98/ME",
OperatingSystem::Windows95 => "Windows 95",
OperatingSystem::WindowsCE => "Windows CE",
OperatingSystem::WindowsUnknown => "Windows",
OperatingSystem::Linux => "Linux",
OperatingSystem::MacOS => "MacOS",
})
}
}
/// The available player manufacturers
pub enum Manufacturer {
Windows,
Macintosh,
Linux,
Other(String),
}
impl Manufacturer {
pub fn get_manufacturer_string(&self, version: u8) -> String {
let os_part = match self {
Manufacturer::Windows => "Windows",
Manufacturer::Macintosh => "Macintosh",
Manufacturer::Linux => "Linux",
Manufacturer::Other(name) => name.as_str(),
};
if version <= 8 {
format!("Macromedia {}", os_part)
} else {
format!("Adobe {}", os_part)
}
}
pub fn get_platform_name(&self) -> &str {
match self {
Manufacturer::Windows => "WIN",
Manufacturer::Macintosh => "MAC",
Manufacturer::Linux => "LNX",
_ => "",
}
}
}
/// The language of the host os
pub enum Language {
Czech,
Danish,
Dutch,
English,
Finnish,
French,
German,
Hungarian,
Italian,
Japanese,
Korean,
Norwegian,
Unknown,
Polish,
Portuguese,
Russian,
SimplifiedChinese,
Spanish,
Swedish,
TraditionalChinese,
Turkish,
}
impl Language {
pub fn get_language_code(&self, player_version: u8) -> &str {
match self {
Language::Czech => "cs",
Language::Danish => "da",
Language::Dutch => "nl",
Language::English => {
if player_version < 7 {
"en-US"
} else {
"en"
}
}
Language::Finnish => "fi",
Language::French => "fr",
Language::German => "de",
Language::Hungarian => "hu",
Language::Italian => "it",
Language::Japanese => "ja",
Language::Korean => "ko",
Language::Norwegian => "no",
Language::Unknown => "xu",
Language::Polish => "pl",
Language::Portuguese => "pt",
Language::Russian => "ru",
Language::SimplifiedChinese => "zh-CN",
Language::Spanish => "es",
Language::Swedish => "sv",
Language::TraditionalChinese => "zh-TW",
Language::Turkish => "tr",
}
}
}
/// The supported colors of the screen
pub enum ScreenColor {
Color,
Gray,
BlackWhite,
}
impl fmt::Display for ScreenColor {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(match self {
ScreenColor::Color => "color",
ScreenColor::Gray => "gray",
ScreenColor::BlackWhite => "bw",
})
}
}
/// The type of the player
pub enum PlayerType {
StandAlone,
External,
PlugIn,
ActiveX,
}
impl fmt::Display for PlayerType {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(match self {
PlayerType::StandAlone => "StandAlone",
PlayerType::External => "External",
PlayerType::PlugIn => "PlugIn",
PlayerType::ActiveX => "ActiveX",
})
}
}
#[derive(Debug, Copy, Clone, TryFromPrimitive)]
#[repr(u8)]
enum SettingsPanel {
Privacy = 0,
LocalStorage = 1,
Microphone = 2,
Camera = 3,
}
#[derive(EnumSetType, Debug)]
pub enum SystemCapabilities {
AvHardware,
Accessibility,
Audio,
AudioEncoder,
EmbeddedVideo,
IME,
MP3,
Printing,
ScreenBroadcast,
ScreenPlayback,
StreamingAudio,
StreamingVideo,
VideoEncoder,
Debugger,
LocalFileRead,
Process64Bit,
Process32Bit,
AcrobatEmbedded,
TLS,
WindowLess,
}
/// The properties modified by 'System'
pub struct SystemProperties {
/// If true then settings should be saved and read from the exact same domain of the player
/// If false then they should be saved to the super domain
pub exact_settings: bool,
/// If true then the system codepage should be used instead of unicode for text files
/// If false then unicode should be used
pub use_codepage: bool,
/// The capabilities of the player
pub capabilities: EnumSet<SystemCapabilities>,
/// The type of the player
pub player_type: PlayerType,
/// The type of screen available to the player
pub screen_color: ScreenColor,
/// The language of the host os
pub language: Language,
/// The resolution of the available screen
pub screen_resolution: (u32, u32),
/// The aspect ratio of the screens pixels
pub aspect_ratio: f32,
/// The dpi of the screen
pub dpi: f32,
/// The manufacturer of the player
pub manufacturer: Manufacturer,
/// The os of the host
pub os: OperatingSystem,
/// The type of the player sandbox
pub sandbox_type: SandboxType,
/// The cpu architecture of the platform
pub cpu_architecture: CpuArchitecture,
/// The highest supported h264 decoder level
pub idc_level: String,
}
impl SystemProperties {
pub fn get_version_string(&self, avm: &Avm1) -> String {
format!(
"{} {},0,0,0",
self.manufacturer.get_platform_name(),
avm.player_version
)
}
pub fn has_capability(&self, cap: SystemCapabilities) -> bool {
self.capabilities.contains(cap)
}
fn encode_capability(&self, cap: SystemCapabilities) -> &str {
if self.has_capability(cap) {
"t"
} else {
"f"
}
}
fn encode_not_capability(&self, cap: SystemCapabilities) -> &str {
if self.has_capability(cap) {
"f"
} else {
"t"
}
}
fn encode_string(&self, s: &str) -> String {
percent_encoding::utf8_percent_encode(s, percent_encoding::NON_ALPHANUMERIC).to_string()
}
pub fn get_server_string(&self, avm: &Avm1) -> String {
url::form_urlencoded::Serializer::new(String::new())
.append_pair("A", self.encode_capability(SystemCapabilities::Audio))
.append_pair(
"SA",
self.encode_capability(SystemCapabilities::StreamingAudio),
)
.append_pair(
"SV",
self.encode_capability(SystemCapabilities::StreamingVideo),
)
.append_pair(
"EV",
self.encode_capability(SystemCapabilities::EmbeddedVideo),
)
.append_pair("MP3", self.encode_capability(SystemCapabilities::MP3))
.append_pair(
"AE",
self.encode_capability(SystemCapabilities::AudioEncoder),
)
.append_pair(
"VE",
self.encode_capability(SystemCapabilities::VideoEncoder),
)
.append_pair(
"ACC",
self.encode_not_capability(SystemCapabilities::Accessibility),
)
.append_pair("PR", self.encode_capability(SystemCapabilities::Printing))
.append_pair(
"SP",
self.encode_capability(SystemCapabilities::ScreenPlayback),
)
.append_pair(
"SB",
self.encode_capability(SystemCapabilities::ScreenBroadcast),
)
.append_pair("DEB", self.encode_capability(SystemCapabilities::Debugger))
.append_pair(
"M",
&self.encode_string(
self.manufacturer
.get_manufacturer_string(avm.player_version)
.as_str(),
),
)
.append_pair(
"R",
&format!("{}x{}", self.screen_resolution.0, self.screen_resolution.1),
)
.append_pair("COL", &self.screen_color.to_string())
.append_pair("AR", &self.aspect_ratio.to_string())
.append_pair("OS", &self.encode_string(&self.os.to_string()))
.append_pair("L", self.language.get_language_code(avm.player_version))
.append_pair("IME", self.encode_capability(SystemCapabilities::IME))
.append_pair("PT", &self.player_type.to_string())
.append_pair(
"AVD",
self.encode_not_capability(SystemCapabilities::AvHardware),
)
.append_pair(
"LFD",
self.encode_not_capability(SystemCapabilities::LocalFileRead),
)
.append_pair("DP", &self.dpi.to_string())
.finish()
}
}
impl Default for SystemProperties {
fn default() -> Self {
SystemProperties {
//TODO: default to true on fp>=7, false <= 6
exact_settings: true,
//TODO: default to false on fp>=7, true <= 6
use_codepage: false,
capabilities: EnumSet::empty(),
player_type: PlayerType::StandAlone,
screen_color: ScreenColor::Color,
// TODO: note for fp <7 this should be the locale and the ui lang for >= 7, on windows
language: Language::English,
screen_resolution: (0, 0),
aspect_ratio: 1_f32,
dpi: 1_f32,
manufacturer: Manufacturer::Linux,
os: OperatingSystem::Linux,
sandbox_type: SandboxType::LocalTrusted,
cpu_architecture: CpuArchitecture::X86,
idc_level: "5.1".into(),
}
}
}
pub fn set_clipboard<'gc>(
avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
let new_content = args
.get(0)
.unwrap_or(&Value::Undefined)
.to_owned()
.coerce_to_string(avm, action_context)?;
action_context.input.set_clipboard_content(new_content);
Ok(Value::Undefined.into())
}
pub fn show_settings<'gc>(
avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
//TODO: should default to the last panel displayed
let last_panel_pos = 0;
let panel_pos = args
.get(0)
.unwrap_or(&Value::Number(last_panel_pos as f64))
.coerce_to_i32(avm, action_context)?;
let panel = SettingsPanel::try_from(panel_pos as u8).unwrap_or(SettingsPanel::Privacy);
log::warn!("System.showSettings({:?}) not not implemented", panel);
Ok(Value::Undefined.into())
}
pub fn set_use_code_page<'gc>(
avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
let value = args
.get(0)
.unwrap_or(&Value::Undefined)
.to_owned()
.as_bool(avm.current_swf_version());
action_context.system.use_codepage = value;
Ok(Value::Undefined.into())
}
pub fn get_use_code_page<'gc>(
_avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(action_context.system.use_codepage.into())
}
pub fn set_exact_settings<'gc>(
avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
let value = args
.get(0)
.unwrap_or(&Value::Undefined)
.to_owned()
.as_bool(avm.current_swf_version());
action_context.system.exact_settings = value;
Ok(Value::Undefined.into())
}
pub fn get_exact_settings<'gc>(
_avm: &mut Avm1<'gc>,
action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(action_context.system.exact_settings.into())
}
pub fn on_status<'gc>(
_avm: &mut Avm1<'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.onStatus() not implemented");
Ok(Value::Undefined.into())
}
pub fn create<'gc>(
gc_context: MutationContext<'gc, '_>,
proto: Option<Object<'gc>>,
fn_proto: Option<Object<'gc>>,
security: Object<'gc>,
capabilities: Object<'gc>,
ime: Object<'gc>,
) -> Object<'gc> {
let mut system = ScriptObject::object(gc_context, proto);
system.add_property(
gc_context,
"exactSettings",
Executable::Native(get_exact_settings),
Some(Executable::Native(set_exact_settings)),
EnumSet::empty(),
);
system.add_property(
gc_context,
"useCodepage",
Executable::Native(get_use_code_page),
Some(Executable::Native(set_use_code_page)),
EnumSet::empty(),
);
system.define_value(gc_context, "security", security.into(), EnumSet::empty());
system.define_value(
gc_context,
"capabilities",
capabilities.into(),
EnumSet::empty(),
);
system.define_value(gc_context, "IME", ime.into(), EnumSet::empty());
system.force_set_function(
"setClipboard",
set_clipboard,
gc_context,
EnumSet::empty(),
fn_proto,
);
system.force_set_function(
"showSettings",
show_settings,
gc_context,
EnumSet::empty(),
fn_proto,
);
// Pretty sure this is a variable
system.force_set_function(
"onStatus",
on_status,
gc_context,
EnumSet::empty(),
fn_proto,
);
system.into()
}

View File

@ -0,0 +1,246 @@
use crate::avm1::function::Executable;
use crate::avm1::globals::system::SystemCapabilities;
use crate::avm1::object::Object;
use crate::avm1::return_value::ReturnValue;
use crate::avm1::{Avm1, Error, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use enumset::EnumSet;
use gc_arena::MutationContext;
macro_rules! capabilities_func {
($func_name: ident, $capability: expr) => {
pub fn $func_name<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.has_capability($capability).into())
}
};
}
macro_rules! inverse_capabilities_func {
($func_name: ident, $capability: expr) => {
pub fn $func_name<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok((!context.system.has_capability($capability)).into())
}
};
}
macro_rules! capabilities_prop {
($gc_ctx: expr, $capabilities: expr, $($name:expr => $func:expr),* ) => {{
$(
$capabilities.add_property(
$gc_ctx,
$name,
Executable::Native($func),
None,
EnumSet::empty()
);
)*
}};
}
capabilities_func!(get_has_64_bit_support, SystemCapabilities::Process64Bit);
capabilities_func!(get_has_32_bit_support, SystemCapabilities::Process32Bit);
capabilities_func!(get_is_acrobat_embedded, SystemCapabilities::AcrobatEmbedded);
capabilities_func!(get_has_tls, SystemCapabilities::TLS);
capabilities_func!(get_has_accessibility, SystemCapabilities::Accessibility);
capabilities_func!(get_has_audio, SystemCapabilities::Audio);
capabilities_func!(get_has_audio_encoder, SystemCapabilities::AudioEncoder);
capabilities_func!(get_has_embedded_video, SystemCapabilities::EmbeddedVideo);
capabilities_func!(get_has_ime, SystemCapabilities::IME);
capabilities_func!(get_has_mp3, SystemCapabilities::MP3);
capabilities_func!(get_has_printing, SystemCapabilities::Printing);
capabilities_func!(
get_has_screen_broadcast,
SystemCapabilities::ScreenBroadcast
);
capabilities_func!(get_has_screen_playback, SystemCapabilities::ScreenPlayback);
capabilities_func!(get_has_streaming_audio, SystemCapabilities::StreamingAudio);
capabilities_func!(get_has_streaming_video, SystemCapabilities::StreamingVideo);
capabilities_func!(get_has_video_encoder, SystemCapabilities::VideoEncoder);
capabilities_func!(get_is_debugger, SystemCapabilities::Debugger);
inverse_capabilities_func!(
get_is_local_file_read_disabled,
SystemCapabilities::LocalFileRead
);
inverse_capabilities_func!(get_is_av_hardware_disabled, SystemCapabilities::AvHardware);
inverse_capabilities_func!(get_is_windowless_disabled, SystemCapabilities::WindowLess);
pub fn get_player_type<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.player_type.to_string().into())
}
pub fn get_screen_color<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.screen_color.to_string().into())
}
pub fn get_language<'gc>(
avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context
.system
.language
.get_language_code(avm.player_version)
.into())
}
pub fn get_screen_resolution_x<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.screen_resolution.0.into())
}
pub fn get_screen_resolution_y<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.screen_resolution.1.into())
}
pub fn get_pixel_aspect_ratio<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.aspect_ratio.into())
}
pub fn get_screen_dpi<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.dpi.into())
}
pub fn get_manufacturer<'gc>(
avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context
.system
.manufacturer
.get_manufacturer_string(avm.player_version)
.into())
}
pub fn get_os_name<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.os.to_string().into())
}
pub fn get_version<'gc>(
avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.get_version_string(avm).into())
}
pub fn get_server_string<'gc>(
avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.get_server_string(avm).into())
}
pub fn get_cpu_architecture<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.cpu_architecture.to_string().into())
}
pub fn get_max_idc_level<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.idc_level.clone().into())
}
pub fn create<'gc>(
gc_context: MutationContext<'gc, '_>,
proto: Option<Object<'gc>>,
) -> Object<'gc> {
let capabilities = ScriptObject::object(gc_context, proto);
capabilities_prop!(gc_context, capabilities,
"supports64BitProcesses" => get_has_64_bit_support,
"supports32BitProcesses" => get_has_32_bit_support,
"isEmbeddedInAcrobat" => get_is_acrobat_embedded,
"hasTLS" => get_has_tls,
"cpuArchitecture" => get_cpu_architecture,
"hasAccessibility" => get_has_accessibility,
"hasAudio" => get_has_audio,
"hasAudioEncoder" => get_has_audio_encoder,
"hasEmbeddedVideo" => get_has_embedded_video,
"hasIME" => get_has_ime,
"hasMP3" => get_has_mp3,
"hasPrinting" => get_has_printing,
"hasScreenBroadcast" => get_has_screen_broadcast,
"hasScreenPlayback" => get_has_screen_playback,
"hasStreamingAudio" => get_has_streaming_audio,
"hasStreamingVideo" => get_has_streaming_video,
"hasVideoEncoder" => get_has_video_encoder,
"isDebugger" => get_is_debugger,
"avHardwareDisable" => get_is_av_hardware_disabled,
"localFileReadDisable" => get_is_local_file_read_disabled,
"windowlessDisable" => get_is_windowless_disabled,
"language" => get_language,
"manufacturer" => get_manufacturer,
"os" => get_os_name,
"pixelAspectRatio" => get_pixel_aspect_ratio,
"playerType"=>get_player_type,
"screenColor" => get_screen_color,
"screenDPI" => get_screen_dpi,
"screenResolutionX" => get_screen_resolution_x,
"screenResolutionY" => get_screen_resolution_y,
"serverString" => get_server_string,
"version" => get_version,
"maxLevelIDC" => get_max_idc_level
);
capabilities.into()
}

View File

@ -0,0 +1,190 @@
use crate::avm1::listeners::Listeners;
use crate::avm1::object::Object;
use crate::avm1::property::Attribute;
use crate::avm1::property::Attribute::{DontDelete, DontEnum, ReadOnly};
use crate::avm1::return_value::ReturnValue;
use crate::avm1::{Avm1, Error, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use gc_arena::MutationContext;
use std::convert::Into;
fn on_ime_composition<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(false.into())
}
fn do_conversion<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(true.into())
}
fn get_conversion_mode<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok("KOREAN".into())
}
fn get_enabled<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(false.into())
}
fn set_composition_string<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(false.into())
}
fn set_conversion_mode<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(false.into())
}
fn set_enabled<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(false.into())
}
pub fn create<'gc>(
gc_context: MutationContext<'gc, '_>,
proto: Option<Object<'gc>>,
fn_proto: Option<Object<'gc>>,
listener: &Listeners<'gc>,
) -> Object<'gc> {
let mut ime = ScriptObject::object(gc_context, proto);
register_listener!(gc_context, ime, listener, fn_proto, ime);
ime.define_value(
gc_context,
"ALPHANUMERIC_FULL",
"ALPHANUMERIC_FULL".into(),
Attribute::DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"ALPHANUMERIC_HALF",
"ALPHANUMERIC_HALF".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"CHINESE",
"CHINESE".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"JAPANESE_HIRAGANA",
"JAPANESE_HIRAGANA".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"JAPANESE_KATAKANA_FULL",
"JAPANESE_KATAKANA_FULL".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"KOREAN",
"KOREAN".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.define_value(
gc_context,
"UNKNOWN",
"UNKNOWN".into(),
DontDelete | ReadOnly | DontEnum,
);
ime.force_set_function(
"onIMEComposition",
on_ime_composition,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"doConversion",
do_conversion,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"getConversionMode",
get_conversion_mode,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"getEnabled",
get_enabled,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"setCompositionString",
set_composition_string,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"setConversionMode",
set_conversion_mode,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.force_set_function(
"setEnabled",
set_enabled,
gc_context,
DontDelete | ReadOnly | DontEnum,
fn_proto,
);
ime.into()
}

View File

@ -0,0 +1,143 @@
use crate::avm1::function::Executable;
use crate::avm1::object::Object;
use crate::avm1::return_value::ReturnValue;
use crate::avm1::{Avm1, Error, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use enumset::EnumSet;
use gc_arena::MutationContext;
use std::convert::Into;
fn allow_domain<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.allowDomain() not implemented");
Ok(Value::Undefined.into())
}
fn allow_insecure_domain<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.allowInsecureDomain() not implemented");
Ok(Value::Undefined.into())
}
fn load_policy_file<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.allowInsecureDomain() not implemented");
Ok(Value::Undefined.into())
}
fn escape_domain<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.escapeDomain() not implemented");
Ok(Value::Undefined.into())
}
fn get_sandbox_type<'gc>(
_avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
Ok(context.system.sandbox_type.to_string().into())
}
fn get_choose_local_swf_path<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.chooseLocalSwfPath() not implemented");
Ok(Value::Undefined.into())
}
fn policy_file_resolver<'gc>(
_avm: &mut Avm1<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
log::warn!("System.security.chooseLocalSwfPath() not implemented");
Ok(Value::Undefined.into())
}
pub fn create<'gc>(
gc_context: MutationContext<'gc, '_>,
proto: Option<Object<'gc>>,
fn_proto: Option<Object<'gc>>,
) -> Object<'gc> {
let mut security = ScriptObject::object(gc_context, proto);
security.force_set_function(
"PolicyFileResolver",
policy_file_resolver,
gc_context,
EnumSet::empty(),
fn_proto,
);
security.force_set_function(
"allowDomain",
allow_domain,
gc_context,
EnumSet::empty(),
fn_proto,
);
security.force_set_function(
"allowInsecureDomain",
allow_insecure_domain,
gc_context,
EnumSet::empty(),
fn_proto,
);
security.force_set_function(
"loadPolicyFile",
load_policy_file,
gc_context,
EnumSet::empty(),
fn_proto,
);
security.force_set_function(
"escapeDomain",
escape_domain,
gc_context,
EnumSet::empty(),
fn_proto,
);
security.add_property(
gc_context,
"sandboxType",
Executable::Native(get_sandbox_type),
None,
EnumSet::empty(),
);
security.add_property(
gc_context,
"chooseLocalSwfPath",
Executable::Native(get_choose_local_swf_path),
None,
EnumSet::empty(),
);
security.into()
}

View File

@ -136,24 +136,28 @@ impl<'gc> Listeners<'gc> {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SystemListener {
Mouse,
Ime,
}
#[derive(Clone, Collect, Debug, Copy)]
#[collect(no_drop)]
pub struct SystemListeners<'gc> {
pub mouse: Listeners<'gc>,
pub ime: Listeners<'gc>,
}
impl<'gc> SystemListeners<'gc> {
pub fn new(gc_context: MutationContext<'gc, '_>, array_proto: Option<Object<'gc>>) -> Self {
Self {
mouse: Listeners::new(gc_context, array_proto),
ime: Listeners::new(gc_context, array_proto),
}
}
pub fn get(&self, listener: SystemListener) -> Listeners<'gc> {
match listener {
SystemListener::Mouse => self.mouse,
SystemListener::Ime => self.ime,
}
}
}

View File

@ -704,6 +704,7 @@ mod tests {
use super::*;
use crate::avm1::activation::Activation;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::property::Attribute::*;
use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend;
@ -758,6 +759,7 @@ mod tests {
stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
player: None,
load_manager: &mut LoadManager::new(),
system: &mut SystemProperties::default(),
};
root.post_instantiation(&mut avm, &mut context, root, None);

View File

@ -1,4 +1,5 @@
use crate::avm1::activation::Activation;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::{Avm1, Object, UpdateContext};
use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend;
@ -57,6 +58,7 @@ where
stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
player: None,
load_manager: &mut LoadManager::new(),
system: &mut SystemProperties::default(),
};
root.post_instantiation(&mut avm, &mut context, root, None);

View File

@ -14,6 +14,9 @@ pub trait InputBackend: Downcast {
/// Changes the mouse cursor image.
fn set_mouse_cursor(&mut self, cursor: MouseCursor);
/// Set the clipboard to the given content
fn set_clipboard_content(&mut self, content: String);
}
impl_downcast!(InputBackend);
@ -44,6 +47,8 @@ impl InputBackend for NullInputBackend {
fn show_mouse(&mut self) {}
fn set_mouse_cursor(&mut self, _cursor: MouseCursor) {}
fn set_clipboard_content(&mut self, _content: String) {}
}
impl Default for NullInputBackend {

View File

@ -1,6 +1,7 @@
//! Contexts and helper types passed between functions.
use crate::avm1;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::listeners::SystemListener;
use crate::avm1::{Object, Value};
use crate::backend::input::InputBackend;
@ -96,6 +97,9 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
/// This is required for asynchronous behavior, such as fetching data from
/// a URL.
pub load_manager: &'a mut LoadManager<'gc>,
/// The system properties
pub system: &'a mut SystemProperties,
}
/// A queued ActionScript call.

View File

@ -1,4 +1,5 @@
use crate::avm1::debug::VariableDumper;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::listeners::SystemListener;
use crate::avm1::{Activation, Avm1, TObject, Value};
use crate::backend::input::{InputBackend, MouseCursor};
@ -135,6 +136,8 @@ pub struct Player {
/// The current mouse cursor icon.
mouse_cursor: MouseCursor,
system: SystemProperties,
/// Self-reference to ourselves.
///
/// This is a weak reference that is upgraded and handed out in various
@ -233,6 +236,7 @@ impl Player {
navigator,
input,
self_reference: None,
system: SystemProperties::default(),
};
player.mutate_with_update_context(|avm, context| {
@ -831,6 +835,7 @@ impl Player {
stage_width,
stage_height,
player,
system_properties,
) = (
self.player_version,
self.global_time,
@ -845,6 +850,7 @@ impl Player {
Twips::from_pixels(self.movie_width.into()),
Twips::from_pixels(self.movie_height.into()),
self.self_reference.clone(),
&mut self.system,
);
self.gc_arena.mutate(|gc_context, gc_root| {
@ -874,6 +880,7 @@ impl Player {
system_prototypes: avm.prototypes().clone(),
player,
load_manager,
system: system_properties,
};
let ret = f(avm, &mut update_context);

View File

@ -21,6 +21,7 @@ structopt = "0.3.14"
winit = "0.22"
webbrowser = "0.5.4"
url = "2.1.1"
clipboard = "0.5.0"
[target.'cfg(windows)'.build-dependencies]
embed-resource = "1"

View File

@ -1,3 +1,4 @@
use clipboard::{ClipboardContext, ClipboardProvider};
use ruffle_core::backend::input::{InputBackend, MouseCursor};
use ruffle_core::events::{KeyCode, PlayerEvent};
use std::collections::HashSet;
@ -10,6 +11,7 @@ pub struct WinitInputBackend {
window: Rc<Window>,
cursor_visible: bool,
last_key: KeyCode,
clipboard: ClipboardContext,
}
impl WinitInputBackend {
@ -19,6 +21,7 @@ impl WinitInputBackend {
cursor_visible: true,
last_key: KeyCode::Unknown,
window,
clipboard: ClipboardProvider::new().unwrap(),
}
}
@ -196,6 +199,10 @@ impl InputBackend for WinitInputBackend {
};
self.window.set_cursor_icon(icon);
}
fn set_clipboard_content(&mut self, content: String) {
self.clipboard.set_contents(content).unwrap();
}
}
/// Converts a winit `VirtualKeyCode` into a Ruffle `KeyCode`.

View File

@ -183,6 +183,10 @@ impl InputBackend for WebInputBackend {
self.cursor = cursor;
self.update_mouse_cursor();
}
fn set_clipboard_content(&mut self, _content: String) {
log::warn!("set clipboard not implemented");
}
}
/// Converts a Web `KeyboardEvent.code` value into a Ruffle `KeyCode`.