├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── mach ├── mach.bat ├── python ├── README.md ├── mach_bootstrap.py ├── mach_bootstrap.pyc ├── requirements-salt.txt ├── requirements.txt ├── servo │ ├── __init__.py │ ├── __init__.pyc │ ├── bootstrap.py │ ├── bootstrap.pyc │ ├── bootstrap_commands.py │ ├── bootstrap_commands.pyc │ ├── build_commands.py │ ├── build_commands.pyc │ ├── command_base.py │ ├── command_base.pyc │ ├── devenv_commands.py │ ├── devenv_commands.pyc │ ├── lints │ │ ├── wpt_lint.py │ │ └── wpt_lint.pyc │ ├── package_commands.py │ ├── package_commands.pyc │ ├── packages.py │ ├── packages.pyc │ ├── post_build_commands.py │ ├── post_build_commands.pyc │ ├── servo-binary-formula.rb.in │ ├── testing_commands.py │ ├── testing_commands.pyc │ ├── util.py │ ├── util.pyc │ └── win32_toast.py ├── tidy │ ├── HISTORY.rst │ ├── Makefile │ ├── README.rst │ ├── servo_tidy │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── licenseck.py │ │ ├── licenseck.pyc │ │ ├── tidy.py │ │ └── tidy.pyc │ ├── servo_tidy_tests │ │ ├── Cargo.toml │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── apache2_license.rs │ │ ├── ban-domrefcell.rs │ │ ├── ban.rs │ │ ├── dir_check │ │ │ ├── only_webidl │ │ │ │ └── test.webidl │ │ │ └── webidl_plus │ │ │ │ ├── test.rs │ │ │ │ ├── test.test │ │ │ │ ├── test.webidl │ │ │ │ └── test2.rs │ │ ├── duplicate_key.json │ │ ├── duplicate_keys_buildbot_steps.yml │ │ ├── duplicated_package.lock │ │ ├── empty_file.rs │ │ ├── incorrect_license.rs │ │ ├── lib.rs │ │ ├── lints │ │ │ ├── invalid_error_tuple.py │ │ │ ├── no_lint.py │ │ │ ├── no_run.py │ │ │ ├── not_inherited.py │ │ │ ├── not_script │ │ │ └── proper_file.py │ │ ├── long_line.rs │ │ ├── malformed_json.json │ │ ├── modeline.txt │ │ ├── non_list_mapping_buildbot_steps.yml │ │ ├── non_string_list_buildbot_steps.yml │ │ ├── rust_tidy.rs │ │ ├── script_thread.rs │ │ ├── servo-tidy.toml │ │ ├── shebang_license.py │ │ ├── shell_tidy.sh │ │ ├── spec.webidl │ │ ├── speclink.rs │ │ ├── test_ignored │ │ │ └── whee │ │ │ │ ├── foo │ │ │ │ └── bar.rs │ │ │ │ └── test.rs │ │ ├── test_tidy.py │ │ ├── test_tidy.pyc │ │ ├── unordered_key.json │ │ ├── whatwg_link.rs │ │ └── wrong_space.rs │ └── setup.py └── tox.ini ├── rust-toolchain ├── screenshots ├── dark-theme.png ├── debug.png ├── mini.png ├── options.png ├── regular.png ├── tabs.png └── toolbar.png ├── servo_resources ├── Credits.rtf.mako ├── Servo.ico ├── ahem.css ├── ahem │ ├── AHEM____.TTF │ ├── Ahem.ps │ ├── Ahem.sit │ ├── COPIED-FROM │ ├── COPYING │ └── README ├── android_params ├── badcert.html ├── badcert.jpg ├── cert-google-only ├── certs ├── failure.html ├── gatt_blocklist.txt ├── hsts_preload.json ├── iso-8859-8.css ├── itried.jpg ├── neterror.html ├── not-found.html ├── package-prefs.json ├── prefs.json ├── presentational-hints.css ├── privatekey_for_testing.key ├── public_domains.txt ├── quirks-mode.css ├── quotes.css ├── rippy.png ├── self_signed_certificate_for_testing.crt ├── servo.css ├── servo.icns ├── servo.png ├── servo.svg ├── tumbeast.png ├── user-agent-js │ └── 00.example.js └── user-agent.css ├── shell_resources ├── home.html └── icons │ ├── 128x128-x2.png │ ├── 128x128.png │ ├── 32x32.png │ ├── ServoShell.icns │ └── ServoShell.ico ├── src ├── logs.rs ├── main.rs ├── platform │ ├── cocoa │ │ ├── app.rs │ │ ├── bookmarks.rs │ │ ├── mod.rs │ │ ├── toolbar.rs │ │ ├── utils.rs │ │ ├── view.rs │ │ ├── window.rs │ │ └── xib │ │ │ ├── App.xib │ │ │ └── Window.xib │ ├── glutin │ │ ├── app.rs │ │ ├── mod.rs │ │ ├── utils.rs │ │ ├── view.rs │ │ └── window.rs │ └── mod.rs ├── servo.rs ├── state │ ├── app.rs │ ├── browser.rs │ ├── mod.rs │ ├── state.rs │ ├── tabs.rs │ └── window.rs └── traits │ ├── app.rs │ ├── mod.rs │ ├── view.rs │ └── window.rs ├── support ├── macos │ ├── Credits.rtf.mako │ └── Info.plist.mako └── windows │ ├── ServoShell.wxs.mako │ └── servoshell.exe.manifest └── tests.md /.gitignore: -------------------------------------------------------------------------------- 1 | /nibs 2 | /target 3 | /python/_virtualenv/ 4 | /python/tidy/servo_tidy.egg-info/ 5 | .cargo 6 | .servo 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "macos/MMTabBarView"] 2 | path = src/platform/cocoa/MMTabBarView 3 | url = https://github.com/MiMo42/MMTabBarView 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "servoshell" 3 | version = "0.1.0" 4 | authors = ["Paul Rouget "] 5 | description = "A basic servo-based browser" 6 | build = "build.rs" 7 | 8 | [dependencies] 9 | open = "1.1.1" 10 | log = "0.3" 11 | libservo = { git = "https://github.com/servo/servo", rev = "989d2fd532" } 12 | glutin = "0.9" 13 | tinyfiledialogs = "3.0" 14 | treediff = { version = "2.5.3", features = ["with-serde-json"] } 15 | serde = "1.0" 16 | serde_json = "1.0" 17 | serde_derive = "1.0" 18 | 19 | [target.'cfg(target_os = "macos")'.dependencies] 20 | objc = "0.2" 21 | core-foundation = "0.3" 22 | core-graphics = "0.8" 23 | cocoa = "^0.9.2" 24 | cgl = "0.2" 25 | libc = "0.2" 26 | 27 | [target.'cfg(target_os = "windows")'.dependencies] 28 | winapi = "0.2" 29 | user32-sys = "0.2" 30 | gdi32-sys = "0.2" 31 | 32 | [features] 33 | force-glutin = [] 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ServoShell 2 | 3 | This is a sandbox project. Prototyping and experimenting with embedding Servo. 4 | 5 | [Download](https://github.com/paulrouget/servoshell/releases/). 6 | 7 | ## Full UI 8 | 9 | A regular browser user interface (only available for MacOS for now). 10 | 11 | ![Full UI](https://github.com/paulrouget/servoshell/blob/master/screenshots/tabs.png?raw=true "Full UI") 12 | 13 | ## Mini UI 14 | 15 | Same features as a Full UI, just no widgets. Tabs are displayed in the titlebar as text. 16 | 17 | ![Mini UI](https://github.com/paulrouget/servoshell/blob/master/screenshots/mini.png?raw=true "Mini UI") 18 | 19 | ## Build 20 | 21 | There are 2 versions of the UI: 22 | 1. Full UI: Tabs + urlbar interface. Cocoa based (only MacOS). 23 | 2. Mini UI: No visual controls. Driven by keybindings (Windows, Linux, Mac). 24 | 25 | The minimal UI can be compiled on MacOS with `--features=force-glutin`. 26 | 27 | ### Linux and Mac 28 | 29 | 1. ``rustup install `cat rust-toolchain` `` 30 | 2. `cargo build --release` 31 | 3. `cargo run --release` 32 | 33 | ### Windows 34 | 35 | Make sure you installed all the [dependencies necessary to build Servo](https://github.com/servo/servo#on-windows-msvc). 36 | 37 | 1. `mach build -r` 38 | 2. `mach run -r` 39 | 40 | ## How to update Servo 41 | 42 | 1. change `rev` in `Cargo.toml` 43 | 2. copy `rust-toolchain` to `servoshell/rust-toolchain` 44 | 3. copy `servo/Cargo.lock` to `servoshell/Cargo.lock` 45 | 4. copy `servo/resources` to `servoshell/servo_resources` 46 | 47 | ## Screenshots 48 | 49 | ![regular](https://github.com/paulrouget/servoshell/blob/master/screenshots/regular.png?raw=true "regular") 50 | ![dark theme](https://github.com/paulrouget/servoshell/blob/master/screenshots/dark-theme.png?raw=true "dark theme") 51 | ![options](https://github.com/paulrouget/servoshell/blob/master/screenshots/options.png?raw=true "options") 52 | ![debug](https://github.com/paulrouget/servoshell/blob/master/screenshots/debug.png?raw=true "debug") 53 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use std::fs; 6 | use std::path::Path; 7 | use std::process::Command; 8 | 9 | fn main() { 10 | if cfg!(all(not(feature = "force-glutin"), target_os = "macos")) { 11 | build_mmtabbarview(); 12 | build_nibs(); 13 | } 14 | } 15 | 16 | fn build_mmtabbarview() { 17 | if !Path::new("./src/platform/cocoa/MMTabBarView/.git").exists() { 18 | let _ = Command::new("git") 19 | .args(&["submodule", "update", "--init"]) 20 | .status(); 21 | } 22 | let status = Command::new("xcodebuild") 23 | .args(&["-project", 24 | "./src/platform/cocoa/MMTabBarView/MMTabBarView/MMTabBarView.xcodeproj"]) 25 | .args(&["-configuration", "Release"]) 26 | .args(&["SYMROOT=../../../../../target/MMTabBarView/"]) 27 | .status() 28 | .expect("failed to execute xcodebuild"); 29 | assert!(status.success(), "xcodebuild failed"); 30 | 31 | println!("cargo:rustc-link-search=framework=target/MMTabBarView/Release/"); 32 | } 33 | 34 | fn build_nibs() { 35 | fn ibtool(src: &str, out_dir: &Path) { 36 | let out = out_dir.to_str().unwrap(); 37 | let filename = Path::new(src).file_name().unwrap(); 38 | let out_file = filename.to_str().unwrap().replace("xib", "nib"); 39 | let status = Command::new("ibtool") 40 | .arg(src) 41 | .arg("--compile") 42 | .arg(&format!("{}/{}", out, out_file)) 43 | .status() 44 | .expect("failed to execute ibtool"); 45 | assert!(status.success(), "ibtool failed"); 46 | } 47 | let nibs_dir = Path::new("target/nibs"); 48 | fs::create_dir_all(&nibs_dir).unwrap(); 49 | ibtool("src/platform/cocoa/xib/App.xib", nibs_dir); 50 | ibtool("src/platform/cocoa/xib/Window.xib", nibs_dir); 51 | } 52 | -------------------------------------------------------------------------------- /mach: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This Source Code Form is subject to the terms of the Mozilla Public 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | # The beginning of this script is both valid shell and valid python, 7 | # such that the script starts with the shell and is reexecuted with 8 | # the right python. 9 | ''':' && if [ ! -z "$MSYSTEM" ] ; then exec python "$0" "$@" ; else which python2.7 > /dev/null 2> /dev/null && exec python2.7 "$0" "$@" || exec python "$0" "$@" ; fi 10 | ''' 11 | 12 | from __future__ import print_function, unicode_literals 13 | 14 | 15 | import os 16 | import sys 17 | 18 | 19 | def main(args): 20 | topdir = os.path.abspath(os.path.dirname(sys.argv[0])) 21 | sys.path.insert(0, os.path.join(topdir, "python")) 22 | import mach_bootstrap 23 | mach = mach_bootstrap.bootstrap(topdir) 24 | sys.exit(mach.run(sys.argv[1:])) 25 | 26 | 27 | if __name__ == '__main__': 28 | sys.dont_write_bytecode = True 29 | if sys.platform == 'win32': 30 | # This is a complete hack to work around the fact that Windows 31 | # multiprocessing needs to import the original module (ie: this 32 | # file), but only works if it has a .py extension. 33 | # 34 | # We do this by a sort of two-level function interposing. The first 35 | # level interposes forking.get_command_line() with our version defined 36 | # in my_get_command_line(). Our version of get_command_line will 37 | # replace the command string with the contents of the fork_interpose() 38 | # function to be used in the subprocess. 39 | # 40 | # The subprocess then gets an interposed imp.find_module(), which we 41 | # hack up to find 'mach' without the .py extension, since we already 42 | # know where it is (it's us!). If we're not looking for 'mach', then 43 | # the original find_module will suffice. 44 | # 45 | # See also: http://bugs.python.org/issue19946 46 | # And: https://bugzilla.mozilla.org/show_bug.cgi?id=914563 47 | import inspect 48 | from multiprocessing import forking 49 | global orig_command_line 50 | 51 | def fork_interpose(): 52 | import imp 53 | import os 54 | import sys 55 | orig_find_module = imp.find_module 56 | def my_find_module(name, dirs): 57 | if name == 'mach': 58 | path = os.path.join(dirs[0], 'mach') 59 | f = open(path) 60 | return (f, path, ('', 'r', imp.PY_SOURCE)) 61 | return orig_find_module(name, dirs) 62 | 63 | # Don't allow writing bytecode file for mach module. 64 | orig_load_module = imp.load_module 65 | def my_load_module(name, file, path, description): 66 | # multiprocess.forking invokes imp.load_module manually and 67 | # hard-codes the name __parents_main__ as the module name. 68 | if name == '__parents_main__': 69 | old_bytecode = sys.dont_write_bytecode 70 | sys.dont_write_bytecode = True 71 | try: 72 | return orig_load_module(name, file, path, description) 73 | finally: 74 | sys.dont_write_bytecode = old_bytecode 75 | 76 | return orig_load_module(name, file, path, description) 77 | 78 | imp.find_module = my_find_module 79 | imp.load_module = my_load_module 80 | from multiprocessing.forking import main; main() 81 | 82 | def my_get_command_line(): 83 | fork_code, lineno = inspect.getsourcelines(fork_interpose) 84 | # Remove the first line (for 'def fork_interpose():') and the three 85 | # levels of indentation (12 spaces). 86 | fork_string = ''.join(x[12:] for x in fork_code[1:]) 87 | cmdline = orig_command_line() 88 | cmdline[2] = fork_string 89 | return cmdline 90 | orig_command_line = forking.get_command_line 91 | forking.get_command_line = my_get_command_line 92 | 93 | main(sys.argv) 94 | -------------------------------------------------------------------------------- /mach.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | IF EXIST "%ProgramFiles(x86)%" ( 4 | set "ProgramFiles32=%ProgramFiles(x86)%" 5 | ) ELSE ( 6 | set "ProgramFiles32=%ProgramFiles%" 7 | ) 8 | 9 | set VC14VARS=%VS140COMNTOOLS%..\..\VC\vcvarsall.bat 10 | IF EXIST "%VC14VARS%" ( 11 | set "VS_VCVARS=%VC14VARS%" 12 | ) ELSE ( 13 | for %%e in (Enterprise Professional Community) do ( 14 | IF EXIST "%ProgramFiles32%\Microsoft Visual Studio\2017\%%e\VC\Auxiliary\Build\vcvarsall.bat" ( 15 | set "VS_VCVARS=%ProgramFiles32%\Microsoft Visual Studio\2017\%%e\VC\Auxiliary\Build\vcvarsall.bat" 16 | ) 17 | ) 18 | ) 19 | 20 | IF EXIST "%VS_VCVARS%" ( 21 | IF NOT DEFINED Platform ( 22 | IF EXIST "%ProgramFiles(x86)%" ( 23 | call "%VS_VCVARS%" x64 24 | ) ELSE ( 25 | ECHO 32-bit Windows is currently unsupported. 26 | EXIT /B 27 | ) 28 | ) 29 | ) ELSE ( 30 | ECHO Visual Studio 2015 or 2017 is not installed. 31 | ECHO Download and install Visual Studio 2015 or 2017 from https://www.visualstudio.com/ 32 | EXIT /B 33 | ) 34 | 35 | python mach %* 36 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | This directory contains various Python modules used to support servo 2 | development. 3 | 4 | # `servo` 5 | 6 | servo-specific python code e.g. implementations of mach commands. This 7 | is the canonical repository for this code. 8 | 9 | # `tidy` 10 | 11 | servo-tidy is used to check licenses, line lengths, whitespace, flake8 on 12 | Python files, lock file versions, and more. 13 | -------------------------------------------------------------------------------- /python/mach_bootstrap.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | from __future__ import print_function, unicode_literals 6 | 7 | import os 8 | import platform 9 | import sys 10 | from distutils.spawn import find_executable 11 | from subprocess import PIPE, Popen 12 | 13 | SEARCH_PATHS = [ 14 | os.path.join("python", "tidy"), 15 | ] 16 | 17 | # Individual files providing mach commands. 18 | MACH_MODULES = [ 19 | os.path.join('python', 'servo', 'bootstrap_commands.py'), 20 | os.path.join('python', 'servo', 'build_commands.py'), 21 | # os.path.join('python', 'servo', 'testing_commands.py'), 22 | os.path.join('python', 'servo', 'post_build_commands.py'), 23 | os.path.join('python', 'servo', 'package_commands.py'), 24 | os.path.join('python', 'servo', 'devenv_commands.py'), 25 | ] 26 | 27 | CATEGORIES = { 28 | 'bootstrap': { 29 | 'short': 'Bootstrap Commands', 30 | 'long': 'Bootstrap the build system', 31 | 'priority': 90, 32 | }, 33 | 'build': { 34 | 'short': 'Build Commands', 35 | 'long': 'Interact with the build system', 36 | 'priority': 80, 37 | }, 38 | 'post-build': { 39 | 'short': 'Post-build Commands', 40 | 'long': 'Common actions performed after completing a build.', 41 | 'priority': 70, 42 | }, 43 | 'testing': { 44 | 'short': 'Testing', 45 | 'long': 'Run tests.', 46 | 'priority': 60, 47 | }, 48 | 'devenv': { 49 | 'short': 'Development Environment', 50 | 'long': 'Set up and configure your development environment.', 51 | 'priority': 50, 52 | }, 53 | 'build-dev': { 54 | 'short': 'Low-level Build System Interaction', 55 | 'long': 'Interact with specific parts of the build system.', 56 | 'priority': 20, 57 | }, 58 | 'package': { 59 | 'short': 'Package', 60 | 'long': 'Create objects to distribute', 61 | 'priority': 15, 62 | }, 63 | 'misc': { 64 | 'short': 'Potpourri', 65 | 'long': 'Potent potables and assorted snacks.', 66 | 'priority': 10, 67 | }, 68 | 'disabled': { 69 | 'short': 'Disabled', 70 | 'long': 'The disabled commands are hidden by default. Use -v to display them. These commands are unavailable ' 71 | 'for your current context, run "mach " to see why.', 72 | 'priority': 0, 73 | } 74 | } 75 | 76 | # Possible names of executables 77 | # NOTE: Windows Python doesn't provide versioned executables, so we must use 78 | # the plain names. On MSYS, we still use Windows Python. 79 | if sys.platform in ['msys', 'win32']: 80 | PYTHON_NAMES = ["python"] 81 | VIRTUALENV_NAMES = ["virtualenv"] 82 | PIP_NAMES = ["pip"] 83 | else: 84 | PYTHON_NAMES = ["python-2.7", "python2.7", "python2", "python"] 85 | VIRTUALENV_NAMES = ["virtualenv-2.7", "virtualenv2.7", "virtualenv2", "virtualenv"] 86 | PIP_NAMES = ["pip-2.7", "pip2.7", "pip2", "pip"] 87 | 88 | 89 | def _get_exec_path(names, is_valid_path=lambda _path: True): 90 | for name in names: 91 | path = find_executable(name) 92 | if path and is_valid_path(path): 93 | return path 94 | return None 95 | 96 | 97 | def _get_virtualenv_script_dir(): 98 | # Virtualenv calls its scripts folder "bin" on linux/OSX/MSYS64 but "Scripts" on Windows 99 | if os.name == "nt" and os.sep != "/": 100 | return "Scripts" 101 | return "bin" 102 | 103 | 104 | def wpt_path(is_firefox, topdir, *paths): 105 | if is_firefox: 106 | rel = os.path.join("..", "testing", "web-platform") 107 | else: 108 | rel = os.path.join("tests", "wpt") 109 | 110 | return os.path.join(topdir, rel, *paths) 111 | 112 | 113 | def wpt_harness_path(is_firefox, topdir, *paths): 114 | wpt_root = wpt_path(is_firefox, topdir) 115 | if is_firefox: 116 | rel = os.path.join(wpt_root, "tests", "tools", "wptrunner") 117 | else: 118 | rel = os.path.join(wpt_root, "harness") 119 | 120 | return os.path.join(topdir, rel, *paths) 121 | 122 | 123 | def _activate_virtualenv(topdir, is_firefox): 124 | virtualenv_path = os.path.join(topdir, "python", "_virtualenv") 125 | check_exec_path = lambda path: path.startswith(virtualenv_path) 126 | python = _get_exec_path(PYTHON_NAMES) # If there was no python, mach wouldn't have run at all! 127 | if not python: 128 | sys.exit('Failed to find python executable for starting virtualenv.') 129 | 130 | script_dir = _get_virtualenv_script_dir() 131 | activate_path = os.path.join(virtualenv_path, script_dir, "activate_this.py") 132 | need_pip_upgrade = False 133 | if not (os.path.exists(virtualenv_path) and os.path.exists(activate_path)): 134 | virtualenv = _get_exec_path(VIRTUALENV_NAMES) 135 | if not virtualenv: 136 | sys.exit("Python virtualenv is not installed. Please install it prior to running mach.") 137 | 138 | process = Popen( 139 | [virtualenv, "-p", python, "--system-site-packages", virtualenv_path], 140 | stdout=PIPE, 141 | stderr=PIPE 142 | ) 143 | process.wait() 144 | if process.returncode: 145 | out, err = process.communicate() 146 | print('Python virtualenv failed to execute properly:') 147 | sys.exit('Output: %s\nError: %s' % (out, err)) 148 | # We want to upgrade pip when virtualenv created for the first time 149 | need_pip_upgrade = True 150 | 151 | execfile(activate_path, dict(__file__=activate_path)) 152 | 153 | python = _get_exec_path(PYTHON_NAMES, is_valid_path=check_exec_path) 154 | if not python: 155 | sys.exit("Python executable in virtualenv failed to activate.") 156 | 157 | # TODO: Right now, we iteratively install all the requirements by invoking 158 | # `pip install` each time. If it were the case that there were conflicting 159 | # requirements, we wouldn't know about them. Once 160 | # https://github.com/pypa/pip/issues/988 is addressed, then we can just 161 | # chain each of the requirements files into the same `pip install` call 162 | # and it will check for conflicts. 163 | requirements_paths = [ 164 | os.path.join("python", "requirements.txt"), 165 | # wpt_harness_path(is_firefox, topdir, "requirements.txt",), 166 | # wpt_harness_path(is_firefox, topdir, "requirements_firefox.txt"), 167 | # wpt_harness_path(is_firefox, topdir, "requirements_servo.txt"), 168 | ] 169 | 170 | if need_pip_upgrade: 171 | # Upgrade pip when virtualenv is created to fix the issue 172 | # https://github.com/servo/servo/issues/11074 173 | pip = _get_exec_path(PIP_NAMES, is_valid_path=check_exec_path) 174 | if not pip: 175 | sys.exit("Python pip is either not installed or not found in virtualenv.") 176 | 177 | process = Popen([pip, "install", "-q", "-I", "-U", "pip"], stdout=PIPE, stderr=PIPE) 178 | process.wait() 179 | if process.returncode: 180 | out, err = process.communicate() 181 | print('Pip failed to upgrade itself properly:') 182 | sys.exit('Output: %s\nError: %s' % (out, err)) 183 | 184 | for req_rel_path in requirements_paths: 185 | req_path = os.path.join(topdir, req_rel_path) 186 | marker_file = req_rel_path.replace(os.path.sep, '-') 187 | marker_path = os.path.join(virtualenv_path, marker_file) 188 | 189 | try: 190 | if os.path.getmtime(req_path) + 10 < os.path.getmtime(marker_path): 191 | continue 192 | except OSError: 193 | pass 194 | 195 | pip = _get_exec_path(PIP_NAMES, is_valid_path=check_exec_path) 196 | if not pip: 197 | sys.exit("Python pip is either not installed or not found in virtualenv.") 198 | 199 | process = Popen([pip, "install", "-q", "-I", "-r", req_path], stdout=PIPE, stderr=PIPE) 200 | process.wait() 201 | if process.returncode: 202 | out, err = process.communicate() 203 | print('Pip failed to execute properly:') 204 | sys.exit('Output: %s\nError: %s' % (out, err)) 205 | 206 | open(marker_path, 'w').close() 207 | 208 | 209 | def _ensure_case_insensitive_if_windows(): 210 | # The folder is called 'python'. By deliberately checking for it with the wrong case, we determine if the file 211 | # system is case sensitive or not. 212 | if _is_windows() and not os.path.exists('Python'): 213 | print('Cannot run mach in a path on a case-sensitive file system on Windows.') 214 | print('For more details, see https://github.com/pypa/virtualenv/issues/935') 215 | sys.exit(1) 216 | 217 | 218 | def _is_windows(): 219 | return sys.platform == 'win32' 220 | 221 | 222 | def bootstrap(topdir): 223 | _ensure_case_insensitive_if_windows() 224 | 225 | topdir = os.path.abspath(topdir) 226 | 227 | # We don't support paths with Unicode characters for now 228 | # https://github.com/servo/servo/issues/10002 229 | try: 230 | topdir.decode('ascii') 231 | except UnicodeDecodeError: 232 | print('Cannot run mach in a path with Unicode characters.') 233 | print('Current path:', topdir) 234 | sys.exit(1) 235 | 236 | # We don't support paths with spaces for now 237 | # https://github.com/servo/servo/issues/9442 238 | if ' ' in topdir: 239 | print('Cannot run mach in a path with spaces.') 240 | print('Current path:', topdir) 241 | sys.exit(1) 242 | 243 | # Ensure we are running Python 2.7+. We put this check here so we generate a 244 | # user-friendly error message rather than a cryptic stack trace on module import. 245 | if not (3, 0) > sys.version_info >= (2, 7): 246 | print('Python 2.7 or above (but not Python 3) is required to run mach.') 247 | print('You are running Python', platform.python_version()) 248 | sys.exit(1) 249 | 250 | # See if we're inside a Firefox checkout. 251 | parentdir = os.path.normpath(os.path.join(topdir, '..')) 252 | is_firefox = os.path.isfile(os.path.join(parentdir, 253 | 'build/mach_bootstrap.py')) 254 | 255 | _activate_virtualenv(topdir, is_firefox) 256 | 257 | def populate_context(context, key=None): 258 | if key is None: 259 | return 260 | if key == 'topdir': 261 | return topdir 262 | raise AttributeError(key) 263 | 264 | sys.path[0:0] = [os.path.join(topdir, path) for path in SEARCH_PATHS] 265 | 266 | sys.path[0:0] = [wpt_path(is_firefox, topdir), 267 | wpt_harness_path(is_firefox, topdir)] 268 | 269 | import mach.main 270 | mach = mach.main.Mach(os.getcwd()) 271 | mach.populate_context_handler = populate_context 272 | 273 | for category, meta in CATEGORIES.items(): 274 | mach.define_category(category, meta['short'], meta['long'], meta['priority']) 275 | 276 | for path in MACH_MODULES: 277 | mach.load_commands_from_file(os.path.join(topdir, path)) 278 | 279 | return mach 280 | -------------------------------------------------------------------------------- /python/mach_bootstrap.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/mach_bootstrap.pyc -------------------------------------------------------------------------------- /python/requirements-salt.txt: -------------------------------------------------------------------------------- 1 | # Ensure all versions are pinned for repeatability, 2 | # since `--system-site-packages` is enabled 3 | 4 | # For boostrapping, make sure versions match those in saltfs 5 | salt == 2016.3.4 6 | GitPython == 0.3.2 7 | -------------------------------------------------------------------------------- /python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Ensure all versions are pinned for repeatability, 2 | # since `--system-site-packages` is enabled 3 | 4 | blessings == 1.6 5 | mach == 0.6.0 6 | mozdebug == 0.1 7 | mozinfo == 0.8 8 | mozlog == 3.3 9 | setuptools == 18.5 10 | toml == 0.9.2 11 | Mako == 1.0.4 12 | 13 | # For Python linting 14 | flake8 == 2.4.1 15 | pep8 == 1.5.7 16 | pyflakes == 0.8.1 17 | 18 | # For buildbot checking 19 | PyYAML == 3.12 20 | 21 | # For test-webidl 22 | ply == 3.8 23 | 24 | # For Cross-platform colored terminal text 25 | colorama == 0.3.7 26 | 27 | # For package uploading 28 | boto3 == 1.4.4 29 | 30 | -e python/tidy 31 | -------------------------------------------------------------------------------- /python/servo/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | -------------------------------------------------------------------------------- /python/servo/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/__init__.pyc -------------------------------------------------------------------------------- /python/servo/bootstrap.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | from __future__ import absolute_import, print_function 6 | 7 | from distutils.spawn import find_executable 8 | from distutils.version import LooseVersion 9 | import json 10 | import os 11 | import platform 12 | import shutil 13 | import subprocess 14 | from subprocess import PIPE 15 | 16 | import servo.packages as packages 17 | from servo.util import extract, download_file, host_triple 18 | 19 | 20 | def run_as_root(command): 21 | if os.geteuid() != 0: 22 | command.insert(0, 'sudo') 23 | return subprocess.call(command) 24 | 25 | 26 | def install_salt_dependencies(context, force): 27 | install = False 28 | if context.distro == 'Ubuntu': 29 | pkgs = ['build-essential', 'libssl-dev', 'libffi-dev', 'python-dev'] 30 | command = ['apt-get', 'install'] 31 | if subprocess.call(['dpkg', '-s'] + pkgs, stdout=PIPE, stderr=PIPE) != 0: 32 | install = True 33 | elif context.distro in ['CentOS', 'CentOS Linux', 'Fedora']: 34 | installed_pkgs = str(subprocess.check_output(['rpm', '-qa'])).replace('\n', '|') 35 | pkgs = ['gcc', 'libffi-devel', 'python-devel', 'openssl-devel'] 36 | for p in pkgs: 37 | command = ['dnf', 'install'] 38 | if "|{}".format(p) not in installed_pkgs: 39 | install = True 40 | break 41 | 42 | if install: 43 | if force: 44 | command.append('-y') 45 | print("Installing missing Salt dependencies...") 46 | run_as_root(command + pkgs) 47 | 48 | 49 | def salt(context, force=False): 50 | # Ensure Salt dependencies are installed 51 | install_salt_dependencies(context, force) 52 | # Ensure Salt is installed in the virtualenv 53 | # It's not instaled globally because it's a large, non-required dependency, 54 | # and the installation fails on Windows 55 | print("Checking Salt installation...", end='') 56 | reqs_path = os.path.join(context.topdir, 'python', 'requirements-salt.txt') 57 | process = subprocess.Popen( 58 | ["pip", "install", "-q", "-I", "-r", reqs_path], 59 | stdout=PIPE, 60 | stderr=PIPE 61 | ) 62 | process.wait() 63 | if process.returncode: 64 | out, err = process.communicate() 65 | print('failed to install Salt via pip:') 66 | print('Output: {}\nError: {}'.format(out, err)) 67 | return 1 68 | print("done") 69 | 70 | salt_root = os.path.join(context.sharedir, 'salt') 71 | config_dir = os.path.join(salt_root, 'etc', 'salt') 72 | pillar_dir = os.path.join(config_dir, 'pillars') 73 | 74 | # In order to allow `mach bootstrap` to work from any CWD, 75 | # the `root_dir` must be an absolute path. 76 | # We place it under `context.sharedir` because 77 | # Salt caches data (e.g. gitfs files) in its `var` subdirectory. 78 | # Hence, dynamically generate the config with an appropriate `root_dir` 79 | # and serialize it as JSON (which is valid YAML). 80 | config = { 81 | 'hash_type': 'sha384', 82 | 'master': 'localhost', 83 | 'root_dir': salt_root, 84 | 'state_output': 'changes', 85 | 'state_tabular': True, 86 | } 87 | if 'SERVO_SALTFS_ROOT' in os.environ: 88 | config.update({ 89 | 'fileserver_backend': ['roots'], 90 | 'file_roots': { 91 | 'base': [os.path.abspath(os.environ['SERVO_SALTFS_ROOT'])], 92 | }, 93 | }) 94 | else: 95 | config.update({ 96 | 'fileserver_backend': ['git'], 97 | 'gitfs_env_whitelist': 'base', 98 | 'gitfs_provider': 'gitpython', 99 | 'gitfs_remotes': [ 100 | 'https://github.com/servo/saltfs.git', 101 | ], 102 | }) 103 | 104 | if not os.path.exists(config_dir): 105 | os.makedirs(config_dir, mode=0o700) 106 | with open(os.path.join(config_dir, 'minion'), 'w') as config_file: 107 | config_file.write(json.dumps(config) + '\n') 108 | 109 | # Similarly, the pillar data is created dynamically 110 | # and temporarily serialized to disk. 111 | # This dynamism is not yet used, but will be in the future 112 | # to enable Android bootstrapping by using 113 | # context.sharedir as a location for Android packages. 114 | pillar = { 115 | 'top.sls': { 116 | 'base': { 117 | '*': ['bootstrap'], 118 | }, 119 | }, 120 | 'bootstrap.sls': { 121 | 'fully_managed': False, 122 | }, 123 | } 124 | if os.path.exists(pillar_dir): 125 | shutil.rmtree(pillar_dir) 126 | os.makedirs(pillar_dir, mode=0o700) 127 | for filename in pillar: 128 | with open(os.path.join(pillar_dir, filename), 'w') as pillar_file: 129 | pillar_file.write(json.dumps(pillar[filename]) + '\n') 130 | 131 | cmd = [ 132 | # sudo escapes from the venv, need to use full path 133 | find_executable('salt-call'), 134 | '--local', 135 | '--config-dir={}'.format(config_dir), 136 | '--pillar-root={}'.format(pillar_dir), 137 | 'state.apply', 138 | 'servo-build-dependencies', 139 | ] 140 | 141 | if not force: 142 | print('Running bootstrap in dry-run mode to show changes') 143 | # Because `test=True` mode runs each state individually without 144 | # considering how required/previous states affect the system, 145 | # it will often report states with requisites as failing due 146 | # to the requisites not actually being run, 147 | # even though these are spurious and will succeed during 148 | # the actual highstate. 149 | # Hence `--retcode-passthrough` is not helpful in dry-run mode, 150 | # so only detect failures of the actual salt-call binary itself. 151 | retcode = run_as_root(cmd + ['test=True']) 152 | if retcode != 0: 153 | print('Something went wrong while bootstrapping') 154 | return retcode 155 | 156 | proceed = raw_input( 157 | 'Proposed changes are above, proceed with bootstrap? [y/N]: ' 158 | ) 159 | if proceed.lower() not in ['y', 'yes']: 160 | return 0 161 | 162 | print('') 163 | 164 | print('Running Salt bootstrap') 165 | retcode = run_as_root(cmd + ['--retcode-passthrough']) 166 | if retcode == 0: 167 | print('Salt bootstrapping complete') 168 | else: 169 | print('Salt bootstrapping encountered errors') 170 | return retcode 171 | 172 | 173 | def windows_msvc(context, force=False): 174 | '''Bootstrapper for MSVC building on Windows.''' 175 | 176 | deps_dir = os.path.join(context.sharedir, "msvc-dependencies") 177 | deps_url = "https://servo-deps.s3.amazonaws.com/msvc-deps/" 178 | 179 | def version(package): 180 | return packages.WINDOWS_MSVC[package] 181 | 182 | def package_dir(package): 183 | return os.path.join(deps_dir, package, version(package)) 184 | 185 | def check_cmake(version): 186 | cmake_path = find_executable("cmake") 187 | if cmake_path: 188 | cmake = subprocess.Popen([cmake_path, "--version"], stdout=PIPE) 189 | cmake_version = cmake.stdout.read().splitlines()[0].replace("cmake version ", "") 190 | if LooseVersion(cmake_version) >= LooseVersion(version): 191 | return True 192 | return False 193 | 194 | to_install = {} 195 | for package in packages.WINDOWS_MSVC: 196 | # Don't install CMake if it already exists in PATH 197 | if package == "cmake" and check_cmake(version("cmake")): 198 | continue 199 | 200 | if not os.path.isdir(package_dir(package)): 201 | to_install[package] = version(package) 202 | 203 | if not to_install: 204 | return 0 205 | 206 | print("Installing missing MSVC dependencies...") 207 | for package in to_install: 208 | full_spec = '{}-{}'.format(package, version(package)) 209 | 210 | parent_dir = os.path.dirname(package_dir(package)) 211 | if not os.path.isdir(parent_dir): 212 | os.makedirs(parent_dir) 213 | 214 | zip_path = package_dir(package) + ".zip" 215 | if not os.path.isfile(zip_path): 216 | zip_url = "{}{}.zip".format(deps_url, full_spec) 217 | download_file(full_spec, zip_url, zip_path) 218 | 219 | print("Extracting {}...".format(full_spec), end='') 220 | extract(zip_path, deps_dir) 221 | print("done") 222 | 223 | extracted_path = os.path.join(deps_dir, full_spec) 224 | os.rename(extracted_path, package_dir(package)) 225 | 226 | return 0 227 | 228 | 229 | def bootstrap(context, force=False): 230 | '''Dispatches to the right bootstrapping function for the OS.''' 231 | 232 | bootstrapper = None 233 | 234 | if "windows-msvc" in host_triple(): 235 | bootstrapper = windows_msvc 236 | elif "linux-gnu" in host_triple(): 237 | distro, version, _ = platform.linux_distribution() 238 | if distro.lower() in [ 239 | 'centos', 240 | 'centos linux', 241 | 'debian', 242 | 'fedora', 243 | 'ubuntu', 244 | ]: 245 | context.distro = distro 246 | bootstrapper = salt 247 | 248 | if bootstrapper is None: 249 | print('Bootstrap support is not yet available for your OS.') 250 | return 1 251 | 252 | return bootstrapper(context, force=force) 253 | -------------------------------------------------------------------------------- /python/servo/bootstrap.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/bootstrap.pyc -------------------------------------------------------------------------------- /python/servo/bootstrap_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/bootstrap_commands.pyc -------------------------------------------------------------------------------- /python/servo/build_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/build_commands.pyc -------------------------------------------------------------------------------- /python/servo/command_base.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/command_base.pyc -------------------------------------------------------------------------------- /python/servo/devenv_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/devenv_commands.pyc -------------------------------------------------------------------------------- /python/servo/lints/wpt_lint.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | import os 11 | import sys 12 | 13 | from servo_tidy.tidy import LintRunner, filter_file 14 | 15 | WPT_PATH = os.path.join(".", "tests", "wpt") 16 | SUITES = ["web-platform-tests", os.path.join("mozilla", "tests")] 17 | 18 | 19 | class Lint(LintRunner): 20 | def _get_wpt_files(self, suite): 21 | working_dir = os.path.join(WPT_PATH, suite, '') 22 | file_iter = self.get_files(working_dir, exclude_dirs=[]) 23 | print '\nRunning the WPT lint on %s...' % working_dir 24 | for f in file_iter: 25 | if filter_file(f): 26 | yield f[len(working_dir):] 27 | 28 | def run(self): 29 | if self.stylo: 30 | return 31 | 32 | wpt_working_dir = os.path.abspath(os.path.join(WPT_PATH, "web-platform-tests")) 33 | for suite in SUITES: 34 | files = self._get_wpt_files(suite) 35 | sys.path.insert(0, wpt_working_dir) 36 | from tools.lint import lint 37 | sys.path.remove(wpt_working_dir) 38 | file_dir = os.path.abspath(os.path.join(WPT_PATH, suite)) 39 | returncode = lint.lint(file_dir, list(files), output_format="json", css_mode=False) 40 | if returncode: 41 | yield ("WPT Lint Tool", "", "lint error(s) in Web Platform Tests: exit status %s" % returncode) 42 | -------------------------------------------------------------------------------- /python/servo/lints/wpt_lint.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/lints/wpt_lint.pyc -------------------------------------------------------------------------------- /python/servo/package_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/package_commands.pyc -------------------------------------------------------------------------------- /python/servo/packages.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | # You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | WINDOWS_MSVC = { 6 | "cmake": "3.7.2", 7 | "moztools": "0.0.1-5", 8 | "ninja": "1.7.1", 9 | "openssl": "1.1.0e-vs2015", 10 | } 11 | -------------------------------------------------------------------------------- /python/servo/packages.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/packages.pyc -------------------------------------------------------------------------------- /python/servo/post_build_commands.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | from __future__ import print_function, unicode_literals 11 | 12 | import os 13 | import os.path as path 14 | import subprocess 15 | from shutil import copytree, rmtree, copy2 16 | 17 | from mach.registrar import Registrar 18 | 19 | from mach.decorators import ( 20 | CommandArgument, 21 | CommandProvider, 22 | Command, 23 | ) 24 | 25 | from servo.command_base import ( 26 | CommandBase, 27 | call, check_call, 28 | is_linux, is_windows, is_macosx, set_osmesa_env, 29 | get_browserhtml_path, 30 | ) 31 | 32 | 33 | def read_file(filename, if_exists=False): 34 | if if_exists and not path.exists(filename): 35 | return None 36 | with open(filename) as f: 37 | return f.read() 38 | 39 | 40 | @CommandProvider 41 | class PostBuildCommands(CommandBase): 42 | @Command('run', 43 | description='Run Servo', 44 | category='post-build') 45 | @CommandArgument('--release', '-r', action='store_true', 46 | help='Run the release build') 47 | @CommandArgument('--dev', '-d', action='store_true', 48 | help='Run the dev build') 49 | @CommandArgument('--android', action='store_true', default=None, 50 | help='Run on an Android device through `adb shell`') 51 | @CommandArgument('--debug', action='store_true', 52 | help='Enable the debugger. Not specifying a ' 53 | '--debugger option will result in the default ' 54 | 'debugger being used. The following arguments ' 55 | 'have no effect without this.') 56 | @CommandArgument('--debugger', default=None, type=str, 57 | help='Name of debugger to use.') 58 | @CommandArgument('--browserhtml', '-b', action='store_true', 59 | help='Launch with Browser.html') 60 | @CommandArgument('--headless', '-z', action='store_true', 61 | help='Launch in headless mode') 62 | @CommandArgument('--software', '-s', action='store_true', 63 | help='Launch with software rendering') 64 | @CommandArgument( 65 | 'params', nargs='...', 66 | help="Command-line arguments to be passed through to Servo") 67 | def run(self, params, release=False, dev=False, android=None, debug=False, debugger=None, browserhtml=False, 68 | headless=False, software=False): 69 | env = self.build_env() 70 | env["RUST_BACKTRACE"] = "1" 71 | 72 | # Make --debugger imply --debug 73 | if debugger: 74 | debug = True 75 | 76 | if android is None: 77 | android = self.config["build"]["android"] 78 | 79 | if android: 80 | if debug: 81 | print("Android on-device debugging is not supported by mach yet. See") 82 | print("https://github.com/servo/servo/wiki/Building-for-Android#debugging-on-device") 83 | return 84 | script = [ 85 | "am force-stop com.mozilla.servo", 86 | "echo servo >/sdcard/Android/data/com.mozilla.servo/files/android_params" 87 | ] 88 | for param in params: 89 | script += [ 90 | "echo '%s' >>/sdcard/Android/data/com.mozilla.servo/files/android_params" 91 | % param.replace("'", "\\'") 92 | ] 93 | script += [ 94 | "am start com.mozilla.servo/com.mozilla.servo.MainActivity", 95 | "exit" 96 | ] 97 | shell = subprocess.Popen(["adb", "shell"], stdin=subprocess.PIPE) 98 | shell.communicate("\n".join(script) + "\n") 99 | return shell.wait() 100 | 101 | args = [self.get_binary_path(release, dev)] 102 | 103 | if browserhtml: 104 | browserhtml_path = get_browserhtml_path(args[0]) 105 | if is_macosx(): 106 | # Enable borderless on OSX 107 | args = args + ['-b'] 108 | elif is_windows(): 109 | # Convert to a relative path to avoid mingw -> Windows path conversions 110 | browserhtml_path = path.relpath(browserhtml_path, os.getcwd()) 111 | 112 | args = args + ['--pref', 'dom.mozbrowser.enabled', 113 | '--pref', 'dom.forcetouch.enabled', 114 | '--pref', 'shell.builtin-key-shortcuts.enabled=false', 115 | path.join(browserhtml_path, 'index.html')] 116 | 117 | if headless: 118 | set_osmesa_env(args[0], env) 119 | args.append('-z') 120 | 121 | if software: 122 | if not is_linux(): 123 | print("Software rendering is only supported on Linux at the moment.") 124 | return 125 | 126 | env['LIBGL_ALWAYS_SOFTWARE'] = "1" 127 | 128 | # Borrowed and modified from: 129 | # http://hg.mozilla.org/mozilla-central/file/c9cfa9b91dea/python/mozbuild/mozbuild/mach_commands.py#l883 130 | if debug: 131 | import mozdebug 132 | if not debugger: 133 | # No debugger name was provided. Look for the default ones on 134 | # current OS. 135 | debugger = mozdebug.get_default_debugger_name( 136 | mozdebug.DebuggerSearch.KeepLooking) 137 | 138 | self.debuggerInfo = mozdebug.get_debugger_info(debugger) 139 | if not self.debuggerInfo: 140 | print("Could not find a suitable debugger in your PATH.") 141 | return 1 142 | 143 | command = self.debuggerInfo.path 144 | if debugger == 'gdb' or debugger == 'lldb': 145 | rustCommand = 'rust-' + debugger 146 | try: 147 | subprocess.check_call([rustCommand, '--version'], env=env, stdout=open(os.devnull, 'w')) 148 | except (OSError, subprocess.CalledProcessError): 149 | pass 150 | else: 151 | command = rustCommand 152 | 153 | # Prepend the debugger args. 154 | args = ([command] + self.debuggerInfo.args + 155 | args + params) 156 | else: 157 | args = args + params 158 | 159 | try: 160 | check_call(args, env=env) 161 | except subprocess.CalledProcessError as e: 162 | print("Servo exited with return value %d" % e.returncode) 163 | return e.returncode 164 | except OSError as e: 165 | if e.errno == 2: 166 | print("Servo Binary can't be found! Run './mach build'" 167 | " and try again!") 168 | else: 169 | raise e 170 | 171 | @Command('rr-record', 172 | description='Run Servo whilst recording execution with rr', 173 | category='post-build') 174 | @CommandArgument('--release', '-r', action='store_true', 175 | help='Use release build') 176 | @CommandArgument('--dev', '-d', action='store_true', 177 | help='Use dev build') 178 | @CommandArgument( 179 | 'params', nargs='...', 180 | help="Command-line arguments to be passed through to Servo") 181 | def rr_record(self, release=False, dev=False, params=[]): 182 | env = self.build_env() 183 | env["RUST_BACKTRACE"] = "1" 184 | 185 | servo_cmd = [self.get_binary_path(release, dev)] + params 186 | rr_cmd = ['rr', '--fatal-errors', 'record'] 187 | try: 188 | check_call(rr_cmd + servo_cmd) 189 | except OSError as e: 190 | if e.errno == 2: 191 | print("rr binary can't be found!") 192 | else: 193 | raise e 194 | 195 | @Command('rr-replay', 196 | description='Replay the most recent execution of Servo that was recorded with rr', 197 | category='post-build') 198 | def rr_replay(self): 199 | try: 200 | check_call(['rr', '--fatal-errors', 'replay']) 201 | except OSError as e: 202 | if e.errno == 2: 203 | print("rr binary can't be found!") 204 | else: 205 | raise e 206 | 207 | @Command('doc', 208 | description='Generate documentation', 209 | category='post-build') 210 | @CommandArgument( 211 | 'params', nargs='...', 212 | help="Command-line arguments to be passed through to cargo doc") 213 | def doc(self, params): 214 | self.ensure_bootstrapped() 215 | if not path.exists(path.join(self.config["tools"]["rust-root"], "doc")): 216 | Registrar.dispatch("bootstrap-rust-docs", context=self.context) 217 | rust_docs = path.join(self.config["tools"]["rust-root"], "doc") 218 | docs = path.join(self.get_target_dir(), "doc") 219 | if not path.exists(docs): 220 | os.makedirs(docs) 221 | 222 | if read_file(path.join(docs, "version_info.html"), if_exists=True) != \ 223 | read_file(path.join(rust_docs, "version_info.html")): 224 | print("Copying Rust documentation.") 225 | # copytree doesn't like the destination already existing. 226 | for name in os.listdir(rust_docs): 227 | if not name.startswith('.'): 228 | full_name = path.join(rust_docs, name) 229 | destination = path.join(docs, name) 230 | if path.isdir(full_name): 231 | if path.exists(destination): 232 | rmtree(destination) 233 | copytree(full_name, destination) 234 | else: 235 | copy2(full_name, destination) 236 | 237 | return call(["cargo", "doc"] + params, 238 | env=self.build_env(), cwd=self.servo_crate()) 239 | 240 | @Command('browse-doc', 241 | description='Generate documentation and open it in a web browser', 242 | category='post-build') 243 | def serve_docs(self): 244 | self.doc([]) 245 | import webbrowser 246 | webbrowser.open("file://" + path.abspath(path.join( 247 | self.get_target_dir(), "doc", "servo", "index.html"))) 248 | -------------------------------------------------------------------------------- /python/servo/post_build_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/post_build_commands.pyc -------------------------------------------------------------------------------- /python/servo/servo-binary-formula.rb.in: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | class ServoBin < Formula 6 | desc "Servo, the Parallel Browser Engine Project (binary version)" 7 | homepage "http://servo.org" 8 | url "PACKAGEURL" 9 | version "VERSION" 10 | sha256 "SHA" 11 | 12 | bottle :unneeded 13 | 14 | def install 15 | prefix.install "bin", "libexec", "resources" 16 | end 17 | 18 | test do 19 | system bin/"servo", "-o", "/dev/null", "-x", "http://example.com" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /python/servo/testing_commands.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/testing_commands.pyc -------------------------------------------------------------------------------- /python/servo/util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | from __future__ import absolute_import, print_function, unicode_literals 11 | 12 | import os 13 | import os.path 14 | import platform 15 | import shutil 16 | from socket import error as socket_error 17 | import StringIO 18 | import sys 19 | import tarfile 20 | import zipfile 21 | import urllib2 22 | 23 | 24 | def delete(path): 25 | if os.path.isdir(path) and not os.path.islink(path): 26 | shutil.rmtree(path) 27 | else: 28 | os.remove(path) 29 | 30 | 31 | def host_platform(): 32 | os_type = platform.system().lower() 33 | if os_type == "linux": 34 | os_type = "unknown-linux-gnu" 35 | elif os_type == "darwin": 36 | os_type = "apple-darwin" 37 | elif os_type == "android": 38 | os_type = "linux-androideabi" 39 | elif os_type == "windows": 40 | # If we are in a Visual Studio environment, use msvc 41 | if os.getenv("PLATFORM") is not None: 42 | os_type = "pc-windows-msvc" 43 | else: 44 | os_type = "unknown" 45 | elif os_type == "freebsd": 46 | os_type = "unknown-freebsd" 47 | else: 48 | os_type = "unknown" 49 | return os_type 50 | 51 | 52 | def host_triple(): 53 | os_type = host_platform() 54 | cpu_type = platform.machine().lower() 55 | if os_type.endswith("-msvc"): 56 | # vcvars*.bat should set it properly 57 | platform_env = os.environ.get("PLATFORM").upper() 58 | if platform_env == "X86": 59 | cpu_type = "i686" 60 | elif platform_env == "X64": 61 | cpu_type = "x86_64" 62 | else: 63 | cpu_type = "unknown" 64 | elif cpu_type in ["i386", "i486", "i686", "i768", "x86"]: 65 | cpu_type = "i686" 66 | elif cpu_type in ["x86_64", "x86-64", "x64", "amd64"]: 67 | cpu_type = "x86_64" 68 | elif cpu_type == "arm": 69 | cpu_type = "arm" 70 | elif cpu_type == "aarch64": 71 | cpu_type = "aarch64" 72 | else: 73 | cpu_type = "unknown" 74 | 75 | return "{}-{}".format(cpu_type, os_type) 76 | 77 | 78 | def download(desc, src, writer, start_byte=0): 79 | if start_byte: 80 | print("Resuming download of {}...".format(desc)) 81 | else: 82 | print("Downloading {}...".format(desc)) 83 | dumb = (os.environ.get("TERM") == "dumb") or (not sys.stdout.isatty()) 84 | 85 | try: 86 | req = urllib2.Request(src) 87 | if start_byte: 88 | req = urllib2.Request(src, headers={'Range': 'bytes={}-'.format(start_byte)}) 89 | resp = urllib2.urlopen(req) 90 | 91 | fsize = None 92 | if resp.info().getheader('Content-Length'): 93 | fsize = int(resp.info().getheader('Content-Length').strip()) + start_byte 94 | 95 | recved = start_byte 96 | chunk_size = 8192 97 | 98 | while True: 99 | chunk = resp.read(chunk_size) 100 | if not chunk: 101 | break 102 | recved += len(chunk) 103 | if not dumb: 104 | if fsize is not None: 105 | pct = recved * 100.0 / fsize 106 | print("\rDownloading %s: %5.1f%%" % (desc, pct), end="") 107 | 108 | sys.stdout.flush() 109 | writer.write(chunk) 110 | 111 | if not dumb: 112 | print() 113 | except urllib2.HTTPError, e: 114 | print("Download failed ({}): {} - {}".format(e.code, e.reason, src)) 115 | if e.code == 403: 116 | print("No Rust compiler binary available for this platform. " 117 | "Please see https://github.com/servo/servo/#prerequisites") 118 | sys.exit(1) 119 | except urllib2.URLError, e: 120 | print("Error downloading {}: {}. The failing URL was: {}".format(desc, e.reason, src)) 121 | sys.exit(1) 122 | except socket_error, e: 123 | print("Looks like there's a connectivity issue, check your Internet connection. {}".format(e)) 124 | sys.exit(1) 125 | except KeyboardInterrupt: 126 | writer.flush() 127 | raise 128 | 129 | 130 | def download_bytes(desc, src): 131 | content_writer = StringIO.StringIO() 132 | download(desc, src, content_writer) 133 | return content_writer.getvalue() 134 | 135 | 136 | def download_file(desc, src, dst): 137 | tmp_path = dst + ".part" 138 | try: 139 | start_byte = os.path.getsize(tmp_path) 140 | with open(tmp_path, 'ab') as fd: 141 | download(desc, src, fd, start_byte=start_byte) 142 | except os.error: 143 | with open(tmp_path, 'wb') as fd: 144 | download(desc, src, fd) 145 | os.rename(tmp_path, dst) 146 | 147 | 148 | def extract(src, dst, movedir=None): 149 | if src.endswith(".zip"): 150 | zipfile.ZipFile(src).extractall(dst) 151 | else: 152 | tarfile.open(src).extractall(dst) 153 | 154 | if movedir: 155 | for f in os.listdir(movedir): 156 | frm = os.path.join(movedir, f) 157 | to = os.path.join(dst, f) 158 | os.rename(frm, to) 159 | os.rmdir(movedir) 160 | 161 | os.remove(src) 162 | -------------------------------------------------------------------------------- /python/servo/util.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/servo/util.pyc -------------------------------------------------------------------------------- /python/servo/win32_toast.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | from win32api import GetModuleHandle 11 | from win32gui import WNDCLASS, RegisterClass, CreateWindow, UpdateWindow 12 | from win32gui import DestroyWindow, LoadIcon, NIF_ICON, NIF_MESSAGE, NIF_TIP 13 | from win32gui import Shell_NotifyIcon, NIM_ADD, NIM_MODIFY, NIF_INFO, NIIF_INFO 14 | import win32con 15 | 16 | 17 | class WindowsToast: 18 | def __init__(self): 19 | # Register window class; it's okay to do this multiple times 20 | wc = WNDCLASS() 21 | wc.lpszClassName = 'ServoTaskbarNotification' 22 | wc.lpfnWndProc = {win32con.WM_DESTROY: self.OnDestroy, } 23 | self.classAtom = RegisterClass(wc) 24 | self.hinst = wc.hInstance = GetModuleHandle(None) 25 | 26 | def OnDestroy(self, hwnd, msg, wparam, lparam): 27 | # We don't have to Shell_NotifyIcon to delete it, since 28 | # we destroyed 29 | pass 30 | 31 | def balloon_tip(self, title, msg): 32 | style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU 33 | hwnd = CreateWindow(self.classAtom, "Taskbar", style, 0, 0, 34 | win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 35 | 0, 0, self.hinst, None) 36 | UpdateWindow(hwnd) 37 | 38 | hicon = LoadIcon(0, win32con.IDI_APPLICATION) 39 | 40 | nid = (hwnd, 0, NIF_ICON | NIF_MESSAGE | NIF_TIP, win32con.WM_USER + 20, hicon, 'Tooltip') 41 | Shell_NotifyIcon(NIM_ADD, nid) 42 | nid = (hwnd, 0, NIF_INFO, win32con.WM_USER + 20, hicon, 'Balloon Tooltip', msg, 200, title, NIIF_INFO) 43 | Shell_NotifyIcon(NIM_MODIFY, nid) 44 | 45 | DestroyWindow(hwnd) 46 | -------------------------------------------------------------------------------- /python/tidy/HISTORY.rst: -------------------------------------------------------------------------------- 1 | Release History 2 | --------------- 3 | 4 | 0.3.0 (2017-02-24) 5 | ++++++++++++++++++ 6 | 7 | - Added checking for blocked packages 8 | - Added checking for alphabetical order for JSON keys and ``#![feature(...)]`` 9 | - Improved duplicated packages checking 10 | - Improved ordering ``use`` statements 11 | - Allow tidy to run custom project-specific lints 12 | - And many other improvements 13 | 14 | 0.2.0 (2016-08-09) 15 | ++++++++++++++++++ 16 | 17 | - Improve license checking to disregard comments and line breaks 18 | - License checking verifies that COPYRIGHT is specified when apache2 is used 19 | 20 | 0.0.3 (2016-04-19) 21 | ++++++++++++++++++ 22 | 23 | - Add alternate wording of apache2 license 24 | 25 | 0.0.2 (2016-04-17) 26 | ++++++++++++++++++ 27 | - Cleanup Tidy to work on external deps 28 | 29 | 0.0.1 (2016-04-12) 30 | ++++++++++++++++++ 31 | - Package Tidy 32 | -------------------------------------------------------------------------------- /python/tidy/Makefile: -------------------------------------------------------------------------------- 1 | PYTHON := python 2 | VENV := env-$(PYTHON) 3 | 4 | # for travis 5 | 6 | $(VENV)/bin/python: 7 | [ -d $(VENV) ] || $(PYTHON) -m virtualenv $(VENV) || virtualenv $(VENV) 8 | $(VENV)/bin/pip install --upgrade setuptools 9 | $(VENV)/bin/python setup.py develop 10 | 11 | 12 | .PHONY: dev-env 13 | dev-env: $(VENV)/bin/python 14 | 15 | 16 | # for testing 17 | .PHONY: test 18 | test: dev-env 19 | $(VENV)/bin/python -m unittest discover -s servo_tidy_tests -v 20 | 21 | 22 | .PHONY: clean 23 | clean: 24 | find . -name "*.pyc" -type f -delete 25 | rm -rf $(VENV) 26 | -------------------------------------------------------------------------------- /python/tidy/README.rst: -------------------------------------------------------------------------------- 1 | servo_tidy 2 | ========== 3 | 4 | Servo's code and license checker. 5 | 6 | Installation 7 | ++++++++++++ 8 | 9 | Install from PyPI: 10 | 11 | :: 12 | 13 | pip install servo-tidy 14 | 15 | or from git: 16 | 17 | :: 18 | 19 | pip install -e git+https://github.com/servo/servo.git#egg=servo_tidy&subdirectory=python/tidy 20 | 21 | To run the tests 22 | ++++++++++++++++ 23 | 24 | :: 25 | 26 | ./mach test-tidy --self-test 27 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy/__init__.pyc -------------------------------------------------------------------------------- /python/tidy/servo_tidy/licenseck.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | MPL = """\ 11 | This Source Code Form is subject to the terms of the Mozilla Public \ 12 | License, v. 2.0. If a copy of the MPL was not distributed with this \ 13 | file, You can obtain one at http://mozilla.org/MPL/2.0/.\ 14 | """ 15 | 16 | APACHE = """\ 17 | Licensed under the Apache License, Version 2.0 or the MIT license \ 19 | , at your \ 20 | option. This file may not be copied, modified, or distributed \ 21 | except according to those terms.\ 22 | """ 23 | 24 | COPYRIGHT = [ 25 | "See the COPYRIGHT file at the top-level directory of this distribution", 26 | "See http://rust-lang.org/COPYRIGHT", 27 | ] 28 | 29 | # The valid licenses, in the form we'd expect to see them in a Cargo.toml file. 30 | licenses_toml = [ 31 | 'license = "MPL-2.0"', 32 | 'license = "MIT/Apache-2.0"', 33 | ] 34 | 35 | # The valid dependency licenses, in the form we'd expect to see them in a Cargo.toml file. 36 | licenses_dep_toml = [ 37 | # Licenses that are compatible with Servo's licensing 38 | 'license = "Apache-2 / MIT"', 39 | 'license = "Apache-2.0 / MIT"', 40 | 'license = "Apache-2.0"', 41 | 'license = "Apache-2.0/MIT"', 42 | 'license = "BSD-2-Clause"', 43 | 'license = "BSD-3-Clause"', 44 | 'license = "BSD-3-Clause/MIT"', 45 | 'license = "CC0-1.0"', 46 | 'license = "ISC"', 47 | 'license = "MIT / Apache-2.0"', 48 | 'license = "MIT OR Apache-2.0"', 49 | 'license = "MIT"', 50 | 'license = "MIT/Apache-2.0"', 51 | 'license = "MPL-2.0"', 52 | 'license = "Unlicense/MIT"', 53 | 'license = "zlib-acknowledgement"', 54 | 'license-file = "LICENSE-MIT"', 55 | 'license= "MIT / Apache-2.0"', 56 | # Whitelisted crates whose licensing has been checked manually 57 | 'name = "device"', 58 | 'name = "dylib"', 59 | 'name = "ipc-channel"', 60 | 'name = "mozjs_sys"', 61 | 'name = "azure"', 62 | 'name = "freetype"', 63 | 'name = "js"', 64 | 'name = "servo-freetype-sys"', 65 | 'name = "simd"', 66 | 'name = "webrender"', 67 | 'name = "webrender_api"', 68 | ] 69 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy/licenseck.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy/licenseck.pyc -------------------------------------------------------------------------------- /python/tidy/servo_tidy/tidy.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy/tidy.pyc -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test" 3 | version = "0.0.1" 4 | authors = ["The Servo Project Developers"] 5 | publish = false 6 | 7 | [dependencies] 8 | test-package = { version = "*" } 9 | 10 | [lib] 11 | path = "lib.rs" -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/__init__.pyc -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/apache2_license.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 or the MIT license 3 | // , at your 4 | // option. This file may not be copied, modified, or distributed 5 | // except according to those terms. 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/ban-domrefcell.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![feature(plugin)] 6 | #![plugin(script_plugins)] 7 | 8 | extern crate script; 9 | 10 | use script::test::DOMRefCell; 11 | use script::test::JS; 12 | use script::test::Node; 13 | 14 | struct Foo { 15 | bar: DOMRefCell> 16 | //~^ ERROR Banned type DOMRefCell> detected. Use MutJS> instead 17 | } 18 | 19 | fn main() {} 20 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/ban.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![feature(plugin)] 6 | #![plugin(script_plugins)] 7 | 8 | extern crate js; 9 | 10 | use js::jsval::JSVal; 11 | use std::cell::Cell; 12 | use std::cell::UnsafeCell; 13 | 14 | struct Foo { 15 | bar: Cell, 16 | //~^ ERROR Banned type Cell detected. Use MutJS instead 17 | foo: UnsafeCell 18 | //~^ NOT AN ERROR 19 | } 20 | 21 | fn main() {} 22 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/dir_check/only_webidl/test.webidl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/dir_check/only_webidl/test.webidl -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.rs -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.test -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.webidl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/dir_check/webidl_plus/test.webidl -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/dir_check/webidl_plus/test2.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/dir_check/webidl_plus/test2.rs -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/duplicate_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "value", 3 | "other_key": { 4 | "the_duplicated_key": 1, 5 | "the_duplicated_key": 2 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/duplicate_keys_buildbot_steps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | duplicate_yaml_key: 3 | - value1 4 | other_key: 5 | - value2 6 | duplicate_yaml_key: 7 | - value3 8 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/duplicated_package.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "servo" 3 | version = "0.0.1" 4 | 5 | [[package]] 6 | name = "test" 7 | version = "0.4.9" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | 10 | [[package]] 11 | name = "test" 12 | version = "0.5.1" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | 15 | [[package]] 16 | name = "test2" 17 | version = "0.1.0" 18 | source = "git+https://github.com/user/test2#c54edsf" 19 | dependencies = [ 20 | "test 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", 21 | ] 22 | 23 | [[package]] 24 | name = "test3" 25 | version = "0.5.1" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | 28 | [[package]] 29 | name = "test3" 30 | version = "0.5.1" 31 | source = "git+https://github.com/user/test3#c54edsf" 32 | 33 | [[package]] 34 | name = "test4" 35 | version = "0.1.0" 36 | source = "git+https://github.com/user/test4#c54edsf" 37 | dependencies = [ 38 | "test3 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 39 | ] 40 | 41 | [[package]] 42 | name = "test5" 43 | version = "0.1.0" 44 | source = "git+https://github.com/" 45 | dependencies = [ 46 | "test3 0.5.1 (git+https://github.com/user/test3)", 47 | ] 48 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/empty_file.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/empty_file.rs -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/incorrect_license.rs: -------------------------------------------------------------------------------- 1 | /* Incorrect license here */ 2 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lib.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![feature(def)] 6 | #![feature(abc)] 7 | 8 | #![feature(abc, def, ghi)] 9 | #![feature(aaa)] 10 | 11 | #![feature(def, ghi, abc)] 12 | 13 | #![feature(ghi)] 14 | #![feature(abd, hef)] 15 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/invalid_error_tuple.py: -------------------------------------------------------------------------------- 1 | from servo_tidy.tidy import LintRunner 2 | 3 | class Lint(LintRunner): 4 | def run(self): 5 | yield None 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/no_lint.py: -------------------------------------------------------------------------------- 1 | from servo_tidy.tidy import LintRunner 2 | 3 | class Linter(LintRunner): 4 | def run(self): 5 | pass 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/no_run.py: -------------------------------------------------------------------------------- 1 | from servo_tidy.tidy import LintRunner 2 | 3 | class Lint(LintRunner): 4 | def some_method(self): 5 | pass 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/not_inherited.py: -------------------------------------------------------------------------------- 1 | class Lint(object): 2 | pass 3 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/not_script: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/lints/not_script -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/lints/proper_file.py: -------------------------------------------------------------------------------- 1 | from servo_tidy.tidy import LintRunner 2 | 3 | class Lint(LintRunner): 4 | def run(self): 5 | for _ in [None]: 6 | yield ('path', 0, 'foobar') 7 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/long_line.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | println!("really really loooooooooooooooooooooooooooooooooooooooooooong lineeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/malformed_json.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "value", 3 | "other_key": "value_with_bad_quote' 4 | } 5 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/modeline.txt: -------------------------------------------------------------------------------- 1 | # vim: set noexpandtab: 2 | // vi: et: 3 | /* ex: et: 4 | anything -*-Lisp-*- 5 | -*- mode: Lisp -*- 6 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/non_list_mapping_buildbot_steps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | non-list-key: "string string" 3 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/non_string_list_buildbot_steps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is a buildbot_steps.yml file that should break linting becasue it is not a 3 | # mapping to a list of strings 4 | mapping_key: 5 | - - list_of_list 6 | - sublist_item1 7 | - sublist_item2 8 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/rust_tidy.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use app_units::Au; 6 | use azure::azure_hl::{ AntialiasMode, Color, ColorPattern, CompositionOp }; 7 | use azure::azure_hl::{AntialiasMode, Color, 8 | ColorPattern, CompositionOp}; 9 | use euclid::Size2D; 10 | use azure::azure::AzIntSize; 11 | use azure::azure::{AzIntSize}; 12 | 13 | use std; 14 | 15 | mod paint_context; 16 | pub mod display_list; 17 | mod test::{ 18 | }; 19 | 20 | extern crate webrender_api; 21 | extern crate style_traits; 22 | 23 | #[foo = "bar,baz"] 24 | #[derive(Copy,Debug, ComputeSquaredDistance)] 25 | impl test { 26 | 27 | fn test_fun(y:f32)->f32{ 28 | let x=5; 29 | x = x-1; 30 | x = x*x; 31 | let z = match y { 32 | 1 =>2, 33 | 2 => 1, 34 | }; 35 | let z = &Vec; 36 | struct Member { 37 | member_name:"Foo" 38 | member_id:5 39 | } 40 | } 41 | 42 | fn test_fun2(y : &String, z : &Vec, r: &Root) -> () { 43 | let x = true; 44 | x 45 | && x; 46 | if x { 47 | ; 48 | } 49 | else { 50 | ; 51 | } 52 | } 53 | 54 | type Text_Fun3 = fn( i32) -> i32; 55 | 56 | fn test_fun3( y: Text_Fun3) { 57 | let (x, y) = (1, 2) // Should not trigger 58 | test_fun( x); 59 | test_fun (y); 60 | } 61 | 62 | // Should not be triggered 63 | macro_rules! test_macro ( ( $( $fun:ident = $flag:ident ; )* ) => ()); 64 | 65 | let var 66 | = "val"; 67 | 68 | fn test_fun4() 69 | { 70 | } 71 | let var = if true { 72 | "true" 73 | } else { // Should not trigger 74 | "false" 75 | } // Should not trigger 76 | 77 | if true { // Double space after keyword 78 | 42 79 | } else { 80 | let xif = 42 in { xif } // Should not trigger 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/script_thread.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // This should trigger an error. 3 | match self.documents.borrow_mut() { 4 | _ => {} 5 | } 6 | // This should trigger an error. 7 | match self.documents.borrow() { 8 | _ => {} 9 | } 10 | // This should not trigger an error. 11 | match { self.documents.borrow().find_window(id) } { 12 | => {} 13 | } 14 | // This should not trigger an error. 15 | match self.documents_status.borrow() { 16 | => {} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/servo-tidy.toml: -------------------------------------------------------------------------------- 1 | key-outside = "" 2 | 3 | [configs] 4 | skip-check-length = false 5 | skip-check-licenses = false 6 | wrong-key = false 7 | 8 | [blocked-packages] 9 | 10 | [wrong] 11 | wrong-key = true 12 | 13 | [ignore] 14 | files = [ 15 | "./fake/file.html", 16 | ] 17 | directories = [ 18 | "./fake/dir", 19 | ] 20 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/shebang_license.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This Source Code Form is subject to the terms of the Mozilla Public 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/shell_tidy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Tests tidy for shell scripts. 4 | 5 | set -o nounset 6 | 7 | # Talking about some `concept in backticks` # shouldn't trigger 8 | echo "hello world" 9 | some_var=`echo "command substitution"` 10 | another_var="$some_var" 11 | if [ -z "${some_var}" ]; then 12 | echo "should have used [[" 13 | fi 14 | [ -z "${another_var}" ] 15 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/spec.webidl: -------------------------------------------------------------------------------- 1 | /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | 7 | interface Test { 8 | [SameObject ] 9 | readonly attribute Node root; 10 | }; 11 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/speclink.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | impl SpecLinkMethods for SpecLink { 6 | amacro!("Macros inside impls should trigger spec checks.") 7 | 8 | // Method declarations should trigger spec checks. 9 | fn Test(&self) -> f32 { 10 | amacro!("Macros inside function declarations should not trigger spec checks."); 11 | if unsafe { false } { 12 | } 13 | amacro!("Even if there's weird brace counts."); 14 | 0 15 | } 16 | 17 | // A spec link. 18 | // https://example.com/ 19 | fn Foo() {} 20 | 21 | /// A spec link. 22 | /// https://example.com/ 23 | fn Foo() {} 24 | 25 | /// A spec link. 26 | /// https://example.com/ 27 | /// Doc comments are OK 28 | // Regular comments are OK 29 | #[allow(attributes_too)] 30 | fn Foo() {} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/test_ignored/whee/foo/bar.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/test_ignored/whee/foo/bar.rs -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/test_ignored/whee/test.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/test_ignored/whee/test.rs -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/test_tidy.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/python/tidy/servo_tidy_tests/test_tidy.pyc -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/unordered_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "value", 3 | "other_key": { 4 | "b": 1, 5 | "a": 2 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/whatwg_link.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | // https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-putimagedata 6 | // https://html.spec.whatwg.org/#typographic-conventions 7 | -------------------------------------------------------------------------------- /python/tidy/servo_tidy_tests/wrong_space.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | pub struct TestStruct( 6 | pub testMember1: usize, 7 | pub testMember2: bool, ); -------------------------------------------------------------------------------- /python/tidy/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | # file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 or the MIT license 6 | # , at your 7 | # option. This file may not be copied, modified, or distributed 8 | # except according to those terms. 9 | 10 | import os 11 | from setuptools import setup, find_packages 12 | 13 | 14 | VERSION = '0.3.0' 15 | 16 | install_requires = [ 17 | "flake8==2.4.1", 18 | "toml==0.9.2", 19 | "colorama==0.3.7", 20 | ] 21 | 22 | here = os.path.dirname(os.path.abspath(__file__)) 23 | # get documentation from the README and HISTORY 24 | try: 25 | with open(os.path.join(here, 'README.rst')) as doc: 26 | readme = doc.read() 27 | except: 28 | readme = '' 29 | 30 | try: 31 | with open(os.path.join(here, 'HISTORY.rst')) as doc: 32 | history = doc.read() 33 | except: 34 | history = '' 35 | 36 | long_description = readme + '\n\n' + history 37 | 38 | if __name__ == '__main__': 39 | setup( 40 | name='servo_tidy', 41 | version=VERSION, 42 | description='The servo-tidy is used to check licenses, ' 43 | 'line lengths, whitespace, flake8 on Python files, lock file versions, and more.', 44 | long_description=long_description, 45 | keywords='mozilla servo tidy ', 46 | author='The Servo Project Developers', 47 | author_email='dev-servo@lists.mozilla.org', 48 | url='https://github.com/servo/servo', 49 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), 50 | package_data={}, 51 | install_requires=install_requires, 52 | zip_safe=False, 53 | entry_points={ 54 | 'console_scripts': [ 55 | 'servo-tidy=servo_tidy.tidy:scan', 56 | ], 57 | }, 58 | ) 59 | -------------------------------------------------------------------------------- /python/tox.ini: -------------------------------------------------------------------------------- 1 | [flake8] 2 | filename = *.py 3 | max-line-length = 120 4 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2017-11-14 2 | -------------------------------------------------------------------------------- /screenshots/dark-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/dark-theme.png -------------------------------------------------------------------------------- /screenshots/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/debug.png -------------------------------------------------------------------------------- /screenshots/mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/mini.png -------------------------------------------------------------------------------- /screenshots/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/options.png -------------------------------------------------------------------------------- /screenshots/regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/regular.png -------------------------------------------------------------------------------- /screenshots/tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/tabs.png -------------------------------------------------------------------------------- /screenshots/toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/screenshots/toolbar.png -------------------------------------------------------------------------------- /servo_resources/Credits.rtf.mako: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf460 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \vieww12000\viewh15840\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0 6 | 7 | \f0\fs24 \cf0 ${version}} 8 | -------------------------------------------------------------------------------- /servo_resources/Servo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/Servo.ico -------------------------------------------------------------------------------- /servo_resources/ahem.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Ahem; 3 | src: url(ahem/AHEM____.TTF); 4 | } 5 | -------------------------------------------------------------------------------- /servo_resources/ahem/AHEM____.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/ahem/AHEM____.TTF -------------------------------------------------------------------------------- /servo_resources/ahem/Ahem.sit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/ahem/Ahem.sit -------------------------------------------------------------------------------- /servo_resources/ahem/COPIED-FROM: -------------------------------------------------------------------------------- 1 | The files in this directory are copied from http://www.w3.org/Style/CSS/Test/Fonts/Ahem/ 2 | -------------------------------------------------------------------------------- /servo_resources/ahem/COPYING: -------------------------------------------------------------------------------- 1 | The Ahem font in this directory belongs to the public domain. In 2 | jurisdictions that do not recognize public domain ownership of these 3 | files, the following Creative Commons Zero declaration applies: 4 | 5 | 6 | 7 | which is quoted below: 8 | 9 | The person who has associated a work with this document (the "Work") 10 | affirms that he or she (the "Affirmer") is the/an author or owner of 11 | the Work. The Work may be any work of authorship, including a 12 | database. 13 | 14 | The Affirmer hereby fully, permanently and irrevocably waives and 15 | relinquishes all of her or his copyright and related or neighboring 16 | legal rights in the Work available under any federal or state law, 17 | treaty or contract, including but not limited to moral rights, 18 | publicity and privacy rights, rights protecting against unfair 19 | competition and any rights protecting the extraction, dissemination 20 | and reuse of data, whether such rights are present or future, vested 21 | or contingent (the "Waiver"). The Affirmer makes the Waiver for the 22 | benefit of the public at large and to the detriment of the Affirmer's 23 | heirs or successors. 24 | 25 | The Affirmer understands and intends that the Waiver has the effect 26 | of eliminating and entirely removing from the Affirmer's control all 27 | the copyright and related or neighboring legal rights previously held 28 | by the Affirmer in the Work, to that extent making the Work freely 29 | available to the public for any and all uses and purposes without 30 | restriction of any kind, including commercial use and uses in media 31 | and formats or by methods that have not yet been invented or 32 | conceived. Should the Waiver for any reason be judged legally 33 | ineffective in any jurisdiction, the Affirmer hereby grants a free, 34 | full, permanent, irrevocable, nonexclusive and worldwide license for 35 | all her or his copyright and related or neighboring legal rights in 36 | the Work. 37 | -------------------------------------------------------------------------------- /servo_resources/ahem/README: -------------------------------------------------------------------------------- 1 | The Ahem font was developed by Todd Fahrner to help test writers 2 | develop predictable tests. The font's em square is exactly square. 3 | Its ascent and descent is exactly the size of the em square. This 4 | means that the font's extent is exactly the same as its line-height, 5 | meaning that it can be exactly aligned with padding, borders, margins, 6 | and so forth. 7 | 8 | The font's alphabetic baseline is 0.2em above its bottom, and 0.8em 9 | below its top. The font has an x-height of 0.8em. 10 | 11 | The font has four glyphs: 12 | 13 | 'X' U+0058 A square exactly 1em in height and width. 14 | 15 | 'p' U+0070 A rectangle exactly 0.2em high, 1em wide, and aligned so 16 | that its top is flush with the baseline. 17 | 18 | 'É' U+00C9 A rectangle exactly 0.8em high, 1em wide, and aligned so 19 | that its bottom is flush with the baseline. 20 | 21 | ' ' U+0020 A transparent space exactly 1em high and wide. 22 | 23 | Most other US-ASCII characters in the font have the same glyph as X. 24 | 25 | The Ahem font belongs to the public domain as described in COPYING. 26 | 27 | Acknowledgements: The font was originally created by Todd Fahrner in 28 | the late 90s, and was updated by Paul Nelson in the mid 2000s. The 29 | changes were the introduction of x-height information to the OS/2 30 | table and the addition of the space and non-breaking space glyphs. 31 | -------------------------------------------------------------------------------- /servo_resources/android_params: -------------------------------------------------------------------------------- 1 | # The first line here should be the "servo" argument (without quotes) and the 2 | # last should be the URL to load. 3 | # Blank lines and those beginning with a '#' are ignored. 4 | # Each line should be a separate parameter as would be parsed by the shell. 5 | # For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 6 | # lines (the "-p" and "10" are separate even though they are related). 7 | 8 | servo 9 | http://en.wikipedia.org/wiki/Rust 10 | -------------------------------------------------------------------------------- /servo_resources/badcert.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Certificate error 4 | 5 | 6 | 7 |

