Init commit

This commit is contained in:
Wu Yu Wei
2024-01-15 18:25:57 +09:00
commit 6da3588087
59 changed files with 386933 additions and 0 deletions

2
.cargo/config.toml Normal file
View File

@@ -0,0 +1,2 @@
[env]
RUSTC_BOOTSTRAP = "crown,script,style_tests"

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
target
Cargo.lock
.DS_Store
.vscode/

129
Cargo.toml Normal file
View File

@@ -0,0 +1,129 @@
workspace = {}
[package]
name = "wry"
version = "0.34.2"
authors = ["Tauri Programme within The Commons Conservancy"]
edition = "2021"
license = "Apache-2.0 OR MIT"
description = "Cross-platform WebView rendering library"
readme = "README.md"
repository = "https://github.com/tauri-apps/wry"
documentation = "https://docs.rs/wry"
categories = ["gui"]
[package.metadata.docs.rs]
no-default-features = true
features = ["file-drop", "protocol"]
targets = [
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
"x86_64-apple-darwin",
]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["file-drop", "objc-exception", "protocol", "servo"]
objc-exception = ["objc/exception"]
file-drop = []
protocol = []
devtools = []
transparent = []
fullscreen = []
linux-body = ["webkit2gtk/v2_40", "os-webview"]
mac-proxy = []
os-webview = ["javascriptcore-rs", "webkit2gtk", "webkit2gtk-sys", "dep:gtk", "soup3", "x11-dl", "gdkx11"]
servo = []
[build-dependencies]
cfg_aliases = "0.1"
[dependencies]
libc = "0.2"
log = "0.4"
once_cell = "1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
url = "2.4"
http = "0.2"
raw-window-handle = { version = "0.5", features = ["std"] }
# Servo TODO move to feature gate
libservo = { git = "https://github.com/servo/servo.git", rev = "e7d2d23", features = ["max_log_level", "native-bluetooth", "webdriver"] }
servo-media = { git = "https://github.com/servo/media" }
crossbeam-channel = "0.5"
getopts = "0.2.17"
surfman = { version = "0.8", features = ["chains", "sm-angle", "sm-angle-default", "sm-x11", "sm-raw-window-handle"] }
winit = { version = "0.29", features = ["rwh_05"] }
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
javascriptcore-rs = { version = "=1.1", features = ["v2_28"], optional = true }
webkit2gtk = { version = "=2.0", features = ["v2_38"], optional = true }
webkit2gtk-sys = { version = "=2.0", optional = true }
gtk = { version = "0.18", optional = true }
soup3 = { version = "0.5", optional = true }
x11-dl = { version = "2.9", optional = true }
gdkx11 = { version = "0.18", optional = true }
[target."cfg(target_os = \"windows\")".dependencies]
webview2-com = "0.27"
windows-implement = "0.51"
dunce = "1"
[target."cfg(target_os = \"windows\")".dependencies.windows]
version = "0.51"
features = [
"implement",
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
"Win32_Globalization",
"Win32_UI_HiDpi",
"Win32_UI_Input",
"Win32_UI_Input_KeyboardAndMouse",
]
[target."cfg(any(target_os = \"ios\", target_os = \"macos\"))".dependencies]
block = "0.1"
cocoa = "0.25"
core-graphics = "0.23"
objc = "0.2"
objc_id = "0.1"
[target."cfg(target_os = \"android\")".dependencies]
crossbeam-channel = "0.5"
html5ever = "0.26"
kuchiki = { package = "kuchikiki", version = "0.8" }
sha2 = "0.10"
base64 = "0.21"
jni = "0.21"
ndk = "0.7"
ndk-sys = "0.4"
ndk-context = "0.1"
tao-macros = { version = "0.1.0" }
[dev-dependencies]
http-range = "0.1.5"
pollster = "0.3.0"
# tao = { git = "https://github.com/tauri-apps/tao", default-features = false, features = ["rwh_05"] }
wgpu = "0.18.0"
[patch.crates-io]
bindgen = { git = "https://github.com/sagudev/rust-bindgen", branch = "f16" }
# This is required because we want all dependencies that use WebRender to
# use our vendored version.
[patch."https://github.com/servo/webrender"]
webrender = { git = "https://github.com/servo/servo.git" }
webrender_api = { git = "https://github.com/servo/servo.git" }
[patch."https://github.com/servo/mozjs"]
mozjs = { git = "https://github.com/wusyong/mozjs", branch = "mozjs_mirror" }

201
LICENSE-APACHE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

21
LICENSE-MIT Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2023 Ngo Iok Ui & Tauri Programme within The Commons Conservancy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
README.md Normal file
View File

