├── .gitignore ├── AUTHORS.txt ├── Cargo.toml ├── LICENSE ├── README.md ├── build.sh └── src ├── build.rs ├── lib ├── ffi.rs ├── font.rs ├── fs.rs ├── gles.rs ├── http.rs ├── imagedata.rs ├── input.rs ├── lib.rs ├── media_stream_video_track.rs ├── message_handler.rs ├── pp.rs ├── ppb.rs ├── ppp.rs ├── video_decoder.rs └── video_frame.rs ├── libhelper ├── builtin_defines.hpp ├── helper.cpp └── ppapi.hpp ├── ppapi-tester ├── Cargo.toml ├── index.html ├── lib.rs └── manifest.nmf └── tests ├── Cargo.toml ├── build.rs ├── lib.rs └── tests └── hello_world.rs /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | target/ 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Rust PPApi was written by these outstanding people: 2 | 3 | Richard Diamond 4 | Manuel Adameit 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ppapi" 3 | version = "0.1.2" 4 | authors = ["Richard Diamond "] 5 | links = "helper" 6 | build = "src/build.rs" 7 | description = "Rust idiomatic bindings to parts of the Pepper API" 8 | repository = "https://github.com/DiamondLovesYou/rust-ppapi.git" 9 | documentation = "http://diamondlovesyou.github.io/rust-ppapi/docs/ppapi/index.html" 10 | license = "MPL-2.0" 11 | readme = "README.md" 12 | keywords = [ "PNaCl", "NaCl", "Pepper" ] 13 | exclude = [ "*.so", "build.sh" ] 14 | 15 | [lib] 16 | name = "ppapi" 17 | path = "src/lib/lib.rs" 18 | doc = true 19 | 20 | [dependencies] 21 | log = "*" 22 | url = "*" 23 | httparse = "*" 24 | libc = "0.1.6" 25 | 26 | [dependencies.hyper] 27 | version = "*" 28 | default-features = false 29 | 30 | [build-dependencies.pnacl-build-helper] 31 | version = "*" 32 | 33 | [features] 34 | default = ["pepper"] 35 | pepper = [] 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Rusted Pepper 2 | ========== 3 | 4 | Rust idiomatic bindings to the Pepper API. This API is experimental. Expect it 5 | to change somewhat. 6 | 7 | [Documentation](http://diamondlovesyou.github.io/rust-ppapi/doc/ppapi/index.html) 8 | 9 | ## Build 10 | 11 | You'll need to build and install [the PNaCl/NaCl Rust fork](https://github.com/DiamondLovesYou/rust) first. 12 | Then run: 13 | 14 | ```bash 15 | export NACL_SDK_ROOT=path/to/pepper_39 16 | ``` 17 | 18 | Lastly, run: 19 | 20 | ```bash 21 | cargo build --target le32-unknown-nacl 22 | ``` 23 | 24 | And profit! 25 | 26 | *Don't run ```build.sh```.* It is used to update FFI bindings. 27 | 28 | ## Getting Started 29 | 30 | Taken from [pnacl-hello-world](https://github.com/DiamondLovesYou/rust-pnacl-hello-world): 31 | 32 | ```rust 33 | #![crate_name = "pnacl-hello-world"] 34 | #![crate_type = "bin"] 35 | #![no_main] 36 | 37 | extern crate ppapi; 38 | 39 | use std::collections::HashMap; 40 | 41 | #[no_mangle] 42 | #[cfg(target_os = "nacl")] 43 | // Called when an instance is created. 44 | // This is called from a new task. It is perfectly "safe" to panic!() here, or in 45 | // any callback (though it will result in instance termination). 46 | pub extern fn ppapi_instance_created(_instance: ppapi::Instance, 47 | _args: HashMap) { 48 | println!("Hello, world!"); 49 | } 50 | 51 | #[no_mangle] 52 | pub extern fn ppapi_instance_destroyed() { 53 | } 54 | ``` 55 | 56 | ## [Pepper.js](https://github.com/google/pepper.js) 57 | 58 | Unsupported due to rust-ppapi's use of threads. 59 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BINDGEN_DIR=$1 4 | NACL_DIR=$NACL_SDK_ROOT 5 | NACL_INCLUDE_DIR=$NACL_DIR/include 6 | 7 | OUT=src/lib/ffi.rs 8 | 9 | rm -f $OUT 10 | echo "#![allow(non_camel_case_types)]" >> $OUT 11 | echo "#![allow(non_snake_case)]" >> $OUT 12 | echo "#![allow(raw_pointer_derive)]" >> $OUT 13 | echo "#![allow(missing_copy_implementations)]" >> $OUT 14 | 15 | ($NACL_DIR/toolchain/linux_pnacl/bin/pnacl-clang++ -std=c++11 -dM -E -x c++ - < /dev/null) > src/libhelper/builtin_defines.hpp 16 | 17 | export LD_LIBRARY_PATH=$BINDGEN_DIR:$LD_LIBRARY_PATH 18 | 19 | $BINDGEN_DIR/bindgen -nostdinc -I $NACL_INCLUDE_DIR -isystem $NACL_DIR/toolchain/linux_pnacl/le32-nacl/include -isystem $NACL_DIR/toolchain/linux_pnacl/le32-nacl/include/c++/v1 -isystem $NACL_DIR/include/pnacl -isystem $NACL_DIR/toolchain/linux_pnacl/lib/clang/3.7.0/include -target le32-unknown-nacl src/libhelper/helper.cpp -pthread -o temp -D__BINDGEN__ -std=c++11 20 | #perl -i -e 's/pub\\sstruct\\sStruct_PP_Dummy_Struct_For_(PP_.*_Dev)\\s\\{\\s*_COMPILE_ASSERT_FAILED_The_type_named_\\g1_is_not_[0-9]+_bytes_wide:\\s\\[c_schar,\\s\\.\\.1u\\],\\s*\\}//' $OUT 21 | 22 | # -isystem $NACL_DIR/toolchain/linux_pnacl/usr/include/c++/v1/arm-none-linux-gnueabi -isystem $NACL_DIR/toolchain/linux_pnacl/usr/include/c++/v1/backward -isystem $NACL_DIR/toolchain/linux_pnacl/include/c++/v1 23 | 24 | cat temp >> $OUT 25 | rm temp 26 | 27 | echo "pub type PP_Var = Struct_PP_Var;" >> $OUT 28 | echo "pub type PP_Rect = Struct_PP_Rect;" >> $OUT 29 | echo "pub type PP_Point = Struct_PP_Point;" >> $OUT 30 | echo "pub type PP_FloatPoint = Struct_PP_FloatPoint;" >> $OUT 31 | echo "pub type PP_TouchPoint = Struct_PP_TouchPoint;" >> $OUT 32 | echo "pub type PP_Size = Struct_PP_Size;" >> $OUT 33 | echo "pub type PPB_OpenGLES2 = Struct_PPB_OpenGLES2;" >> $OUT 34 | echo "pub type PP_CompletionCallback = Struct_PP_CompletionCallback;" >> $OUT 35 | -------------------------------------------------------------------------------- /src/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | extern crate pnacl_build_helper as helper; 10 | 11 | pub fn main() { 12 | let mut a = helper::Archive::new("helper"); 13 | a.cxx("src/libhelper/helper.cpp", &["-Os".to_string()]); 14 | a.archive(); 15 | helper::print_lib_paths(); 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/font.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use std::mem; 10 | use std::ptr; 11 | use std::collections::HashSet; 12 | 13 | use super::{ppb, ffi}; 14 | use super::{ToVar, Resource, ToFFIBool}; 15 | use super::ffi::{Struct_PP_FontMetrics_Dev, Struct_PP_TextRun_Dev, 16 | Struct_PP_FontDescription_Dev, PP_FontFamily_Dev}; 17 | use super::StringVar; 18 | 19 | use imagedata; 20 | 21 | 22 | #[derive(Eq, PartialEq, Clone, Hash, Copy)] 23 | pub enum Family { 24 | DefaultFamily, 25 | SerifFamily, 26 | SansSerifFamily, 27 | MonospaceFamily, 28 | } 29 | impl Family { 30 | fn new_from_ffi(v: ffi::PP_FontFamily_Dev) -> Family { 31 | match v { 32 | ffi::PP_FONTFAMILY_DEFAULT => Family::DefaultFamily, 33 | ffi::PP_FONTFAMILY_SERIF => Family::SerifFamily, 34 | ffi::PP_FONTFAMILY_SANSSERIF => Family::SansSerifFamily, 35 | ffi::PP_FONTFAMILY_MONOSPACE => Family::MonospaceFamily, 36 | _ => unreachable!(), 37 | } 38 | } 39 | fn to_ffi(&self) -> PP_FontFamily_Dev { 40 | match self { 41 | &Family::DefaultFamily => ffi::PP_FONTFAMILY_DEFAULT, 42 | &Family::SerifFamily => ffi::PP_FONTFAMILY_SERIF, 43 | &Family::SansSerifFamily => ffi::PP_FONTFAMILY_SANSSERIF, 44 | &Family::MonospaceFamily => ffi::PP_FONTFAMILY_MONOSPACE, 45 | } 46 | } 47 | } 48 | 49 | #[derive(Eq, PartialEq, Clone, Hash, Copy)] 50 | pub enum Weight { 51 | ValueWeight(u16), 52 | NormalWeight, 53 | BoldWeight, 54 | } 55 | 56 | impl Weight { 57 | fn new_from_ffi(v: ffi::PP_FontWeight_Dev) -> Weight { 58 | match v { 59 | ffi::PP_FONTWEIGHT_100 => Weight::ValueWeight(100), 60 | ffi::PP_FONTWEIGHT_200 => Weight::ValueWeight(200), 61 | ffi::PP_FONTWEIGHT_300 => Weight::ValueWeight(300), 62 | ffi::PP_FONTWEIGHT_400 => Weight::NormalWeight, 63 | ffi::PP_FONTWEIGHT_500 => Weight::ValueWeight(500), 64 | ffi::PP_FONTWEIGHT_600 => Weight::ValueWeight(600), 65 | ffi::PP_FONTWEIGHT_700 => Weight::BoldWeight, 66 | ffi::PP_FONTWEIGHT_800 => Weight::ValueWeight(800), 67 | ffi::PP_FONTWEIGHT_900 => Weight::ValueWeight(900), 68 | _ => unreachable!(), 69 | } 70 | } 71 | fn to_ffi(&self) -> ffi::PP_FontWeight_Dev { 72 | match self { 73 | &Weight::ValueWeight(v) if v <= 100 => ffi::PP_FONTWEIGHT_100, 74 | &Weight::ValueWeight(v) if v > 100 && v <= 200 => ffi::PP_FONTWEIGHT_200, 75 | &Weight::ValueWeight(v) if v > 200 && v <= 300 => ffi::PP_FONTWEIGHT_300, 76 | &Weight::ValueWeight(v) if v > 300 && v <= 400 => ffi::PP_FONTWEIGHT_400, 77 | &Weight::NormalWeight => ffi::PP_FONTWEIGHT_400, 78 | &Weight::ValueWeight(v) if v > 400 && v <= 500 => ffi::PP_FONTWEIGHT_500, 79 | &Weight::ValueWeight(v) if v > 500 && v <= 600 => ffi::PP_FONTWEIGHT_600, 80 | &Weight::ValueWeight(v) if v > 600 && v <= 700 => ffi::PP_FONTWEIGHT_700, 81 | &Weight::BoldWeight => ffi::PP_FONTWEIGHT_700, 82 | &Weight::ValueWeight(v) if v > 700 && v <= 800 => ffi::PP_FONTWEIGHT_800, 83 | &Weight::ValueWeight(_) => ffi::PP_FONTWEIGHT_900, 84 | } 85 | } 86 | } 87 | pub type Metrics = ffi::Struct_PP_FontMetrics_Dev; 88 | fn new_metrics_from_ffi(metrics: ffi::Struct_PP_FontMetrics_Dev) -> Metrics { 89 | metrics 90 | } 91 | 92 | 93 | #[derive(Eq, PartialEq, Clone, Hash)] 94 | pub struct Description { 95 | face: Option, 96 | family: Family, 97 | size: u32, 98 | weight: Weight, 99 | italic: bool, 100 | small_caps: bool, 101 | letter_spacing: i32, 102 | word_spacing: i32, 103 | } 104 | impl Description { 105 | pub fn new_from_family(fam: Family) -> Description { 106 | Description { 107 | face: None, 108 | family: fam, 109 | size: 12, 110 | weight: Weight::NormalWeight, 111 | italic: false, 112 | small_caps: false, 113 | letter_spacing: 0, 114 | word_spacing: 0, 115 | } 116 | } 117 | 118 | fn new_from_ffi(v: Struct_PP_FontDescription_Dev) -> Description { 119 | Description { 120 | face: Some(StringVar::new_from_var(v.face)), 121 | family: Family::new_from_ffi(v.family), 122 | size: v.size, 123 | weight: Weight::new_from_ffi(v.weight), 124 | italic: v.italic != 0, 125 | small_caps: v.small_caps != 0, 126 | letter_spacing: v.letter_spacing, 127 | word_spacing: v.word_spacing, 128 | } 129 | } 130 | pub unsafe fn to_ffi(&self) -> Struct_PP_FontDescription_Dev { 131 | let mut desc: Struct_PP_FontDescription_Dev = mem::uninitialized(); 132 | desc.face = self.face.to_var(); 133 | desc.family = self.family.to_ffi(); 134 | desc.size = self.size; 135 | desc.weight = self.weight.to_ffi(); 136 | desc.italic = self.italic.to_ffi_bool(); 137 | desc.small_caps = self.small_caps.to_ffi_bool(); 138 | desc.letter_spacing = self.letter_spacing; 139 | desc 140 | } 141 | } 142 | 143 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct Font(ffi::PP_Resource); 144 | impl_resource_for!(Font, ResourceType::Font); 145 | impl_clone_drop_for!(Font); 146 | 147 | impl Font { 148 | pub fn describe(&self) -> Option<(Description, Metrics)> { 149 | let mut desc: Struct_PP_FontDescription_Dev = Struct_PP_FontDescription_Dev { 150 | face: {super::NullVar}.to_var(), 151 | .. unsafe { mem::uninitialized() } 152 | }; 153 | let mut metr: Struct_PP_FontMetrics_Dev = unsafe { mem::uninitialized() }; 154 | 155 | match (ppb::get_font().Describe.unwrap()) 156 | (self.unwrap(), 157 | &mut desc as *mut Struct_PP_FontDescription_Dev, 158 | &mut metr as *mut Struct_PP_FontMetrics_Dev) { 159 | 0 => None, 160 | _ => Some((Description::new_from_ffi(desc), 161 | new_metrics_from_ffi(metr))), 162 | } 163 | } 164 | 165 | pub fn measure_text(&self, 167 | text: &T, 168 | rtl: bool, 169 | override_direction: bool) -> Option { 170 | let text_run = Struct_PP_TextRun_Dev { 171 | text: text.to_var(), 172 | rtl: rtl.to_ffi_bool(), 173 | override_direction: override_direction.to_ffi_bool(), 174 | }; 175 | let result = (ppb::get_font().MeasureText.unwrap()) 176 | (self.unwrap(), 177 | &text_run as *const Struct_PP_TextRun_Dev); 178 | if result == -1 { None } 179 | else { Some(result) } 180 | } 181 | 182 | /**! 183 | * Draws the text to the image buffer. 184 | * 185 | * The given point represents the baseline of the left edge of the font, 186 | * regardless of whether it is left-to-right or right-to-left (in the case of 187 | * RTL text, this will actually represent the logical end of the text). 188 | * 189 | * The clip is optional and may be NULL. In this case, the text will be 190 | * clipped to the image. 191 | * 192 | * The image_data_is_opaque flag indicates whether subpixel antialiasing can 193 | * be performed, if it is supported. When the image below the text is 194 | * opaque, subpixel antialiasing is supported and you should set this to 195 | * PP_TRUE to pick up the user's default preferences. If your plugin is 196 | * partially transparent, then subpixel antialiasing is not possible and 197 | * grayscale antialiasing will be used instead (assuming the user has 198 | * antialiasing enabled at all). 199 | */ 200 | pub fn draw_text 201 | (&self, 202 | image: &imagedata::ImageData, 203 | text: &TStr, 204 | rtl: bool, 205 | override_direction: bool, 206 | pos: super::Point, 207 | color: u32, 208 | clip: Option, 209 | image_data_is_opaque: bool) -> bool 210 | { 211 | let font_res = self.unwrap(); 212 | let image_res = image.unwrap(); 213 | let text_run = Struct_PP_TextRun_Dev { 214 | text: text.to_var(), 215 | rtl: rtl as u32, 216 | override_direction: override_direction as u32, 217 | }; 218 | let pos: ffi::PP_Point = pos.into(); 219 | let pos_ptr = &pos as *const ffi::PP_Point; 220 | let clip: Option = clip.map(|c| c.into() ); 221 | let clip_ptr = if clip.is_some() { 222 | clip.as_ref().unwrap() as *const _ 223 | } else { 224 | ptr::null() 225 | }; 226 | if (ppb::get_font().DrawTextAt.unwrap()) 227 | (font_res, 228 | image_res, 229 | &text_run as *const Struct_PP_TextRun_Dev, 230 | pos_ptr, 231 | color, 232 | clip_ptr, 233 | image_data_is_opaque as ffi::PP_Bool) != ffi::PP_FALSE 234 | { 235 | true 236 | } else { 237 | false 238 | } 239 | } 240 | 241 | pub fn char_offset_for_pixel 242 | (&self, 243 | text: &TStr, 244 | rtl: bool, 245 | override_direction: bool, 246 | position: i32) -> Option 247 | { 248 | let text_run = Struct_PP_TextRun_Dev { 249 | text: text.to_var(), 250 | rtl: rtl as u32, 251 | override_direction: override_direction as u32, 252 | }; 253 | let result = (ppb::get_font().CharacterOffsetForPixel.unwrap()) 254 | (self.unwrap(), 255 | &text_run as *const Struct_PP_TextRun_Dev, 256 | position); 257 | if result as i32 == -1 { 258 | None 259 | } else { 260 | Some(result) 261 | } 262 | } 263 | 264 | pub fn pixel_offset_for_character 265 | (&self, 266 | text: &TStr, 267 | rtl: bool, 268 | override_direction: bool, 269 | char_offset: u32) -> Option 270 | { 271 | let text_run = Struct_PP_TextRun_Dev { 272 | text: text.to_var(), 273 | rtl: rtl as u32, 274 | override_direction: override_direction as u32, 275 | }; 276 | let result = (ppb::get_font().PixelOffsetForCharacter.unwrap()) 277 | (self.unwrap(), 278 | &text_run as *const Struct_PP_TextRun_Dev, 279 | char_offset); 280 | if result as i32 == -1 { None } 281 | else { Some(result) } 282 | } 283 | } 284 | pub trait FontFamilies { 285 | fn get_font_families(&self) -> HashSet; 286 | } 287 | impl FontFamilies for super::Instance { 288 | fn get_font_families(&self) -> HashSet { 289 | use std::borrow::ToOwned; 290 | let mut dest = HashSet::new(); 291 | let fam_str = (ppb::get_font().GetFontFamilies.unwrap())(self.instance); 292 | let fam_str = StringVar::new_from_var(fam_str); 293 | for font in fam_str.split('\0') { 294 | dest.insert(font.to_owned()); 295 | } 296 | dest 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/lib/fs.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | /// A WIP async file IO implementation. This works/will work both in Pepper plugins and 10 | /// regular unsandboxed applications. For non-pepper mode, this probably isn't 11 | /// the most speedy implementation. However, the API is designed to allow 12 | /// incredibly fast implementations in the future. 13 | /// 14 | /// This interface is currently evolving and therefore fairly unstable. 15 | 16 | pub use self::common::*; 17 | pub use self::impl_::*; 18 | 19 | pub struct ParentsIter 20 | where T: Path, 21 | { 22 | p: T, 23 | } 24 | impl Iterator for ParentsIter { 25 | type Item = T; 26 | fn next(&mut self) -> Option { 27 | let parent = self.p.parent(); 28 | if parent == self.p { 29 | None 30 | } else { 31 | self.p = parent.clone(); 32 | Some(parent) 33 | } 34 | } 35 | } 36 | 37 | pub mod common { 38 | use std::borrow::Cow; 39 | use std::fmt::{Display, Debug}; 40 | 41 | use ffi; 42 | use super::super::{CallbackArgs, Code, Time, Resource, 43 | StringVar}; 44 | 45 | pub use ffi::Struct_PP_FileInfo as Info; 46 | 47 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 48 | #[repr(u32)] 49 | pub enum Type { 50 | Regular = ffi::PP_FILETYPE_REGULAR, 51 | Directory = ffi::PP_FILETYPE_DIRECTORY, 52 | Other = ffi::PP_FILETYPE_OTHER, 53 | } 54 | #[derive(Clone, Eq, PartialEq, Debug, Hash)] 55 | pub struct DirectoryEntry { 56 | pub file: super::FileRef, 57 | pub ty: Type, 58 | } 59 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 60 | pub struct OpenFlags { 61 | read: bool, 62 | write: bool, 63 | create: bool, 64 | truncate: bool, 65 | exclusive: bool, 66 | append: bool, 67 | } 68 | impl OpenFlags { 69 | pub fn new() -> OpenFlags { Default::default() } 70 | 71 | pub fn read(mut self, read: bool) -> OpenFlags { 72 | self.read = read; 73 | self 74 | } 75 | pub fn write(mut self, write: bool) -> OpenFlags { 76 | self.append = false; 77 | self.write = write; 78 | self 79 | } 80 | pub fn create(mut self, create: bool) -> OpenFlags { 81 | self.create = create; 82 | self 83 | } 84 | pub fn truncate(mut self, trunc: bool) -> OpenFlags { 85 | self.truncate = trunc; 86 | self 87 | } 88 | pub fn exclusive(mut self, exclusive: bool) -> OpenFlags { 89 | self.exclusive = exclusive; 90 | self 91 | } 92 | pub fn append(mut self, append: bool) -> OpenFlags { 93 | if append { 94 | self.write = false; 95 | } 96 | self.append = append; 97 | self 98 | } 99 | } 100 | impl Default for OpenFlags { 101 | fn default() -> OpenFlags { 102 | OpenFlags { 103 | read: true, 104 | write: false, 105 | create: false, 106 | truncate: false, 107 | exclusive: false, 108 | append: false, 109 | } 110 | } 111 | } 112 | impl Into for OpenFlags { 113 | fn into(self) -> i32 { 114 | let mut flags = 0; 115 | if self.read { flags |= ffi::PP_FILEOPENFLAG_READ; } 116 | if self.write { flags |= ffi::PP_FILEOPENFLAG_WRITE; } 117 | if self.create { flags |= ffi::PP_FILEOPENFLAG_CREATE; } 118 | if self.truncate { flags |= ffi::PP_FILEOPENFLAG_TRUNCATE; } 119 | if self.exclusive { flags |= ffi::PP_FILEOPENFLAG_EXCLUSIVE; } 120 | if self.append { flags |= ffi::PP_FILEOPENFLAG_APPEND; } 121 | flags as i32 122 | } 123 | } 124 | 125 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 126 | pub struct MkDirFlags { 127 | ancestors: bool, 128 | exclusive: bool, 129 | } 130 | impl Default for MkDirFlags { 131 | fn default() -> MkDirFlags { 132 | MkDirFlags { 133 | // I realize this isn't normally the default, but it's never made 134 | // sence to why it isn't. 135 | ancestors: true, 136 | exclusive: false, 137 | } 138 | } 139 | } 140 | impl MkDirFlags { 141 | pub fn new() -> MkDirFlags { Default::default() } 142 | 143 | pub fn ancestors(mut self, ancestors: bool) -> MkDirFlags { 144 | self.ancestors = ancestors; 145 | self 146 | } 147 | pub fn exclusive(mut self, exclusive: bool) -> MkDirFlags { 148 | self.exclusive = exclusive; 149 | self 150 | } 151 | } 152 | impl Into for MkDirFlags { 153 | fn into(self) -> i32 { 154 | let mut flags = ffi::PP_MAKEDIRECTORYFLAG_NONE; 155 | if self.ancestors { 156 | flags |= ffi::PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS; 157 | } 158 | if self.exclusive { 159 | flags |= ffi::PP_MAKEDIRECTORYFLAG_EXCLUSIVE; 160 | } 161 | flags as i32 162 | } 163 | } 164 | 165 | pub trait AsyncRead { 166 | fn async_read<'a, F>(&mut self, offset: u64, size: usize, 167 | callback: CallbackArgs>) -> 168 | Code> where F: FnOnce(Code>); 169 | } 170 | pub trait AsyncWrite { 171 | fn async_write<'a, F>(&mut self, offset: u64, 172 | buffer: Cow<'a, [u8]>, 173 | callback: CallbackArgs)>) -> 174 | Code<(usize, Cow<'a, [u8]>)> where F: FnOnce(Code<(usize, Cow<'a, [u8]>)>); 175 | fn async_flush(&mut self, callback: CallbackArgs) -> Code<()> 176 | where F: FnOnce(Code<()>); 177 | } 178 | pub trait AsyncStream: AsyncRead + AsyncWrite { } 179 | 180 | 181 | // file/dir releated stuffs 182 | pub trait AsyncCommon { 183 | fn async_touch(&self, atime: Time, mtime: Time, 184 | callback: CallbackArgs) -> 185 | Code<()> where F: FnOnce(Code<()>); 186 | 187 | fn async_query(&self, callback: CallbackArgs) -> Code 188 | where F: FnOnce(Code); 189 | } 190 | pub trait AsyncFile: AsyncCommon { 191 | fn async_set_len(&mut self, len: u64, 192 | callback: CallbackArgs) -> 193 | Code<()> where F: FnOnce(Code<()>); 194 | } 195 | pub trait AsyncPath: AsyncCommon { 196 | fn async_mkdir(&self, flags: MkDirFlags, callback: CallbackArgs) -> Code<()> 197 | where F: FnOnce(Code<()>); 198 | fn async_delete(&self, callback: CallbackArgs) -> Code<()> 199 | where F: FnOnce(Code<()>); 200 | fn async_rename(&self, to: Self, callback: CallbackArgs) -> Code<()> 201 | where F: FnOnce(Code<()>); 202 | fn async_read_directory_entries(&self, callback: CallbackArgs>) -> 203 | Code> where F: FnOnce(Code>); 204 | 205 | fn async_open_io(&self, instance: super::super::Instance, 206 | flags: OpenFlags, 207 | callback: CallbackArgs) -> Code 208 | where F: FnOnce(Code); 209 | } 210 | 211 | pub trait SyncCommon { 212 | fn sync_touch(&self, atime: Time, mtime: Time) -> Code; 213 | fn sync_query(&self) -> Code; 214 | } 215 | pub trait SyncFile: SyncCommon { 216 | fn sync_set_len(&mut self, len: u64) -> Code; 217 | } 218 | pub trait SyncPath: SyncCommon { 219 | fn sync_mkdir(&self, flags: MkDirFlags) -> Code; 220 | fn sync_delete(&self) -> Code; 221 | fn sync_rename(&self, to: Self) -> Code; 222 | fn sync_read_directory_entires(&self) -> Code>; 223 | 224 | fn sync_open_io(&self, instance: super::super::Instance, 225 | flags: OpenFlags) -> Code; 226 | } 227 | 228 | pub trait Path: AsyncPath + SyncPath + Display + Debug + Eq + Sized + Clone { 229 | fn name(&self) -> StringVar; 230 | fn path(&self) -> StringVar; 231 | fn parent(&self) -> Self; 232 | 233 | /// The first element will be Self's parent. 234 | fn parents_iter(self) -> super::ParentsIter { 235 | super::ParentsIter { 236 | p: self, 237 | } 238 | } 239 | } 240 | 241 | pub trait FileView: AsyncStream + AsyncCommon + Resource { 242 | type View; 243 | type Io; 244 | 245 | fn io(&self) -> &Self::Io; 246 | 247 | fn view(&self, from: u64, to: Option) -> Self::View; 248 | fn view_full(&self) -> Self::View { self.view(0, None) } 249 | 250 | fn view_start(&self) -> u64; 251 | fn view_stop (&self) -> Option; 252 | fn view_len (&self) -> Option { 253 | self.view_stop() 254 | .map(|stop| { 255 | let start = self.view_start(); 256 | if stop < start { 257 | 0 258 | } else { 259 | stop - start 260 | } 261 | }) 262 | } 263 | 264 | fn view_absolute_start(&self) -> u64; 265 | } 266 | } 267 | 268 | 269 | #[cfg(feature = "pepper")] 270 | mod impl_ { 271 | use std::borrow::Cow; 272 | use std::path; 273 | 274 | use ffi; 275 | use ppb::{FileSystemIf, FileRefIf, FileIoIf}; 276 | use ppb::{get_file_system, get_file_ref, get_file_io}; 277 | use super::common::{AsyncRead, AsyncWrite, AsyncFile, AsyncPath, 278 | AsyncCommon, AsyncStream, Info, OpenFlags, MkDirFlags, 279 | DirectoryEntry, FileView, SyncCommon, SyncFile, 280 | SyncPath}; 281 | use super::super::{Result, Callback, CallbackArgs, Code, 282 | Resource, StorageToArgsMapper, 283 | InPlaceArrayOutputStorage, Time, 284 | BlockUntilComplete, ResourceType}; 285 | 286 | use std::io::{self, Seek, Read, Write}; 287 | 288 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct FileSystem(ffi::PP_Resource); 289 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct FileRef(ffi::PP_Resource); 290 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct FileIo(ffi::PP_Resource); 291 | 292 | impl_resource_for!(FileSystem, ResourceType::FileSystem); 293 | impl_clone_drop_for!(FileSystem); 294 | impl_resource_for!(FileRef, ResourceType::FileRef); 295 | impl_clone_drop_for!(FileRef); 296 | impl_resource_for!(FileIo, ResourceType::FileIo); 297 | impl_clone_drop_for!(FileIo); 298 | 299 | #[derive(Hash, Eq, PartialEq, Debug, Clone)] 300 | /// Was `SliceIo`, but rustc has a recursion bug :( 301 | pub struct SliceIo(FileIo, u64, Option); 302 | impl Resource for SliceIo { 303 | fn unwrap(&self) -> ffi::PP_Resource { self.io().unwrap() } 304 | fn type_of(&self) -> Option { self.io().type_of() } 305 | } 306 | 307 | #[repr(u32)] 308 | #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] 309 | pub enum Kind { 310 | External = ffi::PP_FILESYSTEMTYPE_EXTERNAL, 311 | LocalPersistent = ffi::PP_FILESYSTEMTYPE_LOCALPERSISTENT, 312 | LocalTemp = ffi::PP_FILESYSTEMTYPE_LOCALTEMPORARY, 313 | Isolated = ffi::PP_FILESYSTEMTYPE_ISOLATED, 314 | } 315 | 316 | impl FileSystem { 317 | pub fn kind(&self) -> Kind { 318 | use std::mem::transmute; 319 | unsafe { transmute(get_file_system().get_type(self.unwrap())) } 320 | } 321 | 322 | /// This must be called before doing any operation on the FS. 323 | pub fn open(&self, expected_size: usize, callback: F) -> Code 324 | where F: Callback 325 | { 326 | let cc = callback.to_ffi_callback(); 327 | let code = get_file_system().open(self.unwrap(), expected_size as i64, 328 | cc.cc); 329 | cc.drop_with_code(code) 330 | } 331 | 332 | pub fn create>(&self, path: T) -> Option { 333 | let cstr = format!("{}\0", path.as_ref().display()); 334 | get_file_ref().create(self.unwrap(), cstr.as_ptr() as *const _) 335 | .map(|r| FileRef(r) ) 336 | } 337 | } 338 | 339 | impl FileView for FileIo { 340 | type View = SliceIo; 341 | type Io = FileIo; 342 | fn io(&self) -> &FileIo { self } 343 | 344 | fn view(&self, from: u64, to: Option) -> SliceIo { 345 | match (from, to) { 346 | (from, Some(to)) => assert!(from <= to), 347 | _ => (), 348 | } 349 | SliceIo(self.io().clone(), from, to) 350 | } 351 | 352 | fn view_start(&self) -> u64 { 0 } 353 | fn view_stop (&self) -> Option { None } 354 | 355 | fn view_absolute_start(&self) -> u64 { 0 } 356 | } 357 | impl FileView for SliceIo { 358 | type View = SliceIo; 359 | type Io = FileIo; 360 | 361 | fn io(&self) -> &FileIo { &self.0 } 362 | 363 | fn view(&self, from: u64, to: Option) -> SliceIo { 364 | match (from, to) { 365 | (from, Some(to)) => assert!(from <= to), 366 | _ => (), 367 | } 368 | let to = to.map(|to| self.view_start() + to ); 369 | SliceIo(self.io().clone(), self.view_start() + from, to) 370 | } 371 | 372 | fn view_start(&self) -> u64 { self.1 } 373 | fn view_stop (&self) -> Option { self.2 } 374 | 375 | fn view_absolute_start(&self) -> u64 { 376 | self.0.view_absolute_start() + self.view_start() 377 | } 378 | } 379 | 380 | impl AsyncRead for FileIo { 381 | fn async_read<'a, F>(&mut self, offset: u64, size: usize, 382 | callback: CallbackArgs>) -> 383 | Code> where F: FnOnce(Code>) 384 | { 385 | fn map_arg<'a>(raw: InPlaceArrayOutputStorage, _status: Code) -> Cow<'a, [u8]> { 386 | let v: Vec<_> = raw.into(); 387 | Cow::Owned(v) 388 | } 389 | 390 | let raw_args: InPlaceArrayOutputStorage = Default::default(); 391 | let mapper = StorageToArgsMapper(map_arg); 392 | let mut cc = callback.to_ffi_callback(raw_args, mapper); 393 | let fficc = cc.cc; 394 | let code = get_file_io() 395 | .read_to_array(self.unwrap(), offset, size as u32, 396 | cc.as_mut(), fficc); 397 | cc.drop_with_code(code) 398 | } 399 | } 400 | 401 | impl AsyncWrite for FileIo { 402 | fn async_write<'a, F>(&mut self, offset: u64, 403 | buffer: Cow<'a, [u8]>, 404 | callback: CallbackArgs)>) -> 405 | Code<(usize, Cow<'a, [u8]>)> where F: FnOnce(Code<(usize, Cow<'a, [u8]>)>) 406 | { 407 | impl<'a> super::super::InPlaceInit for (bool, usize, Cow<'a, [u8]>) { } 408 | 409 | fn map_arg<'a>((sync, written, buf): (bool, usize, Cow<'a, [u8]>), 410 | status: Code) -> (usize, Cow<'a, [u8]>) { 411 | if sync { 412 | (written, buf) 413 | } else { 414 | let written = match status { 415 | Code::Ok(written) => written, 416 | _ => unreachable!(), 417 | }; 418 | (written, buf) 419 | } 420 | } 421 | let mapper = StorageToArgsMapper(map_arg); 422 | let mut cc = callback.to_ffi_callback((false, 0, buffer), mapper); 423 | let written = get_file_io() 424 | .write(self.unwrap(), offset, 425 | cc.2.as_ptr() as *const _, 426 | cc.2.len() as usize, 427 | cc.cc); 428 | match written { 429 | Code::Ok(written) => { 430 | cc.0 = true; 431 | cc.1 = written as usize; 432 | cc.drop_with_code(Code::Ok(written)) 433 | }, 434 | code => cc.drop_with_code(code), 435 | } 436 | } 437 | fn async_flush(&mut self, callback: CallbackArgs) -> Code<()> 438 | where F: FnOnce(Code<()>) 439 | { 440 | let cc = callback.to_ffi_callback((), Default::default()); 441 | let code = get_file_io() 442 | .flush(self.unwrap(), cc.cc); 443 | cc.drop_with_code(code) 444 | } 445 | } 446 | impl AsyncStream for FileIo { } 447 | impl AsyncCommon for FileIo { 448 | fn async_touch(&self, atime: Time, mtime: Time, 449 | callback: CallbackArgs) -> 450 | Code<()> where F: FnOnce(Code<()>) 451 | { 452 | let cc = callback.to_ffi_callback((), Default::default()); 453 | let code = get_file_io() 454 | .touch(self.unwrap(), atime, mtime, cc.cc); 455 | cc.drop_with_code(code) 456 | } 457 | fn async_query(&self, callback: CallbackArgs) -> Code 458 | where F: FnOnce(Code) 459 | { 460 | impl super::super::InPlaceInit for ffi::Struct_PP_FileInfo { } 461 | fn map_arg(arg: Info, _status: Code) -> Info { arg } 462 | let mapper = StorageToArgsMapper(map_arg); 463 | let mut cc = callback.to_ffi_callback(Default::default(), 464 | mapper); 465 | let fficc = cc.cc; 466 | let code = get_file_io() 467 | .query(self.unwrap(), &mut *cc, fficc); 468 | cc.drop_with_code(code) 469 | } 470 | } 471 | impl AsyncFile for FileIo { 472 | fn async_set_len(&mut self, len: u64, 473 | callback: CallbackArgs) -> 474 | Code<()> where F: FnOnce(Code<()>) 475 | { 476 | let cc = callback.to_ffi_callback((), Default::default()); 477 | let code = get_file_io() 478 | .set_length(self.unwrap(), len, cc.cc); 479 | cc.drop_with_code(code) 480 | } 481 | } 482 | 483 | impl SyncCommon for FileIo { 484 | fn sync_touch(&self, atime: Time, mtime: Time) -> Code { 485 | get_file_io() 486 | .touch(self.unwrap(), atime, mtime, 487 | BlockUntilComplete::new()) 488 | } 489 | fn sync_query(&self) -> Code { 490 | let mut dest: Info = Default::default(); 491 | get_file_io() 492 | .query(self.unwrap(), &mut dest, 493 | BlockUntilComplete::new()) 494 | .map_ok(move |_| dest ) 495 | } 496 | } 497 | impl SyncFile for FileIo { 498 | fn sync_set_len(&mut self, len: u64) -> Code { 499 | get_file_io() 500 | .set_length(self.unwrap(), len, 501 | BlockUntilComplete::new()) 502 | } 503 | } 504 | 505 | impl AsyncRead for SliceIo { 506 | fn async_read<'a, F>(&mut self, offset: u64, size: usize, 507 | callback: CallbackArgs>) -> 508 | Code> where F: FnOnce(Code>) 509 | { 510 | let slice_start = self.view_start(); 511 | let slice_stop = self.view_stop().unwrap_or(u64::max_value()); 512 | 513 | let offset = slice_start + offset; 514 | let size = ::std::cmp::min((slice_stop - slice_start) as usize, 515 | size); 516 | 517 | self.0.async_read(offset, size, callback) 518 | } 519 | } 520 | impl AsyncWrite for SliceIo { 521 | fn async_write<'a, F>(&mut self, offset: u64, 522 | buffer: Cow<'a, [u8]>, 523 | callback: CallbackArgs)>) -> 524 | Code<(usize, Cow<'a, [u8]>)> where F: FnOnce(Code<(usize, Cow<'a, [u8]>)>) 525 | { 526 | let offset = self.view_start() + offset; 527 | self.0.async_write(offset, buffer, callback) 528 | } 529 | fn async_flush(&mut self, callback: CallbackArgs) -> Code<()> 530 | where F: FnOnce(Code<()>) 531 | { 532 | self.0.async_flush(callback) 533 | } 534 | } 535 | impl AsyncStream for SliceIo { } 536 | impl AsyncCommon for SliceIo { 537 | fn async_touch(&self, atime: Time, mtime: Time, 538 | callback: CallbackArgs) -> 539 | Code<()> where F: FnOnce(Code<()>) 540 | { 541 | self.0.async_touch(atime, mtime, callback) 542 | } 543 | fn async_query(&self, callback: CallbackArgs) -> Code 544 | where F: FnOnce(Code) 545 | { 546 | let slice_start = self.view_start(); 547 | let slice_stop = self.view_stop().unwrap_or(u64::max_value()); 548 | 549 | fn map(info: Info, slice_start: u64, slice_stop: u64) -> Info { 550 | // Alter the file size to the slice's actual size. 551 | ffi::Struct_PP_FileInfo { 552 | size: (::std::cmp::min(info.size as u64, slice_stop) - slice_start) as i64, 553 | .. info 554 | } 555 | } 556 | let optional = callback.optional; 557 | let mut local = CallbackArgs::new(move |info: Code| { 558 | let info = info.map_ok(|info| map(info, slice_start, slice_stop) ); 559 | callback.call_directly(info) 560 | }); 561 | local.set_optional(optional); 562 | 563 | let code = self.0.async_query(local); 564 | if let Code::Ok(info) = code { 565 | Code::Ok(map(info, slice_start, slice_stop)) 566 | } else { 567 | code 568 | } 569 | } 570 | } 571 | impl SyncCommon for SliceIo { 572 | fn sync_touch(&self, atime: Time, mtime: Time) -> Code { 573 | self.io().sync_touch(atime, mtime) 574 | } 575 | fn sync_query(&self) -> Code { 576 | self.io() 577 | .sync_query() 578 | .map_ok(|info| { 579 | let slice_start = self.view_start(); 580 | let slice_stop = self.view_stop().unwrap_or(u64::max_value()); 581 | // Alter the file size to the slice's actual size. 582 | ffi::Struct_PP_FileInfo { 583 | size: (::std::cmp::min(info.size as u64, slice_stop) - slice_start) as i64, 584 | .. info 585 | } 586 | }) 587 | } 588 | } 589 | 590 | 591 | // FileRef 592 | impl AsyncCommon for FileRef { 593 | fn async_touch(&self, atime: Time, mtime: Time, 594 | callback: CallbackArgs) -> 595 | Code<()> where F: FnOnce(Code<()>) 596 | { 597 | let cc = callback.to_ffi_callback((), Default::default()); 598 | let code = get_file_ref() 599 | .touch(self.unwrap(), atime, mtime, cc.cc); 600 | cc.drop_with_code(code) 601 | } 602 | fn async_query(&self, callback: CallbackArgs) -> Code 603 | where F: FnOnce(Code) 604 | { 605 | fn map_arg(arg: Info, _status: Code) -> Info { arg } 606 | let mapper = StorageToArgsMapper(map_arg); 607 | let mut cc = callback.to_ffi_callback(Default::default(), 608 | mapper); 609 | let fficc = cc.cc; 610 | let code = get_file_ref() 611 | .query(self.unwrap(), &mut *cc, fficc); 612 | cc.drop_with_code(code) 613 | } 614 | } 615 | impl AsyncPath for FileRef { 616 | fn async_mkdir(&self, flags: MkDirFlags, callback: CallbackArgs) -> Code<()> 617 | where F: FnOnce(Code<()>) 618 | { 619 | let cc = callback.to_ffi_callback((), Default::default()); 620 | let code = get_file_ref() 621 | .mkdir(self.unwrap(), flags.into(), cc.cc); 622 | cc.drop_with_code(code) 623 | } 624 | fn async_delete(&self, callback: CallbackArgs) -> Code<()> 625 | where F: FnOnce(Code<()>) 626 | { 627 | let cc = callback.to_ffi_callback((), Default::default()); 628 | let code = get_file_ref() 629 | .delete(self.unwrap(), cc.cc); 630 | cc.drop_with_code(code) 631 | } 632 | fn async_rename(&self, to: Self, callback: CallbackArgs) -> Code<()> 633 | where F: FnOnce(Code<()>) 634 | { 635 | let cc = callback.to_ffi_callback((), Default::default()); 636 | let code = get_file_ref() 637 | .rename(self.unwrap(), to.unwrap(), cc.cc); 638 | cc.drop_with_code(code) 639 | } 640 | fn async_read_directory_entries(&self, callback: CallbackArgs>) -> 641 | Code> where F: FnOnce(Code>) 642 | { 643 | type StorageTy = StorageToArgsMapper, 644 | Vec>; 645 | let raw_args: InPlaceArrayOutputStorage = Default::default(); 646 | let mapper: StorageTy = Default::default(); 647 | let cc = callback.to_ffi_callback(raw_args, mapper); 648 | let fficc = cc.cc; 649 | let code = get_file_ref() 650 | .read_directory_entries(self.unwrap(), *cc.as_ref(), fficc); 651 | cc.drop_with_code(code) 652 | } 653 | 654 | fn async_open_io(&self, instance: super::super::Instance, 655 | flags: OpenFlags, 656 | callback: CallbackArgs) -> Code 657 | where F: FnOnce(Code) 658 | { 659 | impl super::super::InPlaceInit for FileIo { } 660 | 661 | let mut cc = callback.to_ffi_callback(FileIo(0), Default::default()); 662 | 663 | let file_io = get_file_io().create(instance.unwrap()); 664 | if file_io.is_none() { return cc.drop_with_code(Code::BadArgument); } 665 | let file_io = file_io.unwrap(); 666 | cc.0 = file_io; 667 | 668 | let code = get_file_io() 669 | .open(self.unwrap(), file_io, flags.into(), cc.cc); 670 | cc.drop_with_code(code) 671 | } 672 | } 673 | impl SyncCommon for FileRef { 674 | fn sync_touch(&self, atime: Time, mtime: Time) -> Code { 675 | get_file_ref() 676 | .touch(self.unwrap(), atime, mtime, 677 | BlockUntilComplete::new()) 678 | } 679 | fn sync_query(&self) -> Code { 680 | let mut dest: Info = Default::default(); 681 | get_file_ref() 682 | .query(self.unwrap(), &mut dest, 683 | BlockUntilComplete::new()) 684 | .map_ok(move |_| dest ) 685 | } 686 | } 687 | impl SyncPath for FileRef { 688 | fn sync_mkdir(&self, flags: MkDirFlags) -> Code { 689 | get_file_ref() 690 | .mkdir(self.unwrap(), flags.into(), 691 | BlockUntilComplete::new()) 692 | } 693 | fn sync_delete(&self) -> Code { 694 | get_file_ref() 695 | .delete(self.unwrap(), 696 | BlockUntilComplete::new()) 697 | } 698 | fn sync_rename(&self, to: FileRef) -> Code { 699 | get_file_ref() 700 | .rename(self.unwrap(), to.unwrap(), 701 | BlockUntilComplete::new()) 702 | } 703 | fn sync_read_directory_entires(&self) -> Code> { 704 | use super::super::InPlaceInit; 705 | let mut dest: InPlaceArrayOutputStorage = 706 | Default::default(); 707 | dest.inplace_init(); 708 | 709 | get_file_ref() 710 | .read_directory_entries(self.unwrap(), *dest.as_ref(), 711 | BlockUntilComplete::new()) 712 | .map_ok(move |_| dest.into() ) 713 | } 714 | 715 | fn sync_open_io(&self, instance: super::super::Instance, 716 | flags: OpenFlags) -> Code { 717 | let file_io = get_file_io().create(instance.unwrap()); 718 | if file_io.is_none() { return Code::BadArgument; } 719 | let file_io = file_io.unwrap(); 720 | 721 | get_file_io() 722 | .open(self.unwrap(), file_io, flags.into(), 723 | BlockUntilComplete::new()) 724 | .map_ok(move |_| FileIo(file_io) ) 725 | } 726 | } 727 | 728 | impl Read for SliceIo { 729 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 730 | let cc = BlockUntilComplete; 731 | let cc = cc.to_ffi_callback(); 732 | 733 | let to_read = ::std::cmp::min(buf.len() as u64, 734 | self.view_len().unwrap_or(u64::max_value())); 735 | let to_read = to_read as usize; 736 | 737 | let offset = self.view_absolute_start(); 738 | let read = get_file_io() 739 | .read(self.unwrap(), offset, buf.as_mut_ptr() as *mut _, 740 | to_read, cc.cc()); 741 | 742 | let read = match read { 743 | Code::CompletionPending => unreachable!(), 744 | Code::Ok(read) => read, 745 | read => { return Err(read.into()); }, 746 | }; 747 | self.1 += read as u64; 748 | Ok(read as usize) 749 | } 750 | } 751 | impl Seek for SliceIo { 752 | fn seek(&mut self, from: io::SeekFrom) -> io::Result { 753 | match from { 754 | io::SeekFrom::Start(v) => { 755 | self.1 = v; 756 | }, 757 | io::SeekFrom::End(_) => { 758 | // TODO 759 | return Err({Code::NotSupported}.into()); 760 | }, 761 | io::SeekFrom::Current(v) => { 762 | if v < 0 && -v as u64 > self.1 { 763 | return Err(io::Error::new(io::ErrorKind::InvalidInput, 764 | "can't seek before 0")); 765 | } 766 | if v < 0 { 767 | self.1 -= (-v) as u64; 768 | } else { 769 | self.1 += v as u64; 770 | } 771 | }, 772 | } 773 | 774 | Ok(self.1) 775 | } 776 | } 777 | impl Write for SliceIo { 778 | fn write(&mut self, buf: &[u8]) -> io::Result { 779 | let cc = BlockUntilComplete; 780 | let cc = cc.to_ffi_callback(); 781 | 782 | let to_write = ::std::cmp::min(buf.len() as u64, 783 | self.view_len().unwrap_or(u64::max_value())); 784 | let to_write = to_write as usize; 785 | 786 | let offset = self.view_absolute_start(); 787 | let write = get_file_io() 788 | .write(self.unwrap(), offset, buf.as_ptr() as *const _, 789 | to_write, cc.cc()); 790 | 791 | let write = match write { 792 | Code::CompletionPending => unreachable!(), 793 | Code::Ok(write) => write, 794 | write => { return Err(write.into()); }, 795 | }; 796 | self.1 += write as u64; 797 | Ok(write as usize) 798 | } 799 | fn flush(&mut self) -> io::Result<()> { 800 | let cc = BlockUntilComplete::new(); 801 | get_file_io() 802 | .flush(self.unwrap(), cc) 803 | .to_valued_result(()) 804 | .map_err(|code| code.into() ) 805 | } 806 | } 807 | 808 | } 809 | 810 | #[cfg(not(feature = "pepper"))] 811 | mod impl_ { 812 | //! This is implementation based on std's synchronous IO facilities. 813 | //! Every FileSystem has its own IO thread. 814 | use std::io; 815 | use std::fs::File; 816 | use std::sync::mpsc; 817 | 818 | fn to_code_result(res: io::Result) -> super::super::Result { 819 | res.map_err(|err| { 820 | match err.kind() { 821 | ErrorKind::FileNotFound => Code::FileNotFound, 822 | ErrorKind::PermissionDenied => Code::NoAccess, 823 | ErrorKind::ConnectionRefused => Code::ConnectionRefused, 824 | ErrorKind::ConnectionReset => Code::ConnectionReset, 825 | ErrorKind::ConnectionAborted => Code::ConnectionAborted, 826 | ErrorKind::NotConnected => Code::ConnectionClosed, 827 | ErrorKind::BrokenPipe => Code::Failed, 828 | ErrorKind::PathAlreadyExists => Code::FileNotFound, 829 | ErrorKind::PathDoesntExist => Code::FileExists, 830 | ErrorKind::MismatchedFileTypeForOperation => Code::FileNotFound, 831 | ErrorKind::ResourceUnavailable => Code::BadResource, 832 | ErrorKind::InvalidInput => Code::BadArgument, 833 | ErrorKind::TimedOut => Code::TimedOut, 834 | ErrorKind::WriteZero => Code::BadArgument, 835 | ErrorKind::Interrupted => Code::FileNotFound, 836 | ErrorKind::Other => Code::Failed, 837 | } 838 | }) 839 | } 840 | 841 | #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] 842 | pub enum Kind { 843 | External, 844 | LocalPersistent, 845 | LocalTemp, 846 | Isolated, 847 | } 848 | 849 | type FId = u64; 850 | 851 | enum Message { 852 | OpenFileRef(Sender>), 853 | 854 | RefFS, 855 | RefFileRef(FId), 856 | RefFileIo(FId), 857 | DerefFS, 858 | } 859 | 860 | fn fs_thread(recv: mpsc::Receiver) { 861 | 862 | } 863 | 864 | struct FSThreadFileRef { 865 | /// Despite the use of Path, this must be in valid utf8. 866 | path: Path, 867 | refs: usize, 868 | } 869 | impl FSThreadFileRef { 870 | fn add_ref(&mut self) { 871 | self.refs += 1; 872 | } 873 | /// Returns true if this instance should be dropped. Doesn't modify the 874 | /// ref count when it returns true. 875 | fn sub_ref(&mut self) -> bool { 876 | if self.refs == 1 { 877 | true 878 | } else { 879 | self.refs -= 1; 880 | false 881 | } 882 | } 883 | } 884 | 885 | struct FSThreadFileIo { 886 | f: File, 887 | refs: usize, 888 | } 889 | impl FSThreadFileIo { 890 | fn add_ref(&mut self) { 891 | self.refs += 1; 892 | } 893 | /// Returns true if this instance should be dropped. Doesn't modify the 894 | /// ref count when it returns true. 895 | fn sub_ref(&mut self) -> bool { 896 | if self.refs == 1 { 897 | true 898 | } else { 899 | self.refs -= 1; 900 | false 901 | } 902 | } 903 | 904 | } 905 | 906 | struct FSThread { 907 | refs: usize, 908 | root: Path, 909 | recv: mpsc::Receiver, 910 | 911 | /// These paths must be valid utf8: 912 | file_refs: HashMap, 913 | 914 | file_ios: HashMap, 915 | } 916 | 917 | impl FSThread { 918 | fn spawn(recv: mpsc::Receiver, root: Path) { 919 | use std::thread; 920 | 921 | let mut t = FSThread { 922 | refs: 1, 923 | root: Path, 924 | recv: recv, 925 | 926 | file_refs: HashMap::new(), 927 | file_ios: HashMap::new(), 928 | }; 929 | thread::spawn(move || { 930 | let mut t = t; 931 | t.run(); 932 | }) 933 | } 934 | 935 | fn run(&mut self) { 936 | 937 | } 938 | } 939 | 940 | pub struct FileSystem { 941 | kind: Kind, 942 | chan: mpsc::Sender, 943 | } 944 | 945 | impl FileSystem { 946 | pub fn new(instance: &super::super::Instance, kind: Kind) -> 947 | Result 948 | { 949 | 950 | } 951 | pub fn create_file_ref(&self, path: &Path) -> Result { 952 | 953 | } 954 | pub fn filesystem_kind(&self) -> Kind { 955 | self.kind 956 | } 957 | } 958 | 959 | pub struct FileRef { 960 | fs: FileSystem, 961 | id: FId, 962 | } 963 | 964 | pub struct FileRef; 965 | } 966 | -------------------------------------------------------------------------------- /src/lib/http.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use super::{Callback, Resource, Instance, ToStringVar, ToVar, Code, 10 | StringVar, GenericResource, ResourceType, BlockUntilComplete, 11 | Var, CallbackArgs}; 12 | use super::ppb::{get_url_loader, get_url_loader_opt, 13 | get_url_request_opt, 14 | get_url_response}; 15 | use ppb::{self, URLRequestInfoIf, URLResponseInfoIf, URLLoaderIf}; 16 | 17 | use std::borrow::Cow; 18 | use std::io; 19 | use std::str::FromStr; 20 | use std::ops::Deref; 21 | 22 | use collections::enum_set::{CLike, EnumSet}; 23 | 24 | use hyper; 25 | use hyper::header::Headers; 26 | use httparse; 27 | 28 | use super::ffi; 29 | use super::ffi::bool_to_var; 30 | use iurl::Url; 31 | 32 | use fs::{self, SliceIo, FileView}; 33 | 34 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct UrlRequestInfo(ffi::PP_Resource); 35 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct ResponseInfo(ffi::PP_Resource); 36 | 37 | impl_resource_for!(UrlRequestInfo, ResourceType::UrlRequestInfo); 38 | impl_resource_for!(ResponseInfo, ResourceType::UrlResponseInfo); 39 | impl_clone_drop_for!(UrlRequestInfo); 40 | impl_clone_drop_for!(ResponseInfo); 41 | 42 | pub type RequestProperties = EnumSet; 43 | #[derive(Eq, PartialEq, Clone, Hash, Copy, Debug)] 44 | pub enum RequestProperties_ { 45 | AllowCrossOriginRequests, 46 | AllowCredentials, 47 | RecordUploadProgress, 48 | RecordDownloadProgress, 49 | FollowRedirects, 50 | StreamToFile, 51 | } 52 | impl CLike for RequestProperties_ { 53 | fn to_usize(&self) -> usize { 54 | match self { 55 | &RequestProperties_::AllowCrossOriginRequests => 0, 56 | &RequestProperties_::AllowCredentials => 1, 57 | &RequestProperties_::RecordUploadProgress => 2, 58 | &RequestProperties_::RecordDownloadProgress => 3, 59 | &RequestProperties_::FollowRedirects => 4, 60 | &RequestProperties_::StreamToFile => 5, 61 | } 62 | } 63 | fn from_usize(v: usize) -> RequestProperties_ { 64 | match v { 65 | 0 => RequestProperties_::AllowCrossOriginRequests, 66 | 1 => RequestProperties_::AllowCredentials, 67 | 2 => RequestProperties_::RecordUploadProgress, 68 | 3 => RequestProperties_::RecordDownloadProgress, 69 | 4 => RequestProperties_::FollowRedirects, 70 | 5 => RequestProperties_::StreamToFile, 71 | _ => unreachable!(), 72 | } 73 | } 74 | } 75 | impl Into for RequestProperties_ { 76 | fn into(self) -> ffi::PP_URLRequestProperty { 77 | match self { 78 | RequestProperties_::AllowCrossOriginRequests => 79 | ffi::PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, 80 | RequestProperties_::AllowCredentials => 81 | ffi::PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, 82 | RequestProperties_::RecordUploadProgress => 83 | ffi::PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS, 84 | RequestProperties_::RecordDownloadProgress => 85 | ffi::PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS, 86 | RequestProperties_::FollowRedirects => 87 | ffi::PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS, 88 | RequestProperties_::StreamToFile => 89 | ffi::PP_URLREQUESTPROPERTY_STREAMTOFILE, 90 | } 91 | } 92 | } 93 | 94 | #[derive(Clone, Debug)] 95 | pub enum Body { 96 | File(SliceIo, Option), 97 | Blob(Vec), 98 | } 99 | 100 | pub type Method = hyper::method::Method; 101 | 102 | trait CreateUrl { 103 | fn create_url_loader(&self) -> Code; 104 | fn create_url_request_info(&self) -> Code; 105 | } 106 | impl CreateUrl for Instance { 107 | fn create_url_loader(&self) -> Code { 108 | get_url_loader_opt() 109 | .map(|i| { 110 | i.create(self.unwrap()) 111 | .map(|info| Code::Ok(info) ) 112 | .unwrap_or(Code::BadInstance) 113 | }) 114 | .unwrap_or(Code::NoInterface) 115 | } 116 | fn create_url_request_info(&self) -> Code { 117 | get_url_request_opt() 118 | .map(|i| { 119 | i.create(self.unwrap()) 120 | .map(|info| Code::Ok(UrlRequestInfo::new(info)) ) 121 | .unwrap_or(Code::BadInstance) 122 | }) 123 | .unwrap_or(Code::NoInterface) 124 | } 125 | } 126 | 127 | #[derive(Clone, Debug)] 128 | pub struct RequestInfo { 129 | pub url: Url, 130 | 131 | pub method: Method, 132 | 133 | pub prefetch_buffer: Option<(i32, i32)>, 134 | properties: RequestProperties, 135 | set_props: RequestProperties, 136 | 137 | pub bodies: Vec, 138 | 139 | pub headers: Headers, 140 | } 141 | impl RequestInfo { 142 | pub fn new(url: Url, method: Method, 143 | body: Option, headers: Option) -> RequestInfo { 144 | RequestInfo { 145 | url: url, 146 | method: method, 147 | 148 | prefetch_buffer: None, 149 | properties: EnumSet::new(), 150 | set_props: EnumSet::new(), 151 | 152 | bodies: body 153 | .map(|b| vec!(b) ) 154 | .unwrap_or_default(), 155 | 156 | headers: headers.unwrap_or_else(|| Headers::new() ), 157 | } 158 | } 159 | fn clear_bit(bitfield: RequestProperties, prop: RequestProperties_) -> RequestProperties { 160 | let mut new = EnumSet::new(); 161 | for p in bitfield 162 | .iter() 163 | .filter(|&p| p != prop ) { 164 | new.insert(p); 165 | } 166 | new 167 | } 168 | pub fn set_prop(&mut self, prop: RequestProperties_, bit: bool) { 169 | self.set_props.insert(prop); 170 | self.set_prop_value(prop, bit); 171 | } 172 | // unsets the 'this property is set' bit. Doesn't clear the actual property value bit. 173 | pub fn unset_prop(&mut self, prop: RequestProperties_) -> bool { 174 | let was_set = self.set_props.contains(&prop); 175 | self.set_props = RequestInfo::clear_bit(self.set_props, prop); 176 | was_set 177 | } 178 | 179 | // set the property value, but don't set the 'this property is set' bit. 180 | pub fn set_prop_value(&mut self, prop: RequestProperties_, bit: bool) -> bool { 181 | let mut new = RequestInfo::clear_bit(self.properties, prop); 182 | if bit { 183 | new.insert(prop); 184 | } 185 | 186 | let was_set = self.properties.contains(&prop); 187 | self.properties = new; 188 | was_set 189 | } 190 | 191 | pub fn follow_redirects(mut self) -> RequestInfo { 192 | self.set_prop_value(RequestProperties_::FollowRedirects, true); 193 | self 194 | } 195 | pub fn record_download_progress(mut self) -> RequestInfo { 196 | self.set_prop_value(RequestProperties_::RecordDownloadProgress, true); 197 | self 198 | } 199 | pub fn record_upload_progress(mut self) -> RequestInfo { 200 | self.set_prop_value(RequestProperties_::RecordUploadProgress, true); 201 | self 202 | } 203 | 204 | pub fn create_resource(self, instance: Instance) -> Code { 205 | let request = get_url_request_opt(); 206 | if request.is_none() { return Code::NoInterface; } 207 | let request = request.unwrap(); 208 | 209 | let res = try_code!(instance.create_url_request_info()); 210 | 211 | let set_true = self.set_props.intersection(self.properties); 212 | let set_false = self.set_props - set_true; 213 | 214 | let true_var = unsafe { bool_to_var(1) }; 215 | let false_var = unsafe { bool_to_var(0) }; 216 | 217 | for prop in set_true.iter() { 218 | let set = request.property(res.unwrap(), prop.into(), true_var); 219 | if !set { return Code::Failed; } 220 | } 221 | for prop in set_false.iter() { 222 | let set = request.property(res.unwrap(), prop.into(), false_var); 223 | if !set { return Code::Failed; } 224 | } 225 | let RequestInfo { 226 | bodies, headers, url, method, .. 227 | } = self; 228 | for body in bodies.into_iter() { 229 | let success = match body { 230 | Body::File(ref slice, time) => { 231 | request.append_file_to_body(res.unwrap(), 232 | slice.unwrap(), 233 | Some(slice.view_start() as i64), 234 | slice.view_len().map(|v| v as i64 ), 235 | time) 236 | } 237 | Body::Blob(ref blob) => { 238 | request.append_blob_to_body(res.unwrap(), 239 | blob) 240 | } 241 | }; 242 | if !success { return Code::Failed; } 243 | } 244 | let headers_str = headers.to_string(); 245 | let headers_str = headers_str.to_string_var(); 246 | let success = request.property(res.unwrap(), 247 | ffi::PP_URLREQUESTPROPERTY_HEADERS, 248 | headers_str.to_var()); 249 | 250 | let url = url.to_string().to_string_var(); 251 | let success = success && request.property(res.unwrap(), 252 | ffi::PP_URLREQUESTPROPERTY_URL, 253 | url.to_var()); 254 | 255 | let method = method.to_string().to_string_var(); 256 | let success = success && request.property(res.unwrap(), 257 | ffi::PP_URLREQUESTPROPERTY_METHOD, 258 | method.to_var()); 259 | if !success { return Code::Failed; } 260 | Code::Ok(res) 261 | } 262 | } 263 | impl Into> for (Instance, RequestInfo) { 264 | fn into(self) -> Code { 265 | let (instance, this) = self; 266 | this.create_resource(instance) 267 | } 268 | } 269 | 270 | impl ResponseInfo { 271 | pub fn raw_url(&self) -> StringVar { 272 | let v = get_url_response() 273 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_URL); 274 | assert!(v.is_a_string()); 275 | 276 | From::from(v) 277 | } 278 | pub fn url(&self) -> Url { 279 | let v = self.raw_url(); 280 | FromStr::from_str(v.as_ref()) 281 | .unwrap() 282 | } 283 | 284 | pub fn raw_redirect_url(&self) -> StringVar { 285 | let v = get_url_response() 286 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_REDIRECTURL); 287 | assert!(v.is_a_string()); 288 | 289 | From::from(v) 290 | } 291 | pub fn redirect_url(&self) -> Option { 292 | let v = self.raw_redirect_url(); 293 | if v == "" { 294 | None 295 | } else { 296 | Some(FromStr::from_str(v.as_ref()).unwrap()) 297 | } 298 | } 299 | 300 | pub fn raw_redirect_method(&self) -> StringVar { 301 | let v = get_url_response() 302 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_REDIRECTMETHOD); 303 | assert!(v.is_a_string()); 304 | 305 | From::from(v) 306 | } 307 | pub fn redirect_method(&self) -> Option { 308 | let v = get_url_response() 309 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_REDIRECTMETHOD); 310 | debug_assert!(v.is_a_string()); 311 | 312 | let v = self.raw_redirect_method(); 313 | if v == "" { 314 | None 315 | } else { 316 | Some(FromStr::from_str(v.as_ref()).unwrap()) 317 | } 318 | } 319 | 320 | pub fn raw_status_code(&self) -> u16 { 321 | let v = get_url_response() 322 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_STATUSCODE); 323 | debug_assert!(v.is_an_i32()); 324 | 325 | let v = unsafe { ffi::i32_from_var(v) }; 326 | v as u16 327 | } 328 | pub fn status_code(&self) -> hyper::status::StatusCode { 329 | let v = self.raw_status_code(); 330 | hyper::status::StatusCode::from_u16(v) 331 | } 332 | 333 | /// Returns a newline delimited string of `key: value` pairs. 334 | pub fn raw_headers_str<'a>(&'a self) -> &'a str { 335 | use std::str::from_utf8_unchecked; 336 | use std::slice::from_raw_parts; 337 | use std::mem::{transmute, uninitialized}; 338 | 339 | let v = get_url_response() 340 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_HEADERS); 341 | assert!(v.is_a_string()); 342 | 343 | let f = ppb::get_var().VarToUtf8.unwrap(); 344 | 345 | unsafe { 346 | let mut len: u32 = uninitialized(); 347 | let buf = f(v, &mut len as *mut u32); 348 | let len = len as usize; 349 | let slice = from_raw_parts(transmute(&buf), len); 350 | transmute(from_utf8_unchecked(slice)) 351 | } 352 | } 353 | pub fn raw_headers_var(&self) -> StringVar { 354 | let v = get_url_response() 355 | .property(self.unwrap(), ffi::PP_URLRESPONSEPROPERTY_HEADERS); 356 | assert!(v.is_a_string()); 357 | From::from(v) 358 | } 359 | 360 | pub fn headers(&self) -> Headers { 361 | let mut headers = Vec::with_capacity(5); 362 | let mut offset = 0; 363 | let raw_headers: &[u8] = self.raw_headers_str().as_ref(); 364 | loop { 365 | headers.reserve(1); 366 | let current_len = headers.len(); 367 | let current_cap = headers.capacity(); 368 | unsafe { headers.set_len(current_cap) }; 369 | let (bytes, parsed_len) = { 370 | let (b, p) = 371 | httparse::parse_headers(&raw_headers[offset..], 372 | &mut headers[current_len..current_cap]) 373 | .unwrap() 374 | .unwrap(); 375 | (b, p.len()) 376 | }; 377 | unsafe { headers.set_len(current_len + parsed_len) }; 378 | if bytes == 0 { break; } 379 | offset += bytes; 380 | } 381 | 382 | Headers::from_raw(&headers[..]) 383 | .unwrap() 384 | } 385 | } 386 | 387 | #[derive(Clone, Hash, Eq, PartialEq, Debug)] 388 | pub struct Loader { 389 | res: GenericResource, 390 | info: ResponseInfo, 391 | } 392 | impl Resource for Loader { 393 | fn unwrap(&self) -> ffi::PP_Resource { self.res.unwrap() } 394 | fn type_of(&self) -> Option { Some(ResourceType::UrlLoader) } 395 | } 396 | impl From for Loader { 397 | fn from(loader: ffi::PP_Resource) -> Loader { 398 | let info = get_url_loader() 399 | .get_response_info(loader) 400 | .unwrap(); 401 | 402 | Loader { 403 | res: From::from(loader), 404 | info: ResponseInfo(info), 405 | } 406 | } 407 | } 408 | impl Deref for Loader { 409 | type Target = ResponseInfo; 410 | fn deref(&self) -> &ResponseInfo { &self.info } 411 | } 412 | 413 | impl Loader { 414 | pub fn download_progress(&self) -> Option<(u64, Option)> { 415 | use std::mem; 416 | let mut bytes = unsafe { mem::uninitialized() }; 417 | let mut total = unsafe { mem::uninitialized() }; 418 | 419 | let f = get_url_loader().GetDownloadProgress.unwrap(); 420 | if !f(self.unwrap(), &mut bytes, &mut total) != 0 { 421 | None 422 | } else { 423 | if total == -1 { 424 | Some((bytes as u64, None)) 425 | } else { 426 | Some((bytes as u64, Some(total as u64))) 427 | } 428 | } 429 | } 430 | pub fn upload_progress(&self) -> Option<(u64, u64)> { 431 | use std::mem; 432 | let mut bytes = unsafe { mem::uninitialized() }; 433 | let mut total = unsafe { mem::uninitialized() }; 434 | 435 | let f = get_url_loader().GetUploadProgress.unwrap(); 436 | if !f(self.unwrap(), &mut bytes, &mut total) != 0 { 437 | None 438 | } else { 439 | Some((bytes as u64, total as u64)) 440 | } 441 | } 442 | 443 | pub fn finish_streaming_to_file(&self) { unimplemented!() } 444 | 445 | pub fn info(&self) -> ResponseInfo { self.info.clone() } 446 | 447 | /// Completes when the response headers are received. 448 | pub fn async_open(instance: Instance, info: UrlRequestInfo, 449 | callback: super::CallbackArgs) -> 450 | Code where F: FnOnce(Code) 451 | { 452 | let loader = try_code!(instance.create_url_loader()); 453 | 454 | impl super::InPlaceInit for ffi::PP_Resource { } 455 | 456 | fn map(loader: ffi::PP_Resource, _status: Code) -> Loader { 457 | From::from(loader) 458 | } 459 | 460 | let mapper = super::StorageToArgsMapper(map); 461 | let cc = callback.to_ffi_callback(loader, mapper); 462 | 463 | try_code!(get_url_loader().open(loader, info.unwrap(), cc.cc()) => CC(cc)) 464 | } 465 | pub fn sync_open(instance: Instance, info: UrlRequestInfo) -> Code { 466 | let loader = try_code!(instance.create_url_loader()); 467 | 468 | try_code!(get_url_loader().open(loader, info.unwrap(), 469 | BlockUntilComplete::new())); 470 | Code::Ok(From::from(loader)) 471 | } 472 | } 473 | 474 | impl fs::AsyncRead for Loader { 475 | fn async_read<'a, F>(&mut self, offset: u64, size: usize, 476 | callback: CallbackArgs>) -> 477 | Code> where F: FnOnce(Code>) 478 | { 479 | use super::StorageToArgsMapper; 480 | if offset != 0 { return Code::BadArgument; } 481 | 482 | fn map_arg<'a>(raw: Vec, _status: Code) -> Cow<'a, [u8]> { 483 | Cow::Owned(raw) 484 | } 485 | 486 | let raw_args: Vec = Default::default(); 487 | let mapper = StorageToArgsMapper(map_arg); 488 | let mut cc = callback.to_ffi_callback(raw_args, mapper); 489 | let fficc = cc.cc(); 490 | let code = { 491 | let dest: &mut [u8] = cc.as_mut(); 492 | get_url_loader() 493 | .read_response_body(self.unwrap(), dest.as_mut_ptr() as *mut _, 494 | size, fficc) 495 | }; 496 | cc.drop_with_code(code) 497 | } 498 | } 499 | impl io::Read for Loader { 500 | fn read(&mut self, dest: &mut [u8]) -> io::Result { 501 | let cc = BlockUntilComplete; 502 | let cc = cc.to_ffi_callback(); 503 | 504 | let read = get_url_loader() 505 | .read_response_body(self.unwrap(), dest.as_mut_ptr() as *mut _, 506 | dest.len(), cc.cc()); 507 | 508 | let read = match read { 509 | Code::CompletionPending => unreachable!(), 510 | Code::Ok(read) => read, 511 | read => { return Err(read.into()); }, 512 | }; 513 | Ok(read as usize) 514 | } 515 | } 516 | -------------------------------------------------------------------------------- /src/lib/imagedata.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use libc::c_void; 10 | use std::ops; 11 | 12 | use super::ffi; 13 | use super::{Resource}; 14 | use super::ppb; 15 | use ppb::ImageDataIf; 16 | 17 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct ImageData(ffi::PP_Resource); 18 | 19 | impl_resource_for!(ImageData, ResourceType::ImageData); 20 | impl_clone_drop_for!(ImageData); 21 | 22 | #[derive(Eq, PartialEq, Hash, Clone, Copy)] 23 | pub enum Format { 24 | BGRA = ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL as isize, 25 | RGBA = ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL as isize, 26 | } 27 | impl Format { 28 | fn from_ffi(v: ffi::PP_ImageDataFormat) -> Format { 29 | match v { 30 | ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL => Format::BGRA, 31 | ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL => Format::RGBA, 32 | _ => panic!(), 33 | } 34 | } 35 | pub fn to_ffi(&self) -> ffi::PP_ImageDataFormat { 36 | match *self { 37 | Format::BGRA => ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL, 38 | Format::RGBA => ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL, 39 | } 40 | } 41 | pub fn is_supported(&self) -> bool { 42 | let ffi_val = *self as ffi::PP_ImageDataFormat; 43 | (ppb::get_image_data().IsImageDataFormatSupported.unwrap())(ffi_val) != 0 44 | } 45 | } 46 | 47 | #[derive(Clone, Copy)] 48 | pub struct Description { 49 | pub format: Format, 50 | pub size: super::Size, 51 | 52 | /** Taken from the Google PPAPI docs 53 | * This value represents the row width in bytes. This may be different than 54 | * width * 4 since there may be padding at the end of the lines. 55 | */ 56 | pub line_stride: u32, 57 | } 58 | impl Description { 59 | pub fn from_ffi(desc: ffi::Struct_PP_ImageDataDesc) -> Description { 60 | use std::mem::transmute; 61 | Description { 62 | format: Format::from_ffi(desc.format), 63 | size: unsafe { transmute(desc.size) }, 64 | line_stride: desc.stride as u32, 65 | } 66 | } 67 | } 68 | 69 | pub struct MappedImage<'a> { 70 | img: &'a ImageData, 71 | pub desc: Description, 72 | ptr: *mut c_void, 73 | } 74 | pub trait MappedSlice<'a> { 75 | fn as_imm_slice(&self) -> &'a [u8]; 76 | } 77 | impl<'a> MappedSlice<'a> for MappedImage<'a> { 78 | fn as_imm_slice(&self) -> &'a [u8] { 79 | use std::slice::from_raw_parts; 80 | use std::mem::transmute; 81 | let size = (self.desc.size.height * self.desc.line_stride) as usize; 82 | 83 | unsafe { from_raw_parts(transmute(&self.ptr), size) } 84 | } 85 | } 86 | impl<'a> ops::Drop for MappedImage<'a> { 87 | fn drop(&mut self) { 88 | ppb::get_image_data().unmap(&self.img.unwrap()); 89 | } 90 | } 91 | 92 | pub fn native_image_data_format() -> Format { 93 | Format::from_ffi(ppb::get_image_data().native_image_data_format()) 94 | } 95 | 96 | impl ImageData { 97 | pub fn describe(&self) -> Option { 98 | ppb::get_image_data() 99 | .describe(self.unwrap()) 100 | .map(|desc| Description::from_ffi(desc) ) 101 | } 102 | pub fn map<'a>(&'a self) -> MappedImage<'a> { 103 | MappedImage { 104 | img: self, 105 | desc: self.describe().unwrap(), 106 | ptr: ppb::get_image_data().map(&self.unwrap()), 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/lib/input.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use super::{Resource, ResourceType, Ticks, FloatPoint, 10 | StringVar, Point, TouchPoint}; 11 | use super::{ppb, ffi}; 12 | use ppb::{InputEventIf, KeyboardInputEventIf, MouseInputEventIf, 13 | TouchInputEventIf, WheelInputEventIf}; 14 | use collections::enum_set; 15 | use collections::enum_set::{CLike, EnumSet}; 16 | use std::{iter, mem, clone, hash}; 17 | 18 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct KeyboardInputEvent(ffi::PP_Resource); 19 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct MouseInputEvent(ffi::PP_Resource); 20 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct WheelInputEvent(ffi::PP_Resource); 21 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct TouchInputEvent(ffi::PP_Resource); 22 | #[derive(Eq, Debug)] 23 | pub struct IMEInputEvent { 24 | res: ffi::PP_Resource, 25 | pub string: String, 26 | segments_len: usize, 27 | } 28 | 29 | impl_resource_for!(TouchInputEvent, ResourceType::TouchInputEvent); 30 | impl_resource_for!(WheelInputEvent, ResourceType::WheelInputEvent); 31 | impl_resource_for!(MouseInputEvent, ResourceType::MouseInputEvent); 32 | impl_resource_for!(KeyboardInputEvent, ResourceType::KeyboardInputEvent); 33 | 34 | impl_clone_drop_for!(KeyboardInputEvent); 35 | impl_clone_drop_for!(MouseInputEvent); 36 | impl_clone_drop_for!(WheelInputEvent); 37 | impl_clone_drop_for!(TouchInputEvent); 38 | impl_clone_drop_for!(IMEInputEvent); 39 | 40 | impl IMEInputEvent { 41 | pub fn new(res: ffi::PP_Resource) -> IMEInputEvent { 42 | let var = (ppb::get_ime_event().GetText.unwrap())(res); 43 | let string = StringVar::new_from_var(var).to_string(); 44 | let seg_len = (ppb::get_ime_event().GetSegmentNumber.unwrap())(res); 45 | IMEInputEvent { 46 | res: res, 47 | string: string, 48 | segments_len: seg_len as usize, 49 | } 50 | } 51 | } 52 | impl Resource for IMEInputEvent { 53 | fn unwrap(&self) -> ffi::PP_Resource { 54 | self.res 55 | } 56 | fn type_of(&self) -> Option { 57 | Some(super::ResourceType::IMEInputEvent) 58 | } 59 | } 60 | impl PartialEq for IMEInputEvent { 61 | fn eq(&self, rhs: &IMEInputEvent) -> bool { 62 | self.res == rhs.res 63 | } 64 | } 65 | impl hash::Hash for IMEInputEvent { 66 | fn hash(&self, s: &mut H) 67 | where H: hash::Hasher 68 | { 69 | self.res.hash(s) 70 | } 71 | } 72 | 73 | #[derive(Clone, Debug)] 74 | pub enum Class { 75 | Keyboard(Event), 76 | Mouse (Event), 77 | Wheel (Event), 78 | Touch (Event), 79 | IME (Event), 80 | } 81 | 82 | pub type KeyboardClassEvent = Event; 83 | pub type MouseClassEvent = Event; 84 | pub type WheelClassEvent = Event; 85 | pub type TouchClassEvent = Event; 86 | pub type IMEClassEvent = Event; 87 | 88 | impl Class { 89 | pub fn new(res: T) -> Class { 90 | let ticks = res.timestamp(); 91 | let modifiers = res.modifiers(); 92 | 93 | // Wraps a (safe) hack saving us from cloning res. 94 | // This is safe because it will only get called when T && U 95 | // are actually the same. We need this so as to bypass transmute 96 | // on value types (which fails when the types aren't the same 97 | // size). 98 | fn cast_to_expected(mut res: T) -> U { 99 | use std::mem::{replace, uninitialized, transmute}; 100 | unsafe { 101 | let res_ptr: &mut U = transmute(&mut res); 102 | replace(res_ptr, uninitialized()) 103 | } 104 | } 105 | 106 | let input_event = ppb::get_input_event(); 107 | let mouse_event = ppb::get_mouse_event(); 108 | let kb_event = ppb::get_keyboard_event(); 109 | //let wheel_event = ppb::get_wheel_event(); 110 | //let ime_event = ppb::get_ime_event(); 111 | //let touch_event = ppb::get_touch_event(); 112 | 113 | match input_event.type_of(&res.unwrap()) { 114 | ffi::PP_INPUTEVENT_TYPE_MOUSEDOWN => { 115 | Class::Mouse(Event { 116 | event: MouseEvent::Press(Press::Down, 117 | MouseClickEvent { 118 | point: mouse_event.point(&res.unwrap()), 119 | button: MouseButton::from_ffi 120 | (mouse_event.button(&res.unwrap())), 121 | click_count: mouse_event.click_count(&res.unwrap()), 122 | }), 123 | res: cast_to_expected(res), 124 | timestamp: ticks, 125 | mods: modifiers, 126 | }) 127 | } 128 | ffi::PP_INPUTEVENT_TYPE_MOUSEUP => { 129 | Class::Mouse(Event { 130 | event: MouseEvent::Press(Press::Up, 131 | MouseClickEvent { 132 | point: mouse_event.point(&res.unwrap()), 133 | button: MouseButton::from_ffi 134 | (mouse_event.button(&res.unwrap())), 135 | click_count: mouse_event.click_count(&res.unwrap()), 136 | }), 137 | res: cast_to_expected(res), 138 | timestamp: ticks, 139 | mods: modifiers, 140 | }) 141 | } 142 | ffi::PP_INPUTEVENT_TYPE_MOUSEMOVE => { 143 | Class::Mouse(Event { 144 | event: MouseEvent::Move(Move::Move, 145 | MouseMoveEvent { 146 | point: mouse_event.point(&res.unwrap()), 147 | delta: mouse_event.delta(&res.unwrap()), 148 | click_count: mouse_event.click_count(&res.unwrap()), 149 | }), 150 | res: cast_to_expected(res), 151 | timestamp: ticks, 152 | mods: modifiers, 153 | }) 154 | } 155 | ffi::PP_INPUTEVENT_TYPE_MOUSEENTER => { 156 | Class::Mouse(Event { 157 | event: MouseEvent::Move(Move::Enter, 158 | MouseMoveEvent { 159 | point: mouse_event.point(&res.unwrap()), 160 | delta: mouse_event.delta(&res.unwrap()), 161 | click_count: mouse_event.click_count(&res.unwrap()), 162 | }), 163 | res: cast_to_expected(res), 164 | timestamp: ticks, 165 | mods: modifiers, 166 | }) 167 | } 168 | ffi::PP_INPUTEVENT_TYPE_MOUSELEAVE => { 169 | Class::Mouse(Event { 170 | event: MouseEvent::Move(Move::Leave, 171 | MouseMoveEvent { 172 | point: mouse_event.point(&res.unwrap()), 173 | delta: mouse_event.delta(&res.unwrap()), 174 | click_count: mouse_event.click_count(&res.unwrap()), 175 | }), 176 | res: cast_to_expected(res), 177 | timestamp: ticks, 178 | mods: modifiers, 179 | }) 180 | } 181 | ffi::PP_INPUTEVENT_TYPE_WHEEL => { 182 | unreachable!() 183 | } 184 | ffi::PP_INPUTEVENT_TYPE_KEYDOWN => { 185 | Class::Keyboard(Event { 186 | event: KeyboardEvent::Press(Press::Down, 187 | kb_event.key_code(&res.unwrap()) as i32), 188 | res: cast_to_expected(res), 189 | timestamp: ticks, 190 | mods: modifiers, 191 | }) 192 | } 193 | ffi::PP_INPUTEVENT_TYPE_KEYUP => { 194 | Class::Keyboard(Event { 195 | event: KeyboardEvent::Press(Press::Up, 196 | kb_event.key_code(&res.unwrap()) as i32), 197 | res: cast_to_expected(res), 198 | timestamp: ticks, 199 | mods: modifiers, 200 | }) 201 | } 202 | ffi::PP_INPUTEVENT_TYPE_CHAR => { 203 | let char_var = StringVar((unsafe { 204 | ffi::id_from_var(kb_event.text(&res.unwrap())) 205 | }) as i64); 206 | let str = char_var.to_string(); 207 | if str.len() != 1 { 208 | error!("character input event does not have a length of one: \ 209 | \"{}\"", str) 210 | } 211 | Class::Keyboard(Event { 212 | res: cast_to_expected(res), 213 | timestamp: ticks, 214 | mods: modifiers, 215 | event: KeyboardEvent::Char(str.chars().next().unwrap()), 216 | }) 217 | } 218 | ffi::PP_INPUTEVENT_TYPE_CONTEXTMENU => { 219 | Class::Mouse(Event { 220 | event: MouseEvent::ContextMenu(MouseClickEvent { 221 | point: mouse_event.point(&res.unwrap()), 222 | button: MouseButton::Right, 223 | click_count: mouse_event.click_count(&res.unwrap()), 224 | }), 225 | res: cast_to_expected(res), 226 | timestamp: ticks, 227 | mods: modifiers, 228 | }) 229 | } 230 | _ => { 231 | panic!("invalid input event type") 232 | } 233 | } 234 | } 235 | } 236 | impl Resource for Class { 237 | fn unwrap(&self) -> ffi::PP_Resource { 238 | match self { 239 | &Class::Keyboard(ref e) => e.res.unwrap(), 240 | &Class::Mouse (ref e) => e.res.unwrap(), 241 | &Class::Wheel (ref e) => e.res.unwrap(), 242 | &Class::Touch (ref e) => e.res.unwrap(), 243 | &Class::IME (ref e) => e.res.unwrap(), 244 | } 245 | } 246 | fn type_of(&self) -> Option { 247 | match self { 248 | &Class::Keyboard(ref e) => e.res.type_of(), 249 | &Class::Mouse (ref e) => e.res.type_of(), 250 | &Class::Wheel (ref e) => e.res.type_of(), 251 | &Class::Touch (ref e) => e.res.type_of(), 252 | &Class::IME (ref e) => e.res.type_of(), 253 | } 254 | } 255 | } 256 | impl InputEvent for Class { 257 | fn modifiers(&self) -> Modifiers { 258 | match self { 259 | &Class::Keyboard(Event { mods: ref m, .. }) | 260 | &Class::Mouse (Event { mods: ref m, .. }) | 261 | &Class::Wheel (Event { mods: ref m, .. }) | 262 | &Class::Touch (Event { mods: ref m, .. }) | 263 | &Class::IME (Event { mods: ref m, .. }) => m.clone(), 264 | } 265 | } 266 | fn timestamp(&self) -> Ticks { 267 | match self { 268 | &Class::Keyboard(Event { timestamp: ts, .. }) | 269 | &Class::Mouse (Event { timestamp: ts, .. }) | 270 | &Class::Wheel (Event { timestamp: ts, .. }) | 271 | &Class::Touch (Event { timestamp: ts, .. }) | 272 | &Class::IME (Event { timestamp: ts, .. }) => ts, 273 | } 274 | } 275 | } 276 | #[derive(Clone, Debug)] 277 | pub struct Event { 278 | pub res: Res, 279 | pub timestamp: Ticks, 280 | pub mods: Modifiers, 281 | pub event: Class, 282 | } 283 | impl Resource for Event { 284 | fn unwrap(&self) -> ffi::PP_Resource { 285 | self.res.unwrap() 286 | } 287 | fn type_of(&self) -> Option { 288 | self.res.type_of() 289 | } 290 | } 291 | impl InputEvent for Event { 292 | fn modifiers(&self) -> Modifiers { 293 | self.mods.clone() 294 | } 295 | fn timestamp(&self) -> Ticks { 296 | self.timestamp 297 | } 298 | } 299 | #[derive(Clone, Hash, Eq, PartialEq, Debug, Copy)] 300 | pub enum Modifiers_ { 301 | ShiftKey, 302 | ControlKey, 303 | AltKey, 304 | MetaKey, 305 | IsKeyPad, 306 | IsAutoRepeat, 307 | LeftButtonDown, 308 | MiddleButtonDown, 309 | RightButtonDown, 310 | CapsLockKey, 311 | NumLockKey, 312 | IsLeft, 313 | IsRight, 314 | } 315 | impl CLike for Modifiers_ { 316 | fn to_usize(&self) -> usize { 317 | match self { 318 | &Modifiers_::ShiftKey => 0, 319 | &Modifiers_::ControlKey => 1, 320 | &Modifiers_::AltKey => 2, 321 | &Modifiers_::MetaKey => 3, 322 | &Modifiers_::IsKeyPad => 4, 323 | &Modifiers_::IsAutoRepeat => 5, 324 | &Modifiers_::LeftButtonDown => 6, 325 | &Modifiers_::MiddleButtonDown => 7, 326 | &Modifiers_::RightButtonDown => 8, 327 | &Modifiers_::CapsLockKey => 9, 328 | &Modifiers_::NumLockKey => 10, 329 | &Modifiers_::IsLeft => 11, 330 | &Modifiers_::IsRight => 12, 331 | } 332 | } 333 | fn from_usize(v: usize) -> Modifiers_ { 334 | match v { 335 | 0 => Modifiers_::ShiftKey, 336 | 1 => Modifiers_::ControlKey, 337 | 2 => Modifiers_::AltKey, 338 | 3 => Modifiers_::MetaKey, 339 | 4 => Modifiers_::IsKeyPad, 340 | 5 => Modifiers_::IsAutoRepeat, 341 | 6 => Modifiers_::LeftButtonDown, 342 | 7 => Modifiers_::MiddleButtonDown, 343 | 8 => Modifiers_::RightButtonDown, 344 | 9 => Modifiers_::CapsLockKey, 345 | 10 => Modifiers_::NumLockKey, 346 | 11 => Modifiers_::IsLeft, 347 | 12 => Modifiers_::IsRight, 348 | _ => unreachable!(), 349 | } 350 | } 351 | } 352 | pub type Modifiers = EnumSet; 353 | fn modifiers_from_bitset(set: u32) -> Modifiers { 354 | let mut e: Modifiers = enum_set::EnumSet::new(); 355 | if set & 0b0000000000001 != 0 { e.insert(Modifiers_::ShiftKey); } 356 | if set & 0b0000000000010 != 0 { e.insert(Modifiers_::ControlKey); } 357 | if set & 0b0000000000100 != 0 { e.insert(Modifiers_::AltKey); } 358 | if set & 0b0000000001000 != 0 { e.insert(Modifiers_::MetaKey); } 359 | if set & 0b0000000010000 != 0 { e.insert(Modifiers_::IsKeyPad); } 360 | if set & 0b0000000100000 != 0 { e.insert(Modifiers_::IsAutoRepeat); } 361 | if set & 0b0000001000000 != 0 { e.insert(Modifiers_::LeftButtonDown); } 362 | if set & 0b0000010000000 != 0 { e.insert(Modifiers_::MiddleButtonDown); } 363 | if set & 0b0000100000000 != 0 { e.insert(Modifiers_::RightButtonDown); } 364 | if set & 0b0001000000000 != 0 { e.insert(Modifiers_::CapsLockKey); } 365 | if set & 0b0010000000000 != 0 { e.insert(Modifiers_::NumLockKey); } 366 | if set & 0b0100000000000 != 0 { e.insert(Modifiers_::IsLeft); } 367 | if set & 0b1000000000000 != 0 { e.insert(Modifiers_::IsRight); } 368 | e 369 | } 370 | #[derive(Clone, Hash, Eq, PartialEq, Debug, Copy)] 371 | pub enum Move { 372 | Enter, 373 | Leave, 374 | Move, 375 | } 376 | 377 | #[derive(Clone, Hash, Eq, PartialEq, Debug, Copy)] 378 | pub enum Press { 379 | Down, 380 | Up, 381 | } 382 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 383 | pub enum MouseEvent { 384 | Press (Press, MouseClickEvent), 385 | ContextMenu (MouseClickEvent), 386 | Move (Move, MouseMoveEvent), 387 | } 388 | impl MouseEvent { 389 | fn point(&self) -> FloatPoint { 390 | match self { 391 | &MouseEvent::Press(_, MouseClickEvent { 392 | point, .. 393 | }) | &MouseEvent::ContextMenu(MouseClickEvent { 394 | point, .. 395 | }) | &MouseEvent::Move(_, MouseMoveEvent { 396 | point, .. 397 | }) => point, 398 | } 399 | } 400 | } 401 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 402 | pub enum MouseButton { 403 | Left, 404 | Middle, 405 | Right, 406 | } 407 | impl MouseButton { 408 | fn from_ffi(v: i32) -> MouseButton { 409 | match v { 410 | ffi::PP_INPUTEVENT_MOUSEBUTTON_LEFT => MouseButton::Left, 411 | ffi::PP_INPUTEVENT_MOUSEBUTTON_MIDDLE => MouseButton::Middle, 412 | ffi::PP_INPUTEVENT_MOUSEBUTTON_RIGHT => MouseButton::Right, 413 | _ => unreachable!(), 414 | } 415 | } 416 | } 417 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 418 | pub struct MouseClickEvent { 419 | point: FloatPoint, 420 | button: MouseButton, 421 | click_count: i32, 422 | } 423 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 424 | pub struct MouseMoveEvent { 425 | point: FloatPoint, 426 | delta: FloatPoint, 427 | click_count: i32, 428 | } 429 | 430 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 431 | pub enum KeyboardEvent { 432 | Press(Press, i32), 433 | Char(char), 434 | } 435 | 436 | #[derive(Clone, Eq, PartialEq, Debug, Copy)] 437 | pub struct WheelEvent { 438 | delta: FloatPoint, 439 | ticks: FloatPoint, 440 | by_page: bool, 441 | } 442 | 443 | pub trait InputEvent { 444 | fn modifiers(&self) -> Modifiers; 445 | fn timestamp(&self) -> Ticks; 446 | } 447 | 448 | macro_rules! impl_input_event_for( 449 | ($ty:ty) => ( 450 | impl InputEvent for $ty { 451 | fn modifiers(&self) -> Modifiers { 452 | let bitset = ppb::get_input_event().modifiers(&self.unwrap()); 453 | modifiers_from_bitset(bitset) 454 | } 455 | fn timestamp(&self) -> Ticks { 456 | ppb::get_input_event().timestamp(&self.unwrap()) 457 | } 458 | } 459 | ) 460 | ); 461 | 462 | impl_input_event_for!(KeyboardInputEvent); 463 | impl_input_event_for!(MouseInputEvent); 464 | impl_input_event_for!(WheelInputEvent); 465 | impl_input_event_for!(TouchInputEvent); 466 | impl_input_event_for!(IMEInputEvent); 467 | 468 | impl KeyboardInputEvent { 469 | pub fn get_key_code(&self) -> u32 { 470 | (ppb::get_keyboard_event().GetKeyCode.unwrap())(self.unwrap()) 471 | } 472 | pub fn get_char_text(&self) -> StringVar { 473 | let var = (ppb::get_keyboard_event().GetCharacterText.unwrap())(self.unwrap()); 474 | StringVar::new_from_var(var) 475 | } 476 | } 477 | impl MouseInputEvent { 478 | pub fn get_button(&self) -> ffi::PP_InputEvent_MouseButton { 479 | (ppb::get_mouse_event().GetButton.unwrap())(self.unwrap()) 480 | } 481 | pub fn get_position(&self) -> Point { 482 | From::from((ppb::get_mouse_event().GetPosition.unwrap())(self.unwrap())) 483 | } 484 | pub fn get_click_count(&self) -> i32 { 485 | (ppb::get_mouse_event().GetClickCount.unwrap())(self.unwrap()) 486 | } 487 | pub fn get_movement(&self) -> Point { 488 | From::from((ppb::get_mouse_event().GetMovement.unwrap())(self.unwrap())) 489 | } 490 | } 491 | impl WheelInputEvent { 492 | pub fn get_delta(&self) -> FloatPoint { 493 | (ppb::get_wheel_event().GetDelta.unwrap())(self.unwrap()) 494 | } 495 | pub fn get_ticks(&self) -> FloatPoint { 496 | (ppb::get_wheel_event().GetTicks.unwrap())(self.unwrap()) 497 | } 498 | pub fn get_scroll_by_page(&self) -> bool { 499 | (ppb::get_wheel_event().GetScrollByPage.unwrap())(self.unwrap()) != ffi::PP_FALSE 500 | } 501 | } 502 | #[derive(Clone, Eq, PartialEq, Hash, Debug, Copy)] 503 | pub enum TouchListType { 504 | Touches, 505 | Delta, 506 | Target, 507 | } 508 | impl TouchListType { 509 | fn to_ffi(&self) -> ffi::PP_TouchListType { 510 | match self { 511 | &TouchListType::Touches => ffi::PP_TOUCHLIST_TYPE_TOUCHES, 512 | &TouchListType::Delta => ffi::PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, 513 | &TouchListType::Target => ffi::PP_TOUCHLIST_TYPE_TARGETTOUCHES, 514 | } 515 | } 516 | } 517 | #[derive(Clone)] 518 | pub struct TouchList { 519 | event: TouchInputEvent, 520 | list_type: TouchListType, 521 | } 522 | #[derive(Clone)] 523 | pub struct TouchListIterator { 524 | list: TouchList, 525 | current: usize, 526 | size: usize, 527 | } 528 | impl TouchInputEvent { 529 | pub fn get_touch_list(&self, list_type: TouchListType) -> TouchList { 530 | TouchList{ 531 | event: self.clone(), 532 | list_type: list_type, 533 | } 534 | } 535 | } 536 | impl TouchList { 537 | pub fn get(&self, index: usize) -> TouchPoint { 538 | ppb::get_touch_event().by_index 539 | (&self.event.unwrap(), 540 | self.list_type.to_ffi(), 541 | index as u32) 542 | } 543 | pub fn iter(&self) -> TouchListIterator { 544 | TouchListIterator{ 545 | list: self.clone(), 546 | current: 0, 547 | size: self.len(), 548 | } 549 | } 550 | pub fn find_id(&self, id: u32) -> Option { 551 | if id < self.len() as u32 { 552 | Some(ppb::get_touch_event().by_id 553 | (&self.event.unwrap(), 554 | self.list_type.to_ffi(), 555 | id)) 556 | } else { 557 | None 558 | } 559 | } 560 | pub fn len(&self) -> usize { 561 | (ppb::get_touch_event().GetTouchCount.unwrap()) 562 | (self.event.unwrap(), 563 | self.list_type.to_ffi()) as usize 564 | } 565 | } 566 | impl iter::Iterator for TouchListIterator { 567 | type Item = TouchPoint; 568 | fn next(&mut self) -> Option { 569 | if self.current >= self.size { None } 570 | else { self.current += 1; 571 | Some(self.list.get(self.current - 1)) } 572 | } 573 | } 574 | #[allow(deprecated)] 575 | impl iter::RandomAccessIterator for TouchListIterator { 576 | fn indexable(&self) -> usize { 577 | self.size 578 | } 579 | fn idx(&mut self, index: usize) -> Option { 580 | if index < self.size { Some(self.list.get(index)) } 581 | else { None } 582 | } 583 | } 584 | 585 | impl IMEInputEvent { 586 | pub fn segments_len(&self) -> usize { 587 | self.segments_len 588 | } 589 | pub fn segment_offset(&self, index: usize) -> Option<(usize, usize)> { 590 | if index < self.segments_len() { 591 | let interface = ppb::get_ime_event(); 592 | let start = (interface.GetSegmentOffset.unwrap()) 593 | (self.unwrap(), 594 | index as u32); 595 | let end = (interface.GetSegmentOffset.unwrap()) 596 | (self.unwrap(), 597 | (index + 1) as u32); 598 | Some((start as usize, end as usize)) 599 | } else { 600 | None 601 | } 602 | } 603 | pub fn segment_str<'a>(&'a self, index: usize) -> Option<&'a str> { 604 | if index < self.segments_len() { 605 | let segment = self.segment_offset(index); 606 | let (start, end) = segment.expect("WAT. #1"); 607 | Some(&self.string[start .. end]) 608 | } else { 609 | None 610 | } 611 | } 612 | pub fn segment_iter<'a>(&'a self) -> IMESegmentIterator<'a> { 613 | IMESegmentIterator{ 614 | event: self, 615 | current: 0, 616 | } 617 | } 618 | pub fn selection_offset(&self) -> (u32, u32) { 619 | let mut start: u32 = unsafe { mem::uninitialized() }; 620 | let mut end: u32 = unsafe { mem::uninitialized() }; 621 | 622 | 623 | let start_ptr: *mut u32 = &mut start as *mut u32; 624 | let end_ptr: *mut u32 = &mut end as *mut u32; 625 | (ppb::get_ime_event().GetSelection.unwrap()) 626 | (self.unwrap(), 627 | start_ptr, 628 | end_ptr); 629 | 630 | let start = start; 631 | let end = end; 632 | 633 | (start, end) 634 | } 635 | pub fn selection_str<'a>(&'a self) -> &'a str { 636 | let (start, end) = self.selection_offset(); 637 | &self.string[start as usize .. end as usize] 638 | } 639 | pub fn target_segment_index(&self) -> Option { 640 | match (ppb::get_ime_event().GetTargetSegment.unwrap()) 641 | (self.unwrap()) { 642 | -1 => None, 643 | index => Some(index as usize), 644 | } 645 | } 646 | pub fn target_segment_str<'a>(&'a self) -> Option<&'a str> { 647 | match self.target_segment_index() { 648 | Some(index) => self.segment_str(index as usize), 649 | None => None, 650 | } 651 | } 652 | } 653 | pub struct IMESegmentIterator<'a> { 654 | event: &'a IMEInputEvent, 655 | current: usize, 656 | } 657 | impl<'a> clone::Clone for IMESegmentIterator<'a> { 658 | fn clone(&self) -> IMESegmentIterator<'a> { 659 | IMESegmentIterator { 660 | event: self.event, 661 | current: self.current, 662 | } 663 | } 664 | } 665 | impl<'a> iter::Iterator for IMESegmentIterator<'a> { 666 | type Item = &'a str; 667 | fn next(&mut self) -> Option<&'a str> { 668 | self.current += 1; 669 | self.event.segment_str(self.current - 1) 670 | } 671 | } 672 | #[allow(deprecated)] 673 | impl<'a> iter::RandomAccessIterator for IMESegmentIterator<'a> { 674 | fn indexable(&self) -> usize { 675 | self.event.segments_len() 676 | } 677 | fn idx(&mut self, index: usize) -> Option<&'a str> { 678 | self.event.segment_str(index) 679 | } 680 | } 681 | -------------------------------------------------------------------------------- /src/lib/media_stream_video_track.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use ffi; 10 | use ppb::{ResourceInterface, MediaStreamVideoTrackIf, get_media_stream_video_track}; 11 | 12 | use super::{Callback, CallbackArgs, StringVar, Code, Resource}; 13 | use super::video_frame::{self, VideoFrame}; 14 | 15 | /// Created on the JS side and sent in a message. 16 | #[derive(Hash, Eq, PartialEq, Debug)] 17 | pub struct VideoTrack(ffi::PP_Resource); 18 | 19 | impl_clone_drop_for!(VideoTrack); 20 | impl_resource_for!(VideoTrack, ResourceType::VideoFrame); 21 | 22 | #[doc(hidden)] 23 | impl From for VideoTrack { 24 | fn from(v: ffi::PP_Resource) -> VideoTrack { 25 | debug_assert!(get_media_stream_video_track().is(v)); 26 | VideoTrack(v) 27 | } 28 | } 29 | 30 | #[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] 31 | pub enum Attr { 32 | /// The number of buffer frames. Chrome may use more or less. How many 33 | /// frames to buffer depends on usage - request at least 2 to make sure 34 | /// latency doesn't cause lost frames. If the plugin expects to hold on to 35 | /// more than one frame at a time (e.g. to do multi-frame processing), it 36 | /// should request that many more. If this attribute is not specified or 37 | /// value 0 is specified for this attribute, the default value will be 38 | /// used. 39 | Buffers(u32), 40 | 41 | /// The width of video frames in pixels. 42 | /// 43 | /// It should be a multiple of 4. If the specified size is different from 44 | /// the video source (webcam), frames will be scaled to specified size. If 45 | /// this attribute is not specified or value 0 is specified, the original 46 | /// frame size of the video track will be used. 47 | /// 48 | /// Maximum value: 4096 (4K resolution). 49 | Width(u32), 50 | /// The height of video frames in pixels. 51 | /// 52 | /// It should be a multiple of 4. If the specified size is different from 53 | /// the video source (webcam), frames will be scaled to specified size. If 54 | /// this attribute is not specified or value 0 is specified, the original 55 | /// frame size of the video track will be used. 56 | /// 57 | /// Maximum value: 4096 (4K resolution). 58 | Height(u32), 59 | 60 | /// The format of video frames. 61 | /// 62 | /// The attribute value is a `video_frame::Format`. If the specified 63 | /// format is different from the video source (webcam), frames will be 64 | /// converted to specified format. If this attribute is not specified or 65 | /// value `Format::Unknown` is specified, the orignal frame format of the 66 | /// video track will be used. 67 | Format(video_frame::Format), 68 | } 69 | impl Attr { 70 | #[doc(hidden)] 71 | pub fn to_ffi(self) -> ffi::PP_MediaStreamVideoTrack_Attrib { 72 | match self { 73 | Attr::Buffers(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_BUFFERED_FRAMES, 74 | Attr::Width(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, 75 | Attr::Height(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, 76 | Attr::Format(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, 77 | } 78 | } 79 | } 80 | 81 | impl VideoTrack { 82 | pub fn configure, F>(&self, attrs: T, callback: CallbackArgs) -> Code<()> 83 | where F: FnOnce(Code<()>) 84 | { 85 | use std::cmp::min; 86 | 87 | let mut nattrs: Vec = 88 | Vec::with_capacity(attrs.as_ref().len() + 1); 89 | for attr in attrs.as_ref().iter() { 90 | nattrs.push(attr.to_ffi()); 91 | match attr { 92 | &Attr::Buffers(c) => { 93 | nattrs.push(c as ffi::PP_MediaStreamVideoTrack_Attrib); 94 | }, 95 | &Attr::Width(c) | &Attr::Height(c) => { 96 | nattrs.push(min(c, 4096) as ffi::PP_MediaStreamVideoTrack_Attrib); 97 | }, 98 | &Attr::Format(f) => { 99 | nattrs.push(f.to_ffi()); 100 | }, 101 | } 102 | } 103 | nattrs.push(ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE); 104 | 105 | let cc = callback.to_ffi_callback((), Default::default()); 106 | 107 | let code = get_media_stream_video_track() 108 | .configure(self.unwrap(), nattrs.as_ref(), cc.cc); 109 | cc.drop_with_code(code) 110 | } 111 | pub fn buffer_count(&self) -> Code { 112 | get_media_stream_video_track() 113 | .get_attrib(self.unwrap(), Attr::Buffers(0).to_ffi()) 114 | .map_ok(|i| { 115 | i as u32 116 | }) 117 | } 118 | pub fn width(&self) -> Code { 119 | get_media_stream_video_track() 120 | .get_attrib(self.unwrap(), Attr::Width(0).to_ffi()) 121 | .map_ok(|i| { 122 | i as u32 123 | }) 124 | } 125 | pub fn height(&self) -> Code { 126 | get_media_stream_video_track() 127 | .get_attrib(self.unwrap(), Attr::Height(0).to_ffi()) 128 | .map_ok(|i| { 129 | i as u32 130 | }) 131 | } 132 | pub fn format(&self) -> Code { 133 | get_media_stream_video_track() 134 | .get_attrib(self.unwrap(), 135 | Attr::Format(video_frame::Format::Unknown).to_ffi()) 136 | .map_ok(|i| { 137 | From::from(i as ffi::PP_VideoFrame_Format) 138 | }) 139 | } 140 | pub fn get_id(&self) -> StringVar { 141 | From::from(get_media_stream_video_track().get_id(self.unwrap())) 142 | } 143 | pub fn has_ended(&self) -> bool { 144 | get_media_stream_video_track() 145 | .has_ended(self.unwrap()) 146 | } 147 | pub fn get_frame(&self, f: CallbackArgs) -> 148 | Code<(VideoTrack, VideoFrame)> where F: FnOnce(Code<(VideoTrack, VideoFrame)>) 149 | { 150 | impl super::InPlaceInit for (VideoTrack, i32) { } 151 | fn map_args((this, frame): (VideoTrack, i32), _status: Code) -> 152 | (VideoTrack, VideoFrame) 153 | { 154 | (this, From::from(frame)) 155 | } 156 | 157 | let mapper = super::StorageToArgsMapper(map_args); 158 | let mut cc = f.to_ffi_callback((self.clone(), 0i32), mapper); 159 | let fficc = cc.cc; 160 | let code = get_media_stream_video_track() 161 | .get_frame(self.unwrap(), &mut cc.1, fficc); 162 | cc.drop_with_code(code) 163 | } 164 | pub fn recycle_frame(&self, frame: VideoFrame) -> Code { 165 | get_media_stream_video_track() 166 | .recycle_frame(self.unwrap(), frame.unwrap()) 167 | } 168 | pub fn close(self) { 169 | get_media_stream_video_track() 170 | .close(self.unwrap()) 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/lib/message_handler.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use std::cell::RefCell; 10 | use std::mem::transmute; 11 | 12 | use libc; 13 | 14 | use ffi; 15 | use ppb::{get_messaging_opt}; 16 | 17 | use {Code, MessageLoop, Instance, AnyVar, ToVar, Resource}; 18 | 19 | pub trait MessageHandling: Send + Sync { 20 | fn register(&self, handler: T) -> Code<()> 21 | where T: MessageHandler; 22 | fn register_on_loop(&self, handler: T, msg_loop: MessageLoop) -> Code<()> 23 | where T: MessageHandler + Send 24 | { 25 | msg_loop 26 | .post_work(move |_| { 27 | // TODO 28 | let _ = self.register(handler); 29 | }, 0) 30 | .map_ok(|_| () ) 31 | } 32 | fn unregister(&self); 33 | } 34 | impl MessageHandling for Instance { 35 | fn register(&self, handler: T) -> Code<()> 36 | where T: MessageHandler 37 | { 38 | let interface = if let Some(i) = get_messaging_opt() { 39 | i 40 | } else { 41 | return Code::NoInterface; 42 | }; 43 | let interface = interface.RegisterMessageHandler.unwrap(); 44 | 45 | let ffi = ffi::Struct_PPP_MessageHandler_0_2 { 46 | HandleMessage: Some(handle_message::), 47 | HandleBlockingMessage: Some(handle_blocking_message:: ), 48 | Destroy: Some(destroy::), 49 | }; 50 | let internal = Handler { 51 | handler: handler, 52 | ffi: ffi, 53 | }; 54 | let mut handler = Box::new(internal); 55 | 56 | handler.handler.registered(); 57 | 58 | let ffi_ptr = unsafe { 59 | let ptr: *const *const ffi::Struct_PPP_MessageHandler_0_2 = 60 | transmute(&handler); 61 | *ptr 62 | }; 63 | let handler_ptr = unsafe { transmute(handler) }; 64 | 65 | let code = interface(Instance::current().unwrap(), handler_ptr, ffi_ptr, 66 | MessageLoop::current().unwrap().unwrap()); 67 | let code: Code = From::from(code); 68 | code.map_ok(|_| () ) 69 | } 70 | fn unregister(&self) { 71 | let interface = if let Some(i) = get_messaging_opt() { 72 | i 73 | } else { 74 | return; 75 | }; 76 | let interface = interface.UnregisterMessageHandler.unwrap(); 77 | interface(self.unwrap()); 78 | } 79 | } 80 | 81 | pub trait MessageHandler { 82 | fn registered(&mut self); 83 | fn async_message(&mut self, msg: AnyVar); 84 | fn sync_message(&mut self, msg: AnyVar) -> AnyVar; 85 | fn unregistered(self); 86 | } 87 | 88 | struct Handler { 89 | handler: T, 90 | ffi: ffi::Struct_PPP_MessageHandler_0_2, 91 | } 92 | 93 | thread_local!(static HANDLERS: Option>> = Default::default()); 94 | 95 | extern fn handle_message(_instance: ffi::PP_Instance, 96 | user_data: *mut libc::c_void, 97 | message: *const ffi::Struct_PP_Var) 98 | where T: MessageHandler 99 | { 100 | let handler: &mut Handler = unsafe { transmute(user_data) }; 101 | let var = unsafe { *message }; 102 | let var = AnyVar::new_bumped(var); // TODO var refs. 103 | handler.handler.async_message(var); 104 | } 105 | 106 | extern fn handle_blocking_message(_instance: ffi::PP_Instance, 107 | user_data: *mut libc::c_void, 108 | message: *const ffi::Struct_PP_Var, 109 | response: *mut ffi::Struct_PP_Var) 110 | where T: MessageHandler 111 | { 112 | let handler: &mut Handler = unsafe { transmute(user_data) }; 113 | let var = unsafe { *message }; 114 | let var = AnyVar::new_bumped(var); // TODO var refs. 115 | let ret = handler.handler.sync_message(var); 116 | 117 | unsafe { 118 | *response = ret.to_var(); 119 | } 120 | } 121 | 122 | extern fn destroy(_instance: ffi::PP_Instance, 123 | user_data: *mut libc::c_void) 124 | where T: MessageHandler 125 | { 126 | let handler: Box> = unsafe { transmute(user_data) }; 127 | handler.handler.unregistered(); 128 | } 129 | 130 | /// Ensures the local handlers gets unregistered and cleaned up before the 131 | /// message loop terminates. 132 | #[doc(hidden)] 133 | pub fn unregister_handlers(queue: &MessageLoop) { 134 | fn _unregister_handlers(_: Code<()>) { 135 | HANDLERS.with(|h| { 136 | let h = if let &Some(ref h) = h { 137 | h 138 | } else { 139 | return; 140 | }; 141 | 142 | let mut b = h.borrow_mut(); 143 | for instance in b.iter() { 144 | instance.unregister(); 145 | } 146 | b.clear(); 147 | }) 148 | } 149 | queue.post_work(_unregister_handlers, 0) 150 | .unwrap(); 151 | } 152 | -------------------------------------------------------------------------------- /src/lib/pp.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use super::ffi; 10 | 11 | mod globals { 12 | use super::super::ffi; 13 | 14 | pub static mut MODULE: ffi::PP_Module = 0 as ffi::PP_Module; 15 | } 16 | // Initialize the global module handle. 17 | pub fn initialize_globals(module: ffi::PP_Module) { 18 | unsafe { 19 | globals::MODULE = module; 20 | } 21 | } 22 | 23 | // Return a clone of the module handle. 24 | pub fn get_module() -> ffi::PP_Module { 25 | unsafe { 26 | globals::MODULE 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/lib/ppp.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use std::ptr; 10 | use libc::{c_char, c_void}; 11 | 12 | mod consts { 13 | pub static INSTANCE: &'static [u8] = b"PPP_Instance;1.1\0"; 14 | pub static INPUTEVENT: &'static [u8] = b"PPP_InputEvent;0.1\0"; 15 | pub static GRAPHICS: &'static [u8] = b"PPP_Graphics_3D;1.0\0"; 16 | } 17 | mod globals { 18 | use entry; 19 | use ffi; 20 | pub const INSTANCE: ffi::Struct_PPP_Instance_1_1 = ffi::Struct_PPP_Instance_1_1 { 21 | DidCreate: Some(entry::did_create as extern "C" fn(i32, u32, *mut *const i8, *mut *const i8) -> u32), 22 | DidDestroy: Some(entry::did_destroy as extern "C" fn(i32)), 23 | DidChangeView: Some(entry::did_change_view as extern "C" fn(i32, i32)), 24 | DidChangeFocus: Some(entry::did_change_focus as extern "C" fn(i32, u32)), 25 | HandleDocumentLoad: Some(entry::handle_document_load as extern "C" fn(i32, i32) -> u32), 26 | }; 27 | pub static INPUTEVENT: ffi::Struct_PPP_InputEvent_0_1 = ffi::Struct_PPP_InputEvent_0_1 { 28 | HandleInputEvent: Some(entry::handle_input_event as extern "C" fn(i32, i32) -> u32), 29 | }; 30 | pub static GRAPHICS: ffi::Struct_PPP_Graphics3D_1_0 = ffi::Struct_PPP_Graphics3D_1_0 { 31 | Graphics3DContextLost: Some(entry::graphics_context_lost as extern "C" fn(i32)), 32 | }; 33 | } 34 | 35 | #[no_mangle] 36 | #[allow(dead_code)] 37 | #[doc(hidden)] 38 | #[allow(non_snake_case)] 39 | pub extern "C" fn PPP_GetInterface(name: *const c_char) -> *const c_void { 40 | use std::mem::transmute; 41 | use libc::strcmp; 42 | 43 | if name as usize == 0 { return ptr::null(); } 44 | 45 | unsafe { 46 | if strcmp(name, consts::INSTANCE.as_ptr() as *const _) == 0 { 47 | transmute(&globals::INSTANCE) 48 | } else if strcmp(name, consts::INPUTEVENT.as_ptr() as *const _) == 0 { 49 | transmute(&globals::INPUTEVENT) 50 | } else if strcmp(name, consts::GRAPHICS.as_ptr() as *const _) == 0 { 51 | transmute(&globals::GRAPHICS) 52 | } else { 53 | ptr::null() 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/lib/video_decoder.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use std::borrow::Cow; 10 | 11 | use ffi; 12 | 13 | use gles::{self, Context3d, TextureBuffer, TexFormat}; 14 | use ppb::{get_video_decoder_opt, VideoDecoderIf}; 15 | 16 | use super::{GenericResource, Resource, ResourceType, Callback, Code, 17 | CallbackArgs, StorageToArgsMapper}; 18 | 19 | #[derive(Clone, Eq, PartialEq, Hash, Debug)] 20 | pub struct VideoDecoder(GenericResource); 21 | impl Resource for VideoDecoder { 22 | fn unwrap(&self) -> ffi::PP_Resource { self.0.unwrap() } 23 | fn type_of(&self) -> Option { Some(ResourceType::VideoDecoder) } 24 | } 25 | #[doc(hidden)] 26 | impl From for VideoDecoder { 27 | fn from(v: ffi::PP_Resource) -> VideoDecoder { 28 | VideoDecoder(From::from(v)) 29 | } 30 | } 31 | 32 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] 33 | pub enum H264Profile { 34 | BaseLine, 35 | Main, 36 | Extended, 37 | High, 38 | High10, 39 | High422, 40 | High444Predictive, 41 | ScalableBaseLine, 42 | ScalableHigh, 43 | StereoHigh, 44 | MultiViewHigh, 45 | } 46 | #[doc(hidden)] 47 | impl Into for H264Profile { 48 | fn into(self) -> ffi::PP_VideoProfile { 49 | use self::H264Profile::*; 50 | match self { 51 | BaseLine => ffi::PP_VIDEOPROFILE_H264BASELINE, 52 | Main => ffi::PP_VIDEOPROFILE_H264MAIN, 53 | Extended => ffi::PP_VIDEOPROFILE_H264EXTENDED, 54 | High => ffi::PP_VIDEOPROFILE_H264HIGH, 55 | High10 => ffi::PP_VIDEOPROFILE_H264HIGH10PROFILE, 56 | High422 => ffi::PP_VIDEOPROFILE_H264HIGH422PROFILE, 57 | High444Predictive => ffi::PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE, 58 | ScalableBaseLine => ffi::PP_VIDEOPROFILE_H264SCALABLEBASELINE, 59 | ScalableHigh => ffi::PP_VIDEOPROFILE_H264SCALABLEHIGH, 60 | StereoHigh => ffi::PP_VIDEOPROFILE_H264STEREOHIGH, 61 | MultiViewHigh => ffi::PP_VIDEOPROFILE_H264MULTIVIEWHIGH, 62 | } 63 | } 64 | } 65 | 66 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] 67 | pub enum Profile { 68 | VP9, 69 | VP8, 70 | H264(H264Profile), 71 | } 72 | #[doc(hidden)] 73 | impl Into for Profile { 74 | fn into(self) -> ffi::PP_VideoProfile { 75 | use self::Profile::*; 76 | match self { 77 | H264(v) => v.into(), 78 | VP9 => ffi::PP_VIDEOPROFILE_VP9_ANY, 79 | VP8 => ffi::PP_VIDEOPROFILE_VP8_ANY, 80 | } 81 | } 82 | } 83 | 84 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] 85 | pub enum Acceleration { 86 | Hardware { with_fallback: bool }, 87 | Software, 88 | } 89 | #[doc(hidden)] 90 | impl Into for Acceleration { 91 | fn into(self) -> ffi::PP_HardwareAcceleration { 92 | match self { 93 | Acceleration::Hardware { with_fallback: false, } => 94 | ffi::PP_HARDWAREACCELERATION_ONLY, 95 | Acceleration::Hardware { with_fallback: true, } => 96 | ffi::PP_HARDWAREACCELERATION_WITHFALLBACK, 97 | Acceleration::Software => 98 | ffi::PP_HARDWAREACCELERATION_NONE, 99 | } 100 | } 101 | } 102 | impl Default for Acceleration { 103 | fn default() -> Acceleration { Acceleration::Hardware { with_fallback: true } } 104 | } 105 | 106 | pub struct Frame { 107 | pub tag: u32, 108 | texture: TextureBuffer, 109 | texture_target: gles::types::Enum, 110 | pub texture_size: super::Size, 111 | pub visible_rect: super::Rect, 112 | } 113 | impl Frame { 114 | pub fn format(&self) -> TexFormat { TexFormat::Rgba } 115 | } 116 | impl From for Frame { 117 | fn from(raw: ffi::Struct_PP_VideoPicture) -> Frame { 118 | Frame { 119 | tag: raw.decode_id, 120 | texture: From::from(raw.texture_id), 121 | texture_target: From::from(raw.texture_target), 122 | texture_size: From::from(raw.texture_size), 123 | visible_rect: From::from(raw.visible_rect), 124 | } 125 | } 126 | } 127 | impl Into for Frame { 128 | fn into(self) -> ffi::Struct_PP_VideoPicture { 129 | use gles::traits::Buffer; 130 | ffi::Struct_PP_VideoPicture { 131 | decode_id: self.tag, 132 | texture_id: self.texture.unwrap(), 133 | texture_target: self.texture_target, 134 | texture_size: self.texture_size.into(), 135 | visible_rect: self.visible_rect.into(), 136 | } 137 | } 138 | } 139 | impl gles::traits::BindableBuffer for Frame { 140 | type Target = gles::BoundTexBuffer; 141 | fn bind(&self, ctxt: &Context3d) -> gles::BoundTexBuffer { 142 | use gles::traits::BindableTargetBuffer; 143 | self.texture.bind(ctxt, self.texture_target) 144 | } 145 | } 146 | 147 | impl VideoDecoder { 148 | pub fn initialize(&self, g3d: Context3d, profile: Profile, 149 | accel: Acceleration, callback: CallbackArgs) -> Code<()> 150 | where F: FnOnce(Code<()>), 151 | { 152 | get_video_decoder_opt() 153 | .map(move |i| { 154 | let cc = callback.to_ffi_callback((), Default::default()); 155 | let code = i.initialize(self.unwrap(), g3d.unwrap(), profile.into(), 156 | accel.into(), cc.cc()); 157 | cc.drop_with_code(code) 158 | }) 159 | .unwrap_or(Code::NoInterface) 160 | } 161 | /// PPAPI allocates it's own copy of the data before returning. 162 | pub fn decode<'a, F>(&self, decode_tag: u32, data: Cow<'a, [u8]>, 163 | callback: CallbackArgs) -> Code<()> 164 | where F: FnOnce(Code<()>) 165 | { 166 | get_video_decoder_opt() 167 | .map(move |i| { 168 | let cc = callback.to_ffi_callback((), Default::default()); 169 | let code = i.decode(self.unwrap(), decode_tag, 170 | data.as_ref().len(), data.as_ref().as_ptr(), cc.cc()); 171 | cc.drop_with_code(code) 172 | }) 173 | .unwrap_or(Code::NoInterface) 174 | } 175 | pub fn flush(&self, callback: CallbackArgs) -> Code<()> 176 | where F: FnOnce(Code<()>) 177 | { 178 | get_video_decoder_opt() 179 | .map(move |i| { 180 | let cc = callback.to_ffi_callback((), Default::default()); 181 | let code = i.flush(self.unwrap(), cc.cc()); 182 | cc.drop_with_code(code) 183 | }) 184 | .unwrap_or(Code::NoInterface) 185 | } 186 | pub fn reset(&self, callback: CallbackArgs) -> Code<()> 187 | where F: FnOnce(Code<()>) 188 | { 189 | get_video_decoder_opt() 190 | .map(move |i| { 191 | let cc = callback.to_ffi_callback((), Default::default()); 192 | let code = i.reset(self.unwrap(), cc.cc()); 193 | cc.drop_with_code(code) 194 | }) 195 | .unwrap_or(Code::NoInterface) 196 | } 197 | pub fn get_picture(&self, callback: CallbackArgs) -> 198 | Code where F: FnOnce(Code) 199 | { 200 | impl super::InPlaceInit for ffi::Struct_PP_VideoPicture { } 201 | fn arg_map(raw: ffi::Struct_PP_VideoPicture, _status: Code) -> Frame { 202 | From::from(raw) 203 | } 204 | get_video_decoder_opt() 205 | .map(move |i| { 206 | let raw: ffi::Struct_PP_VideoPicture = Default::default(); 207 | let mapper = StorageToArgsMapper(arg_map); 208 | let cc = callback.to_ffi_callback(raw, mapper); 209 | let code = i.get_picture(self.unwrap(), cc.raw_args(), cc.cc()); 210 | cc.drop_with_code(code) 211 | }) 212 | .unwrap_or(Code::NoInterface) 213 | } 214 | pub fn recycle(&self, frame: Frame) { 215 | get_video_decoder_opt() 216 | .map(move |i| { 217 | let ffi: ffi::Struct_PP_VideoPicture = 218 | frame.into(); 219 | i.recycle_picture(self.unwrap(), &ffi) 220 | }); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/lib/video_frame.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | use ffi; 10 | use ppb::{get_video_frame, VideoFrameIf, ResourceInterface}; 11 | 12 | use {TimeDelta, Resource, Size}; 13 | 14 | #[derive(Hash, Eq, PartialEq, Debug)] pub struct VideoFrame(ffi::PP_Resource); 15 | impl_clone_drop_for!(VideoFrame); 16 | impl_resource_for!(VideoFrame, ResourceType::VideoFrame); 17 | 18 | #[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] 19 | pub enum Format { 20 | Unknown, 21 | YV12, 22 | I420, 23 | BGRA, 24 | } 25 | 26 | #[doc(hidden)] 27 | impl From for Format { 28 | fn from(v: ffi::PP_VideoFrame_Format) -> Format { 29 | match v { 30 | ffi::PP_VIDEOFRAME_FORMAT_UNKNOWN => Format::Unknown, 31 | ffi::PP_VIDEOFRAME_FORMAT_YV12 => Format::YV12, 32 | ffi::PP_VIDEOFRAME_FORMAT_I420 => Format::I420, 33 | ffi::PP_VIDEOFRAME_FORMAT_BGRA => Format::BGRA, 34 | _ => unreachable!(), 35 | } 36 | } 37 | } 38 | impl Format { 39 | #[doc(hidden)] 40 | pub fn to_ffi(self) -> ffi::PP_VideoFrame_Format { 41 | match self { 42 | Format::YV12 => ffi::PP_VIDEOFRAME_FORMAT_YV12, 43 | Format::I420 => ffi::PP_VIDEOFRAME_FORMAT_I420, 44 | Format::BGRA => ffi::PP_VIDEOFRAME_FORMAT_BGRA, 45 | Format::Unknown => ffi::PP_VIDEOFRAME_FORMAT_UNKNOWN, 46 | } 47 | } 48 | } 49 | #[doc(hidden)] 50 | impl From for VideoFrame { 51 | fn from(v: ffi::PP_Resource) -> VideoFrame { 52 | debug_assert!(get_video_frame().is(v)); 53 | VideoFrame(v) 54 | } 55 | } 56 | 57 | impl VideoFrame { 58 | pub fn get_timestamp(&self) -> TimeDelta { 59 | get_video_frame() 60 | .get_timestamp(self.unwrap()) 61 | } 62 | pub fn set_timestamp(&self, ts: TimeDelta) { 63 | get_video_frame() 64 | .set_timestamp(self.unwrap(), ts) 65 | } 66 | pub fn format(&self) -> Format { 67 | let f = get_video_frame() 68 | .get_format(self.unwrap()); 69 | From::from(f) 70 | } 71 | pub fn size(&self) -> Option { 72 | get_video_frame() 73 | .get_size(self.unwrap()) 74 | .map(|s| From::from(s) ) 75 | } 76 | pub fn len(&self) -> usize { 77 | get_video_frame() 78 | .get_data_buffer_size(self.unwrap()) 79 | } 80 | } 81 | impl AsRef<[u8]> for VideoFrame { 82 | fn as_ref(&self) -> &[u8] { 83 | use std::slice::from_raw_parts; 84 | let f = get_video_frame(); 85 | 86 | let len = f.get_data_buffer_size(self.unwrap()); 87 | let data = f.get_data_buffer(self.unwrap()); 88 | 89 | unsafe { from_raw_parts(data, len) } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/libhelper/builtin_defines.hpp: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 1 2 | #define _ILP32 1 3 | #define __ATOMIC_ACQUIRE 2 4 | #define __ATOMIC_ACQ_REL 4 5 | #define __ATOMIC_CONSUME 1 6 | #define __ATOMIC_RELAXED 0 7 | #define __ATOMIC_RELEASE 3 8 | #define __ATOMIC_SEQ_CST 5 9 | #define __BIGGEST_ALIGNMENT__ 8 10 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ 11 | #define __CHAR16_TYPE__ unsigned short 12 | #define __CHAR32_TYPE__ unsigned int 13 | #define __CHAR_BIT__ 8 14 | #define __CONSTANT_CFSTRINGS__ 1 15 | #define __DBL_DECIMAL_DIG__ 17 16 | #define __DBL_DENORM_MIN__ 4.9406564584124654e-324 17 | #define __DBL_DIG__ 15 18 | #define __DBL_EPSILON__ 2.2204460492503131e-16 19 | #define __DBL_HAS_DENORM__ 1 20 | #define __DBL_HAS_INFINITY__ 1 21 | #define __DBL_HAS_QUIET_NAN__ 1 22 | #define __DBL_MANT_DIG__ 53 23 | #define __DBL_MAX_10_EXP__ 308 24 | #define __DBL_MAX_EXP__ 1024 25 | #define __DBL_MAX__ 1.7976931348623157e+308 26 | #define __DBL_MIN_10_EXP__ (-307) 27 | #define __DBL_MIN_EXP__ (-1021) 28 | #define __DBL_MIN__ 2.2250738585072014e-308 29 | #define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__ 30 | #define __DEPRECATED 1 31 | #define __ELF__ 1 32 | #define __EXCEPTIONS 1 33 | #define __FINITE_MATH_ONLY__ 0 34 | #define __FLT_DECIMAL_DIG__ 9 35 | #define __FLT_DENORM_MIN__ 1.40129846e-45F 36 | #define __FLT_DIG__ 6 37 | #define __FLT_EPSILON__ 1.19209290e-7F 38 | #define __FLT_EVAL_METHOD__ 0 39 | #define __FLT_HAS_DENORM__ 1 40 | #define __FLT_HAS_INFINITY__ 1 41 | #define __FLT_HAS_QUIET_NAN__ 1 42 | #define __FLT_MANT_DIG__ 24 43 | #define __FLT_MAX_10_EXP__ 38 44 | #define __FLT_MAX_EXP__ 128 45 | #define __FLT_MAX__ 3.40282347e+38F 46 | #define __FLT_MIN_10_EXP__ (-37) 47 | #define __FLT_MIN_EXP__ (-125) 48 | #define __FLT_MIN__ 1.17549435e-38F 49 | #define __FLT_RADIX__ 2 50 | #define __GCC_ATOMIC_BOOL_LOCK_FREE 1 51 | #define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 1 52 | #define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 1 53 | #define __GCC_ATOMIC_CHAR_LOCK_FREE 1 54 | #define __GCC_ATOMIC_INT_LOCK_FREE 1 55 | #define __GCC_ATOMIC_LLONG_LOCK_FREE 1 56 | #define __GCC_ATOMIC_LONG_LOCK_FREE 1 57 | #define __GCC_ATOMIC_POINTER_LOCK_FREE 1 58 | #define __GCC_ATOMIC_SHORT_LOCK_FREE 1 59 | #define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 60 | #define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 1 61 | #define __GNUC_GNU_INLINE__ 1 62 | #define __GNUC_MINOR__ 2 63 | #define __GNUC_PATCHLEVEL__ 1 64 | #define __GNUC__ 4 65 | #define __GNUG__ 4 66 | #define __GXX_ABI_VERSION 1002 67 | #define __GXX_EXPERIMENTAL_CXX0X__ 1 68 | #define __GXX_RTTI 1 69 | #define __GXX_WEAK__ 1 70 | #define __ILP32__ 1 71 | #define __INT16_C_SUFFIX__ 72 | #define __INT16_FMTd__ "hd" 73 | #define __INT16_FMTi__ "hi" 74 | #define __INT16_MAX__ 32767 75 | #define __INT16_TYPE__ short 76 | #define __INT32_C_SUFFIX__ 77 | #define __INT32_FMTd__ "d" 78 | #define __INT32_FMTi__ "i" 79 | #define __INT32_MAX__ 2147483647 80 | #define __INT32_TYPE__ int 81 | #define __INT64_C_SUFFIX__ LL 82 | #define __INT64_FMTd__ "lld" 83 | #define __INT64_FMTi__ "lli" 84 | #define __INT64_MAX__ 9223372036854775807LL 85 | #define __INT64_TYPE__ long long int 86 | #define __INT8_C_SUFFIX__ 87 | #define __INT8_FMTd__ "hhd" 88 | #define __INT8_FMTi__ "hhi" 89 | #define __INT8_MAX__ 127 90 | #define __INT8_TYPE__ signed char 91 | #define __INTMAX_C_SUFFIX__ LL 92 | #define __INTMAX_FMTd__ "lld" 93 | #define __INTMAX_FMTi__ "lli" 94 | #define __INTMAX_MAX__ 9223372036854775807LL 95 | #define __INTMAX_TYPE__ long long int 96 | #define __INTMAX_WIDTH__ 64 97 | #define __INTPTR_FMTd__ "d" 98 | #define __INTPTR_FMTi__ "i" 99 | #define __INTPTR_MAX__ 2147483647 100 | #define __INTPTR_TYPE__ int 101 | #define __INTPTR_WIDTH__ 32 102 | #define __INT_FAST16_FMTd__ "hd" 103 | #define __INT_FAST16_FMTi__ "hi" 104 | #define __INT_FAST16_MAX__ 32767 105 | #define __INT_FAST16_TYPE__ short 106 | #define __INT_FAST32_FMTd__ "d" 107 | #define __INT_FAST32_FMTi__ "i" 108 | #define __INT_FAST32_MAX__ 2147483647 109 | #define __INT_FAST32_TYPE__ int 110 | #define __INT_FAST64_FMTd__ "lld" 111 | #define __INT_FAST64_FMTi__ "lli" 112 | #define __INT_FAST64_MAX__ 9223372036854775807LL 113 | #define __INT_FAST64_TYPE__ long long int 114 | #define __INT_FAST8_FMTd__ "hhd" 115 | #define __INT_FAST8_FMTi__ "hhi" 116 | #define __INT_FAST8_MAX__ 127 117 | #define __INT_FAST8_TYPE__ signed char 118 | #define __INT_LEAST16_FMTd__ "hd" 119 | #define __INT_LEAST16_FMTi__ "hi" 120 | #define __INT_LEAST16_MAX__ 32767 121 | #define __INT_LEAST16_TYPE__ short 122 | #define __INT_LEAST32_FMTd__ "d" 123 | #define __INT_LEAST32_FMTi__ "i" 124 | #define __INT_LEAST32_MAX__ 2147483647 125 | #define __INT_LEAST32_TYPE__ int 126 | #define __INT_LEAST64_FMTd__ "lld" 127 | #define __INT_LEAST64_FMTi__ "lli" 128 | #define __INT_LEAST64_MAX__ 9223372036854775807LL 129 | #define __INT_LEAST64_TYPE__ long long int 130 | #define __INT_LEAST8_FMTd__ "hhd" 131 | #define __INT_LEAST8_FMTi__ "hhi" 132 | #define __INT_LEAST8_MAX__ 127 133 | #define __INT_LEAST8_TYPE__ signed char 134 | #define __INT_MAX__ 2147483647 135 | #define __LDBL_DECIMAL_DIG__ 17 136 | #define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L 137 | #define __LDBL_DIG__ 15 138 | #define __LDBL_EPSILON__ 2.2204460492503131e-16L 139 | #define __LDBL_HAS_DENORM__ 1 140 | #define __LDBL_HAS_INFINITY__ 1 141 | #define __LDBL_HAS_QUIET_NAN__ 1 142 | #define __LDBL_MANT_DIG__ 53 143 | #define __LDBL_MAX_10_EXP__ 308 144 | #define __LDBL_MAX_EXP__ 1024 145 | #define __LDBL_MAX__ 1.7976931348623157e+308L 146 | #define __LDBL_MIN_10_EXP__ (-307) 147 | #define __LDBL_MIN_EXP__ (-1021) 148 | #define __LDBL_MIN__ 2.2250738585072014e-308L 149 | #define __LITTLE_ENDIAN__ 1 150 | #define __LONG_LONG_MAX__ 9223372036854775807LL 151 | #define __LONG_MAX__ 2147483647L 152 | #define __NO_INLINE__ 1 153 | #define __ORDER_BIG_ENDIAN__ 4321 154 | #define __ORDER_LITTLE_ENDIAN__ 1234 155 | #define __ORDER_PDP_ENDIAN__ 3412 156 | #define __POINTER_WIDTH__ 32 157 | #define __PRAGMA_REDEFINE_EXTNAME 1 158 | #define __PTRDIFF_FMTd__ "d" 159 | #define __PTRDIFF_FMTi__ "i" 160 | #define __PTRDIFF_MAX__ 2147483647 161 | #define __PTRDIFF_TYPE__ int 162 | #define __PTRDIFF_WIDTH__ 32 163 | #define __SCHAR_MAX__ 127 164 | #define __SHRT_MAX__ 32767 165 | #define __SIG_ATOMIC_MAX__ 2147483647 166 | #define __SIG_ATOMIC_WIDTH__ 32 167 | #define __SIZEOF_DOUBLE__ 8 168 | #define __SIZEOF_FLOAT__ 4 169 | #define __SIZEOF_INT__ 4 170 | #define __SIZEOF_LONG_DOUBLE__ 8 171 | #define __SIZEOF_LONG_LONG__ 8 172 | #define __SIZEOF_LONG__ 4 173 | #define __SIZEOF_POINTER__ 4 174 | #define __SIZEOF_PTRDIFF_T__ 4 175 | #define __SIZEOF_SHORT__ 2 176 | #define __SIZEOF_SIZE_T__ 4 177 | #define __SIZEOF_WCHAR_T__ 4 178 | #define __SIZEOF_WINT_T__ 4 179 | #define __SIZE_FMTX__ "X" 180 | #define __SIZE_FMTo__ "o" 181 | #define __SIZE_FMTu__ "u" 182 | #define __SIZE_FMTx__ "x" 183 | #define __SIZE_MAX__ 4294967295U 184 | #define __SIZE_TYPE__ unsigned int 185 | #define __SIZE_WIDTH__ 32 186 | #define __STDC_HOSTED__ 1 187 | #define __STDC_UTF_16__ 1 188 | #define __STDC_UTF_32__ 1 189 | #define __STDC__ 1 190 | #define __STRICT_ANSI__ 1 191 | #define __UINT16_C_SUFFIX__ 192 | #define __UINT16_FMTX__ "hX" 193 | #define __UINT16_FMTo__ "ho" 194 | #define __UINT16_FMTu__ "hu" 195 | #define __UINT16_FMTx__ "hx" 196 | #define __UINT16_MAX__ 65535 197 | #define __UINT16_TYPE__ unsigned short 198 | #define __UINT32_C_SUFFIX__ U 199 | #define __UINT32_FMTX__ "X" 200 | #define __UINT32_FMTo__ "o" 201 | #define __UINT32_FMTu__ "u" 202 | #define __UINT32_FMTx__ "x" 203 | #define __UINT32_MAX__ 4294967295U 204 | #define __UINT32_TYPE__ unsigned int 205 | #define __UINT64_C_SUFFIX__ ULL 206 | #define __UINT64_FMTX__ "llX" 207 | #define __UINT64_FMTo__ "llo" 208 | #define __UINT64_FMTu__ "llu" 209 | #define __UINT64_FMTx__ "llx" 210 | #define __UINT64_MAX__ 18446744073709551615ULL 211 | #define __UINT64_TYPE__ long long unsigned int 212 | #define __UINT8_C_SUFFIX__ 213 | #define __UINT8_FMTX__ "hhX" 214 | #define __UINT8_FMTo__ "hho" 215 | #define __UINT8_FMTu__ "hhu" 216 | #define __UINT8_FMTx__ "hhx" 217 | #define __UINT8_MAX__ 255 218 | #define __UINT8_TYPE__ unsigned char 219 | #define __UINTMAX_C_SUFFIX__ ULL 220 | #define __UINTMAX_FMTX__ "llX" 221 | #define __UINTMAX_FMTo__ "llo" 222 | #define __UINTMAX_FMTu__ "llu" 223 | #define __UINTMAX_FMTx__ "llx" 224 | #define __UINTMAX_MAX__ 18446744073709551615ULL 225 | #define __UINTMAX_TYPE__ long long unsigned int 226 | #define __UINTMAX_WIDTH__ 64 227 | #define __UINTPTR_FMTX__ "X" 228 | #define __UINTPTR_FMTo__ "o" 229 | #define __UINTPTR_FMTu__ "u" 230 | #define __UINTPTR_FMTx__ "x" 231 | #define __UINTPTR_MAX__ 4294967295U 232 | #define __UINTPTR_TYPE__ unsigned int 233 | #define __UINTPTR_WIDTH__ 32 234 | #define __UINT_FAST16_FMTX__ "hX" 235 | #define __UINT_FAST16_FMTo__ "ho" 236 | #define __UINT_FAST16_FMTu__ "hu" 237 | #define __UINT_FAST16_FMTx__ "hx" 238 | #define __UINT_FAST16_MAX__ 65535 239 | #define __UINT_FAST16_TYPE__ unsigned short 240 | #define __UINT_FAST32_FMTX__ "X" 241 | #define __UINT_FAST32_FMTo__ "o" 242 | #define __UINT_FAST32_FMTu__ "u" 243 | #define __UINT_FAST32_FMTx__ "x" 244 | #define __UINT_FAST32_MAX__ 4294967295U 245 | #define __UINT_FAST32_TYPE__ unsigned int 246 | #define __UINT_FAST64_FMTX__ "llX" 247 | #define __UINT_FAST64_FMTo__ "llo" 248 | #define __UINT_FAST64_FMTu__ "llu" 249 | #define __UINT_FAST64_FMTx__ "llx" 250 | #define __UINT_FAST64_MAX__ 18446744073709551615ULL 251 | #define __UINT_FAST64_TYPE__ long long unsigned int 252 | #define __UINT_FAST8_FMTX__ "hhX" 253 | #define __UINT_FAST8_FMTo__ "hho" 254 | #define __UINT_FAST8_FMTu__ "hhu" 255 | #define __UINT_FAST8_FMTx__ "hhx" 256 | #define __UINT_FAST8_MAX__ 255 257 | #define __UINT_FAST8_TYPE__ unsigned char 258 | #define __UINT_LEAST16_FMTX__ "hX" 259 | #define __UINT_LEAST16_FMTo__ "ho" 260 | #define __UINT_LEAST16_FMTu__ "hu" 261 | #define __UINT_LEAST16_FMTx__ "hx" 262 | #define __UINT_LEAST16_MAX__ 65535 263 | #define __UINT_LEAST16_TYPE__ unsigned short 264 | #define __UINT_LEAST32_FMTX__ "X" 265 | #define __UINT_LEAST32_FMTo__ "o" 266 | #define __UINT_LEAST32_FMTu__ "u" 267 | #define __UINT_LEAST32_FMTx__ "x" 268 | #define __UINT_LEAST32_MAX__ 4294967295U 269 | #define __UINT_LEAST32_TYPE__ unsigned int 270 | #define __UINT_LEAST64_FMTX__ "llX" 271 | #define __UINT_LEAST64_FMTo__ "llo" 272 | #define __UINT_LEAST64_FMTu__ "llu" 273 | #define __UINT_LEAST64_FMTx__ "llx" 274 | #define __UINT_LEAST64_MAX__ 18446744073709551615ULL 275 | #define __UINT_LEAST64_TYPE__ long long unsigned int 276 | #define __UINT_LEAST8_FMTX__ "hhX" 277 | #define __UINT_LEAST8_FMTo__ "hho" 278 | #define __UINT_LEAST8_FMTu__ "hhu" 279 | #define __UINT_LEAST8_FMTx__ "hhx" 280 | #define __UINT_LEAST8_MAX__ 255 281 | #define __UINT_LEAST8_TYPE__ unsigned char 282 | #define __USER_LABEL_PREFIX__ 283 | #define __VERSION__ "4.2.1 Compatible Clang 3.7.0 (https://chromium.googlesource.com/a/native_client/pnacl-clang.git 0895c9a2aedd33371c6cb8703d5fe8bb4493169b) (https://chromium.googlesource.com/a/native_client/pnacl-llvm.git 58b8aae0d0105ffa0042d6e44f50f06f618cb754)" 284 | #define __WCHAR_MAX__ 2147483647 285 | #define __WCHAR_TYPE__ int 286 | #define __WCHAR_WIDTH__ 32 287 | #define __WINT_TYPE__ int 288 | #define __WINT_WIDTH__ 32 289 | #define __clang__ 1 290 | #define __clang_major__ 3 291 | #define __clang_minor__ 7 292 | #define __clang_patchlevel__ 0 293 | #define __clang_version__ "3.7.0 (https://chromium.googlesource.com/a/native_client/pnacl-clang.git 0895c9a2aedd33371c6cb8703d5fe8bb4493169b) (https://chromium.googlesource.com/a/native_client/pnacl-llvm.git 58b8aae0d0105ffa0042d6e44f50f06f618cb754)" 294 | #define __cplusplus 201103L 295 | #define __cpp_alias_templates 200704 296 | #define __cpp_attributes 200809 297 | #define __cpp_constexpr 200704 298 | #define __cpp_decltype 200707 299 | #define __cpp_delegating_constructors 200604 300 | #define __cpp_exceptions 199711 301 | #define __cpp_inheriting_constructors 200802 302 | #define __cpp_initializer_lists 200806 303 | #define __cpp_lambdas 200907 304 | #define __cpp_nsdmi 200809 305 | #define __cpp_range_based_for 200907 306 | #define __cpp_raw_strings 200710 307 | #define __cpp_ref_qualifiers 200710 308 | #define __cpp_rtti 199711 309 | #define __cpp_rvalue_references 200610 310 | #define __cpp_static_assert 200410 311 | #define __cpp_unicode_characters 200704 312 | #define __cpp_unicode_literals 200710 313 | #define __cpp_user_defined_literals 200809 314 | #define __cpp_variadic_templates 200704 315 | #define __le32__ 1 316 | #define __llvm__ 1 317 | #define __native_client__ 1 318 | #define __pnacl__ 1 319 | #define __private_extern__ extern 320 | #define __unix 1 321 | #define __unix__ 1 322 | -------------------------------------------------------------------------------- /src/libhelper/helper.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | /// This file is here to handle things that the ppapi has either inlined or 10 | /// delegated to macros. 11 | 12 | #ifdef __BINDGEN__ 13 | #include "builtin_defines.hpp" // For bindgen. 14 | #endif 15 | 16 | #include "ppapi.hpp" 17 | #include "stdio.h" 18 | 19 | #include "ppapi/c/pp_completion_callback.h" 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | PP_CompletionCallback make_completion_callback(PP_CompletionCallback_Func func, 26 | void* user_data) { 27 | return PP_MakeCompletionCallback(func, user_data); 28 | } 29 | void run_completion_callback(PP_CompletionCallback func, const int32_t code) { 30 | PP_RunCompletionCallback(&func, code); 31 | } 32 | PP_CompletionCallback block_until_complete() { 33 | return PP_BlockUntilComplete(); 34 | } 35 | 36 | const PP_Var make_undefined_var() { 37 | return PP_MakeUndefined(); 38 | } 39 | const PP_Var make_null_var() { 40 | return PP_MakeNull(); 41 | } 42 | 43 | const PP_Var bool_to_var(const bool value) { 44 | return PP_MakeBool(static_cast(value)); 45 | } 46 | const bool bool_from_var(const PP_Var v) { 47 | return v.value.as_bool; 48 | } 49 | 50 | const PP_Var i32_to_var(const int32_t value) { 51 | return PP_MakeInt32(value); 52 | } 53 | const int32_t i32_from_var(const PP_Var v) { 54 | return v.value.as_int; 55 | } 56 | 57 | const PP_Var f64_to_var(const double value) { 58 | return PP_MakeDouble(value); 59 | } 60 | const double f64_from_var(const PP_Var v) { 61 | return v.value.as_double; 62 | } 63 | 64 | const PP_Var string_id_to_var(const int64_t id) { 65 | PP_VarValue vv; 66 | vv.as_id = id; 67 | const PP_Var v = { 68 | PP_VARTYPE_STRING, 69 | 0, 70 | vv, 71 | }; 72 | return v; 73 | } 74 | const PP_Var object_id_to_var(const int64_t id) { 75 | PP_VarValue vv; 76 | vv.as_id = id; 77 | const PP_Var v = { 78 | PP_VARTYPE_OBJECT, 79 | 0, 80 | vv, 81 | }; 82 | return v; 83 | } 84 | const PP_Var array_id_to_var(const int64_t id) { 85 | PP_VarValue vv; 86 | vv.as_id = id; 87 | const PP_Var v = { 88 | PP_VARTYPE_ARRAY, 89 | 0, 90 | vv, 91 | }; 92 | return v; 93 | } 94 | const PP_Var dictionary_id_to_var(const int64_t id) { 95 | PP_VarValue vv; 96 | vv.as_id = id; 97 | const PP_Var v = { 98 | PP_VARTYPE_DICTIONARY, 99 | 0, 100 | vv, 101 | }; 102 | return v; 103 | } 104 | const PP_Var array_buffer_id_to_var(const int64_t id) { 105 | PP_VarValue vv; 106 | vv.as_id = id; 107 | const PP_Var v = { 108 | PP_VARTYPE_ARRAY_BUFFER, 109 | 0, 110 | vv, 111 | }; 112 | return v; 113 | } 114 | const PP_Var resource_id_to_var(const int64_t id) { 115 | PP_VarValue vv; 116 | vv.as_id = id; 117 | const PP_Var v = { 118 | PP_VARTYPE_RESOURCE, 119 | 0, 120 | vv, 121 | }; 122 | } 123 | const int64_t id_from_var(const PP_Var v) { 124 | return v.value.as_id; 125 | } 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | -------------------------------------------------------------------------------- /src/libhelper/ppapi.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // for now, we just include every file one might need for one very large mod. 10 | // TODO(richard): separate mods for each header 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #if PPAPI_RELEASE >= 34 19 | #include 20 | #endif 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #if PPAPI_RELEASE >= 34 36 | #include 37 | #include 38 | #endif 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #if PPAPI_RELEASE >= 44 59 | #include 60 | #include 61 | #endif 62 | #if PPAPI_RELEASE >= 34 63 | #include 64 | #endif 65 | #include 66 | #include 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | 86 | #include 87 | #include 88 | #include 89 | #if PPAPI_RELEASE >= 39 90 | #include 91 | #endif 92 | #include 93 | #include 94 | #if PPAPI_RELEASE <= 34 95 | #include 96 | #include 97 | #include 98 | #include 99 | #endif 100 | #include 101 | #if PPAPI_RELEASE <= 34 102 | #include 103 | #endif 104 | #include 105 | #if PPAPI_RELEASE <= 34 106 | #include 107 | #endif 108 | #include 109 | #if PPAPI_RELEASE <= 34 110 | #include 111 | #include 112 | #include 113 | #endif 114 | #if PPAPI_RELEASE < 34 115 | #include 116 | #endif 117 | #include 118 | #include 119 | #include 120 | #if PPAPI_RELEASE < 34 121 | #include 122 | #endif 123 | #if PPAPI_RELEASE <= 34 124 | #include 125 | #include 126 | #endif 127 | #include 128 | #include 129 | #if PPAPI_RELEASE <= 34 130 | #include 131 | #include 132 | #include 133 | #endif 134 | #include 135 | #if PPAPI_RELEASE <= 34 136 | #include 137 | #endif 138 | #include 139 | #if PPAPI_RELEASE <= 34 140 | #include 141 | #endif 142 | #include 143 | #include 144 | #include 145 | #if PPAPI_RELEASE <= 34 146 | #include 147 | #include 148 | #include 149 | #endif 150 | #if PPAPI_RELEASE <= 34 151 | #include 152 | #include 153 | #include 154 | #endif 155 | #if PPAPI_RELEASE <= 34 156 | #include 157 | #include 158 | #endif 159 | 160 | #include 161 | #include // for mount. 162 | 163 | // helpers: 164 | extern "C" { 165 | PP_CompletionCallback make_completion_callback(PP_CompletionCallback_Func func, 166 | void* user_data); 167 | void run_completion_callback(PP_CompletionCallback func, const int32_t code); 168 | PP_CompletionCallback block_until_complete(); 169 | 170 | const PP_Var make_undefined_var(); 171 | const PP_Var make_null_var(); 172 | 173 | const PP_Var bool_to_var(const bool value); 174 | const bool bool_from_var(const PP_Var v); 175 | 176 | const PP_Var i32_to_var(const int32_t value); 177 | const int32_t i32_from_var(const PP_Var v); 178 | 179 | const PP_Var f64_to_var(const double value); 180 | const double f64_from_var(const PP_Var v); 181 | 182 | const PP_Var string_id_to_var(const int64_t id); 183 | const PP_Var object_id_to_var(const int64_t id); 184 | const PP_Var array_id_to_var(const int64_t id); 185 | const PP_Var dictionary_id_to_var(const int64_t id); 186 | const PP_Var array_buffer_id_to_var(const int64_t id); 187 | const PP_Var resource_id_to_var(const int64_t id); 188 | const int64_t id_from_var(const PP_Var v); 189 | } 190 | -------------------------------------------------------------------------------- /src/ppapi-tester/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ppapi-tester" 3 | version = "0.0.1" 4 | authors = [ "Richard Diamond " ] 5 | repository = "https://github.com/DiamondLovesYou/rust-ppapi.git" 6 | license = "MPL-2.0" 7 | description = "Compiler plugin to run integration tests in Google Chrome, where Pepper is available." 8 | 9 | [lib] 10 | name = "ppapi_tester" 11 | path = "lib.rs" 12 | plugin = true 13 | -------------------------------------------------------------------------------- /src/ppapi-tester/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | hello_tutorial 13 | 14 | 69 | 70 | 71 |