${reason}

8 | 9 | 10 | -------------------------------------------------------------------------------- /servo_resources/badcert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/badcert.jpg -------------------------------------------------------------------------------- /servo_resources/cert-google-only: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV 3 | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy 4 | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 5 | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx 6 | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B 7 | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f 8 | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A 9 | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC 10 | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ 11 | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm 12 | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw 13 | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj 14 | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF 15 | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA 16 | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 17 | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 18 | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /servo_resources/failure.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | about:failure 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /servo_resources/gatt_blocklist.txt: -------------------------------------------------------------------------------- 1 | # Source: 2 | # https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt 3 | # License: 4 | # https://github.com/WebBluetoothCG/registries/blob/master/LICENSE 5 | 6 | # This file holds a list of GATT UUIDs that websites using the Web 7 | # Bluetooth API are forbidden from accessing. 8 | 9 | ## Services 10 | 11 | # org.bluetooth.service.human_interface_device 12 | # Direct access to HID devices like keyboards would let web pages 13 | # become keyloggers. 14 | 00001812-0000-1000-8000-00805f9b34fb 15 | 16 | # Firmware update services that don't check the update's signature 17 | # present a risk of devices' software being modified by malicious web 18 | # pages. Users may connect to a device believing they are enabling 19 | # only simple interaction or that they're interacting with the 20 | # device's manufacturer, but the site might instead persistently 21 | # compromise the device. 22 | # 23 | # Nordic's Device Firmware Update service, http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/examples_ble_dfu.html: 24 | 00001530-1212-efde-1523-785feabcd123 25 | # TI's Over-the-Air Download service, http://www.ti.com/lit/ug/swru271g/swru271g.pdf: 26 | f000ffc0-0451-4000-b000-000000000000 27 | 28 | 29 | ## Characteristics 30 | 31 | # org.bluetooth.characteristic.gap.peripheral_privacy_flag 32 | # Don't let web pages turn off privacy mode. 33 | 00002a02-0000-1000-8000-00805f9b34fb exclude-writes 34 | 35 | # org.bluetooth.characteristic.gap.reconnection_address 36 | # Disallow messing with connection parameters 37 | 00002a03-0000-1000-8000-00805f9b34fb 38 | 39 | # org.bluetooth.characteristic.serial_number_string 40 | # Block access to standardized unique identifiers, for privacy reasons. 41 | 00002a25-0000-1000-8000-00805f9b34fb 42 | 43 | # Blocklisted characteristic used to test readValue function. 44 | bad1c9a2-9a5b-4015-8b60-1579bbbf2135 exclude-reads 45 | 46 | 47 | ## Descriptors 48 | 49 | # org.bluetooth.descriptor.gatt.client_characteristic_configuration 50 | # Writing to this would let a web page interfere with other pages' 51 | # notifications and indications. 52 | 00002902-0000-1000-8000-00805f9b34fb exclude-writes 53 | 54 | # org.bluetooth.descriptor.gatt.server_characteristic_configuration 55 | # Writing to this would let a web page interfere with the broadcasted services. 56 | 00002903-0000-1000-8000-00805f9b34fb exclude-writes 57 | 58 | # Blocklisted descriptor used to test. 59 | 07711111-6104-0970-7011-1107105110aa 60 | 61 | # Blocklisted descriptor used to test. 62 | aaaaaaaa-aaaa-1181-0510-810819516110 exclude-reads 63 | -------------------------------------------------------------------------------- /servo_resources/iso-8859-8.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | https://html.spec.whatwg.org/multipage/#bidi-rendering 4 | 5 | > When the document's character encoding is ISO-8859-8, 6 | > the following rules are additionally expected to apply, following [user-agent.css] 7 | 8 | */ 9 | 10 | @namespace url(http://www.w3.org/1999/xhtml); 11 | 12 | 13 | address, blockquote, center, div, figure, figcaption, footer, form, header, hr, 14 | legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2, 15 | h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead, 16 | tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, [dir=ltr i], 17 | [dir=rtl i], [dir=auto i], *|* { 18 | unicode-bidi: bidi-override; 19 | } 20 | input:not([type=submit i]):not([type=reset i]):not([type=button i]), 21 | textarea, keygen { 22 | unicode-bidi: normal; 23 | } 24 | -------------------------------------------------------------------------------- /servo_resources/itried.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/itried.jpg -------------------------------------------------------------------------------- /servo_resources/neterror.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Error loading page 4 | 5 | 6 |

