diff --git a/.travis.yml b/.travis.yml index 88e7bcf938..d1f205e109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,3 +10,6 @@ addons: apt: packages: - libgles2-mesa-dev +script: + - (cd webrender_traits && cargo test --verbose) + - (cd webrender && cargo test --verbose) diff --git a/appveyor.yml b/appveyor.yml index f82a3036cf..3f266fe943 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,4 +11,7 @@ install: build: false test_script: + - cd webrender_traits + - cargo test --verbose + - cd ../webrender - cargo test --verbose diff --git a/Cargo.toml b/webrender/Cargo.toml similarity index 78% rename from Cargo.toml rename to webrender/Cargo.toml index 4d12756f3c..84e6a66360 100644 --- a/Cargo.toml +++ b/webrender/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "webrender" -version = "0.2.0" +version = "0.4.0" authors = ["Glenn Watson "] +license = "MPL-2.0" +repository = "https://github.com/servo/webrender" [features] default = ["webrender_traits/serde_codegen"] @@ -17,12 +19,11 @@ gleam = "0.2" ipc-channel = "0.5" lazy_static = "0.2" log = "0.3" -#notify = {git = "https://github.com/glennw/rsnotify.git", branch = "inotify-modify"} num-traits = "0.1.32" offscreen_gl_context = {version = "0.3", features = ["serde_serialization"]} rayon = "0.4.0" time = "0.1" -webrender_traits = {git = "https://github.com/servo/webrender_traits", default-features = false} +webrender_traits = {path = "../webrender_traits", default-features = false} [target.'cfg(any(target_os = "android", target_os = "linux", target_os = "windows"))'.dependencies] freetype = {git = "https://github.com/servo/rust-freetype"} diff --git a/res/blend.fs.glsl b/webrender/res/blend.fs.glsl similarity index 100% rename from res/blend.fs.glsl rename to webrender/res/blend.fs.glsl diff --git a/res/blend.vs.glsl b/webrender/res/blend.vs.glsl similarity index 100% rename from res/blend.vs.glsl rename to webrender/res/blend.vs.glsl diff --git a/res/blur.fs.glsl b/webrender/res/blur.fs.glsl similarity index 100% rename from res/blur.fs.glsl rename to webrender/res/blur.fs.glsl diff --git a/res/blur.vs.glsl b/webrender/res/blur.vs.glsl similarity index 100% rename from res/blur.vs.glsl rename to webrender/res/blur.vs.glsl diff --git a/res/box_shadow.fs.glsl b/webrender/res/box_shadow.fs.glsl similarity index 100% rename from res/box_shadow.fs.glsl rename to webrender/res/box_shadow.fs.glsl diff --git a/res/box_shadow.vs.glsl b/webrender/res/box_shadow.vs.glsl similarity index 100% rename from res/box_shadow.vs.glsl rename to webrender/res/box_shadow.vs.glsl diff --git a/res/debug_color.fs.glsl b/webrender/res/debug_color.fs.glsl similarity index 100% rename from res/debug_color.fs.glsl rename to webrender/res/debug_color.fs.glsl diff --git a/res/debug_color.vs.glsl b/webrender/res/debug_color.vs.glsl similarity index 100% rename from res/debug_color.vs.glsl rename to webrender/res/debug_color.vs.glsl diff --git a/res/debug_font.fs.glsl b/webrender/res/debug_font.fs.glsl similarity index 100% rename from res/debug_font.fs.glsl rename to webrender/res/debug_font.fs.glsl diff --git a/res/debug_font.vs.glsl b/webrender/res/debug_font.vs.glsl similarity index 100% rename from res/debug_font.vs.glsl rename to webrender/res/debug_font.vs.glsl diff --git a/res/es2_common.fs.glsl b/webrender/res/es2_common.fs.glsl similarity index 100% rename from res/es2_common.fs.glsl rename to webrender/res/es2_common.fs.glsl diff --git a/res/es2_common.vs.glsl b/webrender/res/es2_common.vs.glsl similarity index 100% rename from res/es2_common.vs.glsl rename to webrender/res/es2_common.vs.glsl diff --git a/res/filter.fs.glsl b/webrender/res/filter.fs.glsl similarity index 100% rename from res/filter.fs.glsl rename to webrender/res/filter.fs.glsl diff --git a/res/filter.vs.glsl b/webrender/res/filter.vs.glsl similarity index 100% rename from res/filter.vs.glsl rename to webrender/res/filter.vs.glsl diff --git a/res/gl3_common.fs.glsl b/webrender/res/gl3_common.fs.glsl similarity index 100% rename from res/gl3_common.fs.glsl rename to webrender/res/gl3_common.fs.glsl diff --git a/res/gl3_common.vs.glsl b/webrender/res/gl3_common.vs.glsl similarity index 100% rename from res/gl3_common.vs.glsl rename to webrender/res/gl3_common.vs.glsl diff --git a/res/prim_shared.glsl b/webrender/res/prim_shared.glsl similarity index 100% rename from res/prim_shared.glsl rename to webrender/res/prim_shared.glsl diff --git a/res/ps_angle_gradient.fs.glsl b/webrender/res/ps_angle_gradient.fs.glsl similarity index 100% rename from res/ps_angle_gradient.fs.glsl rename to webrender/res/ps_angle_gradient.fs.glsl diff --git a/res/ps_angle_gradient.glsl b/webrender/res/ps_angle_gradient.glsl similarity index 100% rename from res/ps_angle_gradient.glsl rename to webrender/res/ps_angle_gradient.glsl diff --git a/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl similarity index 100% rename from res/ps_angle_gradient.vs.glsl rename to webrender/res/ps_angle_gradient.vs.glsl diff --git a/res/ps_blend.fs.glsl b/webrender/res/ps_blend.fs.glsl similarity index 100% rename from res/ps_blend.fs.glsl rename to webrender/res/ps_blend.fs.glsl diff --git a/res/ps_blend.glsl b/webrender/res/ps_blend.glsl similarity index 100% rename from res/ps_blend.glsl rename to webrender/res/ps_blend.glsl diff --git a/res/ps_blend.vs.glsl b/webrender/res/ps_blend.vs.glsl similarity index 100% rename from res/ps_blend.vs.glsl rename to webrender/res/ps_blend.vs.glsl diff --git a/res/ps_border.fs.glsl b/webrender/res/ps_border.fs.glsl similarity index 100% rename from res/ps_border.fs.glsl rename to webrender/res/ps_border.fs.glsl diff --git a/res/ps_border.glsl b/webrender/res/ps_border.glsl similarity index 100% rename from res/ps_border.glsl rename to webrender/res/ps_border.glsl diff --git a/res/ps_border.vs.glsl b/webrender/res/ps_border.vs.glsl similarity index 100% rename from res/ps_border.vs.glsl rename to webrender/res/ps_border.vs.glsl diff --git a/res/ps_box_shadow.fs.glsl b/webrender/res/ps_box_shadow.fs.glsl similarity index 100% rename from res/ps_box_shadow.fs.glsl rename to webrender/res/ps_box_shadow.fs.glsl diff --git a/res/ps_box_shadow.glsl b/webrender/res/ps_box_shadow.glsl similarity index 100% rename from res/ps_box_shadow.glsl rename to webrender/res/ps_box_shadow.glsl diff --git a/res/ps_box_shadow.vs.glsl b/webrender/res/ps_box_shadow.vs.glsl similarity index 100% rename from res/ps_box_shadow.vs.glsl rename to webrender/res/ps_box_shadow.vs.glsl diff --git a/res/ps_clear.fs.glsl b/webrender/res/ps_clear.fs.glsl similarity index 100% rename from res/ps_clear.fs.glsl rename to webrender/res/ps_clear.fs.glsl diff --git a/res/ps_clear.glsl b/webrender/res/ps_clear.glsl similarity index 100% rename from res/ps_clear.glsl rename to webrender/res/ps_clear.glsl diff --git a/res/ps_clear.vs.glsl b/webrender/res/ps_clear.vs.glsl similarity index 100% rename from res/ps_clear.vs.glsl rename to webrender/res/ps_clear.vs.glsl diff --git a/res/ps_composite.fs.glsl b/webrender/res/ps_composite.fs.glsl similarity index 100% rename from res/ps_composite.fs.glsl rename to webrender/res/ps_composite.fs.glsl diff --git a/res/ps_composite.glsl b/webrender/res/ps_composite.glsl similarity index 100% rename from res/ps_composite.glsl rename to webrender/res/ps_composite.glsl diff --git a/res/ps_composite.vs.glsl b/webrender/res/ps_composite.vs.glsl similarity index 100% rename from res/ps_composite.vs.glsl rename to webrender/res/ps_composite.vs.glsl diff --git a/res/ps_gradient.fs.glsl b/webrender/res/ps_gradient.fs.glsl similarity index 100% rename from res/ps_gradient.fs.glsl rename to webrender/res/ps_gradient.fs.glsl diff --git a/res/ps_gradient.glsl b/webrender/res/ps_gradient.glsl similarity index 100% rename from res/ps_gradient.glsl rename to webrender/res/ps_gradient.glsl diff --git a/res/ps_gradient.vs.glsl b/webrender/res/ps_gradient.vs.glsl similarity index 100% rename from res/ps_gradient.vs.glsl rename to webrender/res/ps_gradient.vs.glsl diff --git a/res/ps_image.fs.glsl b/webrender/res/ps_image.fs.glsl similarity index 100% rename from res/ps_image.fs.glsl rename to webrender/res/ps_image.fs.glsl diff --git a/res/ps_image.glsl b/webrender/res/ps_image.glsl similarity index 100% rename from res/ps_image.glsl rename to webrender/res/ps_image.glsl diff --git a/res/ps_image.vs.glsl b/webrender/res/ps_image.vs.glsl similarity index 100% rename from res/ps_image.vs.glsl rename to webrender/res/ps_image.vs.glsl diff --git a/res/ps_image_clip.fs.glsl b/webrender/res/ps_image_clip.fs.glsl similarity index 100% rename from res/ps_image_clip.fs.glsl rename to webrender/res/ps_image_clip.fs.glsl diff --git a/res/ps_image_clip.glsl b/webrender/res/ps_image_clip.glsl similarity index 100% rename from res/ps_image_clip.glsl rename to webrender/res/ps_image_clip.glsl diff --git a/res/ps_image_clip.vs.glsl b/webrender/res/ps_image_clip.vs.glsl similarity index 100% rename from res/ps_image_clip.vs.glsl rename to webrender/res/ps_image_clip.vs.glsl diff --git a/res/ps_rectangle.fs.glsl b/webrender/res/ps_rectangle.fs.glsl similarity index 100% rename from res/ps_rectangle.fs.glsl rename to webrender/res/ps_rectangle.fs.glsl diff --git a/res/ps_rectangle.glsl b/webrender/res/ps_rectangle.glsl similarity index 100% rename from res/ps_rectangle.glsl rename to webrender/res/ps_rectangle.glsl diff --git a/res/ps_rectangle.vs.glsl b/webrender/res/ps_rectangle.vs.glsl similarity index 100% rename from res/ps_rectangle.vs.glsl rename to webrender/res/ps_rectangle.vs.glsl diff --git a/res/ps_rectangle_clip.fs.glsl b/webrender/res/ps_rectangle_clip.fs.glsl similarity index 100% rename from res/ps_rectangle_clip.fs.glsl rename to webrender/res/ps_rectangle_clip.fs.glsl diff --git a/res/ps_rectangle_clip.glsl b/webrender/res/ps_rectangle_clip.glsl similarity index 100% rename from res/ps_rectangle_clip.glsl rename to webrender/res/ps_rectangle_clip.glsl diff --git a/res/ps_rectangle_clip.vs.glsl b/webrender/res/ps_rectangle_clip.vs.glsl similarity index 100% rename from res/ps_rectangle_clip.vs.glsl rename to webrender/res/ps_rectangle_clip.vs.glsl diff --git a/res/ps_text.fs.glsl b/webrender/res/ps_text.fs.glsl similarity index 100% rename from res/ps_text.fs.glsl rename to webrender/res/ps_text.fs.glsl diff --git a/res/ps_text.glsl b/webrender/res/ps_text.glsl similarity index 100% rename from res/ps_text.glsl rename to webrender/res/ps_text.glsl diff --git a/res/ps_text.vs.glsl b/webrender/res/ps_text.vs.glsl similarity index 100% rename from res/ps_text.vs.glsl rename to webrender/res/ps_text.vs.glsl diff --git a/res/shared.glsl b/webrender/res/shared.glsl similarity index 100% rename from res/shared.glsl rename to webrender/res/shared.glsl diff --git a/res/shared_other.glsl b/webrender/res/shared_other.glsl similarity index 100% rename from res/shared_other.glsl rename to webrender/res/shared_other.glsl diff --git a/src/batch.rs b/webrender/src/batch.rs similarity index 100% rename from src/batch.rs rename to webrender/src/batch.rs diff --git a/src/batch_builder.rs b/webrender/src/batch_builder.rs similarity index 100% rename from src/batch_builder.rs rename to webrender/src/batch_builder.rs diff --git a/src/debug_font_data.rs b/webrender/src/debug_font_data.rs similarity index 100% rename from src/debug_font_data.rs rename to webrender/src/debug_font_data.rs diff --git a/src/debug_render.rs b/webrender/src/debug_render.rs similarity index 100% rename from src/debug_render.rs rename to webrender/src/debug_render.rs diff --git a/src/device.rs b/webrender/src/device.rs similarity index 100% rename from src/device.rs rename to webrender/src/device.rs diff --git a/src/frame.rs b/webrender/src/frame.rs similarity index 100% rename from src/frame.rs rename to webrender/src/frame.rs diff --git a/src/freelist.rs b/webrender/src/freelist.rs similarity index 100% rename from src/freelist.rs rename to webrender/src/freelist.rs diff --git a/src/geometry.rs b/webrender/src/geometry.rs similarity index 100% rename from src/geometry.rs rename to webrender/src/geometry.rs diff --git a/src/internal_types.rs b/webrender/src/internal_types.rs similarity index 100% rename from src/internal_types.rs rename to webrender/src/internal_types.rs diff --git a/src/layer.rs b/webrender/src/layer.rs similarity index 100% rename from src/layer.rs rename to webrender/src/layer.rs diff --git a/src/lib.rs b/webrender/src/lib.rs similarity index 100% rename from src/lib.rs rename to webrender/src/lib.rs diff --git a/src/platform/linux/font.rs b/webrender/src/platform/linux/font.rs similarity index 100% rename from src/platform/linux/font.rs rename to webrender/src/platform/linux/font.rs diff --git a/src/platform/macos/font.rs b/webrender/src/platform/macos/font.rs similarity index 100% rename from src/platform/macos/font.rs rename to webrender/src/platform/macos/font.rs diff --git a/src/profiler.rs b/webrender/src/profiler.rs similarity index 100% rename from src/profiler.rs rename to webrender/src/profiler.rs diff --git a/src/render_backend.rs b/webrender/src/render_backend.rs similarity index 100% rename from src/render_backend.rs rename to webrender/src/render_backend.rs diff --git a/src/renderer.rs b/webrender/src/renderer.rs similarity index 100% rename from src/renderer.rs rename to webrender/src/renderer.rs diff --git a/src/resource_cache.rs b/webrender/src/resource_cache.rs similarity index 100% rename from src/resource_cache.rs rename to webrender/src/resource_cache.rs diff --git a/src/resource_list.rs b/webrender/src/resource_list.rs similarity index 100% rename from src/resource_list.rs rename to webrender/src/resource_list.rs diff --git a/src/scene.rs b/webrender/src/scene.rs similarity index 100% rename from src/scene.rs rename to webrender/src/scene.rs diff --git a/src/spring.rs b/webrender/src/spring.rs similarity index 100% rename from src/spring.rs rename to webrender/src/spring.rs diff --git a/src/texture_cache.rs b/webrender/src/texture_cache.rs similarity index 100% rename from src/texture_cache.rs rename to webrender/src/texture_cache.rs diff --git a/src/tiling.rs b/webrender/src/tiling.rs similarity index 100% rename from src/tiling.rs rename to webrender/src/tiling.rs diff --git a/src/util.rs b/webrender/src/util.rs similarity index 100% rename from src/util.rs rename to webrender/src/util.rs diff --git a/tests/bug_124.html b/webrender/tests/bug_124.html similarity index 100% rename from tests/bug_124.html rename to webrender/tests/bug_124.html diff --git a/tests/bug_134.html b/webrender/tests/bug_134.html similarity index 100% rename from tests/bug_134.html rename to webrender/tests/bug_134.html diff --git a/tests/bug_137.html b/webrender/tests/bug_137.html similarity index 100% rename from tests/bug_137.html rename to webrender/tests/bug_137.html diff --git a/tests/bug_143.html b/webrender/tests/bug_143.html similarity index 100% rename from tests/bug_143.html rename to webrender/tests/bug_143.html diff --git a/tests/bug_159.html b/webrender/tests/bug_159.html similarity index 100% rename from tests/bug_159.html rename to webrender/tests/bug_159.html diff --git a/tests/bug_166.html b/webrender/tests/bug_166.html similarity index 100% rename from tests/bug_166.html rename to webrender/tests/bug_166.html diff --git a/tests/bug_176.html b/webrender/tests/bug_176.html similarity index 100% rename from tests/bug_176.html rename to webrender/tests/bug_176.html diff --git a/tests/bug_177.html b/webrender/tests/bug_177.html similarity index 100% rename from tests/bug_177.html rename to webrender/tests/bug_177.html diff --git a/tests/bug_178.html b/webrender/tests/bug_178.html similarity index 100% rename from tests/bug_178.html rename to webrender/tests/bug_178.html diff --git a/tests/bug_203a.html b/webrender/tests/bug_203a.html similarity index 100% rename from tests/bug_203a.html rename to webrender/tests/bug_203a.html diff --git a/tests/bug_203b.html b/webrender/tests/bug_203b.html similarity index 100% rename from tests/bug_203b.html rename to webrender/tests/bug_203b.html diff --git a/tests/bug_servo_10136.html b/webrender/tests/bug_servo_10136.html similarity index 100% rename from tests/bug_servo_10136.html rename to webrender/tests/bug_servo_10136.html diff --git a/tests/bug_servo_10164.html b/webrender/tests/bug_servo_10164.html similarity index 100% rename from tests/bug_servo_10164.html rename to webrender/tests/bug_servo_10164.html diff --git a/tests/bug_servo_10307.html b/webrender/tests/bug_servo_10307.html similarity index 100% rename from tests/bug_servo_10307.html rename to webrender/tests/bug_servo_10307.html diff --git a/tests/bug_servo_11358.html b/webrender/tests/bug_servo_11358.html similarity index 100% rename from tests/bug_servo_11358.html rename to webrender/tests/bug_servo_11358.html diff --git a/tests/bug_servo_9983a.html b/webrender/tests/bug_servo_9983a.html similarity index 100% rename from tests/bug_servo_9983a.html rename to webrender/tests/bug_servo_9983a.html diff --git a/tests/color_pattern_1.png b/webrender/tests/color_pattern_1.png similarity index 100% rename from tests/color_pattern_1.png rename to webrender/tests/color_pattern_1.png diff --git a/tests/color_pattern_2.png b/webrender/tests/color_pattern_2.png similarity index 100% rename from tests/color_pattern_2.png rename to webrender/tests/color_pattern_2.png diff --git a/tests/fixed-position.html b/webrender/tests/fixed-position.html similarity index 100% rename from tests/fixed-position.html rename to webrender/tests/fixed-position.html diff --git a/tests/mix-blend-mode-2.html b/webrender/tests/mix-blend-mode-2.html similarity index 100% rename from tests/mix-blend-mode-2.html rename to webrender/tests/mix-blend-mode-2.html diff --git a/tests/mix-blend-mode.html b/webrender/tests/mix-blend-mode.html similarity index 100% rename from tests/mix-blend-mode.html rename to webrender/tests/mix-blend-mode.html diff --git a/tests/nav-1.html b/webrender/tests/nav-1.html similarity index 100% rename from tests/nav-1.html rename to webrender/tests/nav-1.html diff --git a/tests/nav-2.html b/webrender/tests/nav-2.html similarity index 100% rename from tests/nav-2.html rename to webrender/tests/nav-2.html diff --git a/webrender_traits/.gitignore b/webrender_traits/.gitignore new file mode 100644 index 0000000000..45a758bb26 --- /dev/null +++ b/webrender_traits/.gitignore @@ -0,0 +1,3 @@ +.cargo/ +target +Cargo.lock diff --git a/webrender_traits/.travis.yml b/webrender_traits/.travis.yml new file mode 100644 index 0000000000..497ac459f7 --- /dev/null +++ b/webrender_traits/.travis.yml @@ -0,0 +1,27 @@ +language: rust +rust: + - nightly + - nightly-2016-07-11 # Should be kept in sync with Servo. + +matrix: + allow_failures: + - rust: nightly + +notifications: + webhooks: http://build.servo.org:54856/travis + +addons: + apt: + packages: + - libgles2-mesa-dev +os: + - linux + - osx + +before_script: + - export PATH=$HOME/.local/bin:/Users/travis/Library/Python/2.7/bin:$PATH + - pip install servo_tidy --user `whoami` + +script: + - servo-tidy + - cargo build --verbose diff --git a/webrender_traits/Cargo.toml b/webrender_traits/Cargo.toml new file mode 100644 index 0000000000..89517dc78b --- /dev/null +++ b/webrender_traits/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "webrender_traits" +version = "0.4.0" +authors = ["Glenn Watson "] +license = "MPL-2.0" +repository = "https://github.com/servo/webrender" +build = "build.rs" + +[features] +default = ["serde_codegen"] +nightly = ["euclid/unstable", "serde/unstable"] + +[dependencies] +app_units = "0.3.0" +byteorder = "0.5" +euclid = "0.9" +gleam = "0.2.19" +heapsize = "0.3.6" +offscreen_gl_context = {version = "0.3.0", features = ["serde_serialization"]} +serde = "0.8" +serde_macros = {version = "0.8", optional = true} +ipc-channel = "0.5.0" + +[target.x86_64-apple-darwin.dependencies] +core-graphics = "0.4" + +[build-dependencies] +serde_codegen = {version = "0.8", optional = true} diff --git a/webrender_traits/build.rs b/webrender_traits/build.rs new file mode 100644 index 0000000000..e954b0bbfe --- /dev/null +++ b/webrender_traits/build.rs @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[cfg(all(feature = "serde_codegen", not(feature = "serde_macros")))] +mod inner { + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/types.rs"); + let dst = Path::new(&out_dir).join("types.rs"); + + serde_codegen::expand(&src, &dst).unwrap(); + println!("cargo:rerun-if-changed=src/types.rs"); + } +} + +#[cfg(all(feature = "serde_macros", not(feature = "serde_codegen")))] +mod inner { + pub fn main() {} +} + +#[cfg(all(feature = "serde_codegen", feature = "serde_macros"))] +mod inner { + pub fn main() { + panic!("serde_codegen and serde_macros are both used. " + "You probably forgot --no-default-features.") + } +} + +#[cfg(not(any(feature = "serde_codegen", feature = "serde_macros")))] +mod inner { + pub fn main() { + panic!("Neither serde_codegen nor serde_macros are used. " + "You probably want --features serde_macros --no-default-features.") + } +} + +fn main() { + inner::main(); +} diff --git a/webrender_traits/src/api.rs b/webrender_traits/src/api.rs new file mode 100644 index 0000000000..d94804fb06 --- /dev/null +++ b/webrender_traits/src/api.rs @@ -0,0 +1,243 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use byteorder::{LittleEndian, WriteBytesExt}; +use euclid::{Point2D, Size2D}; +use ipc_channel::ipc::{self, IpcBytesSender, IpcSender}; +use offscreen_gl_context::{GLContextAttributes, GLLimits}; +use std::cell::Cell; +use {ApiMsg, AuxiliaryLists, BuiltDisplayList, ColorF, DisplayListId, Epoch}; +use {FontKey, IdNamespace, ImageFormat, ImageKey, NativeFontHandle, PipelineId}; +use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState}; +use {StackingContext, StackingContextId, WebGLContextId, WebGLCommand}; + +impl RenderApiSender { + pub fn new(api_sender: IpcSender, + payload_sender: IpcBytesSender) + -> RenderApiSender { + RenderApiSender { + api_sender: api_sender, + payload_sender: payload_sender, + } + } + + pub fn create_api(&self) -> RenderApi { + let RenderApiSender { + ref api_sender, + ref payload_sender + } = *self; + let (sync_tx, sync_rx) = ipc::channel().unwrap(); + let msg = ApiMsg::CloneApi(sync_tx); + api_sender.send(msg).unwrap(); + RenderApi { + api_sender: api_sender.clone(), + payload_sender: payload_sender.clone(), + id_namespace: sync_rx.recv().unwrap(), + next_id: Cell::new(ResourceId(0)), + } + } +} + +pub struct RenderApi { + pub api_sender: IpcSender, + pub payload_sender: IpcBytesSender, + pub id_namespace: IdNamespace, + pub next_id: Cell, +} + +impl RenderApi { + pub fn clone_sender(&self) -> RenderApiSender { + RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone()) + } + + pub fn add_raw_font(&self, bytes: Vec) -> FontKey { + let new_id = self.next_unique_id(); + let key = FontKey::new(new_id.0, new_id.1); + let msg = ApiMsg::AddRawFont(key, bytes); + self.api_sender.send(msg).unwrap(); + key + } + + pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey { + let new_id = self.next_unique_id(); + let key = FontKey::new(new_id.0, new_id.1); + let msg = ApiMsg::AddNativeFont(key, native_font_handle); + self.api_sender.send(msg).unwrap(); + key + } + + /// Creates an `ImageKey`. + pub fn alloc_image(&self) -> ImageKey { + let new_id = self.next_unique_id(); + ImageKey::new(new_id.0, new_id.1) + } + + /// Adds an image and returns the corresponding `ImageKey`. + pub fn add_image(&self, + width: u32, + height: u32, + format: ImageFormat, + bytes: Vec) -> ImageKey { + let new_id = self.next_unique_id(); + let key = ImageKey::new(new_id.0, new_id.1); + let msg = ApiMsg::AddImage(key, width, height, format, bytes); + self.api_sender.send(msg).unwrap(); + key + } + + /// Updates a specific image. + /// + /// Currently doesn't support changing dimensions or format by updating. + // TODO: Support changing dimensions (and format) during image update? + pub fn update_image(&self, + key: ImageKey, + width: u32, + height: u32, + format: ImageFormat, + bytes: Vec) { + let msg = ApiMsg::UpdateImage(key, width, height, format, bytes); + self.api_sender.send(msg).unwrap(); + } + + /// Deletes the specific image. + pub fn delete_image(&self, key: ImageKey) { + let msg = ApiMsg::DeleteImage(key); + self.api_sender.send(msg).unwrap(); + } + + /// Sets the root pipeline. + /// + /// # Examples + /// + /// ```ignore + /// let (mut renderer, sender) = webrender::renderer::Renderer::new(opts); + /// let api = sender.create_api(); + /// ... + /// let pipeline_id = PipelineId(0,0); + /// api.set_root_pipeline(pipeline_id); + /// ``` + pub fn set_root_pipeline(&self, pipeline_id: PipelineId) { + let msg = ApiMsg::SetRootPipeline(pipeline_id); + self.api_sender.send(msg).unwrap(); + } + + /// Supplies a new frame to WebRender. + /// + /// Non-blocking, it notifies a worker process which processes the stacking context. + /// When it's done and a RenderNotifier has been set in `webrender::renderer::Renderer`, + /// [new_frame_ready()][notifier] gets called. + /// + /// Note: Scrolling doesn't require an own Frame. + /// + /// Arguments: + /// + /// * `stacking_context_id`: The ID of the root stacking context. + /// * `background_color`: The background color of this pipeline. + /// * `epoch`: The unique Frame ID, monotonically increasing. + /// * `pipeline_id`: The ID of the pipeline that is supplying this display list. + /// * `viewport_size`: The size of the viewport for this frame. + /// * `stacking_contexts`: Stacking contexts used in this frame. + /// * `display_lists`: Display lists used in this frame. + /// * `auxiliary_lists`: Various items that the display lists and stacking contexts reference. + /// + /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready + pub fn set_root_stacking_context(&self, + stacking_context_id: StackingContextId, + background_color: ColorF, + epoch: Epoch, + pipeline_id: PipelineId, + viewport_size: Size2D, + stacking_contexts: Vec<(StackingContextId, StackingContext)>, + display_lists: Vec<(DisplayListId, BuiltDisplayList)>, + auxiliary_lists: AuxiliaryLists) { + let display_list_descriptors = display_lists.iter().map(|&(display_list_id, + ref built_display_list)| { + (display_list_id, (*built_display_list.descriptor()).clone()) + }).collect(); + let msg = ApiMsg::SetRootStackingContext(stacking_context_id, + background_color, + epoch, + pipeline_id, + viewport_size, + stacking_contexts, + display_list_descriptors, + *auxiliary_lists.descriptor()); + self.api_sender.send(msg).unwrap(); + + let mut payload = vec![]; + payload.write_u32::(stacking_context_id.0).unwrap(); + payload.write_u32::(epoch.0).unwrap(); + + for &(_, ref built_display_list) in &display_lists { + payload.extend_from_slice(built_display_list.data()); + } + payload.extend_from_slice(auxiliary_lists.data()); + + self.payload_sender.send(&payload[..]).unwrap(); + } + + /// Scrolls the scrolling layer under the `cursor` + /// + /// Webrender looks for the layer closest to the user + /// which has `ScrollPolicy::Scrollable` set. + pub fn scroll(&self, delta: Point2D, cursor: Point2D, phase: ScrollEventPhase) { + let msg = ApiMsg::Scroll(delta, cursor, phase); + self.api_sender.send(msg).unwrap(); + } + + pub fn tick_scrolling_bounce_animations(&self) { + let msg = ApiMsg::TickScrollingBounce; + self.api_sender.send(msg).unwrap(); + } + + /// Translates a point from viewport coordinates to layer space + pub fn translate_point_to_layer_space(&self, point: &Point2D) + -> (Point2D, PipelineId) { + let (tx, rx) = ipc::channel().unwrap(); + let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx); + self.api_sender.send(msg).unwrap(); + rx.recv().unwrap() + } + + pub fn get_scroll_layer_state(&self) -> Vec { + let (tx, rx) = ipc::channel().unwrap(); + let msg = ApiMsg::GetScrollLayerState(tx); + self.api_sender.send(msg).unwrap(); + rx.recv().unwrap() + } + + pub fn request_webgl_context(&self, size: &Size2D, attributes: GLContextAttributes) + -> Result<(WebGLContextId, GLLimits), String> { + let (tx, rx) = ipc::channel().unwrap(); + let msg = ApiMsg::RequestWebGLContext(*size, attributes, tx); + self.api_sender.send(msg).unwrap(); + rx.recv().unwrap() + } + + pub fn send_webgl_command(&self, context_id: WebGLContextId, command: WebGLCommand) { + let msg = ApiMsg::WebGLCommand(context_id, command); + self.api_sender.send(msg).unwrap(); + } + + #[inline] + pub fn next_stacking_context_id(&self) -> StackingContextId { + let new_id = self.next_unique_id(); + StackingContextId(new_id.0, new_id.1) + } + + #[inline] + pub fn next_display_list_id(&self) -> DisplayListId { + let new_id = self.next_unique_id(); + DisplayListId(new_id.0, new_id.1) + } + + #[inline] + fn next_unique_id(&self) -> (u32, u32) { + let IdNamespace(namespace) = self.id_namespace; + let ResourceId(id) = self.next_id.get(); + self.next_id.set(ResourceId(id + 1)); + (namespace, id) + } +} + diff --git a/webrender_traits/src/display_item.rs b/webrender_traits/src/display_item.rs new file mode 100644 index 0000000000..1a0e418fd7 --- /dev/null +++ b/webrender_traits/src/display_item.rs @@ -0,0 +1,119 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use display_list::AuxiliaryListsBuilder; +use euclid::{Rect, Size2D}; +use {BorderRadius, BorderDisplayItem, ClipRegion, ColorF, ComplexClipRegion}; +use {FontKey, ImageKey, PipelineId, ScrollLayerId, ScrollLayerInfo}; + +impl BorderDisplayItem { + pub fn top_left_inner_radius(&self) -> Size2D { + Size2D::new((self.radius.top_left.width - self.left.width).max(0.0), + (self.radius.top_left.height - self.top.width).max(0.0)) + } + + pub fn top_right_inner_radius(&self) -> Size2D { + Size2D::new((self.radius.top_right.width - self.right.width).max(0.0), + (self.radius.top_right.height - self.top.width).max(0.0)) + } + + pub fn bottom_left_inner_radius(&self) -> Size2D { + Size2D::new((self.radius.bottom_left.width - self.left.width).max(0.0), + (self.radius.bottom_left.height - self.bottom.width).max(0.0)) + } + + pub fn bottom_right_inner_radius(&self) -> Size2D { + Size2D::new((self.radius.bottom_right.width - self.right.width).max(0.0), + (self.radius.bottom_right.height - self.bottom.width).max(0.0)) + } +} + +impl BorderRadius { + pub fn zero() -> BorderRadius { + BorderRadius { + top_left: Size2D::new(0.0, 0.0), + top_right: Size2D::new(0.0, 0.0), + bottom_left: Size2D::new(0.0, 0.0), + bottom_right: Size2D::new(0.0, 0.0), + } + } + + pub fn uniform(radius: f32) -> BorderRadius { + BorderRadius { + top_left: Size2D::new(radius, radius), + top_right: Size2D::new(radius, radius), + bottom_left: Size2D::new(radius, radius), + bottom_right: Size2D::new(radius, radius), + } + } +} + +impl ClipRegion { + pub fn new(rect: &Rect, + complex: Vec, + auxiliary_lists_builder: &mut AuxiliaryListsBuilder) + -> ClipRegion { + ClipRegion { + main: *rect, + complex: auxiliary_lists_builder.add_complex_clip_regions(&complex), + } + } +} + +impl ColorF { + pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF { + ColorF { + r: r, + g: g, + b: b, + a: a, + } + } + + pub fn scale_rgb(&self, scale: f32) -> ColorF { + ColorF { + r: self.r * scale, + g: self.g * scale, + b: self.b * scale, + a: self.a, + } + } +} + +impl ComplexClipRegion { + pub fn new(rect: Rect, radii: BorderRadius) -> ComplexClipRegion { + ComplexClipRegion { + rect: rect, + radii: radii, + } + } +} + +impl FontKey { + pub fn new(key0: u32, key1: u32) -> FontKey { + FontKey(key0, key1) + } +} + +impl ImageKey { + pub fn new(key0: u32, key1: u32) -> ImageKey { + ImageKey(key0, key1) + } +} + +impl ScrollLayerId { + pub fn new(pipeline_id: PipelineId, index: usize) -> ScrollLayerId { + ScrollLayerId { + pipeline_id: pipeline_id, + info: ScrollLayerInfo::Scrollable(index), + } + } + + pub fn create_fixed(pipeline_id: PipelineId) -> ScrollLayerId { + ScrollLayerId { + pipeline_id: pipeline_id, + info: ScrollLayerInfo::Fixed, + } + } +} diff --git a/webrender_traits/src/display_list.rs b/webrender_traits/src/display_list.rs new file mode 100644 index 0000000000..eb7c7ee71f --- /dev/null +++ b/webrender_traits/src/display_list.rs @@ -0,0 +1,487 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use app_units::Au; +use euclid::{Point2D, Rect, Size2D}; +use std::mem; +use std::slice; +use {AuxiliaryLists, AuxiliaryListsDescriptor, BorderDisplayItem, BorderRadius}; +use {BorderSide, BoxShadowClipMode, BoxShadowDisplayItem, BuiltDisplayList}; +use {BuiltDisplayListDescriptor, ClipRegion, ComplexClipRegion, ColorF}; +use {DisplayItem, DisplayListItem, DisplayListMode, DrawListInfo, FilterOp}; +use {FontKey, GlyphInstance, GradientDisplayItem, GradientStop, IframeInfo}; +use {ImageDisplayItem, ImageKey, ImageRendering, ItemRange, PipelineId}; +use {RectangleDisplayItem, SpecificDisplayItem, SpecificDisplayListItem}; +use {StackingContextId, StackingContextInfo, TextDisplayItem}; +use {WebGLContextId, WebGLDisplayItem}; + +impl BuiltDisplayListDescriptor { + pub fn size(&self) -> usize { + self.display_list_items_size + self.display_items_size + } +} + +impl BuiltDisplayList { + pub fn from_data(data: Vec, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList { + BuiltDisplayList { + data: data, + descriptor: descriptor, + } + } + + pub fn data(&self) -> &[u8] { + &self.data[..] + } + + pub fn descriptor(&self) -> &BuiltDisplayListDescriptor { + &self.descriptor + } + + pub fn display_list_items<'a>(&'a self) -> &'a [DisplayListItem] { + unsafe { + convert_blob_to_pod(&self.data[0..self.descriptor.display_list_items_size]) + } + } + + pub fn display_items<'a>(&'a self, range: &ItemRange) -> &'a [DisplayItem] { + unsafe { + range.get(convert_blob_to_pod(&self.data[self.descriptor.display_list_items_size..])) + } + } +} + +pub struct DisplayListBuilder { + pub mode: DisplayListMode, + pub has_stacking_contexts: bool, + + pub work_list: Vec, + + pub display_list_items: Vec, + pub display_items: Vec, +} + +impl DisplayListBuilder { + pub fn new() -> DisplayListBuilder { + DisplayListBuilder { + mode: DisplayListMode::Default, + has_stacking_contexts: false, + work_list: Vec::new(), + display_list_items: Vec::new(), + display_items: Vec::new(), + } + } + + pub fn push_rect(&mut self, + rect: Rect, + clip: ClipRegion, + color: ColorF) { + let item = RectangleDisplayItem { + color: color, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::Rectangle(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_image(&mut self, + rect: Rect, + clip: ClipRegion, + stretch_size: Size2D, + image_rendering: ImageRendering, + key: ImageKey) { + let item = ImageDisplayItem { + image_key: key, + stretch_size: stretch_size, + image_rendering: image_rendering, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::Image(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_webgl_canvas(&mut self, + rect: Rect, + clip: ClipRegion, + context_id: WebGLContextId) { + let item = WebGLDisplayItem { + context_id: context_id, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::WebGL(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_text(&mut self, + rect: Rect, + clip: ClipRegion, + glyphs: Vec, + font_key: FontKey, + color: ColorF, + size: Au, + blur_radius: Au, + auxiliary_lists_builder: &mut AuxiliaryListsBuilder) { + // Sanity check - anything with glyphs bigger than this + // is probably going to consume too much memory to render + // efficiently anyway. This is specifically to work around + // the font_advance.html reftest, which creates a very large + // font as a crash test - the rendering is also ignored + // by the azure renderer. + if size < Au::from_px(4096) { + let item = TextDisplayItem { + color: color, + glyphs: auxiliary_lists_builder.add_glyph_instances(&glyphs), + font_key: font_key, + size: size, + blur_radius: blur_radius, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::Text(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + } + + pub fn push_border(&mut self, + rect: Rect, + clip: ClipRegion, + left: BorderSide, + top: BorderSide, + right: BorderSide, + bottom: BorderSide, + radius: BorderRadius) { + let item = BorderDisplayItem { + left: left, + top: top, + right: right, + bottom: bottom, + radius: radius, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::Border(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_box_shadow(&mut self, + rect: Rect, + clip: ClipRegion, + box_bounds: Rect, + offset: Point2D, + color: ColorF, + blur_radius: f32, + spread_radius: f32, + border_radius: f32, + clip_mode: BoxShadowClipMode) { + let item = BoxShadowDisplayItem { + box_bounds: box_bounds, + offset: offset, + color: color, + blur_radius: blur_radius, + spread_radius: spread_radius, + border_radius: border_radius, + clip_mode: clip_mode, + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::BoxShadow(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_stacking_context(&mut self, stacking_context_id: StackingContextId) { + self.has_stacking_contexts = true; + self.flush(); + let info = StackingContextInfo { + id: stacking_context_id, + }; + let item = DisplayListItem { + specific: SpecificDisplayListItem::StackingContext(info), + }; + self.display_list_items.push(item); + } + + pub fn push_gradient(&mut self, + rect: Rect, + clip: ClipRegion, + start_point: Point2D, + end_point: Point2D, + stops: Vec, + auxiliary_lists_builder: &mut AuxiliaryListsBuilder) { + let item = GradientDisplayItem { + start_point: start_point, + end_point: end_point, + stops: auxiliary_lists_builder.add_gradient_stops(&stops), + }; + + let display_item = DisplayItem { + item: SpecificDisplayItem::Gradient(item), + rect: rect, + clip: clip, + }; + + self.push_item(display_item); + } + + pub fn push_iframe(&mut self, + rect: Rect, + clip: ClipRegion, + iframe: PipelineId) { + self.flush(); + let info = IframeInfo { + id: iframe, + bounds: rect, + clip: clip, + }; + let item = DisplayListItem { + specific: SpecificDisplayListItem::Iframe(info), + }; + self.display_list_items.push(item); + } + + fn push_item(&mut self, item: DisplayItem) { + self.work_list.push(item); + } + + fn flush(&mut self) { + let items = mem::replace(&mut self.work_list, Vec::new()); + if items.is_empty() { + return + } + + let draw_list = DrawListInfo { + items: ItemRange::new(&mut self.display_items, &items), + }; + self.display_list_items.push(DisplayListItem { + specific: SpecificDisplayListItem::DrawList(draw_list), + }); + } + + pub fn finalize(mut self) -> BuiltDisplayList { + self.flush(); + + unsafe { + let mut blob = convert_pod_to_blob(&self.display_list_items).to_vec(); + let display_list_items_size = blob.len(); + blob.extend_from_slice(convert_pod_to_blob(&self.display_items)); + let display_items_size = blob.len() - display_list_items_size; + BuiltDisplayList { + descriptor: BuiltDisplayListDescriptor { + mode: self.mode, + has_stacking_contexts: self.has_stacking_contexts, + display_list_items_size: display_list_items_size, + display_items_size: display_items_size, + }, + data: blob, + } + } + } + + pub fn display_items<'a>(&'a self, range: &ItemRange) -> &'a [DisplayItem] { + range.get(&self.display_items) + } + + pub fn display_items_mut<'a>(&'a mut self, range: &ItemRange) -> &'a mut [DisplayItem] { + range.get_mut(&mut self.display_items) + } +} + +impl ItemRange { + pub fn new(backing_list: &mut Vec, items: &[T]) -> ItemRange where T: Copy + Clone { + let start = backing_list.len(); + backing_list.extend_from_slice(items); + ItemRange { + start: start, + length: items.len(), + } + } + + pub fn empty() -> ItemRange { + ItemRange { + start: 0, + length: 0, + } + } + + pub fn get<'a, T>(&self, backing_list: &'a [T]) -> &'a [T] { + &backing_list[self.start..(self.start + self.length)] + } + + pub fn get_mut<'a, T>(&self, backing_list: &'a mut [T]) -> &'a mut [T] { + &mut backing_list[self.start..(self.start + self.length)] + } +} + +#[derive(Clone)] +pub struct AuxiliaryListsBuilder { + gradient_stops: Vec, + complex_clip_regions: Vec, + filters: Vec, + glyph_instances: Vec, +} + +impl AuxiliaryListsBuilder { + pub fn new() -> AuxiliaryListsBuilder { + AuxiliaryListsBuilder { + gradient_stops: Vec::new(), + complex_clip_regions: Vec::new(), + filters: Vec::new(), + glyph_instances: Vec::new(), + } + } + + pub fn add_gradient_stops(&mut self, gradient_stops: &[GradientStop]) -> ItemRange { + ItemRange::new(&mut self.gradient_stops, gradient_stops) + } + + pub fn gradient_stops(&self, gradient_stops_range: &ItemRange) -> &[GradientStop] { + gradient_stops_range.get(&self.gradient_stops[..]) + } + + pub fn add_complex_clip_regions(&mut self, complex_clip_regions: &[ComplexClipRegion]) + -> ItemRange { + ItemRange::new(&mut self.complex_clip_regions, complex_clip_regions) + } + + pub fn complex_clip_regions(&self, complex_clip_regions_range: &ItemRange) + -> &[ComplexClipRegion] { + complex_clip_regions_range.get(&self.complex_clip_regions[..]) + } + + pub fn add_filters(&mut self, filters: &[FilterOp]) -> ItemRange { + ItemRange::new(&mut self.filters, filters) + } + + pub fn filters(&self, filters_range: &ItemRange) -> &[FilterOp] { + filters_range.get(&self.filters[..]) + } + + pub fn add_glyph_instances(&mut self, glyph_instances: &[GlyphInstance]) -> ItemRange { + ItemRange::new(&mut self.glyph_instances, glyph_instances) + } + + pub fn glyph_instances(&self, glyph_instances_range: &ItemRange) -> &[GlyphInstance] { + glyph_instances_range.get(&self.glyph_instances[..]) + } + + pub fn finalize(self) -> AuxiliaryLists { + unsafe { + let mut blob = convert_pod_to_blob(&self.gradient_stops).to_vec(); + let gradient_stops_size = blob.len(); + blob.extend_from_slice(convert_pod_to_blob(&self.complex_clip_regions)); + let complex_clip_regions_size = blob.len() - gradient_stops_size; + blob.extend_from_slice(convert_pod_to_blob(&self.filters)); + let filters_size = blob.len() - (complex_clip_regions_size + gradient_stops_size); + blob.extend_from_slice(convert_pod_to_blob(&self.glyph_instances)); + let glyph_instances_size = blob.len() - + (complex_clip_regions_size + gradient_stops_size + filters_size); + + AuxiliaryLists { + data: blob, + descriptor: AuxiliaryListsDescriptor { + gradient_stops_size: gradient_stops_size, + complex_clip_regions_size: complex_clip_regions_size, + filters_size: filters_size, + glyph_instances_size: glyph_instances_size, + }, + } + } + } +} + +impl AuxiliaryListsDescriptor { + pub fn size(&self) -> usize { + self.gradient_stops_size + self.complex_clip_regions_size + self.filters_size + + self.glyph_instances_size + } +} + +impl AuxiliaryLists { + /// Creates a new `AuxiliaryLists` instance from a descriptor and data received over a channel. + pub fn from_data(data: Vec, descriptor: AuxiliaryListsDescriptor) -> AuxiliaryLists { + AuxiliaryLists { + data: data, + descriptor: descriptor, + } + } + + pub fn data(&self) -> &[u8] { + &self.data[..] + } + + pub fn descriptor(&self) -> &AuxiliaryListsDescriptor { + &self.descriptor + } + + /// Returns the gradient stops described by `gradient_stops_range`. + pub fn gradient_stops(&self, gradient_stops_range: &ItemRange) -> &[GradientStop] { + unsafe { + let end = self.descriptor.gradient_stops_size; + gradient_stops_range.get(convert_blob_to_pod(&self.data[0..end])) + } + } + + /// Returns the complex clipping regions described by `complex_clip_regions_range`. + pub fn complex_clip_regions(&self, complex_clip_regions_range: &ItemRange) + -> &[ComplexClipRegion] { + let start = self.descriptor.gradient_stops_size; + let end = start + self.descriptor.complex_clip_regions_size; + unsafe { + complex_clip_regions_range.get(convert_blob_to_pod(&self.data[start..end])) + } + } + + /// Returns the filters described by `filters_range`. + pub fn filters(&self, filters_range: &ItemRange) -> &[FilterOp] { + let start = self.descriptor.gradient_stops_size + + self.descriptor.complex_clip_regions_size; + let end = start + self.descriptor.filters_size; + unsafe { + filters_range.get(convert_blob_to_pod(&self.data[start..end])) + } + } + + /// Returns the glyph instances described by `glyph_instances_range`. + pub fn glyph_instances(&self, glyph_instances_range: &ItemRange) -> &[GlyphInstance] { + let start = self.descriptor.gradient_stops_size + + self.descriptor.complex_clip_regions_size + self.descriptor.filters_size; + unsafe { + glyph_instances_range.get(convert_blob_to_pod(&self.data[start..])) + } + } +} + +unsafe fn convert_pod_to_blob(data: &[T]) -> &[u8] where T: Copy + 'static { + slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) +} + +unsafe fn convert_blob_to_pod(blob: &[u8]) -> &[T] where T: Copy + 'static { + slice::from_raw_parts(blob.as_ptr() as *const T, blob.len() / mem::size_of::()) +} + diff --git a/webrender_traits/src/lib.rs b/webrender_traits/src/lib.rs new file mode 100644 index 0000000000..a26813a181 --- /dev/null +++ b/webrender_traits/src/lib.rs @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![cfg_attr(feature = "nightly", feature(nonzero))] +#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))] +#![cfg_attr(feature = "serde_macros", plugin(serde_macros))] + +extern crate app_units; +extern crate byteorder; +#[cfg(feature = "nightly")] +extern crate core; +extern crate euclid; +extern crate gleam; +extern crate heapsize; +extern crate ipc_channel; +extern crate offscreen_gl_context; +extern crate serde; + +#[cfg(target_os = "macos")] extern crate core_graphics; + +#[cfg(feature = "serde_codegen")] +include!(concat!(env!("OUT_DIR"), "/types.rs")); + +#[cfg(feature = "serde_macros")] +include!("types.rs"); + +mod api; +mod display_item; +mod display_list; +mod stacking_context; +mod webgl; + +pub use api::RenderApi; +pub use display_list::{AuxiliaryListsBuilder, DisplayListBuilder}; diff --git a/webrender_traits/src/stacking_context.rs b/webrender_traits/src/stacking_context.rs new file mode 100644 index 0000000000..1ad24417dc --- /dev/null +++ b/webrender_traits/src/stacking_context.rs @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use display_list::AuxiliaryListsBuilder; +use euclid::{Matrix4D, Rect}; +use {FilterOp, MixBlendMode, ScrollLayerId, ScrollPolicy}; +use {ServoStackingContextId, StackingContext}; + +impl StackingContext { + pub fn new(servo_id: ServoStackingContextId, + scroll_layer_id: Option, + scroll_policy: ScrollPolicy, + bounds: Rect, + overflow: Rect, + z_index: i32, + transform: &Matrix4D, + perspective: &Matrix4D, + establishes_3d_context: bool, + mix_blend_mode: MixBlendMode, + filters: Vec, + auxiliary_lists_builder: &mut AuxiliaryListsBuilder) + -> StackingContext { + StackingContext { + servo_id: servo_id, + scroll_layer_id: scroll_layer_id, + scroll_policy: scroll_policy, + bounds: bounds, + overflow: overflow, + z_index: z_index, + display_lists: Vec::new(), + transform: transform.clone(), + perspective: perspective.clone(), + establishes_3d_context: establishes_3d_context, + mix_blend_mode: mix_blend_mode, + filters: auxiliary_lists_builder.add_filters(&filters), + has_stacking_contexts: false, + } + } +} diff --git a/webrender_traits/src/types.rs b/webrender_traits/src/types.rs new file mode 100644 index 0000000000..0e4e81b9a3 --- /dev/null +++ b/webrender_traits/src/types.rs @@ -0,0 +1,669 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Every serialisable type is defined in this file to only codegen one file +// for the serde implementations. + +use app_units::Au; +#[cfg(feature = "nightly")] +use core::nonzero::NonZero; +use euclid::{Matrix4D, Point2D, Rect, Size2D}; +use ipc_channel::ipc::{IpcBytesSender, IpcSender}; +use offscreen_gl_context::{GLContextAttributes, GLLimits}; + +#[cfg(target_os = "macos")] use core_graphics::font::CGFont; + +#[derive(Deserialize, Serialize)] +pub enum ApiMsg { + AddRawFont(FontKey, Vec), + AddNativeFont(FontKey, NativeFontHandle), + /// Adds an image from the resource cache. + AddImage(ImageKey, u32, u32, ImageFormat, Vec), + /// Updates the the resource cache with the new image data. + UpdateImage(ImageKey, u32, u32, ImageFormat, Vec), + /// Drops an image from the resource cache. + DeleteImage(ImageKey), + CloneApi(IpcSender), + /// Supplies a new frame to WebRender. + /// + /// The first `StackingContextId` describes the root stacking context. The actual stacking + /// contexts are supplied as the sixth parameter, while the display lists that make up those + /// stacking contexts are supplied as the seventh parameter. + /// + /// After receiving this message, WebRender will read the display lists, followed by the + /// auxiliary lists, from the payload channel. + SetRootStackingContext(StackingContextId, + ColorF, + Epoch, + PipelineId, + Size2D, + Vec<(StackingContextId, StackingContext)>, + Vec<(DisplayListId, BuiltDisplayListDescriptor)>, + AuxiliaryListsDescriptor), + SetRootPipeline(PipelineId), + Scroll(Point2D, Point2D, ScrollEventPhase), + TickScrollingBounce, + TranslatePointToLayerSpace(Point2D, IpcSender<(Point2D, PipelineId)>), + GetScrollLayerState(IpcSender>), + RequestWebGLContext(Size2D, GLContextAttributes, IpcSender>), + WebGLCommand(WebGLContextId, WebGLCommand), +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct AuxiliaryLists { + /// The concatenation of: gradient stops, complex clip regions, filters, and glyph instances, + /// in that order. + data: Vec, + descriptor: AuxiliaryListsDescriptor, +} + +/// Describes the memory layout of the auxiliary lists. +/// +/// Auxiliary lists consist of some number of gradient stops, complex clip regions, filters, and +/// glyph instances, in that order. +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct AuxiliaryListsDescriptor { + gradient_stops_size: usize, + complex_clip_regions_size: usize, + filters_size: usize, + glyph_instances_size: usize, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct BorderDisplayItem { + pub left: BorderSide, + pub right: BorderSide, + pub top: BorderSide, + pub bottom: BorderSide, + pub radius: BorderRadius, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct BorderRadius { + pub top_left: Size2D, + pub top_right: Size2D, + pub bottom_left: Size2D, + pub bottom_right: Size2D, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct BorderSide { + pub width: f32, + pub color: ColorF, + pub style: BorderStyle, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum BorderStyle { + None, + Solid, + Double, + Dotted, + Dashed, + Hidden, + Groove, + Ridge, + Inset, + Outset, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum BoxShadowClipMode { + None, + Outset, + Inset, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct BoxShadowDisplayItem { + pub box_bounds: Rect, + pub offset: Point2D, + pub color: ColorF, + pub blur_radius: f32, + pub spread_radius: f32, + pub border_radius: f32, + pub clip_mode: BoxShadowClipMode, +} + +/// A display list. +#[derive(Clone, Deserialize, Serialize)] +pub struct BuiltDisplayList { + data: Vec, + descriptor: BuiltDisplayListDescriptor, +} + +/// Describes the memory layout of a display list. +/// +/// A display list consists of some number of display list items, followed by a number of display +/// items. +#[derive(Copy, Clone, Deserialize, Serialize)] +pub struct BuiltDisplayListDescriptor { + pub mode: DisplayListMode, + pub has_stacking_contexts: bool, + + /// The size in bytes of the display list items in this display list. + display_list_items_size: usize, + /// The size in bytes of the display items in this display list. + display_items_size: usize, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct ColorF { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct ClipRegion { + pub main: Rect, + pub complex: ItemRange, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct ComplexClipRegion { + /// The boundaries of the rectangle. + pub rect: Rect, + /// Border radii of this rectangle. + pub radii: BorderRadius, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct DisplayItem { + pub item: SpecificDisplayItem, + pub rect: Rect, + pub clip: ClipRegion, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct DisplayListId(pub u32, pub u32); + +#[derive(Clone, Copy, Deserialize, Serialize)] +pub struct DisplayListItem { + pub specific: SpecificDisplayListItem, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum DisplayListMode { + Default, + PseudoFloat, + PseudoPositionedContent, +} + +#[derive(Clone, Copy, Deserialize, Serialize)] +pub struct DrawListInfo { + pub items: ItemRange, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub struct Epoch(pub u32); + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub enum FilterOp { + Blur(Au), + Brightness(f32), + Contrast(f32), + Grayscale(f32), + HueRotate(f32), + Invert(f32), + Opacity(f32), + Saturate(f32), + Sepia(f32), +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct FontKey(u32, u32); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum FragmentType { + FragmentBody, + BeforePseudoContent, + AfterPseudoContent, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct GlyphInstance { + pub index: u32, + pub x: f32, + pub y: f32, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct GradientDisplayItem { + pub start_point: Point2D, + pub end_point: Point2D, + pub stops: ItemRange, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct GradientStop { + pub offset: f32, + pub color: ColorF, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct IdNamespace(pub u32); + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct IframeInfo { + pub id: PipelineId, + pub bounds: Rect, + pub clip: ClipRegion, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct ImageDisplayItem { + pub image_key: ImageKey, + pub stretch_size: Size2D, + pub image_rendering: ImageRendering, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum ImageFormat { + Invalid, + A8, + RGB8, + RGBA8, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct ImageKey(u32, u32); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum ImageRendering { + Auto, + CrispEdges, + Pixelated, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct ItemRange { + pub start: usize, + pub length: usize, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum MixBlendMode { + Normal, + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + HardLight, + SoftLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, +} + +#[cfg(target_os = "macos")] +pub type NativeFontHandle = CGFont; + +/// Native fonts are not used on Linux; all fonts are raw. +#[cfg(not(target_os = "macos"))] +#[cfg_attr(not(target_os = "macos"), derive(Clone, Serialize, Deserialize))] +pub struct NativeFontHandle; + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct PipelineId(pub u32, pub u32); + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct RectangleDisplayItem { + pub color: ColorF, +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct RenderApiSender { + api_sender: IpcSender, + payload_sender: IpcBytesSender, +} + +pub trait RenderNotifier: Send { + fn new_frame_ready(&mut self); + fn new_scroll_frame_ready(&mut self, composite_needed: bool); + fn pipeline_size_changed(&mut self, pipeline_id: PipelineId, size: Option>); +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct ResourceId(pub u32); + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum ScrollEventPhase { + /// The user started scrolling. + Start, + /// The user performed a scroll. The Boolean flag indicates whether the user's fingers are + /// down, if a touchpad is in use. (If false, the event is a touchpad fling.) + Move(bool), + /// The user ended scrolling. + End, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct ScrollLayerId { + pub pipeline_id: PipelineId, + pub info: ScrollLayerInfo, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum ScrollLayerInfo { + Fixed, + Scrollable(usize) +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct ScrollLayerState { + pub pipeline_id: PipelineId, + pub stacking_context_id: ServoStackingContextId, + pub scroll_offset: Point2D, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum ScrollPolicy { + Scrollable, + Fixed, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct ServoStackingContextId(pub FragmentType, pub usize); + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum SpecificDisplayItem { + Rectangle(RectangleDisplayItem), + Text(TextDisplayItem), + Image(ImageDisplayItem), + WebGL(WebGLDisplayItem), + Border(BorderDisplayItem), + BoxShadow(BoxShadowDisplayItem), + Gradient(GradientDisplayItem), +} + +#[derive(Clone, Copy, Deserialize, Serialize)] +pub enum SpecificDisplayListItem { + DrawList(DrawListInfo), + StackingContext(StackingContextInfo), + Iframe(IframeInfo), +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct StackingContext { + pub servo_id: ServoStackingContextId, + pub scroll_layer_id: Option, + pub scroll_policy: ScrollPolicy, + pub bounds: Rect, + pub overflow: Rect, + pub z_index: i32, + pub display_lists: Vec, + pub transform: Matrix4D, + pub perspective: Matrix4D, + pub establishes_3d_context: bool, + pub mix_blend_mode: MixBlendMode, + pub filters: ItemRange, + pub has_stacking_contexts: bool, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct StackingContextId(pub u32, pub u32); + +#[derive(Clone, Copy, Deserialize, Serialize)] +pub struct StackingContextInfo { + pub id: StackingContextId, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct TextDisplayItem { + pub glyphs: ItemRange, + pub font_key: FontKey, + pub size: Au, + pub color: ColorF, + pub blur_radius: Au, +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLCommand { + GetContextAttributes(IpcSender), + ActiveTexture(u32), + BlendColor(f32, f32, f32, f32), + BlendEquation(u32), + BlendEquationSeparate(u32, u32), + BlendFunc(u32, u32), + BlendFuncSeparate(u32, u32, u32, u32), + AttachShader(WebGLProgramId, WebGLShaderId), + DetachShader(WebGLProgramId, WebGLShaderId), + BindAttribLocation(WebGLProgramId, u32, String), + BufferData(u32, Vec, u32), + BufferSubData(u32, isize, Vec), + Clear(u32), + ClearColor(f32, f32, f32, f32), + ClearDepth(f64), + ClearStencil(i32), + ColorMask(bool, bool, bool, bool), + CullFace(u32), + FrontFace(u32), + DepthFunc(u32), + DepthMask(bool), + DepthRange(f64, f64), + Enable(u32), + Disable(u32), + CompileShader(WebGLShaderId, String), + CopyTexImage2D(u32, i32, u32, i32, i32, i32, i32, i32), + CopyTexSubImage2D(u32, i32, i32, i32, i32, i32, i32, i32), + CreateBuffer(IpcSender>), + CreateFramebuffer(IpcSender>), + CreateRenderbuffer(IpcSender>), + CreateTexture(IpcSender>), + CreateProgram(IpcSender>), + CreateShader(u32, IpcSender>), + DeleteBuffer(WebGLBufferId), + DeleteFramebuffer(WebGLFramebufferId), + DeleteRenderbuffer(WebGLRenderbufferId), + DeleteTexture(WebGLTextureId), + DeleteProgram(WebGLProgramId), + DeleteShader(WebGLShaderId), + BindBuffer(u32, Option), + BindFramebuffer(u32, WebGLFramebufferBindingRequest), + BindRenderbuffer(u32, Option), + BindTexture(u32, Option), + DrawArrays(u32, i32, i32), + DrawElements(u32, i32, u32, i64), + EnableVertexAttribArray(u32), + GetBufferParameter(u32, u32, IpcSender>), + GetParameter(u32, IpcSender>), + GetProgramParameter(WebGLProgramId, u32, IpcSender>), + GetShaderParameter(WebGLShaderId, u32, IpcSender>), + GetActiveAttrib(WebGLProgramId, u32, IpcSender>), + GetActiveUniform(WebGLProgramId, u32, IpcSender>), + GetAttribLocation(WebGLProgramId, String, IpcSender>), + GetUniformLocation(WebGLProgramId, String, IpcSender>), + GetVertexAttrib(u32, u32, IpcSender>), + PolygonOffset(f32, f32), + ReadPixels(i32, i32, i32, i32, u32, u32, IpcSender>), + SampleCoverage(f32, bool), + Scissor(i32, i32, i32, i32), + StencilFunc(u32, i32, u32), + StencilFuncSeparate(u32, u32, i32, u32), + StencilMask(u32), + StencilMaskSeparate(u32, u32), + StencilOp(u32, u32, u32), + StencilOpSeparate(u32, u32, u32, u32), + Hint(u32, u32), + LineWidth(f32), + PixelStorei(u32, i32), + LinkProgram(WebGLProgramId), + Uniform1f(i32, f32), + Uniform1fv(i32, Vec), + Uniform1i(i32, i32), + Uniform1iv(i32, Vec), + Uniform2f(i32, f32, f32), + Uniform2fv(i32, Vec), + Uniform2i(i32, i32, i32), + Uniform2iv(i32, Vec), + Uniform3f(i32, f32, f32, f32), + Uniform3fv(i32, Vec), + Uniform3i(i32, i32, i32, i32), + Uniform3iv(i32, Vec), + Uniform4f(i32, f32, f32, f32, f32), + Uniform4fv(i32, Vec), + Uniform4i(i32, i32, i32, i32, i32), + Uniform4iv(i32, Vec), + UniformMatrix2fv(i32, bool, Vec), + UniformMatrix3fv(i32, bool, Vec), + UniformMatrix4fv(i32, bool, Vec), + UseProgram(WebGLProgramId), + VertexAttrib(u32, f32, f32, f32, f32), + VertexAttribPointer2f(u32, i32, bool, i32, u32), + Viewport(i32, i32, i32, i32), + TexImage2D(u32, i32, i32, i32, i32, u32, u32, Vec), + TexParameteri(u32, u32, i32), + TexParameterf(u32, u32, f32), + TexSubImage2D(u32, i32, i32, i32, i32, i32, u32, u32, Vec), + DrawingBufferWidth(IpcSender), + DrawingBufferHeight(IpcSender), + Finish(IpcSender<()>), + Flush, + GenerateMipmap(u32), +} + +#[cfg(feature = "nightly")] +macro_rules! define_resource_id_struct { + ($name:ident) => { + #[derive(Clone, Copy, PartialEq)] + pub struct $name(NonZero); + + impl $name { + #[inline] + unsafe fn new(id: u32) -> Self { + $name(NonZero::new(id)) + } + + #[inline] + fn get(self) -> u32 { + *self.0 + } + } + + }; +} + +#[cfg(not(feature = "nightly"))] +macro_rules! define_resource_id_struct { + ($name:ident) => { + #[derive(Clone, Copy, PartialEq)] + pub struct $name(u32); + + impl $name { + #[inline] + unsafe fn new(id: u32) -> Self { + $name(id) + } + + #[inline] + fn get(self) -> u32 { + self.0 + } + } + }; +} + +macro_rules! define_resource_id { + ($name:ident) => { + define_resource_id_struct!($name); + + impl ::serde::Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result + where D: ::serde::Deserializer + { + let id = try!(u32::deserialize(deserializer)); + if id == 0 { + Err(::serde::Error::invalid_value("expected a non-zero value")) + } else { + Ok(unsafe { $name::new(id) }) + } + } + } + + impl ::serde::Serialize for $name { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + self.get().serialize(serializer) + } + } + + impl ::std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + fmt.debug_tuple(stringify!($name)) + .field(&self.get()) + .finish() + } + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + write!(fmt, "{}", self.get()) + } + } + + impl ::heapsize::HeapSizeOf for $name { + fn heap_size_of_children(&self) -> usize { 0 } + } + } +} + +define_resource_id!(WebGLBufferId); +define_resource_id!(WebGLFramebufferId); +define_resource_id!(WebGLRenderbufferId); +define_resource_id!(WebGLTextureId); +define_resource_id!(WebGLProgramId); +define_resource_id!(WebGLShaderId); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub struct WebGLContextId(pub usize); + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct WebGLDisplayItem { + pub context_id: WebGLContextId, +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum WebGLError { + InvalidEnum, + InvalidOperation, + InvalidValue, + OutOfMemory, + ContextLost, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLFramebufferBindingRequest { + Explicit(WebGLFramebufferId), + Default, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLParameter { + Int(i32), + Bool(bool), + String(String), + Float(f32), + FloatArray(Vec), + Invalid, +} + +pub type WebGLResult = Result; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLShaderParameter { + Int(i32), + Bool(bool), + Invalid, +} diff --git a/webrender_traits/src/webgl.rs b/webrender_traits/src/webgl.rs new file mode 100644 index 0000000000..94d3cfd021 --- /dev/null +++ b/webrender_traits/src/webgl.rs @@ -0,0 +1,670 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use gleam::gl; +use ipc_channel::ipc::IpcSender; +use offscreen_gl_context::{GLContext, NativeGLContextMethods}; +use std::fmt; +use {WebGLBufferId, WebGLCommand, WebGLError, WebGLFramebufferBindingRequest}; +use {WebGLFramebufferId, WebGLParameter, WebGLProgramId, WebGLRenderbufferId}; +use {WebGLResult, WebGLShaderId, WebGLTextureId}; + +impl fmt::Debug for WebGLCommand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use WebGLCommand::*; + let name = match *self { + GetContextAttributes(..) => "GetContextAttributes", + ActiveTexture(..) => "ActiveTexture", + BlendColor(..) => "BlendColor", + BlendEquation(..) => "BlendEquation", + BlendEquationSeparate(..) => "BlendEquationSeparate", + BlendFunc(..) => "BlendFunc", + BlendFuncSeparate(..) => "BlendFuncSeparate", + AttachShader(..) => "AttachShader", + DetachShader(..) => "DetachShader", + BindAttribLocation(..) => "BindAttribLocation", + BufferData(..) => "BufferData", + BufferSubData(..) => "BufferSubData", + Clear(..) => "Clear", + ClearColor(..) => "ClearColor", + ClearDepth(..) => "ClearDepth", + ClearStencil(..) => "ClearStencil", + ColorMask(..) => "ColorMask", + CopyTexImage2D(..) => "CopyTexImage2D", + CopyTexSubImage2D(..) => "CopyTexSubImage2D", + CullFace(..) => "CullFace", + FrontFace(..) => "FrontFace", + DepthFunc(..) => "DepthFunc", + DepthMask(..) => "DepthMask", + DepthRange(..) => "DepthRange", + Enable(..) => "Enable", + Disable(..) => "Disable", + CompileShader(..) => "CompileShader", + CreateBuffer(..) => "CreateBuffer", + CreateFramebuffer(..) => "CreateFramebuffer", + CreateRenderbuffer(..) => "CreateRenderbuffer", + CreateTexture(..) => "CreateTexture", + CreateProgram(..) => "CreateProgram", + CreateShader(..) => "CreateShader", + DeleteBuffer(..) => "DeleteBuffer", + DeleteFramebuffer(..) => "DeleteFramebuffer", + DeleteRenderbuffer(..) => "DeleteRenderBuffer", + DeleteTexture(..) => "DeleteTexture", + DeleteProgram(..) => "DeleteProgram", + DeleteShader(..) => "DeleteShader", + BindBuffer(..) => "BindBuffer", + BindFramebuffer(..) => "BindFramebuffer", + BindRenderbuffer(..) => "BindRenderbuffer", + BindTexture(..) => "BindTexture", + DrawArrays(..) => "DrawArrays", + DrawElements(..) => "DrawElements", + EnableVertexAttribArray(..) => "EnableVertexAttribArray", + GetBufferParameter(..) => "GetBufferParameter", + GetParameter(..) => "GetParameter", + GetProgramParameter(..) => "GetProgramParameter", + GetShaderParameter(..) => "GetShaderParameter", + GetActiveAttrib(..) => "GetActiveAttrib", + GetActiveUniform(..) => "GetActiveUniform", + GetAttribLocation(..) => "GetAttribLocation", + GetUniformLocation(..) => "GetUniformLocation", + GetVertexAttrib(..) => "GetVertexAttrib", + PolygonOffset(..) => "PolygonOffset", + ReadPixels(..) => "ReadPixels", + SampleCoverage(..) => "SampleCoverage", + Scissor(..) => "Scissor", + StencilFunc(..) => "StencilFunc", + StencilFuncSeparate(..) => "StencilFuncSeparate", + StencilMask(..) => "StencilMask", + StencilMaskSeparate(..) => "StencilMaskSeparate", + StencilOp(..) => "StencilOp", + StencilOpSeparate(..) => "StencilOpSeparate", + Hint(..) => "Hint", + LineWidth(..) => "LineWidth", + PixelStorei(..) => "PixelStorei", + LinkProgram(..) => "LinkProgram", + Uniform1f(..) => "Uniform1f", + Uniform1fv(..) => "Uniform1fv", + Uniform1i(..) => "Uniform1i", + Uniform1iv(..) => "Uniform1iv", + Uniform2f(..) => "Uniform2f", + Uniform2fv(..) => "Uniform2fv", + Uniform2i(..) => "Uniform2i", + Uniform2iv(..) => "Uniform2iv", + Uniform3f(..) => "Uniform3f", + Uniform3fv(..) => "Uniform3fv", + Uniform3i(..) => "Uniform3i", + Uniform3iv(..) => "Uniform3iv", + Uniform4f(..) => "Uniform4f", + Uniform4fv(..) => "Uniform4fv", + Uniform4i(..) => "Uniform4i", + Uniform4iv(..) => "Uniform4iv", + UniformMatrix2fv(..) => "UniformMatrix2fv", + UniformMatrix3fv(..) => "UniformMatrix3fv", + UniformMatrix4fv(..) => "UniformMatrix4fv", + UseProgram(..) => "UseProgram", + VertexAttrib(..) => "VertexAttrib", + VertexAttribPointer2f(..) => "VertexAttribPointer2f", + Viewport(..) => "Viewport", + TexImage2D(..) => "TexImage2D", + TexParameteri(..) => "TexParameteri", + TexParameterf(..) => "TexParameterf", + TexSubImage2D(..) => "TexSubImage2D", + DrawingBufferWidth(..) => "DrawingBufferWidth", + DrawingBufferHeight(..) => "DrawingBufferHeight", + Finish(..) => "Finish", + Flush => "Flush", + GenerateMipmap(..) => "GenerateMipmap", + }; + + write!(f, "CanvasWebGLMsg::{}(..)", name) + } +} + +impl WebGLCommand { + /// NOTE: This method consumes the command + pub fn apply(self, ctx: &GLContext) { + match self { + WebGLCommand::GetContextAttributes(sender) => + sender.send(*ctx.borrow_attributes()).unwrap(), + WebGLCommand::ActiveTexture(target) => + gl::active_texture(target), + WebGLCommand::AttachShader(program_id, shader_id) => + gl::attach_shader(program_id.get(), shader_id.get()), + WebGLCommand::DetachShader(program_id, shader_id) => + gl::detach_shader(program_id.get(), shader_id.get()), + WebGLCommand::BindAttribLocation(program_id, index, name) => + gl::bind_attrib_location(program_id.get(), index, &name), + WebGLCommand::BlendColor(r, g, b, a) => + gl::blend_color(r, g, b, a), + WebGLCommand::BlendEquation(mode) => + gl::blend_equation(mode), + WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) => + gl::blend_equation_separate(mode_rgb, mode_alpha), + WebGLCommand::BlendFunc(src, dest) => + gl::blend_func(src, dest), + WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => + gl::blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha), + WebGLCommand::BufferData(buffer_type, data, usage) => + gl::buffer_data(buffer_type, &data, usage), + WebGLCommand::BufferSubData(buffer_type, offset, data) => + gl::buffer_sub_data(buffer_type, offset, &data), + WebGLCommand::Clear(mask) => + gl::clear(mask), + WebGLCommand::ClearColor(r, g, b, a) => + gl::clear_color(r, g, b, a), + WebGLCommand::ClearDepth(depth) => + gl::clear_depth(depth), + WebGLCommand::ClearStencil(stencil) => + gl::clear_stencil(stencil), + WebGLCommand::ColorMask(r, g, b, a) => + gl::color_mask(r, g, b, a), + WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y, width, height, border) => + gl::copy_tex_image_2d(target, level, internal_format, x, y, width, height, border), + WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) => + gl::copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height), + WebGLCommand::CullFace(mode) => + gl::cull_face(mode), + WebGLCommand::DepthFunc(func) => + gl::depth_func(func), + WebGLCommand::DepthMask(flag) => + gl::depth_mask(flag), + WebGLCommand::DepthRange(near, far) => + gl::depth_range(near, far), + WebGLCommand::Disable(cap) => + gl::disable(cap), + WebGLCommand::Enable(cap) => + gl::enable(cap), + WebGLCommand::FrontFace(mode) => + gl::front_face(mode), + WebGLCommand::DrawArrays(mode, first, count) => + gl::draw_arrays(mode, first, count), + WebGLCommand::DrawElements(mode, count, type_, offset) => + gl::draw_elements(mode, count, type_, offset as u32), + WebGLCommand::EnableVertexAttribArray(attrib_id) => + gl::enable_vertex_attrib_array(attrib_id), + WebGLCommand::Hint(name, val) => + gl::hint(name, val), + WebGLCommand::LineWidth(width) => + gl::line_width(width), + WebGLCommand::PixelStorei(name, val) => + gl::pixel_store_i(name, val), + WebGLCommand::PolygonOffset(factor, units) => + gl::polygon_offset(factor, units), + WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, chan) => + Self::read_pixels(x, y, width, height, format, pixel_type, chan), + WebGLCommand::SampleCoverage(value, invert) => + gl::sample_coverage(value, invert), + WebGLCommand::Scissor(x, y, width, height) => + gl::scissor(x, y, width, height), + WebGLCommand::StencilFunc(func, ref_, mask) => + gl::stencil_func(func, ref_, mask), + WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => + gl::stencil_func_separate(face, func, ref_, mask), + WebGLCommand::StencilMask(mask) => + gl::stencil_mask(mask), + WebGLCommand::StencilMaskSeparate(face, mask) => + gl::stencil_mask_separate(face, mask), + WebGLCommand::StencilOp(fail, zfail, zpass) => + gl::stencil_op(fail, zfail, zpass), + WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => + gl::stencil_op_separate(face, fail, zfail, zpass), + WebGLCommand::GetActiveAttrib(program_id, index, chan) => + Self::active_attrib(program_id, index, chan), + WebGLCommand::GetActiveUniform(program_id, index, chan) => + Self::active_uniform(program_id, index, chan), + WebGLCommand::GetAttribLocation(program_id, name, chan) => + Self::attrib_location(program_id, name, chan), + WebGLCommand::GetVertexAttrib(index, pname, chan) => + Self::vertex_attrib(index, pname, chan), + WebGLCommand::GetBufferParameter(target, param_id, chan) => + Self::buffer_parameter(target, param_id, chan), + WebGLCommand::GetParameter(param_id, chan) => + Self::parameter(param_id, chan), + WebGLCommand::GetProgramParameter(program_id, param_id, chan) => + Self::program_parameter(program_id, param_id, chan), + WebGLCommand::GetShaderParameter(shader_id, param_id, chan) => + Self::shader_parameter(shader_id, param_id, chan), + WebGLCommand::GetUniformLocation(program_id, name, chan) => + Self::uniform_location(program_id, name, chan), + WebGLCommand::CompileShader(shader_id, source) => + Self::compile_shader(shader_id, source), + WebGLCommand::CreateBuffer(chan) => + Self::create_buffer(chan), + WebGLCommand::CreateFramebuffer(chan) => + Self::create_framebuffer(chan), + WebGLCommand::CreateRenderbuffer(chan) => + Self::create_renderbuffer(chan), + WebGLCommand::CreateTexture(chan) => + Self::create_texture(chan), + WebGLCommand::CreateProgram(chan) => + Self::create_program(chan), + WebGLCommand::CreateShader(shader_type, chan) => + Self::create_shader(shader_type, chan), + WebGLCommand::DeleteBuffer(id) => + gl::delete_buffers(&[id.get()]), + WebGLCommand::DeleteFramebuffer(id) => + gl::delete_framebuffers(&[id.get()]), + WebGLCommand::DeleteRenderbuffer(id) => + gl::delete_renderbuffers(&[id.get()]), + WebGLCommand::DeleteTexture(id) => + gl::delete_textures(&[id.get()]), + WebGLCommand::DeleteProgram(id) => + gl::delete_program(id.get()), + WebGLCommand::DeleteShader(id) => + gl::delete_shader(id.get()), + WebGLCommand::BindBuffer(target, id) => + gl::bind_buffer(target, id.map_or(0, WebGLBufferId::get)), + WebGLCommand::BindFramebuffer(target, request) => + Self::bind_framebuffer(target, request, ctx), + WebGLCommand::BindRenderbuffer(target, id) => + gl::bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)), + WebGLCommand::BindTexture(target, id) => + gl::bind_texture(target, id.map_or(0, WebGLTextureId::get)), + WebGLCommand::LinkProgram(program_id) => + gl::link_program(program_id.get()), + WebGLCommand::Uniform1f(uniform_id, v) => + gl::uniform_1f(uniform_id, v), + WebGLCommand::Uniform1fv(uniform_id, v) => + gl::uniform_1fv(uniform_id, &v), + WebGLCommand::Uniform1i(uniform_id, v) => + gl::uniform_1i(uniform_id, v), + WebGLCommand::Uniform1iv(uniform_id, v) => + gl::uniform_1iv(uniform_id, &v), + WebGLCommand::Uniform2f(uniform_id, x, y) => + gl::uniform_2f(uniform_id, x, y), + WebGLCommand::Uniform2fv(uniform_id, v) => + gl::uniform_2fv(uniform_id, &v), + WebGLCommand::Uniform2i(uniform_id, x, y) => + gl::uniform_2i(uniform_id, x, y), + WebGLCommand::Uniform2iv(uniform_id, v) => + gl::uniform_2iv(uniform_id, &v), + WebGLCommand::Uniform3f(uniform_id, x, y, z) => + gl::uniform_3f(uniform_id, x, y, z), + WebGLCommand::Uniform3fv(uniform_id, v) => + gl::uniform_3fv(uniform_id, &v), + WebGLCommand::Uniform3i(uniform_id, x, y, z) => + gl::uniform_3i(uniform_id, x, y, z), + WebGLCommand::Uniform3iv(uniform_id, v) => + gl::uniform_3iv(uniform_id, &v), + WebGLCommand::Uniform4f(uniform_id, x, y, z, w) => + gl::uniform_4f(uniform_id, x, y, z, w), + WebGLCommand::Uniform4fv(uniform_id, v) => + gl::uniform_4fv(uniform_id, &v), + WebGLCommand::Uniform4i(uniform_id, x, y, z, w) => + gl::uniform_4i(uniform_id, x, y, z, w), + WebGLCommand::Uniform4iv(uniform_id, v) => + gl::uniform_4iv(uniform_id, &v), + WebGLCommand::UniformMatrix2fv(uniform_id, transpose, v) => + gl::uniform_matrix_2fv(uniform_id, transpose, &v), + WebGLCommand::UniformMatrix3fv(uniform_id, transpose, v) => + gl::uniform_matrix_3fv(uniform_id, transpose, &v), + WebGLCommand::UniformMatrix4fv(uniform_id, transpose, v) => + gl::uniform_matrix_4fv(uniform_id, transpose, &v), + WebGLCommand::UseProgram(program_id) => + gl::use_program(program_id.get()), + WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => + gl::vertex_attrib_4f(attrib_id, x, y, z, w), + WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => + gl::vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset), + WebGLCommand::Viewport(x, y, width, height) => + gl::viewport(x, y, width, height), + WebGLCommand::TexImage2D(target, level, internal, width, height, format, data_type, data) => + gl::tex_image_2d(target, level, internal, width, height, /*border*/0, format, data_type, Some(&data)), + WebGLCommand::TexParameteri(target, name, value) => + gl::tex_parameter_i(target, name, value), + WebGLCommand::TexParameterf(target, name, value) => + gl::tex_parameter_f(target, name, value), + WebGLCommand::TexSubImage2D(target, level, xoffset, yoffset, x, y, width, height, data) => + gl::tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height, &data), + WebGLCommand::DrawingBufferWidth(sender) => + sender.send(ctx.borrow_draw_buffer().unwrap().size().width).unwrap(), + WebGLCommand::DrawingBufferHeight(sender) => + sender.send(ctx.borrow_draw_buffer().unwrap().size().height).unwrap(), + WebGLCommand::Finish(sender) => + Self::finish(sender), + WebGLCommand::Flush => + gl::flush(), + WebGLCommand::GenerateMipmap(target) => + gl::generate_mipmap(target), + } + + // FIXME: Use debug_assertions once tests are run with them + let error = gl::get_error(); + assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error); + } + + fn read_pixels(x: i32, y: i32, width: i32, height: i32, format: u32, pixel_type: u32, + chan: IpcSender>) { + let result = gl::read_pixels(x, y, width, height, format, pixel_type); + chan.send(result).unwrap() + } + + fn active_attrib(program_id: WebGLProgramId, + index: u32, + chan: IpcSender>) { + let result = if index >= gl::get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES) as u32 { + Err(WebGLError::InvalidValue) + } else { + Ok(gl::get_active_attrib(program_id.get(), index)) + }; + chan.send(result).unwrap(); + } + + fn active_uniform(program_id: WebGLProgramId, + index: u32, + chan: IpcSender>) { + let result = if index >= gl::get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS) as u32 { + Err(WebGLError::InvalidValue) + } else { + Ok(gl::get_active_uniform(program_id.get(), index)) + }; + chan.send(result).unwrap(); + } + + fn attrib_location(program_id: WebGLProgramId, + name: String, + chan: IpcSender> ) { + let attrib_location = gl::get_attrib_location(program_id.get(), &name); + + let attrib_location = if attrib_location == -1 { + None + } else { + Some(attrib_location) + }; + + chan.send(attrib_location).unwrap(); + } + + fn parameter(param_id: u32, + chan: IpcSender>) { + let result = match param_id { + gl::ACTIVE_TEXTURE | + //gl::ALPHA_BITS | + gl::BLEND_DST_ALPHA | + gl::BLEND_DST_RGB | + gl::BLEND_EQUATION_ALPHA | + gl::BLEND_EQUATION_RGB | + gl::BLEND_SRC_ALPHA | + gl::BLEND_SRC_RGB | + //gl::BLUE_BITS | + gl::CULL_FACE_MODE | + //gl::DEPTH_BITS | + gl::DEPTH_FUNC | + gl::FRONT_FACE | + //gl::GENERATE_MIPMAP_HINT | + //gl::GREEN_BITS | + //gl::IMPLEMENTATION_COLOR_READ_FORMAT | + //gl::IMPLEMENTATION_COLOR_READ_TYPE | + gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS | + gl::MAX_CUBE_MAP_TEXTURE_SIZE | + //gl::MAX_FRAGMENT_UNIFORM_VECTORS | + gl::MAX_RENDERBUFFER_SIZE | + gl::MAX_TEXTURE_IMAGE_UNITS | + gl::MAX_TEXTURE_SIZE | + //gl::MAX_VARYING_VECTORS | + gl::MAX_VERTEX_ATTRIBS | + gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS | + //gl::MAX_VERTEX_UNIFORM_VECTORS | + gl::PACK_ALIGNMENT | + //gl::RED_BITS | + gl::SAMPLE_BUFFERS | + gl::SAMPLES | + gl::STENCIL_BACK_FAIL | + gl::STENCIL_BACK_FUNC | + gl::STENCIL_BACK_PASS_DEPTH_FAIL | + gl::STENCIL_BACK_PASS_DEPTH_PASS | + gl::STENCIL_BACK_REF | + gl::STENCIL_BACK_VALUE_MASK | + gl::STENCIL_BACK_WRITEMASK | + //gl::STENCIL_BITS | + gl::STENCIL_CLEAR_VALUE | + gl::STENCIL_FAIL | + gl::STENCIL_FUNC | + gl::STENCIL_PASS_DEPTH_FAIL | + gl::STENCIL_PASS_DEPTH_PASS | + gl::STENCIL_REF | + gl::STENCIL_VALUE_MASK | + gl::STENCIL_WRITEMASK | + gl::SUBPIXEL_BITS | + gl::UNPACK_ALIGNMENT => + //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL => + Ok(WebGLParameter::Int(gl::get_integer_v(param_id))), + + gl::BLEND | + gl::CULL_FACE | + gl::DEPTH_TEST | + gl::DEPTH_WRITEMASK | + gl::DITHER | + gl::POLYGON_OFFSET_FILL | + gl::SAMPLE_COVERAGE_INVERT | + gl::STENCIL_TEST => + //gl::UNPACK_FLIP_Y_WEBGL | + //gl::UNPACK_PREMULTIPLY_ALPHA_WEBGL => + Ok(WebGLParameter::Bool(gl::get_boolean_v(param_id) != 0)), + + gl::DEPTH_CLEAR_VALUE | + gl::LINE_WIDTH | + gl::POLYGON_OFFSET_FACTOR | + gl::POLYGON_OFFSET_UNITS | + gl::SAMPLE_COVERAGE_VALUE => + Ok(WebGLParameter::Float(gl::get_float_v(param_id))), + + gl::VERSION => Ok(WebGLParameter::String("WebGL 1.0".to_owned())), + gl::RENDERER | + gl::VENDOR => Ok(WebGLParameter::String("Mozilla/Servo".to_owned())), + gl::SHADING_LANGUAGE_VERSION => Ok(WebGLParameter::String("WebGL GLSL ES 1.0".to_owned())), + + // TODO(zbarsky, emilio): Implement support for the following valid parameters + // Float32Array + gl::ALIASED_LINE_WIDTH_RANGE | + //gl::ALIASED_POINT_SIZE_RANGE | + //gl::BLEND_COLOR | + gl::COLOR_CLEAR_VALUE | + gl::DEPTH_RANGE | + + // WebGLBuffer + gl::ARRAY_BUFFER_BINDING | + gl::ELEMENT_ARRAY_BUFFER_BINDING | + + // WebGLFrameBuffer + gl::FRAMEBUFFER_BINDING | + + // WebGLRenderBuffer + gl::RENDERBUFFER_BINDING | + + // WebGLProgram + gl::CURRENT_PROGRAM | + + // WebGLTexture + gl::TEXTURE_BINDING_2D | + gl::TEXTURE_BINDING_CUBE_MAP | + + // sequence + gl::COLOR_WRITEMASK | + + // Uint32Array + gl::COMPRESSED_TEXTURE_FORMATS | + + // Int32Array + gl::MAX_VIEWPORT_DIMS | + gl::SCISSOR_BOX | + gl::VIEWPORT => Err(WebGLError::InvalidEnum), + + // Invalid parameters + _ => Err(WebGLError::InvalidEnum) + }; + + chan.send(result).unwrap(); + } + + fn finish(chan: IpcSender<()>) { + gl::finish(); + chan.send(()).unwrap(); + } + + fn vertex_attrib(index: u32, + pname: u32, + chan: IpcSender>) { + let result = if index >= gl::get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32 { + Err(WebGLError::InvalidValue) + } else { + match pname { + gl::VERTEX_ATTRIB_ARRAY_ENABLED | + gl::VERTEX_ATTRIB_ARRAY_NORMALIZED => + Ok(WebGLParameter::Bool(gl::get_vertex_attrib_iv(index, pname) != 0)), + gl::VERTEX_ATTRIB_ARRAY_SIZE | + gl::VERTEX_ATTRIB_ARRAY_STRIDE | + gl::VERTEX_ATTRIB_ARRAY_TYPE => + Ok(WebGLParameter::Int(gl::get_vertex_attrib_iv(index, pname))), + gl::CURRENT_VERTEX_ATTRIB => + Ok(WebGLParameter::FloatArray(gl::get_vertex_attrib_fv(index, pname))), + // gl::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING should return WebGLBuffer + _ => Err(WebGLError::InvalidEnum), + } + }; + + chan.send(result).unwrap(); + } + + fn buffer_parameter(target: u32, + param_id: u32, + chan: IpcSender>) { + let result = match param_id { + gl::BUFFER_SIZE | + gl::BUFFER_USAGE => + Ok(WebGLParameter::Int(gl::get_buffer_parameter_iv(target, param_id))), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn program_parameter(program_id: WebGLProgramId, + param_id: u32, + chan: IpcSender>) { + let result = match param_id { + gl::DELETE_STATUS | + gl::LINK_STATUS | + gl::VALIDATE_STATUS => + Ok(WebGLParameter::Bool(gl::get_program_iv(program_id.get(), param_id) != 0)), + gl::ATTACHED_SHADERS | + gl::ACTIVE_ATTRIBUTES | + gl::ACTIVE_UNIFORMS => + Ok(WebGLParameter::Int(gl::get_program_iv(program_id.get(), param_id))), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn shader_parameter(shader_id: WebGLShaderId, + param_id: u32, + chan: IpcSender>) { + let result = match param_id { + gl::SHADER_TYPE => + Ok(WebGLParameter::Int(gl::get_shader_iv(shader_id.get(), param_id))), + gl::DELETE_STATUS | + gl::COMPILE_STATUS => + Ok(WebGLParameter::Bool(gl::get_shader_iv(shader_id.get(), param_id) != 0)), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn uniform_location(program_id: WebGLProgramId, + name: String, + chan: IpcSender>) { + let location = gl::get_uniform_location(program_id.get(), &name); + let location = if location == -1 { + None + } else { + Some(location) + }; + + chan.send(location).unwrap(); + } + + fn create_buffer(chan: IpcSender>) { + let buffer = gl::gen_buffers(1)[0]; + let buffer = if buffer == 0 { + None + } else { + Some(unsafe { WebGLBufferId::new(buffer) }) + }; + chan.send(buffer).unwrap(); + } + + fn create_framebuffer(chan: IpcSender>) { + let framebuffer = gl::gen_framebuffers(1)[0]; + let framebuffer = if framebuffer == 0 { + None + } else { + Some(unsafe { WebGLFramebufferId::new(framebuffer) }) + }; + chan.send(framebuffer).unwrap(); + } + + + fn create_renderbuffer(chan: IpcSender>) { + let renderbuffer = gl::gen_renderbuffers(1)[0]; + let renderbuffer = if renderbuffer == 0 { + None + } else { + Some(unsafe { WebGLRenderbufferId::new(renderbuffer) }) + }; + chan.send(renderbuffer).unwrap(); + } + + fn create_texture(chan: IpcSender>) { + let texture = gl::gen_textures(1)[0]; + let texture = if texture == 0 { + None + } else { + Some(unsafe { WebGLTextureId::new(texture) }) + }; + chan.send(texture).unwrap(); + } + + + fn create_program(chan: IpcSender>) { + let program = gl::create_program(); + let program = if program == 0 { + None + } else { + Some(unsafe { WebGLProgramId::new(program) }) + }; + chan.send(program).unwrap(); + } + + fn create_shader(shader_type: u32, chan: IpcSender>) { + let shader = gl::create_shader(shader_type); + let shader = if shader == 0 { + None + } else { + Some(unsafe { WebGLShaderId::new(shader) }) + }; + chan.send(shader).unwrap(); + } + + #[inline] + fn bind_framebuffer(target: u32, + request: WebGLFramebufferBindingRequest, + ctx: &GLContext) { + let id = match request { + WebGLFramebufferBindingRequest::Explicit(id) => id.get(), + WebGLFramebufferBindingRequest::Default => + ctx.borrow_draw_buffer().unwrap().get_framebuffer(), + }; + + gl::bind_framebuffer(target, id); + } + + + #[inline] + fn compile_shader(shader_id: WebGLShaderId, source: String) { + gl::shader_source(shader_id.get(), &[source.as_bytes()]); + gl::compile_shader(shader_id.get()); + } +}