@@ -0,0 +1,52 @@
# Yippee
A web browser.
# Usage
The current demo works best on macOS at the moment, since it tries to customize its traffic light buttons to be seamless in the window.
It should also work on Windows, as well as Linux with X11. You may encounter problems running the demo on Linux with Wayland or Xwayland.
## Prerequisites
### Windows
- Install [Rust](https://www.rust-lang.org/)
- Install [scoop](https://scoop.sh/) and then install other tools from it. You can install them manually but this is easier and recommended:
```sh
scoop install git python llvm cmake
```
### Others(WIP)
For now, please follow the instructions in [Servo - Build Setup](https://github.com/servo/servo) to bootstrap first.
## Build
- Download [mozjs binary](https://github.com/wusyong/mozjs/releases/tag/tag-8410b587d66a36f1660cc3b828359e199eb0760a) and set the environment variable:
```sh
MOZJS_MIRROR=path/to/libmozjs.tar.gz
```
- **NixOS only:** add `wayland` and `libGL` to `LD_LIBRARY_PATH` in `../servo/etc/shell.nix`
- Run demo
```sh
cargo run
```
- Or if you are using Nix or NixOS:
```
nix-shell ../servo/etc/shell.nix --run 'cargo run --example servo'
```
## Future Work
- Add more window and servo features to make it feel more like a general web browser.
- Improve development experience.
- Multi webviews and multi browsing contexts in the same window.

117
build.rs Normal file
View File

@@ -0,0 +1,117 @@
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
fn main() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
if target_os == "macos" || target_os == "ios" {
println!("cargo:rustc-link-lib=framework=WebKit");
}
let is_android = std::env::var("CARGO_CFG_TARGET_OS")
.map(|t| t == "android")
.unwrap_or_default();
if is_android {
use std::{fs, path::PathBuf};
fn env_var(var: &str) -> String {
std::env::var(var).unwrap_or_else(|_| {
panic!(
"`{}` is not set, which is needed to generate the kotlin files for android.",
var
)
})
}
println!("cargo:rerun-if-env-changed=WRY_ANDROID_PACKAGE");
println!("cargo:rerun-if-env-changed=WRY_ANDROID_LIBRARY");
println!("cargo:rerun-if-env-changed=WRY_ANDROID_KOTLIN_FILES_OUT_DIR");
if let Ok(kotlin_out_dir) = std::env::var("WRY_ANDROID_KOTLIN_FILES_OUT_DIR") {
let package = env_var("WRY_ANDROID_PACKAGE");
let library = env_var("WRY_ANDROID_LIBRARY");
let kotlin_out_dir = PathBuf::from(&kotlin_out_dir)
.canonicalize()
.unwrap_or_else(move |_| {
panic!("Failed to canonicalize `WRY_ANDROID_KOTLIN_FILES_OUT_DIR` path {kotlin_out_dir}")
});
let kotlin_files_path =
PathBuf::from(env_var("CARGO_MANIFEST_DIR")).join("src/android/kotlin");
println!("cargo:rerun-if-changed={}", kotlin_files_path.display());
let kotlin_files = fs::read_dir(kotlin_files_path).expect("failed to read kotlin directory");
for file in kotlin_files {
let file = file.unwrap();
let class_extension_env = format!(
"WRY_{}_CLASS_EXTENSION",
file
.path()
.file_stem()
.unwrap()
.to_string_lossy()
.to_uppercase()
);
let class_init_env = format!(
"WRY_{}_CLASS_INIT",
file
.path()
.file_stem()
.unwrap()
.to_string_lossy()
.to_uppercase()
);
println!("cargo:rerun-if-env-changed={}", class_extension_env);
println!("cargo:rerun-if-env-changed={}", class_init_env);
let content = fs::read_to_string(file.path())
.expect("failed to read kotlin file as string")
.replace("{{package}}", &package)
.replace("{{library}}", &library)
.replace(
"{{class-extension}}",
&std::env::var(&class_extension_env).unwrap_or_default(),
)
.replace(
"{{class-init}}",
&std::env::var(&class_init_env).unwrap_or_default(),
);
let auto_generated_comment = match file
.path()
.extension()
.unwrap_or_default()
.to_str()
.unwrap_or_default()
{
"pro" => "# THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!!\n\n",
"kt" => "/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */\n\n",
_ => "String::new()",
};
let mut out = String::from(auto_generated_comment);
out.push_str(&content);
let out_path = kotlin_out_dir.join(file.file_name());
fs::write(&out_path, out).expect("Failed to write kotlin file");
println!("cargo:rerun-if-changed={}", out_path.display());
}
}
}
cfg_aliases::cfg_aliases! {
// Platforms
android: { target_os = "android" },
macos: { target_os = "macos" },
ios: { target_os = "ios" },
windows: { target_os = "windows" },
apple: { any(target_os = "ios", target_os = "macos") },
linux: { all(unix, not(apple), not(android)) },
// Backends
gtk: { all(feature = "native", linux) },
gtk: { all(feature = "os-webview", linux) },
servo: { all(feature = "servo", any(linux, macos, windows)) },
}
}

178
demo.html Normal file
View File

@@ -0,0 +1,178 @@
<!DOCTYPE html>
<html>
<head>
<style>
html {
width: 100%;
height: 100%;
}
body {
width: 100%;
height: 100%;
}
.bg {
position: fixed;
height: 100%;
width: 100%;
background: linear-gradient(-45deg, #f5b23f, #3cc8e7, #d8f931, #26e6b9);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
top: 0;
left: 0;
z-index: -1;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.text-container {
position: relative;
display: inline-block;
top: 100px;
left: 40px;
}
.text {
cursor: default;
position: relative;
color: #fff;
line-height: 50px;
font-weight: bold;
font-size: 50px;
font-family: 'Courier New';
user-select: none;
-webkit-user-select: none;
}
.text-bg {
background-color: rgba(0, 0, 0, 0.2);
padding: 5px;
}
.spotlight {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
background: radial-gradient(
50px 50px at center center,
transparent,
transparent 100px,
rgba(0, 0, 0, 0.05) 150px
);
opacity: 1;
z-index: 1;
}
.traffic-light-area {
display: block;
height: 30px;
width: 62px;
background: #0000007e;
user-select: none;
position: fixed;
top: 0;
left: 0;
right: 0;
padding-left: 10px;
border-radius: 0 0 5px 0;
}
</style>
</head>
<body>
<!-- <div class="traffic-light-area"></div> -->
<div id="spotlight" class="spotlight"></div>
<div class="text-container">
<span id="text-prefix" class="text">Hello </span>
<span id="text-name" class="text text-bg"></span>
<span id="cursor" class="text">_</span>
</div>
<div class="bg"></div>
<script>
/* Spotlight */
const spotlightEl = document.getElementById('spotlight');
function handleMouseMove(event) {
const { clientX, clientY } = event;
spotlightEl.style =
'background:radial-gradient(50px 50px at ' +
clientX +
'px ' +
clientY +
'px, transparent, transparent 100px, rgba(0,0,0,0.05) 150px)';
}
document.addEventListener('mousemove', handleMouseMove);
/* Typing Effect */
async function startCarosel() {
const textNameEl = document.getElementById('text-name');
const texts = ['Tauri.', 'Servo.', 'World!'];
const colors = ['#ffc131', '#3cc8e7', '#ffffff'];
let textIdx = 0;
while (true) {
const text = texts[textIdx];
updateNameColor(textNameEl, colors[textIdx]);
await type(texts[textIdx], textNameEl);
let blinkTimerId = blinkCursor();
await sleep(3200);
cleanCursor(blinkTimerId);
await backspace(textNameEl);
await sleep(500);
textIdx = (textIdx + 1) % texts.length;
}
}
async function type(text, el, delay = 100) {
el.classList.add('text-bg');
for (const ch of text) {
await sleep(delay);
el.innerHTML += ch;
}
}
async function backspace(el) {
let text = el.innerHTML;
while (text.length > 0) {
await sleep(60);
text = text.slice(0, -1);
el.innerHTML = text;
}
el.classList.remove('text-bg');
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function blinkCursor() {
const cursor = document.getElementById('cursor');
return setInterval(() => {
if (cursor.innerHTML === '_') {
cursor.innerHTML = '';
} else {
cursor.innerHTML = '_';
}
}, 500);
}
function cleanCursor(timerId) {
clearTimeout(timerId);
const cursor = document.getElementById('cursor');
cursor.innerHTML = '_';
}
function updateNameColor(el, color) {
el.style.color = color;
}
startCarosel();
</script>
</body>
</html>

View File

@@ -0,0 +1,7 @@
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf460
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\vieww12000\viewh15840\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0
\f0\fs24 \cf0 ${version}}

4
resources/ahem.css Normal file
View File

@@ -0,0 +1,4 @@
@font-face {
font-family: Ahem;
src: url(ahem/AHEM____.TTF);
}

BIN
resources/ahem/AHEM____.TTF Normal file

Binary file not shown.

1
resources/ahem/Ahem.ps Normal file

File diff suppressed because one or more lines are too long

BIN
resources/ahem/Ahem.sit Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
The files in this directory are copied from http://www.w3.org/Style/CSS/Test/Fonts/Ahem/

36
resources/ahem/COPYING Normal file
View File

@@ -0,0 +1,36 @@
The Ahem font in this directory belongs to the public domain. In
jurisdictions that do not recognize public domain ownership of these
files, the following Creative Commons Zero declaration applies:
<http://labs.creativecommons.org/licenses/zero-waive/1.0/us/legalcode>
which is quoted below:
The person who has associated a work with this document (the "Work")
affirms that he or she (the "Affirmer") is the/an author or owner of
the Work. The Work may be any work of authorship, including a
database.
The Affirmer hereby fully, permanently and irrevocably waives and
relinquishes all of her or his copyright and related or neighboring
legal rights in the Work available under any federal or state law,
treaty or contract, including but not limited to moral rights,
publicity and privacy rights, rights protecting against unfair
competition and any rights protecting the extraction, dissemination
and reuse of data, whether such rights are present or future, vested
or contingent (the "Waiver"). The Affirmer makes the Waiver for the
benefit of the public at large and to the detriment of the Affirmer's
heirs or successors.
The Affirmer understands and intends that the Waiver has the effect
of eliminating and entirely removing from the Affirmer's control all
the copyright and related or neighboring legal rights previously held
by the Affirmer in the Work, to that extent making the Work freely
available to the public for any and all uses and purposes without
restriction of any kind, including commercial use and uses in media
and formats or by methods that have not yet been invented or
conceived. Should the Waiver for any reason be judged legally
ineffective in any jurisdiction, the Affirmer hereby grants a free,
full, permanent, irrevocable, nonexclusive and worldwide license for
all her or his copyright and related or neighboring legal rights in
the Work.

30
resources/ahem/README Normal file
View File

@@ -0,0 +1,30 @@
The Ahem font was developed by Todd Fahrner to help test writers
develop predictable tests. The font's em square is exactly square.
Its ascent and descent is exactly the size of the em square. This
means that the font's extent is exactly the same as its line-height,
meaning that it can be exactly aligned with padding, borders, margins,
and so forth.
The font's alphabetic baseline is 0.2em above its bottom, and 0.8em
below its top. The font has an x-height of 0.8em.
The font has four glyphs:
'X' U+0058 A square exactly 1em in height and width.
'p' U+0070 A rectangle exactly 0.2em high, 1em wide, and aligned so
that its top is flush with the baseline.
'É' U+00C9 A rectangle exactly 0.8em high, 1em wide, and aligned so
that its bottom is flush with the baseline.
' ' U+0020 A transparent space exactly 1em high and wide.
Most other US-ASCII characters in the font have the same glyph as X.
The Ahem font belongs to the public domain as described in COPYING.
Acknowledgements: The font was originally created by Todd Fahrner in
the late 90s, and was updated by Paul Nelson in the mid 2000s. The
changes were the introduction of x-height information to the OS/2
table and the addition of the space and non-breaking space glyphs.

9
resources/android_params Normal file
View File

@@ -0,0 +1,9 @@
# The first line here should be the "servo" argument (without quotes) and the
# last should be the URL to load.
# Blank lines and those beginning with a '#' are ignored.
# Each line should be a separate parameter as would be parsed by the shell.
# For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4
# lines (the "-p" and "10" are separate even though they are related).
servo
http://en.wikipedia.org/wiki/Rust

28
resources/badcert.html Normal file
View File

@@ -0,0 +1,28 @@
<html>
<head>
<title>Certificate error</title>
</head>
<body>
<p>${reason}</p>
<button id="leave" onclick="history.back()">Go back (recommended)</button>
<button id="allow">Allow certificate temporarily</button>
<div style="word-break: break-all; font-family: monospace" id="bytes">${bytes}</div>
<script>
let bytes = document.getElementById('bytes').textContent;
let button = document.getElementById('allow');
let exitButton = document.getElementById('leave');
if (bytes.length) {
button.onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('POST', 'chrome:allowcert');
xhr.onloadend = function() {
location.reload(true);
};
xhr.send("${secret}&${bytes}");
};
} else {
button.style.display = "none";
}
</script>
</body>
</html>

BIN
resources/badcert.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----

20
resources/cert-wpt-only Normal file
View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIDC3+YMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
Yi1wbGF0Zm9ybS10ZXN0czAeFw0xODA3MTMxMjU5MTJaFw0yODA3MTAxMjU5MTJa
MB0xGzAZBgNVBAMMEndlYi1wbGF0Zm9ybS10ZXN0czCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBANOUELdwzxsrHn9sIk8VvsmVA0XifCZ40ls8tTyGrKu6
6cEokYOnKJImeQDCvebvu2vX+i45+hbI5SSObumxFYOrmFaZQklNXRY6KP5NLika
PHh4CapzJmLCpSxIkmUScH4/fsfE6grIYO9qsGXc2hAxyYg6VjX9hb0RpFF9f3Ff
FjhkBnglOxXhphkve/+SEa0OYBrUYY5GRQCbe8YfWw67nWz9eimWgiU91RmAtzBu
YSofy1DcrPT/SwJnYFgEF7Zpk5PIkvigXvFW/egkIb30vtTuH99u001VG1jEZpuT
trIQ6A77a5BP+V+ZWAqqjV85M3WDQUVxUwvwgXXcc20CAwEAAaOBmzCBmDAMBgNV
HRMEBTADAQH/MB0GA1UdDgQWBBRb2sjBCfNNkjC870P7JpMerg2aDzBHBgNVHSME
QDA+gBRb2sjBCfNNkjC870P7JpMerg2aD6EhpB8wHTEbMBkGA1UEAwwSd2ViLXBs
YXRmb3JtLXRlc3RzggMLf5gwCwYDVR0PBAQDAgIEMBMGA1UdJQQMMAoGCCsGAQUF
BwMBMA0GCSqGSIb3DQEBCwUAA4IBAQCX4/C5Ywfl3tkff96++OSY1iWX6dOtfG0w
fQ2OxZvv66jFWbIscwhGIqv3YQEZngAMcrwqvYYRHz2AqhlYb80Ftlon/y45GkQI
ouim4iwDUi9jazo7k8a4U8307GNcJFplpOOTnpbwAM+C/NwoGIbxon54gJ/0EbGO
yBC1GJ39norLbY4VIjsfDXlTvSv30AkqpqnxPkzQqoGuKzSwUhbQeOIlweKSRxsv
pqIpb4eaPF1EsI+VPOet0YMcOLc9hSu43EWBunGnHJabwTg+qabHOHFNN27KuOir
zAdOIUOIIcBJEZ7WxBMsV3UdjlQfY5pGGVJAxR4sONK4YkOlhMjk
-----END CERTIFICATE-----

8
resources/crash.html Normal file
View File

@@ -0,0 +1,8 @@
<p>Servo crashed!</p>
<!-- NOTE: unlike in Firefox and Chrome, this reloads POST as GET -->
<!-- see whatwg/html#6600 + whatwg/html#3215 -->
<button onclick="location.reload()">Reload</button>
<pre><plaintext>
${details}

View File

@@ -0,0 +1,62 @@
# Source:
# https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
# License:
# https://github.com/WebBluetoothCG/registries/blob/master/LICENSE
# This file holds a list of GATT UUIDs that websites using the Web
# Bluetooth API are forbidden from accessing.
## Services
# org.bluetooth.service.human_interface_device
# Direct access to HID devices like keyboards would let web pages
# become keyloggers.
00001812-0000-1000-8000-00805f9b34fb
# Firmware update services that don't check the update's signature
# present a risk of devices' software being modified by malicious web
# pages. Users may connect to a device believing they are enabling
# only simple interaction or that they're interacting with the
# device's manufacturer, but the site might instead persistently
# compromise the device.
#
# Nordic's Device Firmware Update service, http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/examples_ble_dfu.html:
00001530-1212-efde-1523-785feabcd123
# TI's Over-the-Air Download service, http://www.ti.com/lit/ug/swru271g/swru271g.pdf:
f000ffc0-0451-4000-b000-000000000000
## Characteristics
# org.bluetooth.characteristic.gap.peripheral_privacy_flag
# Don't let web pages turn off privacy mode.
00002a02-0000-1000-8000-00805f9b34fb exclude-writes
# org.bluetooth.characteristic.gap.reconnection_address
# Disallow messing with connection parameters
00002a03-0000-1000-8000-00805f9b34fb
# org.bluetooth.characteristic.serial_number_string
# Block access to standardized unique identifiers, for privacy reasons.
00002a25-0000-1000-8000-00805f9b34fb
# Blocklisted characteristic used to test readValue function.
bad1c9a2-9a5b-4015-8b60-1579bbbf2135 exclude-reads
## Descriptors
# org.bluetooth.descriptor.gatt.client_characteristic_configuration
# Writing to this would let a web page interfere with other pages'
# notifications and indications.
00002902-0000-1000-8000-00805f9b34fb exclude-writes
# org.bluetooth.descriptor.gatt.server_characteristic_configuration
# Writing to this would let a web page interfere with the broadcasted services.
00002903-0000-1000-8000-00805f9b34fb exclude-writes
# Blocklisted descriptor used to test.
07711111-6104-0970-7011-1107105110aa
# Blocklisted descriptor used to test.
aaaaaaaa-aaaa-1181-0510-810819516110 exclude-reads

372832
resources/hsts_preload.json Normal file

File diff suppressed because it is too large Load Diff

23
resources/iso-8859-8.css Normal file
View File

@@ -0,0 +1,23 @@
/*
https://html.spec.whatwg.org/multipage/#bidi-rendering
> When the document's character encoding is ISO-8859-8,
> the following rules are additionally expected to apply, following [user-agent.css]
*/
@namespace url(http://www.w3.org/1999/xhtml);
address, blockquote, center, div, figure, figcaption, footer, form, header, hr,
legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2,
h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead,
tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, [dir=ltr i],
[dir=rtl i], [dir=auto i], *|* {
unicode-bidi: bidi-override;
}
input:not([type=submit i]):not([type=reset i]):not([type=button i]),
textarea {
unicode-bidi: normal;
}

View File

@@ -0,0 +1,61 @@
button {
display: inline-block;
width: 24px;
height: 24px;
min-width: var(--button-size);
min-height: var(--button-size);
padding: 6px;
border: 0;
margin: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
}
.root {
display: block;
position: relative;
min-height: 40px;
min-width: 230px;
}
.controls {
position: absolute;
bottom: 0;
width: 100%;
height: 40px;
background-color: rgba(26,26,26,.8);
color: #ffffff;
}
.hidden {
display: none;
}
.playing {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAALElEQVR4AWMYQeD///8KQOwAxQq4xQkb1PAfARpwiQ9Kg0YNGjWI8iwycgAA8BVdyMCA4SwAAAAASUVORK5CYII=") no-repeat;
}
.paused {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAATklEQVR4AWMYgeD///8C1DLoARA7UG4QAqynyHX/UcF7II6n3CAE2A/ECpQbhHBdPTUM+gDEDZQadIB8ryFckUBpYG8ARf/AJ0i4K0YBAOu3zFnxHnpDAAAAAElFTkSuQmCC") no-repeat;
}
.ended {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAArElEQVR4AbWRIQ7CQBBFR7QBhcYRFKISVwQcgfsgmiDq8S22BgkGAxwBJBp0BSEkhOaxYs2wW6jhjZn8eeqPfEJbfkHItoECDRRgQq9eSrBQsWLgl1rsAJgyo+TG6IsmBrocudKp1ew25MVcNG5PHDjr05i+oy946qCkcKSCUgdrLgQqCUyy0VIMJE5rsWjIqUgJbfcpFUvfUzLgzsnMA8gIxQcROXszOZH8hTfry4rnukG7bgAAAABJRU5ErkJggg==") no-repeat;
}
.volumeup {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAAi0lEQVR4AWOgNfh/4n/Yfybc0g1gcs////8P/RfCoeT/fyjL9v+H/1f+c2NTAgRwnun/v/+nYCoBAzB7yX9GILni/8//IjBpFAAVyQKSLkA6BJ+i3UBSDEiX4lO0C6qoDJ+iTCDpCqRDCTl8JdDhooSDYDL+wLT7/xEYmDz4omU3ZrRgKj0NjmCqAwANy7W0uf6FTQAAAABJRU5ErkJggg==") no-repeat;
}
.muted {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAAy0lEQVR4AayRtUICUBRA7a7Jye5RF7u+wM4vsF2s0e7O37BzkZqZ+AF2WGk4XLqZeO/dPq/TUtuoZSki7mIgFloFlv3+icgOoKE8GlsH1sVOgOgy9jGjpzIuRjqv/rgNI3/hQCuD0t+8WK7Eywx6NfSGIAX+5t90CwOF5ODgNj4EO2TzxbDkdXwlgmCdLOolr+UlEbTn37QAK0fRBz8BAImvEYwMnmiJfdRzHxTAYoAQJjqPWWxJMf+3vHEAzCf+8A4avXYR9xSpm5QAaOvUDhZuhCsAAAAASUVORK5CYII=") no-repeat;
}
.fullscreen {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAa1JREFUSA3Vlj1Ow0AQhW1OAFUaKmoqOEAklCIlJQ3nyBFyBahc0IAEEnUUunQWVLiloqEKNzDfmJ2V7Z1JlpKRRrt+82bezq7/yrZtH4qiOMUt2wJelWX5aQXJnYDf4UdWHOyjgFTjlm0Bz53ECAsHF65lzUFkDiffXM5Y+esQTq8CZ0ZEchLzBF5gviVsBwgiz2aYvrwtuiFWmkkjEN7S2h+wpn8Gso/ViLhXBP64+COYnkkUiAdqJLgiHhdcD74TWAnQ79pL/AsniGxki+ReTswQmSuJ2BTvm9klhGPNMUcIur+LMYHYIiiYxcd895oiUy9IbI5n3WlejX+OS/uyDV4bxNzt83IiHorfMortOuRlTLImJCe3EpisXIsz7Syulis53L6ZIhAm8hxs8PigMbeKDwpkcuRpXolAg3evipxE3YVdXGL6qqhVAKwTeZJJzwYr1+I6wrO6rcD1ZTcQ6NXtpjuL7xHRWq5ApQVyRqpJJ+PuRaT2vmiXBOPBZ4icwbmweJ7AIeR1jkjgrOFLTmLSmvy2nCSRX0B+W6755n5ZcXLlGbrHvd+W9x/rQiZUwmH0RgAAAABJRU5ErkJggg==') no-repeat;
}
.fullscreen.fullscreen-active {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAbtJREFUSA3tlj0vBFEUhnd8hFhrE4mPbSREovIfdFQ6hcJ/EJVColP6GRoqhZbEFqKmET2xDSpWYjxncu915u6ZzWS20DjJ6577no/3zL1mqNWwNE1HwKb4g5rrdcjayHo54oxVbG8QAepl0FNphLVBQ6bflZ2ySiLU6+a+3bY/Hq/qA0EEog4m4ieDmwOzwrNazUOPwgQKpfkVWDAEVuHvQAsUDhjqSLKmeIQXKxKQ2Jv8UPY7eejuHJIsEantJ6B6l/glIXsKvOgq/DICT+Rld6IHH9IbEursz8GM5kv68+RdxiKJLibYYr+sOeffJknyqXlyZbhJzTn/g9yuwf9Tf3QC8SUPM8eoMUuXi/vWPJcsuSuac36H3I7BZ98UeQduQGwbcQEJ03ES+3vQ8y7kakkQkQegrYzAKwXyLuQs96K5yDrrYi6r3KZJ2jEicnS2EdwCX8Dbu3P6PcGzT3brCWuvCGTc/BpOPsVyJ0UC2ZkT3wfa8iJErObZZ4BYEyzFzww3DsKF4tsiBNaAPhaZ3PrGxBo9e0PkQP6ajYELIFa5uVejh3+SNn74z0JEjkClyX1zv9Jnxzf/AaCJ561FockLAAAAAElFTkSuQmCC') no-repeat;
}

416
resources/media-controls.js Normal file
View File

@@ -0,0 +1,416 @@
/* 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/. */
(() => {
"use strict";
// States.
const BUFFERING = "buffering";
const ENDED = "ended";
const ERRORED = "errored";
const PAUSED = "paused";
const PLAYING = "playing";
// State transitions.
const TRANSITIONS = {
buffer: {
paused: BUFFERING
},
end: {
playing: ENDED,
paused: ENDED
},
error: {
buffering: ERRORED,
playing: ERRORED,
paused: ERRORED
},
pause: {
buffering: PAUSED,
playing: PAUSED
},
play: {
buffering: PLAYING,
ended: PLAYING,
paused: PLAYING
}
};
function generateMarkup(isAudioOnly) {
return `
<div class="controls">
<button id="play-pause-button"></button>
<input id="progress" type="range" value="0" min="0" max="100" step="1"></input>
<span id="position-duration-box" class="hidden">
<span id="position-text">#1</span>
<span id="duration"> / #2</span>
</span>
<button id="volume-switch"></button>
<input id="volume-level" type="range" value="100" min="0" max="100" step="1"></input>
${isAudioOnly ? "" : '<button id="fullscreen-switch" class="fullscreen"></button>'}
</div>
`;
}
function camelCase(str) {
const rdashes = /-(.)/g;
return str.replace(rdashes, (str, p1) => {
return p1.toUpperCase();
});
}
function formatTime(time, showHours = false) {
// Format the duration as "h:mm:ss" or "m:ss"
time = Math.round(time / 1000);
const hours = Math.floor(time / 3600);
const mins = Math.floor((time % 3600) / 60);
const secs = Math.floor(time % 60);
const formattedHours =
hours || showHours ? `${hours.toString().padStart(2, "0")}:` : "";
return `${formattedHours}${mins
.toString()
.padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
}
class MediaControls {
constructor() {
this.nonce = Date.now();
// Get the instance of the shadow root where these controls live.
this.controls = document.servoGetMediaControls("@@@id@@@");
// Get the instance of the host of these controls.
this.media = this.controls.host;
this.mutationObserver = new MutationObserver(() => {
// We can only get here if the `controls` attribute is removed.
this.cleanup();
});
this.mutationObserver.observe(this.media, {
attributeFilter: ["controls"]
});
this.isAudioOnly = this.media.localName == "audio";
// Create root element and load markup.
this.root = document.createElement("div");
this.root.classList.add("root");
this.root.innerHTML = generateMarkup(this.isAudioOnly);
this.controls.appendChild(this.root);
const elementNames = [
"duration",
"play-pause-button",
"position-duration-box",
"position-text",
"progress",
"volume-switch",
"volume-level"
];
if (!this.isAudioOnly) {
elementNames.push("fullscreen-switch");
}
// Import elements.
this.elements = {};
elementNames.forEach(id => {
this.elements[camelCase(id)] = this.controls.getElementById(id);
});
// Init position duration box.
const positionTextNode = this.elements.positionText;
const durationSpan = this.elements.duration;
const durationFormat = durationSpan.textContent;
const positionFormat = positionTextNode.textContent;
durationSpan.classList.add("duration");
durationSpan.setAttribute("role", "none");
Object.defineProperties(this.elements.positionDurationBox, {
durationSpan: {
value: durationSpan
},
position: {
get: () => {
return positionTextNode.textContent;
},
set: v => {
positionTextNode.textContent = positionFormat.replace("#1", v);
}
},
duration: {
get: () => {
return durationSpan.textContent;
},
set: v => {
durationSpan.textContent = v ? durationFormat.replace("#2", v) : "";
}
},
show: {
value: (currentTime, duration) => {
const self = this.elements.positionDurationBox;
if (self.position != currentTime) {
self.position = currentTime;
}
if (self.duration != duration) {
self.duration = duration;
}
self.classList.remove("hidden");
}
}
});
// Add event listeners.
this.mediaEvents = [
"play",
"pause",
"ended",
"volumechange",
"loadeddata",
"loadstart",
"timeupdate",
"progress",
"playing",
"waiting",
"canplay",
"canplaythrough",
"seeking",
"seeked",
"emptied",
"loadedmetadata",
"error",
"suspend"
];
this.mediaEvents.forEach(event => {
this.media.addEventListener(event, this);
});
this.controlEvents = [
{ el: this.elements.playPauseButton, type: "click" },
{ el: this.elements.volumeSwitch, type: "click" },
{ el: this.elements.volumeLevel, type: "input" }
];
if (!this.isAudioOnly) {
this.controlEvents.push({ el: this.elements.fullscreenSwitch, type: "click" });
}
this.controlEvents.forEach(({ el, type }) => {
el.addEventListener(type, this);
});
// Create state transitions.
//
// It exposes one method per transition. i.e. this.pause(), this.play(), etc.
// For each transition, we check that the transition is possible and call
// the `onStateChange` handler.
for (let name in TRANSITIONS) {
if (!TRANSITIONS.hasOwnProperty(name)) {
continue;
}
this[name] = () => {
const from = this.state;
// Checks if the transition is valid in the current state.
if (!TRANSITIONS[name][from]) {
const error = `Transition "${name}" invalid for the current state "${from}"`;
console.error(error);
throw new Error(error);
}
const to = TRANSITIONS[name][from];
if (from == to) {
return;
}
// Transition to the next state.
this.state = to;
this.onStateChange(from);
};
}
// Set initial state.
this.state = this.media.paused ? PAUSED : PLAYING;
this.onStateChange(null);
}
cleanup() {
this.mutationObserver.disconnect();
this.mediaEvents.forEach(event => {
this.media.removeEventListener(event, this);
});
this.controlEvents.forEach(({ el, type }) => {
el.removeEventListener(type, this);
});
}
// State change handler
onStateChange(from) {
this.render(from);
}
render(from = this.state) {
if (!this.isAudioOnly) {
// XXX This should ideally use clientHeight/clientWidth,
// but for some reason I couldn't figure out yet,
// using it breaks layout.
this.root.style.height = this.media.videoHeight;
this.root.style.width = this.media.videoWidth;
}
// Error
if (this.state == ERRORED) {
//XXX render errored state
return;
}
if (this.state != from) {
// Play/Pause button.
const playPauseButton = this.elements.playPauseButton;
playPauseButton.classList.remove(from);
playPauseButton.classList.add(this.state);
}
// Progress.
const positionPercent =
(this.media.currentTime / this.media.duration) * 100;
if (Number.isFinite(positionPercent)) {
this.elements.progress.value = positionPercent;
} else {
this.elements.progress.value = 0;
}
// Current time and duration.
let currentTime = formatTime(0);
let duration = formatTime(0);
if (!isNaN(this.media.currentTime) && !isNaN(this.media.duration)) {
currentTime = formatTime(Math.round(this.media.currentTime * 1000));
duration = formatTime(Math.round(this.media.duration * 1000));
}
this.elements.positionDurationBox.show(currentTime, duration);
// Volume.
this.elements.volumeSwitch.className =
this.media.muted || !this.media.volume ? "muted" : "volumeup";
const volumeLevelValue = this.media.muted
? 0
: Math.round(this.media.volume * 100);
if (this.elements.volumeLevel.value != volumeLevelValue) {
this.elements.volumeLevel.value = volumeLevelValue;
}
}
handleEvent(event) {
if (!event.isTrusted) {
console.warn(`Drop untrusted event ${event.type}`);
return;
}
if (this.mediaEvents.includes(event.type)) {
this.onMediaEvent(event);
} else {
this.onControlEvent(event);
}
}
onControlEvent(event) {
switch (event.type) {
case "click":
switch (event.currentTarget) {
case this.elements.playPauseButton:
this.playOrPause();
break;
case this.elements.volumeSwitch:
this.toggleMuted();
break;
case this.elements.fullscreenSwitch:
this.toggleFullscreen();
break;
}
break;
case "input":
switch (event.currentTarget) {
case this.elements.volumeLevel:
this.changeVolume();
break;
}
break;
default:
throw new Error(`Unknown event ${event.type}`);
}
}
// HTMLMediaElement event handler
onMediaEvent(event) {
switch (event.type) {
case "ended":
this.end();
break;
case "play":
case "pause":
// Transition to PLAYING or PAUSED state.
this[event.type]();
break;
case "volumechange":
case "timeupdate":
case "resize":
this.render();
break;
case "loadedmetadata":
break;
}
}
/* Media actions */
playOrPause() {
switch (this.state) {
case PLAYING:
this.media.pause();
break;
case BUFFERING:
case ENDED:
case PAUSED:
this.media.play();
break;
default:
throw new Error(`Invalid state ${this.state}`);
}
}
toggleMuted() {
this.media.muted = !this.media.muted;
}
toggleFullscreen() {
const { fullscreenEnabled, fullscreenElement } = document;
const isElementFullscreen = fullscreenElement && fullscreenElement === this.media;
if (fullscreenEnabled && isElementFullscreen) {
document.exitFullscreen().then(() => {
this.elements.fullscreenSwitch.classList.remove("fullscreen-active");
});
} else {
this.media.requestFullscreen().then(() => {
this.elements.fullscreenSwitch.classList.add("fullscreen-active");
});
}
}
changeVolume() {
const volume = parseInt(this.elements.volumeLevel.value);
if (!isNaN(volume)) {
this.media.volume = volume / 100;
}
}
}
new MediaControls();
})();

8
resources/neterror.html Normal file
View File

@@ -0,0 +1,8 @@
<html>
<head>
<title>Error loading page</title>
</head>
<body>
<p>Could not load the requested page: ${reason}</p>
</body>
</html>

9
resources/not-found.html Normal file
View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>about:not-found</title>
</head>
<body>
<!-- courtesy of https://mozillians.org/blahblah -->
<img src="tumbeast.png">
</body>
</html>

View File

@@ -0,0 +1,13 @@
{
"_comment": "this file is used to add some specific preferences to the Servo package (nightly builds)",
"all": {},
"macosx": {},
"linux": {},
"android": {},
"windows": {},
"vr": {
"_comment": "settings specific to VR builds",
"dom.webvr.enabled": true,
"dom.webxr.enabled": true
}
}

122
resources/prefs.json Normal file
View File

@@ -0,0 +1,122 @@
{
"devtools.server.enabled": false,
"devtools.server.port": 0,
"dom.bluetooth.enabled": false,
"dom.bluetooth.testing.enabled": false,
"dom.canvas_capture.enabled": false,
"dom.canvas_text.enabled": true,
"dom.compositionevent.enabled": false,
"dom.customelements.enabled": true,
"dom.document.dblclick_dist": 1,
"dom.document.dblclick_timeout": 300,
"dom.forcetouch.enabled": false,
"dom.fullscreen.test": false,
"dom.gamepad.enabled": false,
"dom.imagebitmap.enabled": false,
"dom.microdata.enabled": false,
"dom.microdata.testing.enabled": false,
"dom.mouseevent.which.enabled": false,
"dom.mutation_observer.enabled": true,
"dom.offscreen_canvas.enabled": false,
"dom.permissions.enabled": false,
"dom.permissions.testing.allowed_in_nonsecure_contexts": false,
"dom.script.asynch": true,
"dom.serviceworker.enabled": false,
"dom.serviceworker.timeout_seconds": 60,
"dom.servo_helpers.enabled": false,
"dom.servoparser.async_html_tokenizer.enabled": false,
"dom.shadowdom.enabled": false,
"dom.svg.enabled": false,
"dom.testable_crash.enabled": false,
"dom.testbinding.enabled": false,
"dom.testing.htmlinputelement.select_files.enabled": false,
"dom.webgl2.enabled": false,
"dom.webgpu.enabled": false,
"dom.webrtc.enabled": false,
"dom.webrtc.transceiver.enabled": false,
"dom.webvr.enabled": false,
"dom.webvr.event_polling_interval": 500,
"dom.webvr.test": false,
"dom.webvtt.enabled": false,
"dom.webxr.enabled": true,
"dom.webxr.first_person_observer_view": false,
"dom.webxr.glwindow.cubemap": false,
"dom.webxr.glwindow.enabled": true,
"dom.webxr.glwindow.left-right": false,
"dom.webxr.glwindow.red-cyan": false,
"dom.webxr.glwindow.spherical": false,
"dom.webxr.hands.enabled": false,
"dom.webxr.layers.enabled": false,
"dom.webxr.sessionavailable": false,
"dom.webxr.test": false,
"dom.webxr.unsafe-assume-user-intent": false,
"dom.worklet.timeout_ms": 10,
"gfx.subpixel-text-antialiasing.enabled": true,
"gfx.texture-swizzling.enabled": true,
"js.asmjs.enabled": true,
"js.asyncstack.enabled": false,
"js.baseline.enabled": true,
"js.baseline.unsafe_eager_compilation.enabled": false,
"js.discard_system_source.enabled": false,
"js.dump_stack_on_debuggee_would_run.enabled": false,
"js.ion.enabled": true,
"js.ion.offthread_compilation.enabled": true,
"js.ion.unsafe_eager_compilation.enabled": false,
"js.mem.gc.allocation_threshold_avoid_interrupt_factor": 100,
"js.mem.gc.allocation_threshold_factor": 100,
"js.mem.gc.allocation_threshold_mb": 30,
"js.mem.gc.compacting.enabled": true,
"js.mem.gc.decommit_threshold_mb": 32,
"js.mem.gc.dynamic_heap_growth.enabled": true,
"js.mem.gc.dynamic_mark_slice.enabled": true,
"js.mem.gc.empty_chunk_count_max": 30,
"js.mem.gc.empty_chunk_count_min": 1,
"js.mem.gc.high_frequency_heap_growth_max": 300,
"js.mem.gc.high_frequency_heap_growth_min": 150,
"js.mem.gc.high_frequency_high_limit_mb": 500,
"js.mem.gc.high_frequency_low_limit_mb": 100,
"js.mem.gc.high_frequency_time_limit_ms": 1000,
"js.mem.gc.incremental.enabled": true,
"js.mem.gc.incremental.slice_ms": 10,
"js.mem.gc.low_frequency_heap_growth": 150,
"js.mem.gc.per_zone.enabled": false,
"js.mem.gc.zeal.frequency": 100,
"js.mem.gc.zeal.level": 0,
"js.mem.max": -1,
"js.native_regex.enabled": true,
"js.offthread_compilation.enabled": true,
"js.parallel_parsing.enabled": true,
"js.shared_memory.enabled": true,
"js.strict.debug.enabled": false,
"js.strict.enabled": false,
"js.throw_on_asmjs_validation_failure.enabled": false,
"js.throw_on_debuggee_would_run.enabled": false,
"js.timers.minimum_duration": 1000,
"js.wasm.baseline.enabled": true,
"js.wasm.enabled": true,
"js.wasm.ion.enabled": true,
"js.werror.enabled": false,
"layout.animations.test.enabled": false,
"layout.columns.enabled": false,
"layout.flexbox.enabled": false,
"layout.legacy_layout": false,
"layout.tables.enabled": false,
"layout.threads": 3,
"layout.writing-mode.enabled": false,
"media.glvideo.enabled": false,
"media.testing.enabled": false,
"network.enforce_tls.enabled": false,
"network.enforce_tls.localhost": false,
"network.enforce_tls.onion": false,
"network.http-cache.disabled": false,
"network.mime.sniff": false,
"session-history.max-length": 20,
"shell.background-color.rgba": [1.0, 1.0, 1.0, 1.0],
"shell.crash_reporter.enabled": false,
"shell.homepage": "https://servo.org",
"shell.keep_screen_on.enabled": false,
"shell.native-orientation": "both",
"shell.native-titlebar.enabled": true,
"shell.searchpage": "https://duckduckgo.com/html/?q=%s",
"webgl.testing.context_creation_error": false
}

View File

@@ -0,0 +1,267 @@
/*
https://html.spec.whatwg.org/multipage/#presentational-hints
*/
@namespace url(http://www.w3.org/1999/xhtml);
pre[wrap] { white-space: pre-wrap; }
div[align=left i] { text-align: -servo-left; }
div[align=right i] { text-align: -servo-right; }
div[align=center i], div[align=middle i] { text-align: -servo-center; }
div[align=justify i] { text-align: justify; }
br[clear=left i] { clear: left; }
br[clear=right i] { clear: right; }
br[clear=all i], br[clear=both i] { clear: both; }
ol[type="1"], li[type="1"] { list-style-type: decimal; }
ol[type=a s], li[type=a s] { list-style-type: lower-alpha; }
ol[type=A s], li[type=A s] { list-style-type: upper-alpha; }
ol[type=i s], li[type=i s] { list-style-type: lower-roman; }
ol[type=I s], li[type=I s] { list-style-type: upper-roman; }
ul[type=none i], li[type=none i] { list-style-type: none; }
ul[type=disc i], li[type=disc i] { list-style-type: disc; }
ul[type=circle i], li[type=circle i] { list-style-type: circle; }
ul[type=square i], li[type=square i] { list-style-type: square; }
table[align=left i] { float: left; }
table[align=right i] { float: right; }
table[align=center i] { margin-left: auto; margin-right: auto; }
:matches(thead, tbody, tfoot, tr, td, th)[align=absmiddle i] {
text-align: center;
}
caption[align=bottom i] { caption-side: bottom; }
p[align=left i], h1[align=left i], h2[align=left i], h3[align=left i], h4[align=left i], h5[align=left i], h6[align=left i] { text-align: left; }
p[align=right i], h1[align=right i], h2[align=right i], h3[align=right i], h4[align=right i], h5[align=right i], h6[align=right i] { text-align: right; }
p[align=center i], h1[align=center i], h2[align=center i], h3[align=center i], h4[align=center i], h5[align=center i], h6[align=center i] { text-align: center; }
p[align=justify i], h1[align=justify i], h2[align=justify i], h3[align=justify i], h4[align=justify i], h5[align=justify i], h6[align=justify i] { text-align: justify; }
thead[valign=top i], tbody[valign=top i], tfoot[valign=top i], tr[valign=top i], td[valign=top i], th[valign=top i] { vertical-align: top; }
thead[valign=middle i], tbody[valign=middle i], tfoot[valign=middle i], tr[valign=middle i], td[valign=middle i], th[valign=middle i] { vertical-align: middle; }
thead[valign=bottom i], tbody[valign=bottom i], tfoot[valign=bottom i], tr[valign=bottom i], td[valign=bottom i], th[valign=bottom i] { vertical-align: bottom; }
thead[valign=baseline i], tbody[valign=baseline i], tfoot[valign=baseline i], tr[valign=baseline i], td[valign=baseline i], th[valign=baseline i] { vertical-align: baseline; }
td[nowrap], th[nowrap] { white-space: nowrap; }
table[rules=none i], table[rules=groups i], table[rules=rows i], table[rules=cols i], table[rules=all i] {
border-style: hidden;
border-collapse: collapse;
}
table:-servo-nonzero-border {
border-style: outset;
}
table[frame=void i] { border-style: hidden; }
table[frame=above i] { border-style: outset hidden hidden hidden; }
table[frame=below i] { border-style: hidden hidden outset hidden; }
table[frame=hsides i] { border-style: outset hidden outset hidden; }
table[frame=lhs i] { border-style: hidden hidden hidden outset; }
table[frame=rhs i] { border-style: hidden outset hidden hidden; }
table[frame=vsides i] { border-style: hidden outset; }
table[frame=box i], table[frame=border i] { border-style: outset; }
table:-servo-nonzero-border > tr > td,
table:-servo-nonzero-border > tr > th,
table:-servo-nonzero-border > thead > tr > td,
table:-servo-nonzero-border > thead > tr > th,
table:-servo-nonzero-border > tbody > tr > td,
table:-servo-nonzero-border > tbody > tr > th,
table:-servo-nonzero-border > tfoot > tr > td,
table:-servo-nonzero-border > tfoot > tr > th {
border-width: 1px;
border-style: inset;
}
table[rules=none i] > tr > td, table[rules=groups i] > tr > td, table[rules=rows i] > tr > td, table[rules=none i] > tr > th, table[rules=groups i] > tr > th, table[rules=rows i] > tr > th,
table[rules=none i] > thead > tr > td, table[rules=groups i] > thead > tr > td, table[rules=rows i] > thead > tr > td, table[rules=none i] > thead > tr > th, table[rules=groups i] > thead > tr > th, table[rules=rows i] > thead > tr > th,
table[rules=none i] > tbody > tr > td, table[rules=groups i] > tbody > tr > td, table[rules=rows i] > tbody > tr > td, table[rules=none i] > tbody > tr > th, table[rules=groups i] > tbody > tr > th, table[rules=rows i] > tbody > tr > th,
table[rules=none i] > tfoot > tr > td, table[rules=groups i] > tfoot > tr > td, table[rules=rows i] > tfoot > tr > td, table[rules=none i] > tfoot > tr > th, table[rules=groups i] > tfoot > tr > th, table[rules=rows i] > tfoot > tr > th {
border-width: 1px;
border-style: none;
}
table[rules=cols i] > tr > td, table[rules=cols i] > tr > th,
table[rules=cols i] > thead > tr > td, table[rules=cols i] > thead > tr > th,
table[rules=cols i] > tbody > tr > td, table[rules=cols i] > tbody > tr > th,
table[rules=cols i] > tfoot > tr > td, table[rules=cols i] > tfoot > tr > th {
border-width: 1px;
border-style: none solid;
}
table[rules=all i] > tr > td, table[rules=all i] > tr > th,
table[rules=all i] > thead > tr > td, table[rules=all i] > thead > tr > th,
table[rules=all i] > tbody > tr > td, table[rules=all i] > tbody > tr > th,
table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th {
border-width: 1px;
border-style: solid;
}
table[rules=groups i] > colgroup {
border-left-width: 1px;
border-left-style: solid;
border-right-width: 1px;
border-right-style: solid;
}
table[rules=groups i] > tr,
table[rules=groups i] > thead > tr,
table[rules=groups i] > tbody > tr,
table[rules=groups i] > tfoot > tr {
border-top-width: 1px;
border-top-style: solid;
border-bottom-width: 1px;
border-bottom-style: solid;
}
table[rules=rows i] > tr,
table[rules=rows i] > thead > tr,
table[rules=rows i] > tbody > tr,
table[rules=rows i] > tfoot > tr {
border-top-width: 1px;
border-top-style: solid;
border-bottom-width: 1px;
border-bottom-style: solid;
}
hr[align=left] { margin-left: 0; margin-right: auto; }
hr[align=right] { margin-left: auto; margin-right: 0; }
hr[align=center] { margin-left: auto; margin-right: auto; }
hr[color], hr[noshade] { border-style: solid; }
iframe[frameborder="0"], iframe[frameborder=no i] { border: none; }
embed[align=left i], iframe[align=left i], img[type=image i][align=left i], object[align=left i] {
float: left;
}
embed[align=right i], iframe[align=right i], img[type=image i][align=right i], object[align=right i] {
float: right;
}
embed[align=top i], iframe[align=top i], img[type=image i][align=top i], object[align=top i] {
vertical-align: top;
}
embed[align=baseline i], iframe[align=baseline i], img[type=image i][align=baseline i], object[align=baseline i] {
vertical-align: baseline;
}
embed[align=texttop i], iframe[align=texttop i], img[type=image i][align=texttop i], object[align=texttop i] {
vertical-align: text-top;
}
embed[align=absmiddle i], iframe[align=absmiddle i], img[type=image i][align=absmiddle i], object[align=absmiddle i],
embed[align=abscenter i], iframe[align=abscenter i], img[type=image i][align=abscenter i], object[align=abscenter i] {
vertical-align: middle;
}
embed[align=bottom i], iframe[align=bottom i], img[type=image i][align=bottom i], object[align=bottom i] {
vertical-align: bottom;
}
/*
FIXME:
:matches(embed, iframe, img, input[type=image i], object):matches([align=center i], [align=middle i]) {
vertical-align: "aligns the vertical middle of the element with the parent element's baseline."
}
*/
/*
Presentational attributes which can not currently be expressed in CSS.
FIXME: Deal with them with attr(foo dimension) and the like?
body
marginheight
marginwidth
topmargin
rightmargin
bottommargin
leftmargin
background
bgcolor
text
link
vlink
alink
frame, iframe
marginheight
marginwidth
font
face
color
size
table
cellspacing
cellpadding
hspace
vspace
height
width
bordercolor
border
col
width
tr
height
td, th
width
height
caption, thead, tbody, tfoot, tr, td, and th
align
table, thead, tbody, tfoot, tr, td, or th
background
bgcolor
(quirks mode) th, td
nowrap
hr
color
noshade
size
width
legend
align
embed, iframe, img, input[type=image i], object
hspace
vspace
img, input[type=image i], object
border
embed, iframe, img, input[type=image i], object, video
width
height
*/
/*
Extra
ol > li
https://html.spec.whatwg.org/multipage/#ordinal-value
col
span
colgroup (if not col child)
span
td, th
colspan
rowspan
:computed-value(text-align is initial) > th {
text-align: center;
}
https://html.spec.whatwg.org/multipage/#rendered-legend
*/

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDwJhD2k5vROwKG
ZFbOVShnx0nubyUrPXTe2wnUcU6Pr32qguIOmHD+TttSFVmU5TVe0UlMUkbyRjGM
Lzguf/Eo0FoUKH2GbUpS07hGyxcqUQd+DzFWYY4hoLrWhd+ICPer7Y9OC/qiUOgv
vP7hjaBI//ODWzN0AZbB+SyBfRq0hbLyUIFtfxV42UEC8qQzQItq9eGNSaalvM8a
P8+XZu/4d1dll3u3qwdDoC7M9oEMCemHY+O6dnaJUu38+s41nyatSSKqDkZRFDvH
8TCE7+PQRARkN3qs57EeyeYKhSwXYpgzOC4P38DpD6u6jcETpQZvZJv2x4Z+slrW
48zO21vdAgMBAAECggEBAL8nLb14BUFoXTwoRkh61Gy23wxhgA6JHqv9Yjet8UDC
CZ9eCx5fDSIAFuehgurX/8F3iYasvzg901aoh2nMAWPhZLJDAJeuCskfKcGACvJu
CS64XSdLA92UmOQFL8aSjMJXmAgh1OC60fad06wqFXnF8kmOoMgoM542/swbjtQ9
RUoXUKa2x9ve2b0og4iuEj/iZR+d2/HYPNtpNIFt7+rA1qCd2RIfMSAB6j3ohFNA
AqVZdASgNznj5Sa8jz6zU40zdyLPIDYfCdi3Gmq42LaB4HWHiSpjx49aCQD6UV4+
NxFsYi9WRA79DxdoeWsYm017G5NrHsELCdqwxg46fEECgYEA+/AJsiIjoBJ0SGoe
Oqm86EbOtYtOEsMLF0Pk7OQejAN3VPqP6xN0u6unldo5RLJMsTlTHxIZuZNbXhw8
aKWz0ULoXWi5J8Af2NHI0zaY0naGv3yew+6mq9xpZLHsY9wBWtT2tXEziH7gjPvk
LmJ8+GCKSq9XLHoSyyjjqdr1aOUCgYEA9AVdhIFZ9EDb6zgnCjMvWlNFU/G2+WbU
jCc9GRTFbzsahbawjuJ+47Ajz5aTBWOA1HE4wcMMMEjRebP/15CiCQs34+BIQckW
2zvMipAh6dlbyx2O9t0gdIjAUNiYYMfuHYBQ3Nwmi6Nop3kHQuFHRh6uneGTxcEq
wq3IEhN9T5kCgYAnip8a9Dy/LOZPT0h7UJSzqBldaQXR8AbXmfJeM9ePhiO+lKzt
6lnR8rkUzfFbFNjwn9yp7b9X3wbiGHBqxEcauvOZZYxZ7s+QyixI6jLGJZA0kayh
d910790izsIZUjhsNyyZgbDi5Xb86bQAi7itiwlpe2elNWupszs4N4N4+QKBgQDQ
Le+dhtkeV2MHZm1v90Dzt0zTE8j9Nuwn8aXfSugxP+QdpUE1dSe5yeCTTit5km0r
ULiSHXu9ibIkORsQZdTHEGoLH6Gldg/o0zhqEhLMtWHpg/sewoHYyX4AuvgswQR0
6K6T7cF4qd0z2z4FobmzqaNhEDyInoaDdczVFwl2KQKBgQCHjZLwMZLg0be9i1IS
jzaG2d5CF3WJ+A1zYQLXqzpX5qfbgsEIbpTtdCOhgf94YJsiJ9XdIG8OgGVxhrkT
C41PGdIoq7wVxOwfW9qXQTOarO6ymFZxOnmHukpjfbcp54xDpcF73Xe6XkvmiESd
gcNMfunAcg8sNgIGJzsKJ50+hw==
-----END PRIVATE KEY-----

8818
resources/public_domains.txt Normal file

File diff suppressed because it is too large Load Diff

44
resources/quirks-mode.css Normal file
View File

@@ -0,0 +1,44 @@
/*
https://html.spec.whatwg.org/multipage/#flow-content-3
> In quirks mode, the following rules are also expected to apply:
*/
@namespace url(http://www.w3.org/1999/xhtml);
form { margin-bottom: 1em; }
table {
font-weight: initial;
font-style: initial;
font-variant: initial;
font-size: initial;
line-height: initial;
white-space: initial;
/* text-align: initial; -- see FIXME below */
}
/*
* FIXME(pcwalton): Actually saying `text-align: initial` above breaks `<table>` inside `<center>`
* in quirks mode. This is because we (following Gecko, WebKit, and Blink) implement the HTML5
* align-descendants rules with a special `text-align: -servo-center`. `text-align: initial`, if
* placed on the `<table>` element per the spec, would break this behavior. So we place it on
* `<tbody>` instead.
*/
tbody {
text-align: initial;
}
/* FIXME: https://html.spec.whatwg.org/multipage/#margin-collapsing-quirks */
input:not([type=image]), textarea { box-sizing: border-box; }
img[align=left i] { margin-right: 3px; }
img[align=right i] { margin-left: 3px; }

190
resources/quotes.css Normal file
View File

@@ -0,0 +1,190 @@
/*
https://html.spec.whatwg.org/multipage/#quotes
> This block is automatically generated from the Unicode Common Locale Data Repository.
> http://cldr.unicode.org/
>
> User agents are expected to use either the block [from the spec]
> (which will be regularly updated)
> or to automatically generate their own copy directly from the source material.
> The language codes are derived from the CLDR file names.
> The quotes are derived from the delimiter blocks,
> with fallback handled as specified in the CLDR documentation.
*/
@namespace url(http://www.w3.org/1999/xhtml);
:root { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(af), :not(:lang(af)) > :lang(af) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(agq), :not(:lang(agq)) > :lang(agq) { quotes: '\201e' '\201d' '\201a' '\2019' } /* „ ” */
:root:lang(ak), :not(:lang(ak)) > :lang(ak) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(am), :not(:lang(am)) > :lang(am) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(ar), :not(:lang(ar)) > :lang(ar) { quotes: '\201d' '\201c' '\2019' '\2018' } /* ” “ */
:root:lang(asa), :not(:lang(asa)) > :lang(asa) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ast), :not(:lang(ast)) > :lang(ast) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(az), :not(:lang(az)) > :lang(az) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(az-Cyrl), :not(:lang(az-Cyrl)) > :lang(az-Cyrl) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(bas), :not(:lang(bas)) > :lang(bas) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */
:root:lang(bem), :not(:lang(bem)) > :lang(bem) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(bez), :not(:lang(bez)) > :lang(bez) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(bg), :not(:lang(bg)) > :lang(bg) { quotes: '\201e' '\201c' '\201e' '\201c' } /* „ “ „ “ */
:root:lang(bm), :not(:lang(bm)) > :lang(bm) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(bn), :not(:lang(bn)) > :lang(bn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(br), :not(:lang(br)) > :lang(br) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(brx), :not(:lang(brx)) > :lang(brx) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(bs), :not(:lang(bs)) > :lang(bs) { quotes: '\201e' '\201c' '\2018' '\2019' } /* „ “ */
:root:lang(bs-Cyrl), :not(:lang(bs-Cyrl)) > :lang(bs-Cyrl) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(ca), :not(:lang(ca)) > :lang(ca) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(cgg), :not(:lang(cgg)) > :lang(cgg) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(chr), :not(:lang(chr)) > :lang(chr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(cs), :not(:lang(cs)) > :lang(cs) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(cy), :not(:lang(cy)) > :lang(cy) { quotes: '\2018' '\2019' '\201c' '\201d' } /* “ ” */
:root:lang(da), :not(:lang(da)) > :lang(da) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(dav), :not(:lang(dav)) > :lang(dav) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(de), :not(:lang(de)) > :lang(de) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(de-CH), :not(:lang(de-CH)) > :lang(de-CH) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(dje), :not(:lang(dje)) > :lang(dje) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(dsb), :not(:lang(dsb)) > :lang(dsb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(dua), :not(:lang(dua)) > :lang(dua) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » */
:root:lang(dyo), :not(:lang(dyo)) > :lang(dyo) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(dz), :not(:lang(dz)) > :lang(dz) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ebu), :not(:lang(ebu)) > :lang(ebu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ee), :not(:lang(ee)) > :lang(ee) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(el), :not(:lang(el)) > :lang(el) { quotes: '\00ab' '\00bb' '\0022' '\0022' } /* « » " " */
:root:lang(en), :not(:lang(en)) > :lang(en) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(es), :not(:lang(es)) > :lang(es) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(et), :not(:lang(et)) > :lang(et) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(eu), :not(:lang(eu)) > :lang(eu) { quotes: '\0022' '\0022' '\0022' '\0022' } /* " " " " */
:root:lang(ewo), :not(:lang(ewo)) > :lang(ewo) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(fa), :not(:lang(fa)) > :lang(fa) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(ff), :not(:lang(ff)) > :lang(ff) { quotes: '\201e' '\201d' '\201a' '\2019' } /* „ ” */
:root:lang(fi), :not(:lang(fi)) > :lang(fi) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” */
:root:lang(fil), :not(:lang(fil)) > :lang(fil) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(fr), :not(:lang(fr)) > :lang(fr) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */
:root:lang(fr-CA), :not(:lang(fr-CA)) > :lang(fr-CA) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(fr-CH), :not(:lang(fr-CH)) > :lang(fr-CH) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(ga), :not(:lang(ga)) > :lang(ga) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(gd), :not(:lang(gd)) > :lang(gd) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(gl), :not(:lang(gl)) > :lang(gl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(gsw), :not(:lang(gsw)) > :lang(gsw) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(gu), :not(:lang(gu)) > :lang(gu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(guz), :not(:lang(guz)) > :lang(guz) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ha), :not(:lang(ha)) > :lang(ha) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(he), :not(:lang(he)) > :lang(he) { quotes: '\05f4' '\05f4' '\05f3' '\05f3' } /* ״ ״ ׳ ׳ */
:root:lang(hi), :not(:lang(hi)) > :lang(hi) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(hr), :not(:lang(hr)) > :lang(hr) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(hsb), :not(:lang(hsb)) > :lang(hsb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(hu), :not(:lang(hu)) > :lang(hu) { quotes: '\201e' '\201d' '\00bb' '\00ab' } /* „ ” » « */
:root:lang(hy), :not(:lang(hy)) > :lang(hy) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */
:root:lang(id), :not(:lang(id)) > :lang(id) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ig), :not(:lang(ig)) > :lang(ig) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(is), :not(:lang(is)) > :lang(is) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(it), :not(:lang(it)) > :lang(it) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(ja), :not(:lang(ja)) > :lang(ja) { quotes: '\300c' '\300d' '\300e' '\300f' } /* 「 」 『 』 */
:root:lang(jgo), :not(:lang(jgo)) > :lang(jgo) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(jmc), :not(:lang(jmc)) > :lang(jmc) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ka), :not(:lang(ka)) > :lang(ka) { quotes: '\201e' '\201c' '\00ab' '\00bb' } /* „ “ « » */
:root:lang(kab), :not(:lang(kab)) > :lang(kab) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(kam), :not(:lang(kam)) > :lang(kam) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(kde), :not(:lang(kde)) > :lang(kde) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(kea), :not(:lang(kea)) > :lang(kea) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(khq), :not(:lang(khq)) > :lang(khq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ki), :not(:lang(ki)) > :lang(ki) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(kk), :not(:lang(kk)) > :lang(kk) { quotes: '\201c' '\0022' '\2018' '\2019' } /* “ " */
:root:lang(kkj), :not(:lang(kkj)) > :lang(kkj) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » */
:root:lang(kln), :not(:lang(kln)) > :lang(kln) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(km), :not(:lang(km)) > :lang(km) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(kn), :not(:lang(kn)) > :lang(kn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ko), :not(:lang(ko)) > :lang(ko) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ksb), :not(:lang(ksb)) > :lang(ksb) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ksf), :not(:lang(ksf)) > :lang(ksf) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » */
:root:lang(ky), :not(:lang(ky)) > :lang(ky) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */
:root:lang(lag), :not(:lang(lag)) > :lang(lag) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” */
:root:lang(lb), :not(:lang(lb)) > :lang(lb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(lg), :not(:lang(lg)) > :lang(lg) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ln), :not(:lang(ln)) > :lang(ln) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(lo), :not(:lang(lo)) > :lang(lo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(lt), :not(:lang(lt)) > :lang(lt) { quotes: '\201e' '\201c' '\201e' '\201c' } /* „ “ „ “ */
:root:lang(lu), :not(:lang(lu)) > :lang(lu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(luo), :not(:lang(luo)) > :lang(luo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(luy), :not(:lang(luy)) > :lang(luy) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(lv), :not(:lang(lv)) > :lang(lv) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mas), :not(:lang(mas)) > :lang(mas) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mer), :not(:lang(mer)) > :lang(mer) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mfe), :not(:lang(mfe)) > :lang(mfe) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mg), :not(:lang(mg)) > :lang(mg) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(mgo), :not(:lang(mgo)) > :lang(mgo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mk), :not(:lang(mk)) > :lang(mk) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(ml), :not(:lang(ml)) > :lang(ml) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mn), :not(:lang(mn)) > :lang(mn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mr), :not(:lang(mr)) > :lang(mr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ms), :not(:lang(ms)) > :lang(ms) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mt), :not(:lang(mt)) > :lang(mt) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(mua), :not(:lang(mua)) > :lang(mua) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(my), :not(:lang(my)) > :lang(my) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(naq), :not(:lang(naq)) > :lang(naq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(nb), :not(:lang(nb)) > :lang(nb) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » */
:root:lang(nd), :not(:lang(nd)) > :lang(nd) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ne), :not(:lang(ne)) > :lang(ne) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(nl), :not(:lang(nl)) > :lang(nl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(nmg), :not(:lang(nmg)) > :lang(nmg) { quotes: '\201e' '\201d' '\00ab' '\00bb' } /* „ ” « » */
:root:lang(nn), :not(:lang(nn)) > :lang(nn) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » */
:root:lang(nnh), :not(:lang(nnh)) > :lang(nnh) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(nus), :not(:lang(nus)) > :lang(nus) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(nyn), :not(:lang(nyn)) > :lang(nyn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(pa), :not(:lang(pa)) > :lang(pa) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(pl), :not(:lang(pl)) > :lang(pl) { quotes: '\201e' '\201d' '\00ab' '\00bb' } /* „ ” « » */
:root:lang(pt), :not(:lang(pt)) > :lang(pt) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(pt-PT), :not(:lang(pt-PT)) > :lang(pt-PT) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(rn), :not(:lang(rn)) > :lang(rn) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” */
:root:lang(ro), :not(:lang(ro)) > :lang(ro) { quotes: '\201c' '\201d' '\00ab' '\00bb' } /* “ ” « » */
:root:lang(rof), :not(:lang(rof)) > :lang(rof) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ru), :not(:lang(ru)) > :lang(ru) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */
:root:lang(rw), :not(:lang(rw)) > :lang(rw) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » */
:root:lang(rwk), :not(:lang(rwk)) > :lang(rwk) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(saq), :not(:lang(saq)) > :lang(saq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(sbp), :not(:lang(sbp)) > :lang(sbp) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(seh), :not(:lang(seh)) > :lang(seh) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ses), :not(:lang(ses)) > :lang(ses) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(sg), :not(:lang(sg)) > :lang(sg) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(shi), :not(:lang(shi)) > :lang(shi) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */
:root:lang(shi-Latn), :not(:lang(shi-Latn)) > :lang(shi-Latn) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */
:root:lang(si), :not(:lang(si)) > :lang(si) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(sk), :not(:lang(sk)) > :lang(sk) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(sl), :not(:lang(sl)) > :lang(sl) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ */
:root:lang(sn), :not(:lang(sn)) > :lang(sn) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” */
:root:lang(so), :not(:lang(so)) > :lang(so) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(sq), :not(:lang(sq)) > :lang(sq) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */
:root:lang(sr), :not(:lang(sr)) > :lang(sr) { quotes: '\201e' '\201c' '\2018' '\2018' } /* „ “ */
:root:lang(sr-Latn), :not(:lang(sr-Latn)) > :lang(sr-Latn) { quotes: '\201e' '\201c' '\2018' '\2018' } /* „ “ */
:root:lang(sv), :not(:lang(sv)) > :lang(sv) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” */
:root:lang(sw), :not(:lang(sw)) > :lang(sw) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(swc), :not(:lang(swc)) > :lang(swc) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ta), :not(:lang(ta)) > :lang(ta) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(te), :not(:lang(te)) > :lang(te) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(teo), :not(:lang(teo)) > :lang(teo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(th), :not(:lang(th)) > :lang(th) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(ti-ER), :not(:lang(ti-ER)) > :lang(ti-ER) { quotes: '\2018' '\2019' '\201c' '\201d' } /* “ ” */
:root:lang(to), :not(:lang(to)) > :lang(to) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(tr), :not(:lang(tr)) > :lang(tr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(twq), :not(:lang(twq)) > :lang(twq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(tzm), :not(:lang(tzm)) > :lang(tzm) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(uk), :not(:lang(uk)) > :lang(uk) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */
:root:lang(ur), :not(:lang(ur)) > :lang(ur) { quotes: '\201d' '\201c' '\2019' '\2018' } /* ” “ */
:root:lang(ur-IN), :not(:lang(ur-IN)) > :lang(ur-IN) { quotes: '\0022' '\0022' '\0027' '\0027' } /* " " ' ' */
:root:lang(uz), :not(:lang(uz)) > :lang(uz) { quotes: '\0022' '\0022' '\0027' '\0027' } /* " " ' ' */
:root:lang(uz-Cyrl), :not(:lang(uz-Cyrl)) > :lang(uz-Cyrl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(vai), :not(:lang(vai)) > :lang(vai) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(vai-Latn), :not(:lang(vai-Latn)) > :lang(vai-Latn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(vi), :not(:lang(vi)) > :lang(vi) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(vun), :not(:lang(vun)) > :lang(vun) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(xog), :not(:lang(xog)) > :lang(xog) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(yav), :not(:lang(yav)) > :lang(yav) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */
:root:lang(yo), :not(:lang(yo)) > :lang(yo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(zgh), :not(:lang(zgh)) > :lang(zgh) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */
:root:lang(zh), :not(:lang(zh)) > :lang(zh) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */
:root:lang(zh-Hant), :not(:lang(zh-Hant)) > :lang(zh-Hant) { quotes: '\300c' '\300d' '\300e' '\300f' } /* 「 」 『 』 */
:root:lang(zu), :not(:lang(zu)) > :lang(zu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” */

BIN
resources/rippy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDxjCCAq6gAwIBAgIJAIPzh6mmZhGkMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
Q29tcGFueSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDEgMB4GCSqGSIb3DQEJARYR
dGVzdGluZ0BzZXJ2by5vcmcwHhcNMTcxMjI0MTQxMjA0WhcNMjcxMjIyMTQxMjA0
WjB4MQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQK
DBNEZWZhdWx0IENvbXBhbnkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkq
hkiG9w0BCQEWEXRlc3RpbmdAc2Vydm8ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA8CYQ9pOb0TsChmRWzlUoZ8dJ7m8lKz103tsJ1HFOj699qoLi
Dphw/k7bUhVZlOU1XtFJTFJG8kYxjC84Ln/xKNBaFCh9hm1KUtO4RssXKlEHfg8x
VmGOIaC61oXfiAj3q+2PTgv6olDoL7z+4Y2gSP/zg1szdAGWwfksgX0atIWy8lCB
bX8VeNlBAvKkM0CLavXhjUmmpbzPGj/Pl2bv+HdXZZd7t6sHQ6AuzPaBDAnph2Pj
unZ2iVLt/PrONZ8mrUkiqg5GURQ7x/EwhO/j0EQEZDd6rOexHsnmCoUsF2KYMzgu
D9/A6Q+ruo3BE6UGb2Sb9seGfrJa1uPMzttb3QIDAQABo1MwUTAdBgNVHQ4EFgQU
rzyrtcToBhyprrcbQ698ysb4mqIwHwYDVR0jBBgwFoAUrzyrtcToBhyprrcbQ698
ysb4mqIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAffZmMwi5
ljhc0pM2DUWjfari4pvXzRpPUErTtMxuXQVijPhwOOWFI91xoEZUojxhOr+0Ran9
7OulbgaTN0xMNwSs5cdS/KLY/nuIz0J8zYeW/VfIm+9fAKxt0cqORQppd6nTnfhl
Sfr7MBE9su3fMq142voUgEwb4zxKq/tnlCzkWMAju+EPdTHW+HRhz8nEy/DVThiY
2gTQG5tajQV7XZyWBozLiCjx0I2sidC7uxoy9o9yQRXvikeNxLdiOZlBP25IHTM+
57uYE15RiCOOQB5vYH4L8ISRxDmNRYBSi5HFc68URqOuakpmGDJ8HNMJRb0m8PbR
zDwuZIy1uC+UBg==
-----END CERTIFICATE-----

273
resources/servo.css Normal file
View File

@@ -0,0 +1,273 @@
button {
cursor: default;
}
button,
input {
background: white;
min-height: 1.0em;
padding: 0em;
padding-left: 0.25em;
padding-right: 0.25em;
border: solid lightgrey 1px;
color: black;
font-family: sans-serif;
font-size: 0.8333em;
text-align: left;
line-height: 1.8;
}
textarea {
background: white;
min-height: 1.0em;
padding: 0em;
padding-left: 0.25em;
padding-right: 0.25em;
border: solid lightgrey 1px;
color: black;
font-family: sans-serif;
font-size: 0.8333em;
white-space: pre-wrap;
}
input::selection,
textarea::selection {
background: rgba(176, 214, 255, 1.0);
color: black;
}
button,
input[type="button"],
input[type="submit"],
input[type="reset"] {
background: lightgrey;
border-top: solid 1px #EEEEEE;
border-left: solid 1px #CCCCCC;
border-right: solid 1px #999999;
border-bottom: solid 1px #999999;
text-align: center;
color: black;
}
input[type="hidden"] { display: none !important }
input[type="checkbox"],
input[type="radio"] {
font-family: monospace !important;
border: none !important;
background: transparent;
}
input[type="checkbox"]::before {
display: inline-block;
border: solid currentcolor 1px;
content: "";
padding: 0;
width: 1em;
height: 1em;
text-align: center;
}
input[type="checkbox"]:checked::before { content: "✓"; }
input[type="checkbox"]:indeterminate::before { content: "-"; }
input[type="radio"]::before {
display: inline-block;
border: solid currentcolor 1px;
content: "";
padding: 0;
width: 1em;
height: 1em;
border-radius: 50%;
text-align: center;
}
input[type="radio"]:checked::before { content: "●"; line-height: 1em; }
input[type="file"]::before {
content: "Choose File";
}
input[type="file"] {
background: lightgrey;
text-align: center;
vertical-align: middle;
color: black;
}
select {
border-style: solid;
border-width: 1px;
background: white;
}
select[multiple] { padding: 0em 0.25em; }
select:not([multiple]) { padding: 0.25em 0.5em; border-radius: 6px; }
select:not([multiple])::after {
content: "";
display: inline-block;
border-width: 5.2px 3px 0 3px;
border-style: solid;
border-color: currentcolor transparent transparent transparent;
margin-left: 0.5em;
}
select:not([multiple]) option { display: none !important; }
select:not([multiple]) option[selected] { display: inline !important; }
select[multiple] option { display: block !important; }
select[multiple] option[selected] { background-color: grey; color: white; }
select[multiple]:focus option[selected] { background-color: darkblue; }
td[align="left"] { text-align: left; }
td[align="center"] { text-align: center; }
td[align="right"] { text-align: right; }
center { text-align: -servo-center; }
label { cursor: default; }
input:not([type=radio i]):not([type=checkbox i]):not([type=reset i]):not([type=button i]):not([type=submit i]),
textarea {
cursor: text;
overflow: hidden;
-servo-overflow-clip-box: content-box;
}
input:not([type=radio i]):not([type=checkbox i]):not([type=reset i]):not([type=button i]):not([type=submit i]) {
white-space: pre;
}
textarea {
overflow: auto;
}
/* https://html.spec.whatwg.org/multipage/rendering.html#the-details-and-summary-elements */
details {
display: block;
}
details::-servo-details-summary {
margin-left: 40px;
display: list-item;
list-style: disclosure-closed;
}
details[open]::-servo-details-summary {
list-style: disclosure-open;
}
*|*::-servo-details-content {
margin-left: 40px;
overflow: hidden;
display: block;
}
/*
* Until servo supports svg properly, make sure to at least prevent svg
* children from being layed out and rendered like usual html.
* https://github.com/servo/servo/issues/10646
*/
svg > * {
display: none;
}
/*
* For most (but not all) anon-boxes, we inherit all values from the
* parent.
*
* Anonymous table flows shouldn't inherit their parents properties in order
* to avoid doubling up styles such as transformations. Same for text and such.
*
* For tables, we do want style to inherit, because TableWrapper is
* responsible for handling clipping and scrolling, while Table is
* responsible for creating stacking contexts.
*
* StackingContextCollectionFlags makes sure this is processed
* properly.
*
* FIXME(emilio): inheriting all is a very strong hammer, and it's likely
* broken for stuff like table backgrounds and such. Gecko explicitly inherits
* what it wants, which seems a bit better off-hand.
*/
*|*::-servo-legacy-anonymous-table,
*|*::-servo-legacy-anonymous-table-wrapper,
*|*::-servo-legacy-table-wrapper,
*|*::-servo-legacy-anonymous-block,
*|*::-servo-legacy-inline-block-wrapper,
*|*::-servo-legacy-inline-absolute {
all: inherit;
}
/* style for text node. */
*|*::-servo-legacy-text {
text-overflow: inherit;
overflow: inherit;
}
*|*::-servo-legacy-table-wrapper {
display: table;
border: none;
}
*|*::-servo-legacy-anonymous-table-wrapper {
position: static;
margin: 0;
counter-increment: none;
/* We don't want anonymous table parts to inherit hidden overflow, because
* they will create extra unnecessary ClipScrollNodes which also throws
* off assignment of contained flows. */
overflow: visible;
}
*|*::-servo-legacy-anonymous-table {
display: table;
position: static;
border: none;
padding: 0;
counter-increment: none;
overflow: visible;
}
*|*::-servo-anonymous-table-row {
display: table-row;
position: static;
border: none;
counter-increment: none;
overflow: visible;
}
*|*::-servo-anonymous-table-cell {
display: table-cell;
position: static;
border: none;
counter-increment: none;
overflow: visible;
}
*|*::-servo-legacy-anonymous-block {
display: block;
position: static;
border: none;
padding: 0;
margin: 0;
width: auto;
height: auto;
}
/* The outer fragment wrapper of an inline-block. */
*|*::-servo-legacy-inline-block-wrapper {
position: static;
border: none;
padding: 0;
margin: 0;
}
/* The outer fragment wrapper of an inline absolute hypothetical fragment. */
*|*::-servo-legacy-inline-absolute {
clip: auto;
border: none;
padding: 0;
margin: 0;
}

BIN
resources/servo.icns Normal file

Binary file not shown.

BIN
resources/servo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

21
resources/servo.svg Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63 (92445) - https://sketch.com -->
<title>GitHub - Page</title>
<desc>Created with Sketch.</desc>
<g id="GitHub---Page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" transform="translate(10.000000, 10.000000)">
<g id="Icon---Color">
<g id="servo">
<g id="o" transform="translate(0.316840, 0.042007)">
<path d="M16.7017651,48.9189873 L36.8920575,63.6007304 L36.8920575,78.4179 C21.2468561,77.5053684 8.0646958,67.4117359 2.64512247,53.4412684 L16.7017651,48.9189873 Z" id="Path" fill="#1192E8"></path>
<path d="M61.7159566,48.9189873 L75.7727775,53.4412684 C70.3532248,67.4116829 57.171144,77.5052918 41.5261865,78.4178896 L41.5258425,63.6007304 L61.7159566,48.9189873 Z" id="Path" fill="#1192E8"></path>
<path d="M14.3755249,8.8729592 L23.0441693,20.8542542 L15.3761462,44.473866 L1.2281496,49.0256385 C0.477806609,46.0989575 0.0562613624,43.0403504 0.00525287907,39.8915922 L1.14815464e-13,39.2426433 C1.14815464e-13,27.0016423 5.59987531,16.0696862 14.3755249,8.8729592 Z" id="Path" fill="#009D9A"></path>
<path d="M64.0423751,8.8729592 C72.8180247,16.0696862 78.4179,27.0016423 78.4179,39.2426433 C78.4179,42.6202989 77.9915412,45.8982875 77.1897504,49.0256385 L63.0415756,44.473866 L55.3735525,20.8542542 L64.0423751,8.8729592 Z" id="Path" fill="#009D9A"></path>
<path d="M39.20895,-5.62820901e-15 C46.969487,-5.62820901e-15 54.2034284,2.25656145 60.2914837,6.14986174 L51.5922057,18.1734465 L26.825516,18.1734465 L18.1264163,6.14986174 C24.0445944,2.3651976 31.0456026,0.12720565 38.5605583,0.00525739302 L39.20895,-5.62820901e-15 Z" id="Path" fill="#42BE65"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
resources/servo_1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
resources/servo_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/tumbeast.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -0,0 +1,6 @@
// Keep files in this directory which you would like executed before
// any other script when servo is run with `--userscripts`
// Files are sorted alphabetically. When committing polyfills
// order them with numbers, e.g. `01.innerhtml.js` will be executed before
// `05.jquery.js`
onunhandledrejection = (e) => console.error("xxxjdm error: " + JSON.stringify(e.reason));

316
resources/user-agent.css Normal file
View File

@@ -0,0 +1,316 @@
/*
https://html.spec.whatwg.org/multipage/#form-controls
*/
@namespace url(http://www.w3.org/1999/xhtml);
/*
FIXME: Uncomment this when :lang() is supported, or do something equivalent.
@import url(quotes.css);
*/
[hidden], area, base, basefont, datalist, head, link, menu[type=popup i], meta,
noembed, noframes, param, rp, script, source, style, template, track, title {
display: none;
}
embed[hidden] { display: inline; height: 0; width: 0; }
/* FIXME: only if scripting is enabled */
noscript { display: none !important; }
input[type=hidden i] { display: none !important; }
html, body { display: block; }
body { margin: 8px; }
address, blockquote, center, div, figure, figcaption, footer, form, header, hr,
legend, listing, main, p, plaintext, pre, summary, xmp {
display: block;
}
blockquote, figure, listing, p, plaintext, pre, xmp {
margin-top: 1em; margin-bottom: 1em;
}
blockquote, figure { margin-left: 40px; margin-right: 40px; }
address { font-style: italic; }
listing, plaintext, pre, xmp {
font-family: monospace; white-space: pre;
}
dialog:not([open]) { display: none; }
dialog {
position: absolute;
left: 0; right: 0;
/* FIXME: support fit-content */
width: fit-content;
height: fit-content;
margin: auto;
border: solid;
padding: 1em;
background: white;
color: black;
}
/* FIXME: support ::backdrop */
dialog::backdrop {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background: rgba(0,0,0,0.1);
}
/* for small devices, modal dialogs go full-screen */
@media screen and (max-width: 540px) {
/* FIXME: support :modal */
dialog:modal {
top: 0;
width: auto;
margin: 1em;
}
}
cite, dfn, em, i, var { font-style: italic; }
b, strong { font-weight: bolder; }
code, kbd, samp, tt { font-family: monospace; }
big { font-size: larger; }
small { font-size: smaller; }
sub { vertical-align: sub; }
sup { vertical-align: super; }
sub, sup { line-height: normal; font-size: smaller; }
ruby { display: ruby; }
rt { display: ruby-text; }
/*
* All tag names that can be links are listed here, because applying pseudo-class selectors
* disables style sharing, so we want to apply pseudo-class selectors to as few elements as
* possible.
*/
a:link, area:link, link:link { color: #0000EE; }
a:visited, area:visited, link:visited { color: #551A8B; }
a:link, a:visited,
area:link, area:visited,
link:link, link:visited { text-decoration: underline; cursor: pointer; }
a:link[rel~=help], a:visited[rel~=help],
area:link[rel~=help], area:visited[rel~=help],
link:link[rel~=help], link:visited[rel~=help] { cursor: help; }
/*
* FIXME: use `outline: auto;`
*/
a:focus, area:focus,
input:focus, textarea:focus, button:focus { outline: thin dotted; }
mark { background: yellow; color: black; }
abbr[title], acronym[title] { text-decoration: dotted underline; }
ins, u { text-decoration: underline; }
del, s, strike { text-decoration: line-through; }
blink { text-decoration: blink; }
q::before { content: open-quote; }
q::after { content: close-quote; }
/*br { display-outside: newline; } /* this also has bidi implications */
br::before { content: "\A"; white-space: pre }
nobr { white-space: nowrap; }
wbr { display-outside: break-opportunity; } /* this also has bidi implications */
nobr wbr { white-space: normal; }
[dir]:dir(ltr), bdi:dir(ltr), input[type=tel]:dir(ltr) { direction: ltr; }
[dir]:dir(rtl), bdi:dir(rtl) { direction: rtl; }
address, blockquote, center, div, figure, figcaption, footer, form, header, hr,
legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2,
h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead,
tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, bdi, output,
[dir=ltr i], [dir=rtl i], [dir=auto i] {
unicode-bidi: isolate;
}
bdo, bdo[dir] { unicode-bidi: isolate-override; }
textarea[dir=auto i], pre[dir=auto i] { unicode-bidi: plaintext; }
article, aside, h1, h2, h3, h4, h5, h6, hgroup, nav, section {
display: block;
}
h1 { margin-top: 0.67em; margin-bottom: 0.67em; font-size: 2.00em; font-weight: bold; }
h2 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; font-weight: bold; }
h3 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; font-weight: bold; }
h4 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; font-weight: bold; }
h5 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; font-weight: bold; }
h6 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; font-weight: bold; }
:matches(article, aside, nav, section) h1 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; }
:matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; }
:matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; }
:matches(article, aside, nav, section) hgroup > h1 ~ h4 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; }
:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h4 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; }
:matches(article, aside, nav, section) hgroup > h1 ~ h5 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; }
dir, dd, dl, dt, menu, ol, ul { display: block; }
li { display: list-item; }
dir, dl, menu, ol, ul { margin-top: 1em; margin-bottom: 1em; }
:matches(dir, dl, menu, ol, ul) :matches(dir, dl, menu, ol, ul) {
margin-top: 0; margin-bottom: 0;
}
dd { margin-left: 40px; } /* FIXME: use margin-inline-start when supported */
dir, menu, ol, ul { padding-left: 40px; } /* FIXME: use padding-inline-start when supported */
ol { list-style-type: decimal; }
dir, menu, ul { list-style-type: disc; }
:matches(dir, menu, ol, ul) :matches(dir, menu, ul) {
list-style-type: circle;
}
:matches(dir, menu, ol, ul) :matches(dir, menu, ol, ul) :matches(dir, menu, ul) {
list-style-type: square;
}
table { display: table; }
caption { display: table-caption; }
colgroup, colgroup[hidden] { display: table-column-group; }
col, col[hidden] { display: table-column; }
thead, thead[hidden] { display: table-header-group; }
tbody, tbody[hidden] { display: table-row-group; }
tfoot, tfoot[hidden] { display: table-footer-group; }
tr, tr[hidden] { display: table-row; }
td, th, td[hidden], th[hidden] { display: table-cell; }
colgroup[hidden], col[hidden], thead[hidden], tbody[hidden],
tfoot[hidden], tr[hidden], td[hidden], th[hidden] {
visibility: collapse;
}
table {
box-sizing: border-box;
border-spacing: 2px;
border-collapse: separate;
text-indent: initial;
}
td, th { padding: 1px; }
th { font-weight: bold; }
thead, tbody, tfoot, table > tr { vertical-align: middle; }
tr, td, th { vertical-align: inherit; }
table, td, th { border-color: gray; }
thead, tbody, tfoot, tr { border-color: inherit; }
table:matches(
[rules=none i], [rules=groups i], [rules=rows i],
[rules=cols i], [rules=all i],
[frame=void i], [frame=above i], [frame=below i],
[frame=hsides i], [frame=lhs i], [frame=rhs i],
[frame=vsides i], [frame=box i], [frame=border i]
),
table:matches(
[rules=none i], [rules=groups i], [rules=rows i],
[rules=cols i], [rules=all i]
) > tr > :matches(td, th),
table:matches(
[rules=none i], [rules=groups i], [rules=rows i],
[rules=cols i], [rules=all i]
) > :matches(thead, tbody, tfoot) > tr > :matches(td, th) {
border-color: black;
}
:matches(table, thead, tbody, tfoot, tr) > form {
display: none !important;
}
input, select, option, optgroup, button, textarea {
text-indent: initial;
text-transform: none;
}
textarea { white-space: pre-wrap; }
input[type="radio"], input[type="checkbox"], input[type="reset"], input[type="button"],
input[type="submit"], select, button {
box-sizing: border-box;
}
input, textarea, select, button { display: inline-block; }
hr { color: gray; border-style: inset; border-width: 1px; margin: 0.5em auto; }
fieldset {
display: block; /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=27018 */
margin-left: 2px; margin-right: 2px;
border: groove 2px;
border-color: ThreeDFace; /* FIXME: system color */
padding: 0.35em 0.625em 0.75em;
min-width: min-content;
}
legend {
padding-left: 2px; padding-right: 2px;
}
iframe:not([seamless]) { border: 2px inset; }
iframe[seamless] { display: block; }
video { object-fit: contain; }
textarea { white-space: pre-wrap; }
*|*:not(:root):fullscreen {
position:fixed !important;
top:0 !important; right:0 !important; bottom:0 !important; left:0 !important;
margin:0 !important;
box-sizing:border-box !important;
min-width:0 !important;
max-width:none !important;
min-height:0 !important;
max-height:none !important;
width:100% !important;
height:100% !important;
transform:none !important;
/* intentionally not !important */
object-fit:contain;
/* The internal-only -servo-top-layer property is used
to implement https://fullscreen.spec.whatwg.org/#top-layer */
-servo-top-layer: top;
}
iframe:fullscreen {
border:none !important;
padding:0 !important;
}

13
rust-toolchain.toml Normal file
View File

@@ -0,0 +1,13 @@
[toolchain]
channel = "1.74"
components = [
# For support/crown
"llvm-tools",
# For support/crown
"rustc-dev",
# For docs building
"rust-docs",
# For formatting
"rustfmt",
]
profile = "minimal"

15
rustfmt.toml Normal file
View File

@@ -0,0 +1,15 @@
max_width = 100
hard_tabs = false
tab_spaces = 2
newline_style = "Unix"
use_small_heuristics = "Default"
reorder_imports = true
reorder_modules = true
remove_nested_parens = true
edition = "2018"
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
force_explicit_abi = true
imports_granularity = "Crate"
#license_template_path = ".license_template"

61
src/error.rs Normal file
View File

@@ -0,0 +1,61 @@
/// Convenient type alias of Result type for wry.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors returned by wry.
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[cfg(gtk)]
#[error(transparent)]
GlibError(#[from] gtk::glib::Error),
#[cfg(gtk)]
#[error(transparent)]
GlibBoolError(#[from] gtk::glib::BoolError),
#[cfg(gtk)]
#[error("Fail to fetch security manager")]
MissingManager,
#[cfg(gtk)]
#[error("Couldn't find X11 Display")]
X11DisplayNotFound,
#[cfg(gtk)]
#[error(transparent)]
XlibError(#[from] x11_dl::error::OpenError),
#[error("Failed to initialize the script")]
InitScriptError,
#[error("Bad RPC request: {0} ((1))")]
RpcScriptError(String, String),
#[error(transparent)]
NulError(#[from] std::ffi::NulError),
#[error(transparent)]
ReceiverError(#[from] std::sync::mpsc::RecvError),
#[error(transparent)]
SenderError(#[from] std::sync::mpsc::SendError<String>),
#[error("Failed to send the message")]
MessageSender,
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error(transparent)]
UrlError(#[from] url::ParseError),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[cfg(target_os = "windows")]
#[error("WebView2 error: {0}")]
WebView2Error(webview2_com::Error),
#[error("Duplicate custom protocol registered: {0}")]
DuplicateCustomProtocol(String),
#[error(transparent)]
HttpError(#[from] http::Error),
#[error("Infallible error, something went really wrong: {0}")]
Infallible(#[from] std::convert::Infallible),
#[cfg(target_os = "android")]
#[error(transparent)]
JniError(#[from] jni::errors::Error),
#[error("Failed to create proxy endpoint")]
ProxyEndpointCreationFailed,
#[error(transparent)]
WindowHandleError(#[from] raw_window_handle::HandleError),
#[error("the window handle kind is not supported")]
UnsupportedWindowHandle,
#[error(transparent)]
Utf8Error(#[from] std::str::Utf8Error),
}

1573
src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

76
src/main.rs Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use winit::{
dpi::PhysicalSize,
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use wry::{WebViewBuilder, WebViewBuilderExtServo, WebViewExtServo};
/* window decoration */
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSView, NSWindow};
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSWindowStyleMask, NSWindowTitleVisibility};
#[cfg(target_os = "macos")]
use objc::{msg_send, runtime::Object, sel, sel_impl};
#[cfg(target_os = "macos")]
use raw_window_handle::{AppKitWindowHandle, HasRawWindowHandle, RawWindowHandle};
#[cfg(target_os = "macos")]
use winit::dpi::LogicalPosition;
#[cfg(target_os = "macos")]
use winit::platform::macos::WindowBuilderExtMacOS;
fn main() -> wry::Result<()> {
let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new()
.with_inner_size(PhysicalSize::new(1000, 500))
.build(&event_loop)
.unwrap();
#[cfg(target_os = "macos")]
unsafe {
let rwh = window.raw_window_handle();
if let RawWindowHandle::AppKit(AppKitWindowHandle { ns_window, .. }) = rwh {
decorate_window(ns_window as *mut Object, LogicalPosition::new(8.0, 40.0));
}
}
#[allow(unused_mut)]
let mut builder = WebViewBuilder::new_servo(window, event_loop.create_proxy());
let mut webview = builder.build()?;
event_loop
.run(move |event, evl| {
if !evl.exiting() && webview.servo().is_shutdown() {
if let Some(servo) = webview.servo().servo_client().take() {
servo.deinit();
}
evl.exit();
} else {
webview.servo().set_control_flow(&event, evl);
webview.servo().handle_winit_event(event);
webview.servo().handle_servo_messages();
}
})
.unwrap();
Ok(())
}
#[cfg(target_os = "macos")]
pub unsafe fn decorate_window(window: *mut Object, position: LogicalPosition<f64>) {
NSWindow::setTitlebarAppearsTransparent_(window, true);
NSWindow::setTitleVisibility_(window, NSWindowTitleVisibility::NSWindowTitleHidden);
NSWindow::setStyleMask_(
window,
NSWindowStyleMask::NSTitledWindowMask
| NSWindowStyleMask::NSFullSizeContentViewWindowMask
| NSWindowStyleMask::NSClosableWindowMask
| NSWindowStyleMask::NSResizableWindowMask
| NSWindowStyleMask::NSMiniaturizableWindowMask,
);
}

15
src/proxy.rs Normal file
View File

@@ -0,0 +1,15 @@
#[derive(Debug, Clone)]
pub struct ProxyEndpoint {
/// Proxy server host (e.g. 192.168.0.100, localhost, example.com, etc.)
pub host: String,
/// Proxy server port (e.g. 1080, 3128, etc.)
pub port: String,
}
#[derive(Debug, Clone)]
pub enum ProxyConfig {
/// Connect to proxy server via HTTP CONNECT
Http(ProxyEndpoint),
/// Connect to proxy server via SOCKSv5
Socks5(ProxyEndpoint),
}

310
src/servo/embedder.rs Normal file
View File

@@ -0,0 +1,310 @@
use std::rc::Rc;
use servo::{
compositing::{
windowing::{EmbedderEvent, EmbedderMethods, MouseWindowEvent},
CompositeTarget,
},
embedder_traits::{Cursor, EmbedderMsg, EventLoopWaker},
euclid::{Point2D, Size2D},
script_traits::{TouchEventType, WheelDelta, WheelMode},
servo_url::ServoUrl,
webrender_api::{
units::{DeviceIntPoint, DevicePoint, LayoutVector2D},
ScrollLocation,
},
BrowserId, Servo,
};
use winit::{
dpi::PhysicalPosition,
event::{ElementState, Event, TouchPhase, WindowEvent},
event_loop::{ControlFlow, EventLoopProxy, EventLoopWindowTarget},
window::CursorIcon,
};
use super::window::WebView;
/// The Servo embedder to communicate with servo instance.
pub struct Embedder {
servo: Option<Servo<WebView>>,
// TODO TopLevelBrowsingContextId
browser_id: Option<BrowserId>,
webview: Rc<WebView>,
events: Vec<EmbedderEvent>,
mouse_position: PhysicalPosition<f64>,
is_shutdown: bool,
}
impl Embedder {
pub fn new(webview: WebView, callback: EmbedderWaker) -> Self {
let webview = Rc::new(webview);
let mut init_servo = Servo::new(
Box::new(callback),
webview.clone(),
Some(String::from(
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0",
)),
CompositeTarget::Window,
);
let demo_path = std::env::current_dir().unwrap().join("demo.html");
let url = ServoUrl::from_file_path(demo_path.to_str().unwrap()).unwrap();
init_servo
.servo
.handle_events(vec![EmbedderEvent::NewBrowser(url, init_servo.browser_id)]);
init_servo.servo.setup_logging();
Embedder {
servo: Some(init_servo.servo),
webview,
events: vec![],
mouse_position: PhysicalPosition::default(),
is_shutdown: false,
browser_id: None,
}
}
pub fn set_control_flow(&self, event: &Event<()>, evl: &EventLoopWindowTarget<()>) {
let control_flow = if !self.webview.is_animating() || *event == Event::Suspended {
ControlFlow::Wait
} else {
ControlFlow::Poll
};
evl.set_control_flow(control_flow);
log::trace!("Servo embedder sets control flow to: {control_flow:?}");
}
pub fn handle_winit_event(&mut self, event: Event<()>) {
log::trace!("Servo embedder is creating ebedder event from: {event:?}");
match event {
Event::Suspended => {}
Event::Resumed | Event::UserEvent(()) => {
self.events.push(EmbedderEvent::Idle);
}
Event::WindowEvent {
window_id: _,
event,
} => match event {
WindowEvent::RedrawRequested => {
let Some(servo) = self.servo.as_mut() else {
return;
};
servo.recomposite();
servo.present();
self.events.push(EmbedderEvent::Idle);
}
WindowEvent::Resized(size) => {
let size = Size2D::new(size.width, size.height);
let _ = self.webview.resize(size.to_i32());
self.events.push(EmbedderEvent::Resize);
}
WindowEvent::CursorMoved { position, .. } => {
let event: DevicePoint = DevicePoint::new(position.x as f32, position.y as f32);
self.mouse_position = position;
self
.events
.push(EmbedderEvent::MouseWindowMoveEventClass(event));
}
WindowEvent::MouseInput { state, button, .. } => {
let button: servo::script_traits::MouseButton = match button {
winit::event::MouseButton::Left => servo::script_traits::MouseButton::Left,
winit::event::MouseButton::Right => servo::script_traits::MouseButton::Right,
winit::event::MouseButton::Middle => servo::script_traits::MouseButton::Middle,
_ => {
log::warn!("Servo embedder hasn't supported this mouse button yet: {button:?}");
return;
}
};
let position = Point2D::new(self.mouse_position.x as f32, self.mouse_position.y as f32);
let event: MouseWindowEvent = match state {
ElementState::Pressed => MouseWindowEvent::MouseDown(button, position),
ElementState::Released => MouseWindowEvent::MouseUp(button, position),
};
self
.events
.push(EmbedderEvent::MouseWindowEventClass(event));
// winit didn't send click event, so we send it after mouse up
if state == ElementState::Released {
let event: MouseWindowEvent = MouseWindowEvent::Click(button, position);
self
.events
.push(EmbedderEvent::MouseWindowEventClass(event));
}
}
WindowEvent::TouchpadMagnify { delta, .. } => {
self.events.push(EmbedderEvent::Zoom(1.0 + delta as f32));
}
WindowEvent::MouseWheel { delta, phase, .. } => {
// FIXME: Pixels per line, should be configurable (from browser setting?) and vary by zoom level.
const LINE_HEIGHT: f32 = 38.0;
let (mut x, mut y, mode) = match delta {
winit::event::MouseScrollDelta::LineDelta(x, y) => {
(x as f64, (y * LINE_HEIGHT) as f64, WheelMode::DeltaLine)
}
winit::event::MouseScrollDelta::PixelDelta(position) => {
let position = position.to_logical::<f64>(self.webview.window.scale_factor());
(position.x, position.y, WheelMode::DeltaPixel)
}
};
// Wheel Event
self.events.push(EmbedderEvent::Wheel(
WheelDelta { x, y, z: 0.0, mode },
DevicePoint::new(self.mouse_position.x as f32, self.mouse_position.y as f32),
));
// Scroll Event
// Do one axis at a time.
if y.abs() >= x.abs() {
x = 0.0;
} else {
y = 0.0;
}
let phase: TouchEventType = match phase {
TouchPhase::Started => TouchEventType::Down,
TouchPhase::Moved => TouchEventType::Move,
TouchPhase::Ended => TouchEventType::Up,
TouchPhase::Cancelled => TouchEventType::Cancel,
};
self.events.push(EmbedderEvent::Scroll(
ScrollLocation::Delta(LayoutVector2D::new(x as f32, y as f32)),
DeviceIntPoint::new(self.mouse_position.x as i32, self.mouse_position.y as i32),
phase,
));
}
WindowEvent::CloseRequested => {
self.events.push(EmbedderEvent::Quit);
}
e => log::warn!("Servo embedder hasn't supported this window event yet: {e:?}"),
},
e => log::warn!("Servo embedder hasn't supported this event yet: {e:?}"),
}
}
pub fn handle_servo_messages(&mut self) {
let Some(servo) = self.servo.as_mut() else {
return;
};
let mut need_present = false;
servo.get_events().into_iter().for_each(|(w, m)| {
log::trace!("Servo embedder is handling servo message: {m:?} with browser id: {w:?}");
match m {
EmbedderMsg::BrowserCreated(w) => {
if self.browser_id.is_none() {
self.browser_id = Some(w);
}
self.events.push(EmbedderEvent::SelectBrowser(w));
}
EmbedderMsg::ReadyToPresent => {
need_present = true;
}
EmbedderMsg::SetCursor(cursor) => {
let winit_cursor = match cursor {
Cursor::Default => CursorIcon::Default,
Cursor::Pointer => CursorIcon::Pointer,
Cursor::ContextMenu => CursorIcon::ContextMenu,
Cursor::Help => CursorIcon::Help,
Cursor::Progress => CursorIcon::Progress,
Cursor::Wait => CursorIcon::Wait,
Cursor::Cell => CursorIcon::Cell,
Cursor::Crosshair => CursorIcon::Crosshair,
Cursor::Text => CursorIcon::Text,
Cursor::VerticalText => CursorIcon::VerticalText,
Cursor::Alias => CursorIcon::Alias,
Cursor::Copy => CursorIcon::Copy,
Cursor::Move => CursorIcon::Move,
Cursor::NoDrop => CursorIcon::NoDrop,
Cursor::NotAllowed => CursorIcon::NotAllowed,
Cursor::Grab => CursorIcon::Grab,
Cursor::Grabbing => CursorIcon::Grabbing,
Cursor::EResize => CursorIcon::EResize,
Cursor::NResize => CursorIcon::NResize,
Cursor::NeResize => CursorIcon::NeResize,
Cursor::NwResize => CursorIcon::NwResize,
Cursor::SResize => CursorIcon::SResize,
Cursor::SeResize => CursorIcon::SeResize,
Cursor::SwResize => CursorIcon::SwResize,
Cursor::WResize => CursorIcon::WResize,
Cursor::EwResize => CursorIcon::EwResize,
Cursor::NsResize => CursorIcon::NsResize,
Cursor::NeswResize => CursorIcon::NeswResize,
Cursor::NwseResize => CursorIcon::NwseResize,
Cursor::ColResize => CursorIcon::ColResize,
Cursor::RowResize => CursorIcon::RowResize,
Cursor::AllScroll => CursorIcon::AllScroll,
Cursor::ZoomIn => CursorIcon::ZoomIn,
Cursor::ZoomOut => CursorIcon::ZoomOut,
_ => CursorIcon::Default,
};
self.webview.window.set_cursor_icon(winit_cursor);
}
EmbedderMsg::AllowNavigationRequest(pipeline_id, _url) => {
if w.is_some() {
self
.events
.push(EmbedderEvent::AllowNavigationResponse(pipeline_id, true));
}
}
EmbedderMsg::CloseBrowser => {
self.events.push(EmbedderEvent::Quit);
}
EmbedderMsg::Shutdown => {
self.is_shutdown = true;
}
e => {
log::warn!("Servo embedder hasn't supported handling this message yet: {e:?}")
}
}
});
log::trace!(
"Servo embedder is handling embedder events: {:?}",
self.events
);
if servo.handle_events(self.events.drain(..)) {
servo.repaint_synchronously();
servo.present();
} else if need_present {
self.webview.request_redraw();
}
}
pub fn is_shutdown(&self) -> bool {
self.is_shutdown
}
pub fn servo_client(&mut self) -> &mut Option<Servo<WebView>> {
&mut self.servo
}
}
#[derive(Debug, Clone)]
pub struct EmbedderWaker(pub EventLoopProxy<()>);
impl EmbedderMethods for EmbedderWaker {
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> {
Box::new(self.clone())
}
}
impl EventLoopWaker for EmbedderWaker {
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
Box::new(self.clone())
}
fn wake(&self) {
if let Err(e) = self.0.send_event(()) {
log::error!(
"Servo waker failed to send wake up event to servo embedder: {}",
e
);
}
}
}

133
src/servo/mod.rs Normal file
View File

@@ -0,0 +1,133 @@
use raw_window_handle::HasRawWindowHandle;
use url::Url;
use winit::{event_loop::EventLoopProxy, window::Window};
use crate::{Rect, Result, WebContext, WebViewAttributes, WebViewBuilder, RGBA};
use self::{
embedder::{Embedder, EmbedderWaker},
window::WebView,
};
mod embedder;
mod prefs;
mod resources;
mod window;
pub(crate) struct InnerWebView {
embedder: Embedder,
}
impl InnerWebView {
pub fn new_servo(
window: Window,
proxy: EventLoopProxy<()>,
attributes: WebViewAttributes,
pl_attrs: super::PlatformSpecificWebViewAttributes,
web_context: Option<&mut WebContext>,
) -> Result<Self> {
resources::init(web_context);
prefs::init();
let webview = WebView::new(window);
let callback = EmbedderWaker(proxy);
let embedder = Embedder::new(webview, callback);
Ok(Self { embedder })
}
pub fn new<W: HasRawWindowHandle>(
_window: &W,
_attributes: WebViewAttributes,
_pl_attrs: super::PlatformSpecificWebViewAttributes,
_web_context: Option<&mut WebContext>,
) -> Result<Self> {
todo!()
}
pub fn new_as_child<W: HasRawWindowHandle>(
_parent: &W,
_attributes: WebViewAttributes,
_pl_attrs: super::PlatformSpecificWebViewAttributes,
_web_context: Option<&mut WebContext>,
) -> Result<Self> {
todo!()
}
pub fn print(&self) {}
pub fn url(&self) -> Url {
Url::parse("").unwrap()
}
pub fn eval(
&self,
js: &str,
callback: Option<impl FnOnce(String) + Send + 'static>,
) -> Result<()> {
Ok(())
}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn open_devtools(&self) {}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn close_devtools(&self) {}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn is_devtools_open(&self) -> bool {
true
}
pub fn zoom(&self, scale_factor: f64) {}
pub fn set_background_color(&self, background_color: RGBA) -> Result<()> {
Ok(())
}
pub fn load_url(&self, url: &str) {}
pub fn load_url_with_headers(&self, url: &str, headers: http::HeaderMap) {}
pub fn clear_all_browsing_data(&self) -> Result<()> {
Ok(())
}
pub fn set_bounds(&self, bounds: Rect) {}
pub fn set_visible(&self, visible: bool) {}
pub fn focus(&self) {}
}
pub fn platform_webview_version() -> Result<String> {
Ok(String::from(""))
}
pub trait WebViewBuilderExtServo {
fn new_servo(window: Window, proxy: EventLoopProxy<()>) -> Self;
}
impl WebViewBuilderExtServo for WebViewBuilder<'_> {
fn new_servo(window: Window, proxy: EventLoopProxy<()>) -> Self {
Self {
attrs: WebViewAttributes::default(),
window: None,
as_child: false,
#[allow(clippy::default_constructed_unit_structs)]
platform_specific: super::PlatformSpecificWebViewAttributes::default(),
web_context: None,
winit: Some((window, proxy)),
}
}
}
pub trait WebViewExtServo {
fn servo(&mut self) -> &mut Embedder; // TODO expose method instead.
}
impl WebViewExtServo for super::WebView {
fn servo(&mut self) -> &mut Embedder {
&mut self.webview.embedder
}
}

32
src/servo/prefs.rs Normal file
View File

@@ -0,0 +1,32 @@
use std::{collections::HashMap, env, fs::File, io::Read};
use getopts::Options;
use servo::config::{basedir, opts, prefs};
pub fn init() {
// Reads opts first and then prefs.
let args: Vec<String> = env::args().collect();
let opts = Options::new();
// FIXME: Most results are not handled. Better wait for user feedback to handle each config.
let _ = opts::from_cmdline_args(opts, &args);
let user_prefs_path = opts::get()
.config_dir
.clone()
.or_else(basedir::default_config_dir)
.map(|path| path.join("prefs.json"))
.filter(|path| path.exists());
let userprefs = if let Some(path) = user_prefs_path {
let mut file = File::open(path).expect("Error opening user prefs");
let mut txt = String::new();
file
.read_to_string(&mut txt)
.expect("Can't read user prefs file");
prefs::read_prefs_map(&txt).expect("Can't parse user prefs file")
} else {
HashMap::new()
};
prefs::add_user_prefs(userprefs);
}

46
src/servo/resources.rs Normal file
View File

@@ -0,0 +1,46 @@
use std::{env, fs, path::PathBuf};
use servo::embedder_traits::resources::{self, Resource, ResourceReaderMethods};
use crate::WebContext;
struct ResourceReader(PathBuf);
pub fn init(context: Option<&mut WebContext>) {
match context {
Some(c) if c.data_directory().is_some() => resources::set(Box::new(ResourceReader(
c.data_directory().unwrap().to_path_buf(),
))),
_ => resources::set(Box::new(ResourceReader(resources_dir_path()))),
}
}
impl ResourceReaderMethods for ResourceReader {
fn read(&self, res: Resource) -> Vec<u8> {
let mut path = self.0.clone();
path.push(res.filename());
fs::read(path).expect("Can't read file")
}
fn sandbox_access_files(&self) -> Vec<PathBuf> {
vec![self.0.clone()]
}
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
vec![]
}
}
fn resources_dir_path() -> PathBuf {
// Try ./resources relative to the directory containing the
// canonicalised executable path, then each of its ancestors.
let mut path = env::current_exe().unwrap().canonicalize().unwrap();
while path.pop() {
path.push("resources");
if path.is_dir() {
return path;
}
path.pop();
}
panic!("Can not find the resources directory. Please specify it in WebContext instead.");
}

167
src/servo/window.rs Normal file
View File

@@ -0,0 +1,167 @@
use std::cell::Cell;
use raw_window_handle::HasRawWindowHandle;
use servo::{
compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods},
config::pref,
euclid::{Point2D, Scale, Size2D, UnknownUnit},
webrender_api::units::DeviceIntRect,
webrender_surfman::WebrenderSurfman,
};
use surfman::{Connection, GLApi, GLVersion, SurfaceType};
// FIXME servo should re-export this.
use servo_media::player::context::{GlApi, GlContext, NativeDisplay};
use winit::window::Window;
/// This is the type for servo embedder. Not for public usage.
pub struct WebView {
pub webrender_surfman: WebrenderSurfman,
animation_state: Cell<AnimationState>,
pub window: Window,
}
impl WebView {
pub fn new(window: Window) -> Self {
let connection = Connection::new().expect("Failed to create surfman connection");
let adapter = connection
.create_adapter()
.expect("Failed to create surfman adapter");
let native_widget = connection
.create_native_widget_from_rwh(window.raw_window_handle())
.expect("Failed to create surfman native widget");
let surface_type = SurfaceType::Widget { native_widget };
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.expect("Failed to create webrender surfman");
log::trace!("Created webrender surfman for window {:?}", window);
Self {
webrender_surfman,
animation_state: Cell::new(AnimationState::Idle),
window,
}
}
pub fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating
}
pub fn resize(&self, size: Size2D<i32, UnknownUnit>) {
let _ = self.webrender_surfman.resize(size);
}
pub fn request_redraw(&self) {
self.window.request_redraw();
}
}
unsafe impl Send for WebView {}
unsafe impl Sync for WebView {}
impl WindowMethods for WebView {
fn get_coordinates(&self) -> EmbedderCoordinates {
let size = self.window.inner_size();
let pos = Point2D::new(0, 0);
let viewport = Size2D::new(size.width as i32, size.height as i32);
let size = self.window.current_monitor().unwrap().size();
let screen = Size2D::new(size.width as i32, size.height as i32);
EmbedderCoordinates {
hidpi_factor: Scale::new(self.window.scale_factor() as f32),
screen,
screen_avail: screen,
window: (viewport, pos),
framebuffer: viewport,
viewport: DeviceIntRect::new(pos, viewport),
}
}
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state);
}
fn get_gl_context(&self) -> GlContext {
if !pref!(media.glvideo.enabled) {
return GlContext::Unknown;
}
#[allow(unused_variables)]
let native_context = self.webrender_surfman.native_context();
#[cfg(target_os = "windows")]
return GlContext::Egl(native_context.egl_context as usize);
#[cfg(target_os = "linux")]
return {
use surfman::platform::generic::multi::context::NativeContext;
match native_context {
NativeContext::Default(NativeContext::Default(native_context)) => {
GlContext::Egl(native_context.egl_context as usize)
}
NativeContext::Default(NativeContext::Alternate(native_context)) => {
GlContext::Egl(native_context.egl_context as usize)
}
NativeContext::Alternate(_) => unimplemented!(),
}
};
// @TODO(victor): https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
#[allow(unreachable_code)]
return unimplemented!();
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
}
fn get_native_display(&self) -> NativeDisplay {
if !pref!(media.glvideo.enabled) {
return NativeDisplay::Unknown;
}
#[allow(unused_variables)]
let native_connection = self.webrender_surfman.connection().native_connection();
#[allow(unused_variables)]
let native_device = self.webrender_surfman.native_device();
#[cfg(target_os = "windows")]
return NativeDisplay::Egl(native_device.egl_display as usize);
#[cfg(target_os = "linux")]
return {
use surfman::platform::generic::multi::connection::NativeConnection;
match native_connection {
NativeConnection::Default(NativeConnection::Default(conn)) => {
NativeDisplay::Egl(conn.0 as usize)
}
NativeConnection::Default(NativeConnection::Alternate(conn)) => {
NativeDisplay::X11(conn.x11_display as usize)
}
NativeConnection::Alternate(_) => unimplemented!(),
}
};
// @TODO(victor): https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
#[allow(unreachable_code)]
return unimplemented!();
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
}
fn get_gl_api(&self) -> GlApi {
let api = self.webrender_surfman.connection().gl_api();
let attributes = self.webrender_surfman.context_attributes();
let GLVersion { major, minor } = attributes.version;
match api {
GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3,
GLApi::GL => GlApi::OpenGL,
GLApi::GLES if major > 1 => GlApi::Gles2,
GLApi::GLES => GlApi::Gles1,
}
}
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
}

93
src/web_context.rs Normal file
View File

@@ -0,0 +1,93 @@
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
#[cfg(gtk)]
use crate::webkitgtk::WebContextImpl;
use std::path::{Path, PathBuf};
/// A context that is shared between multiple [`WebView`]s.
///
/// A browser would have a context for all the normal tabs and a different context for all the
/// private/incognito tabs.
///
/// # Warning
/// If [`WebView`] is created by a WebContext. Dropping `WebContext` will cause [`WebView`] lose
/// some actions like custom protocol on Mac. Please keep both instances when you still wish to
/// interact with them.
///
/// [`WebView`]: crate::WebView
#[derive(Debug)]
pub struct WebContext {
data: WebContextData,
#[allow(dead_code)] // It's not needed on Windows and macOS.
pub(crate) os: WebContextImpl,
}
impl WebContext {
/// Create a new [`WebContext`].
///
/// `data_directory`:
/// * Whether the WebView window should have a custom user data path. This is useful in Windows
/// when a bundled application can't have the webview data inside `Program Files`.
pub fn new(data_directory: Option<PathBuf>) -> Self {
let data = WebContextData { data_directory };
let os = WebContextImpl::new(&data);
Self { data, os }
}
#[cfg(gtk)]
pub(crate) fn new_ephemeral() -> Self {
let data = WebContextData::default();
let os = WebContextImpl::new_ephemeral();
Self { data, os }
}
/// A reference to the data directory the context was created with.
pub fn data_directory(&self) -> Option<&Path> {
self.data.data_directory()
}
/// Set if this context allows automation.
///
/// **Note:** This is currently only enforced on Linux, and has the stipulation that
/// only 1 context allows automation at a time.
pub fn set_allows_automation(&mut self, flag: bool) {
self.os.set_allows_automation(flag);
}
}
impl Default for WebContext {
fn default() -> Self {
let data = WebContextData::default();
let os = WebContextImpl::new(&data);
Self { data, os }
}
}
/// Data that all [`WebContext`] share regardless of platform.
#[derive(Default, Debug)]
pub struct WebContextData {
data_directory: Option<PathBuf>,
}
impl WebContextData {
/// A reference to the data directory the context was created with.
pub fn data_directory(&self) -> Option<&Path> {
self.data_directory.as_deref()
}
}
#[cfg(not(gtk))]
#[derive(Debug)]
pub(crate) struct WebContextImpl;
#[cfg(not(gtk))]
impl WebContextImpl {
fn new(_data: &WebContextData) -> Self {
Self
}
fn set_allows_automation(&mut self, _flag: bool) {}
}