Could not load the requested page: ${reason}

7 | 8 | 9 | -------------------------------------------------------------------------------- /servo_resources/not-found.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | about:not-found 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /servo_resources/package-prefs.json: -------------------------------------------------------------------------------- 1 | { 2 | "dom.forcetouch.enabled": true, 3 | "dom.mozbrowser.enabled": true, 4 | "shell.builtin-key-shortcuts.enabled": false, 5 | "os:windows,os:linux;shell.homepage": "browserhtml/index.html", 6 | "os:macosx;shell.native-titlebar.enabled": false 7 | } 8 | -------------------------------------------------------------------------------- /servo_resources/prefs.json: -------------------------------------------------------------------------------- 1 | { 2 | "dom.bluetooth.enabled": false, 3 | "dom.bluetooth.testing.enabled": false, 4 | "dom.canvas-text.enabled": false, 5 | "dom.compositionevent.enabled": false, 6 | "dom.customelements.enabled": true, 7 | "dom.forcetouch.enabled": false, 8 | "dom.gamepad.enabled": false, 9 | "dom.microdata.testing.enabled": true, 10 | "dom.mouseevent.which.enabled": false, 11 | "dom.mozbrowser.enabled": false, 12 | "dom.mutation_observer.enabled": false, 13 | "dom.permissions.enabled": false, 14 | "dom.permissions.testing.allowed_in_nonsecure_contexts": false, 15 | "dom.serviceworker.timeout_seconds": 60, 16 | "dom.servoparser.async_html_tokenizer.enabled": false, 17 | "dom.testable_crash.enabled": false, 18 | "dom.testbinding.enabled": false, 19 | "dom.webgl.dom_to_texture.enabled": false, 20 | "dom.webgl2.enabled": false, 21 | "dom.webvr.enabled": false, 22 | "dom.webvr.event_polling_interval": 500, 23 | "js.asmjs.enabled": true, 24 | "js.asyncstack.enabled": false, 25 | "js.baseline.enabled": true, 26 | "js.baseline.unsafe_eager_compilation.enabled": false, 27 | "js.discard_system_source.enabled": false, 28 | "js.dump_stack_on_debuggee_would_run.enabled": false, 29 | "js.ion.enabled": true, 30 | "js.ion.offthread_compilation.enabled": true, 31 | "js.ion.unsafe_eager_compilation.enabled": false, 32 | "js.mem.gc.allocation_threshold_mb": 30, 33 | "js.mem.gc.compacting.enabled": true, 34 | "js.mem.gc.decommit_threshold_mb": 32, 35 | "js.mem.gc.dynamic_heap_growth.enabled": true, 36 | "js.mem.gc.dynamic_mark_slice.enabled": true, 37 | "js.mem.gc.empty_chunk_count_max": 30, 38 | "js.mem.gc.empty_chunk_count_min": 1, 39 | "js.mem.gc.high_frequency_heap_growth_max": 300, 40 | "js.mem.gc.high_frequency_heap_growth_min": 150, 41 | "js.mem.gc.high_frequency_high_limit_mb": 500, 42 | "js.mem.gc.high_frequency_low_limit_mb": 100, 43 | "js.mem.gc.high_frequency_time_limit_ms": 1000, 44 | "js.mem.gc.incremental.enabled": true, 45 | "js.mem.gc.incremental.slice_ms": 10, 46 | "js.mem.gc.low_frequency_heap_growth": 150, 47 | "js.mem.gc.per_compartment.enabled": true, 48 | "js.mem.gc.refresh_frame_slices.enabled": true, 49 | "js.mem.gc.zeal.frequency": 100, 50 | "js.mem.gc.zeal.level": 0, 51 | "js.mem.high_water_mark": 128, 52 | "js.mem.max": -1, 53 | "js.native_regexp.enabled": true, 54 | "js.parallel_parsing.enabled": true, 55 | "js.shared_memory.enabled": true, 56 | "js.strict.debug.enabled": false, 57 | "js.strict.enabled": false, 58 | "js.throw_on_asmjs_validation_failure.enabled": false, 59 | "js.throw_on_debuggee_would_run.enabled": false, 60 | "js.werror.enabled": false, 61 | "layout.animations.test.enabled": false, 62 | "layout.column-count.enabled": false, 63 | "layout.column-gap.enabled": false, 64 | "layout.column-width.enabled": false, 65 | "layout.columns.enabled": false, 66 | "layout.text-orientation.enabled": false, 67 | "layout.viewport.enabled": false, 68 | "layout.writing-mode.enabled": false, 69 | "network.http-cache.disabled": false, 70 | "network.mime.sniff": false, 71 | "session-history.max-length": 20, 72 | "shell.builtin-key-shortcuts.enabled": true, 73 | "shell.homepage": "https://servo.org", 74 | "shell.keep_screen_on.enabled": false, 75 | "shell.native-orientation": "both", 76 | "shell.native-titlebar.enabled": true, 77 | "webgl.testing.context_creation_error": false 78 | } 79 | -------------------------------------------------------------------------------- /servo_resources/presentational-hints.css: -------------------------------------------------------------------------------- 1 | /* 2 | https://html.spec.whatwg.org/multipage/#presentational-hints 3 | */ 4 | 5 | @namespace url(http://www.w3.org/1999/xhtml); 6 | 7 | 8 | pre[wrap] { white-space: pre-wrap; } 9 | 10 | div[align=left i] { text-align: -servo-left; } 11 | div[align=right i] { text-align: -servo-right; } 12 | div[align=center i], div[align=middle i] { text-align: -servo-center; } 13 | div[align=justify i] { text-align: justify; } 14 | 15 | 16 | br[clear=left i] { clear: left; } 17 | br[clear=right i] { clear: right; } 18 | br[clear=all i], br[clear=both i] { clear: both; } 19 | 20 | 21 | ol[type="1"], li[type="1"] { list-style-type: decimal; } 22 | ol:-servo-case-sensitive-type-attr(a), 23 | li:-servo-case-sensitive-type-attr(a) { list-style-type: lower-alpha; } 24 | ol:-servo-case-sensitive-type-attr(A), 25 | li:-servo-case-sensitive-type-attr(A) { list-style-type: upper-alpha; } 26 | ol:-servo-case-sensitive-type-attr(i), 27 | li:-servo-case-sensitive-type-attr(i) { list-style-type: lower-roman; } 28 | ol:-servo-case-sensitive-type-attr(I), 29 | li:-servo-case-sensitive-type-attr(I) { list-style-type: upper-roman; } 30 | ul[type=none i], li[type=none i] { list-style-type: none; } 31 | ul[type=disc i], li[type=disc i] { list-style-type: disc; } 32 | ul[type=circle i], li[type=circle i] { list-style-type: circle; } 33 | ul[type=square i], li[type=square i] { list-style-type: square; } 34 | 35 | 36 | table[align=left i] { float: left; } 37 | table[align=right i] { float: right; } 38 | table[align=center i] { margin-left: auto; margin-right: auto; } 39 | :matches(thead, tbody, tfoot, tr, td, th)[align=absmiddle i] { 40 | text-align: center; 41 | } 42 | 43 | caption[align=bottom i] { caption-side: bottom; } 44 | 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; } 45 | 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; } 46 | 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; } 47 | 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; } 48 | 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; } 49 | 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; } 50 | 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; } 51 | 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; } 52 | 53 | td[nowrap], th[nowrap] { white-space: nowrap; } 54 | 55 | table[rules=none i], table[rules=groups i], table[rules=rows i], table[rules=cols i], table[rules=all i] { 56 | border-style: hidden; 57 | border-collapse: collapse; 58 | } 59 | 60 | table:-servo-nonzero-border { 61 | border-style: outset; 62 | } 63 | table[frame=void i] { border-style: hidden; } 64 | table[frame=above i] { border-style: outset hidden hidden hidden; } 65 | table[frame=below i] { border-style: hidden hidden outset hidden; } 66 | table[frame=hsides i] { border-style: outset hidden outset hidden; } 67 | table[frame=lhs i] { border-style: hidden hidden hidden outset; } 68 | table[frame=rhs i] { border-style: hidden outset hidden hidden; } 69 | table[frame=vsides i] { border-style: hidden outset; } 70 | table[frame=box i], table[frame=border i] { border-style: outset; } 71 | 72 | 73 | table:-servo-nonzero-border > tr > td, 74 | table:-servo-nonzero-border > tr > th, 75 | table:-servo-nonzero-border > thead > tr > td, 76 | table:-servo-nonzero-border > thead > tr > th, 77 | table:-servo-nonzero-border > tbody > tr > td, 78 | table:-servo-nonzero-border > tbody > tr > th, 79 | table:-servo-nonzero-border > tfoot > tr > td, 80 | table:-servo-nonzero-border > tfoot > tr > th { 81 | border-width: 1px; 82 | border-style: inset; 83 | } 84 | 85 | 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, 86 | 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, 87 | 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, 88 | 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 { 89 | border-width: 1px; 90 | border-style: none; 91 | } 92 | table[rules=cols i] > tr > td, table[rules=cols i] > tr > th, 93 | table[rules=cols i] > thead > tr > td, table[rules=cols i] > thead > tr > th, 94 | table[rules=cols i] > tbody > tr > td, table[rules=cols i] > tbody > tr > th, 95 | table[rules=cols i] > tfoot > tr > td, table[rules=cols i] > tfoot > tr > th { 96 | border-width: 1px; 97 | border-style: none solid; 98 | } 99 | table[rules=all i] > tr > td, table[rules=all i] > tr > th, 100 | table[rules=all i] > thead > tr > td, table[rules=all i] > thead > tr > th, 101 | table[rules=all i] > tbody > tr > td, table[rules=all i] > tbody > tr > th, 102 | table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th { 103 | border-width: 1px; 104 | border-style: solid; 105 | } 106 | 107 | table[rules=groups i] > colgroup { 108 | border-left-width: 1px; 109 | border-left-style: solid; 110 | border-right-width: 1px; 111 | border-right-style: solid; 112 | } 113 | table[rules=groups i] > tr, 114 | table[rules=groups i] > thead > tr, 115 | table[rules=groups i] > tbody > tr, 116 | table[rules=groups i] > tfoot > tr { 117 | border-top-width: 1px; 118 | border-top-style: solid; 119 | border-bottom-width: 1px; 120 | border-bottom-style: solid; 121 | } 122 | table[rules=rows i] > tr, 123 | table[rules=rows i] > thead > tr, 124 | table[rules=rows i] > tbody > tr, 125 | table[rules=rows i] > tfoot > tr { 126 | border-top-width: 1px; 127 | border-top-style: solid; 128 | border-bottom-width: 1px; 129 | border-bottom-style: solid; 130 | } 131 | 132 | 133 | hr[align=left] { margin-left: 0; margin-right: auto; } 134 | hr[align=right] { margin-left: auto; margin-right: 0; } 135 | hr[align=center] { margin-left: auto; margin-right: auto; } 136 | hr[color], hr[noshade] { border-style: solid; } 137 | 138 | 139 | 140 | iframe[frameborder="0"], iframe[frameborder=no i] { border: none; } 141 | 142 | embed[align=left i], iframe[align=left i], img[type=image i][align=left i], object[align=left i] { 143 | float: left; 144 | } 145 | embed[align=right i], iframe[align=right i], img[type=image i][align=right i], object[align=right i] { 146 | float: right; 147 | } 148 | embed[align=top i], iframe[align=top i], img[type=image i][align=top i], object[align=top i] { 149 | vertical-align: top; 150 | } 151 | embed[align=baseline i], iframe[align=baseline i], img[type=image i][align=baseline i], object[align=baseline i] { 152 | vertical-align: baseline; 153 | } 154 | embed[align=texttop i], iframe[align=texttop i], img[type=image i][align=texttop i], object[align=texttop i] { 155 | vertical-align: text-top; 156 | } 157 | embed[align=absmiddle i], iframe[align=absmiddle i], img[type=image i][align=absmiddle i], object[align=absmiddle i], 158 | embed[align=abscenter i], iframe[align=abscenter i], img[type=image i][align=abscenter i], object[align=abscenter i] { 159 | vertical-align: middle; 160 | } 161 | embed[align=bottom i], iframe[align=bottom i], img[type=image i][align=bottom i], object[align=bottom i] { 162 | vertical-align: bottom; 163 | } 164 | /* 165 | FIXME: 166 | :matches(embed, iframe, img, input[type=image i], object):matches([align=center i], [align=middle i]) { 167 | vertical-align: "aligns the vertical middle of the element with the parent element's baseline." 168 | } 169 | */ 170 | 171 | /* 172 | 173 | Presentational attributes which can not currently be expressed in CSS. 174 | FIXME: Deal with them with attr(foo dimension) and the like? 175 | 176 | body 177 | marginheight 178 | marginwidth 179 | topmargin 180 | rightmargin 181 | bottommargin 182 | leftmargin 183 | background 184 | bgcolor 185 | text 186 | link 187 | vlink 188 | alink 189 | 190 | frame, iframe 191 | marginheight 192 | marginwidth 193 | 194 | font 195 | face 196 | color 197 | size 198 | 199 | table 200 | cellspacing 201 | cellpadding 202 | hspace 203 | vspace 204 | height 205 | width 206 | bordercolor 207 | border 208 | 209 | col 210 | width 211 | 212 | tr 213 | height 214 | 215 | td, th 216 | width 217 | height 218 | 219 | caption, thead, tbody, tfoot, tr, td, and th 220 | align 221 | 222 | table, thead, tbody, tfoot, tr, td, or th 223 | background 224 | bgcolor 225 | 226 | (quirks mode) th, td 227 | nowrap 228 | 229 | hr 230 | color 231 | noshade 232 | size 233 | width 234 | 235 | legend 236 | align 237 | 238 | embed, iframe, img, input[type=image i], object 239 | hspace 240 | vspace 241 | 242 | img, input[type=image i], object 243 | border 244 | 245 | embed, iframe, img, input[type=image i], object, video 246 | width 247 | height 248 | 249 | */ 250 | 251 | /* 252 | 253 | Extra 254 | ol > li 255 | https://html.spec.whatwg.org/multipage/#ordinal-value 256 | col 257 | span 258 | colgroup (if not col child) 259 | span 260 | td, th 261 | colspan 262 | rowspan 263 | 264 | :computed-value(text-align is initial) > th { 265 | text-align: center; 266 | } 267 | 268 | https://html.spec.whatwg.org/multipage/#rendered-legend 269 | 270 | */ 271 | 272 | -------------------------------------------------------------------------------- /servo_resources/privatekey_for_testing.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDwJhD2k5vROwKG 3 | ZFbOVShnx0nubyUrPXTe2wnUcU6Pr32qguIOmHD+TttSFVmU5TVe0UlMUkbyRjGM 4 | Lzguf/Eo0FoUKH2GbUpS07hGyxcqUQd+DzFWYY4hoLrWhd+ICPer7Y9OC/qiUOgv 5 | vP7hjaBI//ODWzN0AZbB+SyBfRq0hbLyUIFtfxV42UEC8qQzQItq9eGNSaalvM8a 6 | P8+XZu/4d1dll3u3qwdDoC7M9oEMCemHY+O6dnaJUu38+s41nyatSSKqDkZRFDvH 7 | 8TCE7+PQRARkN3qs57EeyeYKhSwXYpgzOC4P38DpD6u6jcETpQZvZJv2x4Z+slrW 8 | 48zO21vdAgMBAAECggEBAL8nLb14BUFoXTwoRkh61Gy23wxhgA6JHqv9Yjet8UDC 9 | CZ9eCx5fDSIAFuehgurX/8F3iYasvzg901aoh2nMAWPhZLJDAJeuCskfKcGACvJu 10 | CS64XSdLA92UmOQFL8aSjMJXmAgh1OC60fad06wqFXnF8kmOoMgoM542/swbjtQ9 11 | RUoXUKa2x9ve2b0og4iuEj/iZR+d2/HYPNtpNIFt7+rA1qCd2RIfMSAB6j3ohFNA 12 | AqVZdASgNznj5Sa8jz6zU40zdyLPIDYfCdi3Gmq42LaB4HWHiSpjx49aCQD6UV4+ 13 | NxFsYi9WRA79DxdoeWsYm017G5NrHsELCdqwxg46fEECgYEA+/AJsiIjoBJ0SGoe 14 | Oqm86EbOtYtOEsMLF0Pk7OQejAN3VPqP6xN0u6unldo5RLJMsTlTHxIZuZNbXhw8 15 | aKWz0ULoXWi5J8Af2NHI0zaY0naGv3yew+6mq9xpZLHsY9wBWtT2tXEziH7gjPvk 16 | LmJ8+GCKSq9XLHoSyyjjqdr1aOUCgYEA9AVdhIFZ9EDb6zgnCjMvWlNFU/G2+WbU 17 | jCc9GRTFbzsahbawjuJ+47Ajz5aTBWOA1HE4wcMMMEjRebP/15CiCQs34+BIQckW 18 | 2zvMipAh6dlbyx2O9t0gdIjAUNiYYMfuHYBQ3Nwmi6Nop3kHQuFHRh6uneGTxcEq 19 | wq3IEhN9T5kCgYAnip8a9Dy/LOZPT0h7UJSzqBldaQXR8AbXmfJeM9ePhiO+lKzt 20 | 6lnR8rkUzfFbFNjwn9yp7b9X3wbiGHBqxEcauvOZZYxZ7s+QyixI6jLGJZA0kayh 21 | d910790izsIZUjhsNyyZgbDi5Xb86bQAi7itiwlpe2elNWupszs4N4N4+QKBgQDQ 22 | Le+dhtkeV2MHZm1v90Dzt0zTE8j9Nuwn8aXfSugxP+QdpUE1dSe5yeCTTit5km0r 23 | ULiSHXu9ibIkORsQZdTHEGoLH6Gldg/o0zhqEhLMtWHpg/sewoHYyX4AuvgswQR0 24 | 6K6T7cF4qd0z2z4FobmzqaNhEDyInoaDdczVFwl2KQKBgQCHjZLwMZLg0be9i1IS 25 | jzaG2d5CF3WJ+A1zYQLXqzpX5qfbgsEIbpTtdCOhgf94YJsiJ9XdIG8OgGVxhrkT 26 | C41PGdIoq7wVxOwfW9qXQTOarO6ymFZxOnmHukpjfbcp54xDpcF73Xe6XkvmiESd 27 | gcNMfunAcg8sNgIGJzsKJ50+hw== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /servo_resources/quirks-mode.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | https://html.spec.whatwg.org/multipage/#flow-content-3 4 | 5 | > In quirks mode, the following rules are also expected to apply: 6 | 7 | */ 8 | 9 | @namespace url(http://www.w3.org/1999/xhtml); 10 | 11 | 12 | form { margin-bottom: 1em; } 13 | 14 | 15 | table { 16 | font-weight: initial; 17 | font-style: initial; 18 | font-variant: initial; 19 | font-size: initial; 20 | line-height: initial; 21 | white-space: initial; 22 | /* text-align: initial; -- see FIXME below */ 23 | } 24 | 25 | /* 26 | * FIXME(pcwalton): Actually saying `text-align: initial` above breaks `` inside `
` 27 | * in quirks mode. This is because we (following Gecko, WebKit, and Blink) implement the HTML5 28 | * align-descendants rules with a special `text-align: -servo-center`. `text-align: initial`, if 29 | * placed on the `
` element per the spec, would break this behavior. So we place it on 30 | * `` instead. 31 | */ 32 | tbody { 33 | text-align: initial; 34 | } 35 | 36 | 37 | /* FIXME: https://html.spec.whatwg.org/multipage/#margin-collapsing-quirks */ 38 | 39 | 40 | input:not([type=image]), textarea { box-sizing: border-box; } 41 | 42 | 43 | img[align=left i] { margin-right: 3px; } 44 | img[align=right i] { margin-left: 3px; } 45 | -------------------------------------------------------------------------------- /servo_resources/rippy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/rippy.png -------------------------------------------------------------------------------- /servo_resources/self_signed_certificate_for_testing.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxjCCAq6gAwIBAgIJAIPzh6mmZhGkMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV 3 | BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg 4 | Q29tcGFueSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDEgMB4GCSqGSIb3DQEJARYR 5 | dGVzdGluZ0BzZXJ2by5vcmcwHhcNMTcxMjI0MTQxMjA0WhcNMjcxMjIyMTQxMjA0 6 | WjB4MQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQK 7 | DBNEZWZhdWx0IENvbXBhbnkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkq 8 | hkiG9w0BCQEWEXRlc3RpbmdAc2Vydm8ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC 9 | AQ8AMIIBCgKCAQEA8CYQ9pOb0TsChmRWzlUoZ8dJ7m8lKz103tsJ1HFOj699qoLi 10 | Dphw/k7bUhVZlOU1XtFJTFJG8kYxjC84Ln/xKNBaFCh9hm1KUtO4RssXKlEHfg8x 11 | VmGOIaC61oXfiAj3q+2PTgv6olDoL7z+4Y2gSP/zg1szdAGWwfksgX0atIWy8lCB 12 | bX8VeNlBAvKkM0CLavXhjUmmpbzPGj/Pl2bv+HdXZZd7t6sHQ6AuzPaBDAnph2Pj 13 | unZ2iVLt/PrONZ8mrUkiqg5GURQ7x/EwhO/j0EQEZDd6rOexHsnmCoUsF2KYMzgu 14 | D9/A6Q+ruo3BE6UGb2Sb9seGfrJa1uPMzttb3QIDAQABo1MwUTAdBgNVHQ4EFgQU 15 | rzyrtcToBhyprrcbQ698ysb4mqIwHwYDVR0jBBgwFoAUrzyrtcToBhyprrcbQ698 16 | ysb4mqIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAffZmMwi5 17 | ljhc0pM2DUWjfari4pvXzRpPUErTtMxuXQVijPhwOOWFI91xoEZUojxhOr+0Ran9 18 | 7OulbgaTN0xMNwSs5cdS/KLY/nuIz0J8zYeW/VfIm+9fAKxt0cqORQppd6nTnfhl 19 | Sfr7MBE9su3fMq142voUgEwb4zxKq/tnlCzkWMAju+EPdTHW+HRhz8nEy/DVThiY 20 | 2gTQG5tajQV7XZyWBozLiCjx0I2sidC7uxoy9o9yQRXvikeNxLdiOZlBP25IHTM+ 21 | 57uYE15RiCOOQB5vYH4L8ISRxDmNRYBSi5HFc68URqOuakpmGDJ8HNMJRb0m8PbR 22 | zDwuZIy1uC+UBg== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /servo_resources/servo.css: -------------------------------------------------------------------------------- 1 | button, 2 | input { 3 | background: white; 4 | min-height: 1.0em; 5 | padding: 0em; 6 | padding-left: 0.25em; 7 | padding-right: 0.25em; 8 | border: solid lightgrey 1px; 9 | color: black; 10 | font-family: sans-serif; 11 | font-size: 0.8333em; 12 | text-align: left; 13 | line-height: 1.8; 14 | } 15 | 16 | textarea { 17 | background: white; 18 | min-height: 1.0em; 19 | padding: 0em; 20 | padding-left: 0.25em; 21 | padding-right: 0.25em; 22 | border: solid lightgrey 1px; 23 | color: black; 24 | font-family: sans-serif; 25 | font-size: 0.8333em; 26 | white-space: pre-wrap; 27 | } 28 | 29 | input::selection, 30 | textarea::selection { 31 | background: rgba(176, 214, 255, 1.0); 32 | color: black; 33 | } 34 | 35 | button, 36 | input[type="button"], 37 | input[type="submit"], 38 | input[type="reset"] { 39 | background: lightgrey; 40 | border-top: solid 1px #EEEEEE; 41 | border-left: solid 1px #CCCCCC; 42 | border-right: solid 1px #999999; 43 | border-bottom: solid 1px #999999; 44 | text-align: center; 45 | color: black; 46 | } 47 | 48 | input[type="hidden"] { display: none !important } 49 | 50 | input[type="checkbox"], 51 | input[type="radio"] { 52 | font-family: monospace !important; 53 | border: none !important; 54 | background: transparent; 55 | } 56 | 57 | input[type="checkbox"]::before { 58 | display: inline-block; 59 | border: solid currentcolor 1px; 60 | content: ""; 61 | padding: 0; 62 | width: 1em; 63 | height: 1em; 64 | text-align: center; 65 | } 66 | 67 | input[type="checkbox"]:checked::before { content: "✓"; } 68 | input[type="checkbox"]:indeterminate::before { content: "-"; } 69 | 70 | input[type="radio"]::before { 71 | display: inline-block; 72 | border: solid currentcolor 1px; 73 | content: ""; 74 | padding: 0; 75 | width: 1em; 76 | height: 1em; 77 | border-radius: 50%; 78 | text-align: center; 79 | } 80 | 81 | input[type="radio"]:checked::before { content: "●"; line-height: 1em; } 82 | 83 | input[type="file"]::before { 84 | content: "Choose File"; 85 | } 86 | 87 | input[type="file"] { 88 | background: lightgrey; 89 | text-align: center; 90 | vertical-align: middle; 91 | color: black; 92 | } 93 | 94 | select { 95 | border-style: solid; 96 | border-width: 1px; 97 | background: white; 98 | } 99 | 100 | select[multiple] { padding: 0em 0.25em; } 101 | select:not([multiple]) { padding: 0.25em 0.5em; border-radius: 6px; } 102 | 103 | select:not([multiple])::after { 104 | content: ""; 105 | display: inline-block; 106 | border-width: 5.2px 3px 0 3px; 107 | border-style: solid; 108 | border-color: currentcolor transparent transparent transparent; 109 | margin-left: 0.5em; 110 | } 111 | 112 | select:not([multiple]) option { display: none !important; } 113 | select:not([multiple]) option[selected] { display: inline !important; } 114 | select[multiple] option { display: block !important; } 115 | select[multiple] option[selected] { background-color: grey; color: white; } 116 | select[multiple]:focus option[selected] { background-color: darkblue; } 117 | 118 | td[align="left"] { text-align: left; } 119 | td[align="center"] { text-align: center; } 120 | td[align="right"] { text-align: right; } 121 | 122 | center { text-align: -servo-center; } 123 | 124 | label { cursor: default; } 125 | 126 | input:not([type=radio i]):not([type=checkbox i]):not([type=reset i]):not([type=button i]):not([type=submit i]), 127 | textarea { 128 | cursor: text; 129 | overflow: hidden; 130 | -servo-overflow-clip-box: content-box; 131 | } 132 | 133 | input:not([type=radio i]):not([type=checkbox i]):not([type=reset i]):not([type=button i]):not([type=submit i]) { 134 | white-space: pre; 135 | } 136 | 137 | textarea { 138 | overflow: auto; 139 | } 140 | 141 | /* https://html.spec.whatwg.org/multipage/rendering.html#the-details-and-summary-elements */ 142 | details { 143 | display: block; 144 | } 145 | 146 | details::-servo-details-summary { 147 | margin-left: 40px; 148 | display: list-item; 149 | list-style: disclosure-closed; 150 | } 151 | 152 | details[open]::-servo-details-summary { 153 | list-style: disclosure-open; 154 | } 155 | 156 | *|*::-servo-details-content { 157 | margin-left: 40px; 158 | overflow: hidden; 159 | display: block; 160 | } 161 | 162 | /* 163 | * Until servo supports svg properly, make sure to at least prevent svg 164 | * children from being layed out and rendered like usual html. 165 | * https://github.com/servo/servo/issues/10646 166 | */ 167 | svg > * { 168 | display: none; 169 | } 170 | 171 | /* style for text node. */ 172 | *|*::-servo-text { 173 | margin: 0; 174 | text-overflow: inherit; 175 | overflow: inherit; 176 | } 177 | 178 | /* style for text in input elements. */ 179 | *|*::-servo-input-text { 180 | margin: 0; 181 | } 182 | 183 | *|*::-servo-table-wrapper { 184 | display: table; 185 | border: none; 186 | } 187 | 188 | *|*::-servo-anonymous-table-wrapper { 189 | position: static; 190 | margin: 0; 191 | counter-increment: none; 192 | 193 | /* We don't want anonymous table parts to inherit hidden overflow, because 194 | * they will create extra unnecessary ClipScrollNodes which also throws 195 | * off assignment of contained flows. */ 196 | overflow: visible; 197 | } 198 | 199 | *|*::-servo-anonymous-table { 200 | display: table; 201 | position: static; 202 | border: none; 203 | padding: 0; 204 | counter-increment: none; 205 | overflow: visible; 206 | } 207 | 208 | *|*::-servo-anonymous-table-row { 209 | display: table-row; 210 | position: static; 211 | border: none; 212 | counter-increment: none; 213 | overflow: visible; 214 | } 215 | 216 | *|*::-servo-anonymous-table-cell { 217 | display: table-cell; 218 | position: static; 219 | border: none; 220 | counter-increment: none; 221 | overflow: visible; 222 | } 223 | 224 | *|*::-servo-anonymous-block { 225 | display: block; 226 | position: static; 227 | border: none; 228 | padding: 0; 229 | margin: 0; 230 | width: auto; 231 | height: auto; 232 | } 233 | 234 | /* The outer fragment wrapper of an inline-block. */ 235 | *|*::-servo-inline-block-wrapper { 236 | position: static; 237 | border: none; 238 | padding: 0; 239 | margin: 0; 240 | } 241 | 242 | /* The outer fragment wrapper of an inline absolute hypothetical fragment. */ 243 | *|*::-servo-inline-absolute { 244 | clip: auto; 245 | border: none; 246 | padding: 0; 247 | margin: 0; 248 | } 249 | -------------------------------------------------------------------------------- /servo_resources/servo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/servo.icns -------------------------------------------------------------------------------- /servo_resources/servo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/servo.png -------------------------------------------------------------------------------- /servo_resources/tumbeast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/servo_resources/tumbeast.png -------------------------------------------------------------------------------- /servo_resources/user-agent-js/00.example.js: -------------------------------------------------------------------------------- 1 | // Keep files in this directory which you would like executed before 2 | // any other script when servo is run with `--userscripts` 3 | // Files are sorted alphabetically. When committing polyfills 4 | // order them with numbers, e.g. `01.innerhtml.js` will be executed before 5 | // `05.jquery.js` 6 | -------------------------------------------------------------------------------- /servo_resources/user-agent.css: -------------------------------------------------------------------------------- 1 | /* 2 | https://html.spec.whatwg.org/multipage/#form-controls 3 | */ 4 | 5 | @namespace url(http://www.w3.org/1999/xhtml); 6 | 7 | /* 8 | FIXME: Uncomment this when :lang() is supported, or do something equivalent. 9 | @import url(quotes.css); 10 | */ 11 | 12 | [hidden], area, base, basefont, datalist, head, link, menu[type=popup i], meta, 13 | noembed, noframes, param, rp, script, source, style, template, track, title { 14 | display: none; 15 | } 16 | 17 | embed[hidden] { display: inline; height: 0; width: 0; } 18 | 19 | /* FIXME: only if scripting is enabled */ 20 | noscript { display: none !important; } 21 | 22 | input[type=hidden i] { display: none !important; } 23 | 24 | 25 | html, body { display: block; } 26 | 27 | body { margin: 8px; } 28 | 29 | 30 | address, blockquote, center, div, figure, figcaption, footer, form, header, hr, 31 | legend, listing, main, p, plaintext, pre, summary, xmp { 32 | display: block; 33 | } 34 | 35 | blockquote, figure, listing, p, plaintext, pre, xmp { 36 | margin-top: 1em; margin-bottom: 1em; 37 | } 38 | 39 | blockquote, figure { margin-left: 40px; margin-right: 40px; } 40 | 41 | address { font-style: italic; } 42 | listing, plaintext, pre, xmp { 43 | font-family: monospace; white-space: pre; 44 | } 45 | 46 | dialog:not([open]) { display: none; } 47 | dialog { 48 | position: absolute; 49 | left: 0; right: 0; 50 | /* FIXME: support fit-content */ 51 | width: fit-content; 52 | height: fit-content; 53 | margin: auto; 54 | border: solid; 55 | padding: 1em; 56 | background: white; 57 | color: black; 58 | } 59 | /* FIXME: support ::backdrop */ 60 | dialog::backdrop { 61 | position: fixed; 62 | top: 0; right: 0; bottom: 0; left: 0; 63 | background: rgba(0,0,0,0.1); 64 | } 65 | 66 | /* for small devices, modal dialogs go full-screen */ 67 | @media screen and (max-width: 540px) { 68 | /* FIXME: support :modal */ 69 | dialog:modal { 70 | top: 0; 71 | width: auto; 72 | margin: 1em; 73 | } 74 | } 75 | 76 | 77 | cite, dfn, em, i, var { font-style: italic; } 78 | b, strong { font-weight: bolder; } 79 | code, kbd, samp, tt { font-family: monospace; } 80 | big { font-size: larger; } 81 | small { font-size: smaller; } 82 | 83 | sub { vertical-align: sub; } 84 | sup { vertical-align: super; } 85 | sub, sup { line-height: normal; font-size: smaller; } 86 | 87 | ruby { display: ruby; } 88 | rt { display: ruby-text; } 89 | 90 | /* 91 | * All tag names that can be links are listed here, because applying pseudo-class selectors 92 | * disables style sharing, so we want to apply pseudo-class selectors to as few elements as 93 | * possible. 94 | */ 95 | a:link, area:link { color: #0000EE; } 96 | a:visited, area:visited { color: #551A8B; } 97 | a:link, a:visited, 98 | area:link, area:visited { text-decoration: underline; cursor: pointer; } 99 | a:link[rel~=help], a:visited[rel~=help], 100 | area:link[rel~=help], area:visited[rel~=help] { cursor: help; } 101 | 102 | /* 103 | * FIXME: use `outline: auto;` 104 | */ 105 | a:focus, area:focus, 106 | input:focus, textarea:focus, button:focus { outline: thin dotted; } 107 | 108 | mark { background: yellow; color: black; } 109 | 110 | abbr[title], acronym[title] { text-decoration: dotted underline; } 111 | ins, u { text-decoration: underline; } 112 | del, s, strike { text-decoration: line-through; } 113 | blink { text-decoration: blink; } 114 | 115 | q::before { content: open-quote; } 116 | q::after { content: close-quote; } 117 | 118 | /*br { display-outside: newline; } /* this also has bidi implications */ 119 | br::before { content: "\A"; white-space: pre } 120 | 121 | nobr { white-space: nowrap; } 122 | wbr { display-outside: break-opportunity; } /* this also has bidi implications */ 123 | nobr wbr { white-space: normal; } 124 | 125 | 126 | [dir]:dir(ltr), bdi:dir(ltr), input[type=tel]:dir(ltr) { direction: ltr; } 127 | [dir]:dir(rtl), bdi:dir(rtl) { direction: rtl; } 128 | 129 | address, blockquote, center, div, figure, figcaption, footer, form, header, hr, 130 | legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2, 131 | h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead, 132 | tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, bdi, output, 133 | [dir=ltr i], [dir=rtl i], [dir=auto i] { 134 | unicode-bidi: isolate; 135 | } 136 | 137 | bdo, bdo[dir] { unicode-bidi: isolate-override; } 138 | 139 | textarea[dir=auto i], pre[dir=auto i] { unicode-bidi: plaintext; } 140 | 141 | 142 | article, aside, h1, h2, h3, h4, h5, h6, hgroup, nav, section { 143 | display: block; 144 | } 145 | 146 | h1 { margin-top: 0.67em; margin-bottom: 0.67em; font-size: 2.00em; font-weight: bold; } 147 | h2 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; font-weight: bold; } 148 | h3 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; font-weight: bold; } 149 | h4 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; font-weight: bold; } 150 | h5 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; font-weight: bold; } 151 | h6 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; font-weight: bold; } 152 | 153 | :matches(article, aside, nav, section) h1 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; } 154 | :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; } 155 | :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; } 156 | :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; } 157 | :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; } 158 | 159 | :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; } 160 | :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; } 161 | :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; } 162 | :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; } 163 | 164 | :matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; } 165 | :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; } 166 | :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; } 167 | 168 | :matches(article, aside, nav, section) hgroup > h1 ~ h4 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; } 169 | :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; } 170 | 171 | :matches(article, aside, nav, section) hgroup > h1 ~ h5 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } 172 | 173 | 174 | dir, dd, dl, dt, menu, ol, ul { display: block; } 175 | li { display: list-item; } 176 | 177 | dir, dl, menu, ol, ul { margin-top: 1em; margin-bottom: 1em; } 178 | 179 | :matches(dir, dl, menu, ol, ul) :matches(dir, dl, menu, ol, ul) { 180 | margin-top: 0; margin-bottom: 0; 181 | } 182 | 183 | dd { margin-left: 40px; } /* FIXME: use margin-inline-start when supported */ 184 | dir, menu, ol, ul { padding-left: 40px; } /* FIXME: use padding-inline-start when supported */ 185 | 186 | ol { list-style-type: decimal; } 187 | 188 | dir, menu, ul { list-style-type: disc; } 189 | 190 | :matches(dir, menu, ol, ul) :matches(dir, menu, ul) { 191 | list-style-type: circle; 192 | } 193 | 194 | :matches(dir, menu, ol, ul) :matches(dir, menu, ol, ul) :matches(dir, menu, ul) { 195 | list-style-type: square; 196 | } 197 | 198 | 199 | table { display: table; } 200 | caption { display: table-caption; } 201 | colgroup, colgroup[hidden] { display: table-column-group; } 202 | col, col[hidden] { display: table-column; } 203 | thead, thead[hidden] { display: table-header-group; } 204 | tbody, tbody[hidden] { display: table-row-group; } 205 | tfoot, tfoot[hidden] { display: table-footer-group; } 206 | tr, tr[hidden] { display: table-row; } 207 | td, th, td[hidden], th[hidden] { display: table-cell; } 208 | 209 | colgroup[hidden], col[hidden], thead[hidden], tbody[hidden], 210 | tfoot[hidden], tr[hidden], td[hidden], th[hidden] { 211 | visibility: collapse; 212 | } 213 | 214 | table { 215 | box-sizing: border-box; 216 | border-spacing: 2px; 217 | border-collapse: separate; 218 | text-indent: initial; 219 | } 220 | td, th { padding: 1px; } 221 | th { font-weight: bold; } 222 | 223 | thead, tbody, tfoot, table > tr { vertical-align: middle; } 224 | tr, td, th { vertical-align: inherit; } 225 | 226 | 227 | table, td, th { border-color: gray; } 228 | thead, tbody, tfoot, tr { border-color: inherit; } 229 | table:matches( 230 | [rules=none i], [rules=groups i], [rules=rows i], 231 | [rules=cols i], [rules=all i], 232 | [frame=void i], [frame=above i], [frame=below i], 233 | [frame=hsides i], [frame=lhs i], [frame=rhs i], 234 | [frame=vsides i], [frame=box i], [frame=border i] 235 | ), 236 | table:matches( 237 | [rules=none i], [rules=groups i], [rules=rows i], 238 | [rules=cols i], [rules=all i] 239 | ) > tr > :matches(td, th), 240 | table:matches( 241 | [rules=none i], [rules=groups i], [rules=rows i], 242 | [rules=cols i], [rules=all i] 243 | ) > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { 244 | border-color: black; 245 | } 246 | 247 | 248 | :matches(table, thead, tbody, tfoot, tr) > form { 249 | display: none !important; 250 | } 251 | 252 | 253 | input, select, option, optgroup, button, textarea, keygen { 254 | text-indent: initial; 255 | text-transform: none; 256 | } 257 | 258 | textarea { white-space: pre-wrap; } 259 | 260 | input[type="radio"], input[type="checkbox"], input[type="reset"], input[type="button"], 261 | input[type="submit"], select, button { 262 | box-sizing: border-box; 263 | } 264 | 265 | input, textarea, select, button { display: inline-block; } 266 | 267 | hr { color: gray; border-style: inset; border-width: 1px; margin: 0.5em auto; } 268 | 269 | 270 | fieldset { 271 | display: block; /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=27018 */ 272 | margin-left: 2px; margin-right: 2px; 273 | border: groove 2px; 274 | border-color: ThreeDFace; /* FIXME: system color */ 275 | padding: 0.35em 0.625em 0.75em; 276 | min-width: min-content; 277 | } 278 | 279 | legend { 280 | padding-left: 2px; padding-right: 2px; 281 | } 282 | 283 | iframe:not([seamless]) { border: 2px inset; } 284 | iframe[seamless] { display: block; } 285 | video { object-fit: contain; } 286 | 287 | 288 | textarea { white-space: pre-wrap; } 289 | 290 | *|*:not(:root):fullscreen { 291 | position:fixed !important; 292 | top:0 !important; right:0 !important; bottom:0 !important; left:0 !important; 293 | margin:0 !important; 294 | box-sizing:border-box !important; 295 | min-width:0 !important; 296 | max-width:none !important; 297 | min-height:0 !important; 298 | max-height:none !important; 299 | width:100% !important; 300 | height:100% !important; 301 | transform:none !important; 302 | 303 | /* intentionally not !important */ 304 | object-fit:contain; 305 | } 306 | 307 | iframe:fullscreen { 308 | border:none !important; 309 | padding:0 !important; 310 | } 311 | -------------------------------------------------------------------------------- /shell_resources/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ServoShell Home 5 | 6 | 14 | 15 |

ServoShell

16 |

Report a Servo issue

17 |

Report a ServoShell issue

18 |
19 |
T
new tab
20 |
W
close tab
21 |
R
reload
22 |
Left/Right
go back/forward in history
23 |
L
search or enter a new url
24 |
=/-/0
zoom in/out/reset
25 |
Ctrl (shift) tab
next/previous tab
26 |
1..9
select tab
27 |
Q
quit
28 |
29 | 30 | 42 | -------------------------------------------------------------------------------- /shell_resources/icons/128x128-x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/shell_resources/icons/128x128-x2.png -------------------------------------------------------------------------------- /shell_resources/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/shell_resources/icons/128x128.png -------------------------------------------------------------------------------- /shell_resources/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/shell_resources/icons/32x32.png -------------------------------------------------------------------------------- /shell_resources/icons/ServoShell.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/shell_resources/icons/ServoShell.icns -------------------------------------------------------------------------------- /shell_resources/icons/ServoShell.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulrouget/servoshell/a51916ae135730afda6bf3e26e5793595049ecba/shell_resources/icons/ServoShell.ico -------------------------------------------------------------------------------- /src/logs.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use log::*; 6 | use std::sync::{Arc, Mutex}; 7 | 8 | pub struct ShellLog { 9 | pub level: LogLevel, 10 | pub target: String, 11 | pub message: String, 12 | } 13 | 14 | pub struct ShellLogs(Mutex>); 15 | 16 | impl ShellLogs { 17 | pub fn get_logs(&self) -> Vec { 18 | let mut vec = self.0.lock().unwrap(); 19 | let res = vec.drain(..).collect(); 20 | res 21 | } 22 | } 23 | 24 | pub struct Logger(Arc); 25 | 26 | impl Logger { 27 | pub fn init() -> Arc { 28 | let mut rv = None; 29 | set_logger(|max_log_level| { 30 | max_log_level.set(LogLevelFilter::Info); 31 | let logs = Arc::new(ShellLogs(Mutex::new(Vec::new()))); 32 | rv = Some(logs.clone()); 33 | Box::new(Logger(logs)) 34 | }) 35 | .unwrap(); 36 | rv.unwrap() 37 | } 38 | } 39 | 40 | impl Log for Logger { 41 | fn enabled(&self, metadata: &LogMetadata) -> bool { 42 | metadata.level() <= LogLevel::Info 43 | } 44 | 45 | fn log(&self, record: &LogRecord) { 46 | if self.enabled(record.metadata()) { 47 | let log = ShellLog { 48 | level: record.level(), 49 | message: format!("{}", record.args()), 50 | target: format!("{}", record.target()), 51 | }; 52 | (self.0).0.lock().unwrap().push(log); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/platform/cocoa/bookmarks.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use cocoa::base::*; 6 | use cocoa::foundation::*; 7 | use objc::declare::ClassDecl; 8 | use objc::runtime::{Class, Object, Sel}; 9 | 10 | pub fn register() { 11 | 12 | /* NShellBookmark */ 13 | { 14 | let superclass = Class::get("NSObject").unwrap(); 15 | let mut newclass = ClassDecl::new("NSShellBookmark", superclass).unwrap(); 16 | newclass.add_ivar::("link"); 17 | newclass.add_ivar::("name"); 18 | newclass.register(); 19 | } 20 | 21 | /* NSShellBookmarks */ 22 | { 23 | let superclass = Class::get("NSObject").unwrap(); 24 | let mut newclass = ClassDecl::new("NSShellBookmarks", superclass).unwrap(); 25 | newclass.add_ivar::("bookmarks"); 26 | 27 | extern "C" fn awake_from_nib(_this: &mut Object, _sel: Sel) {} 28 | 29 | extern "C" fn child_of_item(_this: &Object, 30 | _sel: Sel, 31 | _outlineview: id, 32 | _index: NSInteger, 33 | _item: id) 34 | -> id { 35 | nil 36 | } 37 | 38 | extern "C" fn is_item_expandable(_this: &Object, 39 | _sel: Sel, 40 | _outlineview: id, 41 | _item: id) 42 | -> BOOL { 43 | NO 44 | } 45 | 46 | extern "C" fn number_of_child_of_item(_this: &Object, 47 | _sel: Sel, 48 | _outlineview: id, 49 | _item: id) 50 | -> NSInteger { 51 | 0 52 | } 53 | 54 | extern "C" fn object_value(_this: &Object, 55 | _sel: Sel, 56 | _outlineview: id, 57 | _column: id, 58 | _item: id) 59 | -> id { 60 | nil 61 | } 62 | 63 | // FIXME: Yeah! Outlets, we want to use that everywhere instead of subviews 64 | // let textfield = msg_send![view, textField]; 65 | 66 | unsafe { 67 | newclass.add_method(sel!(outlineView:child:ofItem:), 68 | child_of_item as 69 | extern "C" fn(&Object, Sel, id, NSInteger, id) -> id); 70 | newclass.add_method(sel!(outlineView:isItemExpandable:), 71 | is_item_expandable as extern "C" fn(&Object, Sel, id, id) -> BOOL); 72 | newclass.add_method(sel!(outlineView:numberOfChildrenOfItem:), 73 | number_of_child_of_item as 74 | extern "C" fn(&Object, Sel, id, id) -> NSInteger); 75 | newclass.add_method(sel!(outlineView:objectValueForTableColumn:byItem:), 76 | object_value as extern "C" fn(&Object, Sel, id, id, id) -> id); 77 | newclass.add_method(sel!(awakeFromNib), 78 | awake_from_nib as extern "C" fn(&mut Object, Sel)); 79 | } 80 | 81 | newclass.register(); 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/platform/cocoa/mod.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | mod app; 6 | mod bookmarks; 7 | mod toolbar; 8 | mod utils; 9 | mod view; 10 | mod window; 11 | 12 | pub use self::app::App; 13 | pub use self::view::View; 14 | pub use self::window::Window; 15 | -------------------------------------------------------------------------------- /src/platform/cocoa/toolbar.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use cocoa::base::*; 6 | use cocoa::foundation::*; 7 | use objc::declare::ClassDecl; 8 | use objc::runtime::{Class, Object, Sel}; 9 | use super::utils::get_app_state; 10 | 11 | pub fn register() { 12 | 13 | /* NSShellSegmentedCell */ 14 | { 15 | let superclass = Class::get("NSSegmentedCell").unwrap(); 16 | let mut class = ClassDecl::new("NSShellSegmentedCell", superclass).unwrap(); 17 | 18 | extern "C" fn draw(this: &Object, _sel: Sel, rect: NSRect, view: id) { 19 | unsafe { 20 | let dark = get_app_state().dark_theme; 21 | if dark { 22 | msg_send![this, drawInteriorWithFrame:rect inView:view]; 23 | } else { 24 | let class = Class::get("NSSegmentedCell").unwrap(); 25 | msg_send![super(this, class), drawWithFrame:rect inView:view]; 26 | } 27 | } 28 | } 29 | 30 | unsafe { 31 | class.add_method(sel!(drawWithFrame:inView:), 32 | draw as extern "C" fn(&Object, Sel, NSRect, id)); 33 | } 34 | 35 | class.register(); 36 | } 37 | 38 | /* NSShellTextFieldCell */ 39 | { 40 | let superclass = Class::get("NSTextFieldCell").unwrap(); 41 | let mut newclass = ClassDecl::new("NSShellTextFieldCell", superclass).unwrap(); 42 | 43 | extern "C" fn draw(this: &Object, _sel: Sel, rect: NSRect, view: id) { 44 | unsafe { 45 | let dark = get_app_state().dark_theme; 46 | let superclass = Class::get("NSTextFieldCell").unwrap(); 47 | if dark { 48 | msg_send![super(this, superclass), drawInteriorWithFrame:rect inView:view]; 49 | } else { 50 | msg_send![super(this, superclass), drawWithFrame:rect inView:view]; 51 | } 52 | } 53 | } 54 | 55 | unsafe { 56 | newclass.add_method(sel!(drawWithFrame:inView:), 57 | draw as extern "C" fn(&Object, Sel, NSRect, id)); 58 | } 59 | 60 | newclass.register(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/platform/cocoa/utils.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use cocoa::appkit::*; 6 | use cocoa::base::*; 7 | use cocoa::foundation::*; 8 | use libc; 9 | use objc::runtime::Object; 10 | use platform::App; 11 | use state::{AppState, WindowState}; 12 | use std::ffi::CStr; 13 | use std::os::raw::c_void; 14 | 15 | pub fn load_nib<'a>(filename: &str) -> Result, &'a str> { 16 | 17 | let path = match App::get_nibs_path() { 18 | Some(path) => path, 19 | None => return Err(&"Can't find nib file"), 20 | }; 21 | let path = path.join(filename); 22 | let path = path.to_str().unwrap(); 23 | 24 | unsafe { 25 | let filename = NSString::alloc(nil).init_str(path); 26 | let nsdata: id = msg_send![class("NSData"), dataWithContentsOfFile: filename]; 27 | let nsnib: id = msg_send![class("NSNib"), alloc]; 28 | msg_send![nsnib, initWithNibData:nsdata bundle:nil]; 29 | 30 | let objects: id = msg_send![class("NSArray"), alloc]; 31 | msg_send![objects, init]; 32 | 33 | let success: BOOL = msg_send![nsnib, instantiateWithOwner:nil topLevelObjects:&objects]; 34 | if success == NO { 35 | return Err(&"Can't load nib file"); 36 | } 37 | 38 | let count: NSInteger = msg_send![objects, count]; 39 | 40 | let mut instances = Vec::new(); 41 | 42 | for i in 0..count { 43 | let instance: id = msg_send![objects, objectAtIndex: i]; 44 | instances.push(instance); 45 | } 46 | 47 | Ok(instances) 48 | } 49 | } 50 | 51 | pub fn id_is_instance_of(id: id, classname: &'static str) -> bool { 52 | let is_instance: BOOL = unsafe { 53 | let classname = class(classname); 54 | msg_send![id, isKindOfClass: classname] 55 | }; 56 | is_instance == YES 57 | } 58 | 59 | pub fn get_event_queue(obj: &Object) -> &mut Vec { 60 | get_ivar(obj, "event_queue") 61 | } 62 | 63 | pub fn get_ivar<'a, T>(obj: &'a Object, var: &'static str) -> &'a mut T { 64 | unsafe { 65 | let ivar: *mut c_void = *obj.get_ivar(var); 66 | &mut *(ivar as *mut T) 67 | } 68 | } 69 | 70 | // FIXME: Is there a better way? 71 | #[allow(dead_code)] 72 | pub fn get_classname(id: id) -> String { 73 | unsafe { 74 | let name: id = msg_send![id, className]; 75 | let name: *const libc::c_char = msg_send![name, UTF8String]; 76 | CStr::from_ptr(name).to_string_lossy().into_owned() 77 | } 78 | } 79 | 80 | pub fn get_view_by_id(id: id, name: &'static str) -> Option { 81 | // FIXME: cache 82 | let mut toolbar: Option = None; 83 | let nsview: id = if id_is_instance_of(id, "NSWindow") { 84 | unsafe { 85 | toolbar = Some(msg_send![id, toolbar]); 86 | msg_send![id, contentView] 87 | } 88 | } else { 89 | id 90 | }; 91 | let view = get_view(nsview, 92 | &|view| unsafe { 93 | let identifier: id = msg_send![view, identifier]; 94 | NSString::isEqualToString(identifier, name) 95 | }); 96 | // If we can't find a view in the window, let's look in the toolbar 97 | view.or_else(|| { 98 | unsafe { 99 | if let Some(toolbar) = toolbar { 100 | let items: id = msg_send![toolbar, items]; 101 | let count: NSInteger = msg_send![items, count]; 102 | for i in 0..count { 103 | let item: id = msg_send![items, objectAtIndex:i]; 104 | let item_identifier: id = msg_send![item, itemIdentifier]; 105 | let view = msg_send![item, view]; 106 | if NSString::isEqualToString(item_identifier, name) { 107 | return Some(view); 108 | } 109 | if let Some(view) = get_view(view, &|view| { 110 | let identifier: id = msg_send![view, identifier]; 111 | NSString::isEqualToString(identifier, name) 112 | }) { 113 | return Some(view); 114 | } 115 | } 116 | } 117 | } 118 | None 119 | }) 120 | } 121 | 122 | pub fn get_view(nsview: id, predicate: &F) -> Option 123 | where F: Fn(id) -> bool 124 | { 125 | if predicate(nsview) { 126 | return Some(nsview); 127 | } 128 | unsafe { 129 | let subviews: id = msg_send![nsview, subviews]; 130 | let count: NSInteger = msg_send![subviews, count]; 131 | for i in 0..count { 132 | let view: id = msg_send![subviews, objectAtIndex: i]; 133 | if let Some(view) = get_view(view, predicate) { 134 | return Some(view); 135 | } 136 | } 137 | return None; 138 | } 139 | } 140 | 141 | pub fn get_app_state<'a>() -> &'a AppState { 142 | unsafe { 143 | let delegate: id = msg_send![NSApp(), delegate]; 144 | let ivar: *const c_void = *(&*delegate).get_ivar("app_state"); 145 | &*(ivar as *const AppState) 146 | } 147 | } 148 | 149 | pub fn get_win_state<'a>() -> &'a WindowState { 150 | unsafe { 151 | let delegate: id = msg_send![NSApp(), delegate]; 152 | let ivar: *const c_void = *(&*delegate).get_ivar("win_state"); 153 | &*(ivar as *const WindowState) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/platform/glutin/app.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use glutin::{self, GlContext}; 6 | use platform::Window; 7 | use servo::{ServoCursor, EventLoopWaker}; 8 | use state::{AppState, ChangeType, DiffKey, WindowState}; 9 | use std::cell::{Cell, RefCell}; 10 | use std::collections::HashMap; 11 | use std::env; 12 | use std::path::PathBuf; 13 | use std::rc::Rc; 14 | use std::sync::Arc; 15 | use super::GlutinWindow; 16 | use super::utils; 17 | use traits::app::{AppEvent, AppMethods}; 18 | use traits::window::{WindowEvent, WindowMethods}; 19 | use traits::view::{gl, KeyModifiers}; 20 | 21 | pub struct WinitEventLoopWaker { 22 | proxy: Arc, 23 | } 24 | 25 | impl EventLoopWaker for WinitEventLoopWaker { 26 | fn clone(&self) -> Box { 27 | box WinitEventLoopWaker { proxy: self.proxy.clone() } 28 | } 29 | fn wake(&self) { 30 | self.proxy.wakeup().expect("wakeup eventloop failed"); 31 | } 32 | } 33 | 34 | pub struct App { 35 | event_loop: RefCell, 36 | event_loop_waker: Box, 37 | windows: Rc>>, 38 | } 39 | 40 | impl App { 41 | fn should_exit(&self, event: &glutin::WindowEvent) -> bool { 42 | // Exit if window is closed or if Cmd/Ctrl Q 43 | match *event { 44 | glutin::WindowEvent::Closed => return true, 45 | _ => {} 46 | } 47 | 48 | if let glutin::WindowEvent::KeyboardInput { 49 | device_id: _, 50 | input: glutin::KeyboardInput { 51 | state: glutin::ElementState::Pressed, 52 | scancode: _, 53 | virtual_keycode: Some(glutin::VirtualKeyCode::Q), 54 | modifiers, 55 | }, 56 | } = *event { 57 | if utils::cmd_or_ctrl(modifiers) { 58 | return true; 59 | } 60 | } 61 | false 62 | } 63 | 64 | fn render_cursor(&self, cursor: ServoCursor) { 65 | let cursor = utils::servo_cursor_to_glutin_cursor(cursor); 66 | let windows = self.windows.borrow(); 67 | for (_, window) in windows.iter() { 68 | window.glutin_window.set_cursor(cursor); 69 | } 70 | } 71 | } 72 | 73 | impl AppMethods for App { 74 | fn new<'a>(_state: &AppState) -> Result { 75 | 76 | let event_loop = glutin::EventsLoop::new(); 77 | let event_loop_waker = 78 | box WinitEventLoopWaker { proxy: Arc::new(event_loop.create_proxy()) }; 79 | let windows = Rc::new(RefCell::new(HashMap::new())); 80 | Ok(App { 81 | windows, 82 | event_loop: RefCell::new(event_loop), 83 | event_loop_waker, 84 | }) 85 | } 86 | 87 | fn get_resources_path() -> Option { 88 | // Try current directory. Used for example with "cargo run" 89 | let p = env::current_dir().unwrap(); 90 | if p.join("servo_resources/").exists() { 91 | return Some(p.join("servo_resources/")); 92 | } 93 | 94 | // Maybe in /resources/ 95 | let p = p.join("resources").join("servo_resources"); 96 | if p.exists() { 97 | return Some(p); 98 | } 99 | 100 | // Maybe we run from an app bundle 101 | let p = env::current_exe().unwrap(); 102 | let p = p.parent().unwrap(); 103 | let p = p.parent().unwrap().join("Resources"); 104 | 105 | if p.join("servo_resources/").exists() { 106 | return Some(p.join("servo_resources/")); 107 | } 108 | 109 | None 110 | } 111 | 112 | fn render(&self, diff: Vec, state: &AppState) { 113 | for change in diff { 114 | use self::DiffKey as K; 115 | match change { 116 | ChangeType::Modified(keys) => { 117 | match keys.as_slice() { 118 | &[K::cursor] => self.render_cursor(state.cursor), 119 | _ => println!("App::render: unexpected keys: {:?}", keys), 120 | } 121 | } 122 | _ => println!("App::render: unexpected change type: {:?}", change), 123 | } 124 | } 125 | } 126 | 127 | fn get_events(&self) -> Vec { 128 | vec![] 129 | } 130 | 131 | fn new_window<'a>(&self, state: &WindowState) -> Result, &'a str> { 132 | 133 | #[cfg(target_os = "windows")] 134 | let factor = utils::windows_hidpi_factor(); 135 | #[cfg(not(target_os = "windows"))] 136 | let factor = 1.0; 137 | 138 | let window = glutin::WindowBuilder::new().with_dimensions(1024 * factor as u32, 139 | 768 * factor as u32); 140 | let context = glutin::ContextBuilder::new() 141 | .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2))) 142 | .with_vsync(true); 143 | let glutin_window = glutin::GlWindow::new(window, context, &*self.event_loop.borrow_mut()) 144 | .unwrap(); 145 | 146 | let gl = unsafe { 147 | glutin_window 148 | .context() 149 | .make_current() 150 | .expect("Couldn't make window current"); 151 | gl::GlFns::load_with(|s| glutin_window.context().get_proc_address(s) as *const _) 152 | }; 153 | 154 | gl.clear_color(1.0, 1.0, 1.0, 1.0); 155 | gl.clear(gl::COLOR_BUFFER_BIT); 156 | gl.finish(); 157 | 158 | glutin_window.show(); 159 | 160 | let id = glutin_window.id(); 161 | 162 | self.windows 163 | .borrow_mut() 164 | .insert(id, 165 | GlutinWindow { 166 | gl, 167 | glutin_window, 168 | event_loop_waker: self.event_loop_waker.clone(), 169 | key_modifiers: Cell::new(KeyModifiers::empty()), 170 | last_pressed_key: Cell::new(None), 171 | view_events: vec![], 172 | window_events: vec![], 173 | mouse_coordinate: (0, 0), 174 | }); 175 | 176 | Ok(Box::new(Window::new(id, state, self.windows.clone()))) 177 | } 178 | 179 | fn run(&self, mut callback: T) 180 | where T: FnMut() 181 | { 182 | self.event_loop 183 | .borrow_mut() 184 | .run_forever(|e| { 185 | let mut call_callback = false; 186 | match e { 187 | glutin::Event::WindowEvent { event, window_id } => { 188 | if self.should_exit(&event) { 189 | return glutin::ControlFlow::Break; 190 | } 191 | let mut windows = self.windows.borrow_mut(); 192 | match windows.get_mut(&window_id) { 193 | Some(window) => { 194 | match (*window).glutin_event_to_command(&event) { 195 | Some(command) => { 196 | window 197 | .window_events 198 | .push(WindowEvent::DoCommand(command)); 199 | call_callback = true; 200 | } 201 | None => { 202 | match (*window).glutin_event_to_view_event(&event) { 203 | Some(event) => { 204 | window.view_events.push(event); 205 | call_callback = true; 206 | } 207 | None => { 208 | warn!("Got unknown glutin event: {:?}", event); 209 | } 210 | } 211 | } 212 | } 213 | } 214 | None => { 215 | warn!("Unexpected event ({:?} for unknown Windows ({:?})", 216 | event, 217 | window_id); 218 | } 219 | } 220 | } 221 | glutin::Event::Awakened => { 222 | let mut windows = self.windows.borrow_mut(); 223 | for (_, window) in windows.iter_mut() { 224 | window.window_events.push(WindowEvent::EventLoopAwaken); 225 | } 226 | call_callback = true; 227 | } 228 | _ => {} 229 | } 230 | if call_callback { 231 | callback(); 232 | } 233 | glutin::ControlFlow::Continue 234 | }); 235 | callback() 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/platform/glutin/mod.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | mod app; 6 | mod utils; 7 | mod view; 8 | mod window; 9 | 10 | use glutin; 11 | use servo::EventLoopWaker; 12 | use std::cell::Cell; 13 | use std::rc::Rc; 14 | use traits::view::*; 15 | use traits::window::{WindowCommand, WindowEvent}; 16 | 17 | pub use self::app::App; 18 | pub use self::view::View; 19 | pub use self::window::Window; 20 | 21 | pub struct GlutinWindow { 22 | gl: Rc, 23 | glutin_window: glutin::GlWindow, 24 | event_loop_waker: Box, 25 | key_modifiers: Cell, 26 | last_pressed_key: Cell>, 27 | mouse_coordinate: (i32, i32), 28 | view_events: Vec, 29 | window_events: Vec, 30 | } 31 | 32 | impl GlutinWindow { 33 | pub fn glutin_event_to_command(&self, event: &glutin::WindowEvent) -> Option { 34 | match *event { 35 | glutin::WindowEvent::KeyboardInput { 36 | input: glutin::KeyboardInput { 37 | state: glutin::ElementState::Pressed, 38 | virtual_keycode, 39 | modifiers, 40 | .. 41 | }, 42 | .. 43 | } => { 44 | match (virtual_keycode, 45 | utils::cmd_or_ctrl(modifiers), 46 | modifiers.ctrl, 47 | modifiers.shift) { 48 | (Some(glutin::VirtualKeyCode::R), true, _, _) => Some(WindowCommand::Reload), 49 | (Some(glutin::VirtualKeyCode::Left), true, _, _) => { 50 | Some(WindowCommand::NavigateBack) 51 | } 52 | (Some(glutin::VirtualKeyCode::Right), true, _, _) => { 53 | Some(WindowCommand::NavigateForward) 54 | } 55 | (Some(glutin::VirtualKeyCode::L), true, _, _) => { 56 | Some(WindowCommand::OpenLocation) 57 | } 58 | (Some(glutin::VirtualKeyCode::Equals), true, _, _) => { 59 | Some(WindowCommand::ZoomIn) 60 | } 61 | (Some(glutin::VirtualKeyCode::Minus), true, _, _) => { 62 | Some(WindowCommand::ZoomOut) 63 | } 64 | (Some(glutin::VirtualKeyCode::Key0), true, _, _) => { 65 | Some(WindowCommand::ZoomToActualSize) 66 | } 67 | (Some(glutin::VirtualKeyCode::T), true, _, _) => Some(WindowCommand::NewTab), 68 | (Some(glutin::VirtualKeyCode::W), true, _, _) => Some(WindowCommand::CloseTab), 69 | (Some(glutin::VirtualKeyCode::Tab), _, true, false) => { 70 | Some(WindowCommand::NextTab) 71 | } 72 | (Some(glutin::VirtualKeyCode::Tab), _, true, true) => { 73 | Some(WindowCommand::PrevTab) 74 | } 75 | (Some(glutin::VirtualKeyCode::Key1), true, _, _) => { 76 | Some(WindowCommand::SelectTab(0)) 77 | } 78 | (Some(glutin::VirtualKeyCode::Key2), true, _, _) => { 79 | Some(WindowCommand::SelectTab(1)) 80 | } 81 | (Some(glutin::VirtualKeyCode::Key3), true, _, _) => { 82 | Some(WindowCommand::SelectTab(2)) 83 | } 84 | (Some(glutin::VirtualKeyCode::Key4), true, _, _) => { 85 | Some(WindowCommand::SelectTab(3)) 86 | } 87 | (Some(glutin::VirtualKeyCode::Key5), true, _, _) => { 88 | Some(WindowCommand::SelectTab(4)) 89 | } 90 | (Some(glutin::VirtualKeyCode::Key6), true, _, _) => { 91 | Some(WindowCommand::SelectTab(5)) 92 | } 93 | (Some(glutin::VirtualKeyCode::Key7), true, _, _) => { 94 | Some(WindowCommand::SelectTab(6)) 95 | } 96 | (Some(glutin::VirtualKeyCode::Key8), true, _, _) => { 97 | Some(WindowCommand::SelectTab(7)) 98 | } 99 | (Some(glutin::VirtualKeyCode::Key9), true, _, _) => { 100 | Some(WindowCommand::SelectTab(8)) 101 | } 102 | _ => None, 103 | } 104 | } 105 | _ => None, 106 | } 107 | } 108 | 109 | pub fn glutin_event_to_view_event(&mut self, event: &glutin::WindowEvent) -> Option { 110 | match *event { 111 | glutin::WindowEvent::Resized(..) => Some(ViewEvent::GeometryDidChange), 112 | glutin::WindowEvent::MouseMoved { position: (x, y), .. } => { 113 | self.mouse_coordinate = (x as i32, y as i32); 114 | Some(ViewEvent::MouseMoved(x as i32, y as i32)) 115 | } 116 | glutin::WindowEvent::MouseWheel { delta, phase, .. } => { 117 | let delta = match delta { 118 | // FIXME: magic value 119 | glutin::MouseScrollDelta::LineDelta(dx, dy) => { 120 | MouseScrollDelta::LineDelta(dx, dy) 121 | } 122 | glutin::MouseScrollDelta::PixelDelta(dx, dy) => { 123 | MouseScrollDelta::PixelDelta(dx, dy) 124 | } 125 | }; 126 | let phase = match phase { 127 | glutin::TouchPhase::Started => TouchPhase::Started, 128 | glutin::TouchPhase::Moved => TouchPhase::Moved, 129 | glutin::TouchPhase::Ended => TouchPhase::Ended, 130 | // FIXME: 131 | glutin::TouchPhase::Cancelled => TouchPhase::Ended, 132 | }; 133 | Some(ViewEvent::MouseWheel(delta, phase)) 134 | } 135 | glutin::WindowEvent::MouseInput { 136 | state, 137 | button: glutin::MouseButton::Left, 138 | .. 139 | } => { 140 | let state = match state { 141 | glutin::ElementState::Released => ElementState::Released, 142 | glutin::ElementState::Pressed => ElementState::Pressed, 143 | }; 144 | Some(ViewEvent::MouseInput(state, 145 | MouseButton::Left, 146 | self.mouse_coordinate.0, 147 | self.mouse_coordinate.1)) 148 | } 149 | glutin::WindowEvent::ReceivedCharacter(ch) => { 150 | 151 | let mods = self.key_modifiers.get(); 152 | 153 | // FIXME: cleanup 154 | let event = if let Some(last_pressed_key) = self.last_pressed_key.get() { 155 | Some(ViewEvent::KeyEvent(Some(ch), last_pressed_key, KeyState::Pressed, mods)) 156 | } else { 157 | if !ch.is_control() { 158 | match utils::char_to_script_key(ch) { 159 | Some(key) => { 160 | Some(ViewEvent::KeyEvent(Some(ch), key, KeyState::Pressed, mods)) 161 | } 162 | None => None, 163 | } 164 | } else { 165 | None 166 | } 167 | }; 168 | self.last_pressed_key.set(None); 169 | event 170 | } 171 | glutin::WindowEvent::KeyboardInput { 172 | input: glutin::KeyboardInput { 173 | state, 174 | virtual_keycode: Some(virtual_keycode), 175 | modifiers, 176 | .. 177 | }, 178 | .. 179 | } => { 180 | 181 | let mut servo_mods = KeyModifiers::empty(); 182 | if modifiers.shift { 183 | servo_mods.insert(KeyModifiers::SHIFT); 184 | } 185 | if modifiers.ctrl { 186 | servo_mods.insert(KeyModifiers::CONTROL); 187 | } 188 | if modifiers.alt { 189 | servo_mods.insert(KeyModifiers::ALT); 190 | } 191 | if modifiers.logo { 192 | servo_mods.insert(KeyModifiers::SUPER); 193 | } 194 | 195 | self.key_modifiers.set(servo_mods); 196 | 197 | if let Ok(key) = utils::glutin_key_to_script_key(virtual_keycode) { 198 | let state = match state { 199 | glutin::ElementState::Pressed => KeyState::Pressed, 200 | glutin::ElementState::Released => KeyState::Released, 201 | }; 202 | if state == KeyState::Pressed { 203 | if utils::is_printable(virtual_keycode) { 204 | self.last_pressed_key.set(Some(key)); 205 | } 206 | } 207 | Some(ViewEvent::KeyEvent(None, key, state, self.key_modifiers.get())) 208 | } else { 209 | None 210 | } 211 | } 212 | 213 | _ => { 214 | None /* FIXME */ 215 | } 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/platform/glutin/view.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use glutin::{self, GlContext}; 6 | use std::cell::RefCell; 7 | use std::collections::HashMap; 8 | use std::rc::Rc; 9 | use super::GlutinWindow; 10 | use traits::view::*; 11 | 12 | pub struct View { 13 | id: glutin::WindowId, 14 | windows: Rc>>, 15 | } 16 | 17 | impl View { 18 | pub fn new(id: glutin::WindowId, 19 | windows: Rc>>) 20 | -> View { 21 | View { id, windows } 22 | } 23 | 24 | #[cfg(not(target_os = "windows"))] 25 | fn hidpi_factor(&self) -> f32 { 26 | let windows = self.windows.borrow(); 27 | let win = windows.get(&self.id).unwrap(); 28 | win.glutin_window.hidpi_factor() 29 | } 30 | 31 | #[cfg(target_os = "windows")] 32 | fn hidpi_factor(&self) -> f32 { 33 | super::utils::windows_hidpi_factor() 34 | } 35 | } 36 | 37 | impl ViewMethods for View { 38 | fn get_geometry(&self) -> DrawableGeometry { 39 | let windows = self.windows.borrow(); 40 | let win = windows.get(&self.id).unwrap(); 41 | let (mut width, mut height) = win.glutin_window 42 | .get_inner_size() 43 | .expect("Failed to get window inner size."); 44 | 45 | #[cfg(target_os = "windows")] 46 | let factor = super::utils::windows_hidpi_factor(); 47 | #[cfg(not(target_os = "windows"))] 48 | let factor = 1.0; 49 | 50 | width /= factor as u32; 51 | height /= factor as u32; 52 | 53 | DrawableGeometry { 54 | view_size: (width, height), 55 | margins: (0, 0, 0, 0), 56 | position: win.glutin_window 57 | .get_position() 58 | .expect("Failed to get window position."), 59 | hidpi_factor: self.hidpi_factor(), 60 | } 61 | } 62 | 63 | fn update_drawable(&self) { 64 | let windows = self.windows.borrow(); 65 | let win = windows.get(&self.id).unwrap(); 66 | let (w, h) = win.glutin_window 67 | .get_inner_size() 68 | .expect("Failed to get window inner size."); 69 | win.glutin_window.resize(w, h); 70 | } 71 | 72 | // FIXME: should be controlled by state 73 | fn enter_fullscreen(&self) {} 74 | 75 | // FIXME: should be controlled by state 76 | fn exit_fullscreen(&self) {} 77 | 78 | fn set_live_resize_callback(&self, _callback: &FnMut()) { 79 | // FIXME 80 | } 81 | 82 | fn gl(&self) -> Rc { 83 | self.windows 84 | .borrow() 85 | .get(&self.id) 86 | .unwrap() 87 | .gl 88 | .clone() 89 | } 90 | 91 | fn get_events(&self) -> Vec { 92 | let mut windows = self.windows.borrow_mut(); 93 | let win = windows.get_mut(&self.id).unwrap(); 94 | let events = win.view_events.drain(..).collect(); 95 | events 96 | } 97 | 98 | fn swap_buffers(&self) { 99 | self.windows 100 | .borrow() 101 | .get(&self.id) 102 | .unwrap() 103 | .glutin_window 104 | .swap_buffers() 105 | .unwrap(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/platform/glutin/window.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use glutin; 6 | use logs::ShellLog; 7 | use platform::View; 8 | use servo::EventLoopWaker; 9 | use state::{BrowserState, ChangeType, DiffKey, WindowState}; 10 | use std::cell::RefCell; 11 | use std::collections::HashMap; 12 | use std::rc::Rc; 13 | use super::GlutinWindow; 14 | use tinyfiledialogs; 15 | use traits::view::ViewMethods; 16 | use traits::window::{WindowCommand, WindowEvent, WindowMethods}; 17 | 18 | pub struct Window { 19 | id: glutin::WindowId, 20 | windows: Rc>>, 21 | } 22 | 23 | impl Window { 24 | pub fn new(id: glutin::WindowId, 25 | state: &WindowState, 26 | windows: Rc>>) 27 | -> Window { 28 | let window = Window { id, windows }; 29 | window.render_title(state); 30 | window 31 | } 32 | 33 | fn render_title(&self, state: &WindowState) { 34 | let text = state 35 | .tabs 36 | .alive_browsers() 37 | .iter() 38 | .fold("|".to_owned(), |f, b| { 39 | let title = b.title 40 | .as_ref() 41 | .and_then(|t| if t.is_empty() { None } else { Some(t) }) 42 | .map_or("No Title", |t| t.as_str()); 43 | let selected = if !b.is_background { '>' } else { ' ' }; 44 | let loading = if b.is_loading { '*' } else { ' ' }; 45 | format!("{} {} {:15.15} {}|", f, selected, title, loading) 46 | }); 47 | let mut windows = self.windows.borrow_mut(); 48 | windows 49 | .get_mut(&self.id) 50 | .unwrap() 51 | .glutin_window 52 | .set_title(&text); 53 | } 54 | 55 | fn render_urlbar(&self, state: &BrowserState) { 56 | if state.urlbar_focused { 57 | let mut windows = self.windows.borrow_mut(); 58 | let url = format!("{}", state.url.as_ref().map_or("", |t| t.as_str())); 59 | match tinyfiledialogs::input_box("Search or type URL", "Search or type URL", &url) { 60 | Some(input) => { 61 | let win = windows.get_mut(&self.id).unwrap(); 62 | win.window_events 63 | .push(WindowEvent::DoCommand(WindowCommand::Load(input))); 64 | } 65 | None => {} 66 | } 67 | windows 68 | .get_mut(&self.id) 69 | .unwrap() 70 | .window_events 71 | .push(WindowEvent::UrlbarFocusChanged(false)); 72 | } 73 | } 74 | } 75 | 76 | impl WindowMethods for Window { 77 | fn render(&self, diff: Vec, state: &WindowState) { 78 | 79 | let idx = state 80 | .tabs 81 | .fg_browser_index() 82 | .expect("no current browser"); 83 | let current_browser_state = state.tabs.ref_fg_browser().expect("no current browser"); 84 | 85 | for change in diff { 86 | use self::DiffKey as K; 87 | match change { 88 | ChangeType::Modified(keys) => { 89 | match keys.as_slice() { 90 | &[K::tabs, K::Index(_), K::Alive, K::is_background] | 91 | &[K::tabs, K::Index(_), K::Alive, K::is_loading] | 92 | &[K::tabs, K::Index(_), K::Alive, K::title] => { 93 | self.render_title(state); 94 | } 95 | 96 | &[K::status] | 97 | &[K::tabs, K::Index(_), K::Alive, K::url] | 98 | &[K::tabs, K::Index(_), K::Alive, K::can_go_back] | 99 | &[K::tabs, K::Index(_), K::Alive, K::can_go_forward] | 100 | &[K::tabs, K::Index(_), K::Alive, K::zoom] | 101 | &[K::tabs, K::Index(_), K::Alive, K::user_input] => { 102 | // Nothing to do 103 | } 104 | &[K::tabs, K::Index(i), K::Alive, K::urlbar_focused] if i == idx => { 105 | self.render_urlbar(current_browser_state); 106 | } 107 | _ => println!("Window::render: unexpected Modified keys: {:?}", keys), 108 | } 109 | } 110 | ChangeType::Added(keys) => { 111 | match keys.as_slice() { 112 | &[K::tabs, K::Index(_)] => { 113 | self.render_title(state); 114 | } 115 | _ => println!("Window::render: unexpected Added keys: {:?}", keys), 116 | } 117 | } 118 | ChangeType::Removed(keys) => { 119 | match keys.as_slice() { 120 | &[K::tabs, K::Index(_), K::Alive] => { 121 | self.render_title(state); 122 | } 123 | _ => println!("Window::render: unexpected Removed keys: {:?}", keys), 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | fn new_view(&self) -> Result, &'static str> { 131 | Ok(Rc::new(View::new(self.id, self.windows.clone()))) 132 | } 133 | 134 | fn new_event_loop_waker(&self) -> Box { 135 | let mut windows = self.windows.borrow_mut(); 136 | windows 137 | .get_mut(&self.id) 138 | .unwrap() 139 | .event_loop_waker 140 | .clone() 141 | } 142 | 143 | fn get_events(&self) -> Vec { 144 | let mut windows = self.windows.borrow_mut(); 145 | let win = windows.get_mut(&self.id).unwrap(); 146 | let events = win.window_events.drain(..).collect(); 147 | events 148 | } 149 | 150 | fn append_logs(&self, _logs: &Vec) {} 151 | } 152 | -------------------------------------------------------------------------------- /src/platform/mod.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | pub use self::platform::*; 6 | 7 | #[cfg(all(not(feature = "force-glutin"), target_os = "macos"))] 8 | #[path="cocoa/mod.rs"] 9 | mod platform; 10 | 11 | #[cfg(any(feature = "force-glutin", not(target_os = "macos")))] 12 | #[path="glutin/mod.rs"] 13 | mod platform; 14 | -------------------------------------------------------------------------------- /src/state/app.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use servo::ServoCursor; 6 | 7 | #[derive(Clone, PartialEq, Deserialize, Serialize)] 8 | pub struct AppState { 9 | pub current_window_index: Option, 10 | pub dark_theme: bool, 11 | pub cursor: ServoCursor, 12 | } 13 | 14 | impl AppState { 15 | pub fn new() -> AppState { 16 | AppState { 17 | current_window_index: None, 18 | dark_theme: false, 19 | cursor: ServoCursor::Default, 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/state/browser.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use servo::BrowserId; 6 | 7 | #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] 8 | pub struct BrowserState { 9 | pub id: BrowserId, 10 | pub is_background: bool, 11 | pub zoom: f32, 12 | pub url: Option, 13 | pub title: Option, 14 | // FIXME: pub favicon: Option<>, 15 | pub user_input: Option, 16 | pub can_go_back: bool, 17 | pub can_go_forward: bool, 18 | pub is_loading: bool, 19 | pub urlbar_focused: bool, 20 | // FIXME: 21 | // creation_timestamp 22 | } 23 | 24 | #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] 25 | pub struct DeadBrowserState { 26 | pub id: BrowserId, 27 | // FIXME: 28 | // close_timestamp, 29 | // creation_timestamp, 30 | // load_data: LoadData, 31 | } 32 | -------------------------------------------------------------------------------- /src/state/mod.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | mod app; 6 | mod browser; 7 | mod state; 8 | mod tabs; 9 | mod window; 10 | 11 | pub use self::state::{DiffKey, ChangeType, State}; 12 | pub use self::app::AppState; 13 | pub use self::browser::{BrowserState, DeadBrowserState}; 14 | pub use self::window::WindowState; 15 | -------------------------------------------------------------------------------- /src/state/state.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use treediff::{self, Delegate}; 6 | use serde::{Deserialize, Serialize}; 7 | use serde_json; 8 | 9 | pub struct State { 10 | current_state: T, 11 | last_state: T, 12 | has_changed: bool, 13 | } 14 | 15 | impl<'t, T> State 16 | where T: Clone + Deserialize<'t> + Serialize 17 | { 18 | pub fn new(state: T) -> State { 19 | State { 20 | last_state: state.clone(), 21 | current_state: state, 22 | has_changed: false, 23 | } 24 | } 25 | 26 | pub fn get(&self) -> &T { 27 | &self.current_state 28 | } 29 | 30 | pub fn get_mut(&mut self) -> &mut T { 31 | self.has_changed = true; 32 | &mut self.current_state 33 | } 34 | 35 | pub fn snapshot(&mut self) { 36 | self.has_changed = false; 37 | self.last_state = self.current_state.clone(); 38 | } 39 | 40 | pub fn diff<'a>(&self) -> Vec { 41 | if self.has_changed() { 42 | let from = serde_json::to_value(&self.last_state).unwrap(); 43 | let to = serde_json::to_value(&self.current_state).unwrap(); 44 | let mut recorder = DiffRecorder::new(); 45 | treediff::diff(&from, &to, &mut recorder); 46 | recorder.changes 47 | } else { 48 | vec![] 49 | } 50 | } 51 | 52 | pub fn has_changed(&self) -> bool { 53 | self.has_changed 54 | } 55 | } 56 | 57 | // FIXME: can we generate all of these with macros? 58 | // FIXME: I'm not even sure everything bound to a string 59 | 60 | #[allow(non_camel_case_types)] 61 | #[derive(Clone, Debug, PartialEq)] 62 | pub enum DiffKey { 63 | // Don't keep the string 64 | Unknown(String), 65 | Index(usize), 66 | Alive, 67 | Dead, 68 | is_background, 69 | dark_theme, 70 | cursor, 71 | tabs, 72 | sidebar_is_open, 73 | logs_visible, 74 | debug_options, 75 | status, 76 | urlbar_focused, 77 | options_open, 78 | title, 79 | id, 80 | zoom, 81 | url, 82 | user_input, 83 | can_go_back, 84 | can_go_forward, 85 | is_loading, 86 | show_fragment_borders, 87 | parallel_display_list_building, 88 | show_parallel_layout, 89 | convert_mouse_to_touch, 90 | show_tiles_borders, 91 | wr_profiler, 92 | wr_texture_cache_debug, 93 | wr_render_target_debug, 94 | } 95 | 96 | impl DiffKey { 97 | fn from_key(key: &treediff::value::Key) -> DiffKey { 98 | use treediff::value::Key::{Index, String}; 99 | match *key { 100 | Index(idx) => DiffKey::Index(idx), 101 | String(ref name) => { 102 | match name.as_ref() { 103 | "Dead" => DiffKey::Dead, 104 | "Alive" => DiffKey::Alive, 105 | "is_background" => DiffKey::is_background, 106 | "dark_theme" => DiffKey::dark_theme, 107 | "cursor" => DiffKey::cursor, 108 | "tabs" => DiffKey::tabs, 109 | "sidebar_is_open" => DiffKey::sidebar_is_open, 110 | "logs_visible" => DiffKey::logs_visible, 111 | "debug_options" => DiffKey::debug_options, 112 | "status" => DiffKey::status, 113 | "urlbar_focused" => DiffKey::urlbar_focused, 114 | "options_open" => DiffKey::options_open, 115 | "id" => DiffKey::id, 116 | "zoom" => DiffKey::zoom, 117 | "url" => DiffKey::url, 118 | "title" => DiffKey::title, 119 | "user_input" => DiffKey::user_input, 120 | "can_go_back" => DiffKey::can_go_back, 121 | "can_go_forward" => DiffKey::can_go_forward, 122 | "is_loading" => DiffKey::is_loading, 123 | "show_fragment_borders" => DiffKey::show_fragment_borders, 124 | "parallel_display_list_building" => DiffKey::parallel_display_list_building, 125 | "show_parallel_layout" => DiffKey::show_parallel_layout, 126 | "convert_mouse_to_touch" => DiffKey::convert_mouse_to_touch, 127 | "show_tiles_borders" => DiffKey::show_tiles_borders, 128 | "wr_profiler" => DiffKey::wr_profiler, 129 | "wr_texture_cache_debug" => DiffKey::wr_texture_cache_debug, 130 | "wr_render_target_debug" => DiffKey::wr_render_target_debug, 131 | s => DiffKey::Unknown(s.to_owned()), 132 | } 133 | } 134 | } 135 | } 136 | } 137 | 138 | #[derive(Debug, PartialEq)] 139 | pub enum ChangeType { 140 | Removed(Vec), 141 | Added(Vec), 142 | Modified(Vec), 143 | } 144 | 145 | #[derive(Debug, PartialEq)] 146 | struct DiffRecorder { 147 | cursor: Vec, 148 | pub changes: Vec, 149 | } 150 | 151 | impl DiffRecorder { 152 | fn new() -> DiffRecorder { 153 | DiffRecorder { 154 | cursor: Vec::new(), 155 | changes: Vec::new(), 156 | } 157 | } 158 | } 159 | 160 | fn mk<'b>(c: &Vec, k: Option<&'b treediff::value::Key>) -> Vec { 161 | let mut c = c.clone(); 162 | match k { 163 | Some(k) => { 164 | c.push(DiffKey::from_key(k)); 165 | c 166 | } 167 | None => c, 168 | } 169 | } 170 | 171 | impl<'a> Delegate<'a, treediff::value::Key, serde_json::Value> for DiffRecorder { 172 | fn push<'b>(&mut self, k: &'b treediff::value::Key) { 173 | self.cursor.push(DiffKey::from_key(k)) 174 | } 175 | fn pop(&mut self) { 176 | self.cursor.pop(); 177 | } 178 | fn removed<'b>(&mut self, k: &'b treediff::value::Key, _v: &'a serde_json::Value) { 179 | self.changes 180 | .push(ChangeType::Removed(mk(&self.cursor, Some(k)))); 181 | } 182 | fn added<'b>(&mut self, k: &'b treediff::value::Key, _v: &'a serde_json::Value) { 183 | self.changes 184 | .push(ChangeType::Added(mk(&self.cursor, Some(k)))); 185 | } 186 | fn modified<'b>(&mut self, _v1: &'a serde_json::Value, _v2: &'a serde_json::Value) { 187 | self.changes 188 | .push(ChangeType::Modified(mk(&self.cursor, None))); 189 | } 190 | fn unchanged<'b>(&mut self, _v: &'a serde_json::Value) {} 191 | } 192 | -------------------------------------------------------------------------------- /src/state/tabs.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use servo::BrowserId; 6 | use super::{BrowserState, DeadBrowserState}; 7 | 8 | #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] 9 | pub enum TabState { 10 | Alive(BrowserState), 11 | Dead(DeadBrowserState), 12 | } 13 | 14 | impl TabState { 15 | fn is_alive(&self) -> bool { 16 | match *self { 17 | TabState::Alive(_) => true, 18 | TabState::Dead(_) => false, 19 | } 20 | } 21 | fn is_fg(&self) -> bool { 22 | self.ref_browser() 23 | .map(|b| !b.is_background) 24 | .unwrap_or(false) 25 | } 26 | fn is_bg(&self) -> bool { 27 | self.ref_browser() 28 | .map(|b| b.is_background) 29 | .unwrap_or(false) 30 | } 31 | fn ref_browser(&self) -> Result<&BrowserState, &'static str> { 32 | match *self { 33 | TabState::Alive(ref x) => Ok(x), 34 | TabState::Dead(_) => Err("Dead browser"), 35 | } 36 | } 37 | fn mut_browser(&mut self) -> Result<&mut BrowserState, &'static str> { 38 | match *self { 39 | TabState::Alive(ref mut x) => Ok(x), 40 | TabState::Dead(_) => Err("Dead browser"), 41 | } 42 | } 43 | fn kill(&mut self) -> Result<(), &'static str> { 44 | if !self.is_alive() { 45 | return Err("Already dead"); 46 | } 47 | let id = self.ref_browser().unwrap().id; 48 | let tab = TabState::Dead(DeadBrowserState { id }); 49 | *self = tab; 50 | Ok(()) 51 | } 52 | fn foreground(&mut self) -> Result<(), &'static str> { 53 | match *self { 54 | TabState::Alive(ref mut browser) if browser.is_background => { 55 | browser.is_background = false; 56 | Ok(()) 57 | } 58 | TabState::Alive(_) => Err("Already foreground"), 59 | TabState::Dead(_) => Err("Dead browser"), 60 | } 61 | } 62 | fn background(&mut self) -> Result<(), &'static str> { 63 | match *self { 64 | TabState::Alive(ref mut browser) if !browser.is_background => { 65 | browser.is_background = true; 66 | Ok(()) 67 | } 68 | TabState::Alive(_) => Err("Already background"), 69 | TabState::Dead(_) => Err("Dead browser"), 70 | } 71 | } 72 | } 73 | 74 | #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] 75 | pub struct TabsState(Vec); 76 | 77 | #[allow(dead_code)] 78 | impl TabsState { 79 | pub fn new() -> TabsState { 80 | TabsState(Vec::new()) 81 | } 82 | 83 | pub fn has_more_than_one(&self) -> bool { 84 | self.0.iter().filter(|tab| tab.is_alive()).count() > 1 85 | } 86 | 87 | pub fn kill_fg(&mut self) -> Result { 88 | let fg_idx = self.0 89 | .iter() 90 | .position(TabState::is_fg) 91 | .ok_or("No foreground tab")?; 92 | if self.can_select_next()? { 93 | self.select_next()?; 94 | } else if self.can_select_prev()? { 95 | self.select_prev()?; 96 | } else { 97 | return Err("No background tab to select"); 98 | } 99 | let id = self.0[fg_idx].ref_browser()?.id; 100 | self.0[fg_idx].kill()?; 101 | Ok(id) 102 | } 103 | 104 | pub fn can_select_next(&self) -> Result { 105 | let fg_idx = self.0 106 | .iter() 107 | .position(TabState::is_fg) 108 | .ok_or("No foreground tab")?; 109 | Ok(self.0.iter().skip(fg_idx + 1).any(TabState::is_bg)) 110 | } 111 | 112 | pub fn select_next(&mut self) -> Result<(), &'static str> { 113 | let fg_idx = self.0 114 | .iter() 115 | .position(|tab| tab.is_fg()) 116 | .ok_or("No foreground tab")?; 117 | let next_idx = self.0 118 | .iter() 119 | .enumerate() 120 | .skip(fg_idx + 1) 121 | .find(|&(_, tab)| tab.is_bg()) 122 | .map(|(idx, _)| idx) 123 | .ok_or("No tab to select")?; 124 | self.0[fg_idx].background()?; 125 | self.0[next_idx].foreground()?; 126 | Ok(()) 127 | } 128 | 129 | pub fn can_select_prev(&self) -> Result { 130 | let fg_idx = self.0 131 | .iter() 132 | .position(TabState::is_fg) 133 | .ok_or("No foreground tab")?; 134 | Ok(self.0 135 | .iter() 136 | .rev() 137 | .skip(self.0.len() - fg_idx) 138 | .any(TabState::is_bg)) 139 | } 140 | 141 | pub fn select_prev(&mut self) -> Result<(), &'static str> { 142 | let fg_idx = self.0 143 | .iter() 144 | .position(TabState::is_fg) 145 | .ok_or("No foreground tab")?; 146 | let prev_idx = self.0 147 | .iter() 148 | .enumerate() 149 | .rev() 150 | .skip(self.0.len() - fg_idx) 151 | .find(|&(_, tab)| tab.is_bg()) 152 | .map(|(idx, _)| idx) 153 | .ok_or("No tab to select")?; 154 | self.0[fg_idx].background()?; 155 | self.0[prev_idx].foreground()?; 156 | Ok(()) 157 | } 158 | 159 | pub fn select_first(&mut self) -> Result<(), &'static str> { 160 | let fg_idx = self.0 161 | .iter() 162 | .position(TabState::is_fg) 163 | .ok_or("No foreground tab")?; 164 | let first_idx = self.0 165 | .iter() 166 | .position(TabState::is_bg) 167 | .ok_or("No tab to select")?; 168 | self.0[fg_idx].background()?; 169 | self.0[first_idx].foreground()?; 170 | Ok(()) 171 | } 172 | 173 | pub fn select_last(&mut self) -> Result<(), &'static str> { 174 | let fg_idx = self.0 175 | .iter() 176 | .position(TabState::is_fg) 177 | .ok_or("No foreground tab")?; 178 | let last_idx = self.0 179 | .iter() 180 | .enumerate() 181 | .rev() 182 | .find(|&(_, tab)| tab.is_bg()) 183 | .map(&|(idx, _)| idx) 184 | .ok_or("No tab to select")?; 185 | self.0[fg_idx].background()?; 186 | self.0[last_idx].foreground()?; 187 | Ok(()) 188 | } 189 | 190 | pub fn can_select_nth(&self, index: usize) -> bool { 191 | self.0 192 | .iter() 193 | .filter(|tab| tab.is_alive()) 194 | .nth(index) 195 | .is_some() 196 | } 197 | 198 | pub fn select_nth(&mut self, index: usize) -> Result<(), &'static str> { 199 | let fg_idx = self.0 200 | .iter() 201 | .position(TabState::is_fg) 202 | .ok_or("No foreground tab")?; 203 | let nth_idx = self.0 204 | .iter() 205 | .enumerate() 206 | .filter(|&(_, tab)| tab.is_alive()) 207 | .nth(index) 208 | .map(|(index, _)| index) 209 | .ok_or("No tab to select")?; 210 | self.0[fg_idx].background()?; 211 | self.0[nth_idx].foreground()?; 212 | Ok(()) 213 | } 214 | 215 | pub fn append_new(&mut self, mut browser: BrowserState) -> Result<(), &'static str> { 216 | if self.0.len() == 0 { 217 | browser.is_background = false; 218 | self.0.push(TabState::Alive(browser)); 219 | Ok(()) 220 | } else if !browser.is_background { 221 | browser.is_background = true; 222 | self.0.push(TabState::Alive(browser)); 223 | self.select_last() 224 | } else { 225 | self.0.push(TabState::Alive(browser)); 226 | Ok(()) 227 | } 228 | } 229 | 230 | pub fn find_browser(&mut self, id: &BrowserId) -> Option<&mut BrowserState> { 231 | self.0 232 | .iter_mut() 233 | .filter_map(|tab| tab.mut_browser().ok()) 234 | .find(|b| b.id == *id) 235 | } 236 | 237 | pub fn find_browser_at(&self, idx: usize) -> Option<&BrowserState> { 238 | self.0 239 | .iter() 240 | .nth(idx) 241 | .and_then(|tab| tab.ref_browser().ok()) 242 | } 243 | 244 | pub fn index_to_alive_index(&self, idx: usize) -> Option { 245 | // We need to also check tab == found_tab as we don't want 246 | // to discard a dead tab. The user might want to know the 247 | // position of what used to be an alive tab 248 | self.0 249 | .iter() 250 | .nth(idx) 251 | .and_then(|found_tab| { 252 | self.0 253 | .iter() 254 | .filter(|&tab| tab.is_alive() || tab == found_tab) 255 | .position(|tab| tab == found_tab) 256 | }) 257 | } 258 | 259 | pub fn ref_fg_browser(&self) -> Result<&BrowserState, &'static str> { 260 | self.0 261 | .iter() 262 | .find(|tab| tab.is_fg()) 263 | .ok_or("No foreground tab") 264 | .and_then(|tab| tab.ref_browser()) 265 | } 266 | 267 | pub fn mut_fg_browser(&mut self) -> Result<&mut BrowserState, &'static str> { 268 | self.0 269 | .iter_mut() 270 | .find(|tab| tab.is_fg()) 271 | .ok_or("No foreground tab") 272 | .and_then(|tab| tab.mut_browser()) 273 | } 274 | 275 | pub fn fg_browser_index(&self) -> Result { 276 | self.0 277 | .iter() 278 | .position(|tab| tab.is_fg()) 279 | .ok_or("No foreground tab") 280 | } 281 | 282 | pub fn alive_browsers<'a>(&self) -> Vec<&BrowserState> { 283 | self.0 284 | .iter() 285 | .filter_map(|tab| tab.ref_browser().ok()) 286 | .collect() 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/state/window.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use super::tabs::TabsState; 6 | 7 | #[derive(Clone, PartialEq, Deserialize, Serialize)] 8 | pub struct WindowState { 9 | pub tabs: TabsState, 10 | pub sidebar_is_open: bool, 11 | pub logs_visible: bool, 12 | pub debug_options: DebugOptions, 13 | pub status: Option, 14 | pub options_open: bool, 15 | pub title: String, 16 | } 17 | 18 | impl WindowState { 19 | pub fn new() -> WindowState { 20 | WindowState { 21 | tabs: TabsState::new(), 22 | sidebar_is_open: false, 23 | logs_visible: false, 24 | status: None, 25 | options_open: false, 26 | title: "ServoShell".to_owned(), 27 | debug_options: DebugOptions { 28 | show_fragment_borders: false, 29 | parallel_display_list_building: false, 30 | show_parallel_layout: false, 31 | convert_mouse_to_touch: false, 32 | show_tiles_borders: false, 33 | wr_profiler: false, 34 | wr_texture_cache_debug: false, 35 | wr_render_target_debug: false, 36 | }, 37 | } 38 | } 39 | } 40 | 41 | #[derive(Clone, PartialEq, Deserialize, Serialize)] 42 | pub struct DebugOptions { 43 | pub show_fragment_borders: bool, 44 | pub parallel_display_list_building: bool, 45 | pub show_parallel_layout: bool, 46 | pub convert_mouse_to_touch: bool, 47 | pub show_tiles_borders: bool, 48 | 49 | // webrender: 50 | pub wr_profiler: bool, 51 | pub wr_texture_cache_debug: bool, 52 | pub wr_render_target_debug: bool, 53 | } 54 | -------------------------------------------------------------------------------- /src/traits/app.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![cfg_attr(any(feature = "force-glutin", not(target_os = "macos")), allow(dead_code))] 6 | 7 | use state::{AppState, ChangeType, WindowState}; 8 | use std::path::PathBuf; 9 | use traits::window::WindowMethods; 10 | 11 | #[derive(Clone, Debug)] 12 | pub enum AppEvent { 13 | DidFinishLaunching, 14 | WillTerminate, 15 | DidChangeScreenParameters, 16 | DoCommand(AppCommand), 17 | } 18 | 19 | #[allow(dead_code)] 20 | #[derive(Clone, Debug, PartialEq, Eq)] 21 | pub enum AppCommand { 22 | ClearHistory, 23 | ToggleOptionDarkTheme, 24 | } 25 | 26 | pub trait AppMethods { 27 | fn new<'a>(state: &AppState) -> Result where Self: Sized; 28 | fn new_window<'a>(&self, state: &WindowState) -> Result, &'a str>; 29 | fn get_resources_path() -> Option; 30 | fn render(&self, diff: Vec, state: &AppState); 31 | fn get_events(&self) -> Vec; 32 | fn run(&self, callback: T) where T: FnMut(); 33 | } 34 | -------------------------------------------------------------------------------- /src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | pub mod app; 6 | pub mod view; 7 | pub mod window; 8 | -------------------------------------------------------------------------------- /src/traits/view.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![cfg_attr(any(feature = "force-glutin", not(target_os = "macos")), allow(dead_code))] 6 | 7 | use std::rc::Rc; 8 | 9 | pub use servo::{Key, KeyState, KeyModifiers}; 10 | pub use servo::gl; 11 | 12 | #[derive(Debug, Copy, Clone)] 13 | pub struct DrawableGeometry { 14 | pub view_size: (u32, u32), 15 | pub margins: (u32, u32, u32, u32), 16 | pub position: (i32, i32), 17 | pub hidpi_factor: f32, 18 | } 19 | 20 | /// View events 21 | // FIXME: why not Servo events again? 22 | #[derive(Debug, Clone)] 23 | pub enum ViewEvent { 24 | GeometryDidChange, 25 | MouseWheel(MouseScrollDelta, TouchPhase), 26 | MouseInput(ElementState, MouseButton, i32, i32), 27 | MouseMoved(i32, i32), 28 | KeyEvent(Option, Key, KeyState, KeyModifiers), 29 | } 30 | 31 | #[derive(Debug, Clone)] 32 | pub enum TouchPhase { 33 | Started, 34 | Moved, 35 | Ended, 36 | } 37 | 38 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 39 | pub enum ElementState { 40 | Pressed, 41 | Released, 42 | } 43 | 44 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 45 | pub enum MouseButton { 46 | Left, 47 | Right, 48 | Middle, 49 | } 50 | 51 | #[derive(Debug, Clone)] 52 | pub enum MouseScrollDelta { 53 | LineDelta(f32, f32), 54 | PixelDelta(f32, f32), 55 | } 56 | 57 | pub trait ViewMethods { 58 | fn get_geometry(&self) -> DrawableGeometry; 59 | fn update_drawable(&self); 60 | fn enter_fullscreen(&self); 61 | fn exit_fullscreen(&self); 62 | fn set_live_resize_callback(&self, callback: &FnMut()); 63 | fn gl(&self) -> Rc; 64 | fn get_events(&self) -> Vec; 65 | fn swap_buffers(&self); 66 | } 67 | -------------------------------------------------------------------------------- /src/traits/window.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![cfg_attr(any(feature = "force-glutin", not(target_os = "macos")), allow(dead_code))] 6 | 7 | use state::{ChangeType, WindowState}; 8 | use traits::view::ViewMethods; 9 | use servo::EventLoopWaker; 10 | use std::rc::Rc; 11 | use logs::ShellLog; 12 | 13 | #[derive(Clone, Debug)] 14 | pub enum WindowEvent { 15 | EventLoopAwaken, 16 | GeometryDidChange, 17 | DidEnterFullScreen, 18 | DidExitFullScreen, 19 | WillClose, 20 | OptionsClosed, 21 | UrlbarFocusChanged(bool), 22 | DoCommand(WindowCommand), 23 | } 24 | 25 | #[derive(Clone, Debug, PartialEq, Eq)] 26 | pub enum WindowCommand { 27 | Reload, 28 | Stop, 29 | NavigateBack, 30 | NavigateForward, 31 | OpenLocation, 32 | OpenInDefaultBrowser, 33 | ZoomIn, 34 | ZoomOut, 35 | ZoomToActualSize, 36 | ToggleSidebar, 37 | NewTab, 38 | CloseTab, 39 | NextTab, 40 | PrevTab, 41 | SelectTab(usize), 42 | ShowOptions, 43 | Load(String), 44 | ToggleOptionShowLogs, 45 | ToggleOptionFragmentBorders, 46 | ToggleOptionParallelDisplayListBuidling, 47 | ToggleOptionShowParallelLayout, 48 | ToggleOptionConvertMouseToTouch, 49 | ToggleOptionTileBorders, 50 | ToggleOptionWRProfiler, 51 | ToggleOptionWRTextureCacheDebug, 52 | ToggleOptionWRTargetDebug, 53 | } 54 | 55 | pub trait WindowMethods { 56 | fn render(&self, diff: Vec, state: &WindowState); 57 | fn new_view(&self) -> Result, &'static str>; 58 | fn new_event_loop_waker(&self) -> Box; 59 | fn get_events(&self) -> Vec; 60 | fn append_logs(&self, logs: &Vec); 61 | } 62 | -------------------------------------------------------------------------------- /support/macos/Credits.rtf.mako: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf460 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \vieww12000\viewh15840\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0 6 | 7 | \f0\fs24 \cf0 ${version}} 8 | -------------------------------------------------------------------------------- /support/macos/Info.plist.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | servoshell 7 | CFBundleGetInfoString 8 | ServoShell 9 | CFBundleIconFile 10 | shell_resources/icons/ServoShell.icns 11 | CFBundleIdentifier 12 | org.servo.ServoShell 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ServoShell 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | ${version} 21 | NSHighResolutionCapable 22 | 23 | NSPrincipalClass 24 | NSApplication 25 | NSQuitAlwaysKeepsWindows 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /support/windows/ServoShell.wxs.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 30 | 35 | 42 | 43 | ${include_dependencies()} 44 | 45 | 46 | ${include_directory(resources_path, "resources")} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | % for c in components: 68 | 69 | % endfor 70 | 71 | 72 | 73 | 74 | 75 | 76 | <%! 77 | import os 78 | import os.path as path 79 | import re 80 | import uuid 81 | from servo.command_base import host_triple 82 | 83 | def make_id(s): 84 | s = s.replace("-", "_").replace("/", "_").replace("\\", "_") 85 | return "Id{}".format(s) 86 | 87 | def listfiles(directory): 88 | return [f for f in os.listdir(directory) 89 | if path.isfile(path.join(directory, f))] 90 | 91 | def listdirs(directory): 92 | return [f for f in os.listdir(directory) 93 | if path.isdir(path.join(directory, f))] 94 | 95 | def listdeps(temp_dir): 96 | return [path.join(temp_dir, f) for f in os.listdir(temp_dir) if os.path.isfile(path.join(temp_dir, f)) and f != "servoshell.exe"] 97 | 98 | def windowize(p): 99 | if not p.startswith("/"): 100 | return p 101 | return re.sub("^/([^/])+", "\\1:", p) 102 | 103 | components = [] 104 | %> 105 | 106 | <%def name="include_dependencies()"> 107 | % for f in listdeps(dir_to_temp): 108 | 112 | % endfor 113 | 114 | 115 | <%def name="include_directory(d, n)"> 116 | 117 | 120 | 121 | <% components.append(make_id(path.basename(d))) %> 122 | % for f in listfiles(d): 123 | 127 | % endfor 128 | 129 | 130 | % for f in listdirs(d): 131 | ${include_directory(path.join(d, f), f)} 132 | % endfor 133 | 134 | 135 | -------------------------------------------------------------------------------- /support/windows/servoshell.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests.md: -------------------------------------------------------------------------------- 1 | Some test to run manually until we have a testing system in place. 2 | 3 | - can control reload, back and forward from menu 4 | - can control reload, back and forward from toolbar 5 | - can control reload, back and forward from key bindings 6 | - buttons/toolbaritems/key bindings are enabled/disabled properly 7 | - go back/fwd with Cmd-Left/Right 8 | - page is properly drawn under toolbar 9 | - position:fixed top:0 is drawn below toolbar 10 | - unsupported key bindings to make the app beep 11 | - history buttons get updated 12 | - hovering a link show the url in the bottombar 13 | - hovering a link update cursor 14 | - showing the tabbar and toolbar update the dimension of the view 15 | - popover 16 | - customize toolbar 17 | - toolbar buttons get greyed out 18 | 19 | Failing: 20 | - go back/fwd with Cmd-[/] 21 | - fullscreen *from* servo exit/enter 22 | --------------------------------------------------------------------------------