72 | 85 |

86 | 97 |
98 |

99 | 100 |

Status NO-STATUS

101 | 102 | 103 | -------------------------------------------------------------------------------- /src/ppapi-tester/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | 10 | //! Provides the ```pnacl_test! {}``` macro. 11 | //! Usage: 12 | //! ```rust 13 | //! #[ppapi_test] 14 | //! fn test_name(instance: ppapi::Instance, args: HashMap) { 15 | //! // Put the test here. 16 | //! } 17 | //! ``` 18 | //! 19 | //! In the future I plan allowing #[ppapi_test] on modules so callbacks can be 20 | //! tested as well. 21 | //! 22 | 23 | #![crate_name = "ppapi-tester"] 24 | #![crate_type = "dylib"] 25 | #![feature(plugin_registrar, quote)] 26 | 27 | #![allow(unstable)] 28 | 29 | extern crate rustc; 30 | extern crate syntax; 31 | 32 | use syntax::ext::base::{SyntaxExtension, ExtCtxt}; 33 | use syntax::ext::build::AstBuilder; 34 | use syntax::ext::quote::rt::{ToSource, ToTokens}; 35 | use syntax::parse::token::{intern, intern_and_get_ident}; 36 | use syntax::{ast, codemap}; 37 | use syntax::codemap::Span; 38 | use syntax::ptr::P; 39 | use rustc::plugin::Registry; 40 | 41 | #[plugin_registrar] 42 | pub fn plugin_registrar(reg: &mut Registry) { 43 | let ppapi_test_expander = SyntaxExtension::Modifier(Box::new(expand_test)); 44 | let ppapi_test = intern("ppapi_test"); 45 | reg.register_syntax_extension(ppapi_test, ppapi_test_expander); 46 | } 47 | 48 | const HTML: &'static str = include_str!("index.html"); 49 | const MANIFEST: &'static str = include_str!("manifest.nmf"); 50 | 51 | fn expand_test(ecx: &mut ExtCtxt, 52 | sp: Span, 53 | _meta_item: &ast::MetaItem, 54 | item: P) -> P { 55 | // we replace the input function with a function that instead compiles the 56 | // pretty printed original to a pexe and invokes chrome to simulate being 57 | // embedding in a website. 58 | 59 | #[derive(PartialEq)] 60 | enum HasTestSignature { 61 | Yes, 62 | No, 63 | NotEvenAFunction, 64 | } 65 | 66 | fn has_correct_signature(i: &ast::Item) -> HasTestSignature { 67 | match &i.node { 68 | &ast::ItemFn(ref decl, _, _, ref generics, _) => { 69 | let no_output = match decl.output { 70 | ast::DefaultReturn(..) => true, 71 | _ => false 72 | }; 73 | if decl.inputs.len() == 2 74 | && no_output 75 | && !generics.is_parameterized() { 76 | HasTestSignature::Yes 77 | } else { 78 | HasTestSignature::No 79 | } 80 | } 81 | _ => HasTestSignature::NotEvenAFunction, 82 | } 83 | } 84 | 85 | // first check that the annotated item is, in fact, a function: 86 | match has_correct_signature(&*item) { 87 | HasTestSignature::Yes => { }, 88 | HasTestSignature::No => { 89 | ecx.span_err(sp, "function must be typed: fn(instance: \ 90 | ppapi::Instance, args: HashMap) -> ()"); 91 | return item; 92 | }, 93 | HasTestSignature::NotEvenAFunction => { 94 | ecx.span_err(sp, "must be a function: fn(instance: ppapi::Instance, \ 95 | args: HashMap) -> ()"); 96 | return item; 97 | }, 98 | } 99 | 100 | let test_name = item.ident; 101 | let wrapper = 102 | quote_item!( 103 | ecx, 104 | #![no_main] 105 | extern crate ppapi; 106 | 107 | use std::collections::HashMap; 108 | 109 | struct ResultMessager(ppapi::Messaging); 110 | impl Drop for ResultMessager { 111 | fn drop(&mut self) { 112 | use std::rt::unwind::panicking; 113 | let &mut ResultMessager(msg) = self; 114 | 115 | if panicking() { 116 | msg.post_message("failure"); 117 | } else { 118 | msg.post_message("success"); 119 | } 120 | } 121 | } 122 | 123 | $item 124 | 125 | #[no_mangle] pub extern fn ppapi_instance_created(instance: ppapi::Instance, 126 | args: HashMap) { 127 | use ppapi::MessageLoop; 128 | assert!(MessageLoop::post_to_self(move |: _| { 129 | let result = ResultMessager(instance.messaging()); 130 | $test_name(instance.clone(), args.clone()); 131 | }).is_ok()); 132 | assert!(MessageLoop::current().unwrap().shutdown().is_ok()); 133 | } 134 | #[no_mangle] pub extern fn ppapi_instance_destroyed() { } 135 | ); 136 | let wrapper = wrapper.expect("the wrapper failed to quote"); 137 | let wrapper_ident = intern_and_get_ident(wrapper.to_source().as_slice()); 138 | let wrapper_str = ecx.expr_str(sp, wrapper_ident); 139 | 140 | let cwd = ::std::os::getcwd().unwrap(); 141 | let deps_str = cwd.join_many(["target", "le32-unknown-nacl", "deps"].as_slice()) 142 | .display().to_string(); 143 | let deps_ident = intern_and_get_ident(deps_str.as_slice()); 144 | let deps_dir = ecx.expr_str(codemap::DUMMY_SP, deps_ident); 145 | 146 | let timeout = None::; 147 | 148 | let host_test = 149 | quote_item!( 150 | ecx, 151 | #[test] fn $test_name() { 152 | use std::io::TempDir; 153 | use std::io::fs::File; 154 | use std::io::{Command, LineBufferedWriter}; 155 | use std::io::process::{ProcessExit, ProcessOutput}; 156 | use std::io::stdio::{stdout, stderr, StdWriter}; 157 | 158 | // the source to the real test: 159 | const REAL_TEST: &'static str = $wrapper_str; 160 | 161 | let tmp = TempDir::new(stringify!($test_name)) 162 | .ok().expect("need temp directory for test artifacts"); 163 | 164 | let url = format!("file://{}", 165 | tmp.path().join("index.html").display()); 166 | let chrome_args = ["--allow-file-access-from-files".to_string(), 167 | "--bwsi".to_string(), 168 | "--no-sandbox".to_string(), 169 | "--silent-launch".to_string(), 170 | "--noerrdialogs".to_string(), 171 | "--no-first-run".to_string(), 172 | "--no-default-browser-check".to_string(), 173 | url]; 174 | 175 | let stdout_path = tmp.path().join("stdout"); 176 | let stdout_name = stdout_path 177 | .display().to_string(); 178 | let stderr_path = tmp.path().join("stderr"); 179 | let stderr_name = stderr_path 180 | .display().to_string(); 181 | let chrome_env = [("NACL_EXE_STDOUT".to_string(), stdout_name), 182 | ("NACL_EXE_STDERR".to_string(), stderr_name)]; 183 | 184 | let rustc_args = ["-".to_string(), 185 | "-o".to_string(), 186 | tmp.path().join("test-main.pexe").display().to_string(), 187 | "--crate-type".to_string(), "bin".to_string(), 188 | "--target".to_string(), 189 | "le32-unknown-nacl".to_string(), 190 | "-L".to_string(), 191 | ($deps_dir).to_string()]; 192 | let mut rustc = Command::new("rustc"); 193 | rustc.args(rustc_args); 194 | println!("∨∨∨∨∨∨∨∨∨∨∨ rustc ∨∨∨∨∨∨∨∨∨∨∨"); 195 | println!("spawning `{:?}`", rustc); 196 | let mut rustc = rustc.spawn().unwrap(); 197 | rustc.stdin 198 | .as_mut() 199 | .unwrap() 200 | .write_str(REAL_TEST) 201 | .unwrap(); 202 | 203 | { 204 | let path = tmp.path() 205 | .join("index.html"); 206 | let file = File::create(&path).unwrap(); 207 | file.write_str($HTML).unwrap(); 208 | } 209 | { 210 | let path = tmp.path() 211 | .join("manifest.nmf"); 212 | let file = File::create(&path).unwrap(); 213 | file.write_str($MANIFEST).unwrap(); 214 | } 215 | 216 | match rustc.wait_with_output() { 217 | Ok(ProcessOutput { 218 | status: exit_status, 219 | output: out, error: err, 220 | }) => { 221 | stdout().write(out.as_slice()); 222 | stderr().write(err.as_slice()); 223 | assert!(exit_status.success()); 224 | } 225 | err => { err.unwrap(); }, 226 | } 227 | println!("∧∧∧∧∧∧∧∧∧∧∧ rustc ∧∧∧∧∧∧∧∧∧∧∧"); 228 | 229 | let mut chrome = Command::new("google-chrome"); 230 | chrome.args(chrome_args); 231 | for (k, v) in chrome_env.iter() { 232 | chrome.env(k, v); 233 | } 234 | println!("∨∨∨∨∨∨∨∨∨∨∨ chrome ∨∨∨∨∨∨∨∨∨∨∨"); 235 | println!("spawning `{:?}`:", chrome); 236 | 237 | let mut chrome = chrome.spawn().unwrap(); 238 | chrome.set_timeout($timeout); 239 | 240 | fn split_and_print(where_: LineBufferedWriter, 241 | kind: &'static str, out: &[u8]) { 242 | for line in out.split(move |: v| v == '\n' ) { 243 | where_.write_str(kind).unwrap(); 244 | where_.write(line).unwrap(); 245 | where_.write_u8('\n').unwrap(); 246 | } 247 | } 248 | 249 | fn dump_output(cmd: &mut Process) { 250 | let output = cmd.stdout 251 | .as_mut().unwrap() 252 | .read_to_end().unwrap(); 253 | let error = cmd.stderr 254 | .as_mut().unwrap() 255 | .read_to_end().unwrap(); 256 | split_and_print(stdout(), "stdout: ", output.as_slice()); 257 | split_and_print(stderr(), "stderr: ", error.as_slice()); 258 | } 259 | 260 | match chrome.wait() { 261 | Ok(status) => { 262 | dump_output(&mut chrome); 263 | assert!(status.success()); 264 | }, 265 | Err(IoError { kind: IoErrorKind::TimedOut, .. }) => { 266 | println!("timeout! sending sigterm..."); 267 | chrome.set_timeout(Some(6000)); 268 | chrome.signal_exit().unwrap(); 269 | let res = chrome.wait(); 270 | let res = match res { 271 | Err(IoError { kind: IoErrorKind::TimedOut, .. }) => { 272 | println!("1s later: chrome still hasn't quit; killing."); 273 | chrome.signal_kill().unwrap(); 274 | chrome.wait() 275 | }, 276 | res => res, 277 | } 278 | dump_output(&mut chrome); 279 | assert_eq!(res, Ok(ProcessExit::ExitStatus(0))); // always false. 280 | unreachable!() 281 | }, 282 | res => { 283 | dump_output(&mut chrome); 284 | res.unwrap(); 285 | unreachable!() 286 | } 287 | } 288 | println!("∧∧∧∧∧∧∧∧∧∧∧ chrome ∧∧∧∧∧∧∧∧∧∧∧"); 289 | 290 | println!("∨∨∨∨∨∨∨∨∨∨∨ test output ∨∨∨∨∨∨∨∨∨∨∨"); 291 | fn read_log(p: &Path) -> Vec { 292 | let f = File::open(p).unwrap(); 293 | f.read_to_end().unwrap() 294 | } 295 | let test_stdout = read_log(&stdout_path); 296 | let test_stderr = read_log(&stderr_path); 297 | split_and_print(stdout(), "test stdout: ", test_stdout.as_slice()); 298 | split_and_print(stderr(), "test stderr: ", test_stderr.as_slice()); 299 | println!("∧∧∧∧∧∧∧∧∧∧∧ test output ∧∧∧∧∧∧∧∧∧∧∧"); 300 | }); 301 | host_test.unwrap() 302 | } 303 | -------------------------------------------------------------------------------- /src/ppapi-tester/manifest.nmf: -------------------------------------------------------------------------------- 1 | { 2 | "program": { 3 | "portable": { 4 | "pnacl-translate": { 5 | "url": "test-main.pexe" 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ppapi-tests" 3 | description = "Integration tests that run inside Chrome. This requires a bit of magic, including getting Cargo to not build ppapi proper for the host. This package contains no usable library." 4 | version = "0.0.0" 5 | authors = [ "Richard Diamond " ] 6 | license = "MPL-2.0" 7 | build = "build.rs" 8 | 9 | [lib] 10 | name = "dont_use" 11 | path = "lib.rs" 12 | 13 | [build-dependencies] 14 | pnacl-build-helper = "*" 15 | 16 | [dev-dependencies.ppapi-tester] 17 | path = "../ppapi-tester" 18 | -------------------------------------------------------------------------------- /src/tests/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #![allow(unstable)] 10 | 11 | extern crate "pnacl-build-helper" as helper; 12 | extern crate libc; 13 | 14 | use std::io::{Command}; 15 | use std::io::process::InheritFd; 16 | use std::os::{change_dir, getcwd, getenv}; 17 | 18 | 19 | pub fn main() { 20 | let ppapi_root = getcwd().unwrap() 21 | .join_many(["..", ".."].as_slice()); 22 | change_dir(&ppapi_root).unwrap(); 23 | 24 | let target = getenv("PPAPI_TESTS_TARGET") 25 | .unwrap_or_else(move |:| "le32-unknown-nacl".to_string() ); 26 | let env_target = target.replace("-", "_"); 27 | 28 | let tools: helper::NativeTools = helper::NativeTools::new(target.as_slice()); 29 | let envs = [(format!("CC_{}", env_target), 30 | tools.cc.display().to_string()), 31 | (format!("CXX_{}", env_target), 32 | tools.cxx.display().to_string()), 33 | (format!("AR_{}", env_target), 34 | tools.ar.display().to_string()), 35 | (format!("RANLIB_{}", env_target), 36 | tools.ranlib.display().to_string()), 37 | ]; 38 | 39 | let mut cargo = Command::new("cargo"); 40 | cargo.args(["build", "--verbose", "--target"].as_slice()); 41 | cargo.arg(target); 42 | for &(ref k, ref v) in envs.iter() { 43 | cargo.env(k, v); 44 | } 45 | cargo.stdout(InheritFd(libc::STDOUT_FILENO)); 46 | cargo.stderr(InheritFd(libc::STDERR_FILENO)); 47 | println!("spawning `{:?}`:", cargo); 48 | let mut cargo = cargo.spawn().unwrap(); 49 | assert!(cargo.wait().unwrap().success()); 50 | } 51 | -------------------------------------------------------------------------------- /src/tests/lib.rs: -------------------------------------------------------------------------------- 1 | // Empty. 2 | -------------------------------------------------------------------------------- /src/tests/tests/hello_world.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Richard Diamond & contributors. 2 | // 3 | // This file is part of the Rust PPApi project. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this 7 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #![feature(plugin)] 10 | 11 | #[plugin] #[no_link] 12 | extern crate "ppapi-tester" as _ppapi_tester; 13 | 14 | #[ppapi_test] 15 | fn hello_world(instance: ppapi::Instance, args: HashMap) { 16 | println!("Hello, world!"); 17 | } 18 | --------------------------------------------------------------------------------